the beginnings of a proper man page for busybox.
[oweals/busybox.git] / umount.c
index 95f7dfb3cbeab4bb9e829d3ea75b343e253ccd1a..af1b3a43e2a95c3b39f1b86f67deafabc1e0037c 100644 (file)
--- a/umount.c
+++ b/umount.c
 #include <fstab.h>
 #include <errno.h>
 
+#if defined BB_FEATURE_MOUNT_LOOP
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/loop.h>
+
+static int del_loop(const char *device);
+#endif
+
 static const char umount_usage[] = 
-"Usage: umount filesystem\n"
-"   or: umount directory\n"
-"   or: umount -a"
-"to unmount all mounted file systems.\n";
+"Usage: umount [flags] filesystem|directory\n\n"
+"Flags:\n"
+"\t-a:\tUnmount all file systems"
+#ifdef BB_MTAB
+" in /etc/mtab\n\t-n:\tDon't erase /etc/mtab entries\n"
+#else
+"\n"
+#endif
+;
+
+
+static int useMtab = TRUE;
+static int umountAll = FALSE;
+extern const char mtab_file[]; /* Defined in utility.c */
+
+static int 
+do_umount(const char* name, int useMtab)
+{
+    int status;
+
+#if defined BB_FEATURE_MOUNT_LOOP
+    /* check to see if this is a loop device */
+    struct stat fst;
+    char dev[20];
+    const char *oldname = NULL;
+    int i;
+    
+    if (stat(name, &fst)) {
+       fprintf(stderr, "umount: %s: %s\n", name, strerror(errno));
+       exit(1);
+    }
+    for (i = 0 ; i <= 7 ; i++) {
+       struct stat lst;
+       sprintf(dev, "/dev/loop%d", i);
+       if (stat(dev, &lst))
+           continue;
+       if (lst.st_dev == fst.st_dev) {
+           oldname = name;
+           name = dev;
+           break;
+       }
+    }
+#endif
+
+    status = umount(name);
+
+#if defined BB_FEATURE_MOUNT_LOOP
+    if (!strncmp("/dev/loop", name, 9)) { /* this was a loop device, delete it */
+       del_loop(name);
+       if (oldname != NULL)
+           name = oldname;
+    }
+#endif
+#if defined BB_MTAB
+    if ( status == 0 ) {
+       if ( useMtab==TRUE )
+           erase_mtab(name);
+       return 0;
+    }
+    else
+#endif
+       return(status);
+}
 
 static int
-umount_all()
+umount_all(int useMtab)
 {
        int status;
        struct mntent *m;
         FILE *mountTable;
 
-        if ((mountTable = setmntent ("/proc/mounts", "r"))) {
+        if ((mountTable = setmntent (mtab_file, "r"))) {
             while ((m = getmntent (mountTable)) != 0) {
                 char *blockDevice = m->mnt_fsname;
-                if (strcmp (blockDevice, "/dev/root") == 0)
-                    blockDevice = (getfsfile ("/"))->fs_spec;
-               status=umount (m->mnt_dir);
+#if ! defined BB_MTAB
+               if (strcmp (blockDevice, "/dev/root") == 0) {
+                   struct fstab* fstabItem;
+                   fstabItem = getfsfile ("/");
+                   if (fstabItem != NULL) {
+                       blockDevice = fstabItem->fs_spec;
+                   }
+               }
+#endif
+               /* Don't umount /proc when doing umount -a */
+                if (strcmp (blockDevice, "proc") == 0)
+                   continue;
+
+               status=do_umount (m->mnt_dir, useMtab);
                if (status!=0) {
                    /* Don't bother retrying the umount on busy devices */
                    if (errno==EBUSY) {
                        perror(m->mnt_dir); 
                        continue;
                    }
-                   printf ("Trying to umount %s failed: %s\n", 
-                           m->mnt_dir, strerror(errno)); 
-                   printf ("Instead trying to umount %s\n", blockDevice); 
-                   status=umount (blockDevice);
+                   status=do_umount (blockDevice, useMtab);
                    if (status!=0) {
                        printf ("Couldn't umount %s on %s (type %s): %s\n", 
                                blockDevice, m->mnt_dir, m->mnt_type, strerror(errno));
@@ -69,30 +144,54 @@ umount_all()
 }
 
 extern int
-umount_main(int argc, char * * argv)
+umount_main(int argc, char** argv)
 {
-
     if (argc < 2) {
        usage( umount_usage); 
     }
-    argc--;
-    argv++;
 
     /* Parse any options */
-    while (**argv == '-') {
+    while (--argc > 0 && **(++argv) == '-') {
        while (*++(*argv)) switch (**argv) {
            case 'a':
-               exit ( umount_all() );
+               umountAll = TRUE;
+               break;
+#ifdef BB_MTAB
+           case 'n':
+               useMtab = FALSE;
                break;
+#endif
            default:
                usage( umount_usage);
        }
     }
-    if ( umount(*argv) == 0 )
-            exit (TRUE);
+
+
+    if(umountAll==TRUE) {
+       exit(umount_all(useMtab));
+    }
+    if ( do_umount(*argv,useMtab) == 0 )
+       exit (TRUE);
     else {
        perror("umount");
-       exit( FALSE);
+       exit(FALSE);
     }
 }
 
+#if defined BB_FEATURE_MOUNT_LOOP
+static int del_loop(const char *device)
+{
+       int fd;
+
+       if ((fd = open(device, O_RDONLY)) < 0) {
+               perror(device);
+               exit(1);
+       }
+       if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
+               perror("ioctl: LOOP_CLR_FD");
+               exit(1);
+       }
+       close(fd);
+       return(0);
+}
+#endif