Commit | Line | Data |
---|---|---|
1d1ccf4f MW |
1 | /* -*-c-*- |
2 | * | |
3 | * Allow open(2) to work on Unix-domain sockets | |
4 | * | |
5 | * (c) 2008 Straylight/Edgeware | |
6 | */ | |
7 | ||
8 | /*----- Licensing notice --------------------------------------------------* | |
9 | * | |
10 | * This file is part of the preload-hacks package. | |
11 | * | |
12 | * Preload-hacks are free software; you can redistribute it and/or modify | |
13 | * them under the terms of the GNU General Public License as published by | |
14 | * the Free Software Foundation; either version 2 of the License, or (at | |
15 | * your option) any later version. | |
16 | * | |
de6df72d MW |
17 | * Preload-hacks are distributed in the hope that it will be useful, but |
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
19 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
20 | * for more details. | |
1d1ccf4f MW |
21 | * |
22 | * You should have received a copy of the GNU General Public License along | |
de6df72d MW |
23 | * with preload-hacks; if not, write to the Free Software Foundation, Inc., |
24 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
1d1ccf4f MW |
25 | */ |
26 | ||
e4976bb0 | 27 | #define _GNU_SOURCE |
28 | #undef sun | |
29 | ||
1d1ccf4f MW |
30 | /*----- Header files ------------------------------------------------------*/ |
31 | ||
e4976bb0 | 32 | #include <errno.h> |
33 | #include <stdarg.h> | |
34 | #include <stdio.h> | |
35 | #include <string.h> | |
36 | ||
37 | #include <unistd.h> | |
38 | #include <dlfcn.h> | |
39 | #include <fcntl.h> | |
40 | ||
41 | #include <sys/socket.h> | |
42 | #include <sys/stat.h> | |
43 | #include <sys/un.h> | |
44 | ||
3fa60931 MW |
45 | #ifndef SUN_LEN |
46 | # define SUN_LEN (sun) \ | |
47 | (strlen((sun)->sun_path) + offsetof(struct sockaddr_un, sun_path)) | |
48 | #endif | |
49 | ||
1d1ccf4f MW |
50 | /*----- Import the real versions of functions -----------------------------*/ |
51 | ||
52 | /* The list of functions to immport. */ | |
e4976bb0 | 53 | #define IMPORTS(_) \ |
54 | _(open, int, (const char *, int, ...)) \ | |
55 | _(open64, int, (const char *, int, ...)) \ | |
56 | _(fopen, FILE *, (const char *, const char *)) \ | |
57 | _(freopen, FILE *, (const char *, const char *, FILE *)) | |
58 | ||
1d1ccf4f | 59 | /* Function pointers to set up. */ |
e4976bb0 | 60 | #define DECL(imp, ret, args) static ret (*real_##imp) args; |
61 | IMPORTS(DECL) | |
62 | #undef DECL | |
63 | ||
1d1ccf4f | 64 | /* Import the system calls. */ |
e4976bb0 | 65 | static void import(void) |
66 | { | |
67 | #define IMPORT(imp, ret, args) \ | |
68 | real_##imp = (ret (*)args)dlsym(RTLD_NEXT, #imp); | |
69 | IMPORTS(IMPORT) | |
70 | #undef IMPORT | |
71 | } | |
1d1ccf4f | 72 | /*----- Utilities ---------------------------------------------------------*/ |
e4976bb0 | 73 | |
1d1ccf4f | 74 | /* Socket address casts */ |
e4976bb0 | 75 | #define SA(sa) ((struct sockaddr *)(sa)) |
76 | ||
1d1ccf4f | 77 | /* Preservation of error status */ |
e4976bb0 | 78 | #define PRESERVING_ERRNO(body) do { \ |
79 | int _err = errno; { body } errno = _err; \ | |
80 | } while (0) | |
81 | ||
1d1ccf4f MW |
82 | /*----- Connecting to Unix-domain sockets ---------------------------------*/ |
83 | ||
84 | /* If FN refers to a Unix-domain socket, connect to it, stash the socket | |
85 | * (or -1 on error) in *FDP, and return 1. Otherwise return 0. | |
86 | */ | |
e4976bb0 | 87 | static int maybe_connect(const char *fn, int *fdp) |
88 | { | |
89 | int fd; | |
90 | struct sockaddr_un sun; | |
91 | struct stat st; | |
92 | ||
93 | if (stat(fn, &st) || !S_ISSOCK(st.st_mode)) | |
94 | return (0); | |
95 | *fdp = -1; | |
96 | if (strlen(fn) >= sizeof(sun.sun_path)) { | |
97 | errno = EINVAL; | |
98 | return (1); | |
99 | } | |
100 | strncpy(sun.sun_path, fn, sizeof(sun.sun_path)); | |
101 | sun.sun_family = AF_UNIX; | |
102 | if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0 || | |
103 | connect(fd, SA(&sun), SUN_LEN(&sun))) { | |
104 | PRESERVING_ERRNO( if (fd >= 0) close(fd); ); | |
105 | return (1); | |
106 | } | |
107 | *fdp = fd; | |
108 | return (1); | |
109 | } | |
110 | ||
1d1ccf4f MW |
111 | /*----- Intercepted system calls ------------------------------------------*/ |
112 | ||
113 | /* Create an open(2)-like function OPEN. */ | |
e4976bb0 | 114 | #define OPEN_VENEER(open) \ |
115 | int open(const char *fn, int how, ...) \ | |
116 | { \ | |
117 | int mode = 0; \ | |
118 | int fd; \ | |
119 | va_list ap; \ | |
120 | \ | |
121 | PRESERVING_ERRNO({ \ | |
122 | if (how & O_CREAT) \ | |
123 | { va_start(ap, how); mode = va_arg(ap, int); va_end(ap); } \ | |
124 | if (!maybe_connect(fn, &fd)) fd = real_##open(fn, how, mode); \ | |
125 | if (fd < 0) return (-1); \ | |
126 | }); \ | |
127 | return (fd); \ | |
128 | } | |
1d1ccf4f MW |
129 | |
130 | /* open(2) and open64(2). */ | |
e4976bb0 | 131 | OPEN_VENEER(open) |
132 | OPEN_VENEER(open64) | |
133 | ||
134 | FILE *fopen(const char *fn, const char *how) | |
135 | { | |
136 | int fd; | |
137 | FILE *fp = 0; | |
138 | ||
139 | PRESERVING_ERRNO({ | |
140 | if (!maybe_connect(fn, &fd)) | |
141 | fp = real_fopen(fn, how); | |
142 | else if (fd >= 0 && (fp = fdopen(fd, how)) == 0) | |
143 | PRESERVING_ERRNO( close(fd); ); | |
144 | }); | |
145 | return (fp); | |
146 | } | |
147 | ||
148 | FILE *freopen(const char *fn, const char *how, FILE *fp) | |
149 | { | |
150 | int fd; | |
151 | ||
152 | PRESERVING_ERRNO({ | |
153 | if (!maybe_connect(fn, &fd)) | |
154 | fp = real_freopen(fn, how, fp); | |
155 | else if (fd >= 0) { | |
156 | if (fflush(fp) || dup2(fd, fileno(fp))) fp = 0; | |
157 | PRESERVING_ERRNO( close(fd); ); | |
158 | } | |
159 | }); | |
160 | return (fp); | |
161 | } | |
162 | ||
1d1ccf4f MW |
163 | /*----- Initialization ----------------------------------------------------*/ |
164 | ||
165 | static void setup(void) __attribute__((constructor)); | |
e4976bb0 | 166 | static void setup(void) |
167 | { | |
168 | PRESERVING_ERRNO({ | |
169 | import(); | |
170 | }); | |
171 | } | |
1d1ccf4f MW |
172 | |
173 | /*----- That's all, folks -------------------------------------------------*/ |