toybox/toys/lsb/umount.c
<<
>>
Prefs
   1/* umount.c - Unmount a mount point.
   2 *
   3 * Copyright 2012 Rob Landley <rob@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
  11USE_UMOUNT(NEWTOY(umount, "cndDflrat*v[!na]", TOYFLAG_BIN|TOYFLAG_STAYROOT))
  12
  13config 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
  34GLOBALS(
  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
  51static 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
 107void 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