umount.c 4.2 KB

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