X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=inline;f=util-linux%2Fumount.c;h=7063a474d1b7822be6c014cda98c406c6af71e0c;hb=dcf6de552a15c1e7bddb32f1028ceb6214915425;hp=6de71b4aba5b984c607172ddb874333d8454b7f5;hpb=6a6798b8e47c71888945ec5cb55c703db19b956c;p=oweals%2Fbusybox.git diff --git a/util-linux/umount.c b/util-linux/umount.c index 6de71b4ab..7063a474d 100644 --- a/util-linux/umount.c +++ b/util-linux/umount.c @@ -4,137 +4,151 @@ * * Copyright (C) 1999-2004 by Erik Andersen * Copyright (C) 2005 by Rob Landley - * - * This program is licensed under the GNU General Public license (GPL) - * version 2 or later, see http://www.fsf.org/licensing/licenses/gpl.html - * or the file "LICENSE" in the busybox source tarball for the full text. * + * Licensed under GPL version 2, see file LICENSE in this tarball for details. */ -#include -#include #include -#include -#include -#include -#include -#include "busybox.h" +#include +#include "libbb.h" -extern int umount_main(int argc, char **argv) +#define OPTION_STRING "flDnravdt:" +#define OPT_FORCE 1 +#define OPT_LAZY 2 +#define OPT_DONTFREELOOP 4 +#define OPT_NO_MTAB 8 +#define OPT_REMOUNT 16 +#define OPT_ALL (ENABLE_FEATURE_UMOUNT_ALL ? 32 : 0) + +int umount_main(int argc, char **argv); +int umount_main(int argc, char **argv) { - int doForce = 0; - int freeLoop = ENABLE_FEATURE_MOUNT_LOOP; - int useMtab = ENABLE_FEATURE_MTAB_SUPPORT; - int umountAll = FALSE; - int doRemount = FALSE; + int doForce; char path[2*PATH_MAX]; struct mntent me; FILE *fp; - int status=EXIT_SUCCESS; + char *fstype = 0; + int status = EXIT_SUCCESS; + unsigned opt; struct mtab_list { char *dir; char *device; - struct mtab_list *next; + struct mtab_list *next; } *mtl, *m; - if(argc < 2) bb_show_usage(); - /* Parse any options */ - while (--argc > 0 && **(++argv) == '-') { - while (*++(*argv)) { - if(**argv=='a') umountAll = TRUE; - else if(ENABLE_FEATURE_MOUNT_LOOP && **argv=='D') freeLoop = FALSE; - else if(ENABLE_FEATURE_MTAB_SUPPORT && **argv=='n') useMtab = FALSE; - else if(**argv=='f') doForce = 1; // MNT_FORCE - else if(**argv=='l') doForce = 2; // MNT_DETACH - else if(**argv=='r') doRemount = TRUE; - else if(**argv=='v'); - else bb_show_usage(); - } - } + + opt = getopt32(argc, argv, OPTION_STRING, &fstype); + + argc -= optind; + argv += optind; + + doForce = MAX((opt & OPT_FORCE), (opt & OPT_LAZY)); /* Get a list of mount points from mtab. We read them all in now mostly * for umount -a (so we don't have to worry about the list changing while * we iterate over it, or about getting stuck in a loop on the same failing * entry. Notice that this also naturally reverses the list so that -a * umounts the most recent entries first. */ - - m=mtl=0; - if(!(fp = setmntent(bb_path_mtab_file, "r"))) - bb_error_msg_and_die("Cannot open %s", bb_path_mtab_file); - while (getmntent_r(fp,&me,path,sizeof(path))) { - m=xmalloc(sizeof(struct mtab_list)); - m->next=mtl; - m->device=bb_xstrdup(me.mnt_fsname); - m->dir=bb_xstrdup(me.mnt_dir); - mtl=m; - } - endmntent(fp); + + m = mtl = 0; /* If we're umounting all, then m points to the start of the list and * the argument list should be empty (which will match all). */ - if(!umountAll) m=0; + + fp = setmntent(bb_path_mtab_file, "r"); + if (!fp) { + if (opt & OPT_ALL) + bb_error_msg_and_die("cannot open %s", bb_path_mtab_file); + } else { + while (getmntent_r(fp, &me, path, sizeof(path))) { + /* Match fstype if passed */ + if (fstype && match_fstype(&me, fstype)) + continue; + m = xmalloc(sizeof(struct mtab_list)); + m->next = mtl; + m->device = xstrdup(me.mnt_fsname); + m->dir = xstrdup(me.mnt_dir); + mtl = m; + } + endmntent(fp); + } + + /* If we're not umounting all, we need at least one argument. */ + if (!(opt & OPT_ALL) && !fstype) { + m = 0; + if (!argc) bb_show_usage(); + } // Loop through everything we're supposed to umount, and do so. - for(;;) { + for (;;) { int curstat; - - // Do we alrady know what to umount this time through the loop? - if(m) safe_strncpy(path,m->dir,PATH_MAX); - // For umountAll, end of mtab means time to exit. - else if(umountAll) break; + char *zapit = *argv; + + // Do we already know what to umount this time through the loop? + if (m) safe_strncpy(path, m->dir, PATH_MAX); + // For umount -a, end of mtab means time to exit. + else if (opt & OPT_ALL) break; // Get next command line argument (and look it up in mtab list) - else if(!argc--) break; + else if (!argc--) break; else { - // Get next command line argument (and look it up in mtab list) - realpath(*argv++, path); - for(m = mtl; m; m = m->next) - if(!strcmp(path, m->dir) || !strcmp(path, m->device)) + argv++; + realpath(zapit, path); + for (m = mtl; m; m = m->next) + if (!strcmp(path, m->dir) || !strcmp(path, m->device)) break; } + // If we couldn't find this sucker in /etc/mtab, punt by passing our + // command line argument straight to the umount syscall. Otherwise, + // umount the directory even if we were given the block device. + if (m) zapit = m->dir; // Let's ask the thing nicely to unmount. - curstat = umount(path); + curstat = umount(zapit); // Force the unmount, if necessary. - if(curstat && doForce) { - curstat = umount2(path, doForce); - if(curstat) - bb_error_msg_and_die("forced umount of %s failed!", path); + if (curstat && doForce) { + curstat = umount2(zapit, doForce); + if (curstat) + bb_error_msg("forced umount of %s failed!", zapit); } - // If still can't umount, maybe remount read-only? - if (curstat && doRemount && errno == EBUSY && m) { - curstat = mount(m->device, path, NULL, MS_REMOUNT|MS_RDONLY, NULL); - bb_error_msg(curstat ? "Cannot remount %s read-only" : + // If still can't umount, maybe remount read-only? + if (curstat && (opt & OPT_REMOUNT) && errno == EBUSY && m) { + curstat = mount(m->device, zapit, NULL, MS_REMOUNT|MS_RDONLY, NULL); + bb_error_msg(curstat ? "cannot remount %s read-only" : "%s busy - remounted read-only", m->device); } - /* De-allcate the loop device. This ioctl should be ignored on any - * non-loop block devices. */ - if(ENABLE_FEATURE_MOUNT_LOOP && freeLoop && m) - del_loop(m->device); - - if(curstat) { - if(useMtab && m) erase_mtab(m->dir); + if (curstat) { status = EXIT_FAILURE; - bb_perror_msg("Couldn't umount %s\n", path); + bb_perror_msg("cannot umount %s", zapit); + } else { + /* De-allocate the loop device. This ioctl should be ignored on + * any non-loop block devices. */ + if (ENABLE_FEATURE_MOUNT_LOOP && !(opt & OPT_DONTFREELOOP) && m) + del_loop(m->device); + if (ENABLE_FEATURE_MTAB_SUPPORT && !(opt & OPT_NO_MTAB) && m) + erase_mtab(m->dir); } + // Find next matching mtab entry for -a or umount /dev - while(m && (m = m->next)) - if(umountAll || !strcmp(path,m->device)) - break; + // Note this means that "umount /dev/blah" will unmount all instances + // of /dev/blah, not just the most recent. + while (m && (m = m->next)) + if ((opt & OPT_ALL) || !strcmp(path, m->device)) + break; } // Free mtab list if necessary - - if(ENABLE_FEATURE_CLEAN_UP) { - while(mtl) { - m=mtl->next; + + if (ENABLE_FEATURE_CLEAN_UP) { + while (mtl) { + m = mtl->next; free(mtl->device); free(mtl->dir); free(mtl); - mtl=m; + mtl = m; } }