Exemple #1
0
/*
 * Handle an amd restart.
 *
 * Scan through the mount list finding all "interesting" mount points.
 * Next hack up partial data structures and add the mounted file
 * system to the list of known filesystems.
 *
 * This module relies on internal details of other components.  If
 * you change something else make *sure* restart() still works.
 */
void
restart(void)
{
  mntlist *ml, *mlp;

  /*
   * Read the existing mount table.  For each entry, find nfs, ufs or auto
   * mounts and create a partial am_node to represent it.
   */
  for (mlp = ml = read_mtab("restart", mnttab_file_name);
       mlp;
       mlp = mlp->mnext) {
    mntent_t *me = mlp->mnt;
    am_ops *fs_ops = NULL;

    if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS)) {
      /*
       * NFS entry, or possibly an Amd entry...
       * The mnt_fsname for daemon mount points is
       * 	host:(pidXXX)
       * or (seen on Solaris)
       *        host:daemon(pidXXX)
       */
      char *colon = strchr(me->mnt_fsname, ':');
      if (colon && strstr(colon, "(pid"))
	continue;
    }

    /* Search for the correct filesystem ops */
    fs_ops = ops_search(me->mnt_type);

    /*
     * Catch everything else with symlinks to
     * avoid recursive mounts.  This is debatable...
     */
    if (!fs_ops)
      fs_ops = &amfs_link_ops;

    restart_fake_mntfs(me, fs_ops);
  }

  /*
   * Free the mount list
   */
  free_mntlist(ml);
}
Exemple #2
0
/*
 * Handle an amd restart.
 *
 * Scan through the mount list finding all "interesting" mount points.
 * Next hack up partial data structures and add the mounted file
 * system to the list of known filesystems.  This will leave a
 * dangling reference to that filesystems, so when the filesystem is
 * finally inherited, an extra "free" must be done on it.
 *
 * This module relies on internal details of other components.  If
 * you change something else make *sure* restart() still works.
 */
void
restart(void)
{
  /*
   * Read the existing mount table
   */
  mntlist *ml, *mlp;

  /*
   * For each entry, find nfs, ufs or auto mounts
   * and create a partial am_node to represent it.
   */
  for (mlp = ml = read_mtab("restart", mnttab_file_name);
       mlp;
       mlp = mlp->mnext) {
    mntent_t *me = mlp->mnt;
    am_ops *fs_ops = 0;
    if (STREQ(me->mnt_type, MNTTAB_TYPE_UFS)) {
      /*
       * UFS entry
       */
      fs_ops = &ufs_ops;
    } else if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS)) {
      /*
       * NFS entry, or possibly an Amd entry...
       * The mnt_fsname for daemon mount points is
       * 	host:(pidXXX)
       * or (seen on Solaris)
       *        host:daemon(pidXXX)
       */
      char *colon = strchr(me->mnt_fsname, ':');

      if (colon && strstr(colon, "(pid")) {
	plog(XLOG_WARNING, "%s is an existing automount point", me->mnt_dir);
	fs_ops = &amfs_link_ops;
      } else {
	fs_ops = &nfs_ops;
      }
#ifdef MNTTAB_TYPE_NFS3
    } else if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS3)) {
      fs_ops = &nfs_ops;
#endif /* MNTTAB_TYPE_NFS3 */
#ifdef MNTTAB_TYPE_LOFS
    } else if (STREQ(me->mnt_type, MNTTAB_TYPE_LOFS)) {
      fs_ops = &lofs_ops;
#endif /* MNTTAB_TYPE_LOFS */
#ifdef MNTTAB_TYPE_CDFS
    } else if (STREQ(me->mnt_type, MNTTAB_TYPE_CDFS)) {
      fs_ops = &cdfs_ops;
#endif /* MNTTAB_TYPE_CDFS */
#ifdef MNTTAB_TYPE_PCFS
    } else if (STREQ(me->mnt_type, MNTTAB_TYPE_PCFS)) {
      fs_ops = &pcfs_ops;
#endif /* MNTTAB_TYPE_PCFS */
#ifdef MNTTAB_TYPE_MFS
    } else if (STREQ(me->mnt_type, MNTTAB_TYPE_MFS)) {
      /*
       * MFS entry.  Fake with a symlink.
       */
      fs_ops = &amfs_link_ops;
#endif /* MNTTAB_TYPE_MFS */
    } else {
      /*
       * Catch everything else with symlinks to
       * avoid recursive mounts.  This is debatable...
       */
      fs_ops = &amfs_link_ops;
    }

    /*
     * If we found something to do
     */
    if (fs_ops) {
      mntfs *mf;
      am_opts mo;
      char *cp;
      cp = strchr(me->mnt_fsname, ':');

      /*
       * Partially fake up an opts structure
       */
      memset(&mo, 0, sizeof(mo));
      mo.opt_rhost = 0;
      mo.opt_rfs = 0;
      if (cp) {
	*cp = '\0';
	mo.opt_rhost = strdup(me->mnt_fsname);
	mo.opt_rfs = strdup(cp + 1);
	*cp = ':';
      } else if (fs_ops->ffserver == find_nfs_srvr) {
	/*
	 * Prototype 4.4 BSD used to end up here -
	 * might as well keep the workaround for now
	 */
	plog(XLOG_WARNING, "NFS server entry assumed to be %s:/", me->mnt_fsname);
	mo.opt_rhost = strdup(me->mnt_fsname);
	mo.opt_rfs = strdup("/");
	me->mnt_fsname = str3cat(me->mnt_fsname, mo.opt_rhost, ":", "/");
      }
      mo.opt_fs = me->mnt_dir;
      mo.opt_opts = me->mnt_opts;

      /*
       * Make a new mounted filesystem
       */
      mf = find_mntfs(fs_ops, &mo, me->mnt_dir,
		      me->mnt_fsname, "", me->mnt_opts, "");
      if (mf->mf_refc == 1) {
	mf->mf_flags |= MFF_RESTART | MFF_MOUNTED;
	mf->mf_error = 0;	/* Already mounted correctly */
	mf->mf_fo = 0;
	/*
	 * If the restarted type is a link then
	 * don't time out.
	 */
	if (fs_ops == &amfs_link_ops || fs_ops == &ufs_ops)
	  mf->mf_flags |= MFF_RSTKEEP;
	if (fs_ops->fs_init) {
	  /*
	   * Don't care whether this worked since
	   * it is checked again when the fs is
	   * inherited.
	   */
	  (void) (*fs_ops->fs_init) (mf);
	}
	plog(XLOG_INFO, "%s restarted fstype %s on %s",
	     me->mnt_fsname, fs_ops->fs_type, me->mnt_dir);
      } else {
	/* Something strange happened - two mounts at the same place! */
	free_mntfs(mf);
      }
      /*
       * Clean up mo
       */
      if (mo.opt_rhost)
	XFREE(mo.opt_rhost);
      if (mo.opt_rfs)
	XFREE(mo.opt_rfs);
    }
  }

  /*
   * Free the mount list
   */
  free_mntlist(ml);
}
Exemple #3
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;
}
Exemple #4
0
int
umount_fs(char *mntdir, const char *mnttabname, u_int unmount_flags)
{
  mntlist *mlist, *mp, *mp_save = NULL;
  int error = 0;

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

#ifdef NEED_AUTOFS_SPACE_HACK
    if (unmount_flags & AMU_UMOUNT_AUTOFS) {
      char *mnt_dir_save = mp_save->mnt->mnt_dir;
      mp_save->mnt->mnt_dir = autofs_strdup_space_hack(mnt_dir_save);
      error = UNMOUNT_TRAP(mp_save->mnt);
      XFREE(mp_save->mnt->mnt_dir);
      mp_save->mnt->mnt_dir = mnt_dir_save;
    } else
#endif /* NEED_AUTOFS_SPACE_HACK */
      error = UNMOUNT_TRAP(mp_save->mnt);
    if (error < 0) {
      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(MNT2_GEN_OPT_FORCE) && defined(HAVE_UVMOUNT)
      case EBUSY:
      case EIO:
      case ESTALE:
	/* caller determines if forced unmounts should be used */
	if (unmount_flags & AMU_UMOUNT_FORCE) {
	  error = umount2_fs(mntdir, unmount_flags);
	  if (error < 0)
	    error = errno;
	  else
	    break;		/* all is OK */
	}
	/* fallthrough */
#endif /* MNT2_GEN_OPT_FORCE && HAVE_UVMOUNT */
      default:
	dlog("%s: unmount: %m", mp_save->mnt->mnt_dir);
	break;
      }
    }
    dlog("Finished unmount(%s)", mp_save->mnt->mnt_dir);

    if (!error) {
#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 */
    }

  } else {

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

  free_mntlist(mlist);

  return error;
}
Exemple #5
0
/*
 * Handle an amd restart for amd's own mount points.
 *
 * Scan through the mount list finding all daemon mount points
 * (determined by the presence of a pid inside the mount info).
 * Next hack up partial data structures and add the mounted file
 * system to the list of known filesystems.
 *
 * This module relies on internal details of other components.  If
 * you change something else make *sure* restart() still works.
 */
void
restart_automounter_nodes(void)
{
  mntlist *ml, *mlp;
  /* reasonably sized list of restarted nfs ports */
  u_short old_ports[256];

  memset((voidp) &old_ports, 0, sizeof(u_short) * 256);

  /*
   * Read the existing mount table.  For each entry, find nfs, ufs or auto
   * mounts and create a partial am_node to represent it.
   */
  for (mlp = ml = read_mtab("restart", mnttab_file_name);
       mlp;
       mlp = mlp->mnext) {
    mntent_t *me = mlp->mnt;
    am_ops *fs_ops = NULL;
    char *colon;
    long pid;
    u_short port;
    int err;

    if (!STREQ(me->mnt_type, MNTTAB_TYPE_NFS))
      continue;			/* to next mlp */
    /*
     * NFS entry, or possibly an Amd entry...
     * The mnt_fsname for daemon mount points is
     *	   host:(pidXXX)
     * or (seen on Solaris)
     *     host:daemon(pidXXX)
     */
    colon = strchr(me->mnt_fsname, ':');
    if (!colon || !strstr(colon, "(pid"))
      continue;
    /* if got here, then we matched an existing Amd mount point */
    err = 1;

    plog(XLOG_WARNING, "%s is an existing automount point", me->mnt_dir);

    /* Is the old automounter still alive? */
    if (sscanf(colon, "%*[^(](pid%ld%*[,)]", &pid) != 1) {
      plog(XLOG_WARNING, "Can't parse pid in %s", me->mnt_fsname);
      goto give_up;
    }
    if (kill(pid, 0) != -1 || errno != ESRCH) {
      plog(XLOG_WARNING, "Automounter (pid: %ld) still alive", pid);
      goto give_up;
    }

    /*
     * Do we have a map for this mount point?  Who cares, we'll restart
     * anyway -- getting ESTALE is way better than hanging.
     */

    /* Can we restart it? Only if it tells us what port it was using... */
    if (sscanf(colon, "%*[^,],port%hu)", &port) != 1) {
      plog(XLOG_WARNING, "No port specified for %s", me->mnt_fsname);
      goto give_up;
    }

    /* Maybe we already own that port... */
    if (port != nfs_port) {
      int i;
      for (i = 0; i < 256; i++) {
	if (old_ports[i] == port ||
	    old_ports[i] == 0)
	  break;
      }
      if (i == 256) {
	plog(XLOG_WARNING, "Too many open ports (256)");
	goto give_up;
      }

      if (old_ports[i] == 0) {
	int soNFS;
	SVCXPRT *nfsxprt;
	if (create_nfs_service(&soNFS, &port, &nfsxprt, nfs_program_2) != 0) {
	  plog(XLOG_WARNING, "Can't bind to port %u", port);
	  goto give_up;
	}
	old_ports[i] = nfs_port = port;
      }
    }
    err = 0;

  give_up:
    if (err) {
      plog(XLOG_WARNING, "Can't restart %s, leaving it alone", me->mnt_dir);
      fs_ops = &amfs_link_ops;
    } else {
      fs_ops = &amfs_toplvl_ops;
    }

    restart_fake_mntfs(me, fs_ops);
  } /* end of "for (mlp" */

  /* free the mount list */
  free_mntlist(ml);
}