blob: 86833b717c544d582beb2ec42130fff7e1e5c9b8 [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Eric Andersenf811e071999-10-09 00:25:00 +00002/*
3 * Mini umount implementation for busybox
4 *
Eric Andersenc4996011999-10-20 22:08:37 +00005 *
Erik Andersen61677fe2000-04-13 01:18:56 +00006 * Copyright (C) 1999,2000 by Lineo, inc.
Eric Andersenc4996011999-10-20 22:08:37 +00007 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
Eric Andersenf811e071999-10-09 00:25:00 +00008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
Eric Andersencc8ed391999-10-05 16:24:54 +000025#include "internal.h"
Eric Andersencc8ed391999-10-05 16:24:54 +000026#include <stdio.h>
Eric Andersencc8ed391999-10-05 16:24:54 +000027#include <sys/mount.h>
Eric Andersenf811e071999-10-09 00:25:00 +000028#include <mntent.h>
Eric Andersenf811e071999-10-09 00:25:00 +000029#include <errno.h>
Eric Andersencc8ed391999-10-05 16:24:54 +000030
Erik Andersene132f4b2000-02-09 04:16:43 +000031
Erik Andersene49d5ec2000-02-08 19:58:47 +000032static const char umount_usage[] =
Erik Andersen7ab9c7e2000-05-12 19:41:47 +000033 "umount [flags] filesystem|directory\n"
34#ifndef BB_FEATURE_TRIVIAL_HELP
35 "Unmount file systems\n"
36 "\nFlags:\n" "\t-a:\tUnmount all file systems"
Eric Andersend0246fb1999-11-04 21:18:07 +000037#ifdef BB_MTAB
Erik Andersene49d5ec2000-02-08 19:58:47 +000038 " in /etc/mtab\n\t-n:\tDon't erase /etc/mtab entries\n"
Eric Andersend0246fb1999-11-04 21:18:07 +000039#else
Erik Andersene49d5ec2000-02-08 19:58:47 +000040 "\n"
Eric Andersend0246fb1999-11-04 21:18:07 +000041#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +000042 "\t-r:\tTry to remount devices as read-only if mount is busy\n"
Erik Andersen6c5f2c62000-05-05 19:49:33 +000043#if defined BB_FEATURE_MOUNT_FORCE
44 "\t-f:\tForce filesystem umount (i.e. unreachable NFS server)\n"
45#endif
Erik Andersence917322000-03-13 04:07:02 +000046#if defined BB_FEATURE_MOUNT_LOOP
Erik Andersen6c5f2c62000-05-05 19:49:33 +000047 "\t-l:\tDo not free loop device (if a loop device has been used)\n"
Erik Andersence917322000-03-13 04:07:02 +000048#endif
Erik Andersen7ab9c7e2000-05-12 19:41:47 +000049#endif
Eric Andersend0246fb1999-11-04 21:18:07 +000050;
51
Erik Andersenfac10d72000-02-07 05:29:42 +000052struct _mtab_entry_t {
Erik Andersene49d5ec2000-02-08 19:58:47 +000053 char *device;
54 char *mountpt;
55 struct _mtab_entry_t *next;
Erik Andersenfac10d72000-02-07 05:29:42 +000056};
57
58static struct _mtab_entry_t *mtab_cache = NULL;
59
60
Eric Andersend0246fb1999-11-04 21:18:07 +000061
Erik Andersen6c5f2c62000-05-05 19:49:33 +000062#if defined BB_FEATURE_MOUNT_FORCE
63static int doForce = FALSE;
64#endif
Erik Andersence917322000-03-13 04:07:02 +000065#if defined BB_FEATURE_MOUNT_LOOP
66static int freeLoop = TRUE;
67#endif
Eric Andersend0246fb1999-11-04 21:18:07 +000068static int useMtab = TRUE;
69static int umountAll = FALSE;
Erik Andersenfac10d72000-02-07 05:29:42 +000070static int doRemount = FALSE;
Erik Andersene49d5ec2000-02-08 19:58:47 +000071extern const char mtab_file[]; /* Defined in utility.c */
Eric Andersend0246fb1999-11-04 21:18:07 +000072
Erik Andersenfac10d72000-02-07 05:29:42 +000073
Erik Andersen5b911dd2000-02-23 22:49:58 +000074
Erik Andersenfac10d72000-02-07 05:29:42 +000075/* These functions are here because the getmntent functions do not appear
76 * to be re-entrant, which leads to all sorts of problems when we try to
77 * use them recursively - randolph
Erik Andersen5b911dd2000-02-23 22:49:58 +000078 *
79 * TODO: Perhaps switch to using Glibc's getmntent_r
80 * -Erik
Erik Andersenfac10d72000-02-07 05:29:42 +000081 */
82void mtab_read(void)
83{
Erik Andersene49d5ec2000-02-08 19:58:47 +000084 struct _mtab_entry_t *entry = NULL;
85 struct mntent *e;
86 FILE *fp;
87
88 if (mtab_cache != NULL)
89 return;
90
91 if ((fp = setmntent(mtab_file, "r")) == NULL) {
92 fprintf(stderr, "Cannot open %s\n", mtab_file);
93 return;
94 }
95 while ((e = getmntent(fp))) {
Erik Andersen0d068a22000-03-21 22:32:57 +000096 entry = xmalloc(sizeof(struct _mtab_entry_t));
Erik Andersene49d5ec2000-02-08 19:58:47 +000097 entry->device = strdup(e->mnt_fsname);
98 entry->mountpt = strdup(e->mnt_dir);
99 entry->next = mtab_cache;
100 mtab_cache = entry;
101 }
102 endmntent(fp);
Erik Andersenfac10d72000-02-07 05:29:42 +0000103}
104
105char *mtab_getinfo(const char *match, const char which)
106{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000107 struct _mtab_entry_t *cur = mtab_cache;
108
109 while (cur) {
110 if (strcmp(cur->mountpt, match) == 0 ||
111 strcmp(cur->device, match) == 0) {
112 if (which == MTAB_GETMOUNTPT) {
113 return cur->mountpt;
114 } else {
Erik Andersenfac10d72000-02-07 05:29:42 +0000115#if !defined BB_MTAB
Erik Andersene49d5ec2000-02-08 19:58:47 +0000116 if (strcmp(cur->device, "/dev/root") == 0) {
Erik Andersenec5bd902000-03-22 07:12:05 +0000117 /* Adjusts device to be the real root device,
118 * or leaves device alone if it can't find it */
119 find_real_root_device_name( cur->device);
120 return ( cur->device);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000121 }
Erik Andersenfac10d72000-02-07 05:29:42 +0000122#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000123 return cur->device;
124 }
125 }
126 cur = cur->next;
Erik Andersenfac10d72000-02-07 05:29:42 +0000127 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000128 return NULL;
Erik Andersenfac10d72000-02-07 05:29:42 +0000129}
130
131char *mtab_first(void **iter)
132{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000133 struct _mtab_entry_t *mtab_iter;
134
135 if (!iter)
136 return NULL;
137 mtab_iter = mtab_cache;
138 *iter = (void *) mtab_iter;
139 return mtab_next(iter);
Erik Andersenfac10d72000-02-07 05:29:42 +0000140}
141
142char *mtab_next(void **iter)
143{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000144 char *mp;
145
146 if (iter == NULL || *iter == NULL)
147 return NULL;
148 mp = ((struct _mtab_entry_t *) (*iter))->mountpt;
149 *iter = (void *) ((struct _mtab_entry_t *) (*iter))->next;
150 return mp;
Erik Andersenfac10d72000-02-07 05:29:42 +0000151}
152
Erik Andersen298854f2000-03-23 01:09:18 +0000153/* Don't bother to clean up, since exit() does that
154 * automagically, so we can save a few bytes */
155#if 0
Erik Andersenfac10d72000-02-07 05:29:42 +0000156void mtab_free(void)
157{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000158 struct _mtab_entry_t *this, *next;
Erik Andersenfac10d72000-02-07 05:29:42 +0000159
Erik Andersene49d5ec2000-02-08 19:58:47 +0000160 this = mtab_cache;
161 while (this) {
162 next = this->next;
163 if (this->device)
164 free(this->device);
165 if (this->mountpt)
166 free(this->mountpt);
167 free(this);
168 this = next;
169 }
Erik Andersenfac10d72000-02-07 05:29:42 +0000170}
Erik Andersen298854f2000-03-23 01:09:18 +0000171#endif
Erik Andersene132f4b2000-02-09 04:16:43 +0000172
173static int do_umount(const char *name, int useMtab)
174{
175 int status;
176 char *blockDevice = mtab_getinfo(name, MTAB_GETDEVICE);
177
178 if (blockDevice && strcmp(blockDevice, name) == 0)
179 name = mtab_getinfo(blockDevice, MTAB_GETMOUNTPT);
180
181 status = umount(name);
182
183#if defined BB_FEATURE_MOUNT_LOOP
Erik Andersence917322000-03-13 04:07:02 +0000184 if (freeLoop == TRUE && blockDevice != NULL && !strncmp("/dev/loop", blockDevice, 9))
Erik Andersene132f4b2000-02-09 04:16:43 +0000185 /* this was a loop device, delete it */
186 del_loop(blockDevice);
187#endif
Erik Andersen6c5f2c62000-05-05 19:49:33 +0000188#if defined BB_FEATURE_MOUNT_FORCE
189 if (status != 0 && doForce == TRUE) {
190 status = umount2(blockDevice, MNT_FORCE);
191 if (status != 0) {
192 fatalError("umount: forced umount of %s failed!\n", blockDevice);
193 }
194 }
195#endif
Erik Andersene132f4b2000-02-09 04:16:43 +0000196 if (status != 0 && doRemount == TRUE && errno == EBUSY) {
197 status = mount(blockDevice, name, NULL,
198 MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL);
199 if (status == 0) {
200 fprintf(stderr, "umount: %s busy - remounted read-only\n",
201 blockDevice);
Erik Andersene132f4b2000-02-09 04:16:43 +0000202 } else {
203 fprintf(stderr, "umount: Cannot remount %s read-only\n",
204 blockDevice);
205 }
206 }
Erik Andersene132f4b2000-02-09 04:16:43 +0000207 if (status == 0) {
208#if defined BB_MTAB
209 if (useMtab == TRUE)
210 erase_mtab(name);
211#endif
212 return (TRUE);
213 }
214 return (FALSE);
215}
216
217static int umount_all(int useMtab)
218{
219 int status = TRUE;
220 char *mountpt;
221 void *iter;
222
223 for (mountpt = mtab_first(&iter); mountpt; mountpt = mtab_next(&iter)) {
224 /* Never umount /proc on a umount -a */
225 if (strstr(mountpt, "proc")!= NULL)
226 continue;
227 status = do_umount(mountpt, useMtab);
228 if (status != 0) {
229 /* Don't bother retrying the umount on busy devices */
230 if (errno == EBUSY) {
231 perror(mountpt);
232 continue;
233 }
234 status = do_umount(mountpt, useMtab);
235 if (status != 0) {
236 printf("Couldn't umount %s on %s: %s\n",
237 mountpt, mtab_getinfo(mountpt, MTAB_GETDEVICE),
238 strerror(errno));
239 }
240 }
241 }
242 return (status);
243}
244
245extern int umount_main(int argc, char **argv)
246{
247 if (argc < 2) {
248 usage(umount_usage);
249 }
250
251 /* Parse any options */
252 while (--argc > 0 && **(++argv) == '-') {
253 while (*++(*argv))
254 switch (**argv) {
255 case 'a':
256 umountAll = TRUE;
257 break;
Erik Andersence917322000-03-13 04:07:02 +0000258#if defined BB_FEATURE_MOUNT_LOOP
Erik Andersen6c5f2c62000-05-05 19:49:33 +0000259 case 'l':
Erik Andersence917322000-03-13 04:07:02 +0000260 freeLoop = FALSE;
261 break;
262#endif
Erik Andersene132f4b2000-02-09 04:16:43 +0000263#ifdef BB_MTAB
264 case 'n':
265 useMtab = FALSE;
266 break;
267#endif
Erik Andersen6c5f2c62000-05-05 19:49:33 +0000268#ifdef BB_FEATURE_MOUNT_FORCE
269 case 'f':
270 doForce = TRUE;
271 break;
272#endif
Erik Andersene132f4b2000-02-09 04:16:43 +0000273 case 'r':
274 doRemount = TRUE;
275 break;
Erik Andersen983b51b2000-04-04 18:14:25 +0000276 case 'v':
277 break; /* ignore -v */
Erik Andersene132f4b2000-02-09 04:16:43 +0000278 default:
279 usage(umount_usage);
280 }
281 }
282
283 mtab_read();
284 if (umountAll == TRUE) {
285 exit(umount_all(useMtab));
286 }
287 if (do_umount(*argv, useMtab) == 0)
288 exit(TRUE);
289 else {
290 perror("umount");
291 exit(FALSE);
292 }
293}
294