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