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