Annotation of src/lib/librumphijack/hijack.c, Revision 1.69
1.69 ! pooka 1: /* $NetBSD: hijack.c,v 1.68 2011/02/25 18:29:00 pooka Exp $ */
1.1 pooka 2:
3: /*-
4: * Copyright (c) 2011 Antti Kantee. All Rights Reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25: * SUCH DAMAGE.
26: */
27:
28: #include <sys/cdefs.h>
1.69 ! pooka 29: __RCSID("$NetBSD: hijack.c,v 1.68 2011/02/25 18:29:00 pooka Exp $");
1.21 christos 30:
31: #define __ssp_weak_name(fun) _hijack_ ## fun
1.1 pooka 32:
33: #include <sys/param.h>
34: #include <sys/types.h>
1.10 pooka 35: #include <sys/event.h>
1.1 pooka 36: #include <sys/ioctl.h>
1.62 pooka 37: #include <sys/mman.h>
1.48 pooka 38: #include <sys/mount.h>
39: #include <sys/poll.h>
1.1 pooka 40: #include <sys/socket.h>
1.45 pooka 41: #include <sys/statvfs.h>
1.1 pooka 42:
43: #include <rump/rumpclient.h>
44: #include <rump/rump_syscalls.h>
45:
46: #include <assert.h>
47: #include <dlfcn.h>
48: #include <err.h>
49: #include <errno.h>
50: #include <fcntl.h>
51: #include <poll.h>
52: #include <pthread.h>
1.3 pooka 53: #include <signal.h>
1.1 pooka 54: #include <stdarg.h>
1.8 pooka 55: #include <stdbool.h>
1.1 pooka 56: #include <stdio.h>
57: #include <stdlib.h>
1.28 pooka 58: #include <string.h>
1.3 pooka 59: #include <time.h>
1.1 pooka 60: #include <unistd.h>
61:
1.64 pooka 62: #include "hijack.h"
63:
1.17 pooka 64: enum dualcall {
1.60 pooka 65: DUALCALL_WRITE, DUALCALL_WRITEV, DUALCALL_PWRITE, DUALCALL_PWRITEV,
1.17 pooka 66: DUALCALL_IOCTL, DUALCALL_FCNTL,
67: DUALCALL_SOCKET, DUALCALL_ACCEPT, DUALCALL_BIND, DUALCALL_CONNECT,
68: DUALCALL_GETPEERNAME, DUALCALL_GETSOCKNAME, DUALCALL_LISTEN,
69: DUALCALL_RECVFROM, DUALCALL_RECVMSG,
70: DUALCALL_SENDTO, DUALCALL_SENDMSG,
71: DUALCALL_GETSOCKOPT, DUALCALL_SETSOCKOPT,
72: DUALCALL_SHUTDOWN,
1.60 pooka 73: DUALCALL_READ, DUALCALL_READV, DUALCALL_PREAD, DUALCALL_PREADV,
1.41 pooka 74: DUALCALL_DUP2,
1.34 pooka 75: DUALCALL_CLOSE,
1.17 pooka 76: DUALCALL_POLLTS,
1.34 pooka 77: DUALCALL_KEVENT,
1.45 pooka 78: DUALCALL_STAT, DUALCALL_LSTAT, DUALCALL_FSTAT,
79: DUALCALL_CHMOD, DUALCALL_LCHMOD, DUALCALL_FCHMOD,
80: DUALCALL_CHOWN, DUALCALL_LCHOWN, DUALCALL_FCHOWN,
81: DUALCALL_OPEN,
82: DUALCALL_STATVFS1, DUALCALL_FSTATVFS1,
83: DUALCALL_CHDIR, DUALCALL_FCHDIR,
84: DUALCALL_LSEEK,
85: DUALCALL_GETDENTS,
86: DUALCALL_UNLINK, DUALCALL_SYMLINK, DUALCALL_READLINK,
87: DUALCALL_RENAME,
88: DUALCALL_MKDIR, DUALCALL_RMDIR,
89: DUALCALL_UTIMES, DUALCALL_LUTIMES, DUALCALL_FUTIMES,
90: DUALCALL_TRUNCATE, DUALCALL_FTRUNCATE,
91: DUALCALL_FSYNC, DUALCALL_FSYNC_RANGE,
1.48 pooka 92: DUALCALL_MOUNT, DUALCALL_UNMOUNT,
1.57 pooka 93: DUALCALL___GETCWD,
1.60 pooka 94: DUALCALL_CHFLAGS, DUALCALL_LCHFLAGS, DUALCALL_FCHFLAGS,
1.65 pooka 95: DUALCALL_ACCESS,
1.68 pooka 96: DUALCALL_MKNOD,
1.17 pooka 97: DUALCALL__NUM
1.1 pooka 98: };
99:
1.8 pooka 100: #define RSYS_STRING(a) __STRING(a)
101: #define RSYS_NAME(a) RSYS_STRING(__CONCAT(RUMP_SYS_RENAME_,a))
102:
1.1 pooka 103: /*
1.14 pooka 104: * Would be nice to get this automatically in sync with libc.
105: * Also, this does not work for compat-using binaries!
106: */
107: #if !__NetBSD_Prereq__(5,99,7)
1.29 pooka 108: #define REALSELECT select
109: #define REALPOLLTS pollts
1.34 pooka 110: #define REALKEVENT kevent
1.45 pooka 111: #define REALSTAT __stat30
112: #define REALLSTAT __lstat30
113: #define REALFSTAT __fstat30
114: #define REALUTIMES utimes
115: #define REALLUTIMES lutimes
116: #define REALFUTIMES futimes
1.68 pooka 117: #define REALMKNOD mknod
1.14 pooka 118: #else
1.29 pooka 119: #define REALSELECT _sys___select50
120: #define REALPOLLTS _sys___pollts50
1.34 pooka 121: #define REALKEVENT _sys___kevent50
1.45 pooka 122: #define REALSTAT __stat50
123: #define REALLSTAT __lstat50
124: #define REALFSTAT __fstat50
125: #define REALUTIMES __utimes50
126: #define REALLUTIMES __lutimes50
1.69 ! pooka 127: #define REALFUTIMES __futimes50
1.68 pooka 128: #define REALMKNOD __mknod50
1.17 pooka 129: #endif
1.31 pooka 130: #define REALREAD _sys_read
1.60 pooka 131: #define REALPREAD _sys_pread
132: #define REALPWRITE _sys_pwrite
1.45 pooka 133: #define REALGETDENTS __getdents30
1.48 pooka 134: #define REALMOUNT __mount50
1.14 pooka 135:
1.29 pooka 136: int REALSELECT(int, fd_set *, fd_set *, fd_set *, struct timeval *);
137: int REALPOLLTS(struct pollfd *, nfds_t,
1.20 pooka 138: const struct timespec *, const sigset_t *);
1.34 pooka 139: int REALKEVENT(int, const struct kevent *, size_t, struct kevent *, size_t,
140: const struct timespec *);
1.31 pooka 141: ssize_t REALREAD(int, void *, size_t);
1.60 pooka 142: ssize_t REALPREAD(int, void *, size_t, off_t);
143: ssize_t REALPWRITE(int, const void *, size_t, off_t);
1.45 pooka 144: int REALSTAT(const char *, struct stat *);
145: int REALLSTAT(const char *, struct stat *);
146: int REALFSTAT(int, struct stat *);
147: int REALGETDENTS(int, char *, size_t);
148: int REALUTIMES(const char *, const struct timeval [2]);
149: int REALLUTIMES(const char *, const struct timeval [2]);
150: int REALFUTIMES(int, const struct timeval [2]);
1.48 pooka 151: int REALMOUNT(const char *, const char *, int, void *, size_t);
1.57 pooka 152: int __getcwd(char *, size_t);
1.68 pooka 153: int REALMKNOD(const char *, mode_t, dev_t);
1.17 pooka 154:
155: #define S(a) __STRING(a)
156: struct sysnames {
157: enum dualcall scm_callnum;
158: const char *scm_hostname;
159: const char *scm_rumpname;
160: } syscnames[] = {
161: { DUALCALL_SOCKET, "__socket30", RSYS_NAME(SOCKET) },
162: { DUALCALL_ACCEPT, "accept", RSYS_NAME(ACCEPT) },
163: { DUALCALL_BIND, "bind", RSYS_NAME(BIND) },
164: { DUALCALL_CONNECT, "connect", RSYS_NAME(CONNECT) },
165: { DUALCALL_GETPEERNAME, "getpeername", RSYS_NAME(GETPEERNAME) },
166: { DUALCALL_GETSOCKNAME, "getsockname", RSYS_NAME(GETSOCKNAME) },
167: { DUALCALL_LISTEN, "listen", RSYS_NAME(LISTEN) },
168: { DUALCALL_RECVFROM, "recvfrom", RSYS_NAME(RECVFROM) },
169: { DUALCALL_RECVMSG, "recvmsg", RSYS_NAME(RECVMSG) },
170: { DUALCALL_SENDTO, "sendto", RSYS_NAME(SENDTO) },
171: { DUALCALL_SENDMSG, "sendmsg", RSYS_NAME(SENDMSG) },
172: { DUALCALL_GETSOCKOPT, "getsockopt", RSYS_NAME(GETSOCKOPT) },
173: { DUALCALL_SETSOCKOPT, "setsockopt", RSYS_NAME(SETSOCKOPT) },
174: { DUALCALL_SHUTDOWN, "shutdown", RSYS_NAME(SHUTDOWN) },
1.31 pooka 175: { DUALCALL_READ, S(REALREAD), RSYS_NAME(READ) },
1.17 pooka 176: { DUALCALL_READV, "readv", RSYS_NAME(READV) },
1.60 pooka 177: { DUALCALL_PREAD, S(REALPREAD), RSYS_NAME(PREAD) },
178: { DUALCALL_PREADV, "preadv", RSYS_NAME(PREADV) },
1.17 pooka 179: { DUALCALL_WRITE, "write", RSYS_NAME(WRITE) },
180: { DUALCALL_WRITEV, "writev", RSYS_NAME(WRITEV) },
1.60 pooka 181: { DUALCALL_PWRITE, S(REALPWRITE), RSYS_NAME(PWRITE) },
182: { DUALCALL_PWRITEV, "pwritev", RSYS_NAME(PWRITEV) },
1.17 pooka 183: { DUALCALL_IOCTL, "ioctl", RSYS_NAME(IOCTL) },
184: { DUALCALL_FCNTL, "fcntl", RSYS_NAME(FCNTL) },
185: { DUALCALL_DUP2, "dup2", RSYS_NAME(DUP2) },
186: { DUALCALL_CLOSE, "close", RSYS_NAME(CLOSE) },
1.29 pooka 187: { DUALCALL_POLLTS, S(REALPOLLTS), RSYS_NAME(POLLTS) },
1.34 pooka 188: { DUALCALL_KEVENT, S(REALKEVENT), RSYS_NAME(KEVENT) },
1.45 pooka 189: { DUALCALL_STAT, S(REALSTAT), RSYS_NAME(STAT) },
190: { DUALCALL_LSTAT, S(REALLSTAT), RSYS_NAME(LSTAT) },
191: { DUALCALL_FSTAT, S(REALFSTAT), RSYS_NAME(FSTAT) },
192: { DUALCALL_CHOWN, "chown", RSYS_NAME(CHOWN) },
193: { DUALCALL_LCHOWN, "lchown", RSYS_NAME(LCHOWN) },
194: { DUALCALL_FCHOWN, "fchown", RSYS_NAME(FCHOWN) },
195: { DUALCALL_CHMOD, "chmod", RSYS_NAME(CHMOD) },
196: { DUALCALL_LCHMOD, "lchmod", RSYS_NAME(LCHMOD) },
197: { DUALCALL_FCHMOD, "fchmod", RSYS_NAME(FCHMOD) },
198: { DUALCALL_UTIMES, S(REALUTIMES), RSYS_NAME(UTIMES) },
199: { DUALCALL_LUTIMES, S(REALLUTIMES), RSYS_NAME(LUTIMES) },
200: { DUALCALL_FUTIMES, S(REALFUTIMES), RSYS_NAME(FUTIMES) },
201: { DUALCALL_OPEN, "open", RSYS_NAME(OPEN) },
202: { DUALCALL_STATVFS1, "statvfs1", RSYS_NAME(STATVFS1) },
203: { DUALCALL_FSTATVFS1, "fstatvfs1", RSYS_NAME(FSTATVFS1) },
204: { DUALCALL_CHDIR, "chdir", RSYS_NAME(CHDIR) },
205: { DUALCALL_FCHDIR, "fchdir", RSYS_NAME(FCHDIR) },
1.61 pooka 206: { DUALCALL_LSEEK, "lseek", RSYS_NAME(LSEEK) },
1.45 pooka 207: { DUALCALL_GETDENTS, "__getdents30", RSYS_NAME(GETDENTS) },
208: { DUALCALL_UNLINK, "unlink", RSYS_NAME(UNLINK) },
209: { DUALCALL_SYMLINK, "symlink", RSYS_NAME(SYMLINK) },
210: { DUALCALL_READLINK, "readlink", RSYS_NAME(READLINK) },
211: { DUALCALL_RENAME, "rename", RSYS_NAME(RENAME) },
212: { DUALCALL_MKDIR, "mkdir", RSYS_NAME(MKDIR) },
213: { DUALCALL_RMDIR, "rmdir", RSYS_NAME(RMDIR) },
214: { DUALCALL_TRUNCATE, "truncate", RSYS_NAME(TRUNCATE) },
215: { DUALCALL_FTRUNCATE, "ftruncate", RSYS_NAME(FTRUNCATE) },
216: { DUALCALL_FSYNC, "fsync", RSYS_NAME(FSYNC) },
217: { DUALCALL_FSYNC_RANGE, "fsync_range", RSYS_NAME(FSYNC_RANGE) },
1.48 pooka 218: { DUALCALL_MOUNT, S(REALMOUNT), RSYS_NAME(MOUNT) },
219: { DUALCALL_UNMOUNT, "unmount", RSYS_NAME(UNMOUNT) },
1.57 pooka 220: { DUALCALL___GETCWD, "__getcwd", RSYS_NAME(__GETCWD) },
1.60 pooka 221: { DUALCALL_CHFLAGS, "chflags", RSYS_NAME(CHFLAGS) },
222: { DUALCALL_LCHFLAGS, "lchflags", RSYS_NAME(LCHFLAGS) },
223: { DUALCALL_FCHFLAGS, "fchflags", RSYS_NAME(FCHFLAGS) },
1.65 pooka 224: { DUALCALL_ACCESS, "access", RSYS_NAME(ACCESS) },
1.68 pooka 225: { DUALCALL_MKNOD, S(REALMKNOD), RSYS_NAME(MKNOD) },
1.17 pooka 226: };
227: #undef S
228:
229: struct bothsys {
230: void *bs_host;
231: void *bs_rump;
232: } syscalls[DUALCALL__NUM];
233: #define GETSYSCALL(which, name) syscalls[DUALCALL_##name].bs_##which
234:
1.25 pooka 235: pid_t (*host_fork)(void);
236: int (*host_daemon)(int, int);
1.39 pooka 237: int (*host_execve)(const char *, char *const[], char *const[]);
1.62 pooka 238: void * (*host_mmap)(void *, size_t, int, int, int, off_t);
1.17 pooka 239:
1.47 pooka 240: /* ok, we need *two* bits per dup2'd fd to track fd+HIJACKOFF aliases */
1.40 pooka 241: static uint32_t dup2mask;
1.47 pooka 242: #define ISDUP2D(fd) (((fd) < 16) && (1<<(fd) & dup2mask))
1.40 pooka 243: #define SETDUP2(fd) \
1.47 pooka 244: do { if ((fd) < 16) dup2mask |= (1<<(fd)); } while (/*CONSTCOND*/0)
1.40 pooka 245: #define CLRDUP2(fd) \
1.47 pooka 246: do { if ((fd) < 16) dup2mask &= ~(1<<(fd)); } while (/*CONSTCOND*/0)
247: #define ISDUP2ALIAS(fd) (((fd) < 16) && (1<<((fd)+16) & dup2mask))
248: #define SETDUP2ALIAS(fd) \
249: do { if ((fd) < 16) dup2mask |= (1<<((fd)+16)); } while (/*CONSTCOND*/0)
250: #define CLRDUP2ALIAS(fd) \
251: do { if ((fd) < 16) dup2mask &= ~(1<<((fd)+16)); } while (/*CONSTCOND*/0)
1.17 pooka 252:
253: //#define DEBUGJACK
254: #ifdef DEBUGJACK
255: #define DPRINTF(x) mydprintf x
256: static void
257: mydprintf(const char *fmt, ...)
258: {
259: va_list ap;
260:
261: if (ISDUP2D(STDERR_FILENO))
262: return;
263:
264: va_start(ap, fmt);
265: vfprintf(stderr, fmt, ap);
266: va_end(ap);
267: }
268:
269: #else
270: #define DPRINTF(x)
1.14 pooka 271: #endif
272:
1.17 pooka 273: #define FDCALL(type, name, rcname, args, proto, vars) \
274: type name args \
275: { \
276: type (*fun) proto; \
277: \
1.33 pooka 278: DPRINTF(("%s -> %d\n", __STRING(name), fd)); \
1.17 pooka 279: if (fd_isrump(fd)) { \
280: fun = syscalls[rcname].bs_rump; \
281: fd = fd_host2rump(fd); \
282: } else { \
283: fun = syscalls[rcname].bs_host; \
284: } \
285: \
286: return fun vars; \
287: }
288:
1.45 pooka 289: #define PATHCALL(type, name, rcname, args, proto, vars) \
290: type name args \
291: { \
292: type (*fun) proto; \
293: \
294: DPRINTF(("%s -> %s\n", __STRING(name), path)); \
295: if (path_isrump(path)) { \
296: fun = syscalls[rcname].bs_rump; \
297: path = path_host2rump(path); \
298: } else { \
299: fun = syscalls[rcname].bs_host; \
300: } \
301: \
302: return fun vars; \
303: }
304:
1.14 pooka 305: /*
1.49 pooka 306: * This tracks if our process is in a subdirectory of /rump.
307: * It's preserved over exec.
308: */
309: static bool pwdinrump = false;
310:
311: /*
312: * These variables are set from the RUMPHIJACK string and control
313: * which operations can product rump kernel file descriptors.
314: * This should be easily extendable for future needs.
315: */
316: #define RUMPHIJACK_DEFAULT "path=/rump,socket=all:nolocal"
317: static bool rumpsockets[PF_MAX];
318: static const char *rumpprefix;
319: static size_t rumpprefixlen;
320:
321: static struct {
322: int pf;
323: const char *name;
324: } socketmap[] = {
1.51 pooka 325: { PF_LOCAL, "local" },
1.49 pooka 326: { PF_INET, "inet" },
327: { PF_LINK, "link" },
1.55 pooka 328: #ifdef PF_OROUTE
1.56 pooka 329: { PF_OROUTE, "oroute" },
330: #endif
1.49 pooka 331: { PF_ROUTE, "route" },
332: { PF_INET6, "inet6" },
1.55 pooka 333: #ifdef PF_MPLS
334: { PF_MPLS, "mpls" },
335: #endif
1.49 pooka 336: { -1, NULL }
337: };
338:
339: static void
340: sockparser(char *buf)
341: {
342: char *p, *l;
343: bool value;
344: int i;
345:
346: /* if "all" is present, it must be specified first */
347: if (strncmp(buf, "all", strlen("all")) == 0) {
1.50 pooka 348: for (i = 0; i < (int)__arraycount(rumpsockets); i++) {
1.49 pooka 349: rumpsockets[i] = true;
350: }
351: buf += strlen("all");
352: if (*buf == ':')
353: buf++;
354: }
355:
356: for (p = strtok_r(buf, ":", &l); p; p = strtok_r(NULL, ":", &l)) {
357: value = true;
358: if (strncmp(p, "no", strlen("no")) == 0) {
359: value = false;
360: p += strlen("no");
361: }
1.45 pooka 362:
1.49 pooka 363: for (i = 0; socketmap[i].name; i++) {
364: if (strcmp(p, socketmap[i].name) == 0) {
365: rumpsockets[socketmap[i].pf] = value;
366: break;
367: }
368: }
369: if (socketmap[i].name == NULL) {
370: warnx("invalid socket specifier %s", p);
371: }
372: }
373: }
374:
375: static void
376: pathparser(char *buf)
377: {
378:
1.57 pooka 379: /* sanity-check */
1.49 pooka 380: if (*buf != '/')
381: errx(1, "hijack path specifier must begin with ``/''");
1.57 pooka 382: rumpprefixlen = strlen(buf);
383: if (rumpprefixlen < 2)
384: errx(1, "invalid hijack prefix: %s", buf);
385: if (buf[rumpprefixlen-1] == '/' && strspn(buf, "/") != rumpprefixlen)
386: errx(1, "hijack prefix may end in slash only if pure "
387: "slash, gave %s", buf);
1.49 pooka 388:
389: if ((rumpprefix = strdup(buf)) == NULL)
390: err(1, "strdup");
391: rumpprefixlen = strlen(rumpprefix);
392: }
393:
394: static struct {
395: void (*parsefn)(char *);
396: const char *name;
397: } hijackparse[] = {
398: { sockparser, "socket" },
399: { pathparser, "path" },
400: { NULL, NULL },
401: };
402:
403: static void
404: parsehijack(char *hijack)
405: {
406: char *p, *p2, *l;
407: const char *hijackcopy;
408: int i;
409:
410: if ((hijackcopy = strdup(hijack)) == NULL)
411: err(1, "strdup");
412:
413: /* disable everything explicitly */
414: for (i = 0; i < PF_MAX; i++)
415: rumpsockets[i] = false;
416:
417: for (p = strtok_r(hijack, ",", &l); p; p = strtok_r(NULL, ",", &l)) {
418: p2 = strchr(p, '=');
419: if (!p2)
420: errx(1, "invalid hijack specifier: %s", hijackcopy);
421:
422: for (i = 0; hijackparse[i].parsefn; i++) {
423: if (strncmp(hijackparse[i].name, p,
424: (size_t)(p2-p)) == 0) {
425: hijackparse[i].parsefn(p2+1);
426: break;
427: }
428: }
429: }
430:
431: }
1.7 pooka 432:
1.1 pooka 433: static void __attribute__((constructor))
434: rcinit(void)
435: {
1.49 pooka 436: char buf[1024];
1.19 pooka 437: unsigned i, j;
1.1 pooka 438:
1.17 pooka 439: host_fork = dlsym(RTLD_NEXT, "fork");
1.25 pooka 440: host_daemon = dlsym(RTLD_NEXT, "daemon");
1.39 pooka 441: host_execve = dlsym(RTLD_NEXT, "execve");
1.62 pooka 442: host_mmap = dlsym(RTLD_NEXT, "mmap");
1.17 pooka 443:
444: /*
445: * In theory cannot print anything during lookups because
446: * we might not have the call vector set up. so, the errx()
447: * is a bit of a strech, but it might work.
448: */
1.1 pooka 449:
1.17 pooka 450: for (i = 0; i < DUALCALL__NUM; i++) {
451: /* build runtime O(1) access */
452: for (j = 0; j < __arraycount(syscnames); j++) {
453: if (syscnames[j].scm_callnum == i)
454: break;
455: }
456:
457: if (j == __arraycount(syscnames))
458: errx(1, "rumphijack error: syscall pos %d missing", i);
459:
1.23 pooka 460: syscalls[i].bs_host = dlsym(RTLD_NEXT,
461: syscnames[j].scm_hostname);
1.17 pooka 462: if (syscalls[i].bs_host == NULL)
463: errx(1, "hostcall %s not found missing",
464: syscnames[j].scm_hostname);
465:
1.23 pooka 466: syscalls[i].bs_rump = dlsym(RTLD_NEXT,
467: syscnames[j].scm_rumpname);
1.17 pooka 468: if (syscalls[i].bs_rump == NULL)
469: errx(1, "rumpcall %s not found missing",
470: syscnames[j].scm_rumpname);
1.1 pooka 471: }
472:
1.22 pooka 473: if (rumpclient_init() == -1)
1.1 pooka 474: err(1, "rumpclient init");
1.28 pooka 475:
1.49 pooka 476: /* check which syscalls we're supposed to hijack */
477: if (getenv_r("RUMPHIJACK", buf, sizeof(buf)) == -1) {
478: strcpy(buf, RUMPHIJACK_DEFAULT);
479: }
480: parsehijack(buf);
481:
1.28 pooka 482: /* set client persistence level */
1.44 pooka 483: if (getenv_r("RUMPHIJACK_RETRYCONNECT", buf, sizeof(buf)) != -1) {
1.28 pooka 484: if (strcmp(buf, "die") == 0)
485: rumpclient_setconnretry(RUMPCLIENT_RETRYCONN_DIE);
486: else if (strcmp(buf, "inftime") == 0)
487: rumpclient_setconnretry(RUMPCLIENT_RETRYCONN_INFTIME);
488: else if (strcmp(buf, "once") == 0)
489: rumpclient_setconnretry(RUMPCLIENT_RETRYCONN_ONCE);
490: else {
491: time_t timeout;
1.44 pooka 492: char *ep;
1.28 pooka 493:
1.44 pooka 494: timeout = (time_t)strtoll(buf, &ep, 10);
495: if (timeout <= 0 || ep != buf + strlen(buf))
496: errx(1, "RUMPHIJACK_RETRYCONNECT must be "
497: "keyword or integer, got: %s", buf);
1.28 pooka 498:
499: rumpclient_setconnretry(timeout);
500: }
501: }
1.39 pooka 502:
503: if (getenv_r("RUMPHIJACK__DUP2MASK", buf, sizeof(buf)) == 0) {
1.40 pooka 504: dup2mask = strtoul(buf, NULL, 10);
1.45 pooka 505: unsetenv("RUMPHIJACK__DUP2MASK");
506: }
507: if (getenv_r("RUMPHIJACK__PWDINRUMP", buf, sizeof(buf)) == 0) {
1.49 pooka 508: pwdinrump = true;
1.45 pooka 509: unsetenv("RUMPHIJACK__PWDINRUMP");
1.39 pooka 510: }
1.1 pooka 511: }
512:
1.2 pooka 513: /* XXX: need runtime selection. low for now due to FD_SETSIZE */
514: #define HIJACK_FDOFF 128
515: static int
516: fd_rump2host(int fd)
517: {
518:
519: if (fd == -1)
520: return fd;
521:
522: if (!ISDUP2D(fd))
523: fd += HIJACK_FDOFF;
524:
525: return fd;
526: }
527:
528: static int
529: fd_host2rump(int fd)
530: {
531:
532: if (!ISDUP2D(fd))
533: fd -= HIJACK_FDOFF;
534: return fd;
535: }
536:
537: static bool
538: fd_isrump(int fd)
539: {
540:
541: return ISDUP2D(fd) || fd >= HIJACK_FDOFF;
542: }
543:
1.40 pooka 544: #define assertfd(_fd_) assert(ISDUP2D(_fd_) || (_fd_) >= HIJACK_FDOFF)
545:
1.49 pooka 546: static bool
1.45 pooka 547: path_isrump(const char *path)
548: {
549:
1.49 pooka 550: if (rumpprefix == NULL)
551: return false;
552:
1.45 pooka 553: if (*path == '/') {
1.49 pooka 554: if (strncmp(path, rumpprefix, rumpprefixlen) == 0)
555: return true;
556: return false;
1.45 pooka 557: } else {
558: return pwdinrump;
559: }
560: }
561:
562: static const char *rootpath = "/";
563: static const char *
564: path_host2rump(const char *path)
565: {
566: const char *rv;
567:
568: if (*path == '/') {
1.49 pooka 569: rv = path + rumpprefixlen;
1.45 pooka 570: if (*rv == '\0')
571: rv = rootpath;
572: } else {
573: rv = path;
574: }
575:
576: return rv;
577: }
578:
1.40 pooka 579: static int
580: dodup(int oldd, int minfd)
581: {
582: int (*op_fcntl)(int, int, ...);
583: int newd;
584: int isrump;
585:
586: DPRINTF(("dup -> %d (minfd %d)\n", oldd, minfd));
587: if (fd_isrump(oldd)) {
588: op_fcntl = GETSYSCALL(rump, FCNTL);
589: oldd = fd_host2rump(oldd);
1.63 pooka 590: if (minfd >= HIJACK_FDOFF)
591: minfd -= HIJACK_FDOFF;
1.40 pooka 592: isrump = 1;
593: } else {
594: op_fcntl = GETSYSCALL(host, FCNTL);
595: isrump = 0;
596: }
597:
598: newd = op_fcntl(oldd, F_DUPFD, minfd);
599:
600: if (isrump)
601: newd = fd_rump2host(newd);
602: DPRINTF(("dup <- %d\n", newd));
603:
604: return newd;
605: }
1.2 pooka 606:
1.47 pooka 607: /*
608: * dup a host file descriptor so that it doesn't collide with the dup2mask
609: */
610: static int
611: fd_dupgood(int fd)
612: {
613: int (*op_fcntl)(int, int, ...) = GETSYSCALL(host, FCNTL);
614: int (*op_close)(int) = GETSYSCALL(host, CLOSE);
615: int ofd, i;
616:
617: for (i = 1; ISDUP2D(fd); i++) {
618: ofd = fd;
619: fd = op_fcntl(ofd, F_DUPFD, i);
620: op_close(ofd);
621: }
622:
623: return fd;
624: }
625:
1.45 pooka 626: int
627: open(const char *path, int flags, ...)
628: {
629: int (*op_open)(const char *, int, ...);
630: bool isrump;
631: va_list ap;
632: int fd;
633:
634: if (path_isrump(path)) {
635: path = path_host2rump(path);
636: op_open = GETSYSCALL(rump, OPEN);
637: isrump = true;
638: } else {
639: op_open = GETSYSCALL(host, OPEN);
640: isrump = false;
641: }
642:
643: va_start(ap, flags);
644: fd = op_open(path, flags, va_arg(ap, mode_t));
645: va_end(ap);
646:
647: if (isrump)
648: fd = fd_rump2host(fd);
1.47 pooka 649: else
650: fd = fd_dupgood(fd);
1.45 pooka 651: return fd;
652: }
653:
654: int
655: chdir(const char *path)
656: {
657: int (*op_chdir)(const char *);
658: bool isrump;
659: int rv;
660:
661: if (path_isrump(path)) {
662: op_chdir = GETSYSCALL(rump, CHDIR);
663: isrump = true;
664: path = path_host2rump(path);
665: } else {
666: op_chdir = GETSYSCALL(host, CHDIR);
667: isrump = false;
668: }
669:
670: rv = op_chdir(path);
671: if (rv == 0) {
672: if (isrump)
673: pwdinrump = true;
674: else
675: pwdinrump = false;
676: }
677:
678: return rv;
679: }
680:
681: int
682: fchdir(int fd)
683: {
684: int (*op_fchdir)(int);
685: bool isrump;
686: int rv;
687:
688: if (fd_isrump(fd)) {
689: op_fchdir = GETSYSCALL(rump, FCHDIR);
690: isrump = true;
691: fd = fd_host2rump(fd);
692: } else {
693: op_fchdir = GETSYSCALL(host, FCHDIR);
694: isrump = false;
695: }
696:
697: rv = op_fchdir(fd);
698: if (rv == 0) {
699: if (isrump)
700: pwdinrump = true;
701: else
702: pwdinrump = false;
703: }
704:
705: return rv;
706: }
707:
1.52 pooka 708: int
1.57 pooka 709: __getcwd(char *bufp, size_t len)
710: {
711: int (*op___getcwd)(char *, size_t);
712: int rv;
713:
714: if (pwdinrump) {
715: size_t prefixgap;
716: bool iamslash;
717:
718: if (rumpprefix[rumpprefixlen-1] == '/')
719: iamslash = true;
720: else
721: iamslash = false;
722:
723: if (iamslash)
724: prefixgap = rumpprefixlen - 1; /* ``//+path'' */
725: else
726: prefixgap = rumpprefixlen; /* ``/pfx+/path'' */
727: if (len <= prefixgap) {
1.66 pooka 728: errno = ERANGE;
729: return -1;
1.57 pooka 730: }
731:
732: op___getcwd = GETSYSCALL(rump, __GETCWD);
733: rv = op___getcwd(bufp + prefixgap, len - prefixgap);
734: if (rv == -1)
735: return rv;
736:
737: /* augment the "/" part only for a non-root path */
738: memcpy(bufp, rumpprefix, rumpprefixlen);
739:
740: /* append / only to non-root cwd */
741: if (rv != 2)
742: bufp[prefixgap] = '/';
743:
744: /* don't append extra slash in the purely-slash case */
745: if (rv == 2 && !iamslash)
746: bufp[rumpprefixlen] = '\0';
747:
748: return rv;
749: } else {
750: op___getcwd = GETSYSCALL(host, __GETCWD);
751: return op___getcwd(bufp, len);
752: }
753: }
754:
755: int
1.52 pooka 756: rename(const char *from, const char *to)
757: {
758: int (*op_rename)(const char *, const char *);
759:
760: if (path_isrump(from)) {
1.66 pooka 761: if (!path_isrump(to)) {
762: errno = EXDEV;
763: return -1;
764: }
1.52 pooka 765:
766: from = path_host2rump(from);
767: to = path_host2rump(to);
768: op_rename = GETSYSCALL(rump, RENAME);
769: } else {
1.66 pooka 770: if (path_isrump(to)) {
771: errno = EXDEV;
772: return -1;
773: }
1.53 pooka 774:
1.52 pooka 775: op_rename = GETSYSCALL(host, RENAME);
776: }
777:
778: return op_rename(from, to);
779: }
780:
1.1 pooka 781: int __socket30(int, int, int);
782: int
783: __socket30(int domain, int type, int protocol)
784: {
1.17 pooka 785: int (*op_socket)(int, int, int);
1.1 pooka 786: int fd;
1.49 pooka 787: bool isrump;
1.7 pooka 788:
1.49 pooka 789: isrump = domain < PF_MAX && rumpsockets[domain];
1.1 pooka 790:
1.49 pooka 791: if (isrump)
792: op_socket = GETSYSCALL(rump, SOCKET);
793: else
1.17 pooka 794: op_socket = GETSYSCALL(host, SOCKET);
795: fd = op_socket(domain, type, protocol);
1.2 pooka 796:
1.49 pooka 797: if (isrump)
1.7 pooka 798: fd = fd_rump2host(fd);
1.47 pooka 799: else
800: fd = fd_dupgood(fd);
1.7 pooka 801: DPRINTF(("socket <- %d\n", fd));
1.2 pooka 802:
1.7 pooka 803: return fd;
1.1 pooka 804: }
805:
806: int
807: accept(int s, struct sockaddr *addr, socklen_t *addrlen)
808: {
1.17 pooka 809: int (*op_accept)(int, struct sockaddr *, socklen_t *);
1.1 pooka 810: int fd;
1.7 pooka 811: bool isrump;
812:
813: isrump = fd_isrump(s);
1.1 pooka 814:
1.2 pooka 815: DPRINTF(("accept -> %d", s));
1.7 pooka 816: if (isrump) {
1.17 pooka 817: op_accept = GETSYSCALL(rump, ACCEPT);
1.7 pooka 818: s = fd_host2rump(s);
819: } else {
1.17 pooka 820: op_accept = GETSYSCALL(host, ACCEPT);
1.7 pooka 821: }
1.17 pooka 822: fd = op_accept(s, addr, addrlen);
1.7 pooka 823: if (fd != -1 && isrump)
824: fd = fd_rump2host(fd);
1.47 pooka 825: else
826: fd = fd_dupgood(fd);
1.7 pooka 827:
828: DPRINTF((" <- %d\n", fd));
1.2 pooka 829:
1.7 pooka 830: return fd;
1.1 pooka 831: }
832:
1.17 pooka 833: /*
834: * ioctl and fcntl are varargs calls and need special treatment
835: */
1.1 pooka 836: int
1.17 pooka 837: ioctl(int fd, unsigned long cmd, ...)
1.1 pooka 838: {
1.17 pooka 839: int (*op_ioctl)(int, unsigned long cmd, ...);
840: va_list ap;
841: int rv;
1.1 pooka 842:
1.17 pooka 843: DPRINTF(("ioctl -> %d\n", fd));
844: if (fd_isrump(fd)) {
845: fd = fd_host2rump(fd);
846: op_ioctl = GETSYSCALL(rump, IOCTL);
1.7 pooka 847: } else {
1.17 pooka 848: op_ioctl = GETSYSCALL(host, IOCTL);
1.7 pooka 849: }
1.1 pooka 850:
1.17 pooka 851: va_start(ap, cmd);
852: rv = op_ioctl(fd, cmd, va_arg(ap, void *));
853: va_end(ap);
854: return rv;
1.1 pooka 855: }
856:
1.40 pooka 857: #include <syslog.h>
1.1 pooka 858: int
1.17 pooka 859: fcntl(int fd, int cmd, ...)
1.1 pooka 860: {
1.17 pooka 861: int (*op_fcntl)(int, int, ...);
862: va_list ap;
1.40 pooka 863: int rv, minfd, i;
864:
865: DPRINTF(("fcntl -> %d (cmd %d)\n", fd, cmd));
866:
867: switch (cmd) {
868: case F_DUPFD:
869: va_start(ap, cmd);
870: minfd = va_arg(ap, int);
871: va_end(ap);
872: return dodup(fd, minfd);
873:
874: case F_CLOSEM:
875: /*
876: * So, if fd < HIJACKOFF, we want to do a host closem.
877: */
878:
879: if (fd < HIJACK_FDOFF) {
880: int closemfd = fd;
1.1 pooka 881:
1.40 pooka 882: if (rumpclient__closenotify(&closemfd,
1.39 pooka 883: RUMPCLIENT_CLOSE_FCLOSEM) == -1)
884: return -1;
1.40 pooka 885: op_fcntl = GETSYSCALL(host, FCNTL);
886: rv = op_fcntl(closemfd, cmd);
887: if (rv)
888: return rv;
889: }
890:
891: /*
892: * Additionally, we want to do a rump closem, but only
893: * for the file descriptors not within the dup2mask.
894: */
895:
896: /* why don't we offer fls()? */
1.47 pooka 897: for (i = 15; i >= 0; i--) {
898: if (ISDUP2D(i))
1.40 pooka 899: break;
900: }
901:
902: if (fd >= HIJACK_FDOFF)
903: fd -= HIJACK_FDOFF;
904: else
905: fd = 0;
906: fd = MAX(i+1, fd);
907:
908: /* hmm, maybe we should close rump fd's not within dup2mask? */
909:
910: return rump_sys_fcntl(fd, F_CLOSEM);
911:
912: case F_MAXFD:
913: /*
914: * For maxfd, if there's a rump kernel fd, return
915: * it hostified. Otherwise, return host's MAXFD
916: * return value.
917: */
918: if ((rv = rump_sys_fcntl(fd, F_MAXFD)) != -1) {
919: /*
920: * This might go a little wrong in case
921: * of dup2 to [012], but I'm not sure if
922: * there's a justification for tracking
923: * that info. Consider e.g.
924: * dup2(rumpfd, 2) followed by rump_sys_open()
925: * returning 1. We should return 1+HIJACKOFF,
926: * not 2+HIJACKOFF. However, if [01] is not
927: * open, the correct return value is 2.
928: */
929: return fd_rump2host(fd);
930: } else {
931: op_fcntl = GETSYSCALL(host, FCNTL);
932: return op_fcntl(fd, F_MAXFD);
933: }
934: /*NOTREACHED*/
935:
936: default:
937: if (fd_isrump(fd)) {
938: fd = fd_host2rump(fd);
939: op_fcntl = GETSYSCALL(rump, FCNTL);
940: } else {
941: op_fcntl = GETSYSCALL(host, FCNTL);
942: }
943:
944: va_start(ap, cmd);
945: rv = op_fcntl(fd, cmd, va_arg(ap, void *));
946: va_end(ap);
947: return rv;
1.7 pooka 948: }
1.40 pooka 949: /*NOTREACHED*/
1.1 pooka 950: }
951:
1.39 pooka 952: int
953: close(int fd)
954: {
955: int (*op_close)(int);
956: int rv;
957:
958: DPRINTF(("close -> %d\n", fd));
959: if (fd_isrump(fd)) {
960: int undup2 = 0;
961:
1.47 pooka 962: fd = fd_host2rump(fd);
963: if (ISDUP2ALIAS(fd)) {
964: _DIAGASSERT(ISDUP2D(fd));
965: CLRDUP2ALIAS(fd);
966: return 0;
967: }
968:
1.39 pooka 969: if (ISDUP2D(fd))
970: undup2 = 1;
971: op_close = GETSYSCALL(rump, CLOSE);
972: rv = op_close(fd);
973: if (rv == 0 && undup2)
1.40 pooka 974: CLRDUP2(fd);
1.39 pooka 975: } else {
976: if (rumpclient__closenotify(&fd, RUMPCLIENT_CLOSE_CLOSE) == -1)
977: return -1;
978: op_close = GETSYSCALL(host, CLOSE);
979: rv = op_close(fd);
980: }
981:
982: return rv;
983: }
984:
1.17 pooka 985: /*
986: * write cannot issue a standard debug printf due to recursion
987: */
1.1 pooka 988: ssize_t
1.17 pooka 989: write(int fd, const void *buf, size_t blen)
1.1 pooka 990: {
1.17 pooka 991: ssize_t (*op_write)(int, const void *, size_t);
1.1 pooka 992:
1.17 pooka 993: if (fd_isrump(fd)) {
994: fd = fd_host2rump(fd);
995: op_write = GETSYSCALL(rump, WRITE);
1.16 pooka 996: } else {
1.17 pooka 997: op_write = GETSYSCALL(host, WRITE);
1.16 pooka 998: }
1.1 pooka 999:
1.17 pooka 1000: return op_write(fd, buf, blen);
1.2 pooka 1001: }
1002:
1003: /*
1004: * dup2 is special. we allow dup2 of a rump kernel fd to 0-2 since
1005: * many programs do that. dup2 of a rump kernel fd to another value
1006: * not >= fdoff is an error.
1007: *
1008: * Note: cannot rump2host newd, because it is often hardcoded.
1009: */
1010: int
1011: dup2(int oldd, int newd)
1012: {
1.17 pooka 1013: int (*host_dup2)(int, int);
1.2 pooka 1014: int rv;
1015:
1016: DPRINTF(("dup2 -> %d (o) -> %d (n)\n", oldd, newd));
1017:
1018: if (fd_isrump(oldd)) {
1.66 pooka 1019: if (!(newd >= 0 && newd <= 2)) {
1020: errno = EBADF;
1021: return -1;
1022: }
1.2 pooka 1023: oldd = fd_host2rump(oldd);
1.47 pooka 1024: if (oldd == newd) {
1025: SETDUP2(newd);
1026: SETDUP2ALIAS(newd);
1027: return newd;
1028: }
1.2 pooka 1029: rv = rump_sys_dup2(oldd, newd);
1030: if (rv != -1)
1.40 pooka 1031: SETDUP2(newd);
1.2 pooka 1032: } else {
1.17 pooka 1033: host_dup2 = syscalls[DUALCALL_DUP2].bs_host;
1.39 pooka 1034: if (rumpclient__closenotify(&newd, RUMPCLIENT_CLOSE_DUP2) == -1)
1035: return -1;
1.10 pooka 1036: rv = host_dup2(oldd, newd);
1.2 pooka 1037: }
1.10 pooka 1038:
1039: return rv;
1.2 pooka 1040: }
1041:
1.34 pooka 1042: int
1043: dup(int oldd)
1044: {
1045:
1.40 pooka 1046: return dodup(oldd, 0);
1.34 pooka 1047: }
1048:
1.2 pooka 1049: pid_t
1050: fork()
1051: {
1052: pid_t rv;
1053:
1054: DPRINTF(("fork\n"));
1055:
1.43 pooka 1056: rv = rumpclient__dofork(host_fork);
1.2 pooka 1057:
1058: DPRINTF(("fork returns %d\n", rv));
1059: return rv;
1.1 pooka 1060: }
1.43 pooka 1061: /* we do not have the luxury of not requiring a stackframe */
1062: __strong_alias(__vfork14,fork);
1.1 pooka 1063:
1.25 pooka 1064: int
1065: daemon(int nochdir, int noclose)
1066: {
1067: struct rumpclient_fork *rf;
1068:
1069: if ((rf = rumpclient_prefork()) == NULL)
1070: return -1;
1071:
1072: if (host_daemon(nochdir, noclose) == -1)
1073: return -1;
1074:
1075: if (rumpclient_fork_init(rf) == -1)
1076: return -1;
1077:
1078: return 0;
1079: }
1080:
1.39 pooka 1081: int
1.42 pooka 1082: execve(const char *path, char *const argv[], char *const envp[])
1.39 pooka 1083: {
1084: char buf[128];
1085: char *dup2str;
1.49 pooka 1086: const char *pwdinrumpstr;
1.42 pooka 1087: char **newenv;
1088: size_t nelem;
1089: int rv, sverrno;
1.45 pooka 1090: int bonus = 1, i = 0;
1091:
1092: if (dup2mask) {
1093: snprintf(buf, sizeof(buf), "RUMPHIJACK__DUP2MASK=%u", dup2mask);
1094: dup2str = malloc(strlen(buf)+1);
1.66 pooka 1095: if (dup2str == NULL) {
1096: errno = ENOMEM;
1097: return -1;
1098: }
1.45 pooka 1099: strcpy(dup2str, buf);
1100: bonus++;
1101: } else {
1102: dup2str = NULL;
1103: }
1.39 pooka 1104:
1.45 pooka 1105: if (pwdinrump) {
1.49 pooka 1106: pwdinrumpstr = "RUMPHIJACK__PWDINRUMP=true";
1.45 pooka 1107: bonus++;
1108: } else {
1109: pwdinrumpstr = NULL;
1110: }
1.39 pooka 1111:
1.42 pooka 1112: for (nelem = 0; envp && envp[nelem]; nelem++)
1113: continue;
1.45 pooka 1114: newenv = malloc(sizeof(*newenv) * nelem+bonus);
1.42 pooka 1115: if (newenv == NULL) {
1.39 pooka 1116: free(dup2str);
1.66 pooka 1117: errno = ENOMEM;
1118: return -1;
1.39 pooka 1119: }
1.42 pooka 1120: memcpy(newenv, envp, nelem*sizeof(*newenv));
1.45 pooka 1121: if (dup2str) {
1122: newenv[nelem+i] = dup2str;
1123: i++;
1124: }
1125: if (pwdinrumpstr) {
1.49 pooka 1126: newenv[nelem+i] = __UNCONST(pwdinrumpstr);
1.45 pooka 1127: i++;
1128: }
1129: newenv[nelem+i] = NULL;
1130: _DIAGASSERT(i < bonus);
1.42 pooka 1131:
1132: rv = rumpclient_exec(path, argv, newenv);
1133:
1134: _DIAGASSERT(rv != 0);
1135: sverrno = errno;
1136: free(newenv);
1137: free(dup2str);
1138: errno = sverrno;
1.39 pooka 1139: return rv;
1140: }
1141:
1.1 pooka 1142: /*
1.17 pooka 1143: * select is done by calling poll.
1.1 pooka 1144: */
1145: int
1.29 pooka 1146: REALSELECT(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
1.4 pooka 1147: struct timeval *timeout)
1.1 pooka 1148: {
1.4 pooka 1149: struct pollfd *pfds;
1150: struct timespec ts, *tsp = NULL;
1.19 pooka 1151: nfds_t realnfds;
1152: int i, j;
1.4 pooka 1153: int rv, incr;
1154:
1.7 pooka 1155: DPRINTF(("select\n"));
1156:
1.4 pooka 1157: /*
1158: * Well, first we must scan the fds to figure out how many
1159: * fds there really are. This is because up to and including
1.17 pooka 1160: * nb5 poll() silently refuses nfds > process_maxopen_fds.
1.4 pooka 1161: * Seems to be fixed in current, thank the maker.
1162: * god damn cluster...bomb.
1163: */
1164:
1165: for (i = 0, realnfds = 0; i < nfds; i++) {
1166: if (readfds && FD_ISSET(i, readfds)) {
1167: realnfds++;
1168: continue;
1169: }
1170: if (writefds && FD_ISSET(i, writefds)) {
1171: realnfds++;
1172: continue;
1173: }
1174: if (exceptfds && FD_ISSET(i, exceptfds)) {
1175: realnfds++;
1176: continue;
1.1 pooka 1177: }
1178: }
1179:
1.6 pooka 1180: if (realnfds) {
1.38 pooka 1181: pfds = calloc(realnfds, sizeof(*pfds));
1.6 pooka 1182: if (!pfds)
1183: return -1;
1184: } else {
1185: pfds = NULL;
1186: }
1.1 pooka 1187:
1.4 pooka 1188: for (i = 0, j = 0; i < nfds; i++) {
1189: incr = 0;
1190: if (readfds && FD_ISSET(i, readfds)) {
1191: pfds[j].fd = i;
1192: pfds[j].events |= POLLIN;
1193: incr=1;
1194: }
1195: if (writefds && FD_ISSET(i, writefds)) {
1196: pfds[j].fd = i;
1197: pfds[j].events |= POLLOUT;
1198: incr=1;
1199: }
1200: if (exceptfds && FD_ISSET(i, exceptfds)) {
1201: pfds[j].fd = i;
1202: pfds[j].events |= POLLHUP|POLLERR;
1203: incr=1;
1.1 pooka 1204: }
1.4 pooka 1205: if (incr)
1206: j++;
1.1 pooka 1207: }
1.37 pooka 1208: assert(j == (int)realnfds);
1.1 pooka 1209:
1.4 pooka 1210: if (timeout) {
1211: TIMEVAL_TO_TIMESPEC(timeout, &ts);
1212: tsp = &ts;
1213: }
1.29 pooka 1214: rv = REALPOLLTS(pfds, realnfds, tsp, NULL);
1.36 pooka 1215: /*
1216: * "If select() returns with an error the descriptor sets
1217: * will be unmodified"
1218: */
1219: if (rv < 0)
1.4 pooka 1220: goto out;
1221:
1222: /*
1.36 pooka 1223: * zero out results (can't use FD_ZERO for the
1224: * obvious select-me-not reason). whee.
1225: *
1226: * We do this here since some software ignores the return
1227: * value of select, and hence if the timeout expires, it may
1228: * assume all input descriptors have activity.
1.4 pooka 1229: */
1230: for (i = 0; i < nfds; i++) {
1231: if (readfds)
1232: FD_CLR(i, readfds);
1233: if (writefds)
1234: FD_CLR(i, writefds);
1235: if (exceptfds)
1236: FD_CLR(i, exceptfds);
1.1 pooka 1237: }
1.36 pooka 1238: if (rv == 0)
1239: goto out;
1.1 pooka 1240:
1.36 pooka 1241: /*
1242: * We have >0 fds with activity. Harvest the results.
1243: */
1.19 pooka 1244: for (i = 0; i < (int)realnfds; i++) {
1.4 pooka 1245: if (readfds) {
1246: if (pfds[i].revents & POLLIN) {
1247: FD_SET(pfds[i].fd, readfds);
1248: }
1249: }
1250: if (writefds) {
1251: if (pfds[i].revents & POLLOUT) {
1252: FD_SET(pfds[i].fd, writefds);
1253: }
1254: }
1255: if (exceptfds) {
1256: if (pfds[i].revents & (POLLHUP|POLLERR)) {
1257: FD_SET(pfds[i].fd, exceptfds);
1258: }
1259: }
1.1 pooka 1260: }
1261:
1.4 pooka 1262: out:
1263: free(pfds);
1.1 pooka 1264: return rv;
1265: }
1266:
1267: static void
1268: checkpoll(struct pollfd *fds, nfds_t nfds, int *hostcall, int *rumpcall)
1269: {
1270: nfds_t i;
1271:
1272: for (i = 0; i < nfds; i++) {
1.12 pooka 1273: if (fds[i].fd == -1)
1274: continue;
1275:
1.2 pooka 1276: if (fd_isrump(fds[i].fd))
1277: (*rumpcall)++;
1278: else
1.1 pooka 1279: (*hostcall)++;
1280: }
1281: }
1282:
1283: static void
1.2 pooka 1284: adjustpoll(struct pollfd *fds, nfds_t nfds, int (*fdadj)(int))
1.1 pooka 1285: {
1286: nfds_t i;
1287:
1288: for (i = 0; i < nfds; i++) {
1.2 pooka 1289: fds[i].fd = fdadj(fds[i].fd);
1.1 pooka 1290: }
1291: }
1292:
1293: /*
1294: * poll is easy as long as the call comes in the fds only in one
1295: * kernel. otherwise its quite tricky...
1296: */
1297: struct pollarg {
1298: struct pollfd *pfds;
1299: nfds_t nfds;
1.3 pooka 1300: const struct timespec *ts;
1301: const sigset_t *sigmask;
1.1 pooka 1302: int pipefd;
1303: int errnum;
1304: };
1305:
1306: static void *
1307: hostpoll(void *arg)
1308: {
1.17 pooka 1309: int (*op_pollts)(struct pollfd *, nfds_t, const struct timespec *,
1310: const sigset_t *);
1.1 pooka 1311: struct pollarg *parg = arg;
1312: intptr_t rv;
1313:
1.35 pooka 1314: op_pollts = GETSYSCALL(host, POLLTS);
1.17 pooka 1315: rv = op_pollts(parg->pfds, parg->nfds, parg->ts, parg->sigmask);
1.1 pooka 1316: if (rv == -1)
1317: parg->errnum = errno;
1318: rump_sys_write(parg->pipefd, &rv, sizeof(rv));
1319:
1320: return (void *)(intptr_t)rv;
1321: }
1322:
1323: int
1.29 pooka 1324: REALPOLLTS(struct pollfd *fds, nfds_t nfds, const struct timespec *ts,
1.3 pooka 1325: const sigset_t *sigmask)
1.1 pooka 1326: {
1.3 pooka 1327: int (*op_pollts)(struct pollfd *, nfds_t, const struct timespec *,
1328: const sigset_t *);
1.17 pooka 1329: int (*host_close)(int);
1.1 pooka 1330: int hostcall = 0, rumpcall = 0;
1331: pthread_t pt;
1332: nfds_t i;
1333: int rv;
1334:
1.2 pooka 1335: DPRINTF(("poll\n"));
1.1 pooka 1336: checkpoll(fds, nfds, &hostcall, &rumpcall);
1337:
1338: if (hostcall && rumpcall) {
1339: struct pollfd *pfd_host = NULL, *pfd_rump = NULL;
1340: int rpipe[2] = {-1,-1}, hpipe[2] = {-1,-1};
1341: struct pollarg parg;
1342: uintptr_t lrv;
1343: int sverrno = 0, trv;
1344:
1345: /*
1346: * ok, this is where it gets tricky. We must support
1347: * this since it's a very common operation in certain
1348: * types of software (telnet, netcat, etc). We allocate
1349: * two vectors and run two poll commands in separate
1350: * threads. Whichever returns first "wins" and the
1351: * other kernel's fds won't show activity.
1352: */
1353: rv = -1;
1354:
1355: /* allocate full vector for O(n) joining after call */
1356: pfd_host = malloc(sizeof(*pfd_host)*(nfds+1));
1357: if (!pfd_host)
1358: goto out;
1359: pfd_rump = malloc(sizeof(*pfd_rump)*(nfds+1));
1360: if (!pfd_rump) {
1361: goto out;
1362: }
1363:
1.59 pooka 1364: /*
1365: * then, open two pipes, one for notifications
1366: * to each kernel.
1367: */
1368: if ((rv = rump_sys_pipe(rpipe)) == -1) {
1369: sverrno = errno;
1370: }
1371: if (rv == 0 && (rv = pipe(hpipe)) == -1) {
1372: sverrno = errno;
1373: }
1374:
1375: /* split vectors (or signal errors) */
1.1 pooka 1376: for (i = 0; i < nfds; i++) {
1.59 pooka 1377: int fd;
1378:
1379: fds[i].revents = 0;
1.3 pooka 1380: if (fds[i].fd == -1) {
1381: pfd_host[i].fd = -1;
1382: pfd_rump[i].fd = -1;
1383: } else if (fd_isrump(fds[i].fd)) {
1.2 pooka 1384: pfd_host[i].fd = -1;
1.59 pooka 1385: fd = fd_host2rump(fds[i].fd);
1386: if (fd == rpipe[0] || fd == rpipe[1]) {
1387: fds[i].revents = POLLNVAL;
1388: if (rv != -1)
1389: rv++;
1390: }
1391: pfd_rump[i].fd = fd;
1.2 pooka 1392: pfd_rump[i].events = fds[i].events;
1393: } else {
1394: pfd_rump[i].fd = -1;
1.59 pooka 1395: fd = fds[i].fd;
1396: if (fd == hpipe[0] || fd == hpipe[1]) {
1397: fds[i].revents = POLLNVAL;
1398: if (rv != -1)
1399: rv++;
1400: }
1401: pfd_host[i].fd = fd;
1.1 pooka 1402: pfd_host[i].events = fds[i].events;
1403: }
1.39 pooka 1404: pfd_rump[i].revents = pfd_host[i].revents = 0;
1.1 pooka 1405: }
1.59 pooka 1406: if (rv) {
1.1 pooka 1407: goto out;
1.59 pooka 1408: }
1.1 pooka 1409:
1410: pfd_host[nfds].fd = hpipe[0];
1411: pfd_host[nfds].events = POLLIN;
1412: pfd_rump[nfds].fd = rpipe[0];
1413: pfd_rump[nfds].events = POLLIN;
1414:
1415: /*
1416: * then, create a thread to do host part and meanwhile
1417: * do rump kernel part right here
1418: */
1419:
1420: parg.pfds = pfd_host;
1421: parg.nfds = nfds+1;
1.3 pooka 1422: parg.ts = ts;
1423: parg.sigmask = sigmask;
1.1 pooka 1424: parg.pipefd = rpipe[1];
1425: pthread_create(&pt, NULL, hostpoll, &parg);
1426:
1.35 pooka 1427: op_pollts = GETSYSCALL(rump, POLLTS);
1.3 pooka 1428: lrv = op_pollts(pfd_rump, nfds+1, ts, NULL);
1.1 pooka 1429: sverrno = errno;
1430: write(hpipe[1], &rv, sizeof(rv));
1431: pthread_join(pt, (void *)&trv);
1432:
1433: /* check who "won" and merge results */
1434: if (lrv != 0 && pfd_host[nfds].revents & POLLIN) {
1435: rv = trv;
1436:
1437: for (i = 0; i < nfds; i++) {
1438: if (pfd_rump[i].fd != -1)
1439: fds[i].revents = pfd_rump[i].revents;
1440: }
1441: sverrno = parg.errnum;
1442: } else if (trv != 0 && pfd_rump[nfds].revents & POLLIN) {
1443: rv = trv;
1444:
1445: for (i = 0; i < nfds; i++) {
1446: if (pfd_host[i].fd != -1)
1447: fds[i].revents = pfd_host[i].revents;
1448: }
1449: } else {
1450: rv = 0;
1451: }
1452:
1453: out:
1.35 pooka 1454: host_close = GETSYSCALL(host, CLOSE);
1.1 pooka 1455: if (rpipe[0] != -1)
1456: rump_sys_close(rpipe[0]);
1457: if (rpipe[1] != -1)
1458: rump_sys_close(rpipe[1]);
1459: if (hpipe[0] != -1)
1.9 pooka 1460: host_close(hpipe[0]);
1.1 pooka 1461: if (hpipe[1] != -1)
1.9 pooka 1462: host_close(hpipe[1]);
1.1 pooka 1463: free(pfd_host);
1464: free(pfd_rump);
1465: errno = sverrno;
1466: } else {
1467: if (hostcall) {
1.35 pooka 1468: op_pollts = GETSYSCALL(host, POLLTS);
1.1 pooka 1469: } else {
1.35 pooka 1470: op_pollts = GETSYSCALL(rump, POLLTS);
1.2 pooka 1471: adjustpoll(fds, nfds, fd_host2rump);
1.1 pooka 1472: }
1473:
1.3 pooka 1474: rv = op_pollts(fds, nfds, ts, sigmask);
1.1 pooka 1475: if (rumpcall)
1.2 pooka 1476: adjustpoll(fds, nfds, fd_rump2host);
1.1 pooka 1477: }
1478:
1479: return rv;
1480: }
1481:
1482: int
1.24 pooka 1483: poll(struct pollfd *fds, nfds_t nfds, int timeout)
1.1 pooka 1484: {
1.3 pooka 1485: struct timespec ts;
1486: struct timespec *tsp = NULL;
1487:
1488: if (timeout != INFTIM) {
1489: ts.tv_sec = timeout / 1000;
1.11 pooka 1490: ts.tv_nsec = (timeout % 1000) * 1000*1000;
1.3 pooka 1491:
1492: tsp = &ts;
1493: }
1.1 pooka 1494:
1.29 pooka 1495: return REALPOLLTS(fds, nfds, tsp, NULL);
1.1 pooka 1496: }
1.10 pooka 1497:
1498: int
1.34 pooka 1499: REALKEVENT(int kq, const struct kevent *changelist, size_t nchanges,
1500: struct kevent *eventlist, size_t nevents,
1501: const struct timespec *timeout)
1.10 pooka 1502: {
1.34 pooka 1503: int (*op_kevent)(int, const struct kevent *, size_t,
1504: struct kevent *, size_t, const struct timespec *);
1505: const struct kevent *ev;
1506: size_t i;
1.10 pooka 1507:
1.34 pooka 1508: /*
1509: * Check that we don't attempt to kevent rump kernel fd's.
1510: * That needs similar treatment to select/poll, but is slightly
1511: * trickier since we need to manage to different kq descriptors.
1512: * (TODO, in case you're wondering).
1513: */
1514: for (i = 0; i < nchanges; i++) {
1515: ev = &changelist[i];
1516: if (ev->filter == EVFILT_READ || ev->filter == EVFILT_WRITE ||
1517: ev->filter == EVFILT_VNODE) {
1.66 pooka 1518: if (fd_isrump((int)ev->ident)) {
1519: errno = ENOTSUP;
1520: return -1;
1521: }
1.34 pooka 1522: }
1.27 pooka 1523: }
1.10 pooka 1524:
1.35 pooka 1525: op_kevent = GETSYSCALL(host, KEVENT);
1.34 pooka 1526: return op_kevent(kq, changelist, nchanges, eventlist, nevents, timeout);
1.10 pooka 1527: }
1.17 pooka 1528:
1529: /*
1.62 pooka 1530: * mmapping from a rump kernel is not supported, so disallow it.
1531: */
1532: void *
1533: mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
1534: {
1535:
1536: if (flags & MAP_FILE && fd_isrump(fd)) {
1537: errno = ENOSYS;
1538: return MAP_FAILED;
1539: }
1540: return host_mmap(addr, len, prot, flags, fd, offset);
1541: }
1542:
1543: /*
1.17 pooka 1544: * Rest are std type calls.
1545: */
1546:
1547: FDCALL(int, bind, DUALCALL_BIND, \
1548: (int fd, const struct sockaddr *name, socklen_t namelen), \
1549: (int, const struct sockaddr *, socklen_t), \
1550: (fd, name, namelen))
1551:
1552: FDCALL(int, connect, DUALCALL_CONNECT, \
1553: (int fd, const struct sockaddr *name, socklen_t namelen), \
1554: (int, const struct sockaddr *, socklen_t), \
1555: (fd, name, namelen))
1556:
1557: FDCALL(int, getpeername, DUALCALL_GETPEERNAME, \
1558: (int fd, struct sockaddr *name, socklen_t *namelen), \
1559: (int, struct sockaddr *, socklen_t *), \
1560: (fd, name, namelen))
1561:
1562: FDCALL(int, getsockname, DUALCALL_GETSOCKNAME, \
1563: (int fd, struct sockaddr *name, socklen_t *namelen), \
1564: (int, struct sockaddr *, socklen_t *), \
1565: (fd, name, namelen))
1566:
1567: FDCALL(int, listen, DUALCALL_LISTEN, \
1568: (int fd, int backlog), \
1569: (int, int), \
1570: (fd, backlog))
1571:
1572: FDCALL(ssize_t, recvfrom, DUALCALL_RECVFROM, \
1573: (int fd, void *buf, size_t len, int flags, \
1574: struct sockaddr *from, socklen_t *fromlen), \
1575: (int, void *, size_t, int, struct sockaddr *, socklen_t *), \
1576: (fd, buf, len, flags, from, fromlen))
1577:
1578: FDCALL(ssize_t, sendto, DUALCALL_SENDTO, \
1579: (int fd, const void *buf, size_t len, int flags, \
1580: const struct sockaddr *to, socklen_t tolen), \
1581: (int, const void *, size_t, int, \
1582: const struct sockaddr *, socklen_t), \
1583: (fd, buf, len, flags, to, tolen))
1584:
1585: FDCALL(ssize_t, recvmsg, DUALCALL_RECVMSG, \
1586: (int fd, struct msghdr *msg, int flags), \
1587: (int, struct msghdr *, int), \
1588: (fd, msg, flags))
1589:
1590: FDCALL(ssize_t, sendmsg, DUALCALL_SENDMSG, \
1591: (int fd, const struct msghdr *msg, int flags), \
1592: (int, const struct msghdr *, int), \
1593: (fd, msg, flags))
1594:
1595: FDCALL(int, getsockopt, DUALCALL_GETSOCKOPT, \
1596: (int fd, int level, int optn, void *optval, socklen_t *optlen), \
1597: (int, int, int, void *, socklen_t *), \
1598: (fd, level, optn, optval, optlen))
1599:
1600: FDCALL(int, setsockopt, DUALCALL_SETSOCKOPT, \
1601: (int fd, int level, int optn, \
1602: const void *optval, socklen_t optlen), \
1603: (int, int, int, const void *, socklen_t), \
1604: (fd, level, optn, optval, optlen))
1605:
1606: FDCALL(int, shutdown, DUALCALL_SHUTDOWN, \
1607: (int fd, int how), \
1608: (int, int), \
1609: (fd, how))
1610:
1.21 christos 1611: #if _FORTIFY_SOURCE > 0
1612: #define STUB(fun) __ssp_weak_name(fun)
1613: ssize_t _sys_readlink(const char * __restrict, char * __restrict, size_t);
1614: ssize_t
1615: STUB(readlink)(const char * __restrict path, char * __restrict buf,
1616: size_t bufsiz)
1617: {
1618: return _sys_readlink(path, buf, bufsiz);
1619: }
1620:
1621: char *_sys_getcwd(char *, size_t);
1622: char *
1623: STUB(getcwd)(char *buf, size_t size)
1624: {
1625: return _sys_getcwd(buf, size);
1626: }
1627: #else
1628: #define STUB(fun) fun
1629: #endif
1630:
1.31 pooka 1631: FDCALL(ssize_t, REALREAD, DUALCALL_READ, \
1.17 pooka 1632: (int fd, void *buf, size_t buflen), \
1633: (int, void *, size_t), \
1634: (fd, buf, buflen))
1635:
1.18 pooka 1636: FDCALL(ssize_t, readv, DUALCALL_READV, \
1.17 pooka 1637: (int fd, const struct iovec *iov, int iovcnt), \
1638: (int, const struct iovec *, int), \
1639: (fd, iov, iovcnt))
1640:
1.60 pooka 1641: FDCALL(ssize_t, REALPREAD, DUALCALL_PREAD, \
1642: (int fd, void *buf, size_t nbytes, off_t offset), \
1643: (int, void *, size_t, off_t), \
1644: (fd, buf, nbytes, offset))
1645:
1646: FDCALL(ssize_t, preadv, DUALCALL_PREADV, \
1647: (int fd, const struct iovec *iov, int iovcnt, off_t offset), \
1648: (int, const struct iovec *, int, off_t), \
1649: (fd, iov, iovcnt, offset))
1650:
1.17 pooka 1651: FDCALL(ssize_t, writev, DUALCALL_WRITEV, \
1652: (int fd, const struct iovec *iov, int iovcnt), \
1653: (int, const struct iovec *, int), \
1654: (fd, iov, iovcnt))
1.45 pooka 1655:
1.60 pooka 1656: FDCALL(ssize_t, REALPWRITE, DUALCALL_PWRITE, \
1657: (int fd, const void *buf, size_t nbytes, off_t offset), \
1658: (int, const void *, size_t, off_t), \
1659: (fd, buf, nbytes, offset))
1660:
1661: FDCALL(ssize_t, pwritev, DUALCALL_PWRITEV, \
1662: (int fd, const struct iovec *iov, int iovcnt, off_t offset), \
1663: (int, const struct iovec *, int, off_t), \
1664: (fd, iov, iovcnt, offset))
1665:
1.45 pooka 1666: FDCALL(int, REALFSTAT, DUALCALL_FSTAT, \
1667: (int fd, struct stat *sb), \
1668: (int, struct stat *), \
1669: (fd, sb))
1670:
1671: FDCALL(int, fstatvfs1, DUALCALL_FSTATVFS1, \
1672: (int fd, struct statvfs *buf, int flags), \
1673: (int, struct statvfs *, int), \
1674: (fd, buf, flags))
1675:
1.61 pooka 1676: FDCALL(off_t, lseek, DUALCALL_LSEEK, \
1.45 pooka 1677: (int fd, off_t offset, int whence), \
1678: (int, off_t, int), \
1679: (fd, offset, whence))
1.61 pooka 1680: __strong_alias(_lseek,lseek);
1.45 pooka 1681:
1682: FDCALL(int, REALGETDENTS, DUALCALL_GETDENTS, \
1683: (int fd, char *buf, size_t nbytes), \
1684: (int, char *, size_t), \
1685: (fd, buf, nbytes))
1686:
1687: FDCALL(int, fchown, DUALCALL_FCHOWN, \
1688: (int fd, uid_t owner, gid_t group), \
1689: (int, uid_t, gid_t), \
1690: (fd, owner, group))
1691:
1692: FDCALL(int, fchmod, DUALCALL_FCHMOD, \
1693: (int fd, mode_t mode), \
1694: (int, mode_t), \
1695: (fd, mode))
1696:
1697: FDCALL(int, ftruncate, DUALCALL_FTRUNCATE, \
1698: (int fd, off_t length), \
1699: (int, off_t), \
1700: (fd, length))
1701:
1702: FDCALL(int, fsync, DUALCALL_FSYNC, \
1703: (int fd), \
1704: (int), \
1705: (fd))
1706:
1707: FDCALL(int, fsync_range, DUALCALL_FSYNC_RANGE, \
1708: (int fd, int how, off_t start, off_t length), \
1709: (int, int, off_t, off_t), \
1710: (fd, how, start, length))
1711:
1712: FDCALL(int, futimes, DUALCALL_FUTIMES, \
1713: (int fd, const struct timeval *tv), \
1714: (int, const struct timeval *), \
1715: (fd, tv))
1716:
1.60 pooka 1717: FDCALL(int, fchflags, DUALCALL_FCHFLAGS, \
1718: (int fd, u_long flags), \
1719: (int, u_long), \
1720: (fd, flags))
1721:
1.45 pooka 1722: /*
1723: * path-based selectors
1724: */
1725:
1726: PATHCALL(int, REALSTAT, DUALCALL_STAT, \
1727: (const char *path, struct stat *sb), \
1728: (const char *, struct stat *), \
1729: (path, sb))
1730:
1731: PATHCALL(int, REALLSTAT, DUALCALL_LSTAT, \
1732: (const char *path, struct stat *sb), \
1733: (const char *, struct stat *), \
1734: (path, sb))
1735:
1736: PATHCALL(int, chown, DUALCALL_CHOWN, \
1737: (const char *path, uid_t owner, gid_t group), \
1738: (const char *, uid_t, gid_t), \
1739: (path, owner, group))
1740:
1741: PATHCALL(int, lchown, DUALCALL_LCHOWN, \
1742: (const char *path, uid_t owner, gid_t group), \
1743: (const char *, uid_t, gid_t), \
1744: (path, owner, group))
1745:
1746: PATHCALL(int, chmod, DUALCALL_CHMOD, \
1747: (const char *path, mode_t mode), \
1748: (const char *, mode_t), \
1749: (path, mode))
1750:
1751: PATHCALL(int, lchmod, DUALCALL_LCHMOD, \
1752: (const char *path, mode_t mode), \
1753: (const char *, mode_t), \
1754: (path, mode))
1755:
1756: PATHCALL(int, statvfs1, DUALCALL_STATVFS1, \
1757: (const char *path, struct statvfs *buf, int flags), \
1758: (const char *, struct statvfs *, int), \
1759: (path, buf, flags))
1760:
1761: PATHCALL(int, unlink, DUALCALL_UNLINK, \
1762: (const char *path), \
1763: (const char *), \
1764: (path))
1765:
1766: PATHCALL(int, symlink, DUALCALL_SYMLINK, \
1.58 pooka 1767: (const char *target, const char *path), \
1.45 pooka 1768: (const char *, const char *), \
1.58 pooka 1769: (target, path))
1.45 pooka 1770:
1.46 pooka 1771: PATHCALL(ssize_t, readlink, DUALCALL_READLINK, \
1.45 pooka 1772: (const char *path, char *buf, size_t bufsiz), \
1773: (const char *, char *, size_t), \
1774: (path, buf, bufsiz))
1775:
1776: PATHCALL(int, mkdir, DUALCALL_MKDIR, \
1777: (const char *path, mode_t mode), \
1778: (const char *, mode_t), \
1779: (path, mode))
1780:
1781: PATHCALL(int, rmdir, DUALCALL_RMDIR, \
1782: (const char *path), \
1783: (const char *), \
1784: (path))
1785:
1786: PATHCALL(int, utimes, DUALCALL_UTIMES, \
1787: (const char *path, const struct timeval *tv), \
1788: (const char *, const struct timeval *), \
1789: (path, tv))
1790:
1791: PATHCALL(int, lutimes, DUALCALL_LUTIMES, \
1792: (const char *path, const struct timeval *tv), \
1793: (const char *, const struct timeval *), \
1794: (path, tv))
1795:
1.60 pooka 1796: PATHCALL(int, chflags, DUALCALL_CHFLAGS, \
1797: (const char *path, u_long flags), \
1798: (const char *, u_long), \
1799: (path, flags))
1800:
1801: PATHCALL(int, lchflags, DUALCALL_LCHFLAGS, \
1802: (const char *path, u_long flags), \
1803: (const char *, u_long), \
1804: (path, flags))
1805:
1.45 pooka 1806: PATHCALL(int, truncate, DUALCALL_TRUNCATE, \
1807: (const char *path, off_t length), \
1808: (const char *, off_t), \
1809: (path, length))
1.48 pooka 1810:
1.65 pooka 1811: PATHCALL(int, access, DUALCALL_ACCESS, \
1812: (const char *path, int mode), \
1813: (const char *, int), \
1814: (path, mode))
1815:
1.68 pooka 1816: PATHCALL(int, REALMKNOD, DUALCALL_MKNOD, \
1817: (const char *path, mode_t mode, dev_t dev), \
1818: (const char *, mode_t, dev_t), \
1819: (path, mode, dev))
1820:
1.48 pooka 1821: /*
1822: * Note: with mount the decisive parameter is the mount
1823: * destination directory. This is because we don't really know
1824: * about the "source" directory in a generic call (and besides,
1825: * it might not even exist, cf. nfs).
1826: */
1827: PATHCALL(int, REALMOUNT, DUALCALL_MOUNT, \
1828: (const char *type, const char *path, int flags, \
1829: void *data, size_t dlen), \
1830: (const char *, const char *, int, void *, size_t), \
1831: (type, path, flags, data, dlen))
1832:
1833: PATHCALL(int, unmount, DUALCALL_UNMOUNT, \
1834: (const char *path, int flags), \
1835: (const char *, int), \
1836: (path, flags))
CVSweb <webmaster@jp.NetBSD.org>