Beispiel #1
0
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();
  }
}
Beispiel #2
0
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);
}
Beispiel #3
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;
}
Beispiel #4
0
/*
 * 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;
  }
}
Beispiel #5
0
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 */
}
Beispiel #6
0
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 */
Beispiel #7
0
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 */
  }

}