home *** CD-ROM | disk | FTP | other *** search
/ Chip 1995 March / CHIP3.mdf / slackwar / a / util / util-lin.2 / util-lin / util-linux-2.2 / mount / mount.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-26  |  18.4 KB  |  735 lines

  1. /*
  2.  * A mount(8) for Linux 0.99.
  3.  * mount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
  4.  *
  5.  * Thu Jul 14 07:32:40 1994: faith@cs.unc.edu added changed from Adam
  6.  * J. Richter (adam@adam.yggdrasil.com) so that /proc/filesystems is used
  7.  * if no -t option is given.  I modified his patches so that, if
  8.  * /proc/filesystems is not available, the behavior of mount is the same as
  9.  * it was previously.
  10.  *
  11.  * Wed Sep 14 22:43:00 1994: Mitchum DSouza
  12.  * (mitch@mrc-applied-psychology.cambridge.ac.uk) added support for mounting
  13.  * the "loop" device.
  14.  *
  15.  * Wed Sep 14 22:55:10 1994: Sander van Malssen (svm@kozmix.hacktic.nl)
  16.  * added support for remounting readonly file systems readonly.
  17.  *
  18.  * Wed Feb 8 09:23:18 1995: Mike Grupenhoff <kashmir@umiacs.UMD.EDU> added
  19.  * a probe of the superblock for the type before /proc/filesystems is
  20.  * checked.
  21.  *
  22.  * Wed Feb  8 12:27:00 1995: Andries.Brouwer@cwi.nl fixed up error messages.
  23.  *
  24.  */
  25.  
  26. #include "sundries.h"
  27.  
  28. #include <linux/fs.h>
  29. #include <linux/minix_fs.h>
  30. #include <linux/ext_fs.h>
  31. #include <linux/ext2_fs.h>
  32. #include <linux/xia_fs.h>
  33. #include <sys/stat.h>
  34. #include <unistd.h>
  35.  
  36. int del_loop (const char *);
  37.  
  38. /* True for fake mount (-f).  */
  39. int fake = 0;
  40.  
  41. /* Don't write a entry in /etc/mtab (-n).  */
  42. int nomtab = 0;
  43.  
  44. /* True for readonly (-r).  */
  45. int readonly = 0;
  46.  
  47. /* Nonzero for chatty (-v).  */
  48. int verbose = 0;
  49.  
  50. /* True for read/write (-w).  */
  51. int readwrite = 0;
  52.  
  53. /* True for all mount (-a).  */
  54. int all = 0;
  55.  
  56. /* True if ruid != euid.  */
  57. int suid = 0;
  58.  
  59. /* Map from -o and fstab option strings to the flag argument to mount(2).  */
  60. struct opt_map
  61. {
  62.   const char *opt;        /* option name */
  63.   int  inv;            /* true if flag value should be inverted */
  64.   int  mask;            /* flag mask value */
  65. };
  66.  
  67. /* Custom mount options for our own purposes.  */
  68. #define MS_NOAUTO    0x80000000
  69. #define MS_USER        0x40000000
  70.  
  71. /* Options that we keep the mount system call from seeing.  */
  72. #define MS_NOSYS    (MS_NOAUTO|MS_USER)
  73.  
  74. /* Options that we keep from appearing in the options field in the mtab.  */
  75. #define MS_NOMTAB    (MS_REMOUNT|MS_NOAUTO|MS_USER)
  76.  
  77. /* OPTIONS that we make ordinary users have by default.  */
  78. #define MS_SECURE    (MS_NOEXEC|MS_NOSUID|MS_NODEV)
  79.  
  80. const struct opt_map opt_map[] =
  81. {
  82.   { "defaults",    0, 0        },    /* default options */
  83.   { "ro",    0, MS_RDONLY    },    /* read-only */
  84.   { "rw",    1, MS_RDONLY    },    /* read-write */
  85.   { "exec",    1, MS_NOEXEC    },    /* permit execution of binaries */
  86.   { "noexec",    0, MS_NOEXEC    },    /* don't execute binaries */
  87.   { "suid",    1, MS_NOSUID    },    /* honor suid executables */
  88.   { "nosuid",    0, MS_NOSUID    },    /* don't honor suid executables */
  89.   { "dev",    1, MS_NODEV    },    /* interpret device files  */
  90.   { "nodev",    0, MS_NODEV    },    /* don't interpret devices */
  91.   { "sync",    0, MS_SYNCHRONOUS},    /* synchronous I/O */
  92.   { "async",    1, MS_SYNCHRONOUS},    /* asynchronous I/O */
  93.   { "remount",  0, MS_REMOUNT   },      /* Alter flags of mounted FS */
  94.   { "auto",    1, MS_NOAUTO    },    /* Can be mounted using -a */
  95.   { "noauto",    0, MS_NOAUTO    },    /* Can  only be mounted explicitly */
  96.   { "user",    0, MS_USER    },    /* Allow ordinary user to mount */
  97.   { "nouser",    1, MS_USER    },    /* Forbid ordinary user to mount */
  98.   /* add new options here */
  99. #ifdef MS_NOSUB
  100.   { "sub",    1, MS_NOSUB    },    /* allow submounts */
  101.   { "nosub",    0, MS_NOSUB    },    /* don't allow submounts */
  102. #endif
  103.   { NULL,    0, 0        }
  104. };
  105.  
  106.  
  107. /* Report on a single mount.  */
  108. static void
  109. print_one (const struct mntent *mnt)
  110. {
  111.   printf ("%s on %s", mnt->mnt_fsname, mnt->mnt_dir);
  112.   if ((mnt->mnt_type != NULL) && *mnt->mnt_type != '\0')
  113.     printf (" type %s", mnt->mnt_type);
  114.   if (mnt->mnt_opts != NULL)
  115.     printf (" (%s)", mnt->mnt_opts);
  116.   printf ("\n");
  117. }
  118.  
  119. /* Report on everything in mtab (of the specified types if any).  */
  120. static int
  121. print_all (string_list types)
  122. {
  123.   struct mntent *mnt;
  124.   
  125.   open_mtab ("r");
  126.  
  127.   while ((mnt = getmntent (F_mtab)) != NULL)
  128.     if (matching_type (mnt->mnt_type, types))
  129.       print_one (mnt);
  130.  
  131.   if (ferror (F_mtab))
  132.     die (1, "mount: error reading %s: %s", MOUNTED, strerror (errno));
  133.  
  134.   exit (0);
  135. }
  136.  
  137.  
  138. /* Look for OPT in opt_map table and return mask value.  If OPT isn't found,
  139.    tack it onto extra_opts.  */
  140. static inline void
  141. parse_opt (const char *opt, int *mask, char *extra_opts)
  142. {
  143.   const struct opt_map *om;
  144.  
  145.   for (om = opt_map; om->opt != NULL; om++)
  146.     if (streq (opt, om->opt))
  147.       {
  148.     if (om->inv)
  149.       *mask &= ~om->mask;
  150.     else
  151.       *mask |= om->mask;
  152.     if (om->mask == MS_USER)
  153.       *mask |= MS_SECURE;
  154.     return;
  155.       }
  156.   if (*extra_opts)
  157.     strcat(extra_opts, ",");
  158.   strcat(extra_opts, opt);
  159. }
  160.   
  161. /* Take -o options list and compute 4th and 5th args to mount(2).  flags
  162.    gets the standard options and extra_opts anything we don't recognize.  */
  163. static void
  164. parse_opts (char *opts, int *flags, char **extra_opts)
  165. {
  166.   char *opt;
  167.  
  168.   *flags = 0;
  169.   *extra_opts = NULL;
  170.  
  171.   if (opts != NULL)
  172.     {
  173.       *extra_opts = xmalloc (strlen (opts) + 1); 
  174.       **extra_opts = '\0';
  175.  
  176.       for (opt = strtok (opts, ",");
  177.        opt != NULL;
  178.        opt = strtok (NULL, ","))
  179.     parse_opt (opt, flags, *extra_opts);
  180.     }
  181.  
  182.   if (readonly)
  183.     *flags |= MS_RDONLY;
  184.   if (readwrite)
  185.     *flags &= ~MS_RDONLY;
  186. }
  187.  
  188. /* Try to build a canonical options string.  */
  189. static char *
  190. fix_opts_string (int flags, char *extra_opts)
  191. {
  192.   const struct opt_map *om;
  193.   char *new_opts;
  194.   char *tmp;
  195.  
  196.   new_opts = (flags & MS_RDONLY) ? "ro" : "rw";
  197.   for (om = opt_map; om->opt != NULL; om++)
  198.     {
  199.       if (om->mask & MS_RDONLY)
  200.     continue;
  201.       if (om->inv || !om->mask || (flags & om->mask) != om->mask)
  202.     continue;
  203.       tmp = xmalloc(strlen(new_opts) + strlen(om->opt) + 2);
  204.       sprintf(tmp, "%s,%s", new_opts, om->opt);
  205.       new_opts = tmp;
  206.       flags &= ~om->mask;
  207.     }
  208.   if (extra_opts && *extra_opts)
  209.     {
  210.       tmp = xmalloc(strlen(new_opts) + strlen(extra_opts) + 2);
  211.       sprintf(tmp, "%s,%s", new_opts, extra_opts);
  212.       new_opts = tmp;
  213.     }
  214.   return new_opts;
  215. }
  216.  
  217.  
  218. /*
  219.     char *fstype(const char *device);
  220.  
  221.     probes the device and attempts to determine the type of filesystem
  222.     contained within.
  223.  
  224.     Original routine by <jmorriso@bogomips.ww.ubc.ca>; made into a function
  225.     for mount(8) by Mike Grupenhoff <kashmir@umiacs.umd.edu>.
  226.  
  227.     Currently supports: minix, ext, ext2, xia
  228. */
  229.  
  230. static char *
  231. fstype(const char *device)
  232. {
  233.     int fd;
  234.  
  235.     /* MINIX */
  236.     struct minix_super_block ms;
  237.     /* extended fs */
  238.     struct ext_super_block es;
  239.     /* 2nd extended fs */
  240.     struct ext2_super_block e2s;
  241.     /* xia fs */
  242.     struct xiafs_super_block xfs;
  243.  
  244.     fd = open(device, O_RDONLY);
  245.     if (fd < 0) {
  246.     perror(device);
  247.     return 0;
  248.     }
  249.     lseek(fd, BLOCK_SIZE, SEEK_SET);
  250.     read(fd, (char *) &ms, sizeof(ms));
  251.     if (ms.s_magic == MINIX_SUPER_MAGIC || ms.s_magic == MINIX_SUPER_MAGIC2) {
  252.         close(fd);
  253.     return("minix");
  254.     }
  255.  
  256.     lseek(fd, BLOCK_SIZE, SEEK_SET);
  257.     read(fd, (char *) &es, sizeof(es));
  258.     if (es.s_magic == EXT_SUPER_MAGIC) {
  259.         close(fd);
  260.     return("ext");
  261.     }
  262.  
  263.     lseek(fd, BLOCK_SIZE, SEEK_SET);
  264.     read(fd, (char *) &e2s, sizeof(e2s));
  265.     if (e2s.s_magic == EXT2_SUPER_MAGIC || e2s.s_magic == EXT2_PRE_02B_MAGIC) {
  266.         close(fd);
  267.     return("ext2");
  268.     }
  269.  
  270.     lseek(fd, 0, SEEK_SET);
  271.     read(fd, (char *) &xfs, sizeof(xfs));
  272.     if (xfs.s_magic == _XIAFS_SUPER_MAGIC) {
  273.         close(fd);
  274.     return("xiafs");
  275.     }
  276.  
  277.     close(fd);
  278.  
  279.     return(0);
  280.  
  281. }
  282.  
  283.  
  284. /* Mount a single file system.  Return status,
  285.    so don't exit on non-fatal errors.  */
  286.  
  287. static int
  288. try_mount5 (char *spec, char *node, char **type, int flags, char *mount_opts) {
  289.    FILE *procfs_file;
  290.    char line[100];
  291.    char fsname[50];
  292.    
  293.    if (*type) return mount5 (spec, node, *type, flags & ~MS_NOSYS, mount_opts);
  294.    if (( procfs_file = fopen("/proc/filesystems", "r")) == NULL) {
  295.                 /* If /proc/filesystems is not available,
  296.                    preserve the old behavior of mount. */
  297.       return mount5 (spec,
  298.              node,
  299.              FSTYPE_DEFAULT,
  300.              flags & ~MS_NOSYS, mount_opts);
  301.    }
  302.    while (fgets(line, sizeof(line), procfs_file)) {
  303.       if (sscanf (line, "nodev %[^\n]\n", fsname) == 1) continue;
  304.       if (sscanf (line, " %[^ \n]\n", fsname) != 1) continue;
  305.       if (mount5 (spec, node, fsname, flags & ~MS_NOSYS, mount_opts) == 0) {
  306.       *type=xstrdup(fsname);
  307.       fclose(procfs_file);
  308.       return 0;
  309.       }
  310.    }
  311.    fclose(procfs_file);
  312.    return -1;
  313. }
  314.  
  315.  
  316. static int
  317. mount_one (char *spec, char *node, char *type, char *opts, int freq, int pass)
  318. {
  319.   struct mntent mnt;
  320.   int mnt_err;
  321.   int flags;
  322.   char *extra_opts;
  323.   char *mount_opts;
  324.   int anti_recurse = 0;
  325.   int loop=0;
  326.  
  327.   if (type == NULL)
  328.     {
  329.       if (strchr (spec, ':') != NULL)
  330.     type = "nfs";
  331.     }
  332.  
  333.   parse_opts (xstrdup (opts), &flags, &extra_opts);
  334.  
  335.   /* root may allow certain types of mounts by ordinary users */
  336.   if (suid && !(flags & MS_USER))
  337.     die (3, "mount: only root can mount %s on %s", spec, node);
  338.  
  339.   /* quietly succeed for fstab entries that don't get mounted automatically */
  340.   if (all && (flags & MS_NOAUTO))
  341.     return 0;
  342.  
  343.   mount_opts = extra_opts;
  344.  
  345.   if (!fake && type && strncmp("lo@", type, 3)==0) {
  346.     extern int lomount (char *, char *, char *, char **, 
  347.             int *, char **, char **);
  348.     char *dev=type+3;
  349.  
  350.     loop=1;
  351.     if (lomount (spec, node, dev, &type,
  352.          &flags, &opts, &mount_opts) != 0)
  353.       return 1;
  354.     spec=dev;
  355.     mount_opts=NULL;
  356.   }
  357.  
  358.   if (!fake && type && streq (type, "nfs"))
  359. #ifdef HAVE_NFS
  360.     if (nfsmount (spec, node, &flags, &extra_opts, &mount_opts) != 0)
  361.       return 1;
  362. #else
  363.     die (1, "mount: this version doesn't support the type `nfs'");
  364. #endif
  365.  
  366.   if (!type && !(type = fstype(spec)))
  367.       return 1;
  368.  
  369.   block_signals (SIG_BLOCK);
  370.  
  371.   if (fake
  372.       || (try_mount5 (spec, node, &type, flags & ~MS_NOSYS, mount_opts)) == 0)
  373.     /* Mount succeeded, write mtab entry.  */
  374.     {
  375.       if (!nomtab)
  376.     {
  377.       mnt.mnt_fsname = canonicalize (spec);
  378.       mnt.mnt_dir = canonicalize (node);
  379.       mnt.mnt_type = loop?"loop":type;
  380.       mnt.mnt_opts = fix_opts_string (flags & ~MS_NOMTAB, 
  381.                       loop?opts:extra_opts);
  382.       mnt.mnt_freq = freq;
  383.       mnt.mnt_passno = pass;
  384.       
  385.       /* We get chatty now rather than after the update to mtab since the
  386.          mount succeeded, even if the write to /etc/mtab should fail.  */
  387.       if (verbose)
  388.         print_one (&mnt);
  389.  
  390.       if (flags & MS_REMOUNT)
  391.         {
  392.           close_mtab ();
  393.           update_mtab (mnt.mnt_dir, &mnt);
  394.           open_mtab ("a+");
  395.         }
  396.       else
  397.         if ((addmntent (F_mtab, &mnt)) == 1)
  398.           die (1, "mount: error writing %s: %s",
  399.            MOUNTED, strerror (errno));
  400.     }
  401.  
  402.       block_signals (SIG_UNBLOCK);
  403.       return 0;
  404.     }
  405.  
  406.   if (loop)
  407.     del_loop(spec);
  408.  
  409.   mnt_err = errno; /* work around for errno bug in sigprocmask */
  410.  
  411.   block_signals (SIG_UNBLOCK);
  412.  
  413.   /* Mount failed, complain, but don't die.  */
  414.   switch (mnt_err)
  415.     {
  416.     case EPERM:
  417.       if (geteuid() == 0)
  418.     error ("mount: mount point %s is not a directory", node);
  419.       else
  420.     error ("mount: must be superuser to use mount");
  421.       break;
  422.     case EBUSY:
  423.       error ("mount: %s already mounted or %s busy", spec, node);
  424.       break;
  425.     case ENOENT:
  426.       { struct stat statbuf;
  427.     if (stat (node, &statbuf))
  428.           error ("mount: mount point %s does not exist", node);
  429.     else if (stat (spec, &statbuf))
  430.           error ("mount: special device %s does not exist", spec);
  431.     else {
  432.            errno = mnt_err;
  433.            perror("mount");
  434.     }
  435.     break;
  436.      }
  437.     case ENOTDIR:
  438.       error ("mount: mount point %s is not a directory", node); break;
  439.     case EINVAL:
  440.       error ("mount: wrong fs type or bad superblock on %s", spec); break;
  441.     case EMFILE:
  442.       error ("mount table full"); break;
  443.     case EIO:
  444.       error ("mount: %s: can't read superblock", spec); break;
  445.     case ENODEV:
  446.       error ("mount: fs type %s not supported by kernel", type); break;
  447.     case ENOTBLK:
  448.       error ("mount: %s is not a block device", spec); break;
  449.     case ENXIO:
  450.       error ("mount: %s is not a valid block device", spec); break;
  451.     case EACCES:  /* pre-linux 1.1.38 */
  452.     case EROFS:   /* linux 1.1.38 and later */
  453.       if (anti_recurse)
  454.         {
  455.           error ("mount: block device %s is not permitted on its filesystem", spec);
  456.           break;
  457.         }
  458.       else
  459.         {
  460.          anti_recurse++;
  461.          if (opts)
  462.            {
  463.              opts = realloc(xstrdup(opts), strlen(opts)+3);
  464.              strcat(opts, ",ro");
  465.            }
  466.          else
  467.            opts = "ro";
  468.           error ("mount: block device %s is write-protected, mounting read-only", spec);
  469.           return mount_one (spec, node, type, opts, freq, pass);
  470.         }
  471.       break;
  472.     default:
  473.       error ("mount: %s", strerror (mnt_err)); break;
  474.     }
  475.   return 1;
  476. }
  477.  
  478. /* Check if an fsname/dir pair was already in the old mtab.  */
  479. static int
  480. mounted (char *spec, char *node, string_list spec_list, string_list node_list)
  481. {
  482.   spec = canonicalize (spec);
  483.   node = canonicalize (node);
  484.  
  485.   while (spec_list != NULL)
  486.     {
  487.       if (streq (spec, car (spec_list)) && streq (node, car (node_list)))
  488.     return 1;
  489.       spec_list = cdr (spec_list);
  490.       node_list = cdr (node_list);
  491.     }
  492.     return 0;
  493. }
  494.  
  495. /* Mount all filesystems of the specified types except swap and root.  */
  496. static int
  497. mount_all (string_list types)
  498. {
  499.   struct mntent *fstab;
  500.   struct mntent *mnt;
  501.   string_list spec_list = NULL;
  502.   string_list node_list = NULL;
  503.   int status;
  504.  
  505.   rewind (F_mtab);
  506.  
  507.   while ((mnt = getmntent (F_mtab)))
  508.     if (matching_type (mnt->mnt_type, types)
  509.     && !streq (mnt->mnt_dir, "/")
  510.     && !streq (mnt->mnt_dir, "root"))
  511.       {
  512.     spec_list = cons (xstrdup (mnt->mnt_fsname), spec_list);
  513.     node_list = cons (xstrdup (mnt->mnt_dir), node_list);
  514.       }
  515.  
  516.   status = 0;
  517.   while ((fstab = getfsent ()) != NULL)
  518.     if (matching_type (fstab->mnt_type, types)
  519.      && !streq (fstab->mnt_dir, "/")
  520.      && !streq (fstab->mnt_dir, "root"))
  521.       if (mounted (fstab->mnt_fsname, fstab->mnt_dir, spec_list, node_list))
  522.     {
  523.       if (verbose)
  524.         printf("mount: %s already mounted on %s\n",
  525.            fstab->mnt_fsname, fstab->mnt_dir);
  526.     }
  527.       else
  528.         status |= mount_one (fstab->mnt_fsname, fstab->mnt_dir,
  529.                  fstab->mnt_type, fstab->mnt_opts,
  530.                  fstab->mnt_freq, fstab->mnt_passno);
  531.  
  532.   return status;
  533. }
  534.  
  535. /* Create mtab with a root entry.  */
  536. static void
  537. create_mtab (void)
  538. {
  539.   struct mntent *fstab;
  540.   struct mntent mnt;
  541.   int flags;
  542.   char *extra_opts;
  543.  
  544.   if ((F_mtab = setmntent (MOUNTED, "a+")) == NULL)
  545.     die (1, "mount: can't open %s for writing: %s", MOUNTED, strerror (errno));
  546.  
  547.   /* Find the root entry by looking it up in fstab, which might be wrong.
  548.      We could statfs "/" followed by a slew of stats on /dev/ but then
  549.      we'd have to unparse the mount options as well....  */
  550.   if ((fstab = getfsfile ("/")) || (fstab = getfsfile ("root")))
  551.     {
  552.       parse_opts (xstrdup (fstab->mnt_opts), &flags, &extra_opts);
  553.       mnt = *fstab;
  554.       mnt.mnt_fsname = canonicalize (fstab->mnt_fsname);
  555.       mnt.mnt_dir = "/";
  556.       mnt.mnt_opts = fix_opts_string (flags, extra_opts);
  557.  
  558.       if (addmntent (F_mtab, &mnt) == 1)
  559.     die (1, "mount: error writing %s: %s", MOUNTED, strerror (errno));
  560.     }
  561.   if (fchmod (fileno (F_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0)
  562.     die (1, "mount: error changing mode of %s: %s", MOUNTED, strerror (errno));
  563.   endmntent (F_mtab);
  564. }
  565.  
  566. extern char version[];
  567. static struct option longopts[] =
  568. {
  569.   { "all", 0, 0, 'a' },
  570.   { "fake", 0, 0, 'f' },
  571.   { "help", 0, 0, 'h' },
  572.   { "no-mtab", 0, 0, 'n' },
  573.   { "read-only", 0, 0, 'r' },
  574.   { "ro", 0, 0, 'r' },
  575.   { "verbose", 0, 0, 'v' },
  576.   { "version", 0, 0, 'V' },
  577.   { "read-write", 0, 0, 'w' },
  578.   { "rw", 0, 0, 'w' },
  579.   { "options", 1, 0, 'o' },
  580.   { "types", 1, 0, 't' },
  581.   { NULL, 0, 0, 0 }
  582. };
  583.  
  584. const char *usage_string = "\
  585. usage: mount [-hV]\n\
  586.        mount -a [-nfrvw] [-t vfstypes]\n\
  587.        mount [-nfrvw] [-o options] special | node\n\
  588.        mount [-nfrvw] [-t vfstype] [-o options] special node\n\
  589. ";
  590.  
  591. static void
  592. usage (FILE *fp, int n)
  593. {
  594.   fprintf (fp, "%s", usage_string);
  595.   exit (n);
  596. }
  597.  
  598. int
  599. main (int argc, char *argv[])
  600. {
  601.   int c;
  602.   char *options = NULL;
  603.   string_list types = NULL;
  604.   struct mntent *fs;
  605.   char *spec;
  606.   int result = 0;
  607.   struct stat statbuf;
  608.  
  609.   while ((c = getopt_long (argc, argv, "afhnrvVwt:o:", longopts, NULL)) != EOF)
  610.     switch (c)
  611.       {
  612.       case 'a':            /* mount everything in fstab */
  613.     ++all;
  614.     break;
  615.       case 'f':            /* fake (don't actually do mount(2) call) */
  616.     ++fake;
  617.     break;
  618.       case 'h':            /* help */
  619.     usage (stdout, 0);
  620.     break;
  621.       case 'n':            /* mount without writing in /etc/mtab */
  622.     ++nomtab;
  623.     break;
  624.       case 'r':            /* mount readonly */
  625.     ++readonly;
  626.     readwrite = 0;
  627.     break;
  628.       case 'v':            /* be chatty */
  629.     ++verbose;
  630.     break;
  631.       case 'V':            /* version */
  632.     printf ("%s\n", version);
  633.     exit (0);
  634.       case 'w':            /* mount read/write */
  635.     ++readwrite;
  636.     readonly = 0;
  637.     break;
  638.       case 't':            /* specify file system types */
  639.     types = parse_list (optarg);
  640.     break;
  641.       case 'o':            /* specify mount options */
  642.     options = optarg;
  643.     break;
  644.       case 0:
  645.     break;
  646.       case '?':
  647.       default:
  648.     usage (stderr, 1);
  649.     break;
  650.       }
  651.  
  652.   argc -= optind;
  653.   argv += optind;
  654.  
  655.   if (argc == 0)
  656.     {
  657.       if (options)
  658.     usage (stderr, 1);
  659.       if (!all)
  660.     return print_all (types);
  661.     }
  662.  
  663.   if (getuid () != geteuid ())
  664.     {
  665.       suid = 1;
  666.       if (types || options || readwrite || nomtab || all || fake || argc != 1)
  667.     die (2, "mount: only root can do that");
  668.     }
  669.  
  670.   if (!nomtab)
  671.     {
  672.       lock_mtab ();
  673.       if (stat(MOUNTED, &statbuf) < 0)
  674.     create_mtab ();
  675.       open_mtab ("a+");
  676.     }
  677.   else if (stat(MOUNTED, &statbuf) >= 0)
  678.     open_mtab ("r");
  679.  
  680.  
  681.   switch (argc)
  682.     {
  683.     case 0:
  684.       /* mount -a */
  685.       result = mount_all (types);
  686.       break;
  687.  
  688.     case 1:
  689.       /* mount [-nfrvw] [-o options] special | node */
  690.       if (types != NULL)
  691.     usage (stderr, 1);
  692.       /* Try to find the other pathname in fstab.  */ 
  693.       spec = canonicalize (*argv);
  694.       if (!(fs = getmntfile (spec))
  695.       && !(fs = getfsspec (spec)) && !(fs = getfsfile (spec)))
  696.     die (2, "mount: can't find %s in %s or %s",
  697.          spec, MOUNTED, _PATH_FSTAB);
  698.       /* Merge the fstab and command line options.  */
  699.       if (options == NULL)
  700.     options = fs->mnt_opts;
  701.       else
  702.     {
  703.       char *tmp = xmalloc(strlen(fs->mnt_opts) + strlen(options) + 2);
  704.  
  705.       sprintf (tmp, "%s,%s", fs->mnt_opts, options);
  706.       options = tmp;
  707.     }
  708.       result = mount_one (xstrdup (fs->mnt_fsname), xstrdup (fs->mnt_dir),
  709.               xstrdup (fs->mnt_type), options,
  710.               fs->mnt_freq, fs->mnt_passno);
  711.       break;
  712.  
  713.     case 2:
  714.       /* mount [-nfrvw] [-t vfstype] [-o options] special node */
  715.       if (types == NULL)
  716.     result = mount_one (argv[0], argv[1], NULL, options, 0, 0);
  717.       else if (cdr (types) == NULL)
  718.     result = mount_one (argv[0], argv[1], car (types), options, 0, 0);
  719.       else
  720.     usage (stderr, 2);
  721.       break;
  722.       
  723.     default:
  724.       usage (stderr, 2);
  725.     }
  726.  
  727.   if (!nomtab)
  728.     {
  729.       endmntent (F_mtab);
  730.       unlock_mtab ();
  731.     }
  732.  
  733.   exit (result);
  734. }
  735.