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...]]] [-f] [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    -t	Restrict "all" to mounts of TYPE (or use "noTYPE" to skip)
230f66f451Sopenharmony_ci*/
240f66f451Sopenharmony_ci
250f66f451Sopenharmony_ci#define FOR_umount
260f66f451Sopenharmony_ci#include "toys.h"
270f66f451Sopenharmony_ci
280f66f451Sopenharmony_ciGLOBALS(
290f66f451Sopenharmony_ci  struct arg_list *t;
300f66f451Sopenharmony_ci
310f66f451Sopenharmony_ci  char *types;
320f66f451Sopenharmony_ci)
330f66f451Sopenharmony_ci
340f66f451Sopenharmony_ci// todo (done?)
350f66f451Sopenharmony_ci//   borrow df code to identify filesystem?
360f66f451Sopenharmony_ci//   umount -a from fstab
370f66f451Sopenharmony_ci//   umount when getpid() not 0, according to fstab
380f66f451Sopenharmony_ci//   lookup mount: losetup -d, bind, file, block
390f66f451Sopenharmony_ci//   loopback delete
400f66f451Sopenharmony_ci//   fstab -o user
410f66f451Sopenharmony_ci
420f66f451Sopenharmony_ci// TODO
430f66f451Sopenharmony_ci// swapon, swapoff
440f66f451Sopenharmony_ci
450f66f451Sopenharmony_cistatic void do_umount(char *dir, char *dev, int flags)
460f66f451Sopenharmony_ci{
470f66f451Sopenharmony_ci  if (!umount2(dir, flags)) {
480f66f451Sopenharmony_ci    if (toys.optflags & FLAG_v) xprintf("%s unmounted\n", dir);
490f66f451Sopenharmony_ci
500f66f451Sopenharmony_ci    // Attempt to disassociate loopback device. This ioctl should be ignored
510f66f451Sopenharmony_ci    // for anything else, because lanana allocated ioctl range 'L' to loopback
520f66f451Sopenharmony_ci    if (dev && !(toys.optflags & FLAG_D)) {
530f66f451Sopenharmony_ci      int lfd = open(dev, O_RDONLY);
540f66f451Sopenharmony_ci
550f66f451Sopenharmony_ci      if (lfd != -1) {
560f66f451Sopenharmony_ci        // This is LOOP_CLR_FD, fetching it from headers is awkward
570f66f451Sopenharmony_ci        if (!ioctl(lfd, 0x4C01) && (toys.optflags & FLAG_v))
580f66f451Sopenharmony_ci          xprintf("%s cleared\n", dev);
590f66f451Sopenharmony_ci        close(lfd);
600f66f451Sopenharmony_ci      }
610f66f451Sopenharmony_ci    }
620f66f451Sopenharmony_ci    xprintf("umount ok\n");
630f66f451Sopenharmony_ci    return;
640f66f451Sopenharmony_ci  }
650f66f451Sopenharmony_ci
660f66f451Sopenharmony_ci  if (toys.optflags & FLAG_r) {
670f66f451Sopenharmony_ci    if (!mount("", dir, "", MS_REMOUNT|MS_RDONLY, "")) {
680f66f451Sopenharmony_ci      if (toys.optflags & FLAG_v) xprintf("%s remounted ro\n", dir);
690f66f451Sopenharmony_ci      return;
700f66f451Sopenharmony_ci    }
710f66f451Sopenharmony_ci  }
720f66f451Sopenharmony_ci
730f66f451Sopenharmony_ci  perror_msg_raw(dir);
740f66f451Sopenharmony_ci}
750f66f451Sopenharmony_ci
760f66f451Sopenharmony_civoid umount_main(void)
770f66f451Sopenharmony_ci{
780f66f451Sopenharmony_ci  char **optargs, *pm = "/proc/mounts";
790f66f451Sopenharmony_ci  struct mtab_list *mlsave = 0, *mlrev = 0, *ml;
800f66f451Sopenharmony_ci  int flags=0;
810f66f451Sopenharmony_ci
820f66f451Sopenharmony_ci  if (!toys.optc && !(toys.optflags & FLAG_a))
830f66f451Sopenharmony_ci    help_exit("Need 1 arg or -a");
840f66f451Sopenharmony_ci
850f66f451Sopenharmony_ci  if (toys.optflags & FLAG_f) flags |= MNT_FORCE;
860f66f451Sopenharmony_ci  if (toys.optflags & FLAG_l) flags |= MNT_DETACH;
870f66f451Sopenharmony_ci
880f66f451Sopenharmony_ci  // Load /proc/mounts and get a reversed list (newest first)
890f66f451Sopenharmony_ci  // We use the list both for -a, and to umount /dev/name or do losetup -d
900f66f451Sopenharmony_ci  if (!(toys.optflags & FLAG_n) && !access(pm, R_OK))
910f66f451Sopenharmony_ci    mlrev = dlist_terminate(mlsave = xgetmountlist(pm));
920f66f451Sopenharmony_ci
930f66f451Sopenharmony_ci  // Unmount all: loop through mounted filesystems, skip -t, unmount the rest
940f66f451Sopenharmony_ci  if (toys.optflags & FLAG_a) {
950f66f451Sopenharmony_ci    char *typestr = 0;
960f66f451Sopenharmony_ci    struct arg_list *tal;
970f66f451Sopenharmony_ci
980f66f451Sopenharmony_ci    for (tal = TT.t; tal; tal = tal->next) comma_collate(&typestr, tal->arg);
990f66f451Sopenharmony_ci    for (ml = mlrev; ml; ml = ml->prev)
1000f66f451Sopenharmony_ci      if (mountlist_istype(ml, typestr)) do_umount(ml->dir, ml->device, flags);
1010f66f451Sopenharmony_ci    if (CFG_TOYBOX_FREE) {
1020f66f451Sopenharmony_ci      free(typestr);
1030f66f451Sopenharmony_ci      llist_traverse(mlsave, free);
1040f66f451Sopenharmony_ci    }
1050f66f451Sopenharmony_ci  // TODO: under what circumstances do we umount non-absolute path?
1060f66f451Sopenharmony_ci  } else for (optargs = toys.optargs; *optargs; optargs++) {
1070f66f451Sopenharmony_ci    char *abs = xabspath(*optargs, 0);
1080f66f451Sopenharmony_ci
1090f66f451Sopenharmony_ci    for (ml = abs ? mlrev : 0; ml; ml = ml->prev) {
1100f66f451Sopenharmony_ci      if (!strcmp(ml->dir, abs)) break;
1110f66f451Sopenharmony_ci      if (!strcmp(ml->device, abs)) {
1120f66f451Sopenharmony_ci        free(abs);
1130f66f451Sopenharmony_ci        abs = ml->dir;
1140f66f451Sopenharmony_ci        break;
1150f66f451Sopenharmony_ci      }
1160f66f451Sopenharmony_ci    }
1170f66f451Sopenharmony_ci
1180f66f451Sopenharmony_ci    do_umount(abs ? abs : *optargs, ml ? ml->device : 0, flags);
1190f66f451Sopenharmony_ci    if (ml && abs != ml->dir) free(abs);
1200f66f451Sopenharmony_ci  }
1210f66f451Sopenharmony_ci}
122