Home | History | Annotate | Download | only in lsb
      1 /* umount.c - Unmount a mount point.
      2  *
      3  * Copyright 2012 Rob Landley <rob (at) landley.net>
      4  *
      5  * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/umount.html
      6  *
      7  * Note: -n (/etc/mtab) is obsolete, /proc/mounts replaced it. Neither chroot
      8  * nor per-process mount namespaces can work sanely with mtab. The kernel
      9  * tracks mount points now, a userspace application can't do so anymore.
     10 
     11 USE_UMOUNT(NEWTOY(umount, "cndDflrat*v[!na]", TOYFLAG_BIN|TOYFLAG_STAYROOT))
     12 
     13 config UMOUNT
     14   bool "umount"
     15   default y
     16   help
     17     usage: umount [-a [-t TYPE[,TYPE...]]] [-vrfD] [DIR...]
     18 
     19     Unmount the listed filesystems.
     20 
     21     -a	Unmount all mounts in /proc/mounts instead of command line list
     22     -D	Don't free loopback device(s)
     23     -f	Force unmount
     24     -l	Lazy unmount (detach from filesystem now, close when last user does)
     25     -n	Don't use /proc/mounts
     26     -r	Remount read only if unmounting fails
     27     -t	Restrict "all" to mounts of TYPE (or use "noTYPE" to skip)
     28     -v	Verbose
     29 */
     30 
     31 #define FOR_umount
     32 #include "toys.h"
     33 
     34 GLOBALS(
     35   struct arg_list *t;
     36 
     37   char *types;
     38 )
     39 
     40 // todo (done?)
     41 //   borrow df code to identify filesystem?
     42 //   umount -a from fstab
     43 //   umount when getpid() not 0, according to fstab
     44 //   lookup mount: losetup -d, bind, file, block
     45 //   loopback delete
     46 //   fstab -o user
     47 
     48 // TODO
     49 // swapon, swapoff
     50 
     51 static void do_umount(char *dir, char *dev, int flags)
     52 {
     53   // is it ok for this user to umount this mount?
     54   if (CFG_TOYBOX_SUID && getuid()) {
     55     struct mtab_list *mt = dlist_terminate(xgetmountlist("/etc/fstab"));
     56     int len, user = 0;
     57 
     58     while (mt) {
     59       struct mtab_list *mtemp = mt;
     60       char *s;
     61 
     62       if (!strcmp(mt->dir, dir)) while ((s = comma_iterate(&mt->opts, &len))) {
     63         if (len == 4 && strncmp(s, "user", 4)) user = 1;
     64         else if (len == 6 && strncmp(s, "nouser", 6)) user = 0;
     65       }
     66 
     67       mt = mt->next;
     68       free(mtemp);
     69     }
     70 
     71     if (!user) {
     72       error_msg("not root");
     73 
     74       return;
     75     }
     76   }
     77 
     78   if (!umount2(dir, flags)) {
     79     if (toys.optflags & FLAG_v) xprintf("%s unmounted\n", dir);
     80 
     81     // Attempt to disassociate loopback device. This ioctl should be ignored
     82     // for anything else, because lanana allocated ioctl range 'L' to loopback
     83     if (dev && !(toys.optflags & FLAG_D)) {
     84       int lfd = open(dev, O_RDONLY);
     85 
     86       if (lfd != -1) {
     87         // This is LOOP_CLR_FD, fetching it from headers is awkward
     88         if (!ioctl(lfd, 0x4C01) && (toys.optflags & FLAG_v))
     89           xprintf("%s cleared\n", dev);
     90         close(lfd);
     91       }
     92     }
     93 
     94     return;
     95   }
     96 
     97   if (toys.optflags & FLAG_r) {
     98     if (!mount("", dir, "", MS_REMOUNT|MS_RDONLY, "")) {
     99       if (toys.optflags & FLAG_v) xprintf("%s remounted ro\n", dir);
    100       return;
    101     }
    102   }
    103 
    104   perror_msg_raw(dir);
    105 }
    106 
    107 void umount_main(void)
    108 {
    109   char **optargs, *pm = "/proc/mounts";
    110   struct mtab_list *mlsave = 0, *mlrev = 0, *ml;
    111   int flags=0;
    112 
    113   if (!toys.optc && !(toys.optflags & FLAG_a))
    114     error_exit("Need 1 arg or -a");
    115 
    116   if (toys.optflags & FLAG_f) flags |= MNT_FORCE;
    117   if (toys.optflags & FLAG_l) flags |= MNT_DETACH;
    118 
    119   // Load /proc/mounts and get a reversed list (newest first)
    120   // We use the list both for -a, and to umount /dev/name or do losetup -d
    121   if (!(toys.optflags & FLAG_n) && !access(pm, R_OK))
    122     mlrev = dlist_terminate(mlsave = xgetmountlist(pm));
    123 
    124   // Unmount all: loop through mounted filesystems, skip -t, unmount the rest
    125   if (toys.optflags & FLAG_a) {
    126     char *typestr = 0;
    127     struct arg_list *tal;
    128 
    129     for (tal = TT.t; tal; tal = tal->next) comma_collate(&typestr, tal->arg);
    130     for (ml = mlrev; ml; ml = ml->prev)
    131       if (mountlist_istype(ml, typestr)) do_umount(ml->dir, ml->device, flags);
    132     if (CFG_TOYBOX_FREE) {
    133       free(typestr);
    134       llist_traverse(mlsave, free);
    135     }
    136   // TODO: under what circumstances do we umount non-absolute path?
    137   } else for (optargs = toys.optargs; *optargs; optargs++) {
    138     char *abs = xabspath(*optargs, 0);
    139 
    140     for (ml = abs ? mlrev : 0; ml; ml = ml->prev) {
    141       if (!strcmp(ml->dir, abs)) break;
    142       if (!strcmp(ml->device, abs)) {
    143         free(abs);
    144         abs = ml->dir;
    145         break;
    146       }
    147     }
    148 
    149     do_umount(abs ? abs : *optargs, ml ? ml->device : 0, flags);
    150     if (ml && abs != ml->dir) free(abs);
    151   }
    152 }
    153