chiark / gitweb /
noip.c: Shut up some GCC warnings.
[preload-hacks] / uopen.c
CommitLineData
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;
56IMPORTS(DECL)
57#undef DECL
58
1d1ccf4f 59/* Import the system calls. */
e4976bb0 60static 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 82static 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 126OPEN_VENEER(open)
127OPEN_VENEER(open64)
128
129FILE *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
143FILE *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
160static void setup(void) __attribute__((constructor));
e4976bb0 161static void setup(void)
162{
163 PRESERVING_ERRNO({
164 import();
165 });
166}
1d1ccf4f
MW
167
168/*----- That's all, folks -------------------------------------------------*/