/* returns: error = -1, success = 0 , unknown = 1 */ static int is_vers4(struct libmnt_context *cxt) { struct libmnt_fs *fs = mnt_context_get_fs(cxt); struct libmnt_table *tb = NULL; const char *src = mnt_context_get_source(cxt), *tgt = mnt_context_get_target(cxt); int rc = 1; if (!src || !tgt) return -1; if (!mnt_fs_is_kernel(fs)) { struct libmnt_table *tb = mnt_new_table_from_file("/proc/mounts"); if (!tb) return -1; fs = mnt_table_find_pair(tb, src, tgt, MNT_ITER_BACKWARD); } if (fs) { const char *type = mnt_fs_get_fstype(fs); if (type && strcmp(type, "nfs4") == 0) rc = 0; } mnt_free_table(tb); return rc; }
/** * mnt_context_prepare_umount: * @cxt: mount context * * Prepare context for umounting, unnecessary for mnt_context_umount(). * * Returns: 0 on success, and negative number in case of error. */ int mnt_context_prepare_umount(struct libmnt_context *cxt) { int rc; assert(cxt); assert(cxt->fs); assert(cxt->helper_exec_status == 1); assert(cxt->syscall_status == 1); if (!cxt || !cxt->fs || mnt_fs_is_swaparea(cxt->fs)) return -EINVAL; if (!mnt_context_get_source(cxt) && !mnt_context_get_target(cxt)) return -EINVAL; if (cxt->flags & MNT_FL_PREPARED) return 0; free(cxt->helper); /* be paranoid */ cxt->helper = NULL; cxt->action = MNT_ACT_UMOUNT; rc = lookup_umount_fs(cxt); if (!rc) rc = mnt_context_merge_mflags(cxt); if (!rc) rc = evaluate_permissions(cxt); if (!rc && !cxt->helper) { if (cxt->user_mountflags & MNT_MS_HELPER) /* on helper= mount option based helper */ rc = prepare_helper_from_options(cxt, "helper"); if (!rc && !cxt->helper) /* on fstype based helper */ rc = mnt_context_prepare_helper(cxt, "umount", NULL); } if (!rc && (cxt->user_mountflags & MNT_MS_LOOP)) /* loop option explicitly specified in mtab, detach this loop */ mnt_context_enable_loopdel(cxt, TRUE); if (!rc && mnt_context_is_loopdel(cxt) && cxt->fs) { const char *src = mnt_fs_get_srcpath(cxt->fs); if (src && (!is_loopdev(src) || loopdev_is_autoclear(src))) mnt_context_enable_loopdel(cxt, FALSE); } if (rc) { DBG(CXT, mnt_debug_h(cxt, "umount: preparing failed")); return rc; } cxt->flags |= MNT_FL_PREPARED; return rc; }
/* * this has to be called before fix_optstr() */ static int evaluate_permissions(struct libmnt_context *cxt) { unsigned long u_flags = 0; assert(cxt); assert(cxt->fs); assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED)); if (!cxt) return -EINVAL; if (!cxt->fs) return 0; DBG(CXT, mnt_debug_h(cxt, "mount: evaluating permissions")); mnt_context_get_user_mflags(cxt, &u_flags); if (!mnt_context_is_restricted(cxt)) { /* * superuser mount */ cxt->user_mountflags &= ~MNT_MS_OWNER; cxt->user_mountflags &= ~MNT_MS_GROUP; cxt->user_mountflags &= ~MNT_MS_USER; cxt->user_mountflags &= ~MNT_MS_USERS; } else { /* * user mount */ if (!(cxt->flags & MNT_FL_TAB_APPLIED)) { DBG(CXT, mnt_debug_h(cxt, "perms: fstab not applied, ignore user mount")); return -EPERM; } /* * Note that MS_OWNERSECURE and MS_SECURE mount options * are applied by mnt_optstr_get_flags() from mnt_context_merge_mflags() */ /* * MS_OWNER: Allow owners to mount when fstab contains the * owner option. Note that this should never be used in a high * security environment, but may be useful to give people at * the console the possibility of mounting a floppy. MS_GROUP: * Allow members of device group to mount. (Martin Dickopp) */ if (u_flags & (MNT_MS_OWNER | MNT_MS_GROUP)) { struct stat sb; struct libmnt_cache *cache = NULL; char *xsrc = NULL; const char *srcpath = mnt_fs_get_srcpath(cxt->fs); if (!srcpath) { /* Ah... source is TAG */ cache = mnt_context_get_cache(cxt); xsrc = mnt_resolve_spec( mnt_context_get_source(cxt), cache); srcpath = xsrc; } if (!srcpath) { DBG(CXT, mnt_debug_h(cxt, "perms: src undefined")); return -EPERM; } if (strncmp(srcpath, "/dev/", 5) == 0 && stat(srcpath, &sb) == 0 && (((u_flags & MNT_MS_OWNER) && getuid() == sb.st_uid) || ((u_flags & MNT_MS_GROUP) && mnt_in_group(sb.st_gid)))) cxt->user_mountflags |= MNT_MS_USER; if (!cache) free(xsrc); } if (!(cxt->user_mountflags & (MNT_MS_USER | MNT_MS_USERS))) { DBG(CXT, mnt_debug_h(cxt, "permissions evaluation ends with -EPERMS")); return -EPERM; } } return 0; }
static int mount_main(struct libmnt_context *cxt, int argc, char **argv) { int rc, c; struct libmnt_fs *fs; char *spec = NULL, *mount_point = NULL, *opts = NULL; static const struct option longopts[] = { { "fake", 0, 0, 'f' }, { "help", 0, 0, 'h' }, { "no-mtab", 0, 0, 'n' }, { "read-only", 0, 0, 'r' }, { "ro", 0, 0, 'r' }, { "verbose", 0, 0, 'v' }, { "version", 0, 0, 'V' }, { "read-write", 0, 0, 'w' }, { "rw", 0, 0, 'w' }, { "options", 1, 0, 'o' }, { "sloppy", 0, 0, 's' }, { NULL, 0, 0, 0 } }; mount_config_init(progname); mnt_context_init_helper(cxt, MNT_ACT_MOUNT, 0); while ((c = getopt_long(argc, argv, "fhnrVvwo:s", longopts, NULL)) != -1) { rc = mnt_context_helper_setopt(cxt, c, optarg); if (rc == 0) /* valid option */ continue; if (rc < 0) /* error (probably ENOMEM) */ goto err; /* rc==1 means unknow option */ switch (c) { case 'V': printf("%s: ("PACKAGE_STRING")\n", progname); return EX_SUCCESS; case 'h': default: mount_usage(); return EX_USAGE; } } if (optind < argc) spec = argv[optind++]; if (optind < argc) mount_point = argv[optind++]; if (!mount_point) { nfs_error(_("%s: no mount point provided"), progname); goto err; } if (!spec) { nfs_error(_("%s: no mount spec provided"), progname); goto err; } if (geteuid() != 0) { nfs_error(_("%s: not installed setuid - " "\"user\" NFS mounts not supported."), progname); goto err; } verbose = mnt_context_is_verbose(cxt); sloppy = mnt_context_is_sloppy(cxt); nomtab = mnt_context_is_nomtab(cxt); if (strcmp(progname, "mount.nfs4") == 0) mnt_context_set_fstype(cxt, "nfs4"); else mnt_context_set_fstype(cxt, "nfs"); /* default */ rc = mnt_context_set_source(cxt, spec); if (!rc) mnt_context_set_target(cxt, mount_point); if (rc) { nfs_error(_("%s: failed to set spec or mountpoint: %s"), progname, strerror(errno)); goto err; } mount_point = mnt_resolve_path(mount_point, mnt_context_get_cache(cxt)); if (chk_mountpoint(mount_point)) goto err; /* * Concatenate mount options from the configuration file */ fs = mnt_context_get_fs(cxt); if (fs) { opts = mnt_fs_strdup_options(fs); opts = mount_config_opts(spec, mount_point, opts); mnt_fs_set_options(fs, opts); } rc = mnt_context_prepare_mount(cxt); if (rc) { nfs_error(_("%s: failed to prepare mount: %s\n"), progname, strerror(-rc)); goto err; } rc = try_mount(cxt, FOREGROUND); if (rc == EX_BG) { printf(_("%s: backgrounding \"%s\"\n"), progname, mnt_context_get_source(cxt)); printf(_("%s: mount options: \"%s\"\n"), progname, opts); fflush(stdout); if (daemon(0, 0)) { nfs_error(_("%s: failed to start " "background process: %s\n"), progname, strerror(errno)); exit(EX_FAIL); } rc = try_mount(cxt, BACKGROUND); if (verbose && rc) printf(_("%s: giving up \"%s\"\n"), progname, mnt_context_get_source(cxt)); } mnt_context_set_syscall_status(cxt, rc == EX_SUCCESS ? 0 : -1); mnt_context_finalize_mount(cxt); /* mtab update */ return rc; err: return EX_FAIL; }
static int umount_main(struct libmnt_context *cxt, int argc, char **argv) { int rc, c; char *spec = NULL, *opts = NULL; static const struct option longopts[] = { { "force", 0, 0, 'f' }, { "help", 0, 0, 'h' }, { "no-mtab", 0, 0, 'n' }, { "verbose", 0, 0, 'v' }, { "read-only", 0, 0, 'r' }, { "lazy", 0, 0, 'l' }, { "types", 1, 0, 't' }, { NULL, 0, 0, 0 } }; mnt_context_init_helper(cxt, MNT_ACT_UMOUNT, 0); while ((c = getopt_long (argc, argv, "fvnrlh", longopts, NULL)) != -1) { rc = mnt_context_helper_setopt(cxt, c, optarg); if (rc == 0) /* valid option */ continue; if (rc < 0) /* error (probably ENOMEM) */ goto err; /* rc==1 means unknow option */ umount_usage(); return EX_USAGE; } if (optind < argc) spec = argv[optind++]; if (!spec || (*spec != '/' && strchr(spec,':') == NULL)) { nfs_error(_("%s: no mount point provided"), progname); return EX_USAGE; } if (mnt_context_set_target(cxt, spec)) goto err; if (mnt_context_set_fstype_pattern(cxt, "nfs,nfs4")) /* restrict filesystems */ goto err; /* read mtab/fstab, evaluate permissions, etc. */ rc = mnt_context_prepare_umount(cxt); if (rc) { nfs_error(_("%s: failed to prepare umount: %s\n"), progname, strerror(-rc)); goto err; } opts = retrieve_mount_options(mnt_context_get_fs(cxt)); if (!mnt_context_is_lazy(cxt)) { if (opts) { /* we have full FS description (e.g. from mtab or /proc) */ switch (is_vers4(cxt)) { case 0: /* We ignore the error from nfs_umount23. * If the actual umount succeeds (in del_mtab), * we don't want to signal an error, as that * could cause /sbin/mount to retry! */ nfs_umount23(mnt_context_get_source(cxt), opts); break; case 1: /* unknown */ break; default: /* error */ goto err; } } else /* strange, no entry in mtab or /proc not mounted */ nfs_umount23(spec, "tcp,v3"); } rc = mnt_context_do_umount(cxt); /* call umount(2) syscall */ mnt_context_finalize_mount(cxt); /* mtab update */ if (rc && !mnt_context_get_status(cxt)) { /* mnt_context_do_umount() returns errno if umount(2) failed */ umount_error(rc, spec); goto err; } free(opts); return EX_SUCCESS; err: free(opts); return EX_FAIL; }