Пример #1
0
/*
 * Take a little-endian domain name and
 * transform into a big-endian Un*x pathname.
 * For example: kiska.doc.ic -> ic/doc/kiska
 */
static char *
compute_hostpath(char *hn)
{
  char *p = xmalloc(MAXPATHLEN);
  char *d;
  char path[MAXPATHLEN];

  xstrlcpy(p, hn, MAXPATHLEN);
  domain_strip(p, hostname);
  path[0] = '\0';

  do {
    d = strrchr(p, '.');
    if (d) {
      *d = 0;
      xstrlcat(path, d + 1, sizeof(path));
      xstrlcat(path, "/", sizeof(path));
    } else {
      xstrlcat(path, p, sizeof(path));
    }
  } while (d);

  fsi_log("hostpath of '%s' is '%s'", hn, path);

  xstrlcpy(p, path, MAXPATHLEN);
  return p;
}
Пример #2
0
/*
 * Update the destination's file-tree with respect to changes in the
 * source manpath components.
 * "Change" is defined by an updated index or btree database.
 * Returns 1 on success, 0 on failure.
 */
static int
manup(const struct manpaths *dirs, char *base)
{
	char		 dst[MAXPATHLEN],
			 src[MAXPATHLEN];
	const char	*path;
	int		 i, c;
	size_t		 sz;
	FILE		*f;

	/* Create the path and file for the catman.conf file. */

	sz = strlen(base);
	xstrlcpy(dst, base, MAXPATHLEN);
	xstrlcat(dst, "/etc", MAXPATHLEN);
	if (-1 == mkpath(dst, 0755, 0755)) {
		perror(dst);
		return(0);
	}

	xstrlcat(dst, "/catman.conf", MAXPATHLEN);
	if (NULL == (f = fopen(dst, "w"))) {
		perror(dst);
		return(0);
	} else if (verbose)
		printf("%s\n", dst);

	for (i = 0; i < dirs->sz; i++) {
		path = dirs->paths[i];
		dst[(int)sz] = '\0';
		xstrlcat(dst, path, MAXPATHLEN);
		if (-1 == mkpath(dst, 0755, 0755)) {
			perror(dst);
			break;
		}

		xstrlcpy(src, path, MAXPATHLEN);
		if (-1 == (c = treecpy(dst, src)))
			break;
		else if (0 == c)
			continue;

		/*
		 * We want to use a relative path here because manpath.h
		 * will realpath() when invoked with man.cgi, and we'll
		 * make sure to chdir() into the cache directory before.
		 *
		 * This allows the cache directory to be in an arbitrary
		 * place, working in both chroot() and non-chroot()
		 * "safe" modes.
		 */
		assert('/' == path[0]);
		fprintf(f, "_whatdb %s/whatis.db\n", path + 1);
	}

	fclose(f);
	return(i == dirs->sz);
}
Пример #3
0
static void
ops_show1(char *buf, size_t l, int *linesizep, const char *name)
{
  xstrlcat(buf, name, l);
  xstrlcat(buf, ", ", l);
  *linesizep += strlen(name) + 2;
  if (*linesizep > 60) {
    xstrlcat(buf, "\t\n", l);
    *linesizep = 0;
  }
}
Пример #4
0
/*
 * start with an empty string. for each opts1 option that is not
 * in opts2, add it to the string (make sure the reverse of it
 * isn't in either). finally add opts2. return new string.
 * Both opts1 and opts2 must not be null!
 * Caller must eventually free the string being returned.
 */
static char *
merge_opts(const char *opts1, const char *opts2)
{
  mntent_t mnt2;		/* place holder for opts2 */
  char *newstr;			/* new string to return (malloc'ed) */
  char *tmpstr;			/* temp */
  char *eq;			/* pointer to whatever follows '=' within temp */
  char oneopt[80];		/* one option w/o value if any */
  char *revoneopt;		/* reverse of oneopt */
  size_t len = strlen(opts1) + strlen(opts2) + 2; /* space for "," and NULL */
  char *s1 = strdup(opts1);	/* copy of opts1 to munge */

  /* initialization */
  mnt2.mnt_opts = (char *) opts2;
  newstr = xmalloc(len);
  newstr[0] = '\0';

  for (tmpstr = strtok(s1, ",");
       tmpstr;
       tmpstr = strtok(NULL, ",")) {
    /* copy option to temp buffer */
    xstrlcpy(oneopt, tmpstr, sizeof(oneopt));
    /* if option has a value such as rsize=1024, chop the value part */
    if ((eq = haseq(oneopt)))
      *eq = '\0';
    /* find reverse option of oneopt */
    revoneopt = reverse_option(oneopt);
    /* if option orits reverse exist in opts2, ignore it */
    if (amu_hasmntopt(&mnt2, oneopt) || amu_hasmntopt(&mnt2, revoneopt))
      continue;
    /* add option to returned string */
    if (newstr[0]) {
      xstrlcat(newstr, ",", len);
      xstrlcat(newstr, tmpstr, len);
    } else {
      xstrlcpy(newstr, tmpstr, len);
    }
  }

  /* finally, append opts2 itself */
  if (newstr[0]) {
    xstrlcat(newstr, ",", len);
    xstrlcat(newstr, opts2, len);
  } else {
    xstrlcpy(newstr, opts2, len);
  }

  XFREE(s1);
  return newstr;
}
Пример #5
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;
}
Пример #6
0
int
ndbm_init(mnt_map *m, char *map, time_t *tp)
{
  DBM *db;

  db = dbm_open(map, O_RDONLY, 0);
  if (db) {
    struct stat stb;
    int error;
#ifdef DBM_SUFFIX
    char dbfilename[256];

    xstrlcpy(dbfilename, map, sizeof(dbfilename));
    xstrlcat(dbfilename, DBM_SUFFIX, sizeof(dbfilename));
    error = stat(dbfilename, &stb);
#else /* not DBM_SUFFIX */
    error = fstat(dbm_pagfno(db), &stb);
#endif /* not DBM_SUFFIX */
    if (error < 0)
      *tp = clocktime(NULL);
    else
      *tp = stb.st_mtime;
    dbm_close(db);
    return 0;
  }
  return errno;
}
Пример #7
0
int
ndbm_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
{
  DBM *db;

  db = dbm_open(map, O_RDONLY, 0);
  if (db) {
    struct stat stb;
    int error;
#ifdef DBM_SUFFIX
    char dbfilename[256];

    xstrlcpy(dbfilename, map, sizeof(dbfilename));
    xstrlcat(dbfilename, DBM_SUFFIX, sizeof(dbfilename));
    error = stat(dbfilename, &stb);
#else /* not DBM_SUFFIX */
    error = fstat(dbm_pagfno(db), &stb);
#endif /* not DBM_SUFFIX */
    if (!error && *tp < stb.st_mtime) {
      *tp = stb.st_mtime;
      error = -1;
    } else {
      error = search_ndbm(m, db, key, pval);
    }
    (void) dbm_close(db);
    return error;
  }
  return errno;
}
Пример #8
0
static mntent_t *
mnt_dup(struct statfs *mp)
{
  mntent_t *new_mp = ALLOC(mntent_t);
  char *ty;
  char *at;
  char mntfrombuf[MNAMELEN];
  char *mntfromptr;

  /*
   * Under DEC OSF/1 T1.2-2 the f_mntfromname fields of
   * the statfs structure can be in the format <fs>@<host>
   * instead of <host>:<fs>.  Here we check for this and
   * reformat it if necessary.
   */
  mntfromptr = mp->f_mntfromname;

  switch (mp->f_type) {
  case MOUNT_TYPE_NFS:
#ifdef HAVE_FS_NFS3
  case MOUNT_TYPE_NFS3:
#endif /* HAVE_FS_NFS3 */
    at = strchr(mp->f_mntfromname, '@');
    if (at != '\0') {
      xstrlcpy(mntfrombuf, (at + 1), sizeof(mntfrombuf));
      xstrlcat(mntfrombuf, ":", sizeof(mntfrombuf));
      strncat(mntfrombuf, mp->f_mntfromname, (at - mp->f_mntfromname));
      mntfromptr = mntfrombuf;
    }
  }
  new_mp->mnt_fsname = strdup(mntfromptr);

  new_mp->mnt_dir = strdup(mp->f_mntonname);
  switch (mp->f_type) {
  case MOUNT_TYPE_UFS:
    ty = MNTTAB_TYPE_UFS;
    break;
#ifdef HAVE_FS_NFS3
  case MOUNT_TYPE_NFS3:
    ty = MNTTAB_TYPE_NFS3;
    break;
#endif /* HAVE_FS_NFS3 */
  case MOUNT_TYPE_NFS:
    ty = MNTTAB_TYPE_NFS;
    break;
  case MOUNT_TYPE_MFS:
    ty = MNTTAB_TYPE_MFS;
    break;
  default:
    ty = "unknown";
    break;
  }

  new_mp->mnt_type = strdup(ty);
  new_mp->mnt_opts = strdup("unset");
  new_mp->mnt_freq = 0;
  new_mp->mnt_passno = 0;

  return new_mp;
}
Пример #9
0
void
ops_showamfstypes(char *buf, size_t l)
{
  struct am_ops **ap;
  int linesize = 0;

  buf[0] = '\0';
  for (ap = vops; *ap; ap++) {
    xstrlcat(buf, (*ap)->fs_type, l);
    if (ap[1])
      xstrlcat(buf, ", ", l);
    linesize += strlen((*ap)->fs_type) + 2;
    if (linesize > 62) {
      linesize = 0;
      xstrlcat(buf, "\n      ", l);
    }
  }
}
Пример #10
0
void
fatalerror(char *str)
{
#define ERRM ": %m"
  size_t l = strlen(str) + sizeof(ERRM) - 1;
  char *tmp = strnsave(str, l);
  xstrlcat(tmp, ERRM, l);
  fatal(tmp);
}
Пример #11
0
void
mapc_showtypes(char *buf, size_t l)
{
  map_type *mt=NULL, *lastmt;
  int linesize = 0, i;

  i = sizeof(maptypes) / sizeof(maptypes[0]);
  lastmt = maptypes + i;
  buf[0] = '\0';
  for (mt = maptypes; mt < lastmt; mt++) {
    xstrlcat(buf, mt->name, l);
    if (mt == (lastmt-1))
      break;	      /* if last one, don't do xstrlcat's that follows */
    linesize += strlen(mt->name);
    if (--i > 0) {
      xstrlcat(buf, ", ", l);
      linesize += 2;
    }
    if (linesize > 54) {
      linesize = 0;
      xstrlcat(buf, "\n\t\t ", l);
    }
  }
}
Пример #12
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;
}
Пример #13
0
/* get string version (in hex) of identifier */
static char *
get_hex_string(u_int len, const char *fhdata)
{
  u_int i;
  static char buf[128];		/* better not go over it! */
  char str[16];
  short int arr[64];

  if (!fhdata)
    return NULL;
  buf[0] = '\0';
  memset(&arr[0], 0, (64 * sizeof(short int)));
  memcpy(&arr[0], &fhdata[0], len);
  for (i=0; i<len/sizeof(unsigned short int); i++) {
    xsnprintf(str, sizeof(str), "%04x", ntohs(arr[i]));
    xstrlcat(buf, str, sizeof(buf));
  }
  return buf;
}
Пример #14
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;
  }
}
Пример #15
0
/*
 * See if btree or recno databases in the destination are out of date
 * with respect to a single manpath component.
 * Return -1 on fatal error, 0 if the source is no longer valid (and
 * shouldn't be listed), and 1 if the update went well.
 */
static int
treecpy(char *dst, char *src)
{
	size_t		 dsz, ssz;
	int		 rc;

	dsz = strlen(dst);
	ssz = strlen(src);

	xstrlcat(src, "/", MAXPATHLEN);
	xstrlcat(dst, "/", MAXPATHLEN);

	xstrlcat(src, MANDOC_IDX, MAXPATHLEN);
	xstrlcat(dst, MANDOC_IDX, MAXPATHLEN);

	if (-1 == (rc = isnewer(dst, src)))
		return(0);

	dst[(int)dsz] = src[(int)ssz] = '\0';

	if (1 == rc)
		return(update(dst, src));

	xstrlcat(src, "/", MAXPATHLEN);
	xstrlcat(dst, "/", MAXPATHLEN);

	xstrlcat(src, MANDOC_DB, MAXPATHLEN);
	xstrlcat(dst, MANDOC_DB, MAXPATHLEN);

	if (-1 == (rc = isnewer(dst, src)))
		return(0);
	else if (rc == 0)
		return(1);

	dst[(int)dsz] = src[(int)ssz] = '\0';

	return(update(dst, src));
}
Пример #16
0
/* return malloc'ed buffer.  caller must free it */
char *
print_wires(void)
{
  addrlist *al;
  char s[256];
  int i;
  char *buf;
  int bufcount = 0;
  int buf_size = 1024;

  buf = SALLOC(buf_size);	/* initial allocation (may grow!) */
  if (!buf)
    return NULL;

  if (!localnets) {
    xstrlcpy(buf, "No networks\n", buf_size);
    return buf;
  }
  /* check if there's more than one network */
  if (!localnets->ip_next) {
    /* use buf_size for sizeof(buf) because of the realloc() below */
    xsnprintf(buf, buf_size,
	      "Network: wire=\"%s\" (netnumber=%s).\n",
	      localnets->ip_net_name, localnets->ip_net_num);
    return buf;
  }
  buf[0] = '\0';		/* null out buffer before appending */
  for (i = 1, al = localnets; al; al = al->ip_next, i++) {
    xsnprintf(s, sizeof(s), "Network %d: wire=\"%s\" (netnumber=%s).\n",
	      i, al->ip_net_name, al->ip_net_num);
    bufcount += strlen(s);
    if (bufcount > buf_size) {
      buf_size *= 2;
      buf = xrealloc(buf, buf_size);
    }
    xstrlcat(buf, s, buf_size);
  }
  return buf;
}
Пример #17
0
/*
 * Copy both recno and btree databases into the destination.
 * Call in to begin recreating HTML files.
 * Return -1 on fatal error and 1 if the update went well.
 */
static int
update(char *dst, char *src)
{
	size_t		 dsz, ssz;

	dsz = strlen(dst);
	ssz = strlen(src);

	xstrlcat(src, "/", MAXPATHLEN);
	xstrlcat(dst, "/", MAXPATHLEN);

	xstrlcat(src, MANDOC_DB, MAXPATHLEN);
	xstrlcat(dst, MANDOC_DB, MAXPATHLEN);

	if ( ! filecpy(dst, src))
		return(-1);
	if (verbose)
		printf("%s\n", dst);

	dst[(int)dsz] = src[(int)ssz] = '\0';

	xstrlcat(src, "/", MAXPATHLEN);
	xstrlcat(dst, "/", MAXPATHLEN);

	xstrlcat(src, MANDOC_IDX, MAXPATHLEN);
	xstrlcat(dst, MANDOC_IDX, MAXPATHLEN);

	if ( ! filecpy(dst, src))
		return(-1);
	if (verbose)
		printf("%s\n", dst);

	dst[(int)dsz] = src[(int)ssz] = '\0';

	return(indexhtml(src, ssz, dst, dsz));
}
Пример #18
0
static void
set_auto_attrcache_timeout(char *preopts, char *opts, size_t l)
{

#ifdef MNTTAB_OPT_NOAC
  /*
   * Don't cache attributes - they are changing under the kernel's feet.
   * For example, IRIX5.2 will dispense with nfs lookup calls and hand stale
   * filehandles to getattr unless we disable attribute caching on the
   * automount points.
   */
  if (gopt.auto_attrcache == 0) {
    xsnprintf(preopts, l, ",%s", MNTTAB_OPT_NOAC);
    xstrlcat(opts, preopts, l);
  }
#endif /* MNTTAB_OPT_NOAC */

  /*
   * XXX: note that setting these to 0 in the past resulted in an error on
   * some systems, which is why it's better to use "noac" if possible.  For
   * now, we're setting everything possible, but if this will cause trouble,
   * then we'll have to condition the remainder of this on OPT_NOAC.
   */
#ifdef MNTTAB_OPT_ACTIMEO
  xsnprintf(preopts, l, ",%s=%d", MNTTAB_OPT_ACTIMEO, gopt.auto_attrcache);
  xstrlcat(opts, preopts, l);
#else /* MNTTAB_OPT_ACTIMEO */
# ifdef MNTTAB_OPT_ACDIRMIN
  xsnprintf(preopts, l, ",%s=%d", MNTTAB_OPT_ACTDIRMIN, gopt.auto_attrcache);
  xstrlcat(opts, preopts, l);
# endif /* MNTTAB_OPT_ACDIRMIN */
# ifdef MNTTAB_OPT_ACDIRMAX
  xsnprintf(preopts, l, ",%s=%d", MNTTAB_OPT_ACTDIRMAX, gopt.auto_attrcache);
  xstrlcat(opts, preopts, l);
# endif /* MNTTAB_OPT_ACDIRMAX */
# ifdef MNTTAB_OPT_ACREGMIN
  xsnprintf(preopts, l, ",%s=%d", MNTTAB_OPT_ACTREGMIN, gopt.auto_attrcache);
  xstrlcat(opts, preopts, l);
# endif /* MNTTAB_OPT_ACREGMIN */
# ifdef MNTTAB_OPT_ACREGMAX
  xsnprintf(preopts, l, ",%s=%d", MNTTAB_OPT_ACTREGMAX, gopt.auto_attrcache);
  xstrlcat(opts, preopts, l);
# endif /* MNTTAB_OPT_ACREGMAX */
#endif /* MNTTAB_OPT_ACTIMEO */
}
Пример #19
0
int
autofs_get_fh(am_node *mp)
{
    autofs_fh_t *fh;
    char buf[MAXHOSTNAMELEN];
    mntfs *mf = mp->am_al->al_mnt;
    struct utsname utsname;

    plog(XLOG_DEBUG, "autofs_get_fh for %s", mp->am_path);
    fh = ALLOC(autofs_fh_t);
    memset((voidp) fh, 0, sizeof(autofs_fh_t)); /* Paranoid */

    /*
     * SET MOUNT ARGS
     */
    if (uname(&utsname) < 0) {
        xstrlcpy(buf, "localhost.autofs", sizeof(buf));
    } else {
        xstrlcpy(buf, utsname.nodename, sizeof(buf));
        xstrlcat(buf, ".autofs", sizeof(buf));
    }
#ifdef HAVE_AUTOFS_ARGS_T_ADDR
    fh->addr.buf = xstrdup(buf);
    fh->addr.len = fh->addr.maxlen = strlen(buf);
#endif /* HAVE_AUTOFS_ARGS_T_ADDR */

    fh->direct = (mf->mf_fsflags & FS_DIRECT) ? 1 : 0;
    fh->rpc_to = 1;		/* XXX: arbitrary */
    fh->mount_to = mp->am_timeo;
    fh->path = mp->am_path;
    fh->opts = "";		/* XXX: arbitrary */
    fh->map = mp->am_path;	/* this is what we get back in readdir */

    mp->am_autofs_fh = fh;
    return 0;
}
Пример #20
0
/*
 * Return the version string (dynamic buffer)
 */
char *
get_version_string(void)
{
  char *vers = NULL;
  char tmpbuf[1024];
  char *wire_buf;
  int wire_buf_len = 0;
  size_t len;		  /* max allocated length (to avoid buf overflow) */

  /*
   * First get dynamic string listing all known networks.
   * This could be a long list, if host has lots of interfaces.
   */
  wire_buf = print_wires();
  if (wire_buf)
    wire_buf_len = strlen(wire_buf);

  len = 2048 + wire_buf_len;
  vers = xmalloc(len);
  xsnprintf(vers, len, "%s\n%s\n%s\n%s\n",
	    "Copyright (c) 1997-2014 Erez Zadok",
	    "Copyright (c) 1990 Jan-Simon Pendry",
	    "Copyright (c) 1990 Imperial College of Science, Technology & Medicine",
	    "Copyright (c) 1990 The Regents of the University of California.");
  xsnprintf(tmpbuf, sizeof(tmpbuf), "%s version %s (build %d).\n",
	    PACKAGE_NAME, PACKAGE_VERSION, AMU_BUILD_VERSION);
  xstrlcat(vers, tmpbuf, len);
  xsnprintf(tmpbuf, sizeof(tmpbuf), "Report bugs to %s.\n", PACKAGE_BUGREPORT);
  xstrlcat(vers, tmpbuf, len);
#if 0
  /*
   * XXX  This block (between from the #if 0 to #endif was in the
   * XXX  original was in the original merge however in the interest
   * XXX  of reproduceable builds and the fact that this is redundant
   * XXX  information, it is effectively removed.
   */
  xsnprintf(tmpbuf, sizeof(tmpbuf), "Configured by %s@%s on date %s.\n",
	    USER_NAME, HOST_NAME, CONFIG_DATE);
  xstrlcat(vers, tmpbuf, len);
  xsnprintf(tmpbuf, sizeof(tmpbuf), "Built by %s@%s on date %s.\n",
	    BUILD_USER, BUILD_HOST, BUILD_DATE);
  xstrlcat(vers, tmpbuf, len);
#endif
  xsnprintf(tmpbuf, sizeof(tmpbuf), "cpu=%s (%s-endian), arch=%s, karch=%s.\n",
	    cpu, endian, gopt.arch, gopt.karch);
  xstrlcat(vers, tmpbuf, len);
  xsnprintf(tmpbuf, sizeof(tmpbuf), "full_os=%s, os=%s, osver=%s, vendor=%s, distro=%s.\n",
	    gopt.op_sys_full, gopt.op_sys, gopt.op_sys_ver, gopt.op_sys_vendor, DISTRO_NAME);
  xstrlcat(vers, tmpbuf, len);
  xsnprintf(tmpbuf, sizeof(tmpbuf), "domain=%s, host=%s, hostd=%s.\n",
	    hostdomain, am_get_hostname(), hostd);
  xstrlcat(vers, tmpbuf, len);

  xstrlcat(vers, "Map support for: ", len);
  mapc_showtypes(tmpbuf, sizeof(tmpbuf));
  xstrlcat(vers, tmpbuf, len);
  xstrlcat(vers, ".\nAMFS: ", len);
  ops_showamfstypes(tmpbuf, sizeof(tmpbuf));
  xstrlcat(vers, tmpbuf, len);
  xstrlcat(vers, ", inherit.\nFS: ", len); /* hack: "show" that we support type:=inherit */
  ops_showfstypes(tmpbuf, sizeof(tmpbuf));
  xstrlcat(vers, tmpbuf, len);

  /* append list of networks if available */
  if (wire_buf) {
    xstrlcat(vers, wire_buf, len);
    XFREE(wire_buf);
  }

  return vers;
}
Пример #21
0
/*
 * Mount the top-level
 */
int
amfs_toplvl_mount(am_node *mp, mntfs *mf)
{
  struct stat stb;
  char opts[SIZEOF_OPTS], preopts[SIZEOF_OPTS], toplvl_opts[40];
  int error;

  /*
   * Mounting the automounter.
   * Make sure the mount directory exists, construct
   * the mount options and call the mount_amfs_toplvl routine.
   */

  if (stat(mp->am_path, &stb) < 0) {
    return errno;
  } else if ((stb.st_mode & S_IFMT) != S_IFDIR) {
    plog(XLOG_WARNING, "%s is not a directory", mp->am_path);
    return ENOTDIR;
  }

  /*
   * Construct some mount options:
   *
   * Tack on magic map=<mapname> option in mtab to emulate
   * SunOS automounter behavior.
   */

#ifdef HAVE_FS_AUTOFS
  if (mf->mf_flags & MFF_IS_AUTOFS) {
    autofs_get_opts(opts, sizeof(opts), mp->am_autofs_fh);
  } else
#endif /* HAVE_FS_AUTOFS */
  {
    preopts[0] = '\0';
#ifdef MNTTAB_OPT_INTR
    xstrlcat(preopts, MNTTAB_OPT_INTR, sizeof(preopts));
    xstrlcat(preopts, ",", sizeof(preopts));
#endif /* MNTTAB_OPT_INTR */
#ifdef MNTTAB_OPT_IGNORE
    xstrlcat(preopts, MNTTAB_OPT_IGNORE, sizeof(preopts));
    xstrlcat(preopts, ",", sizeof(preopts));
#endif /* MNTTAB_OPT_IGNORE */
    /* write most of the initial options + preopts */
    xsnprintf(opts, sizeof(opts), "%s%s,%s=%d,%s,map=%s",
	      preopts,
	      MNTTAB_OPT_RW,
	      MNTTAB_OPT_PORT, nfs_port,
	      mf->mf_ops->fs_type, mf->mf_info);

    /* process toplvl timeo/retrans options, if any */
    if (gopt.amfs_auto_timeo[AMU_TYPE_TOPLVL] > 0) {
      xsnprintf(toplvl_opts, sizeof(toplvl_opts), ",%s=%d",
		MNTTAB_OPT_TIMEO, gopt.amfs_auto_timeo[AMU_TYPE_TOPLVL]);
      xstrlcat(opts, toplvl_opts, sizeof(opts));
    }
    if (gopt.amfs_auto_retrans[AMU_TYPE_TOPLVL] > 0) {
      xsnprintf(toplvl_opts, sizeof(toplvl_opts), ",%s=%d",
		MNTTAB_OPT_RETRANS, gopt.amfs_auto_retrans[AMU_TYPE_TOPLVL]);
      xstrlcat(opts, toplvl_opts, sizeof(opts));
    }

#ifdef MNTTAB_OPT_NOLOCK
    xstrlcat(opts, ",", sizeof(opts));
    xstrlcat(opts, MNTTAB_OPT_NOLOCK, sizeof(opts));
#endif /* MNTTAB_OPT_NOLOCK */

#ifdef MNTTAB_OPT_NOAC
    if (gopt.auto_attrcache == 0) {
      xstrlcat(opts, ",", sizeof(opts));
      xstrlcat(opts, MNTTAB_OPT_NOAC, sizeof(opts));
    } else
#endif /* MNTTAB_OPT_NOAC */
      set_auto_attrcache_timeout(preopts, opts, sizeof(preopts));
  }

  /* now do the mount */
  error = amfs_mount(mp, mf, opts);
  if (error) {
    errno = error;
    plog(XLOG_FATAL, "amfs_toplvl_mount: amfs_mount failed: %m");
    return error;
  }
  return 0;
}
Пример #22
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;
}
Пример #23
0
void
ops_showfstypes(char *buf, size_t l)
{
  int linesize = 0;

  buf[0] = '\0';

#ifdef MNTTAB_TYPE_AUTOFS
  ops_show1(buf, l, &linesize, MNTTAB_TYPE_AUTOFS);
#endif /* MNTTAB_TYPE_AUTOFS */

#ifdef MNTTAB_TYPE_CACHEFS
  ops_show1(buf, l, &linesize, MNTTAB_TYPE_CACHEFS);
#endif /* MNTTAB_TYPE_CACHEFS */

#ifdef MNTTAB_TYPE_CDFS
  ops_show1(buf, l, &linesize, MNTTAB_TYPE_CDFS);
#endif /* MNTTAB_TYPE_CDFS */

#ifdef MNTTAB_TYPE_CFS
  ops_show1(buf, l, &linesize, MNTTAB_TYPE_CFS);
#endif /* MNTTAB_TYPE_CFS */

#ifdef MNTTAB_TYPE_LOFS
  ops_show1(buf, l, &linesize, MNTTAB_TYPE_LOFS);
#endif /* MNTTAB_TYPE_LOFS */

#ifdef MNTTAB_TYPE_EFS
  ops_show1(buf, l, &linesize, MNTTAB_TYPE_EFS);
#endif /* MNTTAB_TYPE_EFS */

#ifdef MNTTAB_TYPE_MFS
  ops_show1(buf, l, &linesize, MNTTAB_TYPE_MFS);
#endif /* MNTTAB_TYPE_MFS */

#ifdef MNTTAB_TYPE_NFS
  ops_show1(buf, l, &linesize, MNTTAB_TYPE_NFS);
#endif /* MNTTAB_TYPE_NFS */

#ifdef MNTTAB_TYPE_NFS3
  ops_show1(buf, l, &linesize, "nfs3"); /* always hard-code as nfs3 */
#endif /* MNTTAB_TYPE_NFS3 */

#ifdef MNTTAB_TYPE_NULLFS
  ops_show1(buf, l, &linesize, MNTTAB_TYPE_NULLFS);
#endif /* MNTTAB_TYPE_NULLFS */

#ifdef MNTTAB_TYPE_PCFS
  ops_show1(buf, l, &linesize, MNTTAB_TYPE_PCFS);
#endif /* MNTTAB_TYPE_PCFS */

#ifdef MNTTAB_TYPE_TFS
  ops_show1(buf, l, &linesize, MNTTAB_TYPE_TFS);
#endif /* MNTTAB_TYPE_TFS */

#ifdef MNTTAB_TYPE_TMPFS
  ops_show1(buf, l, &linesize, MNTTAB_TYPE_TMPFS);
#endif /* MNTTAB_TYPE_TMPFS */

#ifdef MNTTAB_TYPE_UFS
  ops_show1(buf, l, &linesize, MNTTAB_TYPE_UFS);
#endif /* MNTTAB_TYPE_UFS */

#ifdef MNTTAB_TYPE_UMAPFS
  ops_show1(buf, l, &linesize, MNTTAB_TYPE_UMAPFS);
#endif /* MNTTAB_TYPE_UMAPFS */

#ifdef MNTTAB_TYPE_UNIONFS
  ops_show1(buf, l, &linesize, MNTTAB_TYPE_UNIONFS);
#endif /* MNTTAB_TYPE_UNIONFS */

#ifdef MNTTAB_TYPE_XFS
  ops_show1(buf, l, &linesize, MNTTAB_TYPE_XFS);
#endif /* MNTTAB_TYPE_XFS */

  /* terminate with a period, newline, and NULL */
  if (buf[strlen(buf)-1] == '\n')
    buf[strlen(buf) - 4] = '\0';
  else
    buf[strlen(buf) - 2] = '\0';
  xstrlcat(buf, ".\n", l);
}
Пример #24
0
/*
 * Write out a mount list
 */
void
rewrite_mtab(mntlist *mp, const char *mnttabname)
{
  FILE *mfp;
  int error = 0;
  char tmpname[64];
  int retries;
  int tmpfd;
  char *cp;
  char mcp[128];

  if (!mtab_is_writable()) {
    return;
  }

  /*
   * Concoct a temporary name in the same directory as the target mount
   * table so that rename() will work.
   */
  xstrlcpy(mcp, mnttabname, sizeof(mcp));
  cp = strrchr(mcp, '/');
  if (cp) {
    memmove(tmpname, mcp, cp - mcp);
    tmpname[cp - mcp] = '\0';
  } else {
    plog(XLOG_WARNING, "No '/' in mtab (%s), using \".\" as tmp directory", mnttabname);
    tmpname[0] = '.';
    tmpname[1] = '\0';
  }
  xstrlcat(tmpname, "/mtabXXXXXX", sizeof(tmpname));
  retries = 0;
 enfile1:
#ifdef HAVE_MKSTEMP
  tmpfd = mkstemp(tmpname);
  fchmod(tmpfd, 0644);
#else /* not HAVE_MKSTEMP */
  mktemp(tmpname);
  tmpfd = open(tmpname, O_RDWR | O_CREAT | O_TRUNC, 0644);
#endif /* not HAVE_MKSTEMP */
  if (tmpfd < 0) {
    if (errno == ENFILE && retries++ < NFILE_RETRIES) {
      sleep(1);
      goto enfile1;
    }
    plog(XLOG_ERROR, "%s: open: %m", tmpname);
    return;
  }
  if (close(tmpfd) < 0)
    plog(XLOG_ERROR, "Couldn't close tmp file descriptor: %m");

  retries = 0;
 enfile2:
  mfp = setmntent(tmpname, "w");
  if (!mfp) {
    if (errno == ENFILE && retries++ < NFILE_RETRIES) {
      sleep(1);
      goto enfile2;
    }
    plog(XLOG_ERROR, "setmntent(\"%s\", \"w\"): %m", tmpname);
    error = 1;
    goto out;
  }
  while (mp) {
    if (mp->mnt) {
      if (addmntent(mfp, mp->mnt)) {
	plog(XLOG_ERROR, "Can't write entry to %s", tmpname);
	error = 1;
	goto out;
      }
    }
    mp = mp->mnext;
  }

  /*
   * SunOS 4.1 manuals say that the return code from entmntent()
   * is always 1 and to treat as a void.  That means we need to
   * call fflush() to make sure the new mtab file got written.
   */
  if (fflush(mfp)) {
    plog(XLOG_ERROR, "flush new mtab file: %m");
    error = 1;
    goto out;
  }
  (void) endmntent(mfp);

  /*
   * Rename temporary mtab to real mtab
   */
  if (rename(tmpname, mnttabname) < 0) {
    plog(XLOG_ERROR, "rename %s to %s: %m", tmpname, mnttabname);
    error = 1;
    goto out;
  }
 out:
  if (error)
    (void) unlink(tmpname);
}
Пример #25
0
/*
 * Pass over the recno database and re-create HTML pages if they're
 * found to be out of date.
 * Returns -1 on fatal error, 1 on success.
 */
static int
indexhtml(char *src, size_t ssz, char *dst, size_t dsz)
{
	DB		*idx;
	DBT		 key, val;
	int		 c, rc;
	unsigned int	 fl;
	const char	*f;
	char		*d;
	char		 fname[MAXPATHLEN];
	pid_t		 pid;

	pid = -1;

	xstrlcpy(fname, dst, MAXPATHLEN);
	xstrlcat(fname, "/", MAXPATHLEN);
	xstrlcat(fname, MANDOC_IDX, MAXPATHLEN);

	idx = dbopen(fname, O_RDONLY, 0, DB_RECNO, NULL);
	if (NULL == idx) {
		perror(fname);
		return(-1);
	}

	fl = R_FIRST;
	while (0 == (c = (*idx->seq)(idx, &key, &val, fl))) {
		fl = R_NEXT;
		/*
		 * If the record is zero-length, then it's unassigned.
		 * Skip past these.
		 */
		if (0 == val.size)
			continue;

		f = (const char *)val.data + 1;
		if (NULL == memchr(f, '\0', val.size - 1))
			break;

		src[(int)ssz] = dst[(int)dsz] = '\0';

		xstrlcat(dst, "/", MAXPATHLEN);
		xstrlcat(dst, f, MAXPATHLEN);

		xstrlcat(src, "/", MAXPATHLEN);
		xstrlcat(src, f, MAXPATHLEN);

		if (-1 == (rc = isnewer(dst, src))) {
			fprintf(stderr, "%s: File missing\n", f);
			break;
		} else if (0 == rc)
			continue;

		d = strrchr(dst, '/');
		assert(NULL != d);
		*d = '\0';

		if (-1 == mkpath(dst, 0755, 0755)) {
			perror(dst);
			break;
		}

		*d = '/';

		if ( ! filecpy(dst, src))
			break;
		if (verbose)
			printf("%s\n", dst);
	}

	(*idx->close)(idx);

	if (c < 0)
		perror(fname);
	else if (0 == c) 
		fprintf(stderr, "%s: Corrupt index\n", fname);

	return(1 == c ? 1 : -1);
}
Пример #26
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++;
    }

  /* 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, 0);

#ifndef MOUNT_TABLE_ON_FILE
  if (amuDebug(D_MTAB))
    dlog("-D mtab option ignored");
#endif /* not 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);
  }

  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 */

  /*
   * In the parent, if -D nodaemon, we don't need to
   * set this signal handler.
   */
  if (amuDebug(D_DAEMON)) {
    s = -99;
    while (stoplight != SIGUSR2) {
      plog(XLOG_INFO, "parent waits for child to setup (stoplight=%d)", stoplight);
#ifdef HAVE_SIGSUSPEND
      {
	sigset_t mask;
	sigemptyset(&mask);
	s = sigsuspend(&mask);	/* wait for child to set up */
      }
#else /* not HAVE_SIGSUSPEND */
      s = sigpause(0);		/* wait for child to set up */
#endif /* not HAVE_SIGSUSPEND */
      sleep(1);
    }
  }

  /*
   * setup options to mount table (/etc/{mtab,mnttab}) entry
   */
  xsnprintf(hostpid_fs, sizeof(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 {
    xstrlcpy(preopts, default_mntopts, sizeof(preopts));
    /*
     * 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
    xstrlcat(preopts, ",", sizeof(preopts));
    xstrlcat(preopts, MNTTAB_OPT_INTR, sizeof(preopts));
#endif /* MNTTAB_OPT_INTR */
#ifdef MNTTAB_OPT_IGNORE
    xstrlcat(preopts, ",", sizeof(preopts));
    xstrlcat(preopts, MNTTAB_OPT_IGNORE, sizeof(preopts));
#endif /* MNTTAB_OPT_IGNORE */
#ifdef MNT2_GEN_OPT_CACHE
    xstrlcat(preopts, ",nocache", sizeof(preopts));
#endif /* MNT2_GEN_OPT_CACHE */
#ifdef MNT2_NFS_OPT_SYMTTL
    xstrlcat(preopts, ",symttl=0", sizeof(preopts));
#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, NULL);
  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
   */
  xsnprintf(progpid_fs, sizeof(progpid_fs),
	    "%s:%d", am_get_progname(), masterpid);

  /* Most kernels have a name length restriction. */
  if ((int) strlen(progpid_fs) >= (int) MAXHOSTNAMELEN)
    xstrlcpy(progpid_fs + MAXHOSTNAMELEN - 3, "..",
	     sizeof(progpid_fs) - MAXHOSTNAMELEN + 3);

  genflags = compute_mount_flags(&mnt);

  retry = hasmntval(&mnt, MNTTAB_OPT_RETRY);
  if (retry <= 0)
    retry = 1;			/* XXX */

  memmove(&anh.v2, 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);

/*
 * For some reason, this mount may have to be done in the background, if I am
 * using -D daemon.  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 daemon, 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.
 */
  if (!amuDebug(D_DAEMON)) {	/* Normal case */
    plog(XLOG_INFO, "normal NFS mounting hlfsd service points");
    if (mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name, 0) < 0)
      fatal("nfsmount: %m");
  } else {			/* asked for -D daemon */
    if (fork() == 0) {		/* child runs mount */
      am_set_mypid();
      foreground = 0;
      plog(XLOG_INFO, "child NFS mounting hlfsd service points");
      if (mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name, 0) < 0) {
	fatal("nfsmount: %m");
      }
      exit(0);			/* all went well */
    } else { /* fork failed or parent running */
      plog(XLOG_INFO, "parent waiting 1sec for mount...");
    }
  }

#ifdef HAVE_TRANSPORT_TYPE_TLI
  /*
   * XXX: this free_knetconfig() was not done for hlfsd before,
   * and apparently there was a reason for it, but why? -Erez
   */
  free_knetconfig(nfs_args.knconf);
  /*
   * local automounter mounts do not allocate a special address, so
   * no need to XFREE(nfs_args.addr) under TLI.
   */
#endif /* HAVE_TRANSPORT_TYPE_TLI */

  if (printpid)
    printf("%d\n", masterpid);

  plog(XLOG_INFO, "hlfsd ready to serve");
  /*
   * If asked not to fork a daemon (-D nodaemon), then hlfsd_init()
   * will not run svc_run.  We must start svc_run here.
   */
  if (!amuDebug(D_DAEMON)) {
    plog(XLOG_DEBUG, "starting no-daemon debugging svc_run");
    svc_run();
  }

  cleanup(0);			/* should never happen here */
  return (0);			/* everything went fine? */
}