static RETSIGTYPE reload(int signum) { int child; int status; if (getpid() != masterpid) return; /* * If received a SIGHUP, close and reopen the log file (so that it * can be rotated) */ if (signum == SIGHUP && logfile) switch_to_logfile(logfile, orig_umask, 0); /* * parent performs the reload, while the child continues to serve * clients accessing the home dir link. */ if ((child = fork()) > 0) { serverpid = child; /* parent runs here */ am_set_mypid(); plt_init(); if (kill(child, SIGKILL) < 0) { plog(XLOG_ERROR, "kill child: %m"); } else { /* wait for child to die before continue */ if (wait(&status) != child) { /* * I took out this line because it generates annoying output. It * indicates a very small bug in hlfsd which is totally harmless. * It causes hlfsd to work a bit harder than it should. * Nevertheless, I intend on fixing it in a future release. * -Erez Zadok <*****@*****.**> */ /* plog(XLOG_ERROR, "unknown child"); */ } } serverpid = masterpid; } else if (child < 0) { plog(XLOG_ERROR, "unable to fork: %m"); } else { /* let child handle requests while we reload */ serverpid = getpid(); am_set_mypid(); } }
RETSIGTYPE cleanup(int signum) { struct stat stbuf; int umount_result; if (amuDebug(D_DAEMON)) { if (getpid() != masterpid) return; if (fork() != 0) { masterpid = 0; am_set_mypid(); return; } } am_set_mypid(); for (;;) { while ((umount_result = UMOUNT_FS(dir_name, mnttab_file_name, 0)) == EBUSY) { dlog("cleanup(): umount delaying for 10 seconds"); sleep(10); } if (stat(dir_name, &stbuf) == 0 && stbuf.st_ino == ROOTID) { plog(XLOG_ERROR, "unable to unmount %s", dir_name); plog(XLOG_ERROR, "suspending, unmount before terminating"); kill(am_mypid, SIGSTOP); continue; /* retry unmount */ } break; } if (amuDebug(D_DAEMON)) { plog(XLOG_INFO, "cleanup(): killing processes and terminating"); kill(masterpid, SIGKILL); kill(serverpid, SIGKILL); } plog(XLOG_INFO, "hlfsd terminating with status 0\n"); _exit(0); }
/* * Fork the automounter * * TODO: Need a better strategy for handling errors */ static int dofork(void) { int pid; top: pid = fork(); if (pid < 0) { /* fork error, retry in 1 second */ sleep(1); goto top; } if (pid == 0) { /* child process (foreground==false) */ am_set_mypid(); foreground = 0; } else { /* parent process, has one more child */ NumChild++; } return pid; }
/* * Return the home directory pathname for the user with uid "userid". */ char * homedir(int userid, int groupid) { static char linkval[MAXPATHLEN + 1]; static struct timeval tp; uid2home_t *found; char *homename; struct stat homestat; int old_groupid, old_userid; clock_valid = 0; /* invalidate logging clock */ if ((found = plt_search(userid)) == (uid2home_t *) NULL) { return alt_spooldir; /* use alt spool for unknown uid */ } homename = found->home; if (homename[0] != '/' || homename[1] == '\0') { found->last_status = 1; return alt_spooldir; /* use alt spool for / or rel. home */ } if ((int) userid == 0) /* force all uid 0 to use root's home */ sprintf(linkval, "%s/%s", root_home, home_subdir); else sprintf(linkval, "%s/%s", homename, home_subdir); if (noverify) { found->last_status = 0; return linkval; } /* * To optimize hlfsd, we don't actually check the validity of the * symlink if it has been checked in the last N seconds. It is * very likely that the link, machine, and filesystem are still * valid, as long as N is small. But if N is large, that may not be * true. That's why the default N is 5 minutes, but we allow the * user to override this value via a command line option. Note that * we do not update the last_access_time each time it is accessed, * but only once every N seconds. */ if (gettimeofday(&tp, (struct timezone *) NULL) < 0) { tp.tv_sec = 0; } else { if ((tp.tv_sec - found->last_access_time) < cache_interval) { if (found->last_status == 0) { return linkval; } else { return alt_spooldir; } } else { found->last_access_time = tp.tv_sec; } } #ifdef DEBUG /* * only run this forking code if asked for -D fork * or if did not ask for -D nofork */ amuDebug(D_FORK) { #endif /* DEBUG */ /* fork child to process request if none in progress */ if (found->child && kill(found->child, 0)) found->child = 0; if (found->child) delay(found, 5); /* wait a bit if in progress */ if (found->child) { /* better safe than sorry - maybe */ found->last_status = 1; return alt_spooldir; } if ((found->child = fork()) < 0) { found->last_status = 1; return alt_spooldir; } if (found->child) { /* PARENT */ #ifdef DEBUG if (lastchild) plog(XLOG_INFO, "cache spill uid = %ld, pid = %ld, home = %s", (long) lastchild->uid, (long) lastchild->child, lastchild->home); #endif /* DEBUG */ lastchild = found; return (char *) NULL; /* return NULL to parent, so it can continue */ } #ifdef DEBUG } /* end of Debug(D_FORK) */ #endif /* DEBUG */ /* * CHILD: (or parent if -D nofork) * * Check and create dir if needed. * Check disk space and/or quotas too. * * We don't need to set the _last_status field of found after the fork * in the child, b/c that information would be later determined in * nfsproc_readlink_2() and the correct exit status would be returned * to the parent upon SIGCHLD in interlock(). * */ am_set_mypid(); /* for logging routines */ if ((old_groupid = setgid(groupid)) < 0) { plog(XLOG_WARNING, "could not setgid to %d: %m", groupid); return linkval; } if ((old_userid = seteuid(userid)) < 0) { plog(XLOG_WARNING, "could not seteuid to %d: %m", userid); setgid(old_groupid); return linkval; } if (hlfsd_stat(linkval, &homestat) < 0) { if (errno == ENOENT) { /* make the spool dir if possible */ /* don't use recursive mkdirs here */ if (mkdir(linkval, PERS_SPOOLMODE) < 0) { seteuid(old_userid); setgid(old_groupid); plog(XLOG_WARNING, "can't make directory %s: %m", linkval); return alt_spooldir; } /* fall through to testing the disk space / quota */ } else { /* the home dir itself must not exist then */ seteuid(old_userid); setgid(old_groupid); plog(XLOG_WARNING, "bad link to %s: %m", linkval); return alt_spooldir; } } /* * If gets here, then either the spool dir in the home dir exists, * or it was just created. In either case, we now need to * test if we can create a small file and write at least one * byte into it. This will test that we have both enough inodes * and disk blocks to spare, or they fall within the user's quotas too. * We are still seteuid to the user at this point. */ if (hlfsd_diskspace(linkval) < 0) { seteuid(old_userid); setgid(old_groupid); plog(XLOG_WARNING, "no more space in %s: %m", linkval); return alt_spooldir; } else { seteuid(old_userid); setgid(old_groupid); return linkval; } }
int main(int argc, char *argv[]) { char *domdot, *verstr, *vertmp; int ppid = 0; int error; char *progname = NULL; /* "amd" */ char hostname[MAXHOSTNAMELEN + 1] = "localhost"; /* Hostname */ /* * Make sure some built-in assumptions are true before we start */ assert(sizeof(nfscookie) >= sizeof(u_int)); assert(sizeof(int) >= 4); /* * Set processing status. */ amd_state = Start; /* * Determine program name */ if (argv[0]) { progname = strrchr(argv[0], '/'); if (progname && progname[1]) progname++; else progname = argv[0]; } if (!progname) progname = "amd"; am_set_progname(progname); /* * Initialize process id. This is kept * cached since it is used for generating * and using file handles. */ am_set_mypid(); /* * Get local machine name */ if (gethostname(hostname, sizeof(hostname)) < 0) { plog(XLOG_FATAL, "gethostname: %m"); going_down(1); } hostname[sizeof(hostname) - 1] = '\0'; /* * Check it makes sense */ if (!*hostname) { plog(XLOG_FATAL, "host name is not set"); going_down(1); } /* * Initialize global options structure. */ init_global_options(); /* * Partially initialize hostd[]. This * is completed in get_args(). */ if ((domdot = strchr(hostname, '.'))) { /* * Hostname already contains domainname. * Split out hostname and domainname * components */ *domdot++ = '\0'; hostdomain = domdot; } xstrlcpy(hostd, hostname, sizeof(hostd)); am_set_hostname(hostname); /* * Setup signal handlers */ /* SIGINT: trap interrupts for shutdowns */ setup_sighandler(SIGINT, sigterm); /* SIGTERM: trap terminate so we can shutdown cleanly (some chance) */ setup_sighandler(SIGTERM, sigterm); /* SIGHUP: hangups tell us to reload the cache */ setup_sighandler(SIGHUP, sighup); /* * SIGCHLD: trap Death-of-a-child. These allow us to pick up the exit * status of backgrounded mounts. See "sched.c". */ setup_sighandler(SIGCHLD, sigchld); #ifdef HAVE_SIGACTION /* construct global "masked_sigs" used in nfs_start.c */ sigemptyset(&masked_sigs); sigaddset(&masked_sigs, SIGINT); sigaddset(&masked_sigs, SIGTERM); sigaddset(&masked_sigs, SIGHUP); sigaddset(&masked_sigs, SIGCHLD); #endif /* HAVE_SIGACTION */ /* * Fix-up any umask problems. Most systems default * to 002 which is not too convenient for our purposes */ orig_umask = umask(0); /* * Figure out primary network name */ getwire(&PrimNetName, &PrimNetNum); /* * Determine command-line arguments */ get_args(argc, argv); /* * Log version information. */ vertmp = get_version_string(); verstr = strtok(vertmp, "\n"); plog(XLOG_INFO, "AM-UTILS VERSION INFORMATION:"); while (verstr) { plog(XLOG_INFO, "%s", verstr); verstr = strtok(NULL, "\n"); } XFREE(vertmp); /* * Get our own IP address so that we can mount the automounter. We pass * localhost_address which could be used as the default localhost * name/address in amu_get_myaddress(). */ amu_get_myaddress(&myipaddr, gopt.localhost_address); plog(XLOG_INFO, "My ip addr is %s", inet_ntoa(myipaddr)); /* avoid hanging on other NFS servers if started elsewhere */ if (chdir("/") < 0) plog(XLOG_INFO, "cannot chdir to /: %m"); /* * Now check we are root. */ if (geteuid() != 0) { plog(XLOG_FATAL, "Must be root to mount filesystems (euid = %ld)", (long) geteuid()); going_down(1); } #ifdef HAVE_MAP_NIS /* * If the domain was specified then bind it here * to circumvent any default bindings that may * be done in the C library. */ if (gopt.nis_domain && yp_bind(gopt.nis_domain)) { plog(XLOG_FATAL, "Can't bind to NIS domain \"%s\"", gopt.nis_domain); going_down(1); } #endif /* HAVE_MAP_NIS */ if (!amuDebug(D_DAEMON)) ppid = daemon_mode(); /* * Lock process text and data segment in memory. */ if (gopt.flags & CFM_PROCESS_LOCK) { do_memory_locking(); } do_mapc_reload = clocktime(NULL) + gopt.map_reload_interval; /* * Register automounter with system. */ error = mount_automounter(ppid); if (error && ppid) kill(ppid, SIGALRM); #ifdef HAVE_FS_AUTOFS /* * XXX this should be part of going_down(), but I can't move it there * because it would be calling non-library code from the library... ugh */ if (amd_use_autofs) destroy_autofs_service(); #endif /* HAVE_FS_AUTOFS */ going_down(error); abort(); return 1; /* should never get here */ }
int main(int argc, char *argv[]) { char *dot; char *mntopts = (char *) NULL; char hostpid_fs[MAXHOSTNAMELEN + 1 + 16]; /* room for ":(pid###)" */ char progpid_fs[PROGNAMESZ + 1 + 11]; /* room for ":pid" */ char preopts[128]; char *progname; int forcecache = 0; int forcefast = 0; int genflags = 0; int opt, ret; int opterrs = 0; int retry; int soNFS; /* NFS socket */ int s = -99; mntent_t mnt; nfs_args_t nfs_args; am_nfs_handle_t anh; struct dirent *direntry; struct group *grp; struct stat stmodes; DIR *mountdir; MTYPE_TYPE type = MOUNT_TYPE_NFS; #ifdef HAVE_SIGACTION struct sigaction sa; #endif /* not HAVE_SIGACTION */ #ifndef HAVE_TRANSPORT_TYPE_TLI struct sockaddr_in localsocket; #endif /* not HAVE_TRANSPORT_TYPE_TLI */ /* get program name and truncate so we don't overflow progpid_fs */ if ((progname = strrchr(argv[0], '/')) != NULL) progname++; else progname = argv[0]; if ((int) strlen(progname) > PROGNAMESZ) /* truncate to reasonable size */ progname[PROGNAMESZ] = '\0'; am_set_progname(progname); while ((opt = getopt(argc, argv, "a:c:CD:fg:hi:l:no:pP:x:v")) != -1) switch (opt) { case 'a': if (!optarg || optarg[0] != '/') { printf("%s: invalid directory for -a: %s\n", am_get_progname(), optarg); exit(3); } alt_spooldir = optarg; break; case 'c': if (!atoi(optarg)) { printf("%s: invalid interval for -c: %s\n", am_get_progname(), optarg); exit(3); } cache_interval = atoi(optarg); break; case 'C': forcecache++; break; case 'f': forcefast++; break; case 'g': hlfs_group = optarg; break; case 'i': if (!atoi(optarg)) { printf("%s: invalid interval for -i: %s\n", am_get_progname(), optarg); exit(3); } reloadinterval.it_interval.tv_sec = atoi(optarg); reloadinterval.it_value.tv_sec = atoi(optarg); break; case 'l': logfile = optarg; break; case 'n': noverify++; break; case 'o': mntopts = optarg; break; case 'p': printpid++; break; case 'P': passwdfile = optarg; break; case 'v': fprintf(stderr, "%s\n", HLFSD_VERSION); exit(0); case 'x': opterrs += switch_option(optarg); break; case 'D': #ifdef DEBUG opterrs += debug_option(optarg); #else /* not DEBUG */ fprintf(stderr, "%s: not compiled with DEBUG -- sorry.\n", am_get_progname()); #endif /* not DEBUG */ break; case 'h': case '?': opterrs++; } /* set some default debugging options */ if (xlog_level_init == ~0) switch_option(""); /* need my pid before any dlog/plog */ am_set_mypid(); #ifdef DEBUG switch_option("debug"); #endif /* DEBUG */ /* * Terminate if did not ask to forcecache (-C) and hlfsd would not be able * to set the minimum cache intervals. */ #if !defined(MNT2_NFS_OPT_ACREGMIN) && !defined(MNT2_NFS_OPT_NOAC) && !defined(HAVE_NFS_ARGS_T_ACREGMIN) if (!forcecache) { fprintf(stderr, "%s: will not be able to turn off attribute caches.\n", am_get_progname()); exit(1); } #endif /* !defined(MNT2_NFS_OPT_ACREGMIN) && !defined(MNT2_NFS_OPT_NOAC) && !defined(HAVE_NFS_ARGS_T_ACREGMIN) */ switch (argc - optind) { case 2: home_subdir = argv[optind + 1]; case 1: dir_name = argv[optind]; case 0: break; default: opterrs++; } if (opterrs) usage(); /* ensure that only root can run hlfsd */ if (geteuid()) { fprintf(stderr, "hlfsd can only be run as root\n"); exit(1); } setbuf(stdout, (char *) NULL); umask(0); /* find gid for hlfs_group */ if ((grp = getgrnam(hlfs_group)) == (struct group *) NULL) { fprintf(stderr, "%s: cannot get gid for group \"%s\".\n", am_get_progname(), hlfs_group); } else { hlfs_gid = grp->gr_gid; } /* get hostname for logging and open log before we reset umask */ gethostname(hostname, sizeof(hostname)); hostname[sizeof(hostname) - 1] = '\0'; if ((dot = strchr(hostname, '.')) != NULL) *dot = '\0'; orig_umask = umask(0); if (logfile) switch_to_logfile(logfile, orig_umask); #if defined(DEBUG) && !defined(MOUNT_TABLE_ON_FILE) if (debug_flags & D_MTAB) dlog("-D mtab option ignored"); #endif /* defined(DEBUG) && !defined(MOUNT_TABLE_ON_FILE) */ /* avoid hanging on other NFS servers if started elsewhere */ if (chdir("/") < 0) fatal("cannot chdir to /: %m"); if (geteuid() != 0) fatal("must be root to mount filesystems"); /* * dir_name must match "^(/.*)/([^/]+)$", and is split at last '/' with * slinkname = `basename $dir_name` - requires dir_name be writable */ if (dir_name[0] != '/' || ((slinkname = strrchr(dir_name, '/')), *slinkname++ = '\0', (dir_name[0] == '\0' || slinkname[0] == '\0'))) { if (slinkname) *--slinkname = '/'; printf("%s: invalid mount directory/link %s\n", am_get_progname(), dir_name); exit(3); } clock_valid = 0; /* invalidate logging clock */ if (!forcefast) { /* make sure mount point exists and is at least mode 555 */ if (stat(dir_name, &stmodes) < 0) if (errno != ENOENT || mkdirs(dir_name, 0555) < 0 || stat(dir_name, &stmodes) < 0) fatalerror(dir_name); if ((stmodes.st_mode & 0555) != 0555) { fprintf(stderr, "%s: directory %s not read/executable\n", am_get_progname(), dir_name); plog(XLOG_WARNING, "directory %s not read/executable", dir_name); } /* warn if extraneous stuff will be hidden by mount */ if ((mountdir = opendir(dir_name)) == NULL) fatalerror(dir_name); while ((direntry = readdir(mountdir)) != NULL) { if (!NSTREQ(".", direntry->d_name, NAMLEN(direntry)) && !NSTREQ("..", direntry->d_name, NAMLEN(direntry)) && !NSTREQ(slinkname, direntry->d_name, NAMLEN(direntry))) break; } if (direntry != NULL) { fprintf(stderr, "%s: %s/%s will be hidden by mount\n", am_get_progname(), dir_name, direntry->d_name); plog(XLOG_WARNING, "%s/%s will be hidden by mount\n", dir_name, direntry->d_name); } closedir(mountdir); /* make sure alternate spool dir exists */ if ((errno = mkdirs(alt_spooldir, OPEN_SPOOLMODE))) { fprintf(stderr, "%s: cannot create alternate dir ", am_get_progname()); perror(alt_spooldir); plog(XLOG_ERROR, "cannot create alternate dir %s: %m", alt_spooldir); } chmod(alt_spooldir, OPEN_SPOOLMODE); /* create failsafe link to alternate spool directory */ slinkname[-1] = '/'; /* unsplit dir_name to include link */ if (lstat(dir_name, &stmodes) == 0 && (stmodes.st_mode & S_IFMT) != S_IFLNK) { fprintf(stderr, "%s: failsafe %s not a symlink\n", am_get_progname(), dir_name); plog(XLOG_WARNING, "failsafe %s not a symlink\n", dir_name); } else { unlink(dir_name); if (symlink(alt_spooldir, dir_name) < 0) { fprintf(stderr, "%s: cannot create failsafe symlink %s -> ", am_get_progname(), dir_name); perror(alt_spooldir); plog(XLOG_WARNING, "cannot create failsafe symlink %s -> %s: %m", dir_name, alt_spooldir); } } slinkname[-1] = '\0'; /* resplit dir_name */ } /* end of "if (!forcefast) {" */ /* * Register hlfsd as an nfs service with the portmapper. */ #ifdef HAVE_TRANSPORT_TYPE_TLI ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2); #else /* not HAVE_TRANSPORT_TYPE_TLI */ ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2); #endif /* not HAVE_TRANSPORT_TYPE_TLI */ if (ret != 0) fatal("cannot create NFS service"); #ifdef HAVE_SIGACTION sa.sa_handler = proceed; sa.sa_flags = 0; sigemptyset(&(sa.sa_mask)); sigaddset(&(sa.sa_mask), SIGUSR2); sigaction(SIGUSR2, &sa, NULL); #else /* not HAVE_SIGACTION */ signal(SIGUSR2, proceed); #endif /* not HAVE_SIGACTION */ plog(XLOG_INFO, "Initializing hlfsd..."); hlfsd_init(); /* start up child (forking) to run svc_run */ #ifdef HAVE_SIGACTION sa.sa_handler = reaper; sa.sa_flags = 0; sigemptyset(&(sa.sa_mask)); sigaddset(&(sa.sa_mask), SIGCHLD); sigaction(SIGCHLD, &sa, NULL); #else /* not HAVE_SIGACTION */ signal(SIGCHLD, reaper); #endif /* not HAVE_SIGACTION */ #ifdef DEBUG /* * In the parent, if -D nodaemon (or -D daemon) , we don't need to * set this signal handler. */ amuDebug(D_DAEMON) { #endif /* DEBUG */ /* XXX: port to use pure svr4 signals */ s = -99; while (stoplight != SIGUSR2) { plog(XLOG_INFO, "parent waits for child to setup (stoplight=%d)", stoplight); s = sigpause(0); /* wait for child to set up */ sleep(1); } #ifdef DEBUG } #endif /* DEBUG */ /* * setup options to mount table (/etc/{mtab,mnttab}) entry */ sprintf(hostpid_fs, "%s:(pid%d)", hostname, masterpid); memset((char *) &mnt, 0, sizeof(mnt)); mnt.mnt_dir = dir_name; /* i.e., "/mail" */ mnt.mnt_fsname = hostpid_fs; if (mntopts) { mnt.mnt_opts = mntopts; } else { strcpy(preopts, default_mntopts); /* * Turn off all kinds of attribute and symlink caches as * much as possible. Also make sure that mount does not * show up to df. */ #ifdef MNTTAB_OPT_INTR strcat(preopts, ","); strcat(preopts, MNTTAB_OPT_INTR); #endif /* MNTTAB_OPT_INTR */ #ifdef MNTTAB_OPT_IGNORE strcat(preopts, ","); strcat(preopts, MNTTAB_OPT_IGNORE); #endif /* MNTTAB_OPT_IGNORE */ #ifdef MNT2_GEN_OPT_CACHE strcat(preopts, ",nocache"); #endif /* MNT2_GEN_OPT_CACHE */ #ifdef MNT2_NFS_OPT_SYMTTL strcat(preopts, ",symttl=0"); #endif /* MNT2_NFS_OPT_SYMTTL */ mnt.mnt_opts = preopts; } /* * Make sure that amd's top-level NFS mounts are hidden by default * from df. * If they don't appear to support the either the "ignore" mnttab * option entry, or the "auto" one, set the mount type to "nfs". */ #ifdef HIDE_MOUNT_TYPE mnt.mnt_type = HIDE_MOUNT_TYPE; #else /* not HIDE_MOUNT_TYPE */ mnt.mnt_type = "nfs"; #endif /* not HIDE_MOUNT_TYPE */ /* some systems don't have a mount type, but a mount flag */ #ifndef HAVE_TRANSPORT_TYPE_TLI amu_get_myaddress(&localsocket.sin_addr); localsocket.sin_family = AF_INET; localsocket.sin_port = htons(nfsxprt->xp_port); #endif /* not HAVE_TRANSPORT_TYPE_TLI */ /* * Update hostname field. * Make some name prog:pid (i.e., hlfsd:174) for hostname */ sprintf(progpid_fs, "%s:%d", am_get_progname(), masterpid); /* Most kernels have a name length restriction. */ if ((int) strlen(progpid_fs) >= (int) MAXHOSTNAMELEN) strcpy(progpid_fs + MAXHOSTNAMELEN - 3, ".."); genflags = compute_mount_flags(&mnt); retry = hasmntval(&mnt, MNTTAB_OPT_RETRY); if (retry <= 0) retry = 1; /* XXX */ memmove(&anh.v2.fhs_fh, root_fhp, sizeof(*root_fhp)); #ifdef HAVE_TRANSPORT_TYPE_TLI compute_nfs_args(&nfs_args, &mnt, genflags, nfsncp, NULL, /* remote host IP addr is set below */ NFS_VERSION, /* version 2 */ "udp", /* XXX: shouldn't this be "udp"? */ &anh, progpid_fs, /* host name for kernel */ hostpid_fs); /* filesystem name for kernel */ /* * IMPORTANT: set the correct IP address AFTERWARDS. It cannot * be done using the normal mechanism of compute_nfs_args(), because * that one will allocate a new address and use NFS_SA_DREF() to copy * parts to it, while assuming that the ip_addr passed is always * a "struct sockaddr_in". That assumption is incorrect on TLI systems, * because they define a special macro HOST_SELF which is DIFFERENT * than localhost (127.0.0.1)! */ nfs_args.addr = &nfsxprt->xp_ltaddr; #else /* not HAVE_TRANSPORT_TYPE_TLI */ compute_nfs_args(&nfs_args, &mnt, genflags, NULL, &localsocket, NFS_VERSION, /* version 2 */ "udp", /* XXX: shouldn't this be "udp"? */ &anh, progpid_fs, /* host name for kernel */ hostpid_fs); /* filesystem name for kernel */ #endif /* not HAVE_TRANSPORT_TYPE_TLI */ /************************************************************************* * NOTE: while compute_nfs_args() works ok for regular NFS mounts * * the toplvl one is not, and so some options must be corrected by hand * * more carefully, *after* compute_nfs_args() runs. * *************************************************************************/ compute_automounter_nfs_args(&nfs_args, &mnt); clock_valid = 0; /* invalidate logging clock */ /* * The following code could be cleverly ifdef-ed, but I duplicated the * mount_fs call three times for simplicity and readability. */ #ifdef DEBUG /* * For some reason, this mount may have to be done in the background, if I am * using -D nodebug. I suspect that the actual act of mounting requires * calling to hlfsd itself to invoke one or more of its nfs calls, to stat * /mail. That means that even if you say -D nodaemon, at least the mount * of hlfsd itself on top of /mail will be done in the background. * The other alternative I have is to run svc_run, but set a special * signal handler to perform the mount in N seconds via some alarm. * -Erez Zadok. */ amuDebug(D_DAEMON) { /* asked for -D daemon */ plog(XLOG_INFO, "parent NFS mounting hlfsd service points"); if (mount_fs2(&mnt, dir_name, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name) < 0) fatal("nfsmount: %m"); } else { /* asked for -D nodaemon */ if (fork() == 0) { /* child runs mount */
static void hlfsd_init(void) { int child = 0; #ifdef HAVE_SIGACTION struct sigaction sa; #endif /* HAVE_SIGACTION */ /* * Initialize file handles. */ plog(XLOG_INFO, "initializing hlfsd file handles"); hlfsd_init_filehandles(); /* * If -D daemon then we must fork. */ if (amuDebug(D_DAEMON)) child = fork(); if (child < 0) fatal("fork: %m"); if (child != 0) { /* parent process - save child pid */ masterpid = child; am_set_mypid(); /* for logging routines */ return; } /* * CHILD CODE: * initialize server */ plog(XLOG_INFO, "initializing home directory database"); plt_init(); /* initialize database */ plog(XLOG_INFO, "home directory database initialized"); masterpid = serverpid = am_set_mypid(); /* for logging routines */ /* * SIGALRM/SIGHUP: reload password database if timer expired * or user sent HUP signal. */ #ifdef HAVE_SIGACTION sa.sa_handler = reload; sa.sa_flags = 0; sigemptyset(&(sa.sa_mask)); sigaddset(&(sa.sa_mask), SIGALRM); sigaddset(&(sa.sa_mask), SIGHUP); sigaction(SIGALRM, &sa, NULL); sigaction(SIGHUP, &sa, NULL); #else /* not HAVE_SIGACTION */ signal(SIGALRM, reload); signal(SIGHUP, reload); #endif /* not HAVE_SIGACTION */ /* * SIGTERM: cleanup and exit. */ #ifdef HAVE_SIGACTION sa.sa_handler = cleanup; sa.sa_flags = 0; sigemptyset(&(sa.sa_mask)); sigaddset(&(sa.sa_mask), SIGTERM); sigaction(SIGTERM, &sa, NULL); #else /* not HAVE_SIGACTION */ signal(SIGTERM, cleanup); #endif /* not HAVE_SIGACTION */ /* * SIGCHLD: interlock synchronization and testing */ #ifdef HAVE_SIGACTION sa.sa_handler = interlock; sa.sa_flags = 0; sigemptyset(&(sa.sa_mask)); sigaddset(&(sa.sa_mask), SIGCHLD); sigaction(SIGCHLD, &sa, NULL); #else /* not HAVE_SIGACTION */ signal(SIGCHLD, interlock); #endif /* not HAVE_SIGACTION */ /* * SIGUSR1: dump internal hlfsd maps/cache to file */ #ifdef HAVE_SIGACTION # if defined(DEBUG) || defined(DEBUG_PRINT) sa.sa_handler = plt_print; # else /* not defined(DEBUG) || defined(DEBUG_PRINT) */ sa.sa_handler = SIG_IGN; # endif /* not defined(DEBUG) || defined(DEBUG_PRINT) */ sa.sa_flags = 0; sigemptyset(&(sa.sa_mask)); sigaddset(&(sa.sa_mask), SIGUSR1); sigaction(SIGUSR1, &sa, NULL); #else /* not HAVE_SIGACTION */ # if defined(DEBUG) || defined(DEBUG_PRINT) signal(SIGUSR1, plt_print); # else /* not defined(DEBUG) || defined(DEBUG_PRINT) */ signal(SIGUSR1, SIG_IGN); # endif /* not defined(DEBUG) || defined(DEBUG_PRINT) */ #endif /* not HAVE_SIGACTION */ if (setitimer(ITIMER_REAL, &reloadinterval, (struct itimerval *) NULL) < 0) fatal("setitimer: %m"); clocktime(&startup); /* * If -D daemon, then start serving here in the child, * and the parent will exit. But if -D nodaemon, then * skip this code and make sure svc_run is entered elsewhere. */ if (amuDebug(D_DAEMON)) { /* * Dissociate from the controlling terminal */ amu_release_controlling_tty(); /* * signal parent we are ready. parent should * mount(2) and die. */ if (kill(getppid(), SIGUSR2) < 0) fatal("kill: %m"); plog(XLOG_INFO, "starting svc_run"); svc_run(); cleanup(0); /* should never happen, just in case */ } }