amfs_host.c revision 38494
118334Speter/*
2169689Skan * Copyright (c) 1997-1998 Erez Zadok
3132718Skan * Copyright (c) 1990 Jan-Simon Pendry
418334Speter * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
518334Speter * Copyright (c) 1990 The Regents of the University of California.
6132718Skan * All rights reserved.
718334Speter *
8132718Skan * This code is derived from software contributed to Berkeley by
918334Speter * Jan-Simon Pendry at Imperial College, London.
1018334Speter *
1118334Speter * Redistribution and use in source and binary forms, with or without
1218334Speter * modification, are permitted provided that the following conditions
13132718Skan * are met:
1418334Speter * 1. Redistributions of source code must retain the above copyright
1518334Speter *    notice, this list of conditions and the following disclaimer.
1618334Speter * 2. Redistributions in binary form must reproduce the above copyright
1718334Speter *    notice, this list of conditions and the following disclaimer in the
1818334Speter *    documentation and/or other materials provided with the distribution.
19132718Skan * 3. All advertising materials mentioning features or use of this software
20169689Skan *    must display the following acknowledgement:
21169689Skan *      This product includes software developed by the University of
2218334Speter *      California, Berkeley and its contributors.
2318334Speter * 4. Neither the name of the University nor the names of its contributors
2418334Speter *    may be used to endorse or promote products derived from this software
2518334Speter *    without specific prior written permission.
2618334Speter *
2718334Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2818334Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2918334Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3050397Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31132718Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32132718Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3318334Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3418334Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3518334Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3618334Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3750397Sobrien * SUCH DAMAGE.
3890075Sobrien *
39169689Skan *      %W% (Berkeley) %G%
4018334Speter *
41132718Skan * $Id: amfs_host.c,v 5.2.2.2 1992/05/31 16:36:08 jsp Exp $
42132718Skan *
43169689Skan */
44132718Skan
45169689Skan/*
4618334Speter * NFS host file system.
47117395Skan * Mounts all exported filesystems from a given host.
4818334Speter * This has now degenerated into a mess but will not
4918334Speter * be rewritten.  Amd 6 will support the abstractions
50117395Skan * needed to make this work correctly.
5150397Sobrien */
5290075Sobrien
53169689Skan#ifdef HAVE_CONFIG_H
5418334Speter# include <config.h>
5550397Sobrien#endif /* HAVE_CONFIG_H */
5650397Sobrien#include <am_defs.h>
5718334Speter#include <amd.h>
58132718Skan
5918334Speterstatic char *amfs_host_match(am_opts *fo);
6050397Sobrienstatic int amfs_host_fmount(mntfs *mf);
6150397Sobrienstatic int amfs_host_fumount(mntfs *mf);
6250397Sobrienstatic int amfs_host_init(mntfs *mf);
6350397Sobrienstatic void amfs_host_umounted(am_node *mp);
6450397Sobrien
6550397Sobrien/*
6650397Sobrien * Ops structure
6750397Sobrien */
6850397Sobrienam_ops amfs_host_ops =
6950397Sobrien{
7050397Sobrien  "host",
71169689Skan  amfs_host_match,
72169689Skan  amfs_host_init,
73169689Skan  amfs_auto_fmount,
74169689Skan  amfs_host_fmount,
7550397Sobrien  amfs_auto_fumount,
7650397Sobrien  amfs_host_fumount,
7750397Sobrien  amfs_error_lookuppn,
7850397Sobrien  amfs_error_readdir,
7950397Sobrien  0,				/* amfs_host_readlink */
8050397Sobrien  0,				/* amfs_host_mounted */
8150397Sobrien  amfs_host_umounted,
8250397Sobrien  find_nfs_srvr,
8350397Sobrien  FS_MKMNT | FS_BACKGROUND | FS_AMQINFO
8450397Sobrien};
8550397Sobrien
8650397Sobrien
87169689Skan/*
8818334Speter * Determine the mount point:
8918334Speter *
90132718Skan * The next change we put in to better handle PCs.  This is a bit
91132718Skan * disgusting, so you'd better sit down.  We change the make_mntpt function
9218334Speter * to look for exported file systems without a leading '/'.  If they don't
9318334Speter * have a leading '/', we add one.  If the export is 'a:' through 'z:'
9450397Sobrien * (without a leading slash), we change it to 'a%' (or b% or z%).  This
9518334Speter * allows the entire PC disk to be mounted.
9618334Speter */
9750397Sobrienstatic void
9850397Sobrienmake_mntpt(char *mntpt, const exports ex, const mntfs *mf)
9950397Sobrien{
10018334Speter  if (ex->ex_dir[0] == '/') {
10150397Sobrien    if (ex->ex_dir[1] == 0)
10250397Sobrien      strcpy(mntpt, (mf)->mf_mount);
10350397Sobrien    else
10450397Sobrien      sprintf(mntpt, "%s%s", mf->mf_mount, ex->ex_dir);
105169689Skan  } else if (ex->ex_dir[0] >= 'a' &&
10618334Speter	     ex->ex_dir[0] <= 'z' &&
10718334Speter	     ex->ex_dir[1] == ':' &&
10818334Speter	     ex->ex_dir[2] == '/' &&
10918334Speter	     ex->ex_dir[3] == 0)
11018334Speter    sprintf(mntpt, "%s/%c%%", mf->mf_mount, ex->ex_dir[0]);
11118334Speter  else
112169689Skan    sprintf(mntpt, "%s/%s", mf->mf_mount, ex->ex_dir);
11318334Speter}
11418334Speter
11518334Speter
11618334Speter/*
11790075Sobrien * Execute needs the same as NFS plus a helper command
118169689Skan */
11918334Speterstatic char *
120169689Skanamfs_host_match(am_opts *fo)
121132718Skan{
12218334Speter  extern am_ops nfs_ops;
123132718Skan
12452284Sobrien  /*
12518334Speter   * Make sure rfs is specified to keep nfs_match happy...
12618334Speter   */
127169689Skan  if (!fo->opt_rfs)
12818334Speter    fo->opt_rfs = "/";
12990075Sobrien
13090075Sobrien  return (*nfs_ops.fs_match) (fo);
13118334Speter}
13218334Speter
13318334Speter
134169689Skanstatic int
135117395Skanamfs_host_init(mntfs *mf)
136117395Skan{
13718334Speter  fserver *fs;
138169689Skan  u_short port;
13918334Speter
14018334Speter  if (strchr(mf->mf_info, ':') == 0)
14118334Speter    return ENOENT;
142132718Skan
14318334Speter  /*
14418334Speter   * This is primarily to schedule a wakeup so that as soon
14518334Speter   * as our fileserver is ready, we can continue setting up
14618334Speter   * the host filesystem.  If we don't do this, the standard
14718334Speter   * amfs_auto code will set up a fileserver structure, but it will
14818334Speter   * have to wait for another nfs request from the client to come
14918334Speter   * in before finishing.  Our way is faster since we don't have
150169689Skan   * to wait for the client to resend its request (which could
15118334Speter   * take a second or two).
15218334Speter   */
15318334Speter  /*
154169689Skan   * First, we find the fileserver for this mntfs and then call
15518334Speter   * nfs_srvr_port with our mntfs passed as the wait channel.
15618334Speter   * nfs_srvr_port will check some things and then schedule
157169689Skan   * it so that when the fileserver is ready, a wakeup is done
15818334Speter   * on this mntfs.   amfs_auto_cont() is already sleeping on this mntfs
15918334Speter   * so as soon as that wakeup happens amfs_auto_cont() is called and
16018334Speter   * this mount is retried.
16118334Speter   */
162169689Skan  if ((fs = mf->mf_server))
163169689Skan    /*
164169689Skan     * We don't really care if there's an error returned.
165169689Skan     * Since this is just to help speed things along, the
16690075Sobrien     * error will get handled properly elsewhere.
167169689Skan     */
168169689Skan    (void) nfs_srvr_port(fs, &port, (voidp) mf);
16918334Speter
170169689Skan  return 0;
171169689Skan}
17218334Speter
17318334Speter
17418334Speterstatic int
17550397Sobriendo_mount(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *mf)
17618334Speter{
17718334Speter  struct stat stb;
17818334Speter
17918334Speter#ifdef DEBUG
180117395Skan  dlog("amfs_host: mounting fs %s on %s\n", fs_name, dir);
18150397Sobrien#endif /* DEBUG */
18218334Speter
183117395Skan  (void) mkdirs(dir, 0555);
18450397Sobrien  if (stat(dir, &stb) < 0 || (stb.st_mode & S_IFMT) != S_IFDIR) {
18518334Speter    plog(XLOG_ERROR, "No mount point for %s - skipping", dir);
186117395Skan    return ENOENT;
18718334Speter  }
188169689Skan
189169689Skan  return mount_nfs_fh(fhp, dir, fs_name, opts, mf);
190169689Skan}
191169689Skan
19218334Speter
193169689Skanstatic int
194169689Skansortfun(const voidp x, const voidp y)
19518334Speter{
19618334Speter  exports *a = (exports *) x;
197169689Skan  exports *b = (exports *) y;
19818334Speter
19918334Speter  return strcmp((*a)->ex_dir, (*b)->ex_dir);
20018334Speter}
20118334Speter
20218334Speter
20318334Speter/*
20418334Speter * Get filehandle
205169689Skan */
20618334Speterstatic int
20718334Speterfetch_fhandle(CLIENT * client, char *dir, am_nfs_handle_t *fhp, u_long nfs_version)
208169689Skan{
209132718Skan  struct timeval tv;
21018334Speter  enum clnt_stat clnt_stat;
211169689Skan
21218334Speter  /*
21318334Speter   * Pick a number, any number...
21418334Speter   */
215169689Skan  tv.tv_sec = 20;
21618334Speter  tv.tv_usec = 0;
21718334Speter
218169689Skan#ifdef DEBUG
219169689Skan  dlog("Fetching fhandle for %s", dir);
22018334Speter#endif /* DEBUG */
22118334Speter
22218334Speter  /*
22318334Speter   * Call the mount daemon on the remote host to
22418334Speter   * get the filehandle.  Use NFS version specific call.
225132718Skan   */
22618334Speter
22718334Speter  plog(XLOG_INFO, "fetch_fhandle: NFS version %d", nfs_version);
22850397Sobrien#ifdef HAVE_FS_NFS3
229169689Skan  if (nfs_version == NFS_VERSION3) {
23018334Speter    memset((char *) &fhp->v3, 0, sizeof(fhp->v3));
231132718Skan    clnt_stat = clnt_call(client,
23218334Speter			  MOUNTPROC_MNT,
23318334Speter			  (XDRPROC_T_TYPE) xdr_dirpath,
234169689Skan			  (SVC_IN_ARG_TYPE) &dir,
235169689Skan			  (XDRPROC_T_TYPE) xdr_mountres3,
23618334Speter			  (SVC_IN_ARG_TYPE) &fhp->v3,
237169689Skan			  tv);
23818334Speter    if (clnt_stat != RPC_SUCCESS) {
23918334Speter      plog(XLOG_ERROR, "mountd rpc failed: %s", clnt_sperrno(clnt_stat));
24018334Speter      return EIO;
24118334Speter    }
242169689Skan    /* Check the status of the filehandle */
24350397Sobrien    if ((errno = fhp->v3.fhs_status)) {
244169689Skan#ifdef DEBUG
24550397Sobrien      dlog("fhandle fetch for mount version 3 failed: %m");
246169689Skan#endif /* DEBUG */
247169689Skan      return errno;
248169689Skan    }
249169689Skan  } else {			/* not NFS_VERSION3 mount */
250169689Skan#endif /* HAVE_FS_NFS3 */
251169689Skan    clnt_stat = clnt_call(client,
252169689Skan			  MOUNTPROC_MNT,
253169689Skan			  (XDRPROC_T_TYPE) xdr_dirpath,
254169689Skan			  (SVC_IN_ARG_TYPE) &dir,
255169689Skan			  (XDRPROC_T_TYPE) xdr_fhstatus,
25618334Speter			  (SVC_IN_ARG_TYPE) &fhp->v2,
25718334Speter			  tv);
25818334Speter    if (clnt_stat != RPC_SUCCESS) {
25918334Speter      char *msg = clnt_sperrno(clnt_stat);
260169689Skan      plog(XLOG_ERROR, "mountd rpc failed: %s", msg);
261169689Skan      return EIO;
262169689Skan    }
26318334Speter    /* Check status of filehandle */
26418334Speter    if (fhp->v2.fhs_status) {
26518334Speter      errno = fhp->v2.fhs_status;
26618334Speter#ifdef DEBUG
26718334Speter      dlog("fhandle fetch for mount version 1 failed: %m");
26818334Speter#endif /* DEBUG */
269117395Skan      return errno;
270169689Skan    }
271169689Skan#ifdef HAVE_FS_NFS3
272169689Skan  } /* end of "if (nfs_version == NFS_VERSION3)" statement */
273169689Skan#endif /* HAVE_FS_NFS3 */
274169689Skan
275169689Skan  /* all is well */
276169689Skan  return 0;
277169689Skan}
278169689Skan
279169689Skan
280169689Skan/*
281169689Skan * Scan mount table to see if something already mounted
282169689Skan */
283169689Skanstatic int
284169689Skanalready_mounted(mntlist *mlist, char *dir)
285169689Skan{
286169689Skan  mntlist *ml;
287169689Skan
288169689Skan  for (ml = mlist; ml; ml = ml->mnext)
289169689Skan    if (STREQ(ml->mnt->mnt_dir, dir))
290169689Skan      return 1;
291169689Skan  return 0;
292169689Skan}
293169689Skan
294169689Skan
295169689Skan/*
296169689Skan * Mount the export tree from a host
297169689Skan */
298169689Skanstatic int
299169689Skanamfs_host_fmount(mntfs *mf)
300169689Skan{
301169689Skan  struct timeval tv2;
302169689Skan  CLIENT *client;
303169689Skan  enum clnt_stat clnt_stat;
304169689Skan  int n_export;
305169689Skan  int j, k;
306169689Skan  exports exlist = 0, ex;
307169689Skan  exports *ep = 0;
308169689Skan  am_nfs_handle_t *fp = 0;
309169689Skan  char *host;
310169689Skan  int error = 0;
311169689Skan  struct sockaddr_in sin;
312169689Skan  int sock = RPC_ANYSOCK;
313169689Skan  int ok = FALSE;
314169689Skan  mntlist *mlist;
315169689Skan  char fs_name[MAXPATHLEN], *rfs_dir;
316169689Skan  char mntpt[MAXPATHLEN];
317169689Skan  struct timeval tv;
318169689Skan  u_long mnt_version;
319169689Skan
320169689Skan  /*
321169689Skan   * Read the mount list
322169689Skan   */
323169689Skan  mlist = read_mtab(mf->mf_mount, mnttab_file_name);
324169689Skan
325169689Skan#ifdef MOUNT_TABLE_ON_FILE
326169689Skan  /*
327169689Skan   * Unlock the mount list
328169689Skan   */
329169689Skan  unlock_mntlist();
330169689Skan#endif /* MOUNT_TABLE_ON_FILE */
331169689Skan
332169689Skan  /*
333169689Skan   * Take a copy of the server hostname, address, and nfs version
334169689Skan   * to mount version conversion.
335169689Skan   */
336169689Skan  host = mf->mf_server->fs_host;
337169689Skan  sin = *mf->mf_server->fs_ip;
338169689Skan  plog(XLOG_INFO, "amfs_host_fmount: NFS version %d", mf->mf_server->fs_version);
339169689Skan#ifdef HAVE_FS_NFS3
340169689Skan  if (mf->mf_server->fs_version == NFS_VERSION3)
341169689Skan    mnt_version = MOUNTVERS3;
342169689Skan  else
343169689Skan#endif /* HAVE_FS_NFS3 */
344169689Skan    mnt_version = MOUNTVERS;
345169689Skan
346169689Skan  /*
347169689Skan   * The original 10 second per try timeout is WAY too large, especially
348169689Skan   * if we're only waiting 10 or 20 seconds max for the response.
349169689Skan   * That would mean we'd try only once in 10 seconds, and we could
350169689Skan   * lose the transmitt or receive packet, and never try again.
351169689Skan   * A 2-second per try timeout here is much more reasonable.
352169689Skan   * 09/28/92 Mike Mitchell, mcm@unx.sas.com
353169689Skan   */
354169689Skan  tv.tv_sec = 2;
355169689Skan  tv.tv_usec = 0;
356169689Skan
357169689Skan  /*
358169689Skan   * Create a client attached to mountd
359117395Skan   */
360  client = get_mount_client(host, &sin, &tv, &sock, mnt_version);
361  if (client == NULL) {
362#ifdef HAVE_CLNT_SPCREATEERROR
363    plog(XLOG_ERROR, "get_mount_client failed for %s: %s",
364	 host, clnt_spcreateerror(""));
365#else /* not HAVE_CLNT_SPCREATEERROR */
366    plog(XLOG_ERROR, "get_mount_client failed for %s", host);
367#endif /* not HAVE_CLNT_SPCREATEERROR */
368    error = EIO;
369    goto out;
370  }
371  if (!nfs_auth) {
372    error = make_nfs_auth();
373    if (error)
374      goto out;
375  }
376  client->cl_auth = nfs_auth;
377
378#ifdef DEBUG
379  dlog("Fetching export list from %s", host);
380#endif /* DEBUG */
381
382  /*
383   * Fetch the export list
384   */
385  tv2.tv_sec = 10;
386  tv2.tv_usec = 0;
387  clnt_stat = clnt_call(client,
388			MOUNTPROC_EXPORT,
389			(XDRPROC_T_TYPE) xdr_void,
390			0,
391			(XDRPROC_T_TYPE) xdr_exports,
392			(SVC_IN_ARG_TYPE) & exlist,
393			tv2);
394  if (clnt_stat != RPC_SUCCESS) {
395    char *msg = clnt_sperrno(clnt_stat);
396    plog(XLOG_ERROR, "host_fmount rpc failed: %s", msg);
397    /* clnt_perror(client, "rpc"); */
398    error = EIO;
399    goto out;
400  }
401
402  /*
403   * Figure out how many exports were returned
404   */
405  for (n_export = 0, ex = exlist; ex; ex = ex->ex_next) {
406    /* printf("export %s\n", ex->ex_dir); */
407    n_export++;
408  }
409
410  /*
411   * Allocate an array of pointers into the list
412   * so that they can be sorted.  If the filesystem
413   * is already mounted then ignore it.
414   */
415  ep = (exports *) xmalloc(n_export * sizeof(exports));
416  for (j = 0, ex = exlist; ex; ex = ex->ex_next) {
417    make_mntpt(mntpt, ex, mf);
418    if (!already_mounted(mlist, mntpt))
419      ep[j++] = ex;
420  }
421  n_export = j;
422
423  /*
424   * Sort into order.
425   * This way the mounts are done in order down the tree,
426   * instead of any random order returned by the mount
427   * daemon (the protocol doesn't specify...).
428   */
429  qsort(ep, n_export, sizeof(exports), sortfun);
430
431  /*
432   * Allocate an array of filehandles
433   */
434  fp = (am_nfs_handle_t *) xmalloc(n_export * sizeof(am_nfs_handle_t));
435
436  /*
437   * Try to obtain filehandles for each directory.
438   * If a fetch fails then just zero out the array
439   * reference but discard the error.
440   */
441  for (j = k = 0; j < n_export; j++) {
442    /* Check and avoid a duplicated export entry */
443    if (j > k && ep[k] && STREQ(ep[j]->ex_dir, ep[k]->ex_dir)) {
444#ifdef DEBUG
445      dlog("avoiding dup fhandle requested for %s", ep[j]->ex_dir);
446#endif /* DEBUG */
447      ep[j] = 0;
448    } else {
449      k = j;
450      error = fetch_fhandle(client, ep[j]->ex_dir, &fp[j],
451			    mf->mf_server->fs_version);
452      if (error)
453	ep[j] = 0;
454    }
455  }
456
457  /*
458   * Mount each filesystem for which we have a filehandle.
459   * If any of the mounts succeed then mark "ok" and return
460   * error code 0 at the end.  If they all fail then return
461   * the last error code.
462   */
463  strncpy(fs_name, mf->mf_info, sizeof(fs_name));
464  if ((rfs_dir = strchr(fs_name, ':')) == (char *) 0) {
465    plog(XLOG_FATAL, "amfs_host_fmount: mf_info has no colon");
466    error = EINVAL;
467    goto out;
468  }
469  ++rfs_dir;
470  for (j = 0; j < n_export; j++) {
471    ex = ep[j];
472    if (ex) {
473      strcpy(rfs_dir, ex->ex_dir);
474      make_mntpt(mntpt, ex, mf);
475      if (do_mount(&fp[j], mntpt, fs_name, mf->mf_mopts, mf) == 0)
476	ok = TRUE;
477    }
478  }
479
480  /*
481   * Clean up and exit
482   */
483out:
484  discard_mntlist(mlist);
485  if (ep)
486    XFREE(ep);
487  if (fp)
488    XFREE(fp);
489  if (sock != RPC_ANYSOCK)
490    (void) amu_close(sock);
491  if (client)
492    clnt_destroy(client);
493  if (exlist)
494    xdr_pri_free((XDRPROC_T_TYPE) xdr_exports, (caddr_t) &exlist);
495  if (ok)
496    return 0;
497  return error;
498}
499
500
501/*
502 * Return true if pref is a directory prefix of dir.
503 *
504 * XXX TODO:
505 * Does not work if pref is "/".
506 */
507static int
508directory_prefix(char *pref, char *dir)
509{
510  int len = strlen(pref);
511
512  if (!NSTREQ(pref, dir, len))
513    return FALSE;
514  if (dir[len] == '/' || dir[len] == '\0')
515    return TRUE;
516  return FALSE;
517}
518
519
520/*
521 * Unmount a mount tree
522 */
523static int
524amfs_host_fumount(mntfs *mf)
525{
526  mntlist *ml, *mprev;
527  int xerror = 0;
528
529  /*
530   * Read the mount list
531   */
532  mntlist *mlist = read_mtab(mf->mf_mount, mnttab_file_name);
533
534#ifdef MOUNT_TABLE_ON_FILE
535  /*
536   * Unlock the mount list
537   */
538  unlock_mntlist();
539#endif /* MOUNT_TABLE_ON_FILE */
540
541  /*
542   * Reverse list...
543   */
544  ml = mlist;
545  mprev = 0;
546  while (ml) {
547    mntlist *ml2 = ml->mnext;
548    ml->mnext = mprev;
549    mprev = ml;
550    ml = ml2;
551  }
552  mlist = mprev;
553
554  /*
555   * Unmount all filesystems...
556   */
557  for (ml = mlist; ml && !xerror; ml = ml->mnext) {
558    char *dir = ml->mnt->mnt_dir;
559    if (directory_prefix(mf->mf_mount, dir)) {
560      int error;
561#ifdef DEBUG
562      dlog("amfs_host: unmounts %s", dir);
563#endif /* DEBUG */
564      /*
565       * Unmount "dir"
566       */
567      error = UMOUNT_FS(dir, mnttab_file_name);
568      /*
569       * Keep track of errors
570       */
571      if (error) {
572	if (!xerror)
573	  xerror = error;
574	if (error != EBUSY) {
575	  errno = error;
576	  plog(XLOG_ERROR, "Tree unmount of %s failed: %m", ml->mnt->mnt_dir);
577	}
578      } else {
579	(void) rmdirs(dir);
580      }
581    }
582  }
583
584  /*
585   * Throw away mount list
586   */
587  discard_mntlist(mlist);
588
589  /*
590   * Try to remount, except when we are shutting down.
591   */
592  if (xerror && amd_state != Finishing) {
593    xerror = amfs_host_fmount(mf);
594    if (!xerror) {
595      /*
596       * Don't log this - it's usually too verbose
597       plog(XLOG_INFO, "Remounted host %s", mf->mf_info);
598       */
599      xerror = EBUSY;
600    }
601  }
602  return xerror;
603}
604
605
606/*
607 * Tell mountd we're done.
608 * This is not quite right, because we may still
609 * have other filesystems mounted, but the existing
610 * mountd protocol is badly broken anyway.
611 */
612static void
613amfs_host_umounted(am_node *mp)
614{
615  mntfs *mf = mp->am_mnt;
616  char *host;
617  CLIENT *client;
618  enum clnt_stat clnt_stat;
619  struct sockaddr_in sin;
620  int sock = RPC_ANYSOCK;
621  struct timeval tv;
622  u_long mnt_version;
623
624  if (mf->mf_error || mf->mf_refc > 1 || !mf->mf_server)
625    return;
626
627  /*
628   * Take a copy of the server hostname, address, and NFS version
629   * to mount version conversion.
630   */
631  host = mf->mf_server->fs_host;
632  sin = *mf->mf_server->fs_ip;
633  plog(XLOG_INFO, "amfs_host_umounted: NFS version %d", mf->mf_server->fs_version);
634#ifdef HAVE_FS_NFS3
635  if (mf->mf_server->fs_version == NFS_VERSION3)
636    mnt_version = MOUNTVERS3;
637  else
638#endif /* HAVE_FS_NFS3 */
639    mnt_version = MOUNTVERS;
640
641  /*
642   * Create a client attached to mountd
643   */
644  tv.tv_sec = 10;
645  tv.tv_usec = 0;
646  client = get_mount_client(host, &sin, &tv, &sock, mnt_version);
647  if (client == NULL) {
648#ifdef HAVE_CLNT_SPCREATEERROR
649    plog(XLOG_ERROR, "get_mount_client failed for %s: %s",
650	 host, clnt_spcreateerror(""));
651#else /* not HAVE_CLNT_SPCREATEERROR */
652    plog(XLOG_ERROR, "get_mount_client failed for %s", host);
653#endif /* not HAVE_CLNT_SPCREATEERROR */
654    goto out;
655  }
656
657  if (!nfs_auth) {
658    if (make_nfs_auth())
659      goto out;
660  }
661  client->cl_auth = nfs_auth;
662
663#ifdef DEBUG
664  dlog("Unmounting all from %s", host);
665#endif /* DEBUG */
666
667  clnt_stat = clnt_call(client,
668			MOUNTPROC_UMNTALL,
669			(XDRPROC_T_TYPE) xdr_void,
670			0,
671			(XDRPROC_T_TYPE) xdr_void,
672			0,
673			tv);
674  if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_SYSTEMERROR) {
675    /* RPC_SYSTEMERROR seems to be returned for no good reason ... */
676    char *msg = clnt_sperrno(clnt_stat);
677    plog(XLOG_ERROR, "unmount all from %s rpc failed: %s", host, msg, clnt_stat);
678    goto out;
679  }
680
681out:
682  if (sock != RPC_ANYSOCK)
683    (void) amu_close(sock);
684  if (client)
685    clnt_destroy(client);
686}
687