]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - utils/mount/mount.c
mount.nfs - make sure program name in error message is correct.
[nfs-utils.git] / utils / mount / mount.c
index ca87e3d1b7fb60bc04d7e3504a7bcb4985e79b38..9ae66f070503dc9db3b6a3107f983ef34a1fb546 100644 (file)
@@ -28,6 +28,7 @@
 #include <sys/mount.h>
 #include <getopt.h>
 #include <mntent.h>
+#include <pwd.h>
 
 #include "fstab.h"
 #include "xcommon.h"
@@ -43,6 +44,7 @@ char *progname;
 int nomtab;
 int verbose;
 int mounttype;
+int sloppy;
 
 static struct option longopts[] = {
   { "fake", 0, 0, 'f' },
@@ -74,6 +76,11 @@ struct opt_map {
   int  mask;                    /* flag mask value */
 };
 
+/* Custom mount options for our own purposes.  */
+#define MS_DUMMY       0x00000000
+#define MS_USERS       0x40000000
+#define MS_USER                0x80000000
+
 static const struct opt_map opt_map[] = {
   { "defaults", 0, 0, 0         },      /* default options */
   { "ro",       1, 0, MS_RDONLY },      /* read-only */
@@ -90,6 +97,20 @@ static const struct opt_map opt_map[] = {
   { "remount",  0, 0, MS_REMOUNT},      /* Alter flags of mounted FS */
   { "bind",     0, 0, MS_BIND   },      /* Remount part of tree elsewhere */
   { "rbind",    0, 0, MS_BIND|MS_REC }, /* Idem, plus mounted subtrees */
+  { "auto",     0, 0, MS_DUMMY },       /* Can be mounted using -a */
+  { "noauto",   0, 0, MS_DUMMY },       /* Can  only be mounted explicitly */
+  { "users",    1, 0, MS_USERS|MS_NOEXEC|MS_NOSUID|MS_NODEV  },
+                                       /* Allow ordinary user to mount */
+  { "nousers",  0, 1, MS_DUMMY  },      /* Forbid ordinary user to mount */
+  { "user",     1, 0, MS_USER|MS_NOEXEC|MS_NOSUID|MS_NODEV  },
+                                       /* Allow ordinary user to mount */
+  { "nouser",   0, 1, MS_DUMMY   },     /* Forbid ordinary user to mount */
+  { "owner",    0, 0, MS_DUMMY  },      /* Let the owner of the device mount */
+  { "noowner",  0, 0, MS_DUMMY  },      /* Device owner has no special privs */
+  { "group",    0, 0, MS_DUMMY  },      /* Let the group of the device mount */
+  { "nogroup",  0, 0, MS_DUMMY  },      /* Device group has no special privs */
+  { "_netdev",  0, 0, MS_DUMMY},        /* Device requires network */
+  { "comment",  0, 0, MS_DUMMY},        /* fstab comment only (kudzu,_netdev)*/
 
   /* add new options here */
 #ifdef MS_NOSUB
@@ -104,6 +125,7 @@ static const struct opt_map opt_map[] = {
   { "mand",     0, 0, MS_MANDLOCK },    /* Allow mandatory locks on this FS */
   { "nomand",   0, 1, MS_MANDLOCK },    /* Forbid mandatory locks on this FS */
 #endif
+  { "loop",     1, 0, MS_DUMMY   },      /* use a loop device */
 #ifdef MS_NOATIME
   { "atime",    0, 1, MS_NOATIME },     /* Update access time */
   { "noatime",  0, 0, MS_NOATIME },     /* Do not update access time */
@@ -121,6 +143,15 @@ static char * fix_opts_string (int flags, const char *extra_opts) {
        char *new_opts;
 
        new_opts = xstrdup((flags & MS_RDONLY) ? "ro" : "rw");
+       if (flags & MS_USER) {
+               /* record who mounted this so they can unmount */
+               struct passwd *pw = getpwuid(getuid());
+               if(pw)
+                       new_opts = xstrconcat3(new_opts, ",user=", pw->pw_name);
+       }
+       if (flags & MS_USERS)
+               new_opts = xstrconcat3(new_opts, ",users", "");
+       
        for (om = opt_map; om->opt != NULL; om++) {
                if (om->skip)
                        continue;
@@ -139,7 +170,6 @@ static char * fix_opts_string (int flags, const char *extra_opts) {
 int add_mtab(char *fsname, char *mount_point, char *fstype, int flags, char *opts, int freq, int passno)
 {
        struct mntent ment;
-       int fd;
        FILE *mtab;
 
        ment.mnt_fsname = fsname;
@@ -149,11 +179,12 @@ int add_mtab(char *fsname, char *mount_point, char *fstype, int flags, char *opt
        ment.mnt_freq = 0;
        ment.mnt_passno= 0;
 
-       if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1) {
-               fprintf(stderr, "Can't get "MOUNTED"~ lock file");
-               return 1;
+       if(flags & MS_REMOUNT) {
+               update_mtab(ment.mnt_dir, &ment);
+               return 0;
        }
-        close(fd);
+
+       lock_mtab();
 
         if ((mtab = setmntent(MOUNTED, "a+")) == NULL) {
                fprintf(stderr, "Can't open " MOUNTED);
@@ -161,21 +192,22 @@ int add_mtab(char *fsname, char *mount_point, char *fstype, int flags, char *opt
        }
 
         if (addmntent(mtab, &ment) == 1) {
+               endmntent(mtab);
+               unlock_mtab();
                fprintf(stderr, "Can't write mount entry");
                return 1;
        }
 
         if (fchmod(fileno(mtab), 0644) == -1) {
+               endmntent(mtab);
+               unlock_mtab();
                fprintf(stderr, "Can't set perms on " MOUNTED);
                return 1;
        }
 
        endmntent(mtab);
 
-       if (unlink(MOUNTED"~") == -1) {
-               fprintf(stderr, "Can't remove "MOUNTED"~");
-               return 1;
-       }
+       unlock_mtab();
 
        return 0;
 }
@@ -194,6 +226,7 @@ void mount_usage()
        printf("\t-w\t\tMount file system read-write\n");
        printf("\t-f\t\tFake mount, don't actually mount\n");
        printf("\t-n\t\tDo not update /etc/mtab\n");
+       printf("\t-s\t\tTolerate sloppy mount options rather than failing.\n");
        printf("\t-h\t\tPrint this help\n");
        printf("\tversion\t\tnfs4 - NFS version 4, nfs - older NFS version supported\n");
        printf("\tnfsoptions\tRefer mount.nfs(8) or nfs(5)\n\n");
@@ -246,48 +279,62 @@ static void mount_error(char *node)
 {
        switch(errno) {
                case ENOTDIR:
-                       printf("%s: mount point %s is not a directory\n", progname, node);
+                       fprintf(stderr, "%s: mount point %s is not a directory\n", progname, node);
                        break;
                case EBUSY:
-                       printf("%s: %s is already mounted or busy\n", progname, node);
+                       fprintf(stderr, "%s: %s is already mounted or busy\n", progname, node);
                        break;
                case ENOENT:
-                       printf("%s: mount point %s does not exist\n", progname, node);
+                       fprintf(stderr, "%s: mount point %s does not exist\n", progname, node);
                        break;
                default:
-                       printf("%s: %s\n", progname, strerror(errno));
+                       fprintf(stderr, "%s: %s\n", progname, strerror(errno));
        }
 }
 
+static void start_statd()
+{
+       /* If /var/run/rpc.statd.pid exists and is non-empty,
+        * assume statd already running.
+        * If START_STATD not defined, or defined to a non-existent file,
+        * don't bother,
+        * else run that file (typically a shell script)
+        */
+       struct stat stb;
+       if (stat("/var/run/rpc.statd.pid", &stb) == 0 &&
+           stb.st_size > 0)
+               return;
+#ifdef START_STATD
+       if (stat(START_STATD, &stb) ==0 &&
+           S_ISREG(stb.st_mode) &&
+           (stb.st_mode & S_IXUSR))
+               system(START_STATD);
+#endif
+}
+
 int main(int argc, char *argv[])
 {
        int c, flags = 0, nfs_mount_vers = 0, mnt_err = 1, fake = 0;
        char *spec, *mount_point, *extra_opts = NULL;
        char *mount_opts = NULL, *p;
+       uid_t uid = getuid();
 
        progname = argv[0];
+       if (!progname)
+               exit(2);
+
        if ((p = strrchr(progname, '/')) != NULL)
                progname = p+1;
 
-       if (getuid() != 0) {
-               printf("%s: only root can do that.\n", progname);
-               exit(1);
-       }
-
        if(!strncmp(progname, "umount", strlen("umount"))) {
                if(argc < 2) {
                        umount_usage();
                        exit(1);
                }
-               return(nfsumount(argc, argv));
-       }
-
-       if ((argc < 2)) {
-               mount_usage();
-               exit(1);
+               exit(nfsumount(argc, argv) ? 0 : 1);
        }
 
-       if(argv[1][0] == '-') {
+       if(argv[1] && argv[1][0] == '-') {
                if(argv[1][1] == 'V')
                        printf("%s ("PACKAGE_STRING")\n", progname);
                else
@@ -295,14 +342,31 @@ int main(int argc, char *argv[])
                return 0;
        }
 
-       while ((c = getopt_long (argc - 2, argv + 2, "rt:vVwfno:h",
+       if ((argc < 3)) {
+               mount_usage();
+               exit(1);
+       }
+
+       spec = argv[1];
+       mount_point = argv[2];
+
+       argv[2] = argv[0]; /* so that getopt error messages are correct */
+       while ((c = getopt_long (argc - 2, argv + 2, "rt:vVwfno:hs",
                                longopts, NULL)) != -1) {
                switch (c) {
                case 'r':
                        flags |= MS_RDONLY;
                        break;
                case 't':
-                       nfs_mount_vers = (strncmp(optarg, "nfs4", 4)) ? 0 : 4;
+                       if (strcmp(optarg, "nfs4") == 0)
+                               nfs_mount_vers = 4;
+                       else if (strcmp(optarg, "nfs") == 0)
+                               nfs_mount_vers = 0;
+                       else {
+                               fprintf(stderr, "%s: unknown filesystem type: %s\n",
+                                       progname, optarg);
+                               exit(1);
+                       }
                        break;
                case 'v':
                        ++verbose;
@@ -325,6 +389,9 @@ int main(int argc, char *argv[])
                        else
                                mount_opts = xstrdup(optarg);
                        break;
+               case 's':
+                       ++sloppy;
+                       break;
                case 128: /* bind */
                        mounttype = MS_BIND;
                        break;
@@ -352,36 +419,79 @@ int main(int argc, char *argv[])
                        exit(1);
                }
        }
+       if (optind != argc-2) {
+               /* Extra non-option words at the end... */
+               mount_usage();
+               exit(1);
+       }
 
-       spec = argv[1];
-       mount_point = canonicalize(argv[2]);
+       if (strcmp(progname, "mount.nfsv4") == 0)
+               nfs_mount_vers = 4;
+
+       if (uid != 0) {
+               /* don't even think about it unless options exactly
+                * match fstab
+                */
+               struct mntentchn *mc;
+
+               if ((mc = getfsfile(mount_point)) == NULL ||
+                   strcmp(mc->m.mnt_fsname, spec) != 0 ||
+                   strcmp(mc->m.mnt_type, (nfs_mount_vers == 4 ? "nfs4":"nfs")) != 0 || 
+                   strcmp(mc->m.mnt_opts, mount_opts) != 0) {
+                       fprintf(stderr, "%s: permission died - no match for fstab\n",
+                               progname);
+                       exit(1);
+               }
+               mounttype = 0;
+       }
+
+       mount_point = canonicalize(mount_point);
+       if (mount_point == NULL ||
+           mount_point[0] != '/') {
+               fprintf(stderr, "%s: unknown mount point %s\n",
+                       progname, mount_point ? : "");
+               exit(1);
+       }
        
        parse_opts(mount_opts, &flags, &extra_opts);
 
-       if (!strcmp(progname, "mount.nfs4") || nfs_mount_vers == 4) {
-               nfs_mount_vers = 4;
-               mnt_err = nfs4mount(spec, mount_point, &flags, &extra_opts, &mount_opts, 0);
+       if (uid != 0) {
+           if (! (flags & (MS_USERS | MS_USER))) {
+                   fprintf(stderr, "%s: permission denied\n", progname);
+                   exit(1);
+           }
        }
+
+       if (nfs_mount_vers == 4)
+               mnt_err = nfs4mount(spec, mount_point, &flags, &extra_opts, &mount_opts, 0);
        else {
-               if (!strcmp(progname, "mount.nfs")) {
-                       mnt_err = nfsmount(spec, mount_point, &flags,
-                                       &extra_opts, &mount_opts, &nfs_mount_vers, 0);
-               }
+               int need_statd = 0;
+               mnt_err = nfsmount(spec, mount_point, &flags,
+                                  &extra_opts, &mount_opts,
+                                  0, &need_statd);
+               if (!mnt_err && !fake && need_statd)
+                       start_statd();
        }
 
-       if (!mnt_err && !fake) {
-               mnt_err = do_mount_syscall(spec, mount_point, nfs_mount_vers == 4 ? "nfs4" : "nfs", flags, mount_opts);
-               
-               if(mnt_err) {
+       if (mnt_err)
+               exit(EX_FAIL);
+
+       if (!fake) {
+               mnt_err = do_mount_syscall(spec, mount_point,
+                                          nfs_mount_vers == 4 ? "nfs4" : "nfs",
+                                          flags, mount_opts);
+
+               if (mnt_err) {
                        mount_error(mount_point);
-                       exit(-1);
+                       exit(EX_FAIL);
                }
-
-               if(!nomtab)
-                       add_mtab(spec, mount_point, nfs_mount_vers == 4 ? "nfs4" : "nfs",
-                                flags, extra_opts, 0, 0);
        }
 
+       if (!nomtab)
+               add_mtab(spec, mount_point,
+                        nfs_mount_vers == 4 ? "nfs4" : "nfs",
+                        flags, extra_opts, 0, 0);
+
        return 0;
 }