📄 umount.c
字号:
} } loopdev = 0; if (res >= 0) { /* Umount succeeded */ if (verbose) printf (_("%s umounted\n"), spec); /* Free any loop devices that we allocated ourselves */ if (mc) { char *optl; /* old style mtab line? */ if (streq(mc->m.mnt_type, "loop")) { loopdev = spec; goto gotloop; } /* new style mtab line? */ optl = mc->m.mnt_opts ? xstrdup(mc->m.mnt_opts) : ""; for (optl = strtok (optl, ","); optl; optl = strtok (NULL, ",")) { if (!strncmp(optl, "loop=", 5)) { loopdev = optl+5; goto gotloop; } } } else { /* * If option "-o loop=spec" occurs in mtab, * note the mount point, and delete mtab line. */ if ((mc = getmntoptfile (spec)) != NULL) node = mc->m.mnt_dir; } /* Also free loop devices when -d flag is given */ if (delloop && is_loop_device(spec)) loopdev = spec; } gotloop: if (loopdev) del_loop(loopdev); writemtab: if (!nomtab && mtab_is_writable() && (umnt_err == 0 || umnt_err == EINVAL || umnt_err == ENOENT)) { 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); return 1;}/* * umount_one_bw: unmount FILE that has last occurrence MC0 * * Why this loop? * 1. People who boot a system with a bad fstab root entry * will get an incorrect "/dev/foo on /" in mtab. * If later /dev/foo is actually mounted elsewhere, * it will occur twice in mtab. * 2. With overmounting one can get the situation that * the same filename is used as mount point twice. * In both cases, it is best to try the last occurrence first. */static intumount_one_bw (const char *file, struct mntentchn *mc0) { struct mntentchn *mc; int res = 1; mc = mc0; while (res && mc) { res = umount_one(mc->m.mnt_fsname, mc->m.mnt_dir, mc->m.mnt_type, mc->m.mnt_opts, mc); mc = getmntdirbackward(file, mc); } mc = mc0; while (res && mc) { res = umount_one(mc->m.mnt_fsname, mc->m.mnt_dir, mc->m.mnt_type, mc->m.mnt_opts, mc); mc = getmntdevbackward(file, mc); } return res;}/* Unmount all filesystems of type VFSTYPES found in mtab. Since we are concurrently updating mtab after every successful umount, we have to slurp in the entire file before we start. This isn't too bad, because in any case it's important to umount mtab entries in reverse order to mount, e.g. /usr/spool before /usr. */static intumount_all (char *types, char *test_opts) { struct mntentchn *mc, *hd; int errors = 0; hd = mtab_head(); if (!hd->prev) die (2, _("umount: cannot find list of filesystems to unmount")); for (mc = hd->prev; mc != hd; mc = mc->prev) { if (matching_type (mc->m.mnt_type, types) && matching_opts (mc->m.mnt_opts, test_opts)) { errors |= umount_one (mc->m.mnt_fsname, mc->m.mnt_dir, mc->m.mnt_type, mc->m.mnt_opts, mc); } } sync (); return errors;}extern char version[];static struct option longopts[] ={ { "all", 0, 0, 'a' }, { "force", 0, 0, 'f' }, { "help", 0, 0, 'h' }, { "no-mtab", 0, 0, 'n' }, { "test-opts", 1, 0, 'O' }, { "verbose", 0, 0, 'v' }, { "version", 0, 0, 'V' }, { "read-only", 0, 0, 'r' }, { "types", 1, 0, 't' }, { NULL, 0, 0, 0 }};static voidusage (FILE *fp, int n){ fprintf (fp, _("Usage: umount [-hV]\n" " umount -a [-f] [-r] [-n] [-v] [-t vfstypes] [-O opts]\n" " umount [-f] [-r] [-n] [-v] special | node...\n")); exit (n);}int mount_quiet = 0;/* * Look for an option in a comma-separated list */static intcontains(const char *list, const char *s) { int n = strlen(s); while (*list) { if (strncmp(list, s, n) == 0 && (list[n] == 0 || list[n] == ',')) return 1; while (*list && *list++ != ',') ; } return 0;}/* * If list contains "user=peter" and we ask for "user=", return "peter" */static char *get_value(const char *list, const char *s) { const char *t; int n = strlen(s); while (*list) { if (strncmp(list, s, n) == 0) { s = t = list+n; while (*s && *s != ',') s++; return xstrndup(t, s-t); } while (*list && *list++ != ',') ; } return 0;}static intumount_file (char *arg) { struct mntentchn *mc, *fs; const char *file, *options; int fstab_has_user, fstab_has_users, fstab_has_owner, fstab_has_group; int ok; file = canonicalize(arg); /* mtab paths are canonicalized */ if (verbose > 1) printf(_("Trying to umount %s\n"), file); mc = getmntdirbackward(file, NULL); if (!mc) mc = getmntdevbackward(file, NULL); if (!mc && verbose) printf(_("Could not find %s in mtab\n"), file); if (suid) { char *mtab_user = NULL; if (!mc) die(2, _("umount: %s is not mounted (according to mtab)"), file); if (!is_mounted_once(file)) die(2, _("umount: it seems %s is mounted multiple times"), file); /* If fstab contains the two lines /dev/sda1 /mnt/zip auto user,noauto 0 0 /dev/sda4 /mnt/zip auto user,noauto 0 0 then "mount /dev/sda4" followed by "umount /mnt/zip" used to fail. So, we must not look for file, but for the pair (spec,file) in fstab. */ fs = getfsspecfile(mc->m.mnt_fsname, mc->m.mnt_dir); if (!fs) { if (!getfsspec (file) && !getfsfile (file)) die (2, _("umount: %s is not in the fstab " "(and you are not root)"), file); else die (2, _("umount: %s mount disagrees with " "the fstab"), file); } /* * User mounting and unmounting is allowed only * if fstab contains one of the options `user', * `users' or `owner' or `group'. * * The option `users' allows arbitrary users to mount * and unmount - this may be a security risk. * * The options `user', `owner' and `group' only allow * unmounting by the user that mounted (visible in mtab). */ options = fs->m.mnt_opts; if (!options) options = ""; fstab_has_user = contains(options, "user"); fstab_has_users = contains(options, "users"); fstab_has_owner = contains(options, "owner"); fstab_has_group = contains(options, "group"); ok = 0; if (fstab_has_users) ok = 1; if (!ok && (fstab_has_user || fstab_has_owner || fstab_has_group)) { char *user = getusername(); options = mc->m.mnt_opts; if (!options) options = ""; mtab_user = get_value(options, "user="); if (user && mtab_user && streq (user, mtab_user)) ok = 1; } if (!ok) die (2, _("umount: only %s can unmount %s from %s"), mtab_user ? mtab_user : "root", fs->m.mnt_fsname, fs->m.mnt_dir); } if (mc) return umount_one_bw (file, mc); else return umount_one (arg, arg, arg, arg, NULL);}char *progname;intmain (int argc, char *argv[]) { int c; int all = 0; char *types = NULL, *test_opts = NULL, *p; int result = 0; sanitize_env(); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); progname = argv[0]; if ((p = strrchr(progname, '/')) != NULL) progname = p+1; umask(033); while ((c = getopt_long (argc, argv, "adfhlnrit:O:vV", longopts, NULL)) != -1) switch (c) { case 'a': /* umount everything */ ++all; break; /* fall through? */ case 'd': /* do losetup -d for unmounted loop devices */ ++delloop; break; case 'f': /* force umount */ ++force; break; case 'h': /* help */ usage (stdout, 0); break; case 'l': /* lazy umount */ ++lazy; break; case 'n': /* do not write in /etc/mtab */ ++nomtab; break; case 'O': /* specify file system options */ test_opts = optarg; break; case 'r': /* remount read-only if umount fails */ ++remount; break; case 'v': /* make noise */ ++verbose; break; case 'V': /* version */ printf ("umount: %s\n", version); exit (0); case 't': /* specify file system type */ types = optarg; break; case 'i': external_allowed = 0; break; case 0: break; case '?': default: usage (stderr, 1); } if (getuid () != geteuid ()) { suid = 1; if (all || types || nomtab || force) die (2, _("umount: only root can do that")); } argc -= optind; argv += optind; if (all) { /* nodev stuff: sysfs, usbfs, oprofilefs, ... */ if (types == NULL) types = "noproc,nodevfs,nodevpts"; result = umount_all (types, test_opts); } else if (argc < 1) { usage (stderr, 2); } else while (argc--) { result += umount_file(*argv++); } exit (result); /* nonzero on at least one failure */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -