10f66f451Sopenharmony_ci/* umount.c - Unmount a mount point. 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2012 Rob Landley <rob@landley.net> 40f66f451Sopenharmony_ci * 50f66f451Sopenharmony_ci * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/umount.html 60f66f451Sopenharmony_ci * 70f66f451Sopenharmony_ci * Note: -n (/etc/mtab) is obsolete, /proc/mounts replaced it. Neither chroot 80f66f451Sopenharmony_ci * nor per-process mount namespaces can work sanely with mtab. The kernel 90f66f451Sopenharmony_ci * tracks mount points now, a userspace application can't do so anymore. 100f66f451Sopenharmony_ci 110f66f451Sopenharmony_ciUSE_UMOUNT(NEWTOY(umount, "cndDflrat*v[!na]", TOYFLAG_BIN|TOYFLAG_STAYROOT)) 120f66f451Sopenharmony_ci 130f66f451Sopenharmony_ciconfig UMOUNT 140f66f451Sopenharmony_ci bool "umount" 150f66f451Sopenharmony_ci default y 160f66f451Sopenharmony_ci help 170f66f451Sopenharmony_ci usage: umount [-a [-t TYPE[,TYPE...]]] [-vrfD] [DIR...] 180f66f451Sopenharmony_ci 190f66f451Sopenharmony_ci Unmount the listed filesystems. 200f66f451Sopenharmony_ci 210f66f451Sopenharmony_ci -a Unmount all mounts in /proc/mounts instead of command line list 220f66f451Sopenharmony_ci -D Don't free loopback device(s) 230f66f451Sopenharmony_ci -f Force unmount 240f66f451Sopenharmony_ci -l Lazy unmount (detach from filesystem now, close when last user does) 250f66f451Sopenharmony_ci -n Don't use /proc/mounts 260f66f451Sopenharmony_ci -r Remount read only if unmounting fails 270f66f451Sopenharmony_ci -t Restrict "all" to mounts of TYPE (or use "noTYPE" to skip) 280f66f451Sopenharmony_ci -v Verbose 290f66f451Sopenharmony_ci*/ 300f66f451Sopenharmony_ci 310f66f451Sopenharmony_ci#define FOR_umount 320f66f451Sopenharmony_ci#include "toys.h" 330f66f451Sopenharmony_ci 340f66f451Sopenharmony_ciGLOBALS( 350f66f451Sopenharmony_ci struct arg_list *t; 360f66f451Sopenharmony_ci 370f66f451Sopenharmony_ci char *types; 380f66f451Sopenharmony_ci) 390f66f451Sopenharmony_ci 400f66f451Sopenharmony_ci// todo (done?) 410f66f451Sopenharmony_ci// borrow df code to identify filesystem? 420f66f451Sopenharmony_ci// umount -a from fstab 430f66f451Sopenharmony_ci// umount when getpid() not 0, according to fstab 440f66f451Sopenharmony_ci// lookup mount: losetup -d, bind, file, block 450f66f451Sopenharmony_ci// loopback delete 460f66f451Sopenharmony_ci// fstab -o user 470f66f451Sopenharmony_ci 480f66f451Sopenharmony_ci// TODO 490f66f451Sopenharmony_ci// swapon, swapoff 500f66f451Sopenharmony_ci 510f66f451Sopenharmony_cistatic void do_umount(char *dir, char *dev, int flags) 520f66f451Sopenharmony_ci{ 530f66f451Sopenharmony_ci // is it ok for this user to umount this mount? 540f66f451Sopenharmony_ci if (CFG_TOYBOX_SUID && getuid()) { 550f66f451Sopenharmony_ci struct mtab_list *mt = dlist_terminate(xgetmountlist("/etc/fstab")); 560f66f451Sopenharmony_ci int len, user = 0; 570f66f451Sopenharmony_ci 580f66f451Sopenharmony_ci while (mt) { 590f66f451Sopenharmony_ci struct mtab_list *mtemp = mt; 600f66f451Sopenharmony_ci char *s; 610f66f451Sopenharmony_ci 620f66f451Sopenharmony_ci if (!strcmp(mt->dir, dir)) while ((s = comma_iterate(&mt->opts, &len))) { 630f66f451Sopenharmony_ci if (len == 4 && strncmp(s, "user", 4)) user = 1; 640f66f451Sopenharmony_ci else if (len == 6 && strncmp(s, "nouser", 6)) user = 0; 650f66f451Sopenharmony_ci } 660f66f451Sopenharmony_ci 670f66f451Sopenharmony_ci mt = mt->next; 680f66f451Sopenharmony_ci free(mtemp); 690f66f451Sopenharmony_ci } 700f66f451Sopenharmony_ci 710f66f451Sopenharmony_ci if (!user) { 720f66f451Sopenharmony_ci error_msg("not root"); 730f66f451Sopenharmony_ci 740f66f451Sopenharmony_ci return; 750f66f451Sopenharmony_ci } 760f66f451Sopenharmony_ci } 770f66f451Sopenharmony_ci 780f66f451Sopenharmony_ci if (!umount2(dir, flags)) { 790f66f451Sopenharmony_ci if (toys.optflags & FLAG_v) xprintf("%s unmounted\n", dir); 800f66f451Sopenharmony_ci 810f66f451Sopenharmony_ci // Attempt to disassociate loopback device. This ioctl should be ignored 820f66f451Sopenharmony_ci // for anything else, because lanana allocated ioctl range 'L' to loopback 830f66f451Sopenharmony_ci if (dev && !(toys.optflags & FLAG_D)) { 840f66f451Sopenharmony_ci int lfd = open(dev, O_RDONLY); 850f66f451Sopenharmony_ci 860f66f451Sopenharmony_ci if (lfd != -1) { 870f66f451Sopenharmony_ci // This is LOOP_CLR_FD, fetching it from headers is awkward 880f66f451Sopenharmony_ci if (!ioctl(lfd, 0x4C01) && (toys.optflags & FLAG_v)) 890f66f451Sopenharmony_ci xprintf("%s cleared\n", dev); 900f66f451Sopenharmony_ci close(lfd); 910f66f451Sopenharmony_ci } 920f66f451Sopenharmony_ci } 930f66f451Sopenharmony_ci 940f66f451Sopenharmony_ci return; 950f66f451Sopenharmony_ci } 960f66f451Sopenharmony_ci 970f66f451Sopenharmony_ci if (toys.optflags & FLAG_r) { 980f66f451Sopenharmony_ci if (!mount("", dir, "", MS_REMOUNT|MS_RDONLY, "")) { 990f66f451Sopenharmony_ci if (toys.optflags & FLAG_v) xprintf("%s remounted ro\n", dir); 1000f66f451Sopenharmony_ci return; 1010f66f451Sopenharmony_ci } 1020f66f451Sopenharmony_ci } 1030f66f451Sopenharmony_ci 1040f66f451Sopenharmony_ci perror_msg_raw(dir); 1050f66f451Sopenharmony_ci} 1060f66f451Sopenharmony_ci 1070f66f451Sopenharmony_civoid umount_main(void) 1080f66f451Sopenharmony_ci{ 1090f66f451Sopenharmony_ci char **optargs, *pm = "/proc/mounts"; 1100f66f451Sopenharmony_ci struct mtab_list *mlsave = 0, *mlrev = 0, *ml; 1110f66f451Sopenharmony_ci int flags=0; 1120f66f451Sopenharmony_ci 1130f66f451Sopenharmony_ci if (!toys.optc && !(toys.optflags & FLAG_a)) 1140f66f451Sopenharmony_ci error_exit("Need 1 arg or -a"); 1150f66f451Sopenharmony_ci 1160f66f451Sopenharmony_ci if (toys.optflags & FLAG_f) flags |= MNT_FORCE; 1170f66f451Sopenharmony_ci if (toys.optflags & FLAG_l) flags |= MNT_DETACH; 1180f66f451Sopenharmony_ci 1190f66f451Sopenharmony_ci // Load /proc/mounts and get a reversed list (newest first) 1200f66f451Sopenharmony_ci // We use the list both for -a, and to umount /dev/name or do losetup -d 1210f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_n) && !access(pm, R_OK)) 1220f66f451Sopenharmony_ci mlrev = dlist_terminate(mlsave = xgetmountlist(pm)); 1230f66f451Sopenharmony_ci 1240f66f451Sopenharmony_ci // Unmount all: loop through mounted filesystems, skip -t, unmount the rest 1250f66f451Sopenharmony_ci if (toys.optflags & FLAG_a) { 1260f66f451Sopenharmony_ci char *typestr = 0; 1270f66f451Sopenharmony_ci struct arg_list *tal; 1280f66f451Sopenharmony_ci 1290f66f451Sopenharmony_ci for (tal = TT.t; tal; tal = tal->next) comma_collate(&typestr, tal->arg); 1300f66f451Sopenharmony_ci for (ml = mlrev; ml; ml = ml->prev) 1310f66f451Sopenharmony_ci if (mountlist_istype(ml, typestr)) do_umount(ml->dir, ml->device, flags); 1320f66f451Sopenharmony_ci if (CFG_TOYBOX_FREE) { 1330f66f451Sopenharmony_ci free(typestr); 1340f66f451Sopenharmony_ci llist_traverse(mlsave, free); 1350f66f451Sopenharmony_ci } 1360f66f451Sopenharmony_ci // TODO: under what circumstances do we umount non-absolute path? 1370f66f451Sopenharmony_ci } else for (optargs = toys.optargs; *optargs; optargs++) { 1380f66f451Sopenharmony_ci char *abs = xabspath(*optargs, 0); 1390f66f451Sopenharmony_ci 1400f66f451Sopenharmony_ci for (ml = abs ? mlrev : 0; ml; ml = ml->prev) { 1410f66f451Sopenharmony_ci if (!strcmp(ml->dir, abs)) break; 1420f66f451Sopenharmony_ci if (!strcmp(ml->device, abs)) { 1430f66f451Sopenharmony_ci free(abs); 1440f66f451Sopenharmony_ci abs = ml->dir; 1450f66f451Sopenharmony_ci break; 1460f66f451Sopenharmony_ci } 1470f66f451Sopenharmony_ci } 1480f66f451Sopenharmony_ci 1490f66f451Sopenharmony_ci do_umount(abs ? abs : *optargs, ml ? ml->device : 0, flags); 1500f66f451Sopenharmony_ci if (ml && abs != ml->dir) free(abs); 1510f66f451Sopenharmony_ci } 1520f66f451Sopenharmony_ci} 153