Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / contrib / amd / hlfsd / hlfsd.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1997-1999 Erez Zadok
3 * Copyright (c) 1989 Jan-Simon Pendry
4 * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1989 The Regents of the University of California.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgment:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * %W% (Berkeley) %G%
40 *
41 * $Id: hlfsd.c,v 1.5 1999/09/08 23:36:51 ezk Exp $
42 * $FreeBSD: src/contrib/amd/hlfsd/hlfsd.c,v 1.5 1999/09/15 05:45:15 obrien Exp $
1de703da 43 * $DragonFly: src/contrib/amd/hlfsd/hlfsd.c,v 1.2 2003/06/17 04:23:57 dillon Exp $
984263bc
MD
44 *
45 * HLFSD was written at Columbia University Computer Science Department, by
46 * Erez Zadok <ezk@cs.columbia.edu> and Alexander Dupuy <dupuy@cs.columbia.edu>
47 * It is being distributed under the same terms and conditions as amd does.
48 */
49
50#ifdef HAVE_CONFIG_H
51# include <config.h>
52#endif /* HAVE_CONFIG_H */
53#include <am_defs.h>
54#include <hlfsd.h>
55
56/*
57 * STATIC VARIABLES:
58 */
59static RETSIGTYPE proceed(int);
60static RETSIGTYPE reaper(int);
61static RETSIGTYPE reload(int);
62static char *hlfs_group = DEFAULT_HLFS_GROUP;
63static char default_dir_name[] = DEFAULT_DIRNAME;
64static char *dir_name = default_dir_name;
65static int printpid = 0;
66static int stoplight = 0;
67static void hlfsd_init(void);
68static void usage(void);
69
70static struct itimerval reloadinterval = {
71 {DEFAULT_INTERVAL, 0},
72 {DEFAULT_INTERVAL, 0}
73};
74
75/*
76 * default mount options.
77 */
78static char default_mntopts[] = "ro,noac";
79
80/*
81 * GLOBALS:
82 */
83SVCXPRT *nfsxprt;
84char *alt_spooldir = ALT_SPOOLDIR;
85char *home_subdir = HOME_SUBDIR;
86char *logfile = DEFAULT_LOGFILE;
87char *passwdfile = NULL; /* alternate passwd file to use */
88char *slinkname = 0;
89char hostname[MAXHOSTNAMELEN + 1] = "localhost";
90int cache_interval = DEFAULT_CACHE_INTERVAL;
91gid_t hlfs_gid = (gid_t) INVALIDID;
92int masterpid = 0;
93int noverify = 0;
94int orig_umask = 022;
95int serverpid = 0;
96nfstime startup;
97u_short nfs_port;
98
99/* symbol must be available always */
100#ifdef MOUNT_TABLE_ON_FILE
101char *mnttab_file_name = MNTTAB_FILE_NAME;
102#else /* not MOUNT_TABLE_ON_FILE */
103char *mnttab_file_name = NULL;
104#endif /* not MOUNT_TABLE_ON_FILE */
105
106/* forward declarations */
107void hlfsd_going_down(int rc);
108
109
110static void
111usage(void)
112{
113 fprintf(stderr,
114 "Usage: %s [-Cfhnpv] [-a altdir] [-c cache-interval] [-g group]\n",
115 am_get_progname());
116 fprintf(stderr, "\t[-i interval] [-l logfile] [-o mntopts] [-P passwdfile]\n");
117 show_opts('x', xlog_opt);
118#ifdef DEBUG
119 show_opts('D', dbg_opt);
120#endif /* DEBUG */
121 fprintf(stderr, "\t[dir_name [subdir]]\n");
122 exit(2);
123}
124
125
126int
127main(int argc, char *argv[])
128{
129 char *dot;
130 char *mntopts = (char *) NULL;
131 char hostpid_fs[MAXHOSTNAMELEN + 1 + 16]; /* room for ":(pid###)" */
132 char progpid_fs[PROGNAMESZ + 1 + 11]; /* room for ":pid" */
133 char preopts[128];
134 char *progname;
135 int forcecache = 0;
136 int forcefast = 0;
137 int genflags = 0;
138 int opt, ret;
139 int opterrs = 0;
140 int retry;
141 int soNFS; /* NFS socket */
142 int s = -99;
143 mntent_t mnt;
144 nfs_args_t nfs_args;
145 am_nfs_handle_t anh;
146 struct dirent *direntry;
147 struct group *grp;
148 struct stat stmodes;
149 DIR *mountdir;
150 MTYPE_TYPE type = MOUNT_TYPE_NFS;
151
152#ifdef HAVE_SIGACTION
153 struct sigaction sa;
154#endif /* not HAVE_SIGACTION */
155
156#ifndef HAVE_TRANSPORT_TYPE_TLI
157 struct sockaddr_in localsocket;
158#endif /* not HAVE_TRANSPORT_TYPE_TLI */
159
160
161 /* get program name and truncate so we don't overflow progpid_fs */
162
163 if ((progname = strrchr(argv[0], '/')) != NULL)
164 progname++;
165 else
166 progname = argv[0];
167 if ((int) strlen(progname) > PROGNAMESZ) /* truncate to reasonable size */
168 progname[PROGNAMESZ] = '\0';
169 am_set_progname(progname);
170
171 while ((opt = getopt(argc, argv, "a:c:CD:fg:hi:l:no:pP:x:v")) != -1)
172 switch (opt) {
173
174 case 'a':
175 if (!optarg || optarg[0] != '/') {
176 printf("%s: invalid directory for -a: %s\n",
177 am_get_progname(), optarg);
178 exit(3);
179 }
180 alt_spooldir = optarg;
181 break;
182
183 case 'c':
184 if (!atoi(optarg)) {
185 printf("%s: invalid interval for -c: %s\n",
186 am_get_progname(), optarg);
187 exit(3);
188 }
189 cache_interval = atoi(optarg);
190 break;
191
192 case 'C':
193 forcecache++;
194 break;
195
196 case 'f':
197 forcefast++;
198 break;
199
200 case 'g':
201 hlfs_group = optarg;
202 break;
203
204 case 'i':
205 if (!atoi(optarg)) {
206 printf("%s: invalid interval for -i: %s\n",
207 am_get_progname(), optarg);
208 exit(3);
209 }
210 reloadinterval.it_interval.tv_sec = atoi(optarg);
211 reloadinterval.it_value.tv_sec = atoi(optarg);
212 break;
213
214 case 'l':
215 logfile = optarg;
216 break;
217
218 case 'n':
219 noverify++;
220 break;
221
222 case 'o':
223 mntopts = optarg;
224 break;
225
226 case 'p':
227 printpid++;
228 break;
229
230 case 'P':
231 passwdfile = optarg;
232 break;
233
234 case 'v':
235 fprintf(stderr, "%s\n", HLFSD_VERSION);
236 exit(0);
237
238 case 'x':
239 opterrs += switch_option(optarg);
240 break;
241
242 case 'D':
243#ifdef DEBUG
244 opterrs += debug_option(optarg);
245#else /* not DEBUG */
246 fprintf(stderr, "%s: not compiled with DEBUG -- sorry.\n", am_get_progname());
247#endif /* not DEBUG */
248 break;
249
250 case 'h':
251 case '?':
252 opterrs++;
253 }
254
255 /* set some default debugging options */
256 if (xlog_level_init == ~0)
257 switch_option("");
258 /* need my pid before any dlog/plog */
259 am_set_mypid();
260#ifdef DEBUG
261 switch_option("debug");
262#endif /* DEBUG */
263
264/*
265 * Terminate if did not ask to forcecache (-C) and hlfsd would not be able
266 * to set the minimum cache intervals.
267 */
268#if !defined(MNT2_NFS_OPT_ACREGMIN) && !defined(MNT2_NFS_OPT_NOAC) && !defined(HAVE_FIELD_NFS_ARGS_T_ACREGMIN)
269 if (!forcecache) {
270 fprintf(stderr, "%s: will not be able to turn off attribute caches.\n", am_get_progname());
271 exit(1);
272 }
273#endif /* !defined(MNT2_NFS_OPT_ACREGMIN) && !defined(MNT2_NFS_OPT_NOAC) && !defined(HAVE_FIELD_NFS_ARGS_T_ACREGMIN) */
274
275
276 switch (argc - optind) {
277 case 2:
278 home_subdir = argv[optind + 1];
279 case 1:
280 dir_name = argv[optind];
281 case 0:
282 break;
283 default:
284 opterrs++;
285 }
286
287 if (opterrs)
288 usage();
289
290 /* ensure that only root can run hlfsd */
291 if (geteuid()) {
292 fprintf(stderr, "hlfsd can only be run as root\n");
293 exit(1);
294 }
295 setbuf(stdout, (char *) NULL);
296 umask(0);
297
298 /* find gid for hlfs_group */
299 if ((grp = getgrnam(hlfs_group)) == (struct group *) NULL) {
300 fprintf(stderr, "%s: cannot get gid for group \"%s\".\n",
301 am_get_progname(), hlfs_group);
302 } else {
303 hlfs_gid = grp->gr_gid;
304 }
305
306 /* get hostname for logging and open log before we reset umask */
307 gethostname(hostname, sizeof(hostname));
308 hostname[sizeof(hostname) - 1] = '\0';
309 if ((dot = strchr(hostname, '.')) != NULL)
310 *dot = '\0';
311 orig_umask = umask(0);
312 if (logfile)
313 switch_to_logfile(logfile, orig_umask);
314
315#if defined(DEBUG) && !defined(MOUNT_TABLE_ON_FILE)
316 if (debug_flags & D_MTAB)
317 dlog("-D mtab option ignored");
318#endif /* defined(DEBUG) && !defined(MOUNT_TABLE_ON_FILE) */
319
320 /* avoid hanging on other NFS servers if started elsewhere */
321 if (chdir("/") < 0)
322 fatal("cannot chdir to /: %m");
323
324 if (geteuid() != 0)
325 fatal("must be root to mount filesystems");
326
327 /*
328 * dir_name must match "^(/.*)/([^/]+)$", and is split at last '/' with
329 * slinkname = `basename $dir_name` - requires dir_name be writable
330 */
331
332 if (dir_name[0] != '/'
333 || ((slinkname = strrchr(dir_name, '/')), *slinkname++ = '\0',
334 (dir_name[0] == '\0' || slinkname[0] == '\0'))) {
335 if (slinkname)
336 *--slinkname = '/';
337 printf("%s: invalid mount directory/link %s\n",
338 am_get_progname(), dir_name);
339 exit(3);
340 }
341
342 clock_valid = 0; /* invalidate logging clock */
343
344 if (!forcefast) {
345 /* make sure mount point exists and is at least mode 555 */
346 if (stat(dir_name, &stmodes) < 0)
347 if (errno != ENOENT || mkdirs(dir_name, 0555) < 0
348 || stat(dir_name, &stmodes) < 0)
349 fatalerror(dir_name);
350
351 if ((stmodes.st_mode & 0555) != 0555) {
352 fprintf(stderr, "%s: directory %s not read/executable\n",
353 am_get_progname(), dir_name);
354 plog(XLOG_WARNING, "directory %s not read/executable",
355 dir_name);
356 }
357
358 /* warn if extraneous stuff will be hidden by mount */
359 if ((mountdir = opendir(dir_name)) == NULL)
360 fatalerror(dir_name);
361
362 while ((direntry = readdir(mountdir)) != NULL) {
363 if (!NSTREQ(".", direntry->d_name, NAMLEN(direntry)) &&
364 !NSTREQ("..", direntry->d_name, NAMLEN(direntry)) &&
365 !NSTREQ(slinkname, direntry->d_name, NAMLEN(direntry)))
366 break;
367 }
368
369 if (direntry != NULL) {
370 fprintf(stderr, "%s: %s/%s will be hidden by mount\n",
371 am_get_progname(), dir_name, direntry->d_name);
372 plog(XLOG_WARNING, "%s/%s will be hidden by mount\n",
373 dir_name, direntry->d_name);
374 }
375 closedir(mountdir);
376
377 /* make sure alternate spool dir exists */
378 if ((errno = mkdirs(alt_spooldir, OPEN_SPOOLMODE))) {
379 fprintf(stderr, "%s: cannot create alternate dir ",
380 am_get_progname());
381 perror(alt_spooldir);
382 plog(XLOG_ERROR, "cannot create alternate dir %s: %m",
383 alt_spooldir);
384 }
385 chmod(alt_spooldir, OPEN_SPOOLMODE);
386
387 /* create failsafe link to alternate spool directory */
388 slinkname[-1] = '/'; /* unsplit dir_name to include link */
389 if (lstat(dir_name, &stmodes) == 0 &&
390 (stmodes.st_mode & S_IFMT) != S_IFLNK) {
391 fprintf(stderr, "%s: failsafe %s not a symlink\n",
392 am_get_progname(), dir_name);
393 plog(XLOG_WARNING, "failsafe %s not a symlink\n",
394 dir_name);
395 } else {
396 unlink(dir_name);
397
398 if (symlink(alt_spooldir, dir_name) < 0) {
399 fprintf(stderr,
400 "%s: cannot create failsafe symlink %s -> ",
401 am_get_progname(), dir_name);
402 perror(alt_spooldir);
403 plog(XLOG_WARNING,
404 "cannot create failsafe symlink %s -> %s: %m",
405 dir_name, alt_spooldir);
406 }
407 }
408
409 slinkname[-1] = '\0'; /* resplit dir_name */
410 } /* end of "if (!forcefast) {" */
411
412 /*
413 * Register hlfsd as an nfs service with the portmapper.
414 */
415#ifdef HAVE_TRANSPORT_TYPE_TLI
416 ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2);
417#else /* not HAVE_TRANSPORT_TYPE_TLI */
418 ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2);
419#endif /* not HAVE_TRANSPORT_TYPE_TLI */
420 if (ret != 0)
421 fatal("cannot create NFS service");
422
423#ifdef HAVE_SIGACTION
424 sa.sa_handler = proceed;
425 sa.sa_flags = 0;
426 sigemptyset(&(sa.sa_mask));
427 sigaddset(&(sa.sa_mask), SIGUSR2);
428 sigaction(SIGUSR2, &sa, NULL);
429#else /* not HAVE_SIGACTION */
430 signal(SIGUSR2, proceed);
431#endif /* not HAVE_SIGACTION */
432
433 plog(XLOG_INFO, "Initializing hlfsd...");
434 hlfsd_init(); /* start up child (forking) to run svc_run */
435
436#ifdef HAVE_SIGACTION
437 sa.sa_handler = reaper;
438 sa.sa_flags = 0;
439 sigemptyset(&(sa.sa_mask));
440 sigaddset(&(sa.sa_mask), SIGCHLD);
441 sigaction(SIGCHLD, &sa, NULL);
442#else /* not HAVE_SIGACTION */
443 signal(SIGCHLD, reaper);
444#endif /* not HAVE_SIGACTION */
445
446#ifdef DEBUG
447 /*
448 * In the parent, if -D nodaemon (or -D daemon) , we don't need to
449 * set this signal handler.
450 */
451 amuDebug(D_DAEMON) {
452#endif /* DEBUG */
453 /* XXX: port to use pure svr4 signals */
454 s = -99;
455 while (stoplight != SIGUSR2) {
456 plog(XLOG_INFO, "parent waits for child to setup (stoplight=%d)", stoplight);
457 s = sigpause(0); /* wait for child to set up */
458 sleep(1);
459 }
460#ifdef DEBUG
461 }
462#endif /* DEBUG */
463
464 /*
465 * setup options to mount table (/etc/{mtab,mnttab}) entry
466 */
467 sprintf(hostpid_fs, "%s:(pid%d)", hostname, masterpid);
468 memset((char *) &mnt, 0, sizeof(mnt));
469 mnt.mnt_dir = dir_name; /* i.e., "/mail" */
470 mnt.mnt_fsname = hostpid_fs;
471 if (mntopts) {
472 mnt.mnt_opts = mntopts;
473 } else {
474 strcpy(preopts, default_mntopts);
475 /*
476 * Turn off all kinds of attribute and symlink caches as
477 * much as possible. Also make sure that mount does not
478 * show up to df.
479 */
480#ifdef MNTTAB_OPT_INTR
481 strcat(preopts, ",");
482 strcat(preopts, MNTTAB_OPT_INTR);
483#endif /* MNTTAB_OPT_INTR */
484#ifdef MNTTAB_OPT_IGNORE
485 strcat(preopts, ",");
486 strcat(preopts, MNTTAB_OPT_IGNORE);
487#endif /* MNTTAB_OPT_IGNORE */
488#ifdef MNT2_GEN_OPT_CACHE
489 strcat(preopts, ",nocache");
490#endif /* MNT2_GEN_OPT_CACHE */
491#ifdef MNT2_NFS_OPT_SYMTTL
492 strcat(preopts, ",symttl=0");
493#endif /* MNT2_NFS_OPT_SYMTTL */
494 mnt.mnt_opts = preopts;
495 }
496
497 /*
498 * Make sure that amd's top-level NFS mounts are hidden by default
499 * from df.
500 * If they don't appear to support the either the "ignore" mnttab
501 * option entry, or the "auto" one, set the mount type to "nfs".
502 */
503 mnt.mnt_type = HIDE_MOUNT_TYPE;
504 /* some systems don't have a mount type, but a mount flag */
505
506#ifndef HAVE_TRANSPORT_TYPE_TLI
507 amu_get_myaddress(&localsocket.sin_addr);
508 localsocket.sin_family = AF_INET;
509 localsocket.sin_port = htons(nfsxprt->xp_port);
510#endif /* not HAVE_TRANSPORT_TYPE_TLI */
511
512 /*
513 * Update hostname field.
514 * Make some name prog:pid (i.e., hlfsd:174) for hostname
515 */
516 sprintf(progpid_fs, "%s:%d", am_get_progname(), masterpid);
517
518 /* Most kernels have a name length restriction. */
519 if ((int) strlen(progpid_fs) >= (int) MAXHOSTNAMELEN)
520 strcpy(progpid_fs + MAXHOSTNAMELEN - 3, "..");
521
522 genflags = compute_mount_flags(&mnt);
523
524 retry = hasmntval(&mnt, MNTTAB_OPT_RETRY);
525 if (retry <= 0)
526 retry = 1; /* XXX */
527
528 memmove(&anh.v2.fhs_fh, root_fhp, sizeof(*root_fhp));
529#ifdef HAVE_TRANSPORT_TYPE_TLI
530 compute_nfs_args(&nfs_args,
531 &mnt,
532 genflags,
533 nfsncp,
534 NULL, /* remote host IP addr is set below */
535 NFS_VERSION, /* version 2 */
536 "udp", /* XXX: shouldn't this be "udp"? */
537 &anh,
538 progpid_fs, /* host name for kernel */
539 hostpid_fs); /* filesystem name for kernel */
540 /*
541 * IMPORTANT: set the correct IP address AFTERWARDS. It cannot
542 * be done using the normal mechanism of compute_nfs_args(), because
543 * that one will allocate a new address and use NFS_SA_DREF() to copy
544 * parts to it, while assuming that the ip_addr passed is always
545 * a "struct sockaddr_in". That assumption is incorrect on TLI systems,
546 * because they define a special macro HOST_SELF which is DIFFERENT
547 * than localhost (127.0.0.1)!
548 */
549 nfs_args.addr = &nfsxprt->xp_ltaddr;
550#else /* not HAVE_TRANSPORT_TYPE_TLI */
551 compute_nfs_args(&nfs_args,
552 &mnt,
553 genflags,
554 &localsocket,
555 NFS_VERSION, /* version 2 */
556 "udp", /* XXX: shouldn't this be "udp"? */
557 &anh,
558 progpid_fs, /* host name for kernel */
559 hostpid_fs); /* filesystem name for kernel */
560#endif /* not HAVE_TRANSPORT_TYPE_TLI */
561
562 /*************************************************************************
563 * NOTE: while compute_nfs_args() works ok for regular NFS mounts *
564 * the toplvl one is not, and so some options must be corrected by hand *
565 * more carefully, *after* compute_nfs_args() runs. *
566 *************************************************************************/
567 compute_automounter_nfs_args(&nfs_args, &mnt);
568
569 clock_valid = 0; /* invalidate logging clock */
570
571/*
572 * The following code could be cleverly ifdef-ed, but I duplicated the
573 * mount_fs call three times for simplicity and readability.
574 */
575#ifdef DEBUG
576/*
577 * For some reason, this mount may have to be done in the background, if I am
578 * using -D nodebug. I suspect that the actual act of mounting requires
579 * calling to hlfsd itself to invoke one or more of its nfs calls, to stat
580 * /mail. That means that even if you say -D nodaemon, at least the mount
581 * of hlfsd itself on top of /mail will be done in the background.
582 * The other alternative I have is to run svc_run, but set a special
583 * signal handler to perform the mount in N seconds via some alarm.
584 * -Erez Zadok.
585 */
586 if (debug_flags & D_DAEMON) { /* asked for -D daemon */
587 plog(XLOG_INFO, "parent NFS mounting hlfsd service points");
588 if (mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name) < 0)
589 fatal("nfsmount: %m");
590 } else { /* asked for -D nodaemon */
591 if (fork() == 0) { /* child runs mount */
592 am_set_mypid();
593 foreground = 0;
594 plog(XLOG_INFO, "child NFS mounting hlfsd service points");
595 if (mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name) < 0) {
596 fatal("nfsmount: %m");
597 }
598 exit(0); /* all went well */
599 } else { /* fork failed or parent running */
600 plog(XLOG_INFO, "parent waiting 1sec for mount...");
601 }
602 }
603#else /* not DEBUG */
604 plog(XLOG_INFO, "normal NFS mounting hlfsd service points");
605 if (mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 2, "udp", mnttab_file_name) < 0)
606 fatal("nfsmount: %m");
607#endif /* not DEBUG */
608
609#ifdef HAVE_TRANSPORT_TYPE_TLI
610 /*
611 * XXX: this free_knetconfig() was not done for hlfsd before,
612 * and apparently there was a reason for it, but why? -Erez
613 */
614 free_knetconfig(nfs_args.knconf);
615 /*
616 * local automounter mounts do not allocate a special address, so
617 * no need to XFREE(nfs_args.addr) under TLI.
618 */
619#endif /* HAVE_TRANSPORT_TYPE_TLI */
620
621 if (printpid)
622 printf("%d\n", masterpid);
623
624 plog(XLOG_INFO, "hlfsd ready to serve");
625#ifdef DEBUG
626 /*
627 * If asked not to fork a daemon (-D nodaemon), then hlfsd_init()
628 * will not run svc_run. We must start svc_run here.
629 */
630 dlog("starting no-daemon debugging svc_run");
631 amuDebugNo(D_DAEMON)
632 svc_run();
633#endif /* DEBUG */
634
635 cleanup(0); /* should never happen here */
636 return (0); /* everything went fine? */
637}
638
639
640static void
641hlfsd_init(void)
642{
643 int child = 0;
644#ifdef HAVE_SIGACTION
645 struct sigaction sa;
646#endif /* HAVE_SIGACTION */
647
648 clock_valid = 0; /* invalidate logging clock */
649
650 /*
651 * Initialize file handles.
652 */
653 plog(XLOG_INFO, "initializing hlfsd file handles");
654 hlfsd_init_filehandles();
655
656#ifdef DEBUG
657 /*
658 * If -D daemon then we must fork.
659 */
660 amuDebug(D_DAEMON)
661#endif /* DEBUG */
662 child = fork();
663
664 if (child < 0)
665 fatal("fork: %m");
666
667 if (child != 0) { /* parent process - save child pid */
668 masterpid = child;
669 am_set_mypid(); /* for logging routines */
670 return;
671 }
672
673 /*
674 * CHILD CODE:
675 * initialize server
676 */
677
678 plog(XLOG_INFO, "initializing home directory database");
679 plt_init(); /* initialize database */
680 plog(XLOG_INFO, "home directory database initialized");
681
682 masterpid = serverpid = am_set_mypid(); /* for logging routines */
683
684 /*
685 * SIGALRM/SIGHUP: reload password database if timer expired
686 * or user sent HUP signal.
687 */
688#ifdef HAVE_SIGACTION
689 sa.sa_handler = reload;
690 sa.sa_flags = 0;
691 sigemptyset(&(sa.sa_mask));
692 sigaddset(&(sa.sa_mask), SIGALRM);
693 sigaddset(&(sa.sa_mask), SIGHUP);
694 sigaction(SIGALRM, &sa, NULL);
695 sigaction(SIGHUP, &sa, NULL);
696#else /* not HAVE_SIGACTION */
697 signal(SIGALRM, reload);
698 signal(SIGHUP, reload);
699#endif /* not HAVE_SIGACTION */
700
701 /*
702 * SIGTERM: cleanup and exit.
703 */
704#ifdef HAVE_SIGACTION
705 sa.sa_handler = cleanup;
706 sa.sa_flags = 0;
707 sigemptyset(&(sa.sa_mask));
708 sigaddset(&(sa.sa_mask), SIGTERM);
709 sigaction(SIGTERM, &sa, NULL);
710#else /* not HAVE_SIGACTION */
711 signal(SIGTERM, cleanup);
712#endif /* not HAVE_SIGACTION */
713
714 /*
715 * SIGCHLD: interlock synchronization and testing
716 */
717#ifdef HAVE_SIGACTION
718 sa.sa_handler = interlock;
719 sa.sa_flags = 0;
720 sigemptyset(&(sa.sa_mask));
721 sigaddset(&(sa.sa_mask), SIGCHLD);
722 sigaction(SIGCHLD, &sa, NULL);
723#else /* not HAVE_SIGACTION */
724 signal(SIGCHLD, interlock);
725#endif /* not HAVE_SIGACTION */
726
727 /*
728 * SIGUSR1: dump internal hlfsd maps/cache to file
729 */
730#ifdef HAVE_SIGACTION
731# if defined(DEBUG) || defined(DEBUG_PRINT)
732 sa.sa_handler = plt_print;
733# else /* not defined(DEBUG) || defined(DEBUG_PRINT) */
734 sa.sa_handler = SIG_IGN;
735# endif /* not defined(DEBUG) || defined(DEBUG_PRINT) */
736 sa.sa_flags = 0;
737 sigemptyset(&(sa.sa_mask));
738 sigaddset(&(sa.sa_mask), SIGUSR1);
739 sigaction(SIGUSR1, &sa, NULL);
740#else /* not HAVE_SIGACTION */
741# if defined(DEBUG) || defined(DEBUG_PRINT)
742 signal(SIGUSR1, plt_print);
743# else /* not defined(DEBUG) || defined(DEBUG_PRINT) */
744 signal(SIGUSR1, SIG_IGN);
745# endif /* not defined(DEBUG) || defined(DEBUG_PRINT) */
746#endif /* not HAVE_SIGACTION */
747
748 if (setitimer(ITIMER_REAL, &reloadinterval, (struct itimerval *) 0) < 0)
749 fatal("setitimer: %m");
750
751 gettimeofday((struct timeval *) &startup, (struct timezone *) 0);
752
753#ifdef DEBUG
754 /*
755 * If -D daemon, then start serving here in the child,
756 * and the parent will exit. But if -D nodaemon, then
757 * skip this code and make sure svc_run is entered elsewhere.
758 */
759 amuDebug(D_DAEMON) {
760#endif /* DEBUG */
761
762 /*
763 * Dissociate from the controlling terminal
764 */
765 amu_release_controlling_tty();
766
767 /*
768 * signal parent we are ready. parent should
769 * mount(2) and die.
770 */
771 if (kill(getppid(), SIGUSR2) < 0)
772 fatal("kill: %m");
773 plog(XLOG_INFO, "starting svc_run");
774 svc_run();
775 cleanup(0); /* should never happen, just in case */
776#ifdef DEBUG
777 } /* end of code that runs iff hlfsd daemonizes */
778#endif /* DEBUG */
779
780}
781
782
783static RETSIGTYPE
784proceed(int signum)
785{
786 stoplight = signum;
787}
788
789
790static RETSIGTYPE
791reload(int signum)
792{
793 int child;
794 int status;
795
796 clock_valid = 0; /* invalidate logging clock */
797
798 if (getpid() != masterpid)
799 return;
800
801 /*
802 * If received a SIGHUP, close and reopen the log file (so that it
803 * can be rotated)
804 */
805 if (signum == SIGHUP && logfile)
806 switch_to_logfile(logfile, orig_umask);
807
808 /*
809 * parent performs the reload, while the child continues to serve
810 * clients accessing the home dir link.
811 */
812 if ((child = fork()) > 0) {
813 serverpid = child; /* parent runs here */
814 am_set_mypid();
815
816 plt_init();
817
818 if (kill(child, SIGKILL) < 0) {
819 plog(XLOG_ERROR, "kill child: %m");
820 } else { /* wait for child to die before continue */
821 if (wait(&status) != child) {
822 /*
823 * I took out this line because it generates annoying output. It
824 * indicates a very small bug in hlfsd which is totally harmless.
825 * It causes hlfsd to work a bit harder than it should.
826 * Nevertheless, I intend on fixing it in a future release.
827 * -Erez Zadok <ezk@cs.columbia.edu>
828 */
829 /* plog(XLOG_ERROR, "unknown child"); */
830 }
831 }
832 serverpid = masterpid;
833 } else if (child < 0) {
834 plog(XLOG_ERROR, "unable to fork: %m");
835 } else {
836 /* let child handle requests while we reload */
837 serverpid = getpid();
838 am_set_mypid();
839 }
840}
841
842
843RETSIGTYPE
844cleanup(int signum)
845{
846 struct stat stbuf;
847 int umount_result;
848
849 clock_valid = 0; /* invalidate logging clock */
850
851#ifdef DEBUG
852 amuDebug(D_DAEMON)
853#endif /* DEBUG */
854 if (getpid() != masterpid)
855 return;
856
857#ifdef DEBUG
858 amuDebug(D_DAEMON)
859#endif /* DEBUG */
860 if (fork() != 0) {
861 masterpid = 0;
862 am_set_mypid();
863 return;
864 }
865 am_set_mypid();
866
867 for (;;) {
868 while ((umount_result = UMOUNT_FS(dir_name, mnttab_file_name)) == EBUSY) {
869#ifdef DEBUG
870 dlog("cleanup(): umount delaying for 10 seconds");
871#endif /* DEBUG */
872 sleep(10);
873 }
874 if (stat(dir_name, &stbuf) == 0 && stbuf.st_ino == ROOTID) {
875 plog(XLOG_ERROR, "unable to unmount %s", dir_name);
876 plog(XLOG_ERROR, "suspending, unmount before terminating");
877 kill(am_mypid, SIGSTOP);
878 continue; /* retry unmount */
879 }
880 break;
881 }
882
883#ifdef DEBUG
884 dlog("cleanup(): killing processes and terminating");
885 amuDebug(D_DAEMON)
886#endif /* DEBUG */
887 kill(masterpid, SIGKILL);
888
889#ifdef DEBUG
890 amuDebug(D_DAEMON)
891#endif /* DEBUG */
892 kill(serverpid, SIGKILL);
893
894 plog(XLOG_INFO, "hlfsd terminating with status 0\n");
895 exit(0);
896}
897
898
899static RETSIGTYPE
900reaper(int signum)
901{
902 int result;
903
904 if (wait(&result) == masterpid) {
905 exit(4);
906 }
907}
908
909
910void
911hlfsd_going_down(int rc)
912{
913 int mypid = getpid(); /* XXX: should this be the global am_mypid */
914
915 if (mypid == masterpid)
916 cleanup(0);
917 else if (mypid == serverpid)
918 kill(masterpid, SIGTERM);
919
920 exit(rc);
921}
922
923
924void
925fatal(char *mess)
926{
927 if (logfile && !STREQ(logfile, "stderr")) {
928 char lessmess[128];
929 int messlen;
930
931 messlen = strlen(mess);
932
933 if (!STREQ(&mess[messlen + 1 - sizeof(ERRM)], ERRM))
934 fprintf(stderr, "%s: %s\n", am_get_progname(), mess);
935 else {
936 strcpy(lessmess, mess);
937 lessmess[messlen - 4] = '\0';
938
939 if (errno < sys_nerr)
940 fprintf(stderr, "%s: %s: %s\n", am_get_progname(), lessmess,
941#ifdef HAVE_STRERROR
942 strerror(errno)
943#else /* not HAVE_STRERROR */
944 sys_errlist[errno]
945#endif /* not HAVE_STRERROR */
946 );
947 else
948 fprintf(stderr, "%s: %s: Error %d\n",
949 am_get_progname(), lessmess, errno);
950 }
951 }
952 plog(XLOG_FATAL, mess);
953
954 hlfsd_going_down(1);
955}