3 * Allow open(2) to work on Unix-domain sockets
5 * (c) 2008 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of the preload-hacks package.
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.
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
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.
30 /*----- Header files ------------------------------------------------------*/
41 #include <sys/socket.h>
46 # define SUN_LEN (sun) \
47 (strlen((sun)->sun_path) + offsetof(struct sockaddr_un, sun_path))
50 /*----- Import the real versions of functions -----------------------------*/
52 /* The list of functions to immport. */
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 *))
59 /* Function pointers to set up. */
60 #define DECL(imp, ret, args) static ret (*real_##imp) args;
64 /* Import the system calls. */
65 static void import(void)
67 #define IMPORT(imp, ret, args) \
68 real_##imp = (ret (*)args)dlsym(RTLD_NEXT, #imp);
72 /*----- Utilities ---------------------------------------------------------*/
74 /* Socket address casts */
75 #define SA(sa) ((struct sockaddr *)(sa))
77 /* Preservation of error status */
78 #define PRESERVING_ERRNO(body) do { \
79 int _err = errno; { body } errno = _err; \
82 /*----- Connecting to Unix-domain sockets ---------------------------------*/
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.
87 static int maybe_connect(const char *fn, int *fdp)
90 struct sockaddr_un sun;
93 if (stat(fn, &st) || !S_ISSOCK(st.st_mode))
96 if (strlen(fn) >= sizeof(sun.sun_path)) {
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); );
111 /*----- Intercepted system calls ------------------------------------------*/
113 /* Create an open(2)-like function OPEN. */
114 #define OPEN_VENEER(open) \
115 int open(const char *fn, int how, ...) \
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); \
130 /* open(2) and open64(2). */
134 FILE *fopen(const char *fn, const char *how)
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); );
148 FILE *freopen(const char *fn, const char *how, FILE *fp)
153 if (!maybe_connect(fn, &fd))
154 fp = real_freopen(fn, how, fp);
156 if (fflush(fp) || dup2(fd, fileno(fp))) fp = 0;
157 PRESERVING_ERRNO( close(fd); );
163 /*----- Initialization ----------------------------------------------------*/
165 static void setup(void) __attribute__((constructor));
166 static void setup(void)
173 /*----- That's all, folks -------------------------------------------------*/