home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume21 / amd / part12 / afs_ops.c
C/C++ Source or Header  |  1990-04-10  |  34KB  |  1,543 lines

  1. /*
  2.  * $Id: afs_ops.c,v 5.1.1.3 90/01/11 16:58:01 jsp Exp Locker: jsp $
  3.  *
  4.  * Copyright (c) 1990 Jan-Simon Pendry
  5.  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
  6.  * Copyright (c) 1990 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * This code is derived from software contributed to Berkeley by
  10.  * Jan-Simon Pendry at Imperial College, London.
  11.  *
  12.  * Redistribution and use in source and binary forms are permitted
  13.  * provided that the above copyright notice and this paragraph are
  14.  * duplicated in all such forms and that any documentation,
  15.  * advertising materials, and other materials related to such
  16.  * distribution and use acknowledge that the software was developed
  17.  * by Imperial College of Science, Technology and Medicine, London, UK.
  18.  * The names of the College and University may not be used to endorse
  19.  * or promote products derived from this software without specific
  20.  * prior written permission.
  21.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  22.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  23.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  24.  *
  25.  *    %W% (Berkeley) %G%
  26.  */
  27.  
  28. #include "am.h"
  29.  
  30. #define NFS
  31. #define NFSCLIENT
  32.  
  33. #include <sys/stat.h>
  34. #ifdef NFS_3
  35. typedef nfs_fh fhandle_t;
  36. #endif
  37. #ifdef NFS_HDR
  38. #include NFS_HDR
  39. #endif
  40. #include <sys/mount.h>
  41. #include "mount.h"
  42.  
  43. /*
  44.  * Automount file system
  45.  */
  46.  
  47. /*
  48.  * Interval between forced retries of a mount.
  49.  */
  50. #define RETRY_INTERVAL    2
  51.  
  52. /*
  53.  * AFS needs nothing in particular.
  54.  */
  55. static int afs_match(fo)
  56. am_opts *fo;
  57. {
  58.     char *p = fo->opt_rfs;
  59.     if (!fo->opt_rfs) {
  60.         plog(XLOG_USER, "auto: no mount point named (rfs:=)");
  61.         return 0;
  62.     }
  63.     if (!fo->opt_fs) {
  64.         plog(XLOG_USER, "auto: no map named (fs:=)");
  65.         return 0;
  66.     }
  67.     /*
  68.      * Swap round fs:= and rfs:= options
  69.      * ... historical (jsp)
  70.      */
  71.     fo->opt_rfs = fo->opt_fs;
  72.     fo->opt_fs = p;
  73.     /*
  74.      * fs_mtab turns out to be the name of the mount map
  75.      */
  76.     fo->fs_mtab = strealloc(fo->fs_mtab, fo->opt_rfs ? fo->opt_rfs : ".");
  77.     return 1;
  78. }
  79.  
  80. static int afs_init(mf)
  81. mntfs *mf;
  82. {
  83.     /*
  84.      * Fill in attribute fields
  85.      */
  86.     mf->mf_fattr.type = NFDIR;
  87.     mf->mf_fattr.mode = NFSMODE_DIR | 0555;
  88.     mf->mf_fattr.nlink = 2;
  89.     mf->mf_fattr.size = 512;
  90.  
  91.     return 0;
  92. }
  93.  
  94. /*
  95.  * Mount the an automounter directory.
  96.  * The automounter is connected into the system
  97.  * as a user-level NFS server.  mount_afs constructs
  98.  * the necessary NFS parameters to be given to the
  99.  * kernel so that it will talk back to us.
  100.  */
  101. static int mount_afs(dir, fs_name, opts)
  102. char *dir;
  103. char *fs_name;
  104. char *opts;
  105. {
  106.     struct nfs_args nfs_args;
  107.     struct mntent mnt;
  108.     int retry;
  109.     struct sockaddr_in sin;
  110.     unsigned short port;
  111.     int flags;
  112.     extern nfs_fh *root_fh();
  113.     char fs_hostname[MAXHOSTNAMELEN+MAXPATHLEN+1];
  114.  
  115.     MTYPE_TYPE type = MOUNT_TYPE_NFS;
  116.  
  117.     bzero((voidp) &nfs_args, sizeof(nfs_args));    /* Paranoid */
  118.  
  119.     mnt.mnt_dir = dir;
  120.     mnt.mnt_fsname = fs_name;
  121.     mnt.mnt_type = MNTTYPE_AUTO;
  122.     mnt.mnt_opts = opts;
  123.     mnt.mnt_freq = 0;
  124.     mnt.mnt_passno = 0;
  125.  
  126.     retry = hasmntval(&mnt, "retry");
  127.     if (retry <= 0)
  128.         retry = 2;    /* XXX */
  129.  
  130.     /*
  131.      * get fhandle of remote path for automount point
  132.      */
  133.     nfs_args.fh = (NFS_FH_TYPE) root_fh(fs_name);
  134.  
  135.     if (!nfs_args.fh) {
  136.         plog(XLOG_FATAL, "Can't find root file handle for %s", fs_name);
  137.         return EINVAL;
  138.     }
  139.  
  140.     /*
  141.      * Create sockaddr to point to the local machine.  127.0.0.1
  142.      * is not used since that will not work in HP-UX clusters and
  143.      * this is no more expensive.
  144.      */
  145.     bzero((voidp) &sin, sizeof(sin));
  146.     sin.sin_family = AF_INET;
  147.     sin.sin_addr = myipaddr;
  148.     if (port = hasmntval(&mnt, "port")) {
  149.         sin.sin_port = htons(port);
  150.     } else {
  151.         plog(XLOG_ERROR, "no port number specified for %s", fs_name);
  152.         return EINVAL;
  153.     }
  154.  
  155.     /*
  156.      * set mount args
  157.      */
  158.     nfs_args.addr = &sin;
  159.  
  160.     /*
  161.      * Make a ``hostname'' string for the kernel
  162.      */
  163. #ifdef SHORT_MOUNT_NAME
  164.     sprintf(fs_hostname, "amd:%d", mypid);
  165. #else
  166.     sprintf(fs_hostname, "pid%d@%s:%s", mypid, hostname, dir);
  167. #endif
  168.     nfs_args.hostname = fs_hostname;
  169.     nfs_args.flags |= NFSMNT_HOSTNAME;
  170. #ifdef HOSTNAMESZ
  171.     /*
  172.      * Most kernels have a name length restriction.
  173.      */
  174.     if (strlen(fs_hostname) >= HOSTNAMESZ)
  175.         strcpy(fs_hostname + HOSTNAMESZ - 3, "..");
  176. #endif
  177.  
  178.     /*
  179.      * Parse a subset of the standard nfs options.  The
  180.      * others are probably irrelevant for this application
  181.      */
  182.     if (nfs_args.timeo = hasmntval(&mnt, "timeo"))
  183.         nfs_args.flags |= NFSMNT_TIMEO;
  184.  
  185.     if (nfs_args.retrans = hasmntval(&mnt, "retrans"))
  186.         nfs_args.flags |= NFSMNT_RETRANS;
  187.  
  188. #if defined(NFSMNT_ACREGMIN) && defined(NFSMNT_ACREGMAX)
  189.     /*
  190.      * Don't cache attributes - they are changing under
  191.      * the kernel's feet...
  192.      */
  193.     nfs_args.acregmin = nfs_args.acregmax = 1;
  194.     nfs_args.flags |= NFSMNT_ACREGMIN|NFSMNT_ACREGMAX;
  195. #endif
  196.     /*
  197.      * These two are constructed internally by the calling routine
  198.      */
  199.     if (hasmntopt(&mnt, MNTOPT_SOFT) != NULL)
  200.         nfs_args.flags |= NFSMNT_SOFT;
  201.  
  202. #ifdef MNTOPT_INTR
  203.     if (hasmntopt(&mnt, MNTOPT_INTR) != NULL)
  204.         nfs_args.flags |= NFSMNT_INT;
  205. #endif
  206.  
  207.     flags = compute_mount_flags(&mnt);
  208. #ifdef ULTRIX_HACK
  209.     nfs_args.gfs_flags = flags;
  210.     flags &= M_RDONLY;
  211.     if (flags & M_RDONLY)
  212.         nfs_args.flags |= NFSMNT_RONLY;
  213. #endif
  214.     return mount_fs(&mnt, flags, (caddr_t) &nfs_args, retry, type);
  215. }
  216.  
  217. static int afs_mount(mp)
  218. am_node *mp;
  219. {
  220.     mntfs *mf = mp->am_mnt;
  221.  
  222.     /*
  223.      * There are two cases to consider...
  224.      */
  225.     if (mp->am_parent && mp->am_parent->am_parent) {
  226.         /*
  227.          * If this am_node has a parent which is not the root node, in
  228.          * which case we are supplying a pseudo-directory, in which
  229.          * case no action is needed.  Pseudo-directories are used to
  230.          * provide some structure to the automounted directories instead
  231.          * of putting them all in the top-level automount directory.
  232.          */
  233.         mp->am_parent->am_mnt->mf_fattr.nlink++;
  234.         /*
  235.          * Info field of . means use parent's info field.
  236.          */
  237.         if (mf->mf_info[0] == '.' && mf->mf_info[1] == '\0')
  238.             mf->mf_info = strealloc(mf->mf_info, mp->am_parent->am_mnt->mf_info);
  239.         /*
  240.          * Compute prefix:
  241.          *
  242.          * If there is an option prefix then use that else
  243.          * If the parent had a prefix then use that with name
  244.          *    of this node appended else
  245.          * Use the name of this node.
  246.          *
  247.          * That means if you want no prefix you must say so
  248.          * in the map.
  249.          */
  250.         if (mf->mf_fo->opt_pref) {
  251.             /*
  252.              * the prefix specified as an option
  253.              */
  254.             mp->am_pref = strdup(mf->mf_fo->opt_pref);
  255.         } else {
  256.             /*
  257.              * else the parent's prefix
  258.              * followed by the name
  259.              * followed by /
  260.              */
  261.             char *ppref = mp->am_parent->am_pref;
  262.             if (ppref == 0)
  263.                 ppref = "";
  264.             mp->am_pref = str3cat((char *) 0, ppref, mp->am_name, "/");
  265.         }
  266.     } else {
  267.         /*
  268.          * Otherwise, we are mounting the automounter.  In which case
  269.          * we need to make sure the mount directory exists, construct
  270.          * the mount options and call the mount_afs routine.
  271.          */
  272.         struct stat stb;
  273.         char opts[256];
  274.         int error;
  275.  
  276.         /*
  277.          * Top-level mount - so make
  278.          * sure the mount point exists
  279.          * and is a directory.
  280.          */
  281.         error = mkdirs(mp->am_path, 0555);
  282.         if (error)
  283.             return error;
  284.         mp->am_flags |= AMF_MKPATH;
  285.  
  286.         if (stat(mp->am_path, &stb) < 0) {
  287.             return errno;
  288.         } else if ((stb.st_mode & S_IFMT) != S_IFDIR) {
  289.             plog(XLOG_WARNING, "%s is not a directory", mp->am_path);
  290.             return ENOTDIR;
  291.         }
  292.  
  293.         mf->mf_mount = strealloc(mf->mf_mount, mp->am_path);
  294.  
  295.         /*
  296.          * Construct some mount options
  297.          */
  298.         sprintf(opts,
  299. #ifdef MNTOPT_INTR
  300.             "%s,%s,%s=%d,%s=%d,%s=%d,%sdirect",
  301.             MNTOPT_INTR,
  302. #else
  303.             "%s,%s=%d,%s=%d,%s=%d,%sdirect",
  304. #endif
  305. #ifdef AUTOMOUNT_RO
  306.             MNTOPT_RO,    /* You don't really want this... */
  307. #else
  308.             "rw",
  309. #endif
  310.             "port", nfs_port,
  311.             "timeo", afs_timeo,
  312.             "retrans", afs_retrans,
  313.             mf->mf_ops == &afs_ops ? "in" : "");
  314.  
  315.         error = mount_afs(mp->am_path, mp->am_name, opts);
  316.         if (error) {
  317.             errno = error;
  318.             plog(XLOG_FATAL, "mount_afs: %m");
  319.             return error;
  320.         }
  321.         mp->am_name = pid_fsname;
  322.     }
  323.  
  324.     /*
  325.      * Build a new map cache for this node, or re-use
  326.      * an existing cache for the same map.
  327.      */
  328.     { char *cache;
  329.       if (mf->mf_fo->opt_cache)
  330.           cache = mf->mf_fo->opt_cache;
  331.       else
  332.           cache = "none";
  333.       mf->mf_private = (voidp) mapc_find(mf->mf_info, cache);
  334.       mf->mf_prfree = mapc_free;
  335.     }
  336.  
  337.     return 0;
  338. }
  339.  
  340. /*
  341.  * Unmount an automount node
  342.  */
  343. static int afs_umount(mp)
  344. am_node *mp;
  345. {
  346.     int error;
  347.  
  348.     /*
  349.      * If this is a pseudo-directory then just adjust the link count
  350.      * in the parent, otherwise call the generic unmount routine
  351.      */
  352.     if (!mp->am_parent) {
  353.         error = 0;
  354.     } else if (mp->am_parent && mp->am_parent->am_parent) {
  355.         --mp->am_parent->am_mnt->mf_fattr.nlink;
  356.         error = 0;
  357.     } else {
  358.         struct stat stb;
  359. again:
  360.         /*
  361.          * The lstat is needed if this mount is type=direct.
  362.          * When that happens, the kernel cache gets confused
  363.          * between the underlying type (dir) and the mounted
  364.          * type (link) and so needs to be re-synced before
  365.          * the unmount.  This is all because the unmount system
  366.          * call follows links and so can't actually unmount
  367.          * a link (stupid!).  It was noted that doing and ls -ld
  368.          * of the mount point to see why things were not working
  369.          * actually fixed the problem - so simulate an ls -ld here.
  370.          */
  371.         if (lstat(mp->am_path, &stb) < 0) {
  372. #ifdef DEBUG
  373.             dlog("lstat(%s): %m", mp->am_path);
  374. #endif
  375.         }
  376.         error = UMOUNT_FS(mp->am_path);
  377.         if (error == EBUSY) {
  378.             plog(XLOG_WARNING, "afs_unmount retrying %s in 1s", mp->am_path);
  379.             sleep(1);    /* XXX */
  380.             goto again;
  381.         }
  382.     }
  383.  
  384.     return error;
  385. }
  386.  
  387. /*
  388.  * Unmount an automount node
  389.  */
  390. static void afs_umounted(mp)
  391. am_node *mp;
  392. {
  393.     /*
  394.      * If this is a pseudo-directory then just adjust the link count
  395.      * in the parent, otherwise call the generic unmount routine
  396.      */
  397.     if (mp->am_parent && mp->am_parent->am_parent)
  398.         --mp->am_parent->am_mnt->mf_fattr.nlink;
  399. }
  400.  
  401. /*
  402.  * Mounting a file system may take a significant period of time.  The
  403.  * problem is that if this is done in the main process thread then
  404.  * the entire automounter could be blocked, possibly hanging lots of
  405.  * processes on the system.  Instead we use a continuation scheme to
  406.  * allow mounts to be attempted in a sub-process.  When the sub-process
  407.  * exits we pick up the exit status (by convention a UN*X error number)
  408.  * and continue in a notifier.  The notifier gets handed a data structure
  409.  * and can then determine whether the mount was successful or not.  If
  410.  * not, it updates the data structure and tries again until there are no
  411.  * more ways to try the mount, or some other permanent error occurs.
  412.  * In the mean time no RPC reply is sent, even after the mount is succesful.
  413.  * We rely on the RPC retry mechanism to resend the lookup request which
  414.  * can then be handled.
  415.  */
  416.  
  417.  
  418. struct continuation {
  419.     char **ivec;        /* Current mount info */
  420.     am_node *mp;        /* Node we are trying to mount */
  421.     char *key;        /* Map key */
  422.     char *info;        /* Info string */
  423.     char **xivec;        /* Saved strsplit vector */
  424.     char *opts;        /* Mount options */
  425.     am_opts fs_opts;    /* Filesystem options */
  426.     char *def_opts;        /* Default options */
  427.     int retry;        /* Try again? */
  428.     int tried;        /* Have we tried any yet? */
  429.     time_t start;        /* Time we started this mount */
  430.     int callout;        /* Callout identifier */
  431. };
  432.  
  433. /*
  434.  * Discard an old continuation
  435.  */
  436. static void free_continuation(cp)
  437. struct continuation *cp;
  438. {
  439.     if (cp->callout)
  440.         untimeout(cp->callout);
  441.     free((voidp) cp->key);
  442.     free((voidp) cp->xivec);
  443.     free((voidp) cp->info);
  444.     free((voidp) cp->opts);
  445.     free((voidp) cp->def_opts);
  446.     free_opts(&cp->fs_opts);
  447.     free((voidp) cp);
  448. }
  449.  
  450. static int afs_bgmount P((struct continuation*, int));
  451.  
  452. /*
  453.  * Discard the underlying mount point and replace
  454.  * with a reference to an error filesystem.
  455.  */
  456. static void assign_error_mntfs(mp)
  457. am_node *mp;
  458. {
  459.     if (mp->am_error > 0) {
  460.         /*
  461.          * Save the old error code
  462.          */
  463.         int error = mp->am_error;
  464.         /*
  465.          * Discard the old filesystem
  466.          */
  467.         free_mntfs(mp->am_mnt);
  468.         /*
  469.          * Allocate a new error reference
  470.          */
  471.         mp->am_mnt = new_mntfs();
  472.         /*
  473.          * Put back the error code
  474.          */
  475.         mp->am_mnt->mf_error = error;
  476.         mp->am_mnt->mf_flags |= MFF_ERROR;
  477.         /*
  478.          * Zero the error in the mount point
  479.          */
  480.         mp->am_error = 0;
  481.     }
  482. }
  483.  
  484. /*
  485.  * The continuation function.  This is called by
  486.  * the task notifier when a background mount attempt
  487.  * completes.
  488.  */
  489. static void afs_cont(rc, term, closure)
  490. int rc;
  491. int term;
  492. voidp closure;
  493. {
  494.     struct continuation *cp = (struct continuation *) closure;
  495.     mntfs *mf = cp->mp->am_mnt;
  496.  
  497.     /*
  498.      * Definitely not trying to mount at the moment
  499.      */
  500.     mf->mf_flags &= ~MFF_MOUNTING;
  501.     /*
  502.      * While we are mounting - try to avoid race conditions
  503.      */
  504.     new_ttl(cp->mp);
  505.  
  506.     /*
  507.      * Wakeup anything waiting for this mount
  508.      */
  509.     wakeup((voidp) mf);
  510.  
  511.     /*
  512.      * Check for termination signal or exit status...
  513.      */
  514.     if (rc || term) {
  515.         if (term) {
  516.             /*
  517.              * Not sure what to do for an error code.
  518.              */
  519.             mf->mf_error = EIO;    /* XXX ? */
  520.             mf->mf_flags |= MFF_ERROR;
  521.             plog(XLOG_ERROR, "mount for %s got signal %d", cp->mp->am_path, term);
  522.         } else {
  523.             /*
  524.              * Check for exit status...
  525.              */
  526.             mf->mf_error = rc;
  527.             mf->mf_flags |= MFF_ERROR;
  528.             errno = rc;    /* XXX */
  529.             plog(XLOG_ERROR, "%s: mount (afs_cont): %m", cp->mp->am_path);
  530.         }
  531.  
  532.         /*
  533.          * If we get here then that attempt didn't work, so
  534.          * move the info vector pointer along by one and
  535.          * call the background mount routine again
  536.          */
  537.         amd_stats.d_merr++;
  538.         cp->ivec++;
  539.         (void) afs_bgmount(cp, 0);
  540.         assign_error_mntfs(cp->mp);
  541.     } else {
  542.         /*
  543.          * The mount worked.
  544.          */
  545.         am_mounted(cp->mp);
  546.         free_continuation(cp);
  547.     }
  548.  
  549.     reschedule_timeout_mp();
  550. }
  551.  
  552. /*
  553.  * Retry a mount
  554.  */
  555. /*ARGSUSED*/
  556. static void afs_retry(rc, term, closure)
  557. int rc;
  558. int term;
  559. voidp closure;
  560. {
  561.     struct continuation *cp = (struct continuation *) closure;
  562.     int error = 0;
  563.  
  564. #ifdef DEBUG
  565.     dlog("Commencing retry for mount of %s", cp->mp->am_path);
  566. #endif
  567.  
  568.     if ((cp->start + ALLOWED_MOUNT_TIME) < clocktime()) {
  569.         /*
  570.          * The entire mount has timed out.
  571.          * Set the error code and skip past
  572.          * all the info vectors so that
  573.          * afs_bgmount will not have any more
  574.          * ways to try the mount, so causing
  575.          * an error.
  576.          */
  577.         plog(XLOG_INFO, "mount of \"%s\" has timed out", cp->mp->am_path);
  578.         error = ETIMEDOUT;
  579.         new_ttl(cp->mp);
  580.         while (*cp->ivec)
  581.             cp->ivec++;
  582.     }
  583.  
  584.     (void) afs_bgmount(cp, error);
  585.     reschedule_timeout_mp();
  586. }
  587.  
  588. /*
  589.  * Try to mount a file system.  Can be called
  590.  * directly or in a sub-process by run_task
  591.  */
  592. static int try_mount(mp)
  593. am_node *mp;
  594. {
  595.     /*
  596.      * Mount it!
  597.      */
  598.     int error;
  599.  
  600.     error = mount_node(mp);
  601. #ifdef DEBUG
  602.     if (error) {
  603.         errno = error;
  604.         dlog("afs call to mount_node failed: %m");
  605.     }
  606. #endif
  607.     return error;
  608. }
  609.  
  610. /*
  611.  * Pick a file system to try mounting and
  612.  * do that in the background if necessary
  613.  *
  614. For each location:
  615.     if it is new -defaults then
  616.         extract and process
  617.         continue;
  618.     fi
  619.     if it is a cut then
  620.         if a location has been tried then
  621.             break;
  622.         fi
  623.         continue;
  624.     fi
  625.     parse mount location
  626.     discard previous mount location if required
  627.     find matching mounted filesystem
  628.     if not applicable then
  629.         this_error = No such file or directory
  630.         continue
  631.     fi
  632.     if the filesystem failed to be mounted then
  633.         this_error = error from filesystem
  634.     elif the filesystem is mounting or unmounting then
  635.         this_error = -1
  636.     elif the fileserver is down then
  637.         this_error = -1
  638.     elif the filesystem is already mounted
  639.         this_error = 0
  640.         break
  641.     fi
  642.     if no error on this mount then
  643.         this_error = initialise mount point
  644.     fi
  645.     if no error on this mount and mount is delayed then
  646.         this_error = -1
  647.     fi
  648.     if this_error < 0 then
  649.         retry = true
  650.     fi
  651.     if no error on this mount then
  652.         make mount point if required
  653.     fi
  654.     if no error on this mount then
  655.         if mount in background then
  656.             run mount in background
  657.             return -1
  658.         else
  659.             this_error = mount in foreground
  660.         fi
  661.     fi
  662.     if an error occured on this mount then
  663.         update stats
  664.         save error in mount point
  665.     fi
  666. endfor
  667.  */
  668.  
  669. static int afs_bgmount(cp, mpe)
  670. struct continuation *cp;
  671. int mpe;
  672. {
  673.     mntfs *mf = cp->mp->am_mnt;    /* Current mntfs */
  674.     mntfs *mf_retry = 0;        /* First mntfs which needed retrying */
  675.     int this_error = -1;        /* Per-mount error */
  676.     int hard_error = -1;
  677.     int mp_error = mpe;
  678.  
  679.     /*
  680.      * Try to mount each location.
  681.      * At the end:
  682.      * hard_error == 0 indicates something was mounted.
  683.      * hard_error > 0 indicates everything failed with a hard error
  684.      * hard_error < 0 indicates nothing could be mounted now
  685.      */
  686.     for (; this_error && *cp->ivec; cp->ivec++) {
  687.         am_ops *p;
  688.         am_node *mp = cp->mp;
  689.         char *link_dir;
  690.         int dont_retry;
  691.  
  692.         if (hard_error < 0)
  693.             hard_error = this_error;
  694.  
  695.         this_error = -1;
  696.  
  697.         if (**cp->ivec == '-') {
  698.             /*
  699.              * Pick up new defaults
  700.              */
  701.             if (cp->opts && *cp->opts)
  702.                 cp->def_opts = str3cat(cp->def_opts, cp->opts, ";", *cp->ivec+1);
  703.             else
  704.                 cp->def_opts = strealloc(cp->def_opts, *cp->ivec+1);
  705. #ifdef DEBUG
  706.             dlog("Setting def_opts to \"%s\"", cp->def_opts);
  707. #endif
  708.             continue;
  709.         }
  710.  
  711.         /*
  712.          * If a mount has been attempted, and we find
  713.          * a cut then don't try any more locations.
  714.          */
  715.         if (strcmp(*cp->ivec, "/") == 0 || strcmp(*cp->ivec, "||") == 0) {
  716.             if (cp->tried) {
  717. #ifdef DEBUG
  718.                 dlog("Cut: not trying any more locations for %s",
  719.                     mp->am_path);
  720. #endif
  721.                 break;
  722.             }
  723.             continue;
  724.         }
  725.  
  726. #ifdef SUNOS4_COMPAT
  727.         /*
  728.          * By default, you only get this bit on SunOS4.
  729.          * If you want this anyway, then define SUNOS4_COMPAT
  730.          * in the relevant "os-blah.h" file.
  731.          *
  732.          * We make the observation that if the local key line contains
  733.          * no '=' signs then either it is sick, or it is a SunOS4-style
  734.          * "host:fs[:link]" line.  In the latter case the am_opts field
  735.          * is also assumed to be in old-style, so you can't mix & match.
  736.          * You can use ${} expansions for the fs and link bits though...
  737.          *
  738.          * Actually, this doesn't really cover all the possibilities for
  739.          * the latest SunOS automounter and it is debatable whether there
  740.          * is any point bothering.
  741.          */
  742.         if (strchr(*cp->ivec, '=') == 0)
  743.             p = sunos4_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info);
  744.         else
  745. #endif /* SUNOS4_COMPAT */
  746.             p = ops_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info);
  747.  
  748.         /*
  749.          * Find a mounted filesystem for this node.
  750.          */
  751.         mp->am_mnt = mf = realloc_mntfs(mf, p, &cp->fs_opts, cp->fs_opts.opt_fs,
  752.                         cp->fs_opts.fs_mtab, cp->opts);
  753.  
  754.         p = mf->mf_ops;
  755. #ifdef DEBUG
  756.         dlog("Got a hit with %s", p->fs_type);
  757. #endif
  758.         /*
  759.          * Note whether this is a real mount attempt
  760.          */
  761.         if (p == &efs_ops) {
  762.             plog(XLOG_MAP, "Map entry %s for %s failed to match", *cp->ivec, mp->am_path);
  763.             if (this_error <= 0)
  764.                 this_error = ENOENT;
  765.             continue;
  766.         } else {
  767.             if (cp->fs_opts.fs_mtab) {
  768.                 plog(XLOG_MAP, "Trying mount of %s on %s fstype %s",
  769.                     cp->fs_opts.fs_mtab, mp->am_path, p->fs_type);
  770.             }
  771.             cp->tried = TRUE;
  772.         }
  773.  
  774.         this_error = 0;
  775.         dont_retry = FALSE;
  776.  
  777.         if (mp->am_link) {
  778.             free(mp->am_link);
  779.             mp->am_link = 0;
  780.         }
  781.  
  782.         link_dir = mf->mf_fo->opt_sublink;
  783.  
  784.         if (link_dir && *link_dir) {
  785.             if (*link_dir == '/') {
  786.                 mp->am_link = strdup(link_dir);
  787.             } else {
  788.                 mp->am_link = str3cat((char *) 0,
  789.                     mf->mf_fo->opt_fs, "/", link_dir);
  790.             }
  791.         }
  792.  
  793.         if (mf->mf_error > 0) {
  794.             this_error = mf->mf_error;
  795.         } else if (mf->mf_flags & (MFF_MOUNTING|MFF_UNMOUNTING)) {
  796.             /*
  797.              * Still mounting - retry later
  798.              */
  799. #ifdef DEBUG
  800.             dlog("Duplicate pending fstype %s mount", p->fs_type);
  801. #endif
  802.             this_error = -1;
  803.         } else if (FSRV_ISDOWN(mf->mf_server)) {
  804.             /*
  805.              * Would just mount from the same place
  806.              * as a hung mount - so give up
  807.              */
  808. #ifdef DEBUG
  809.             dlog("%s is already hung - giving up", mf->mf_mount);
  810. #endif
  811.             mp_error = EWOULDBLOCK;
  812.             dont_retry = TRUE;
  813.             this_error = -1;
  814.         } else if (mf->mf_flags & MFF_MOUNTED) {
  815. #ifdef DEBUG
  816.             dlog("duplicate mount of \"%s\" ...", mf->mf_info);
  817. #endif
  818.             this_error = 0;
  819.             break;
  820.         }
  821.  
  822.         /*
  823.          * Will usually need to play around with the mount nodes
  824.          * file attribute structure.  This must be done here.
  825.          */
  826.         if (!this_error) {
  827.             /*
  828.              * Fill in attribute fields
  829.              */
  830.             mf->mf_fattr.type = NFLNK;
  831.             mf->mf_fattr.mode = NFSMODE_LNK | 0777;
  832.             mf->mf_fattr.nlink = 1;
  833.             mf->mf_fattr.size = MAXPATHLEN / 4;    /* Conservative */
  834.             mf->mf_fattr.fileid = mp->am_gen;
  835.  
  836.             if (p->fs_init)
  837.                 this_error = (*p->fs_init)(mf);
  838.         }
  839.  
  840.         if (!this_error && mf->mf_fo->opt_delay) {
  841.             /*
  842.              * If there is a delay timer on the mount
  843.              * then don't try to mount if the timer
  844.              * has not expired.
  845.              */
  846.             int i = atoi(mf->mf_fo->opt_delay);
  847.             if (i > 0 && (cp->start + i) < clocktime()) {
  848. #ifdef DEBUG
  849.                 dlog("Mount of %s delayed by %ds", mf->mf_mount, i);
  850. #endif
  851.                 this_error = -1;
  852.             }
  853.         }
  854.  
  855.         if (this_error < 0 && !dont_retry) {
  856.             if (!mf_retry)
  857.                 mf_retry = dup_mntfs(mf);
  858.             cp->retry = TRUE;
  859.         }
  860.  
  861.         if (!this_error) {
  862.             /*
  863.              * If the directory is not yet made and
  864.              * it needs to be made, then make it!
  865.              */
  866.              if (!(mf->mf_flags & MFF_MKMNT) &&
  867.                      p->fs_flags & FS_MKMNT) {
  868.                 this_error = mkdirs(mf->mf_mount, 0555);
  869.                 if (!this_error)
  870.                     mf->mf_flags |= MFF_MKMNT;
  871.             }
  872.         }
  873.  
  874.         if (!this_error)
  875.         if (p->fs_flags & FS_MBACKGROUND) {
  876.             mf->mf_flags |= MFF_MOUNTING;    /*XXX*/
  877. #ifdef DEBUG
  878.             dlog("backgrounding mount of \"%s\"", mf->mf_info);
  879. #endif
  880.             if (cp->callout) {
  881.                 untimeout(cp->callout);
  882.                 cp->callout = 0;
  883.             }
  884.             run_task(try_mount, (voidp) mp, afs_cont, (voidp) cp);
  885.             if (mf_retry) free_mntfs(mf_retry);
  886.             return -1;
  887.         } else {
  888. #ifdef DEBUG
  889.             dlog("foreground mount of \"%s\" ...", mf->mf_info);
  890. #endif
  891.             this_error = try_mount(mp);
  892.         }
  893.  
  894.         if (this_error >= 0) {
  895.             if (this_error > 0) {
  896.                 amd_stats.d_merr++;
  897.                 if (mf != mf_retry) {
  898.                     mf->mf_error = this_error;
  899.                     mf->mf_flags |= MFF_ERROR;
  900.                 }
  901.             }
  902.             /*
  903.              * Wakeup anything waiting for this mount
  904.              */
  905.             wakeup((voidp) mf);
  906.         }
  907.     }
  908.  
  909.     if (this_error && cp->retry) {
  910.         free_mntfs(mf);
  911.         mf = cp->mp->am_mnt = mf_retry;
  912.         /*
  913.          * Not retrying again (so far)
  914.          */
  915.         cp->retry = FALSE;
  916.         cp->tried = FALSE;
  917.         /*
  918.          * Start at the beginning.
  919.          * Rewind the location vector and
  920.          * reset the default options.
  921.          */
  922.         cp->ivec = cp->xivec;
  923.         cp->def_opts = strealloc(cp->def_opts, cp->opts);
  924.         /*
  925.          * Arrange that afs_bgmount is called
  926.          * after anything else happens.
  927.          */
  928. #ifdef DEBUG
  929.         dlog("Arranging to retry mount of %s", cp->mp->am_path);
  930. #endif
  931.         sched_task(afs_retry, (voidp) cp, (voidp) mf);
  932.         if (cp->callout)
  933.             untimeout(cp->callout);
  934.         cp->callout = timeout(RETRY_INTERVAL, wakeup, (voidp) mf);
  935.  
  936.         cp->mp->am_ttl = clocktime() + RETRY_INTERVAL;
  937.  
  938.         /*
  939.          * Not done yet - so don't return anything
  940.          */
  941.         return -1;
  942.     }
  943.  
  944.     /*
  945.      * Discard handle on duff filesystem.
  946.      * This should never happen since it
  947.      * should be caught by the case above.
  948.      */
  949.     if (mf_retry) {
  950.         plog(XLOG_ERROR, "discarding a retry mntfs for %s", mf_retry->mf_mount);
  951.         free_mntfs(mf_retry);
  952.     }
  953.  
  954.     if (hard_error < 0 || !this_error)
  955.         hard_error = this_error;
  956.  
  957.     /*
  958.      * If we get here, then either the mount succeeded or
  959.      * there is no more mount information available.
  960.      */
  961.     if (hard_error < 0 && mp_error)
  962.         hard_error = cp->mp->am_error = mp_error;
  963.     if (hard_error > 0) {
  964.         /*
  965.          * Set a small(ish) timeout on an error node if
  966.          * the error was not a time out.
  967.          */
  968.         switch (hard_error) {
  969.         case ETIMEDOUT:
  970.         case EWOULDBLOCK:
  971.             cp->mp->am_timeo = 5;
  972.             break;
  973.         default:
  974.             cp->mp->am_timeo = 17;
  975.             break;
  976.         }
  977.         cp->mp->am_timeo_w = 0;
  978.     }
  979.  
  980.     /*
  981.      * Make sure that the error value in the mntfs has a
  982.      * reasonable value.
  983.      */
  984.     if (mf->mf_error < 0) {
  985.         mf->mf_error = hard_error;
  986.         if (hard_error)
  987.             mf->mf_flags |= MFF_ERROR;
  988.     }
  989.  
  990.     /*
  991.      * In any case we don't need the continuation any more
  992.      */
  993.     free_continuation(cp);
  994.  
  995.     return hard_error;
  996. }
  997.  
  998. /*
  999.  * Automount interface to RPC lookup routine
  1000.  */
  1001. static am_node *afs_lookuppn(mp, fname, error_return, op)
  1002. am_node *mp;
  1003. char *fname;
  1004. int *error_return;
  1005. int op;
  1006. {
  1007. #define ereturn(x) { *error_return = x; return 0; }
  1008.  
  1009.     /*
  1010.      * Find the corresponding entry and return
  1011.      * the file handle for it.
  1012.      */
  1013.     am_node *ap, *new_mp, *ap_hung;
  1014.     char *info;            /* Mount info - where to get the file system */
  1015.     char **ivec, **xivec;        /* Split version of info */
  1016.     char *opts;            /* Mount options */
  1017.     int error = 0;            /* Error so far */
  1018.     char path_name[MAXPATHLEN];    /* General path name buffer */
  1019.     char *pfname;            /* Path for database lookup */
  1020.     struct continuation *cp;    /* Continuation structure if we need to mount */
  1021.     int in_progress = 0;        /* # of (un)mount in progress */
  1022.     char *dflts;
  1023.     mntfs *mf;
  1024.  
  1025. #ifdef DEBUG
  1026.     dlog("in afs_lookuppn");
  1027. #endif
  1028.  
  1029.     /*
  1030.      * If the server is shutting down
  1031.      * then don't return information
  1032.      * about the mount point.
  1033.      */
  1034.     if (amd_state == Finishing) {
  1035. #ifdef DEBUG
  1036.         dlog("%s/%s mount ignored - going down",
  1037.             mp->am_path, fname);
  1038. #endif
  1039.         ereturn(ENOENT);
  1040.     }
  1041.  
  1042.     /*
  1043.      * Handle special case of "." and ".."
  1044.      */
  1045.     if (fname[0] == '.') {
  1046.         if (fname[1] == '\0')
  1047.             return mp;    /* "." is the current node */
  1048.         if (fname[1] == '.' && fname[2] == '\0') {
  1049.             if (mp->am_parent) {
  1050. #ifdef DEBUG
  1051.                 dlog(".. in %s gives %s", mp->am_path, mp->am_parent->am_path);
  1052. #endif
  1053.                 return mp->am_parent;    /* ".." is the parent node */
  1054.             }
  1055.             ereturn(ESTALE);
  1056.         }
  1057.     }
  1058.  
  1059.     /*
  1060.      * Check for valid key name.
  1061.      * If it is invalid then pretend it doesn't exist.
  1062.      */
  1063.     if (!valid_key(fname)) {
  1064.         plog(XLOG_WARNING, "Key \"%s\" contains a disallowed character", fname);
  1065.         ereturn(ENOENT);
  1066.     }
  1067.  
  1068.     /*
  1069.      * Expand key name.
  1070.      * fname is now a private copy.
  1071.      */
  1072.     fname = expand_key(fname);
  1073.  
  1074.     for (ap_hung = 0, ap = mp->am_child; ap; ap = ap->am_osib) {
  1075.         /*
  1076.          * Otherwise search children of this node
  1077.          */
  1078.         if (FSTREQ(ap->am_name, fname)) {
  1079.             mf = ap->am_mnt;
  1080.             if (ap->am_error) {
  1081.                 error = ap->am_error;
  1082.                 continue;
  1083.             }
  1084.  
  1085.             /*
  1086.              * If the error code is undefined then it must be
  1087.              * in progress.
  1088.              */
  1089.             if (mf->mf_error < 0)
  1090.                 goto in_progrss;
  1091.  
  1092.             /*
  1093.              * Check for a hung node
  1094.              */
  1095.             if (FSRV_ISDOWN(mf->mf_server)) {
  1096.                 ap_hung = ap;
  1097.                 continue;
  1098.             }
  1099.  
  1100.             /*
  1101.              * If there was a previous error with this node
  1102.              * then return that error code.
  1103.              */
  1104.             if (mf->mf_flags & MFF_ERROR) {
  1105.                 error = mf->mf_error;
  1106.                 continue;
  1107.             }
  1108.  
  1109.             if (!(mf->mf_flags & MFF_MOUNTED) /*|| (mf->mf_flags & MFF_UNMOUNTING)*/) {
  1110. in_progrss:
  1111.                 /*
  1112.                  * If the fs is not mounted or it is unmounting then there
  1113.                  * is a background (un)mount in progress.  In this case
  1114.                  * we just drop the RPC request (return nil) and
  1115.                  * wait for a retry, by which time the (un)mount may
  1116.                  * have completed.
  1117.                  */
  1118. #ifdef DEBUG
  1119.                 dlog("ignoring mount of %s in %s -- in progress",
  1120.                     fname, mf->mf_mount);
  1121. #endif
  1122.                 in_progress++;
  1123.                 continue;
  1124.             }
  1125.  
  1126.             /*
  1127.              * Otherwise we have a hit: return the current mount point.
  1128.              */
  1129. #ifdef DEBUG
  1130.             dlog("matched %s in %s", fname, ap->am_path);
  1131. #endif
  1132.             free(fname);
  1133.             return ap;
  1134.         }
  1135.     }
  1136.  
  1137.     if (in_progress) {
  1138. #ifdef DEBUG
  1139.         dlog("Waiting while %d mount(s) in progress", in_progress);
  1140. #endif
  1141.         free(fname);
  1142.         ereturn(-1);
  1143.     }
  1144.  
  1145.     /*
  1146.      * If an error occured then return it.
  1147.      */
  1148.     if (error) {
  1149. #ifdef DEBUG
  1150.         errno = error; /* XXX */
  1151.         dlog("Returning error: %m", error);
  1152. #endif
  1153.         free(fname);
  1154.         ereturn(error);
  1155.     }
  1156.  
  1157.     /*
  1158.      * If doing a delete then don't create again!
  1159.      */
  1160.     switch (op) {
  1161.     case VLOOK_DELETE:
  1162.         ereturn(ENOENT);
  1163.         break;
  1164.  
  1165.     case VLOOK_CREATE:
  1166.         break;
  1167.  
  1168.     default:
  1169.         plog(XLOG_FATAL, "Unknown op to afs_lookuppn: 0x%x", op);
  1170.         ereturn(EINVAL);
  1171.         break;
  1172.     }
  1173.  
  1174.     /*
  1175.      * If the server is going down then just return,
  1176.      * don't try to mount any more file systems
  1177.      */
  1178.     if ((int)amd_state >= (int)Finishing) {
  1179. #ifdef DEBUG
  1180.         dlog("not found - server going down anyway");
  1181. #endif
  1182.         free(fname);
  1183.         ereturn(ENOENT);
  1184.     }
  1185.  
  1186.     /*
  1187.      * If we get there then this is a reference to an,
  1188.      * as yet, unknown name so we need to search the mount
  1189.      * map for it.
  1190.      */
  1191.     if (mp->am_pref) {
  1192.         sprintf(path_name, "%s%s", mp->am_pref, fname);
  1193.         pfname = path_name;
  1194.     } else {
  1195.         pfname = fname;
  1196.     }
  1197.  
  1198.     mf = mp->am_mnt;
  1199.  
  1200. #ifdef DEBUG
  1201.     dlog("will search map info in %s to find %s", mf->mf_info, pfname);
  1202. #endif
  1203.     /*
  1204.      * Consult the oracle for some mount information.
  1205.      * info is malloc'ed and belongs to this routine.
  1206.      * It ends up being free'd in free_continuation().
  1207.      *
  1208.      * Note that this may return -1 indicating that information
  1209.      * is not yet available.
  1210.      */
  1211.     error = mapc_search((mnt_map*) mf->mf_private, pfname, &info);
  1212.     if (error) {
  1213.         plog(XLOG_MAP, "No map entry for %s", pfname);
  1214.         free(fname);
  1215.         ereturn(error);
  1216.     }
  1217.  
  1218. #ifdef DEBUG
  1219.     dlog("mount info is %s", info);
  1220. #endif
  1221.  
  1222.     /*
  1223.      * Split info into an argument vector.
  1224.      * The vector is malloc'ed and belongs to
  1225.      * this routine.  It is free'd in free_continuation()
  1226.      */
  1227.     xivec = ivec = strsplit(info, '\"');
  1228.  
  1229.     /*
  1230.      * Default error code...
  1231.      */
  1232.     if (ap_hung)
  1233.         error = EWOULDBLOCK;
  1234.     else
  1235.         error = ENOENT;
  1236.  
  1237.     /*
  1238.      * Allocate a new map
  1239.      */
  1240.     new_mp = exported_ap_alloc();
  1241.     if (new_mp == 0) {
  1242.         free((voidp) xivec);
  1243.         free((voidp) info);
  1244.         free((voidp) fname);
  1245.         ereturn(ENOSPC);
  1246.     }
  1247.  
  1248.     if (mf->mf_opts)
  1249.         opts = mf->mf_opts;
  1250.     else
  1251.         opts = "";
  1252.  
  1253.     opts = strdup(opts);
  1254.  
  1255. #ifdef DEBUG
  1256.     dlog("searching for /defaults entry");
  1257. #endif
  1258.     if (mapc_search((mnt_map*) mf->mf_private, "/defaults", &dflts) == 0) {
  1259.           char *dfl;
  1260.         char **rvec;
  1261. #ifdef DEBUG
  1262.         dlog("/defaults gave %s", dflts);
  1263. #endif
  1264.         if (*dflts == '-')
  1265.             dfl = dflts+1;
  1266.         else
  1267.             dfl = dflts;
  1268.  
  1269.         /*
  1270.          * Chop the defaults up
  1271.          */
  1272.         rvec = strsplit(dfl, '\"');
  1273.         /*
  1274.          * Extract first value
  1275.          */
  1276.         dfl = rvec[0];
  1277.  
  1278.         /*
  1279.          * Log error if there were other values
  1280.          */
  1281.         if (rvec[1]) {
  1282. #ifdef DEBUG
  1283.             dlog("/defaults chopped into %s", dfl);
  1284. #endif
  1285.             plog(XLOG_USER, "More than a single value for /defaults in %s", mf->mf_info);
  1286.         }
  1287.  
  1288.         /*
  1289.          * Don't need info vector any more
  1290.          */
  1291.         free((voidp) rvec);
  1292.  
  1293.         /*
  1294.          * If there were any values at all...
  1295.          */
  1296.         if (dfl) {
  1297.             /*
  1298.              * Prepend to existing defaults if they exist,
  1299.              * otherwise just use these defaults.
  1300.              */
  1301.             if (*opts && *dfl) {
  1302.                 char *nopts = (char *) xmalloc(strlen(opts)+strlen(dfl)+2);
  1303.                 sprintf(nopts, "%s;%s", dfl, opts);
  1304.                 free(opts);
  1305.                 opts = nopts;
  1306.             } else if (*dfl) {
  1307.                 opts = strealloc(opts, dfl);
  1308.             }
  1309.         }
  1310.         free(dflts);
  1311.     }
  1312.  
  1313.     /*
  1314.      * Fill it in
  1315.      */
  1316.     init_map(new_mp, fname);
  1317.  
  1318.     /*
  1319.      * Put it in the table
  1320.      */
  1321.     insert_am(new_mp, mp);
  1322.  
  1323.     /*
  1324.      * Fill in some other fields,
  1325.      * path and mount point
  1326.      */
  1327.     new_mp->am_path = str3cat(new_mp->am_path, mp->am_path, *fname == '/' ? "" : "/", fname);
  1328.  
  1329. #ifdef DEBUG
  1330.     dlog("setting path to %s", new_mp->am_path);
  1331. #endif
  1332.  
  1333.     /*
  1334.      * Take private copy of pfname
  1335.      */
  1336.     pfname = strdup(pfname);
  1337.  
  1338.     /*
  1339.      * Construct a continuation
  1340.      */
  1341.     cp = ALLOC(continuation);
  1342.     cp->mp = new_mp;
  1343.     cp->xivec = xivec;
  1344.     cp->ivec = ivec;
  1345.     cp->info = info;
  1346.     cp->key = pfname;
  1347.     cp->opts = opts;
  1348.     cp->retry = FALSE;
  1349.     cp->tried = FALSE;
  1350.     cp->start = clocktime();
  1351.     cp->def_opts = strdup(opts);
  1352.     bzero((voidp) &cp->fs_opts, sizeof(cp->fs_opts));
  1353.  
  1354.     /*
  1355.      * Try and mount the file system
  1356.      * If this succeeds immediately (possible
  1357.      * for a ufs file system) then return
  1358.      * the attributes, otherwise just
  1359.      * return an error.
  1360.      */
  1361.     error = afs_bgmount(cp, error);
  1362.     reschedule_timeout_mp();
  1363.     if (!error) {
  1364.         free(fname);
  1365.         return new_mp;
  1366.     }
  1367.  
  1368.     assign_error_mntfs(cp->mp);
  1369.  
  1370.     free(fname);
  1371.  
  1372.     ereturn(error);
  1373. #undef ereturn
  1374. }
  1375.  
  1376. /*
  1377.  * Locate next node in sibling list which is mounted
  1378.  * and is not an error node.
  1379.  */
  1380. static am_node *next_nonerror_node(xp)
  1381. am_node *xp;
  1382. {
  1383.     mntfs *mf;
  1384.  
  1385.     /*
  1386.      * Bug report (7/12/89) from Rein Tollevik <rein@ifi.uio.no>
  1387.      * Fixes a race condition when mounting direct automounts.
  1388.      * Also fixes a problem when doing a readdir on a directory
  1389.      * containing hung automounts.
  1390.      */
  1391.     while (xp &&
  1392.            (!(mf = xp->am_mnt) ||            /* No mounted filesystem */
  1393.             mf->mf_error != 0 ||            /* There was a mntfs error */
  1394.             xp->am_error != 0 ||            /* There was a mount error */
  1395.             !(mf->mf_flags & MFF_MOUNTED) ||    /* The fs is not mounted */
  1396.             (mf->mf_server->fs_flags & FSF_DOWN))    /* The fs may be down */
  1397.         )
  1398.         xp = xp->am_osib;
  1399.  
  1400.     return xp;
  1401. }
  1402.  
  1403. static int afs_readdir(mp, cookie, dp, ep)
  1404. am_node *mp;
  1405. nfscookie cookie;
  1406. struct dirlist *dp;
  1407. struct entry *ep;
  1408. {
  1409.     unsigned int gen = *(unsigned int*) cookie;
  1410.     am_node *xp;
  1411.  
  1412.     dp->eof = FALSE;
  1413.  
  1414.     if (gen == 0) {
  1415.         /*
  1416.          * In the default instance (which is used to
  1417.          * start a search) we return "." and "..".
  1418.          *
  1419.          * This assumes that the count is big enough
  1420.          * to allow both "." and ".." to be returned in
  1421.          * a single packet.  If it isn't (which would
  1422.          * be fairly unbelievable) then tough.
  1423.          */
  1424. #ifdef DEBUG
  1425.         dlog("default search");
  1426. #endif
  1427.         xp = next_nonerror_node(mp->am_child);
  1428.         dp->entries = ep;
  1429.  
  1430.         /* construct "." */
  1431.         ep[0].fileid = mp->am_gen;
  1432.         ep[0].name = ".";
  1433.         ep[0].nextentry = &ep[1];
  1434.         *(unsigned int *) ep[0].cookie = 0;
  1435.  
  1436.         /* construct ".." */
  1437.         if (mp->am_parent)
  1438.             ep[1].fileid = mp->am_parent->am_gen;
  1439.         else
  1440.             ep[1].fileid = mp->am_gen;
  1441.         ep[1].name = "..";
  1442.         ep[1].nextentry = 0;
  1443.         *(unsigned int *) ep[1].cookie =
  1444.             xp ? xp->am_gen : ~(unsigned int)0;
  1445.  
  1446.         return 0;
  1447.     }
  1448.  
  1449. #ifdef DEBUG
  1450.     dlog("real child");
  1451. #endif
  1452.  
  1453.     if (gen == ~(unsigned int)0) {
  1454. #ifdef DEBUG
  1455.         dlog("End of readdir in %s", mp->am_path);
  1456. #endif
  1457.         dp->eof = TRUE;
  1458.         dp->entries = 0;
  1459.         return 0;
  1460.     }
  1461.  
  1462.     xp = mp->am_child;
  1463.     while (xp && xp->am_gen != gen)
  1464.         xp = xp->am_osib;
  1465.  
  1466.     if (xp) {
  1467.         am_node *xp_next = next_nonerror_node(xp->am_osib);
  1468.  
  1469.         if (xp_next) {
  1470.             *(unsigned int *) ep->cookie = xp_next->am_gen;
  1471.         } else {
  1472.             *(unsigned int *) ep->cookie = ~(unsigned int)0;
  1473.         }
  1474.  
  1475.         ep->fileid = xp->am_gen;
  1476.         ep->name = xp->am_name;
  1477.  
  1478.         ep->nextentry = 0;
  1479.         dp->entries = ep;
  1480.  
  1481.         return 0;
  1482.     }
  1483.  
  1484.     return ESTALE;
  1485.  
  1486. }
  1487.  
  1488. static char *dfs_readlink(mp, error_return)
  1489. am_node *mp;
  1490. int *error_return;
  1491. {
  1492.     am_node *xp;
  1493.     int rc = 0;
  1494.  
  1495.     xp = next_nonerror_node(mp->am_child);
  1496.     if (!xp)
  1497.         xp = afs_lookuppn(mp, mp->am_path+1, &rc, VLOOK_CREATE);
  1498.  
  1499.     if (xp) {
  1500.         new_ttl(xp);    /* (7/12/89) from Rein Tollevik */
  1501.         return xp->am_link ? xp->am_link : xp->am_mnt->mf_mount;
  1502.     }
  1503.     if (amd_state == Finishing)
  1504.         return "/tmp";
  1505.     *error_return = rc;
  1506.     return 0;
  1507. }
  1508.  
  1509. /*
  1510.  * Ops structure
  1511.  */
  1512. am_ops afs_ops = {
  1513.     MNTTYPE_AUTO,
  1514.     afs_match,
  1515.     afs_init,
  1516.     afs_mount,
  1517.     afs_umount,
  1518.     afs_lookuppn,
  1519.     afs_readdir,
  1520.     0, /* afs_readlink */
  1521.     0, /* afs_mounted */
  1522.     afs_umounted,
  1523.     find_afs_srvr,
  1524.     FS_NOTIMEOUT|FS_UBACKGROUND|FS_AMQINFO,
  1525.     &afs_srvr_list
  1526. };
  1527.  
  1528. am_ops dfs_ops = {
  1529.     "direct",
  1530.     afs_match,
  1531.     0, /* dfs_init */
  1532.     afs_mount,
  1533.     afs_umount,
  1534.     efs_lookuppn,
  1535.     efs_readdir,
  1536.     dfs_readlink,
  1537.     0, /* afs_mounted */
  1538.     afs_umounted,
  1539.     find_afs_srvr,
  1540.     FS_NOTIMEOUT|FS_UBACKGROUND|FS_AMQINFO,
  1541.     &afs_srvr_list
  1542. };
  1543.