static int mounted(const char *spec, const char *node) { struct mntentchn *mc; char *fsname = canonicalize(spec); char *dir = canonicalize(node); int ret = 0; mc = getmntdirbackward(dir, NULL); while (mc) { if (strcmp(mc->m.mnt_type, fstype) == 0 && (fsname == NULL || strcmp(mc->m.mnt_fsname, fsname) == 0)) { ret = 1; break; } mc = getmntdirbackward(dir, mc); } my_free(fsname); my_free(dir); return ret; }
/* * 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 int umount_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; }
static int umount_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; if (!*arg) { /* "" would be expanded to `pwd` */ die(2, _("Cannot umount \"\"\n")); return 0; } 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) { struct mntentchn *mc1; mc1 = getmntdirbackward(mc->m.mnt_dir, NULL); if (!mc1) /* 'mc1' must exist, though not necessarily equals to `mc'. Otherwise we go mad. */ die(EX_SOFTWARE, _("umount: confused when analyzing mtab")); if (strcmp(file, mc1->m.mnt_fsname)) { /* Something was stacked over `file' on the same mount point. */ die(EX_FAIL, _("umount: cannot umount %s -- %s is " "mounted over it on the same point."), file, mc1->m.mnt_fsname); } } } if (!mc && verbose) printf(_("Could not find %s in mtab\n"), file); if (restricted) { char *mtab_user = NULL; if (!mc) die(2, _("umount: %s is not mounted (according to mtab)"), file); /* * uhelper - unprivileged umount helper * -- external umount (for example HAL mounts) */ if (external_allowed) { char *uhelper = NULL; if (mc->m.mnt_opts) uhelper = get_value(mc->m.mnt_opts, "uhelper="); if (uhelper) { int status = 0; if (check_special_umountprog(arg, arg, uhelper, &status)) return status; } } /* The 2.4 kernel will generally refuse to mount the same filesystem on the same mount point, but will accept NFS. So, unmounting must be possible. */ if (!is_mounted_once(file) && strcmp(mc->m.mnt_type,"nfs")) 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 (dev,file) in fstab. */ fs = getfs_by_devdir(mc->m.mnt_fsname, mc->m.mnt_dir); if (!fs) { fs = getfs_by_dir(file); if (!fs && !getfs_by_spec(file)) die (2, _("umount: %s is not in the fstab " "(and you are not root)"), file); /* spec could be a file which is loop mounted */ if (fs && !is_valid_loop(mc, fs)) 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="******"umount: only %s can unmount %s from %s"), mtab_user ? mtab_user : "******", 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); }