]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - utils/mount/nfsumount.c
umount.nfs - more strict checks on command line args.
[nfs-utils.git] / utils / mount / nfsumount.c
index c91bfd2d9958ba41c5519d34f074ae09d20ae704..e101105268d3bdd9bd42a49ca3649b3b17250383 100644 (file)
  *
  */
 
+#include <unistd.h>
 #include <stdio.h>
 #include <errno.h>
 #include <getopt.h>
 #include <mntent.h>
 #include <sys/mount.h>
 #include <ctype.h>
+#include <pwd.h>
 
 #include "xcommon.h"
 #include "fstab.h"
@@ -91,30 +93,6 @@ int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp)
        return res;
 }
 
-struct mntentchn *
-getmntentchn(const char *dir)
-{
-       mntFILE *mfp;
-       nfs_mntent_t *mnt;
-       struct mntentchn *mc = NULL;
-
-       mfp = nfs_setmntent ("/proc/mounts", "r");
-       if (mfp == NULL || mfp->mntent_fp == NULL)
-               return NULL;
-
-       while ((mnt = nfs_getmntent(mfp)) != NULL) {
-               if(strcmp(mnt->mnt_fsname, dir) && strcmp(mnt->mnt_dir, dir))
-                       continue;
-
-               if (!mc)
-                       mc = (struct mntentchn *)xmalloc(sizeof(*mc));
-               mc->m = *mnt;
-       }
-
-       nfs_endmntent(mfp);
-       return mc;
-}
-
 /* complain about a failed umount */
 static void complain(int err, const char *dev) {
   switch (err) {
@@ -139,12 +117,11 @@ static void complain(int err, const char *dev) {
   }
 }
 
-int add_mtab2(const char *spec, const char *node, const char *type,
-               const char *opts, struct mntentchn *mc)
+int del_mtab(const char *spec, const char *node)
 {
-       int umnt_err, umnt_err2, res;
+       int umnt_err, res;
 
-        umnt_err = umnt_err2 = 0;
+        umnt_err = 0;
         if (lazy) {
                 res = umount2 (node, MNT_DETACH);
                 if (res < 0)
@@ -167,32 +144,12 @@ int add_mtab2(const char *spec, const char *node, const char *type,
         } else
                 res = umount (node);
 
-        if (res < 0) {
-                umnt_err = errno;
-                /* A device might have been mounted on a node that has since
-                   been deleted or renamed, so if node fails, also try spec. */
-                /* Note that this is incorrect in case spec was mounted
-                   several times. */
-                /* if (umnt_err == ENOENT || umnt_err == EINVAL) */
-                if (umnt_err != EBUSY && strcmp(node, spec)) {
-                        if (verbose)
-                                printf (_("could not umount %s - trying %s instead\n"),
-                                        node, spec);
-                        res = umount (spec);
-                        if (res < 0)
-                                umnt_err2 = errno;
-                       /* Do not complain about remote NFS mount points */
-                        if (errno == ENOENT && index(spec, ':'))
-                                umnt_err2 = 0;
-                }
-        }
-
-        if (res < 0 && remount && (umnt_err == EBUSY || umnt_err2 == EBUSY)) {
+        if (res < 0 && remount && errno == EBUSY && spec) {
                 /* Umount failed - let us try a remount */
                 res = mount(spec, node, NULL,
                             MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL);
                 if (res == 0) {
-                        nfs_mntent_t remnt;
+                        struct mntent remnt;
                         fprintf(stderr,
                                 _("umount: %s busy - remounted read-only\n"),
                                 spec);
@@ -213,21 +170,19 @@ int add_mtab2(const char *spec, const char *node, const char *type,
         if (res >= 0) {
                 /* Umount succeeded */
                 if (verbose)
-                        printf (_("%s umounted\n"), spec);
+                        printf (_("%s umounted\n"), spec ? spec : node);
         }
 
  writemtab:
         if (!nomtab &&
             (umnt_err == 0 || umnt_err == EINVAL || umnt_err == ENOENT)) {
-               update_mtab (node, NULL);
+               update_mtab(node, NULL);
         }
 
         if (res >= 0)
                 return 0;
 
-        if (umnt_err2)
-                complain(umnt_err2, spec);
-        if (umnt_err && umnt_err != umnt_err2)
+        if (umnt_err)
                 complain(umnt_err, node);
         return 1;
 }
@@ -235,7 +190,7 @@ int add_mtab2(const char *spec, const char *node, const char *type,
 /*
  * Returns 1 if everything went well, else 0.
  */
-int _nfsumount(const char *spec, const char *opts)
+int _nfsumount(const char *spec, char *opts)
 {
        char *hostname;
        char *dirname;
@@ -297,7 +252,7 @@ int _nfsumount(const char *spec, const char *opts)
                goto out_bad;
        return nfs_call_umount(&mnt_server, &dirname);
  out_bad:
-       printf("%s: %s: not found or not mounted\n", progname, spec);
+       fprintf(stderr, "%s: %s: not found or not mounted\n", progname, spec);
        return 0;
 }
 
@@ -358,32 +313,71 @@ int nfsumount(int argc, char *argv[])
                        return 0;
                }
        }
+       if (optind != argc) {
+               umount_usage();
+               return 0;
+       }
        
        if (spec == NULL || (*spec != '/' && strchr(spec,':') == NULL)) {
                printf(_("umount: %s: not found\n"), spec);
                return 0;
        }
 
-       mc = getmntentchn(spec);
-       if (!mc)
+       if (*spec == '/')
                mc = getmntdirbackward(spec, NULL);
-       if (!mc)
+       else
                mc = getmntdevbackward(spec, NULL);
        if (!mc && verbose)
                printf(_("Could not find %s in mtab\n"), spec);
 
-       if(mc) {
-               ret = _nfsumount(mc->m.mnt_fsname, mc->m.mnt_opts);
-               if(ret)
-                       ret = add_mtab2(mc->m.mnt_fsname, mc->m.mnt_dir,
-                               mc->m.mnt_type, mc->m.mnt_opts, mc);
+       if (mc && strcmp(mc->m.mnt_type, "nfs") != 0 &&
+           strcmp(mc->m.mnt_type, "nfs4") != 0) {
+               fprintf(stderr, "umount.nfs: %s on %s it not an nfs filesystem\n",
+                       mc->m.mnt_fsname, mc->m.mnt_dir);
+               exit(1);
        }
-       else {
-               ret = _nfsumount(spec, NULL);
-               if(ret)
-                       ret = add_mtab2(spec, spec, spec, spec, NULL);
+
+       if (getuid() != 0) {
+               /* only permitted if "user=" or "users" is in mount options */
+               if (!mc) {
+               only_root:
+                       fprintf(stderr,"%s: You are not permitted to unmount %s\n",
+                               progname, spec);
+                       return 0;
+               }
+               if (hasmntopt(&mc->m, "users") == NULL) {
+                       char *opt = hasmntopt(&mc->m, "user");
+                       struct passwd *pw;
+                       char *comma;
+                       int len;
+                       if (!opt)
+                               goto only_root;
+                       if (opt[5] != '=')
+                               goto only_root;
+                       comma = strchr(opt, ',');
+                       if (comma)
+                               len = comma - (opt + 5);
+                       else
+                               len = strlen(opt+5);
+                       pw = getpwuid(getuid());
+                       if (pw == NULL || strlen(pw->pw_name) != len
+                           || strncmp(pw->pw_name, opt+5, len) != 0)
+                               goto only_root;
+               }
        }
 
+       ret = 0;
+       if (mc) {
+               if (!lazy)
+                       ret = _nfsumount(mc->m.mnt_fsname, mc->m.mnt_opts);
+               if(ret)
+                       ret = del_mtab(mc->m.mnt_fsname, mc->m.mnt_dir);
+       } else if (*spec != '/') {
+               if (!lazy)
+                       ret = _nfsumount(spec, "tcp,v3");
+       } else
+               ret = del_mtab(NULL, spec);
+
        return(ret);
 }