It seems to work!
[preload-hacks] / uopen.c
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 }