Actually hook powernow.4 into the build.
[dragonfly.git] / contrib / amd / hlfsd / hlfsd.c
blobc50d11721cd4fde7ec2d6ec95e8d0a1e7d921470
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.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
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.
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.
39 * %W% (Berkeley) %G%
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 $
43 * $DragonFly: src/contrib/amd/hlfsd/hlfsd.c,v 1.2 2003/06/17 04:23:57 dillon Exp $
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.
50 #ifdef HAVE_CONFIG_H
51 # include <config.h>
52 #endif /* HAVE_CONFIG_H */
53 #include <am_defs.h>
54 #include <hlfsd.h>
57 * STATIC VARIABLES:
59 static RETSIGTYPE proceed(int);
60 static RETSIGTYPE reaper(int);
61 static RETSIGTYPE reload(int);
62 static char *hlfs_group = DEFAULT_HLFS_GROUP;
63 static char default_dir_name[] = DEFAULT_DIRNAME;
64 static char *dir_name = default_dir_name;
65 static int printpid = 0;
66 static int stoplight = 0;
67 static void hlfsd_init(void);
68 static void usage(void);
70 static struct itimerval reloadinterval = {
71 {DEFAULT_INTERVAL, 0},
72 {DEFAULT_INTERVAL, 0}
76 * default mount options.
78 static char default_mntopts[] = "ro,noac";
81 * GLOBALS:
83 SVCXPRT *nfsxprt;
84 char *alt_spooldir = ALT_SPOOLDIR;
85 char *home_subdir = HOME_SUBDIR;
86 char *logfile = DEFAULT_LOGFILE;
87 char *passwdfile = NULL; /* alternate passwd file to use */
88 char *slinkname = 0;
89 char hostname[MAXHOSTNAMELEN + 1] = "localhost";
90 int cache_interval = DEFAULT_CACHE_INTERVAL;
91 gid_t hlfs_gid = (gid_t) INVALIDID;
92 int masterpid = 0;
93 int noverify = 0;
94 int orig_umask = 022;
95 int serverpid = 0;
96 nfstime startup;
97 u_short nfs_port;
99 /* symbol must be available always */
100 #ifdef MOUNT_TABLE_ON_FILE
101 char *mnttab_file_name = MNTTAB_FILE_NAME;
102 #else /* not MOUNT_TABLE_ON_FILE */
103 char *mnttab_file_name = NULL;
104 #endif /* not MOUNT_TABLE_ON_FILE */
106 /* forward declarations */
107 void hlfsd_going_down(int rc);
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);
127 main(int argc, char *argv[])
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;
152 #ifdef HAVE_SIGACTION
153 struct sigaction sa;
154 #endif /* not HAVE_SIGACTION */
156 #ifndef HAVE_TRANSPORT_TYPE_TLI
157 struct sockaddr_in localsocket;
158 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
161 /* get program name and truncate so we don't overflow progpid_fs */
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);
171 while ((opt = getopt(argc, argv, "a:c:CD:fg:hi:l:no:pP:x:v")) != -1)
172 switch (opt) {
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);
180 alt_spooldir = optarg;
181 break;
183 case 'c':
184 if (!atoi(optarg)) {
185 printf("%s: invalid interval for -c: %s\n",
186 am_get_progname(), optarg);
187 exit(3);
189 cache_interval = atoi(optarg);
190 break;
192 case 'C':
193 forcecache++;
194 break;
196 case 'f':
197 forcefast++;
198 break;
200 case 'g':
201 hlfs_group = optarg;
202 break;
204 case 'i':
205 if (!atoi(optarg)) {
206 printf("%s: invalid interval for -i: %s\n",
207 am_get_progname(), optarg);
208 exit(3);
210 reloadinterval.it_interval.tv_sec = atoi(optarg);
211 reloadinterval.it_value.tv_sec = atoi(optarg);
212 break;
214 case 'l':
215 logfile = optarg;
216 break;
218 case 'n':
219 noverify++;
220 break;
222 case 'o':
223 mntopts = optarg;
224 break;
226 case 'p':
227 printpid++;
228 break;
230 case 'P':
231 passwdfile = optarg;
232 break;
234 case 'v':
235 fprintf(stderr, "%s\n", HLFSD_VERSION);
236 exit(0);
238 case 'x':
239 opterrs += switch_option(optarg);
240 break;
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;
250 case 'h':
251 case '?':
252 opterrs++;
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 */
265 * Terminate if did not ask to forcecache (-C) and hlfsd would not be able
266 * to set the minimum cache intervals.
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);
273 #endif /* !defined(MNT2_NFS_OPT_ACREGMIN) && !defined(MNT2_NFS_OPT_NOAC) && !defined(HAVE_FIELD_NFS_ARGS_T_ACREGMIN) */
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++;
287 if (opterrs)
288 usage();
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);
295 setbuf(stdout, (char *) NULL);
296 umask(0);
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;
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);
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) */
320 /* avoid hanging on other NFS servers if started elsewhere */
321 if (chdir("/") < 0)
322 fatal("cannot chdir to /: %m");
324 if (geteuid() != 0)
325 fatal("must be root to mount filesystems");
328 * dir_name must match "^(/.*)/([^/]+)$", and is split at last '/' with
329 * slinkname = `basename $dir_name` - requires dir_name be writable
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);
342 clock_valid = 0; /* invalidate logging clock */
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);
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);
358 /* warn if extraneous stuff will be hidden by mount */
359 if ((mountdir = opendir(dir_name)) == NULL)
360 fatalerror(dir_name);
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;
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);
375 closedir(mountdir);
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);
385 chmod(alt_spooldir, OPEN_SPOOLMODE);
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);
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);
409 slinkname[-1] = '\0'; /* resplit dir_name */
410 } /* end of "if (!forcefast) {" */
413 * Register hlfsd as an nfs service with the portmapper.
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");
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 */
433 plog(XLOG_INFO, "Initializing hlfsd...");
434 hlfsd_init(); /* start up child (forking) to run svc_run */
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 */
446 #ifdef DEBUG
448 * In the parent, if -D nodaemon (or -D daemon) , we don't need to
449 * set this signal handler.
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);
460 #ifdef DEBUG
462 #endif /* DEBUG */
465 * setup options to mount table (/etc/{mtab,mnttab}) entry
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);
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.
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;
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".
503 mnt.mnt_type = HIDE_MOUNT_TYPE;
504 /* some systems don't have a mount type, but a mount flag */
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 */
513 * Update hostname field.
514 * Make some name prog:pid (i.e., hlfsd:174) for hostname
516 sprintf(progpid_fs, "%s:%d", am_get_progname(), masterpid);
518 /* Most kernels have a name length restriction. */
519 if ((int) strlen(progpid_fs) >= (int) MAXHOSTNAMELEN)
520 strcpy(progpid_fs + MAXHOSTNAMELEN - 3, "..");
522 genflags = compute_mount_flags(&mnt);
524 retry = hasmntval(&mnt, MNTTAB_OPT_RETRY);
525 if (retry <= 0)
526 retry = 1; /* XXX */
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 */
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)!
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 */
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);
569 clock_valid = 0; /* invalidate logging clock */
572 * The following code could be cleverly ifdef-ed, but I duplicated the
573 * mount_fs call three times for simplicity and readability.
575 #ifdef DEBUG
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.
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");
598 exit(0); /* all went well */
599 } else { /* fork failed or parent running */
600 plog(XLOG_INFO, "parent waiting 1sec for mount...");
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 */
609 #ifdef HAVE_TRANSPORT_TYPE_TLI
611 * XXX: this free_knetconfig() was not done for hlfsd before,
612 * and apparently there was a reason for it, but why? -Erez
614 free_knetconfig(nfs_args.knconf);
616 * local automounter mounts do not allocate a special address, so
617 * no need to XFREE(nfs_args.addr) under TLI.
619 #endif /* HAVE_TRANSPORT_TYPE_TLI */
621 if (printpid)
622 printf("%d\n", masterpid);
624 plog(XLOG_INFO, "hlfsd ready to serve");
625 #ifdef DEBUG
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.
630 dlog("starting no-daemon debugging svc_run");
631 amuDebugNo(D_DAEMON)
632 svc_run();
633 #endif /* DEBUG */
635 cleanup(0); /* should never happen here */
636 return (0); /* everything went fine? */
640 static void
641 hlfsd_init(void)
643 int child = 0;
644 #ifdef HAVE_SIGACTION
645 struct sigaction sa;
646 #endif /* HAVE_SIGACTION */
648 clock_valid = 0; /* invalidate logging clock */
651 * Initialize file handles.
653 plog(XLOG_INFO, "initializing hlfsd file handles");
654 hlfsd_init_filehandles();
656 #ifdef DEBUG
658 * If -D daemon then we must fork.
660 amuDebug(D_DAEMON)
661 #endif /* DEBUG */
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 *) 0) < 0)
749 fatal("setitimer: %m");
751 gettimeofday((struct timeval *) &startup, (struct timezone *) 0);
753 #ifdef DEBUG
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.
759 amuDebug(D_DAEMON) {
760 #endif /* DEBUG */
763 * Dissociate from the controlling terminal
765 amu_release_controlling_tty();
768 * signal parent we are ready. parent should
769 * mount(2) and die.
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 */
783 static RETSIGTYPE
784 proceed(int signum)
786 stoplight = signum;
790 static RETSIGTYPE
791 reload(int signum)
793 int child;
794 int status;
796 clock_valid = 0; /* invalidate logging clock */
798 if (getpid() != masterpid)
799 return;
802 * If received a SIGHUP, close and reopen the log file (so that it
803 * can be rotated)
805 if (signum == SIGHUP && logfile)
806 switch_to_logfile(logfile, orig_umask);
809 * parent performs the reload, while the child continues to serve
810 * clients accessing the home dir link.
812 if ((child = fork()) > 0) {
813 serverpid = child; /* parent runs here */
814 am_set_mypid();
816 plt_init();
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) {
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>
829 /* plog(XLOG_ERROR, "unknown child"); */
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();
843 RETSIGTYPE
844 cleanup(int signum)
846 struct stat stbuf;
847 int umount_result;
849 clock_valid = 0; /* invalidate logging clock */
851 #ifdef DEBUG
852 amuDebug(D_DAEMON)
853 #endif /* DEBUG */
854 if (getpid() != masterpid)
855 return;
857 #ifdef DEBUG
858 amuDebug(D_DAEMON)
859 #endif /* DEBUG */
860 if (fork() != 0) {
861 masterpid = 0;
862 am_set_mypid();
863 return;
865 am_set_mypid();
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);
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 */
880 break;
883 #ifdef DEBUG
884 dlog("cleanup(): killing processes and terminating");
885 amuDebug(D_DAEMON)
886 #endif /* DEBUG */
887 kill(masterpid, SIGKILL);
889 #ifdef DEBUG
890 amuDebug(D_DAEMON)
891 #endif /* DEBUG */
892 kill(serverpid, SIGKILL);
894 plog(XLOG_INFO, "hlfsd terminating with status 0\n");
895 exit(0);
899 static RETSIGTYPE
900 reaper(int signum)
902 int result;
904 if (wait(&result) == masterpid) {
905 exit(4);
910 void
911 hlfsd_going_down(int rc)
913 int mypid = getpid(); /* XXX: should this be the global am_mypid */
915 if (mypid == masterpid)
916 cleanup(0);
917 else if (mypid == serverpid)
918 kill(masterpid, SIGTERM);
920 exit(rc);
924 void
925 fatal(char *mess)
927 if (logfile && !STREQ(logfile, "stderr")) {
928 char lessmess[128];
929 int messlen;
931 messlen = strlen(mess);
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';
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 */
947 else
948 fprintf(stderr, "%s: %s: Error %d\n",
949 am_get_progname(), lessmess, errno);
952 plog(XLOG_FATAL, mess);
954 hlfsd_going_down(1);