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