whitespace sucks
[oweals/busybox.git] / util-linux / umount.c
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
14 #include <limits.h>
15 #include <stdio.h>
16 #include <mntent.h>
17 #include <errno.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <sys/mount.h>
21 #include <getopt.h>
22 #include "busybox.h"
23
24 #define OPTION_STRING           "flaDnrv"
25 #define OPT_FORCE                       1
26 #define OPT_LAZY                        2
27 #define OPT_ALL                         4
28 #define OPT_DONTFREELOOP        8
29 #define OPT_NO_MTAB                     16
30 #define OPT_REMOUNT                     32
31 /* -v is ignored */
32         
33
34 extern int umount_main(int argc, char **argv)
35 {
36         int doForce;
37         char path[2*PATH_MAX];
38         struct mntent me;
39         FILE *fp;
40         int status=EXIT_SUCCESS;
41         unsigned long opt;
42         struct mtab_list {
43                 char *dir;
44                 char *device;
45                 struct mtab_list *next;
46         } *mtl, *m;
47
48         if(argc < 2) bb_show_usage();
49         
50         /* Parse any options */
51         
52         opt = bb_getopt_ulflags (argc, argv, "flaDnrv");
53         
54         argc -= optind;
55         argv += optind;
56
57         doForce = MAX((opt & OPT_FORCE), (opt & OPT_LAZY));
58         
59         /* Get a list of mount points from mtab.  We read them all in now mostly
60          * for umount -a (so we don't have to worry about the list changing while
61          * we iterate over it, or about getting stuck in a loop on the same failing
62          * entry.  Notice that this also naturally reverses the list so that -a
63          * umounts the most recent entries first. */
64         
65         m=mtl=0;
66         if(!(fp = setmntent(bb_path_mtab_file, "r")))
67                 bb_error_msg_and_die("Cannot open %s", bb_path_mtab_file);
68         while (getmntent_r(fp,&me,path,sizeof(path))) {
69                 m=xmalloc(sizeof(struct mtab_list));
70                 m->next=mtl;
71                 m->device=bb_xstrdup(me.mnt_fsname);
72                 m->dir=bb_xstrdup(me.mnt_dir);
73                 mtl=m;
74         }
75         endmntent(fp);
76
77         /* If we're umounting all, then m points to the start of the list and
78          * the argument list should be empty (which will match all). */
79         if(!(opt & OPT_ALL)) m=0;
80
81         // Loop through everything we're supposed to umount, and do so.
82         for(;;) {
83                 int curstat;
84                 
85                 // Do we already know what to umount this time through the loop?
86                 if(m) safe_strncpy(path,m->dir,PATH_MAX);
87                 // For umount -a, end of mtab means time to exit.
88                 else if(opt & OPT_ALL) break;
89                 // Get next command line argument (and look it up in mtab list)
90                 else if(!argc--) break;
91                 else {
92                         // Get next command line argument (and look it up in mtab list)
93                         realpath(*argv++, path);
94                         for(m = mtl; m; m = m->next)
95                                 if(!strcmp(path, m->dir) || !strcmp(path, m->device))
96                                         break;
97                 }
98
99                 // Let's ask the thing nicely to unmount.
100                 curstat = umount(path);
101
102                 // Force the unmount, if necessary.
103                 if(curstat && doForce) {
104                         curstat = umount2(path, doForce);
105                         if(curstat)
106                                 bb_error_msg_and_die("forced umount of %s failed!", path);
107                 }
108
109                 // If still can't umount, maybe remount read-only?      
110                 if (curstat && (opt & OPT_REMOUNT) && errno == EBUSY && m) {
111                         curstat = mount(m->device, path, NULL, MS_REMOUNT|MS_RDONLY, NULL);
112                         bb_error_msg(curstat ? "Cannot remount %s read-only" :
113                                                  "%s busy - remounted read-only", m->device);
114                 }
115
116                 /* De-allocate the loop device.  This ioctl should be ignored on any
117                  * non-loop block devices. */
118                 if(ENABLE_FEATURE_MOUNT_LOOP && !(opt & OPT_DONTFREELOOP) && m)
119                         del_loop(m->device);
120
121                 if(curstat) {
122                         /* Yes, the ENABLE is redundant here, but the optimizer for ARM
123                          * can't do simple constant propagation in local variables... */
124                         if(ENABLE_FEATURE_MTAB_SUPPORT && !(opt & OPT_NO_MTAB) && m)
125                                 erase_mtab(m->dir);
126                         status = EXIT_FAILURE;
127                         bb_perror_msg("Couldn't umount %s\n", path);
128                 }
129                 // Find next matching mtab entry for -a or umount /dev
130                 while(m && (m = m->next)) 
131                         if((opt & OPT_ALL) || !strcmp(path,m->device))
132                                 break;
133         }
134
135         // Free mtab list if necessary
136         
137         if(ENABLE_FEATURE_CLEAN_UP) {
138                 while(mtl) {
139                         m=mtl->next;
140                         free(mtl->device);
141                         free(mtl->dir);
142                         free(mtl);
143                         mtl=m;
144                 }
145         }
146
147         return status;
148 }