chiark / gitweb /
It seems to work!
[preload-hacks] / uopen.c
CommitLineData
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;
24IMPORTS(DECL)
25#undef DECL
26
27static void setup(void) __attribute__((constructor));
28static 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
42static 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 }
81OPEN_VENEER(open)
82OPEN_VENEER(open64)
83
84FILE *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
98FILE *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
113static void setup(void)
114{
115 PRESERVING_ERRNO({
116 import();
117 });
118}