No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / am-utils / dist / hlfsd / hlfsd.c
blob6e5cc24e2f8e45398b87ef6cbdae7b8945929883
1 /* $NetBSD$ */
3 /*
4 * Copyright (c) 1997-2009 Erez Zadok
5 * Copyright (c) 1989 Jan-Simon Pendry
6 * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
7 * Copyright (c) 1989 The Regents of the University of California.
8 * All rights reserved.
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgment:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
42 * File: am-utils/hlfsd/hlfsd.c
44 * HLFSD was written at Columbia University Computer Science Department, by
45 * Erez Zadok <ezk@cs.columbia.edu> and Alexander Dupuy <dupuy@cs.columbia.edu>
46 * It is being distributed under the same terms and conditions as amd does.
49 #ifdef HAVE_CONFIG_H
50 # include <config.h>
51 #endif /* HAVE_CONFIG_H */
52 #include <am_defs.h>
53 #include <hlfsd.h>
56 * STATIC VARIABLES:
58 static RETSIGTYPE proceed(int);
59 static RETSIGTYPE reaper(int);
60 static RETSIGTYPE reload(int);
61 static char *hlfs_group = DEFAULT_HLFS_GROUP;
62 static char default_dir_name[] = DEFAULT_DIRNAME;
63 static char *dir_name = default_dir_name;
64 static int printpid = 0;
65 static int stoplight = 0;
66 static void hlfsd_init(void);
67 static void usage(void);
69 static struct itimerval reloadinterval = {
70 {DEFAULT_INTERVAL, 0},
71 {DEFAULT_INTERVAL, 0}
75 * default mount options.
77 static char default_mntopts[] = "ro,noac";
80 * GLOBALS:
82 SVCXPRT *nfsxprt;
83 char *alt_spooldir = ALT_SPOOLDIR;
84 char *home_subdir = HOME_SUBDIR;
85 char *logfile = DEFAULT_LOGFILE;
86 char *passwdfile = NULL; /* alternate passwd file to use */
87 char *slinkname = NULL;
88 char hostname[MAXHOSTNAMELEN + 1] = "localhost";
89 u_int cache_interval = DEFAULT_CACHE_INTERVAL;
90 gid_t hlfs_gid = (gid_t) INVALIDID;
91 int masterpid = 0;
92 int noverify = 0;
93 int orig_umask = 022;
94 int serverpid = 0;
95 nfstime startup;
96 u_short nfs_port;
98 /* symbol must be available always */
99 #ifdef MNTTAB_FILE_NAME
100 char *mnttab_file_name = MNTTAB_FILE_NAME;
101 #else /* not MNTTAB_FILE_NAME */
102 char *mnttab_file_name = NULL;
103 #endif /* not MNTTAB_FILE_NAME */
105 /* forward declarations */
106 void hlfsd_going_down(int rc);
107 void fatalerror(char *str);
110 static void
111 usage(void)
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);
126 void
127 fatalerror(char *str)
129 #define ERRM ": %m"
130 size_t l = strlen(str) + sizeof(ERRM) - 1;
131 char *tmp = strnsave(str, l);
132 xstrlcat(tmp, ERRM, l);
133 fatal(tmp);
138 main(int argc, char *argv[])
140 char *dot;
141 char *mntopts = (char *) NULL;
142 char hostpid_fs[MAXHOSTNAMELEN + 1 + 16]; /* room for ":(pid###)" */
143 char progpid_fs[PROGNAMESZ + 1 + 11]; /* room for ":pid" */
144 char preopts[128];
145 char *progname;
146 int forcecache = 0;
147 int forcefast = 0;
148 int genflags = 0;
149 int opt, ret;
150 int opterrs = 0;
151 int retry;
152 int soNFS; /* NFS socket */
153 int s = -99;
154 mntent_t mnt;
155 nfs_args_t nfs_args;
156 am_nfs_handle_t anh;
157 struct dirent *direntry;
158 struct group *grp;
159 struct stat stmodes;
160 DIR *mountdir;
161 MTYPE_TYPE type = MOUNT_TYPE_NFS;
163 #ifdef HAVE_SIGACTION
164 struct sigaction sa;
165 #endif /* not HAVE_SIGACTION */
167 #ifndef HAVE_TRANSPORT_TYPE_TLI
168 struct sockaddr_in localsocket;
169 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
172 /* get program name and truncate so we don't overflow progpid_fs */
174 if ((progname = strrchr(argv[0], '/')) != NULL)
175 progname++;
176 else
177 progname = argv[0];
178 if ((int) strlen(progname) > PROGNAMESZ) /* truncate to reasonable size */
179 progname[PROGNAMESZ] = '\0';
180 am_set_progname(progname);
182 while ((opt = getopt(argc, argv, "a:c:CD:fg:hi:l:no:pP:x:v")) != -1)
183 switch (opt) {
185 case 'a':
186 if (!optarg || optarg[0] != '/') {
187 printf("%s: invalid directory for -a: %s\n",
188 am_get_progname(), optarg);
189 exit(3);
191 alt_spooldir = optarg;
192 break;
194 case 'c':
195 if (!atoi(optarg)) {
196 printf("%s: invalid interval for -c: %s\n",
197 am_get_progname(), optarg);
198 exit(3);
200 cache_interval = atoi(optarg);
201 break;
203 case 'C':
204 forcecache++;
205 break;
207 case 'f':
208 forcefast++;
209 break;
211 case 'g':
212 hlfs_group = optarg;
213 break;
215 case 'i':
216 if (!atoi(optarg)) {
217 printf("%s: invalid interval for -i: %s\n",
218 am_get_progname(), optarg);
219 exit(3);
221 reloadinterval.it_interval.tv_sec = atoi(optarg);
222 reloadinterval.it_value.tv_sec = atoi(optarg);
223 break;
225 case 'l':
226 logfile = optarg;
227 break;
229 case 'n':
230 noverify++;
231 break;
233 case 'o':
234 mntopts = optarg;
235 break;
237 case 'p':
238 printpid++;
239 break;
241 case 'P':
242 passwdfile = optarg;
243 break;
245 case 'v':
246 fprintf(stderr, "%s\n", HLFSD_VERSION);
247 exit(0);
249 case 'x':
250 opterrs += switch_option(optarg);
251 break;
253 case 'D':
254 #ifdef DEBUG
255 opterrs += debug_option(optarg);
256 #else /* not DEBUG */
257 fprintf(stderr, "%s: not compiled with DEBUG -- sorry.\n", am_get_progname());
258 #endif /* not DEBUG */
259 break;
261 case 'h':
262 case '?':
263 opterrs++;
266 /* need my pid before any dlog/plog */
267 am_set_mypid();
268 #ifdef DEBUG
269 switch_option("debug");
270 #endif /* DEBUG */
273 * Terminate if did not ask to forcecache (-C) and hlfsd would not be able
274 * to set the minimum cache intervals.
276 #if !defined(MNT2_NFS_OPT_ACREGMIN) && !defined(MNT2_NFS_OPT_NOAC) && !defined(HAVE_NFS_ARGS_T_ACREGMIN)
277 if (!forcecache) {
278 fprintf(stderr, "%s: will not be able to turn off attribute caches.\n", am_get_progname());
279 exit(1);
281 #endif /* !defined(MNT2_NFS_OPT_ACREGMIN) && !defined(MNT2_NFS_OPT_NOAC) && !defined(HAVE_NFS_ARGS_T_ACREGMIN) */
284 switch (argc - optind) {
285 case 2:
286 home_subdir = argv[optind + 1];
287 case 1:
288 dir_name = argv[optind];
289 case 0:
290 break;
291 default:
292 opterrs++;
295 if (opterrs)
296 usage();
298 /* ensure that only root can run hlfsd */
299 if (geteuid()) {
300 fprintf(stderr, "hlfsd can only be run as root\n");
301 exit(1);
303 setbuf(stdout, (char *) NULL);
304 umask(0);
306 /* find gid for hlfs_group */
307 if ((grp = getgrnam(hlfs_group)) == (struct group *) NULL) {
308 fprintf(stderr, "%s: cannot get gid for group \"%s\".\n",
309 am_get_progname(), hlfs_group);
310 } else {
311 hlfs_gid = grp->gr_gid;
314 /* get hostname for logging and open log before we reset umask */
315 gethostname(hostname, sizeof(hostname));
316 hostname[sizeof(hostname) - 1] = '\0';
317 if ((dot = strchr(hostname, '.')) != NULL)
318 *dot = '\0';
319 orig_umask = umask(0);
320 if (logfile)
321 switch_to_logfile(logfile, orig_umask, 0);
323 #ifndef MOUNT_TABLE_ON_FILE
324 if (amuDebug(D_MTAB))
325 dlog("-D mtab option ignored");
326 #endif /* not MOUNT_TABLE_ON_FILE */
328 /* avoid hanging on other NFS servers if started elsewhere */
329 if (chdir("/") < 0)
330 fatal("cannot chdir to /: %m");
332 if (geteuid() != 0)
333 fatal("must be root to mount filesystems");
336 * dir_name must match "^(/.*)/([^/]+)$", and is split at last '/' with
337 * slinkname = `basename $dir_name` - requires dir_name be writable
340 if (dir_name[0] != '/'
341 || ((slinkname = strrchr(dir_name, '/')), *slinkname++ = '\0',
342 (dir_name[0] == '\0' || slinkname[0] == '\0'))) {
343 if (slinkname)
344 *--slinkname = '/';
345 printf("%s: invalid mount directory/link %s\n",
346 am_get_progname(), dir_name);
347 exit(3);
350 if (!forcefast) {
351 /* make sure mount point exists and is at least mode 555 */
352 if (stat(dir_name, &stmodes) < 0)
353 if (errno != ENOENT || mkdirs(dir_name, 0555) < 0
354 || stat(dir_name, &stmodes) < 0)
355 fatalerror(dir_name);
357 if ((stmodes.st_mode & 0555) != 0555) {
358 fprintf(stderr, "%s: directory %s not read/executable\n",
359 am_get_progname(), dir_name);
360 plog(XLOG_WARNING, "directory %s not read/executable",
361 dir_name);
364 /* warn if extraneous stuff will be hidden by mount */
365 if ((mountdir = opendir(dir_name)) == NULL)
366 fatalerror(dir_name);
368 while ((direntry = readdir(mountdir)) != NULL) {
369 if (!NSTREQ(".", direntry->d_name, NAMLEN(direntry)) &&
370 !NSTREQ("..", direntry->d_name, NAMLEN(direntry)) &&
371 !NSTREQ(slinkname, direntry->d_name, NAMLEN(direntry)))
372 break;
375 if (direntry != NULL) {
376 fprintf(stderr, "%s: %s/%s will be hidden by mount\n",
377 am_get_progname(), dir_name, direntry->d_name);
378 plog(XLOG_WARNING, "%s/%s will be hidden by mount\n",
379 dir_name, direntry->d_name);
381 closedir(mountdir);
383 /* make sure alternate spool dir exists */
384 if ((errno = mkdirs(alt_spooldir, OPEN_SPOOLMODE))) {
385 fprintf(stderr, "%s: cannot create alternate dir ",
386 am_get_progname());
387 perror(alt_spooldir);
388 plog(XLOG_ERROR, "cannot create alternate dir %s: %m",
389 alt_spooldir);
391 chmod(alt_spooldir, OPEN_SPOOLMODE);
393 /* create failsafe link to alternate spool directory */
394 *(slinkname-1) = '/'; /* unsplit dir_name to include link */
395 if (lstat(dir_name, &stmodes) == 0 &&
396 (stmodes.st_mode & S_IFMT) != S_IFLNK) {
397 fprintf(stderr, "%s: failsafe %s not a symlink\n",
398 am_get_progname(), dir_name);
399 plog(XLOG_WARNING, "failsafe %s not a symlink\n",
400 dir_name);
401 } else {
402 unlink(dir_name);
404 if (symlink(alt_spooldir, dir_name) < 0) {
405 fprintf(stderr,
406 "%s: cannot create failsafe symlink %s -> ",
407 am_get_progname(), dir_name);
408 perror(alt_spooldir);
409 plog(XLOG_WARNING,
410 "cannot create failsafe symlink %s -> %s: %m",
411 dir_name, alt_spooldir);
415 *(slinkname-1) = '\0'; /* resplit dir_name */
416 } /* end of "if (!forcefast) {" */
419 * Register hlfsd as an nfs service with the portmapper.
421 #ifdef HAVE_TRANSPORT_TYPE_TLI
422 ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2);
423 #else /* not HAVE_TRANSPORT_TYPE_TLI */
424 ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2);
425 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
426 if (ret != 0)
427 fatal("cannot create NFS service");
429 #ifdef HAVE_SIGACTION
430 sa.sa_handler = proceed;
431 sa.sa_flags = 0;
432 sigemptyset(&(sa.sa_mask));
433 sigaddset(&(sa.sa_mask), SIGUSR2);
434 sigaction(SIGUSR2, &sa, NULL);
435 #else /* not HAVE_SIGACTION */
436 signal(SIGUSR2, proceed);
437 #endif /* not HAVE_SIGACTION */
439 plog(XLOG_INFO, "Initializing hlfsd...");
440 hlfsd_init(); /* start up child (forking) to run svc_run */
442 #ifdef HAVE_SIGACTION
443 sa.sa_handler = reaper;
444 sa.sa_flags = 0;
445 sigemptyset(&(sa.sa_mask));
446 sigaddset(&(sa.sa_mask), SIGCHLD);
447 sigaction(SIGCHLD, &sa, NULL);
448 #else /* not HAVE_SIGACTION */
449 signal(SIGCHLD, reaper);
450 #endif /* not HAVE_SIGACTION */
453 * In the parent, if -D nodaemon, we don't need to
454 * set this signal handler.
456 if (amuDebug(D_DAEMON)) {
457 s = -99;
458 while (stoplight != SIGUSR2) {
459 plog(XLOG_INFO, "parent waits for child to setup (stoplight=%d)", stoplight);
460 #ifdef HAVE_SIGSUSPEND
462 sigset_t mask;
463 sigemptyset(&mask);
464 s = sigsuspend(&mask); /* wait for child to set up */
466 #else /* not HAVE_SIGSUSPEND */
467 s = sigpause(0); /* wait for child to set up */
468 #endif /* not HAVE_SIGSUSPEND */
469 sleep(1);
474 * setup options to mount table (/etc/{mtab,mnttab}) entry
476 xsnprintf(hostpid_fs, sizeof(hostpid_fs),
477 "%s:(pid%d)", hostname, masterpid);
478 memset((char *) &mnt, 0, sizeof(mnt));
479 mnt.mnt_dir = dir_name; /* i.e., "/mail" */
480 mnt.mnt_fsname = hostpid_fs;
481 if (mntopts) {
482 mnt.mnt_opts = mntopts;
483 } else {
484 xstrlcpy(preopts, default_mntopts, sizeof(preopts));
486 * Turn off all kinds of attribute and symlink caches as
487 * much as possible. Also make sure that mount does not
488 * show up to df.
490 #ifdef MNTTAB_OPT_INTR
491 xstrlcat(preopts, ",", sizeof(preopts));
492 xstrlcat(preopts, MNTTAB_OPT_INTR, sizeof(preopts));
493 #endif /* MNTTAB_OPT_INTR */
494 #ifdef MNTTAB_OPT_IGNORE
495 xstrlcat(preopts, ",", sizeof(preopts));
496 xstrlcat(preopts, MNTTAB_OPT_IGNORE, sizeof(preopts));
497 #endif /* MNTTAB_OPT_IGNORE */
498 #ifdef MNT2_GEN_OPT_CACHE
499 xstrlcat(preopts, ",nocache", sizeof(preopts));
500 #endif /* MNT2_GEN_OPT_CACHE */
501 #ifdef MNT2_NFS_OPT_SYMTTL
502 xstrlcat(preopts, ",symttl=0", sizeof(preopts));
503 #endif /* MNT2_NFS_OPT_SYMTTL */
504 mnt.mnt_opts = preopts;
508 * Make sure that amd's top-level NFS mounts are hidden by default
509 * from df.
510 * If they don't appear to support the either the "ignore" mnttab
511 * option entry, or the "auto" one, set the mount type to "nfs".
513 #ifdef HIDE_MOUNT_TYPE
514 mnt.mnt_type = HIDE_MOUNT_TYPE;
515 #else /* not HIDE_MOUNT_TYPE */
516 mnt.mnt_type = "nfs";
517 #endif /* not HIDE_MOUNT_TYPE */
518 /* some systems don't have a mount type, but a mount flag */
520 #ifndef HAVE_TRANSPORT_TYPE_TLI
521 amu_get_myaddress(&localsocket.sin_addr, NULL);
522 localsocket.sin_family = AF_INET;
523 localsocket.sin_port = htons(nfsxprt->xp_port);
524 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
527 * Update hostname field.
528 * Make some name prog:pid (i.e., hlfsd:174) for hostname
530 xsnprintf(progpid_fs, sizeof(progpid_fs),
531 "%s:%d", am_get_progname(), masterpid);
533 /* Most kernels have a name length restriction. */
534 if ((int) strlen(progpid_fs) >= (int) MAXHOSTNAMELEN)
535 xstrlcpy(progpid_fs + MAXHOSTNAMELEN - 3, "..",
536 sizeof(progpid_fs) - MAXHOSTNAMELEN + 3);
538 genflags = compute_mount_flags(&mnt);
540 retry = hasmntval(&mnt, MNTTAB_OPT_RETRY);
541 if (retry <= 0)
542 retry = 1; /* XXX */
544 memmove(&anh.v2, root_fhp, sizeof(*root_fhp));
545 #ifdef HAVE_TRANSPORT_TYPE_TLI
546 compute_nfs_args(&nfs_args,
547 &mnt,
548 genflags,
549 nfsncp,
550 NULL, /* remote host IP addr is set below */
551 NFS_VERSION, /* version 2 */
552 "udp", /* XXX: shouldn't this be "udp"? */
553 &anh,
554 progpid_fs, /* host name for kernel */
555 hostpid_fs); /* filesystem name for kernel */
557 * IMPORTANT: set the correct IP address AFTERWARDS. It cannot
558 * be done using the normal mechanism of compute_nfs_args(), because
559 * that one will allocate a new address and use NFS_SA_DREF() to copy
560 * parts to it, while assuming that the ip_addr passed is always
561 * a "struct sockaddr_in". That assumption is incorrect on TLI systems,
562 * because they define a special macro HOST_SELF which is DIFFERENT
563 * than localhost (127.0.0.1)!
565 nfs_args.addr = &nfsxprt->xp_ltaddr;
566 #else /* not HAVE_TRANSPORT_TYPE_TLI */
567 compute_nfs_args(&nfs_args,
568 &mnt,
569 genflags,
570 NULL,
571 &localsocket,
572 NFS_VERSION, /* version 2 */
573 "udp", /* XXX: shouldn't this be "udp"? */
574 &anh,
575 progpid_fs, /* host name for kernel */
576 hostpid_fs); /* filesystem name for kernel */
577 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
579 /*************************************************************************
580 * NOTE: while compute_nfs_args() works ok for regular NFS mounts *
581 * the toplvl one is not, and so some options must be corrected by hand *
582 * more carefully, *after* compute_nfs_args() runs. *
583 *************************************************************************/
584 compute_automounter_nfs_args(&nfs_args, &mnt);
587 * For some reason, this mount may have to be done in the background, if I am
588 * using -D daemon. I suspect that the actual act of mounting requires
589 * calling to hlfsd itself to invoke one or more of its nfs calls, to stat
590 * /mail. That means that even if you say -D daemon, at least the mount
591 * of hlfsd itself on top of /mail will be done in the background.
592 * The other alternative I have is to run svc_run, but set a special
593 * signal handler to perform the mount in N seconds via some alarm.
594 * -Erez Zadok.
596 if (!amuDebug(D_DAEMON)) { /* Normal case */
597 plog(XLOG_INFO, "normal NFS mounting hlfsd service points");
598 if (mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name, 0) < 0)
599 fatal("nfsmount: %m");
600 } else { /* asked for -D daemon */
601 if (fork() == 0) { /* child runs mount */
602 am_set_mypid();
603 foreground = 0;
604 plog(XLOG_INFO, "child NFS mounting hlfsd service points");
605 if (mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name, 0) < 0) {
606 fatal("nfsmount: %m");
608 exit(0); /* all went well */
609 } else { /* fork failed or parent running */
610 plog(XLOG_INFO, "parent waiting 1sec for mount...");
614 #ifdef HAVE_TRANSPORT_TYPE_TLI
616 * XXX: this free_knetconfig() was not done for hlfsd before,
617 * and apparently there was a reason for it, but why? -Erez
619 free_knetconfig(nfs_args.knconf);
621 * local automounter mounts do not allocate a special address, so
622 * no need to XFREE(nfs_args.addr) under TLI.
624 #endif /* HAVE_TRANSPORT_TYPE_TLI */
626 if (printpid)
627 printf("%d\n", masterpid);
629 plog(XLOG_INFO, "hlfsd ready to serve");
631 * If asked not to fork a daemon (-D nodaemon), then hlfsd_init()
632 * will not run svc_run. We must start svc_run here.
634 if (!amuDebug(D_DAEMON)) {
635 plog(XLOG_DEBUG, "starting no-daemon debugging svc_run");
636 svc_run();
639 cleanup(0); /* should never happen here */
640 return (0); /* everything went fine? */
644 static void
645 hlfsd_init(void)
647 int child = 0;
648 #ifdef HAVE_SIGACTION
649 struct sigaction sa;
650 #endif /* HAVE_SIGACTION */
653 * Initialize file handles.
655 plog(XLOG_INFO, "initializing hlfsd file handles");
656 hlfsd_init_filehandles();
659 * If -D daemon then we must fork.
661 if (amuDebug(D_DAEMON))
662 child = fork();
664 if (child < 0)
665 fatal("fork: %m");
667 if (child != 0) { /* parent process - save child pid */
668 masterpid = child;
669 am_set_mypid(); /* for logging routines */
670 return;
674 * CHILD CODE:
675 * initialize server
678 plog(XLOG_INFO, "initializing home directory database");
679 plt_init(); /* initialize database */
680 plog(XLOG_INFO, "home directory database initialized");
682 masterpid = serverpid = am_set_mypid(); /* for logging routines */
685 * SIGALRM/SIGHUP: reload password database if timer expired
686 * or user sent HUP signal.
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 */
702 * SIGTERM: cleanup and exit.
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 */
715 * SIGCHLD: interlock synchronization and testing
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 */
728 * SIGUSR1: dump internal hlfsd maps/cache to file
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 */
748 if (setitimer(ITIMER_REAL, &reloadinterval, (struct itimerval *) NULL) < 0)
749 fatal("setitimer: %m");
751 clocktime(&startup);
754 * If -D daemon, then start serving here in the child,
755 * and the parent will exit. But if -D nodaemon, then
756 * skip this code and make sure svc_run is entered elsewhere.
758 if (amuDebug(D_DAEMON)) {
760 * Dissociate from the controlling terminal
762 amu_release_controlling_tty();
765 * signal parent we are ready. parent should
766 * mount(2) and die.
768 if (kill(getppid(), SIGUSR2) < 0)
769 fatal("kill: %m");
770 plog(XLOG_INFO, "starting svc_run");
771 svc_run();
772 cleanup(0); /* should never happen, just in case */
778 static RETSIGTYPE
779 proceed(int signum)
781 stoplight = signum;
785 static RETSIGTYPE
786 reload(int signum)
788 int child;
789 int status;
791 if (getpid() != masterpid)
792 return;
795 * If received a SIGHUP, close and reopen the log file (so that it
796 * can be rotated)
798 if (signum == SIGHUP && logfile)
799 switch_to_logfile(logfile, orig_umask, 0);
802 * parent performs the reload, while the child continues to serve
803 * clients accessing the home dir link.
805 if ((child = fork()) > 0) {
806 serverpid = child; /* parent runs here */
807 am_set_mypid();
809 plt_init();
811 if (kill(child, SIGKILL) < 0) {
812 plog(XLOG_ERROR, "kill child: %m");
813 } else { /* wait for child to die before continue */
814 if (wait(&status) != child) {
816 * I took out this line because it generates annoying output. It
817 * indicates a very small bug in hlfsd which is totally harmless.
818 * It causes hlfsd to work a bit harder than it should.
819 * Nevertheless, I intend on fixing it in a future release.
820 * -Erez Zadok <ezk@cs.columbia.edu>
822 /* plog(XLOG_ERROR, "unknown child"); */
825 serverpid = masterpid;
826 } else if (child < 0) {
827 plog(XLOG_ERROR, "unable to fork: %m");
828 } else {
829 /* let child handle requests while we reload */
830 serverpid = getpid();
831 am_set_mypid();
836 RETSIGTYPE
837 cleanup(int signum)
839 struct stat stbuf;
840 int umount_result;
842 if (amuDebug(D_DAEMON)) {
843 if (getpid() != masterpid)
844 return;
846 if (fork() != 0) {
847 masterpid = 0;
848 am_set_mypid();
849 return;
852 am_set_mypid();
854 for (;;) {
855 while ((umount_result = UMOUNT_FS(dir_name, mnttab_file_name, 0)) == EBUSY) {
856 dlog("cleanup(): umount delaying for 10 seconds");
857 sleep(10);
859 if (stat(dir_name, &stbuf) == 0 && stbuf.st_ino == ROOTID) {
860 plog(XLOG_ERROR, "unable to unmount %s", dir_name);
861 plog(XLOG_ERROR, "suspending, unmount before terminating");
862 kill(am_mypid, SIGSTOP);
863 continue; /* retry unmount */
865 break;
868 if (amuDebug(D_DAEMON)) {
869 plog(XLOG_INFO, "cleanup(): killing processes and terminating");
870 kill(masterpid, SIGKILL);
871 kill(serverpid, SIGKILL);
874 plog(XLOG_INFO, "hlfsd terminating with status 0\n");
875 _exit(0);
879 static RETSIGTYPE
880 reaper(int signum)
882 int result;
884 if (wait(&result) == masterpid) {
885 _exit(4);
890 void
891 hlfsd_going_down(int rc)
893 int mypid = getpid(); /* XXX: should this be the global am_mypid */
895 if (mypid == masterpid)
896 cleanup(0);
897 else if (mypid == serverpid)
898 kill(masterpid, SIGTERM);
900 exit(rc);
904 void
905 fatal(char *mess)
907 if (logfile && !STREQ(logfile, "stderr")) {
908 char lessmess[128];
909 int messlen;
911 messlen = strlen(mess);
913 if (!STREQ(&mess[messlen + 1 - sizeof(ERRM)], ERRM))
914 fprintf(stderr, "%s: %s\n", am_get_progname(), mess);
915 else {
916 xstrlcpy(lessmess, mess, sizeof(lessmess));
917 lessmess[messlen - 4] = '\0';
919 fprintf(stderr, "%s: %s: %s\n",
920 am_get_progname(), lessmess, strerror(errno));
923 plog(XLOG_FATAL, "%s", mess);
925 hlfsd_going_down(1);