Пример #1
0
/*
 * return string option which is the reverse of opt.
 * nosuid -> suid
 * quota -> noquota
 * ro -> rw
 * etc.
 * may return pointer to static buffer or subpointer within opt.
 */
static char *
reverse_option(const char *opt)
{
  static char buf[80];

  /* sanity check */
  if (!opt)
    return NULL;

  /* check special cases */
  /* XXX: if this gets too long, rewrite the code more flexibly */
  if (STREQ(opt, "ro")) return "rw";
  if (STREQ(opt, "rw")) return "ro";
  if (STREQ(opt, "bg")) return "fg";
  if (STREQ(opt, "fg")) return "bg";
  if (STREQ(opt, "soft")) return "hard";
  if (STREQ(opt, "hard")) return "soft";

  /* check if string starts with 'no' and chop it */
  if (NSTREQ(opt, "no", 2)) {
    xstrlcpy(buf, &opt[2], sizeof(buf));
  } else {
    /* finally return a string prepended with 'no' */
    xstrlcpy(buf, "no", sizeof(buf));
    xstrlcat(buf, opt, sizeof(buf));
  }
  return buf;
}
Пример #2
0
/*
 * Change current logfile
 */
int
switch_to_logfile(char *logfile, int old_umask)
{
  FILE *new_logfp = stderr;

  if (logfile) {
#ifdef HAVE_SYSLOG
    syslogging = 0;
#endif /* HAVE_SYSLOG */

    if (STREQ(logfile, "/dev/stderr"))
      new_logfp = stderr;
    else if (NSTREQ(logfile, "syslog", strlen("syslog"))) {

#ifdef HAVE_SYSLOG
      syslogging = 1;
      new_logfp = stderr;
      openlog(am_get_progname(),
	      LOG_PID
# ifdef LOG_CONS
	      | LOG_CONS
# endif /* LOG_CONS */
# ifdef LOG_NOWAIT
	      | LOG_NOWAIT
# endif /* LOG_NOWAIT */
# ifdef LOG_DAEMON
	      , get_syslog_facility(logfile)
# endif /* LOG_DAEMON */
	      );
#else /* not HAVE_SYSLOG */
      plog(XLOG_WARNING, "syslog option not supported, logging unchanged");
#endif /* not HAVE_SYSLOG */

    } else {
      (void) umask(old_umask);
      new_logfp = fopen(logfile, "a");
      umask(0);
    }
  }

  /*
   * If we couldn't open a new file, then continue using the old.
   */
  if (!new_logfp && logfile) {
    plog(XLOG_USER, "%s: Can't open logfile: %m", logfile);
    return 1;
  }

  /*
   * Close the previous file
   */
  if (logfp && logfp != stderr)
    (void) fclose(logfp);
  logfp = new_logfp;

  plog(XLOG_INFO, "switched to logfile \"%s\"", logfile);
  return 0;
}
Пример #3
0
/*
 * Return true if pref is a directory prefix of dir.
 *
 * XXX TODO:
 * Does not work if pref is "/".
 */
static int
directory_prefix(char *pref, char *dir)
{
  int len = strlen(pref);

  if (!NSTREQ(pref, dir, len))
    return FALSE;
  if (dir[len] == '/' || dir[len] == '\0')
    return TRUE;
  return FALSE;
}
Пример #4
0
/*
 * replacement for hasmntopt if the system does not have it.
 */
char *
amu_hasmntopt(mntent_t *mnt, char *opt)
{
  char t[MNTMAXSTR];
  char *f;
  char *o = t;
  size_t l = strlen(opt);

  xstrlcpy(t, mnt->mnt_opts, sizeof(t));

  while (*(f = nextmntopt(&o)))
    if (NSTREQ(opt, f, l))
      return f - t + mnt->mnt_opts;

  return 0;
}
Пример #5
0
/*
 * Process PAWD string of remote pawd tool.
 *
 * We repeat the resolution of the string until the resolved string resolves
 * to itself.  This ensures that we follow path resolutions through all
 * possible Amd mount points until we reach some sort of convergence.  To
 * prevent possible infinite loops, we break out of this loop if the strings
 * do not converge after MAX_PAWD_TRIES times.
 */
amq_string *
amqproc_pawd_1_svc(voidp argp, struct svc_req *rqstp)
{
  static amq_string res;
#define MAX_PAWD_TRIES 10
  int index, len, maxagain = MAX_PAWD_TRIES;
  am_node *mp;
  char *mountpoint;
  char *dir = *(char **) argp;
  static char tmp_buf[MAXPATHLEN];
  char prev_buf[MAXPATHLEN];

  tmp_buf[0] = prev_buf[0] = '\0'; /* default is empty string: no match */
  do {
    for (mp = get_first_exported_ap(&index);
	 mp;
	 mp = get_next_exported_ap(&index)) {
      if (STREQ(mp->am_al->al_mnt->mf_ops->fs_type, "toplvl"))
	continue;
      if (STREQ(mp->am_al->al_mnt->mf_ops->fs_type, "auto"))
	continue;
      mountpoint = (mp->am_link ? mp->am_link : mp->am_al->al_mnt->mf_mount);
      len = strlen(mountpoint);
      if (len == 0)
	continue;
      if (!NSTREQ(mountpoint, dir, len))
	continue;
      if (dir[len] != '\0' && dir[len] != '/')
	continue;
      xstrlcpy(tmp_buf, mp->am_path, sizeof(tmp_buf));
      xstrlcat(tmp_buf, &dir[len], sizeof(tmp_buf));
      break;
    } /* end of "for" loop */
    /* once tmp_buf and prev_buf are equal, break out of "do" loop */
    if (STREQ(tmp_buf, prev_buf))
      break;
    else
      xstrlcpy(prev_buf, tmp_buf, sizeof(prev_buf));
  } while (--maxagain);
  /* check if we couldn't resolve the string after MAX_PAWD_TRIES times */
  if (maxagain <= 0)
    plog(XLOG_WARNING, "path \"%s\" did not resolve after %d tries",
	 tmp_buf, MAX_PAWD_TRIES);

  res = tmp_buf;
  return &res;
}
Пример #6
0
/*
 * AIX 3 format
 */
static void
write_aix3_dkfstab(FILE *ef, disk_fs *dp)
{
  if (STREQ(dp->d_fstype, "jfs") &&
      NSTREQ(dp->d_dev, "/dev/", 5) &&
      !dp->d_log)
    error("aix 3 needs a log device for journalled filesystem (jfs) mounts");

  fprintf(ef, "\n%s:\n\tdev = %s\n\tvfs = %s\n\ttype = %s\n\tlog = %s\n\tvol = %s\n\topts = %s\n\tmount = true\n\tcheck = true\n\tfree = false\n",
	  dp->d_mountpt,
	  dp->d_dev,
	  dp->d_fstype,
	  dp->d_fstype,
	  dp->d_log,
	  dp->d_mountpt,
	  dp->d_opts);
}
Пример #7
0
/*
 * Display a pwd data
 */
static void
show_pwd(amq_mount_tree *mt, char *path, size_t l, int *flag)
{
  int len;

  while (mt) {
    len = strlen(mt->mt_mountpoint);
    if (NSTREQ(path, mt->mt_mountpoint, len) &&
	!STREQ(mt->mt_directory, mt->mt_mountpoint)) {
      char buf[MAXPATHLEN+1];	/* must be same size as 'path' */
      xstrlcpy(buf, mt->mt_directory, sizeof(buf));
      xstrlcat(buf, &path[len], sizeof(buf));
      xstrlcpy(path, buf, l);
      *flag = 1;
    }
    show_pwd(mt->mt_next, path, l, flag);
    mt = mt->mt_child;
  }
}
Пример #8
0
nfsstat *
nfsproc_rename_2_svc(nfsrenameargs *argp, struct svc_req *rqstp)
{
  static nfsstat res;

  if (!fh_to_mp(&argp->rna_from.da_fhandle) || !fh_to_mp(&argp->rna_to.da_fhandle))
    res = nfs_error(ESTALE);
  /*
   * If the kernel is doing clever things with referenced files
   * then let it pretend...
   */
  else if (NSTREQ(argp->rna_to.da_name, ".nfs", 4))
    res = NFS_OK;
  /*
   * otherwise a failure
   */
  else
    res = nfs_error(EROFS);

  return &res;
}
Пример #9
0
int
umount_fs(char *mntdir, const char *mnttabname, u_int unmount_flags)
{
  mntlist *mlist, *mp, *mp_save = NULL;
  int error = 0;
#ifdef HAVE_LOOP_DEVICE
  char *opt, *xopts = NULL;
  char loopstr[] = "loop=";
  char *loopdev;
#endif /* HAVE_LOOP_DEVICE */
  unsigned int retries = 8;

  mp = mlist = read_mtab(mntdir, mnttabname);

  /*
   * Search the mount table looking for
   * the correct (ie last) matching entry
   */
  while (mp) {
    if (STREQ(mp->mnt->mnt_dir, mntdir))
      mp_save = mp;
    mp = mp->mnext;
  }

  if (!mp_save) {
    plog(XLOG_ERROR, "Couldn't find how to unmount %s", mntdir);
    /* Assume it is already unmounted */
    error = 0;
    goto out;
  }

  plog(XLOG_ERROR, "Trying unmount %s, umount_flags 0x%x", mp_save->mnt->mnt_dir, unmount_flags);
  dlog("Trying unmount(%s)", mp_save->mnt->mnt_dir);

#ifdef MOUNT_TABLE_ON_FILE
  /*
   * This unmount may hang leaving this process with an exclusive lock on
   * /etc/mtab. Therefore it is necessary to unlock mtab, do the unmount,
   * then lock mtab (again) and reread it and finally update it.
   */
  unlock_mntlist();
#endif /* MOUNT_TABLE_ON_FILE */

again:
#if defined(HAVE_UMOUNT2) && defined(MNT2_GEN_OPT_DETACH)
  /*
   * If user asked to try forced unmounts, then do a quick check to see if
   * the mount point is hung badly.  If so, then try to detach it by
   * force; if the latter works, we're done.
   */
  if (unmount_flags & AMU_UMOUNT_DETACH) {
    /*
     * Note: we pass both DETACH and FORCE flags, because umount2_fs below
     * (on Linux), should try FORCE before DETACH (the latter always
     * succeeds).
     */
    error = umount2_fs(mp_save->mnt->mnt_dir,
		       unmount_flags & (AMU_UMOUNT_DETACH|AMU_UMOUNT_FORCE));
  } else
#endif /* defined(HAVE_UMOUNT2) && defined(MNT2_GEN_OPT_DETACH) */
    error = UNMOUNT_TRAP(mp_save->mnt);

  /* Linux kernel can be sluggish for some reason */
  if (error == EBUSY && retries--) {
    struct timespec tm = {0, 200000000};
    nanosleep(&tm, NULL);
    goto again;
  }

  if (error < 0) {
    plog(XLOG_WARNING, "unmount(%s) failed: %m", mp_save->mnt->mnt_dir);
    switch ((error = errno)) {
    case EINVAL:
    case ENOTBLK:
      plog(XLOG_WARNING, "unmount: %s is not mounted", mp_save->mnt->mnt_dir);
      error = 0;		/* Not really an error */
      break;

    case ENOENT:
      /*
       * This could happen if the kernel insists on following symlinks
       * when we try to unmount a direct mountpoint. We need to propagate
       * the error up so that the top layers know it failed and don't
       * try to rmdir() the mountpoint or other silly things.
       */
      plog(XLOG_ERROR, "mount point %s: %m", mp_save->mnt->mnt_dir);
      break;

#if defined(HAVE_UMOUNT2) && defined(MNT2_GEN_OPT_FORCE)
    case EBUSY:
      /*
       * Caller determines if forced unmounts should be used now (for
       * EBUSY).  If caller asked to force an unmount, *and* the above
       * "trivial" unmount attempt failed with EBUSY, then try to force
       * the unmount.
       */
      if (unmount_flags & AMU_UMOUNT_FORCE) {
	error = umount2_fs(mp_save->mnt->mnt_dir,
			   unmount_flags & AMU_UMOUNT_FORCE);
	if (error < 0) {
	  plog(XLOG_WARNING, "%s: unmount/force: %m",
	       mp_save->mnt->mnt_dir);
	  error = errno;
	}
      }
      break;
#endif /* defined(HAVE_UMOUNT2) && defined(MNT2_GEN_OPT_FORCE) */

    default:
      dlog("%s: unmount: %m", mp_save->mnt->mnt_dir);
      break;
    }
  } else {
    dlog("unmount(%s) succeeded", mp_save->mnt->mnt_dir);
  }
  dlog("Finished unmount(%s)", mp_save->mnt->mnt_dir);

  /*
   * If we are successful or there was an ENOENT, remove
   * the mount entry from the mtab file.
   */
  if (error && error != ENOENT)
    goto out;

#ifdef HAVE_LOOP_DEVICE
  /* look for loop=/dev/loopX in mnt_opts */
  xopts = xstrdup(mp_save->mnt->mnt_opts); /* b/c strtok is destructive */
  for (opt = strtok(xopts, ","); opt; opt = strtok(NULL, ","))
    if (NSTREQ(opt, loopstr, sizeof(loopstr) - 1)) {
      loopdev = opt + sizeof(loopstr) - 1;
      if (delete_loop_device(loopdev) < 0)
	plog(XLOG_WARNING, "unmount() failed to release loop device %s: %m", loopdev);
      else
	plog(XLOG_INFO, "unmount() released loop device %s OK", loopdev);
      break;
    }
  if (xopts)
    XFREE(xopts);
#endif /* HAVE_LOOP_DEVICE */

#ifdef MOUNT_TABLE_ON_FILE
  free_mntlist(mlist);
  mp = mlist = read_mtab(mntdir, mnttabname);

  /*
   * Search the mount table looking for
   * the correct (ie last) matching entry
   */
  mp_save = NULL;
  while (mp) {
    if (STREQ(mp->mnt->mnt_dir, mntdir))
      mp_save = mp;
    mp = mp->mnext;
  }

  if (mp_save) {
    mnt_free(mp_save->mnt);
    mp_save->mnt = NULL;
    rewrite_mtab(mlist, mnttabname);
  }
#endif /* MOUNT_TABLE_ON_FILE */

 out:
  free_mntlist(mlist);

  return error;
}
Пример #10
0
/*
 * No way to probe - check the map name begins with "union:"
 */
int
union_init(mnt_map *m, char *map, time_t *tp)
{
  *tp = 0;
  return NSTREQ(map, UNION_PREFIX, UNION_PREFLEN) ? 0 : ENOENT;
}
Пример #11
0
/*
 * Create a chain of entries which are not linked.
 * -Erez Zadok <*****@*****.**>
 */
static nfsentry *
make_entry_chain(am_node *mp, const nfsentry *current_chain, int fully_browsable)
{
  static u_int last_cookie = (u_int) 2;	/* monotonically increasing */
  static nfsentry chain[MAX_CHAIN];
  static int max_entries = MAX_CHAIN;
  char *key;
  int num_entries = 0, i;
  u_int preflen = 0;
  nfsentry *retval = (nfsentry *) NULL;
  mntfs *mf;
  mnt_map *mmp;

  if (!mp) {
    plog(XLOG_DEBUG, "make_entry_chain: mp is (NULL)");
    return retval;
  }
  mf = mp->am_al->al_mnt;
  if (!mf) {
    plog(XLOG_DEBUG, "make_entry_chain: mp->am_al->al_mnt is (NULL)");
    return retval;
  }
  mmp = (mnt_map *) mf->mf_private;
  if (!mmp) {
    plog(XLOG_DEBUG, "make_entry_chain: mp->am_al->al_mnt->mf_private is (NULL)");
    return retval;
  }

  if (mp->am_pref)
    preflen = strlen(mp->am_pref);

  /* iterate over keys */
  for (i = 0; i < NKVHASH; i++) {
    kv *k;
    for (k = mmp->kvhash[i]; k ; k = k->next) {

      /*
       * Skip unwanted entries which are either not real entries or
       * very difficult to interpret (wildcards...)  This test needs
       * lots of improvement.  Any takers?
       */
      key = k->key;
      if (!key)
	continue;

      /* Skip '/defaults' */
      if (STREQ(key, "/defaults"))
	continue;

      /* Skip '*' */
      if (!fully_browsable && strchr(key, '*'))
	continue;

      /*
       * If the map has a prefix-string then check if the key starts with
       * this string, and if it does, skip over this prefix.  If it has a
       * prefix and it doesn't match the start of the key, skip it.
       */
      if (preflen) {
	if (preflen > strlen(key))
	  continue;
	if (!NSTREQ(key, mp->am_pref, preflen))
	  continue;
	key += preflen;
      }

      /* no more '/' are allowed, unless browsable_dirs=full was used */
      if (!fully_browsable && strchr(key, '/'))
	continue;

      /* no duplicates allowed */
      if (key_already_in_chain(key, current_chain))
	continue;

      /* fill in a cell and link the entry */
      if (num_entries >= max_entries) {
	/* out of space */
	plog(XLOG_DEBUG, "make_entry_chain: no more space in chain");
	if (num_entries > 0) {
	  chain[num_entries - 1].ne_nextentry = NULL;
	  retval = &chain[0];
	}
	return retval;
      }

      /* we have space.  put entry in next cell */
      ++last_cookie;
      chain[num_entries].ne_fileid = last_cookie;
      (void)memcpy(chain[num_entries].ne_cookie, &last_cookie,
	sizeof(last_cookie));
      chain[num_entries].ne_name = key;
      if (num_entries < max_entries - 1) {	/* link to next one */
	chain[num_entries].ne_nextentry = &chain[num_entries + 1];
      }
      ++num_entries;
    } /* end of "while (k)" */
  } /* end of "for (i ... NKVHASH ..." */

  /* terminate chain */
  if (num_entries > 0) {
    chain[num_entries - 1].ne_nextentry = NULL;
    retval = &chain[0];
  }

  return retval;
}
Пример #12
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 */
Пример #13
0
static char *
hack_name(char *dir)
{
  char partition[MAXPATHLEN];
  char username[MAXPATHLEN];
  char hesiod_lookup[MAXPATHLEN];
  char *to, *ch, *hes_name, *dot;
  char **hes;

#ifdef DEBUG
  fprintf(stderr, "hack_name(%s)\n", dir);
#endif /* DEBUG */

  if (dir[0] == '/' && dir[1] == 'a' && dir[2] == '/') {
    /* Could be /a/server/disk/home/partition/user... */
    ch = dir + 3;
    while (*ch && *ch != '/') ch++;  /* Skip server */
    if (!NSTREQ(ch, "/disk/home/", 11))
      return NULL;		/* Nope */
    /* Looking promising, next should be the partition name */
    ch += 11;
    to = partition;
    while (*ch && *ch != '/') *to++ = *ch++;
    to = '\0';
    if (!(*ch))
      return NULL;		/* Off the end */
    /* Now the username */
    ch++;
    to = username;
    while (*ch && *ch != '/') *to++ = *ch++;
    to = '\0';
#ifdef DEBUG
    fprintf(stderr, "partition %s, username %s\n", partition, username);
#endif /* DEBUG */

    xsnprintf(hesiod_lookup, sizeof(hesiod_lookup),
	      "%s.homes-remote", username);
    hes = hes_resolve(hesiod_lookup, "amd");
    if (!hes)
      return NULL;
#ifdef DEBUG
    fprintf(stderr, "hesiod -> <%s>\n", *hes);
#endif /* DEBUG */
    hes_name = strstr(*hes, "/homes/remote/");
    if (!hes_name) return NULL;
    hes_name += 14;
#ifdef DEBUG
    fprintf(stderr, "hesiod -> <%s>\n", hes_name);
#endif /* DEBUG */
    dot = hes_name;
    while (*dot && *dot != '.') dot++;
    *dot = '\0';
#ifdef DEBUG
    fprintf(stderr, "hesiod -> <%s>\n", hes_name);
#endif /* DEBUG */

    if (strcmp(partition, hes_name)) return NULL;
#ifdef DEBUG
    fprintf(stderr, "A match, munging....\n");
#endif /* DEBUG */
    xstrlcpy(transform, "/home/", sizeof(transform));
    xstrlcat(transform, username, sizeof(transform));
    if (*ch)
      xstrlcat(transform, ch, sizeof(transform));
#ifdef DEBUG
    fprintf(stderr, "Munged to <%s>\n", transform);
#endif /* DEBUG */
    return transform;
  }
  return NULL;
}