umount.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  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. * Licensed under GPL version 2, see file LICENSE in this tarball for details.
  9. */
  10. #include "busybox.h"
  11. #include <mntent.h>
  12. #include <getopt.h>
  13. #define OPTION_STRING "flDnravd"
  14. #define OPT_FORCE 1
  15. #define OPT_LAZY 2
  16. #define OPT_DONTFREELOOP 4
  17. #define OPT_NO_MTAB 8
  18. #define OPT_REMOUNT 16
  19. #define OPT_ALL (ENABLE_FEATURE_UMOUNT_ALL ? 32 : 0)
  20. int umount_main(int argc, char **argv)
  21. {
  22. int doForce;
  23. char path[2*PATH_MAX];
  24. struct mntent me;
  25. FILE *fp;
  26. int status = EXIT_SUCCESS;
  27. unsigned opt;
  28. struct mtab_list {
  29. char *dir;
  30. char *device;
  31. struct mtab_list *next;
  32. } *mtl, *m;
  33. /* Parse any options */
  34. opt = getopt32(argc, argv, OPTION_STRING);
  35. argc -= optind;
  36. argv += optind;
  37. doForce = MAX((opt & OPT_FORCE), (opt & OPT_LAZY));
  38. /* Get a list of mount points from mtab. We read them all in now mostly
  39. * for umount -a (so we don't have to worry about the list changing while
  40. * we iterate over it, or about getting stuck in a loop on the same failing
  41. * entry. Notice that this also naturally reverses the list so that -a
  42. * umounts the most recent entries first. */
  43. m = mtl = 0;
  44. /* If we're umounting all, then m points to the start of the list and
  45. * the argument list should be empty (which will match all). */
  46. fp = setmntent(bb_path_mtab_file, "r");
  47. if (!fp) {
  48. if (opt & OPT_ALL)
  49. bb_error_msg_and_die("cannot open %s", bb_path_mtab_file);
  50. } else {
  51. while (getmntent_r(fp, &me, path, sizeof(path))) {
  52. m = xmalloc(sizeof(struct mtab_list));
  53. m->next = mtl;
  54. m->device = xstrdup(me.mnt_fsname);
  55. m->dir = xstrdup(me.mnt_dir);
  56. mtl = m;
  57. }
  58. endmntent(fp);
  59. }
  60. /* If we're not umounting all, we need at least one argument. */
  61. if (!(opt & OPT_ALL)) {
  62. m = 0;
  63. if (!argc) bb_show_usage();
  64. }
  65. // Loop through everything we're supposed to umount, and do so.
  66. for (;;) {
  67. int curstat;
  68. char *zapit = *argv;
  69. // Do we already know what to umount this time through the loop?
  70. if (m) safe_strncpy(path, m->dir, PATH_MAX);
  71. // For umount -a, end of mtab means time to exit.
  72. else if (opt & OPT_ALL) break;
  73. // Get next command line argument (and look it up in mtab list)
  74. else if (!argc--) break;
  75. else {
  76. argv++;
  77. realpath(zapit, path);
  78. for (m = mtl; m; m = m->next)
  79. if (!strcmp(path, m->dir) || !strcmp(path, m->device))
  80. break;
  81. }
  82. // If we couldn't find this sucker in /etc/mtab, punt by passing our
  83. // command line argument straight to the umount syscall. Otherwise,
  84. // umount the directory even if we were given the block device.
  85. if (m) zapit = m->dir;
  86. // Let's ask the thing nicely to unmount.
  87. curstat = umount(zapit);
  88. // Force the unmount, if necessary.
  89. if (curstat && doForce) {
  90. curstat = umount2(zapit, doForce);
  91. if (curstat)
  92. bb_error_msg("forced umount of %s failed!", zapit);
  93. }
  94. // If still can't umount, maybe remount read-only?
  95. if (curstat && (opt & OPT_REMOUNT) && errno == EBUSY && m) {
  96. curstat = mount(m->device, zapit, NULL, MS_REMOUNT|MS_RDONLY, NULL);
  97. bb_error_msg(curstat ? "cannot remount %s read-only" :
  98. "%s busy - remounted read-only", m->device);
  99. }
  100. if (curstat) {
  101. status = EXIT_FAILURE;
  102. bb_perror_msg("cannot umount %s", zapit);
  103. } else {
  104. /* De-allocate the loop device. This ioctl should be ignored on
  105. * any non-loop block devices. */
  106. if (ENABLE_FEATURE_MOUNT_LOOP && !(opt & OPT_DONTFREELOOP) && m)
  107. del_loop(m->device);
  108. if (ENABLE_FEATURE_MTAB_SUPPORT && !(opt & OPT_NO_MTAB) && m)
  109. erase_mtab(m->dir);
  110. }
  111. // Find next matching mtab entry for -a or umount /dev
  112. // Note this means that "umount /dev/blah" will unmount all instances
  113. // of /dev/blah, not just the most recent.
  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. }