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 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
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.
30 /*----- Header files ------------------------------------------------------*/
41 #include <sys/socket.h>
45 /*----- Import the real versions of functions -----------------------------*/
47 /* The list of functions to immport. */
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 *))
54 /* Function pointers to set up. */
55 #define DECL(imp, ret, args) static ret (*real_##imp) args;
59 /* Import the system calls. */
60 static void import(void)
62 #define IMPORT(imp, ret, args) \
63 real_##imp = (ret (*)args)dlsym(RTLD_NEXT, #imp);
67 /*----- Utilities ---------------------------------------------------------*/
69 /* Socket address casts */
70 #define SA(sa) ((struct sockaddr *)(sa))
72 /* Preservation of error status */
73 #define PRESERVING_ERRNO(body) do { \
74 int _err = errno; { body } errno = _err; \
77 /*----- Connecting to Unix-domain sockets ---------------------------------*/
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.
82 static int maybe_connect(const char *fn
, int *fdp
)
85 struct sockaddr_un sun
;
88 if (stat(fn
, &st
) || !S_ISSOCK(st
.st_mode
))
91 if (strlen(fn
) >= sizeof(sun
.sun_path
)) {
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
); );
106 /*----- Intercepted system calls ------------------------------------------*/
108 /* Create an open(2)-like function OPEN. */
109 #define OPEN_VENEER(open) \
110 int open(const char *fn, int how, ...) \
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); \
125 /* open(2) and open64(2). */
129 FILE *fopen(const char *fn
, const char *how
)
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
); );
143 FILE *freopen(const char *fn
, const char *how
, FILE *fp
)
148 if (!maybe_connect(fn
, &fd
))
149 fp
= real_freopen(fn
, how
, fp
);
151 if (fflush(fp
) || dup2(fd
, fileno(fp
))) fp
= 0;
152 PRESERVING_ERRNO( close(fd
); );
158 /*----- Initialization ----------------------------------------------------*/
160 static void setup(void) __attribute__((constructor
));
161 static void setup(void)
168 /*----- That's all, folks -------------------------------------------------*/