123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- /* umount.c - Unmount a mount point.
- *
- * Copyright 2012 Rob Landley <rob@landley.net>
- *
- * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/umount.html
- *
- * Note: -n (/etc/mtab) is obsolete, /proc/mounts replaced it. Neither chroot
- * nor per-process mount namespaces can work sanely with mtab. The kernel
- * tracks mount points now, a userspace application can't do so anymore.
- USE_UMOUNT(NEWTOY(umount, "cndDflrat*v[!na]", TOYFLAG_BIN|TOYFLAG_STAYROOT))
- config UMOUNT
- bool "umount"
- default y
- help
- usage: umount [-a [-t TYPE[,TYPE...]]] [-vrfD] [DIR...]
- Unmount the listed filesystems.
- -a Unmount all mounts in /proc/mounts instead of command line list
- -D Don't free loopback device(s)
- -f Force unmount
- -l Lazy unmount (detach from filesystem now, close when last user does)
- -n Don't use /proc/mounts
- -r Remount read only if unmounting fails
- -t Restrict "all" to mounts of TYPE (or use "noTYPE" to skip)
- -v Verbose
- */
- #define FOR_umount
- #include "toys.h"
- GLOBALS(
- struct arg_list *t;
- char *types;
- )
- // todo (done?)
- // borrow df code to identify filesystem?
- // umount -a from fstab
- // umount when getpid() not 0, according to fstab
- // lookup mount: losetup -d, bind, file, block
- // loopback delete
- // fstab -o user
- // TODO
- // swapon, swapoff
- static void do_umount(char *dir, char *dev, int flags)
- {
- // is it ok for this user to umount this mount?
- if (CFG_TOYBOX_SUID && getuid()) {
- struct mtab_list *mt = dlist_terminate(xgetmountlist("/etc/fstab"));
- int len, user = 0;
- while (mt) {
- struct mtab_list *mtemp = mt;
- char *s;
- if (!strcmp(mt->dir, dir)) while ((s = comma_iterate(&mt->opts, &len))) {
- if (len == 4 && strncmp(s, "user", 4)) user = 1;
- else if (len == 6 && strncmp(s, "nouser", 6)) user = 0;
- }
- mt = mt->next;
- free(mtemp);
- }
- if (!user) {
- error_msg("not root");
- return;
- }
- }
- if (!umount2(dir, flags)) {
- if (toys.optflags & FLAG_v) xprintf("%s unmounted\n", dir);
- // Attempt to disassociate loopback device. This ioctl should be ignored
- // for anything else, because lanana allocated ioctl range 'L' to loopback
- if (dev && !(toys.optflags & FLAG_D)) {
- int lfd = open(dev, O_RDONLY);
- if (lfd != -1) {
- // This is LOOP_CLR_FD, fetching it from headers is awkward
- if (!ioctl(lfd, 0x4C01) && (toys.optflags & FLAG_v))
- xprintf("%s cleared\n", dev);
- close(lfd);
- }
- }
- return;
- }
- if (toys.optflags & FLAG_r) {
- if (!mount("", dir, "", MS_REMOUNT|MS_RDONLY, "")) {
- if (toys.optflags & FLAG_v) xprintf("%s remounted ro\n", dir);
- return;
- }
- }
- perror_msg_raw(dir);
- }
- void umount_main(void)
- {
- char **optargs, *pm = "/proc/mounts";
- struct mtab_list *mlsave = 0, *mlrev = 0, *ml;
- int flags=0;
- if (!toys.optc && !(toys.optflags & FLAG_a))
- error_exit("Need 1 arg or -a");
- if (toys.optflags & FLAG_f) flags |= MNT_FORCE;
- if (toys.optflags & FLAG_l) flags |= MNT_DETACH;
- // Load /proc/mounts and get a reversed list (newest first)
- // We use the list both for -a, and to umount /dev/name or do losetup -d
- if (!(toys.optflags & FLAG_n) && !access(pm, R_OK))
- mlrev = dlist_terminate(mlsave = xgetmountlist(pm));
- // Unmount all: loop through mounted filesystems, skip -t, unmount the rest
- if (toys.optflags & FLAG_a) {
- char *typestr = 0;
- struct arg_list *tal;
-
- for (tal = TT.t; tal; tal = tal->next) comma_collate(&typestr, tal->arg);
- for (ml = mlrev; ml; ml = ml->prev)
- if (mountlist_istype(ml, typestr)) do_umount(ml->dir, ml->device, flags);
- if (CFG_TOYBOX_FREE) {
- free(typestr);
- llist_traverse(mlsave, free);
- }
- // TODO: under what circumstances do we umount non-absolute path?
- } else for (optargs = toys.optargs; *optargs; optargs++) {
- char *abs = xabspath(*optargs, 0);
- for (ml = abs ? mlrev : 0; ml; ml = ml->prev) {
- if (!strcmp(ml->dir, abs)) break;
- if (!strcmp(ml->device, abs)) {
- free(abs);
- abs = ml->dir;
- break;
- }
- }
- do_umount(abs ? abs : *optargs, ml ? ml->device : 0, flags);
- if (ml && abs != ml->dir) free(abs);
- }
- }
|