umount.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Mini umount implementation for busybox
  4. *
  5. * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
  6. * Copyright (C) 2005 by Rob Landley <rob@landley.net>
  7. *
  8. * This program is licensed under the GNU General Public license (GPL)
  9. * version 2 or later, see http://www.fsf.org/licensing/licenses/gpl.html
  10. * or the file "LICENSE" in the busybox source tarball for the full text.
  11. *
  12. */
  13. #include <limits.h>
  14. #include <stdio.h>
  15. #include <mntent.h>
  16. #include <errno.h>
  17. #include <string.h>
  18. #include <stdlib.h>
  19. #include <sys/mount.h>
  20. #include <getopt.h>
  21. #include "busybox.h"
  22. #define OPTION_STRING "flDnrvad"
  23. #define OPT_FORCE 1
  24. #define OPT_LAZY 2
  25. #define OPT_DONTFREELOOP 4
  26. #define OPT_NO_MTAB 8
  27. #define OPT_REMOUNT 16
  28. #define OPT_IGNORED 32 // -v is ignored
  29. #define OPT_ALL (ENABLE_FEATURE_UMOUNT_ALL ? 64 : 0)
  30. int umount_main(int argc, char **argv)
  31. {
  32. int doForce;
  33. char path[2*PATH_MAX];
  34. struct mntent me;
  35. FILE *fp;
  36. int status = EXIT_SUCCESS;
  37. unsigned long opt;
  38. struct mtab_list {
  39. char *dir;
  40. char *device;
  41. struct mtab_list *next;
  42. } *mtl, *m;
  43. /* Parse any options */
  44. opt = bb_getopt_ulflags(argc, argv, OPTION_STRING);
  45. argc -= optind;
  46. argv += optind;
  47. doForce = MAX((opt & OPT_FORCE), (opt & OPT_LAZY));
  48. /* Get a list of mount points from mtab. We read them all in now mostly
  49. * for umount -a (so we don't have to worry about the list changing while
  50. * we iterate over it, or about getting stuck in a loop on the same failing
  51. * entry. Notice that this also naturally reverses the list so that -a
  52. * umounts the most recent entries first. */
  53. m = mtl = 0;
  54. /* If we're umounting all, then m points to the start of the list and
  55. * the argument list should be empty (which will match all). */
  56. if (!(fp = setmntent(bb_path_mtab_file, "r"))) {
  57. if (opt & OPT_ALL)
  58. bb_error_msg_and_die("Cannot open %s", bb_path_mtab_file);
  59. } else while (getmntent_r(fp,&me,path,sizeof(path))) {
  60. m = xmalloc(sizeof(struct mtab_list));
  61. m->next = mtl;
  62. m->device = bb_xstrdup(me.mnt_fsname);
  63. m->dir = bb_xstrdup(me.mnt_dir);
  64. mtl = m;
  65. }
  66. endmntent(fp);
  67. /* If we're not mounting all, we need at least one argument. */
  68. if (!(opt & OPT_ALL)) {
  69. m = 0;
  70. if (!argc) bb_show_usage();
  71. }
  72. // Loop through everything we're supposed to umount, and do so.
  73. for (;;) {
  74. int curstat;
  75. // Do we already know what to umount this time through the loop?
  76. if (m) safe_strncpy(path, m->dir, PATH_MAX);
  77. // For umount -a, end of mtab means time to exit.
  78. else if (opt & OPT_ALL) break;
  79. // Get next command line argument (and look it up in mtab list)
  80. else if (!argc--) break;
  81. else {
  82. realpath(*argv++, path);
  83. for (m = mtl; m; m = m->next)
  84. if (!strcmp(path, m->dir) || !strcmp(path, m->device))
  85. break;
  86. }
  87. // Let's ask the thing nicely to unmount.
  88. curstat = umount(path);
  89. // Force the unmount, if necessary.
  90. if (curstat && doForce) {
  91. curstat = umount2(path, doForce);
  92. if (curstat)
  93. bb_error_msg_and_die("forced umount of %s failed!", path);
  94. }
  95. // If still can't umount, maybe remount read-only?
  96. if (curstat && (opt & OPT_REMOUNT) && errno == EBUSY && m) {
  97. curstat = mount(m->device, path, NULL, MS_REMOUNT|MS_RDONLY, NULL);
  98. bb_error_msg(curstat ? "Cannot remount %s read-only" :
  99. "%s busy - remounted read-only", m->device);
  100. }
  101. /* De-allocate the loop device. This ioctl should be ignored on any
  102. * non-loop block devices. */
  103. if (ENABLE_FEATURE_MOUNT_LOOP && !(opt & OPT_DONTFREELOOP) && m)
  104. del_loop(m->device);
  105. if (curstat) {
  106. /* Yes, the ENABLE is redundant here, but the optimizer for ARM
  107. * can't do simple constant propagation in local variables... */
  108. if(ENABLE_FEATURE_MTAB_SUPPORT && !(opt & OPT_NO_MTAB) && m)
  109. erase_mtab(m->dir);
  110. status = EXIT_FAILURE;
  111. bb_perror_msg("Couldn't umount %s", path);
  112. }
  113. // Find next matching mtab entry for -a or umount /dev
  114. while (m && (m = m->next))
  115. if ((opt & OPT_ALL) || !strcmp(path,m->device))
  116. break;
  117. }
  118. // Free mtab list if necessary
  119. if (ENABLE_FEATURE_CLEAN_UP) {
  120. while (mtl) {
  121. m = mtl->next;
  122. free(mtl->device);
  123. free(mtl->dir);
  124. free(mtl);
  125. mtl=m;
  126. }
  127. }
  128. return status;
  129. }