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