afsd: cleanup syscall cleanup
[openafs.git] / src / afsd / afsd_kernel.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 #include <roken.h>
14
15 #ifdef IGNORE_SOME_GCC_WARNINGS
16 # pragma GCC diagnostic warning "-Wdeprecated-declarations"
17 #endif
18
19 #define VFS 1
20
21 #include <afs/cmd.h>
22
23 #include "afsd.h"
24
25 #include <assert.h>
26 #include <afs/afsutil.h>
27 #include <sys/file.h>
28 #include <sys/wait.h>
29
30 #if defined(AFS_LINUX20_ENV)
31 #include <sys/resource.h>
32 #endif
33
34 #ifdef HAVE_SYS_FS_TYPES_H
35 #include <sys/fs_types.h>
36 #endif
37
38 #ifdef HAVE_SYS_MOUNT_H
39 #include <sys/mount.h>
40 #endif
41
42 #ifdef HAVE_SYS_FCNTL_H
43 #include <sys/fcntl.h>
44 #endif
45
46 #ifdef HAVE_SYS_MNTTAB_H
47 #include <sys/mnttab.h>
48 #endif
49
50 #ifdef HAVE_SYS_MNTENT_H
51 #include <sys/mntent.h>
52 #endif
53
54 #ifdef HAVE_MNTENT_H
55 #include <mntent.h>
56 #endif
57
58 #ifdef HAVE_SYS_MOUNT_H
59 #include <sys/mount.h>
60 #endif
61
62 #ifdef HAVE_SYS_VFS_H
63 #include <sys/vfs.h>
64 #endif
65
66 #ifdef HAVE_SYS_FSTYP_H
67 #include <sys/fstyp.h>
68 #endif
69
70 #include <ctype.h>
71
72 #include <afs/opr.h>
73 #include <afs/afs_args.h>
74 #include <afs/cellconfig.h>
75 #include <afs/afssyscalls.h>
76 #include <afs/afsutil.h>
77
78 #ifdef AFS_DARWIN_ENV
79 #ifdef AFS_DARWIN80_ENV
80 #include <sys/xattr.h>
81 #endif
82 #include <mach/mach.h>
83 #ifndef AFS_DARWIN100_ENV
84 /* Symbols from the DiskArbitration framework */
85 kern_return_t DiskArbStart(mach_port_t *);
86 kern_return_t DiskArbDiskAppearedWithMountpointPing_auto(char *, unsigned int,
87                                                          char *);
88 #define DISK_ARB_NETWORK_DISK_FLAG 8
89 #endif
90 #include <mach/mach_port.h>
91 #include <mach/mach_interface.h>
92 #include <mach/mach_init.h>
93 #endif /* AFS_DARWIN_ENV */
94
95 #ifndef MOUNT_AFS
96 #define MOUNT_AFS AFS_MOUNT_AFS
97 #endif /* MOUNT_AFS */
98
99 #ifdef AFS_SGI65_ENV
100 # include <sched.h>
101 # define SET_RTPRI(P) {  \
102     struct sched_param sp; \
103     sp.sched_priority = P; \
104     if (sched_setscheduler(0, SCHED_RR, &sp)<0) { \
105         perror("sched_setscheduler"); \
106     } \
107 }
108 # define SET_AFSD_RTPRI() SET_RTPRI(68)
109 # define SET_RX_RTPRI()   SET_RTPRI(199)
110 #else
111 # ifdef AFS_LINUX20_ENV
112 #  define SET_AFSD_RTPRI()
113 #  define SET_RX_RTPRI() do { \
114     if (setpriority(PRIO_PROCESS, 0, -10) < 0) \
115         perror("setting rx priority"); \
116 } while (0)
117 # else
118 #  define SET_AFSD_RTPRI()
119 #  define SET_RX_RTPRI()
120 # endif
121 #endif
122
123 void
124 afsd_set_rx_rtpri(void)
125 {
126     SET_RX_RTPRI();
127 }
128
129 void
130 afsd_set_afsd_rtpri(void)
131 {
132     SET_AFSD_RTPRI();
133 }
134
135 #if defined(AFS_LINUX20_ENV)
136 int
137 os_syscall(struct afsd_syscall_args *args)
138 {
139     int error;
140     struct afsprocdata syscall_data;
141
142     int fd = open(PROC_SYSCALL_FNAME, O_RDWR);
143     if (fd < 0)
144         fd = open(PROC_SYSCALL_ARLA_FNAME, O_RDWR);
145
146     if (fd < 0)
147         return -1;
148
149     syscall_data.syscall = AFSCALL_CALL;
150     syscall_data.param1 = args->syscall;
151     syscall_data.param2 = args->params[0];
152     syscall_data.param3 = args->params[1];
153     syscall_data.param4 = (long) &args->params[2];
154
155     error = ioctl(fd, VIOC_SYSCALL, &syscall_data);
156     close(fd);
157
158     return error;
159 }
160 #elif defined(AFS_DARWIN80_ENV)
161
162 # if defined(AFS_DARWIN100_ENV)
163 static int
164 os_syscall64(struct afsd_syscall_args *args)
165 {
166     int error;
167     struct afssysargs64 syscall64_data;
168     int fd = open(SYSCALL_DEV_FNAME, O_RDWR);
169
170     if (fd < 0)
171         return -1;
172
173     syscall64_data.syscall = (int)AFSCALL_CALL;
174     syscall64_data.param1 = args->syscall;
175     syscall64_data.param2 = args->params[0];
176     syscall64_data.param3 = args->params[1];
177     syscall64_data.param4 = args->params[2];
178     syscall64_data.param5 = args->params[3];
179     syscall64_data.param6 = args->params[4];
180
181     error = ioctl(fd, VIOC_SYSCALL64, &syscall64_data);
182     close(fd);
183
184     if (error)
185         return error;
186
187     return syscall64_data.retval;
188 }
189 # endif
190
191 static int
192 os_syscall(struct afsd_syscall_args *args)
193 {
194     int error;
195     struct afssysargs syscall_data;
196     int fd;
197
198 # ifdef AFS_DARWIN100_ENV
199     if (sizeof(long) == 8)
200         return os_syscall64(args);
201 # endif
202
203     fd = open(SYSCALL_DEV_FNAME, O_RDWR);
204     if (fd < 0)
205         return -1;
206
207     syscall_data.syscall = AFSCALL_CALL;
208     syscall_data.param1 = (unsigned int)(uintptr_t)args->syscall;
209     syscall_data.param2 = (unsigned int)(uintptr_t)args->params[0];
210     syscall_data.param3 = (unsigned int)(uintptr_t)args->params[1];
211     syscall_data.param4 = (unsigned int)(uintptr_t)args->params[2];
212     syscall_data.param5 = (unsigned int)(uintptr_t)args->params[3];
213     syscall_data.param6 = (unsigned int)(uintptr_t)args->params[4];
214
215     error = ioctl(fd, VIOC_SYSCALL, syscall_data);
216     close(fd);
217
218     if (error)
219         return error;
220
221     return syscall_data.retval;
222 }
223
224 #elif defined(AFS_SUN511_ENV)
225 static int
226 os_syscall(struct afsd_syscall_args *args)
227 {
228     int retval;
229
230     error = ioctl_sun_afs_syscall(AFSCALL_CALL, args->syscall,
231                                  args->params[0], args->params[1],
232                                  args->params[2], args->params[3],
233                                  args->params[4], &retval);
234     if (error)
235         return error;
236
237     return retval;
238 }
239 #elif defined(AFS_SGI_ENV)
240 static int
241 os_syscall(struct afsd_syscall_args *args)
242 {
243     return afs_syscall(args->syscall, args->params[0], args->params[1],
244                        args->params[2], args->params[3], args->params[4]);
245 }
246 #elif defined(AFS_AIX32_ENV)
247 static int
248 os_syscall(struct afsd_syscall_args *args)
249 {
250     return syscall(AFSCALL_CALL, args->syscall,
251                    args->params[0], args->params[1], args->params[2],
252                    args->params[3], args->params[4], args->params[5],
253                    args->params[6]);
254 }
255 #else
256 static int
257 os_syscall(struct afsd_syscall_args *args)
258 {
259     return syscall(AFS_SYSCALL, AFSCALL_CALL, args->syscall,
260                    args->params[0], args->params[1], args->params[2],
261                    args->params[3], args->params[4], args->params[5]);
262 }
263 #endif
264
265 int
266 afsd_call_syscall(struct afsd_syscall_args *args)
267 {
268     int error;
269
270     error = os_syscall(args);
271
272     if (afsd_debug) {
273 #ifdef AFS_NBSD40_ENV
274         char *s = strerror(errno);
275         printf("SScall(%d, %d, %d)=%d (%d, %s)\n", AFS_SYSCALL, AFSCALL_CALL,
276                 (int)args->params[0], error, errno, s);
277 #else
278         printf("SScall(%d, %d, %d)=%d ", AFS_SYSCALL, AFSCALL_CALL,
279                (int)args->params[0], error);
280 #endif
281     }
282
283     return error;
284 }
285
286 #ifdef  AFS_AIX_ENV
287 /* Special handling for AIX's afs mount operation since they require much more
288  * miscl. information before making the vmount(2) syscall */
289 #include <sys/vfs.h>
290
291 #define ROUNDUP(x)  (((x) + 3) & ~3)
292
293 aix_vmount(const char *cacheMountDir)
294 {
295     struct vmount *vmountp;
296     int size, error;
297
298     size = sizeof(struct vmount) + ROUNDUP(strlen(cacheMountDir) + 1) + 5 * 4;
299     /* Malloc and zero the vmount structure */
300     if ((vmountp = calloc(1, size)) == NULL) {
301         printf("Can't allocate space for the vmount structure (AIX)\n");
302         exit(1);
303     }
304
305     /* transfer info into the vmount structure */
306     vmountp->vmt_revision = VMT_REVISION;
307     vmountp->vmt_length = size;
308     vmountp->vmt_fsid.fsid_dev = 0;
309     vmountp->vmt_fsid.fsid_type = AFS_MOUNT_AFS;
310     vmountp->vmt_vfsnumber = 0;
311     vmountp->vmt_time = 0;      /* We'll put the time soon! */
312     vmountp->vmt_flags = VFS_DEVMOUNT;  /* read/write permission */
313     vmountp->vmt_gfstype = AFS_MOUNT_AFS;
314     vmountdata(vmountp, "AFS", cacheMountDir, "", "", "", "rw");
315
316     /* Do the actual mount system call */
317     error = vmount(vmountp, size);
318     free(vmountp);
319     return (error);
320 }
321
322 vmountdata(struct vmount * vmtp, char *obj, char *stub, char *host,
323            char *hostsname, char *info, char *args)
324 {
325     struct data {
326         short vmt_off;
327         short vmt_size;
328     } *vdp, *vdprev;
329     int size;
330
331     vdp = (struct data *)vmtp->vmt_data;
332     vdp->vmt_off = sizeof(struct vmount);
333     size = ROUNDUP(strlen(obj) + 1);
334     vdp->vmt_size = size;
335     strcpy(vmt2dataptr(vmtp, VMT_OBJECT), obj);
336
337     vdprev = vdp;
338     vdp++;
339     vdp->vmt_off = vdprev->vmt_off + size;
340     size = ROUNDUP(strlen(stub) + 1);
341     vdp->vmt_size = size;
342     strcpy(vmt2dataptr(vmtp, VMT_STUB), stub);
343
344     vdprev = vdp;
345     vdp++;
346     vdp->vmt_off = vdprev->vmt_off + size;
347     size = ROUNDUP(strlen(host) + 1);
348     vdp->vmt_size = size;
349     strcpy(vmt2dataptr(vmtp, VMT_HOST), host);
350
351     vdprev = vdp;
352     vdp++;
353     vdp->vmt_off = vdprev->vmt_off + size;
354     size = ROUNDUP(strlen(hostsname) + 1);
355     vdp->vmt_size = size;
356     strcpy(vmt2dataptr(vmtp, VMT_HOSTNAME), hostsname);
357
358
359     vdprev = vdp;
360     vdp++;
361     vdp->vmt_off = vdprev->vmt_off + size;
362     size = ROUNDUP(strlen(info) + 1);
363     vdp->vmt_size = size;
364     strcpy(vmt2dataptr(vmtp, VMT_INFO), info);
365
366     vdprev = vdp;
367     vdp++;
368     vdp->vmt_off = vdprev->vmt_off + size;
369     size = ROUNDUP(strlen(args) + 1);
370     vdp->vmt_size = size;
371     strcpy(vmt2dataptr(vmtp, VMT_ARGS), args);
372 }
373 #endif /* AFS_AIX_ENV */
374
375 #ifdef  AFS_HPUX_ENV
376 #define MOUNTED_TABLE   MNT_MNTTAB
377 #else
378 #define MOUNTED_TABLE   MOUNTED
379 #endif
380
381 static int
382 HandleMTab(char *cacheMountDir)
383 {
384 #if (defined (AFS_HPUX_ENV) || defined(AFS_SGI_ENV) || defined(AFS_LINUX20_ENV))
385     FILE *tfilep;
386 #if defined(AFS_SGI_ENV) || defined(AFS_LINUX20_ENV)
387     struct mntent tmntent;
388     char *dir;
389     int i;
390
391     tfilep = setmntent("/etc/mtab", "a+");
392     if (!tfilep) {
393         printf("Can't open /etc/mtab for writing (errno %d); not adding "
394                "an entry for AFS\n", errno);
395         return 1;
396     }
397
398     dir = strdup(cacheMountDir);
399
400     /* trim trailing slashes; don't look at dir[0] in case we are somehow
401      * just "/" */
402     for (i = strlen(dir)-1; i > 0; i--) {
403         if (dir[i] == '/') {
404             dir[i] = '\0';
405         } else {
406             break;
407         }
408     }
409
410     tmntent.mnt_fsname = "AFS";
411     tmntent.mnt_dir = dir;
412     tmntent.mnt_type = "afs";
413     tmntent.mnt_opts = "rw";
414     tmntent.mnt_freq = 1;
415     tmntent.mnt_passno = 3;
416     addmntent(tfilep, &tmntent);
417     endmntent(tfilep);
418
419     free(dir);
420     dir = NULL;
421 #else
422     struct mntent tmntent;
423
424     memset(&tmntent, '\0', sizeof(struct mntent));
425     tfilep = setmntent(MOUNTED_TABLE, "a+");
426     if (!tfilep) {
427         printf("Can't open %s for write; Not adding afs entry to it\n",
428                MOUNTED_TABLE);
429         return 1;
430     }
431     tmntent.mnt_fsname = "AFS";
432     tmntent.mnt_dir = cacheMountDir;
433     tmntent.mnt_type = "xx";
434     tmntent.mnt_opts = "rw";
435     tmntent.mnt_freq = 1;
436     tmntent.mnt_passno = 3;
437 #ifdef  AFS_HPUX_ENV
438     tmntent.mnt_type = "afs";
439     tmntent.mnt_time = time(0);
440     tmntent.mnt_cnode = 0;
441 #endif
442     addmntent(tfilep, &tmntent);
443     endmntent(tfilep);
444 #endif /* AFS_SGI_ENV */
445 #endif /* unreasonable systems */
446 #ifdef AFS_DARWIN_ENV
447 #ifndef AFS_DARWIN100_ENV
448     mach_port_t diskarb_port;
449     kern_return_t status;
450
451     status = DiskArbStart(&diskarb_port);
452     if (status == KERN_SUCCESS) {
453         status =
454             DiskArbDiskAppearedWithMountpointPing_auto("AFS",
455                                                        DISK_ARB_NETWORK_DISK_FLAG,
456                                                        cacheMountDir);
457     }
458
459     return status;
460 #endif
461 #endif /* AFS_DARWIN_ENV */
462     return 0;
463 }
464
465 void
466 afsd_mount_afs(const char *rn, const char *cacheMountDir)
467 {
468     int mountFlags;             /*Flags passed to mount() */
469     char *mountDir; /* For HandleMTab() */
470
471     mountFlags = 0;             /* Read/write file system, can do setuid() */
472 #if     defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
473 #ifdef  AFS_SUN5_ENV
474     mountFlags |= MS_DATA;
475 #else
476     mountFlags |= M_NEWTYPE;    /* This searches by name in vfs_conf.c so don't need to recompile vfs.c because MOUNT_MAXTYPE has changed; it seems that Sun fixed this at last... */
477 #endif
478 #endif
479
480 #if defined(AFS_HPUX100_ENV)
481     mountFlags |= MS_DATA;
482 #endif
483
484     if (afsd_verbose)
485         printf("%s: Mounting the AFS root on '%s', flags: %d.\n", rn,
486             cacheMountDir, mountFlags);
487 #if defined(AFS_FBSD60_ENV)
488     /* data must be non-NULL but is otherwise ignored */
489     if ((mount(MOUNT_AFS, cacheMountDir, mountFlags, rn)) < 0) {
490 #elif defined(AFS_FBSD_ENV)
491     if ((mount("AFS", cacheMountDir, mountFlags, (caddr_t) 0)) < 0) {
492 #elif defined(AFS_AIX_ENV)
493     if (aix_vmount(cacheMountDir)) {
494 #elif defined(AFS_HPUX100_ENV)
495     if ((mount("", cacheMountDir, mountFlags, "afs", NULL, 0)) < 0) {
496 #elif defined(AFS_SUN5_ENV)
497     if ((mount("AFS", cacheMountDir, mountFlags, "afs", NULL, 0)) < 0) {
498 #elif defined(AFS_SGI_ENV)
499     mountFlags = MS_FSS;
500     if ((mount(MOUNT_AFS, cacheMountDir, mountFlags, (caddr_t) MOUNT_AFS))
501         < 0) {
502 #elif defined(AFS_LINUX20_ENV)
503     if ((mount("AFS", cacheMountDir, MOUNT_AFS, 0, NULL)) < 0) {
504 #elif defined(AFS_NBSD50_ENV)
505     if ((mount(MOUNT_AFS, cacheMountDir, mountFlags, NULL, 0)) < 0) {
506 #else
507     /* This is the standard mount used by the suns and rts */
508     if ((mount(MOUNT_AFS, cacheMountDir, mountFlags, (caddr_t) 0)) < 0) {
509 #endif
510         printf("%s: Can't mount AFS on %s(%d)\n", rn, cacheMountDir,
511                 errno);
512         exit(1);
513     }
514
515     mountDir = strdup(cacheMountDir);
516     HandleMTab(mountDir);
517     free(mountDir);
518 }
519
520 int
521 afsd_fork(int wait, afsd_callback_func cb, void *rock)
522 {
523     int code;
524     code = fork();
525     if (code == 0) {
526         (*cb) (rock);
527         exit(1);
528     } else {
529         assert(code > 0);
530         if (wait) {
531             assert(waitpid(code, NULL, 0) != -1);
532         }
533     }
534     return 0;
535 }
536
537 int
538 afsd_daemon(int nochdir, int noclose)
539 {
540     return daemon(nochdir, noclose);
541 }
542
543 int
544 afsd_check_mount(const char *rn, const char *mountdir)
545 {
546     struct stat statbuf;
547
548     if (stat(mountdir, &statbuf)) {
549         printf("%s: Mountpoint %s missing.\n", rn, mountdir);
550         return -1;
551     } else if (!S_ISDIR(statbuf.st_mode)) {
552         printf("%s: Mountpoint %s is not a directory.\n", rn, mountdir);
553         return -1;
554     }
555     return 0;
556 }
557
558 int
559 main(int argc, char **argv)
560 {
561     int code;
562
563     afsd_init();
564
565     code = afsd_parse(argc, argv);
566     if (code) {
567         return -1;
568     }
569
570     return afsd_run();
571 }