chiark / gitweb /
noip.c: Fix some holdovers with hardcoded address families.
[preload-hacks] / uopen.c
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 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.
21  *
22  * You should have received a copy of the GNU General Public License along
23  * with preload-hacks; if not, write to the Free Software Foundation, Inc.,
24  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25  */
26
27 #define _GNU_SOURCE
28 #undef sun
29
30 /*----- Header files ------------------------------------------------------*/
31
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
45 /*----- Import the real versions of functions -----------------------------*/
46
47 /* The list of functions to immport. */
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
54 /* Function pointers to set up. */
55 #define DECL(imp, ret, args) static ret (*real_##imp) args;
56 IMPORTS(DECL)
57 #undef DECL
58
59 /* Import the system calls. */
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 }
67 /*----- Utilities ---------------------------------------------------------*/
68
69 /* Socket address casts */
70 #define SA(sa) ((struct sockaddr *)(sa))
71
72 /* Preservation of error status */
73 #define PRESERVING_ERRNO(body) do {                                     \
74   int _err = errno; { body } errno = _err;                              \
75 } while (0)
76
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  */
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
106 /*----- Intercepted system calls ------------------------------------------*/
107
108 /* Create an open(2)-like function OPEN. */
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   }
124
125 /* open(2) and open64(2). */
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
158 /*----- Initialization ----------------------------------------------------*/
159
160 static void setup(void) __attribute__((constructor));
161 static void setup(void)
162 {
163   PRESERVING_ERRNO({
164     import();
165   });
166 }
167
168 /*----- That's all, folks -------------------------------------------------*/