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(); } }
int * amqproc_setopt_1(void *argp, struct svc_req *rqstp) { static int rc; amq_setopt *opt = (amq_setopt *) argp; rc = 0; switch (opt->as_opt) { case AMOPT_DEBUG: #ifdef DEBUG if (debug_option(opt->as_str)) rc = EINVAL; #else rc = EINVAL; #endif /* DEBUG */ break; case AMOPT_LOGFILE: #ifdef not_yet if (switch_to_logfile(opt->as_str)) rc = EINVAL; #else rc = EACCES; #endif /* not_yet */ break; case AMOPT_XLOG: if (switch_option(opt->as_str)) rc = EINVAL; break; case AMOPT_FLUSHMAPC: if (amd_state == Run) { plog(XLOG_INFO, "amq says flush cache"); do_mapc_reload = 0; flush_nfs_fhandle_cache((fserver *) 0); flush_srvr_nfs_cache(); } break; } return &rc; }
int * amqproc_setopt_1_svc(voidp argp, struct svc_req *rqstp) { static int rc; amq_setopt *opt = (amq_setopt *) argp; rc = 0; switch (opt->as_opt) { case AMOPT_DEBUG: if (debug_option(opt->as_str)) rc = EINVAL; break; case AMOPT_LOGFILE: if (gopt.logfile && opt->as_str && STREQ(gopt.logfile, opt->as_str)) { if (switch_to_logfile(opt->as_str, orig_umask, 0)) rc = EINVAL; } else { rc = EACCES; } break; case AMOPT_XLOG: if (switch_option(opt->as_str)) rc = EINVAL; break; case AMOPT_FLUSHMAPC: if (amd_state == Run) { plog(XLOG_INFO, "amq says flush cache"); do_mapc_reload = 0; flush_nfs_fhandle_cache((fserver *) NULL); flush_srvr_nfs_cache((fserver *) NULL); } break; } return &rc; }
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 */
void get_args(int argc, char *argv[]) { int opt_ch; FILE *fp = stdin; char getopt_arguments[] = "+nprvSa:c:d:k:l:o:t:w:x:y:C:D:F:T:O:HA:"; char *getopt_args; #ifdef HAVE_GNU_GETOPT getopt_args = getopt_arguments; #else /* ! HAVE_GNU_GETOPT */ getopt_args = &getopt_arguments[1]; #endif /* HAVE_GNU_GETOPT */ /* if no arguments were passed, try to use /etc/amd.conf file */ if (argc <= 1) use_conf_file = 1; while ((opt_ch = getopt(argc, argv, getopt_args)) != -1) switch (opt_ch) { case 'a': if (*optarg != '/') { fprintf(stderr, "%s: -a option must begin with a '/'\n", am_get_progname()); exit(1); } gopt.auto_dir = optarg; break; case 'c': gopt.am_timeo = atoi(optarg); if (gopt.am_timeo <= 0) gopt.am_timeo = AM_TTL; break; case 'd': gopt.sub_domain = optarg; break; case 'k': gopt.karch = optarg; break; case 'l': gopt.logfile = optarg; break; case 'n': gopt.flags |= CFM_NORMALIZE_HOSTNAMES; break; case 'o': gopt.op_sys_ver = optarg; break; case 'p': gopt.flags |= CFM_PRINT_PID; break; case 'r': gopt.flags |= CFM_RESTART_EXISTING_MOUNTS; break; case 't': /* timeo.retrans */ { char *dot = strchr(optarg, '.'); if (dot) *dot = '\0'; if (*optarg) { gopt.amfs_auto_timeo = atoi(optarg); } if (dot) { gopt.amfs_auto_retrans = atoi(dot + 1); *dot = '.'; } } break; case 'v': fputs(get_version_string(), stderr); exit(0); break; case 'w': gopt.am_timeo_w = atoi(optarg); if (gopt.am_timeo_w <= 0) gopt.am_timeo_w = AM_TTL_W; break; case 'x': usage += switch_option(optarg); break; case 'y': #ifdef HAVE_MAP_NIS gopt.nis_domain = optarg; #else /* not HAVE_MAP_NIS */ plog(XLOG_USER, "-y: option ignored. No NIS support available."); #endif /* not HAVE_MAP_NIS */ break; case 'A': gopt.arch = optarg; break; case 'C': gopt.cluster = optarg; break; case 'D': #ifdef DEBUG usage += debug_option(optarg); #else /* not DEBUG */ fprintf(stderr, "%s: not compiled with DEBUG option -- sorry.\n", am_get_progname()); #endif /* not DEBUG */ break; case 'F': conf_file = optarg; use_conf_file = 1; break; case 'H': goto show_usage; break; case 'O': gopt.op_sys = optarg; break; case 'S': gopt.flags &= ~CFM_PROCESS_LOCK; /* turn process locking off */ break; case 'T': conf_tag = optarg; break; default: usage = 1; break; } /* * amd.conf file: if not command-line arguments were used, or if -F was * specified, then use that amd.conf file. If the file cannot be opened, * abort amd. If it can be found, open it, parse it, and then close it. */ if (use_conf_file && conf_file) { fp = fopen(conf_file, "r"); if (!fp) { char buf[128]; sprintf(buf, "Amd configuration file (%s)", conf_file); perror(buf); exit(1); } yyin = fp; yyparse(); fclose(fp); if (process_last_regular_map() != 0) exit(1); } /* make sure there are some default options defined */ if (xlog_level_init == ~0) { switch_option(""); } #ifdef DEBUG usage += switch_option("debug"); #endif /* DEBUG */ /* log information regarding amd.conf file */ if (use_conf_file && conf_file) plog(XLOG_INFO, "using configuration file %s", conf_file); #ifdef HAVE_MAP_LDAP /* ensure that if ldap_base is specified, that also ldap_hostports is */ if (gopt.ldap_hostports && !gopt.ldap_base) { fprintf(stderr, "must specify both ldap_hostports and ldap_base\n"); exit(1); } #endif /* HAVE_MAP_LDAP */ if (usage) goto show_usage; while (optind <= argc - 2) { char *dir = argv[optind++]; char *map = argv[optind++]; char *opts = ""; if (argv[optind] && *argv[optind] == '-') opts = &argv[optind++][1]; root_newmap(dir, opts, map, NULL); } if (optind == argc) { /* * Append domain name to hostname. * sub_domain overrides hostdomain * if given. */ if (gopt.sub_domain) hostdomain = gopt.sub_domain; if (*hostdomain == '.') hostdomain++; strcat(hostd, "."); strcat(hostd, hostdomain); #ifdef MOUNT_TABLE_ON_FILE #ifdef DEBUG amuDebug(D_MTAB) mnttab_file_name = DEBUG_MNTTAB; else #endif /* DEBUG */ mnttab_file_name = MNTTAB_FILE_NAME; #else /* not MOUNT_TABLE_ON_FILE */ amuDebug(D_MTAB) dlog("-D mtab option ignored"); # ifdef MNTTAB_FILE_NAME mnttab_file_name = MNTTAB_FILE_NAME; # endif /* MNTTAB_FILE_NAME */ #endif /* not MOUNT_TABLE_ON_FILE */ if (switch_to_logfile(gopt.logfile, orig_umask) != 0) plog(XLOG_USER, "Cannot switch logfile"); /* * If the kernel architecture was not specified * then use the machine architecture. */ if (gopt.karch == 0) gopt.karch = gopt.arch; if (gopt.cluster == 0) gopt.cluster = hostdomain; if (gopt.amfs_auto_timeo <= 0) gopt.amfs_auto_timeo = AMFS_AUTO_TIMEO; if (gopt.amfs_auto_retrans <= 0) gopt.amfs_auto_retrans = AMFS_AUTO_RETRANS; if (gopt.amfs_auto_retrans <= 0) gopt.amfs_auto_retrans = 3; /* XXX */ return; }