e4976bb0 |
1 | #define _GNU_SOURCE |
2 | #undef sun |
3 | |
4 | #include <errno.h> |
5 | #include <stdarg.h> |
6 | #include <stdio.h> |
7 | #include <string.h> |
8 | |
9 | #include <unistd.h> |
10 | #include <dlfcn.h> |
11 | #include <fcntl.h> |
12 | |
13 | #include <sys/socket.h> |
14 | #include <sys/stat.h> |
15 | #include <sys/un.h> |
16 | |
17 | #define IMPORTS(_) \ |
18 | _(open, int, (const char *, int, ...)) \ |
19 | _(open64, int, (const char *, int, ...)) \ |
20 | _(fopen, FILE *, (const char *, const char *)) \ |
21 | _(freopen, FILE *, (const char *, const char *, FILE *)) |
22 | |
23 | #define DECL(imp, ret, args) static ret (*real_##imp) args; |
24 | IMPORTS(DECL) |
25 | #undef DECL |
26 | |
27 | static void setup(void) __attribute__((constructor)); |
28 | static void import(void) |
29 | { |
30 | #define IMPORT(imp, ret, args) \ |
31 | real_##imp = (ret (*)args)dlsym(RTLD_NEXT, #imp); |
32 | IMPORTS(IMPORT) |
33 | #undef IMPORT |
34 | } |
35 | |
36 | #define SA(sa) ((struct sockaddr *)(sa)) |
37 | |
38 | #define PRESERVING_ERRNO(body) do { \ |
39 | int _err = errno; { body } errno = _err; \ |
40 | } while (0) |
41 | |
42 | static int maybe_connect(const char *fn, int *fdp) |
43 | { |
44 | int fd; |
45 | struct sockaddr_un sun; |
46 | struct stat st; |
47 | |
48 | if (stat(fn, &st) || !S_ISSOCK(st.st_mode)) |
49 | return (0); |
50 | *fdp = -1; |
51 | if (strlen(fn) >= sizeof(sun.sun_path)) { |
52 | errno = EINVAL; |
53 | return (1); |
54 | } |
55 | strncpy(sun.sun_path, fn, sizeof(sun.sun_path)); |
56 | sun.sun_family = AF_UNIX; |
57 | if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0 || |
58 | connect(fd, SA(&sun), SUN_LEN(&sun))) { |
59 | PRESERVING_ERRNO( if (fd >= 0) close(fd); ); |
60 | return (1); |
61 | } |
62 | *fdp = fd; |
63 | return (1); |
64 | } |
65 | |
66 | #define OPEN_VENEER(open) \ |
67 | int open(const char *fn, int how, ...) \ |
68 | { \ |
69 | int mode = 0; \ |
70 | int fd; \ |
71 | va_list ap; \ |
72 | \ |
73 | PRESERVING_ERRNO({ \ |
74 | if (how & O_CREAT) \ |
75 | { va_start(ap, how); mode = va_arg(ap, int); va_end(ap); } \ |
76 | if (!maybe_connect(fn, &fd)) fd = real_##open(fn, how, mode); \ |
77 | if (fd < 0) return (-1); \ |
78 | }); \ |
79 | return (fd); \ |
80 | } |
81 | OPEN_VENEER(open) |
82 | OPEN_VENEER(open64) |
83 | |
84 | FILE *fopen(const char *fn, const char *how) |
85 | { |
86 | int fd; |
87 | FILE *fp = 0; |
88 | |
89 | PRESERVING_ERRNO({ |
90 | if (!maybe_connect(fn, &fd)) |
91 | fp = real_fopen(fn, how); |
92 | else if (fd >= 0 && (fp = fdopen(fd, how)) == 0) |
93 | PRESERVING_ERRNO( close(fd); ); |
94 | }); |
95 | return (fp); |
96 | } |
97 | |
98 | FILE *freopen(const char *fn, const char *how, FILE *fp) |
99 | { |
100 | int fd; |
101 | |
102 | PRESERVING_ERRNO({ |
103 | if (!maybe_connect(fn, &fd)) |
104 | fp = real_freopen(fn, how, fp); |
105 | else if (fd >= 0) { |
106 | if (fflush(fp) || dup2(fd, fileno(fp))) fp = 0; |
107 | PRESERVING_ERRNO( close(fd); ); |
108 | } |
109 | }); |
110 | return (fp); |
111 | } |
112 | |
113 | static void setup(void) |
114 | { |
115 | PRESERVING_ERRNO({ |
116 | import(); |
117 | }); |
118 | } |