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 | * | |
17 | * Preload-hacks distributed in the hope that it will be useful, but WITHOUT | |
18 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
19 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
20 | * more details. | |
21 | * | |
22 | * You should have received a copy of the GNU General Public License along | |
23 | * with mLib; if not, write to the Free Software Foundation, Inc., 59 Temple | |
24 | * Place - Suite 330, Boston, MA 02111-1307, USA. | |
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 | ||
1d1ccf4f MW |
45 | /*----- Import the real versions of functions -----------------------------*/ |
46 | ||
47 | /* The list of functions to immport. */ | |
e4976bb0 | 48 | #define IMPORTS(_) \ |
49 | _(open, int, (const char *, int, ...)) \ | |
50 | _(open64, int, (const char *, int, ...)) \ | |
51 | _(fopen, FILE *, (const char *, const char *)) \ | |
52 | _(freopen, FILE *, (const char *, const char *, FILE *)) | |
53 | ||
1d1ccf4f | 54 | /* Function pointers to set up. */ |
e4976bb0 | 55 | #define DECL(imp, ret, args) static ret (*real_##imp) args; |
56 | IMPORTS(DECL) | |
57 | #undef DECL | |
58 | ||
1d1ccf4f | 59 | /* Import the system calls. */ |
e4976bb0 | 60 | static void import(void) |
61 | { | |
62 | #define IMPORT(imp, ret, args) \ | |
63 | real_##imp = (ret (*)args)dlsym(RTLD_NEXT, #imp); | |
64 | IMPORTS(IMPORT) | |
65 | #undef IMPORT | |
66 | } | |
1d1ccf4f | 67 | /*----- Utilities ---------------------------------------------------------*/ |
e4976bb0 | 68 | |
1d1ccf4f | 69 | /* Socket address casts */ |
e4976bb0 | 70 | #define SA(sa) ((struct sockaddr *)(sa)) |
71 | ||
1d1ccf4f | 72 | /* Preservation of error status */ |
e4976bb0 | 73 | #define PRESERVING_ERRNO(body) do { \ |
74 | int _err = errno; { body } errno = _err; \ | |
75 | } while (0) | |
76 | ||
1d1ccf4f MW |
77 | /*----- Connecting to Unix-domain sockets ---------------------------------*/ |
78 | ||
79 | /* If FN refers to a Unix-domain socket, connect to it, stash the socket | |
80 | * (or -1 on error) in *FDP, and return 1. Otherwise return 0. | |
81 | */ | |
e4976bb0 | 82 | static int maybe_connect(const char *fn, int *fdp) |
83 | { | |
84 | int fd; | |
85 | struct sockaddr_un sun; | |
86 | struct stat st; | |
87 | ||
88 | if (stat(fn, &st) || !S_ISSOCK(st.st_mode)) | |
89 | return (0); | |
90 | *fdp = -1; | |
91 | if (strlen(fn) >= sizeof(sun.sun_path)) { | |
92 | errno = EINVAL; | |
93 | return (1); | |
94 | } | |
95 | strncpy(sun.sun_path, fn, sizeof(sun.sun_path)); | |
96 | sun.sun_family = AF_UNIX; | |
97 | if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0 || | |
98 | connect(fd, SA(&sun), SUN_LEN(&sun))) { | |
99 | PRESERVING_ERRNO( if (fd >= 0) close(fd); ); | |
100 | return (1); | |
101 | } | |
102 | *fdp = fd; | |
103 | return (1); | |
104 | } | |
105 | ||
1d1ccf4f MW |
106 | /*----- Intercepted system calls ------------------------------------------*/ |
107 | ||
108 | /* Create an open(2)-like function OPEN. */ | |
e4976bb0 | 109 | #define OPEN_VENEER(open) \ |
110 | int open(const char *fn, int how, ...) \ | |
111 | { \ | |
112 | int mode = 0; \ | |
113 | int fd; \ | |
114 | va_list ap; \ | |
115 | \ | |
116 | PRESERVING_ERRNO({ \ | |
117 | if (how & O_CREAT) \ | |
118 | { va_start(ap, how); mode = va_arg(ap, int); va_end(ap); } \ | |
119 | if (!maybe_connect(fn, &fd)) fd = real_##open(fn, how, mode); \ | |
120 | if (fd < 0) return (-1); \ | |
121 | }); \ | |
122 | return (fd); \ | |
123 | } | |
1d1ccf4f MW |
124 | |
125 | /* open(2) and open64(2). */ | |
e4976bb0 | 126 | OPEN_VENEER(open) |
127 | OPEN_VENEER(open64) | |
128 | ||
129 | FILE *fopen(const char *fn, const char *how) | |
130 | { | |
131 | int fd; | |
132 | FILE *fp = 0; | |
133 | ||
134 | PRESERVING_ERRNO({ | |
135 | if (!maybe_connect(fn, &fd)) | |
136 | fp = real_fopen(fn, how); | |
137 | else if (fd >= 0 && (fp = fdopen(fd, how)) == 0) | |
138 | PRESERVING_ERRNO( close(fd); ); | |
139 | }); | |
140 | return (fp); | |
141 | } | |
142 | ||
143 | FILE *freopen(const char *fn, const char *how, FILE *fp) | |
144 | { | |
145 | int fd; | |
146 | ||
147 | PRESERVING_ERRNO({ | |
148 | if (!maybe_connect(fn, &fd)) | |
149 | fp = real_freopen(fn, how, fp); | |
150 | else if (fd >= 0) { | |
151 | if (fflush(fp) || dup2(fd, fileno(fp))) fp = 0; | |
152 | PRESERVING_ERRNO( close(fd); ); | |
153 | } | |
154 | }); | |
155 | return (fp); | |
156 | } | |
157 | ||
1d1ccf4f MW |
158 | /*----- Initialization ----------------------------------------------------*/ |
159 | ||
160 | static void setup(void) __attribute__((constructor)); | |
e4976bb0 | 161 | static void setup(void) |
162 | { | |
163 | PRESERVING_ERRNO({ | |
164 | import(); | |
165 | }); | |
166 | } | |
1d1ccf4f MW |
167 | |
168 | /*----- That's all, folks -------------------------------------------------*/ |