X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fmount%2Fnfsumount.c;h=91d0e85627fa437c3d3d243f8b9ee3ac1a45e21e;hp=c91bfd2d9958ba41c5519d34f074ae09d20ae704;hb=f014bb7f4dbdc45572849465a6410512abffa7ea;hpb=0a2950956d05f8069cd698e28479cbf14a3bba86 diff --git a/utils/mount/nfsumount.c b/utils/mount/nfsumount.c index c91bfd2..91d0e85 100644 --- a/utils/mount/nfsumount.c +++ b/utils/mount/nfsumount.c @@ -17,12 +17,14 @@ * */ +#include #include #include #include #include #include #include +#include #include "xcommon.h" #include "fstab.h" @@ -32,6 +34,7 @@ #include "mount_constants.h" #include "mount.h" #include "nfsumount.h" +#include "error.h" #if !defined(MNT_FORCE) /* dare not try to include -- lots of errors */ @@ -43,14 +46,12 @@ #endif extern char *progname; -extern int nfs_mount_version; extern int nomtab; extern int verbose; int force; int lazy; int remount; -extern int find_kernel_nfs_mount_version(void); extern int probe_mntport(clnt_addr_t *); extern int nfs_gethostbyname(const char *, struct sockaddr_in *); @@ -91,60 +92,11 @@ int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp) return res; } -struct mntentchn * -getmntentchn(const char *dir) +int del_mtab(const char *spec, const char *node) { - mntFILE *mfp; - nfs_mntent_t *mnt; - struct mntentchn *mc = NULL; + int umnt_err, res; - 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) { - case ENXIO: - nfs_error (_("umount: %s: invalid block device"), dev); break; - case EINVAL: - nfs_error (_("umount: %s: not mounted"), dev); break; - case EIO: - nfs_error (_("umount: %s: can't write superblock"), dev); break; - case EBUSY: - /* Let us hope fstab has a line "proc /proc ..." - and not "none /proc ..."*/ - nfs_error (_("umount: %s: device is busy"), dev); break; - case ENOENT: - nfs_error (_("umount: %s: not found"), dev); break; - case EPERM: - nfs_error (_("umount: %s: must be superuser to umount"), dev); break; - case EACCES: - nfs_error (_("umount: %s: block devices not permitted on fs"), dev); break; - default: - nfs_error (_("umount: %s: %s"), dev, strerror (err)); break; - } -} - -int add_mtab2(const char *spec, const char *node, const char *type, - const char *opts, struct mntentchn *mc) -{ - int umnt_err, umnt_err2, res; - - umnt_err = umnt_err2 = 0; + umnt_err = 0; if (lazy) { res = umount2 (node, MNT_DETACH); if (res < 0) @@ -167,32 +119,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,29 +145,27 @@ 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) - complain(umnt_err, node); + if (umnt_err) + umount_error(umnt_err, node); return 1; } /* * 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; @@ -244,7 +174,6 @@ int _nfsumount(const char *spec, const char *opts) struct pmap *pmap = &mnt_server.pmap; char *p; - nfs_mount_version = find_kernel_nfs_mount_version(); if (spec == NULL || (p = strchr(spec,':')) == NULL) goto out_bad; hostname = xstrndup(spec, p-spec); @@ -297,7 +226,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; } @@ -333,6 +262,7 @@ int nfsumount(int argc, char *argv[]) argv += 1; argc -= 1; + argv[0] = argv[-1]; /* So that getopt error messages are correct */ while ((c = getopt_long (argc, argv, "fvnrlh", umount_longopts, NULL)) != -1) { @@ -358,32 +288,75 @@ 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) { + /* umount might call us twice. The second time there will + * be no entry in mtab and we should just exit quietly + */ + return 0; + + 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[4] != '=') + 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) + _nfsumount(mc->m.mnt_fsname, mc->m.mnt_opts); + ret = del_mtab(mc->m.mnt_fsname, mc->m.mnt_dir); + } else if (*spec != '/') { + if (!lazy) + _nfsumount(spec, "tcp,v3"); + } else + ret = del_mtab(NULL, spec); + return(ret); }