* Added -o loop option for mount, and support in umount for loop
[oweals/busybox.git] / util-linux / umount.c
1 /*
2  * Mini umount implementation for busybox
3  *
4  *
5  * Copyright (C) 1999 by Lineo, inc.
6  * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  *
22  */
23
24 #include "internal.h"
25 #include <stdio.h>
26 #include <sys/mount.h>
27 #include <mntent.h>
28 #include <fstab.h>
29 #include <errno.h>
30
31 #if defined BB_FEATURE_MOUNT_LOOP
32 #include <fcntl.h>
33 #include <sys/ioctl.h>
34 #include <linux/loop.h>
35
36 static int del_loop(const char *device);
37 #endif
38
39 static const char umount_usage[] = 
40 "Usage: umount [flags] filesystem|directory\n\n"
41 "Flags:\n"
42 "\t-a:\tUnmount all file systems"
43 #ifdef BB_MTAB
44 " in /etc/mtab\n\t-n:\tDon't erase /etc/mtab entries\n"
45 #else
46 "\n"
47 #endif
48 ;
49
50
51 static int useMtab = TRUE;
52 static int umountAll = FALSE;
53 extern const char mtab_file[]; /* Defined in utility.c */
54
55 static int 
56 do_umount(const char* name, int useMtab)
57 {
58     int status;
59
60 #if defined BB_FEATURE_MOUNT_LOOP
61     /* check to see if this is a loop device */
62     struct stat fst;
63     char dev[20];
64     const char *oldname = NULL;
65     int i;
66     
67     if (stat(name, &fst)) {
68         fprintf(stderr, "umount: %s: %s\n", name, strerror(errno));
69         exit(1);
70     }
71     for (i = 0 ; i <= 7 ; i++) {
72         struct stat lst;
73         sprintf(dev, "/dev/loop%d", i);
74         if (stat(dev, &lst))
75             continue;
76         if (lst.st_dev == fst.st_dev) {
77             oldname = name;
78             name = dev;
79             break;
80         }
81     }
82 #endif
83
84     status = umount(name);
85
86 #if defined BB_FEATURE_MOUNT_LOOP
87     if (!strncmp("/dev/loop", name, 9)) { /* this was a loop device, delete it */
88         del_loop(name);
89         if (oldname != NULL)
90             name = oldname;
91     }
92 #endif
93 #if defined BB_MTAB
94     if ( status == 0 ) {
95         if ( useMtab==TRUE )
96             erase_mtab(name);
97         return 0;
98     }
99     else
100 #endif
101         return(status);
102 }
103
104 static int
105 umount_all(int useMtab)
106 {
107         int status;
108         struct mntent *m;
109         FILE *mountTable;
110
111         if ((mountTable = setmntent (mtab_file, "r"))) {
112             while ((m = getmntent (mountTable)) != 0) {
113                 char *blockDevice = m->mnt_fsname;
114 #if ! defined BB_MTAB
115                 if (strcmp (blockDevice, "/dev/root") == 0) {
116                     struct fstab* fstabItem;
117                     fstabItem = getfsfile ("/");
118                     if (fstabItem != NULL) {
119                         blockDevice = fstabItem->fs_spec;
120                     }
121                 }
122 #endif
123                 /* Don't umount /proc when doing umount -a */
124                 if (strcmp (blockDevice, "proc") == 0)
125                     continue;
126
127                 status=do_umount (m->mnt_dir, useMtab);
128                 if (status!=0) {
129                     /* Don't bother retrying the umount on busy devices */
130                     if (errno==EBUSY) {
131                         perror(m->mnt_dir); 
132                         continue;
133                     }
134                     status=do_umount (blockDevice, useMtab);
135                     if (status!=0) {
136                         printf ("Couldn't umount %s on %s (type %s): %s\n", 
137                                 blockDevice, m->mnt_dir, m->mnt_type, strerror(errno));
138                     }
139                 }
140             }
141             endmntent (mountTable);
142         }
143         return( TRUE);
144 }
145
146 extern int
147 umount_main(int argc, char** argv)
148 {
149     if (argc < 2) {
150         usage( umount_usage); 
151     }
152
153     /* Parse any options */
154     while (--argc > 0 && **(++argv) == '-') {
155         while (*++(*argv)) switch (**argv) {
156             case 'a':
157                 umountAll = TRUE;
158                 break;
159 #ifdef BB_MTAB
160             case 'n':
161                 useMtab = FALSE;
162                 break;
163 #endif
164             default:
165                 usage( umount_usage);
166         }
167     }
168
169
170     if(umountAll==TRUE) {
171         exit(umount_all(useMtab));
172     }
173     if ( do_umount(*argv,useMtab) == 0 )
174         exit (TRUE);
175     else {
176         perror("umount");
177         exit(FALSE);
178     }
179 }
180
181 #if defined BB_FEATURE_MOUNT_LOOP
182 static int del_loop(const char *device)
183 {
184         int fd;
185
186         if ((fd = open(device, O_RDONLY)) < 0) {
187                 perror(device);
188                 exit(1);
189         }
190         if (ioctl(fd, LOOP_CLR_FD, 0) < 0) {
191                 perror("ioctl: LOOP_CLR_FD");
192                 exit(1);
193         }
194         close(fd);
195         return(0);
196 }
197 #endif