blob: e76e0521f261bbe6067ccc6ae1ff5dd8125b9c9f [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 Andersen3570a342000-09-25 21:45:58 +000025#include "busybox.h"
Eric Andersencc8ed391999-10-05 16:24:54 +000026#include <stdio.h>
Eric Andersenf811e071999-10-09 00:25:00 +000027#include <mntent.h>
Eric Andersenf811e071999-10-09 00:25:00 +000028#include <errno.h>
Eric Andersene1e23ee2000-06-19 18:38:51 +000029
30
Eric Andersen2cd439f2000-07-08 19:10:29 +000031#define MNT_FORCE 1
Eric Andersen2cd439f2000-07-08 19:10:29 +000032#define MS_MGC_VAL 0xc0ed0000 /* Magic number indicatng "new" flags */
Eric Andersen2cd439f2000-07-08 19:10:29 +000033#define MS_REMOUNT 32 /* Alter flags of a mounted FS. */
Eric Andersen2cd439f2000-07-08 19:10:29 +000034#define MS_RDONLY 1 /* Mount read-only. */
Eric Andersen2cd439f2000-07-08 19:10:29 +000035
Eric Andersena57ba4d2000-07-08 19:20:49 +000036extern int mount (__const char *__special_file, __const char *__dir,
37 __const char *__fstype, unsigned long int __rwflag,
38 __const void *__data);
39extern int umount (__const char *__special_file);
40extern int umount2 (__const char *__special_file, int __flags);
Eric Andersen2cd439f2000-07-08 19:10:29 +000041
Erik Andersenfac10d72000-02-07 05:29:42 +000042struct _mtab_entry_t {
Erik Andersene49d5ec2000-02-08 19:58:47 +000043 char *device;
44 char *mountpt;
45 struct _mtab_entry_t *next;
Erik Andersenfac10d72000-02-07 05:29:42 +000046};
47
48static struct _mtab_entry_t *mtab_cache = NULL;
49
50
Eric Andersend0246fb1999-11-04 21:18:07 +000051
Erik Andersen6c5f2c62000-05-05 19:49:33 +000052#if defined BB_FEATURE_MOUNT_FORCE
53static int doForce = FALSE;
54#endif
Erik Andersence917322000-03-13 04:07:02 +000055#if defined BB_FEATURE_MOUNT_LOOP
56static int freeLoop = TRUE;
57#endif
Eric Andersend0246fb1999-11-04 21:18:07 +000058static int useMtab = TRUE;
59static int umountAll = FALSE;
Erik Andersenfac10d72000-02-07 05:29:42 +000060static int doRemount = FALSE;
Erik Andersene49d5ec2000-02-08 19:58:47 +000061extern const char mtab_file[]; /* Defined in utility.c */
Eric Andersend0246fb1999-11-04 21:18:07 +000062
Erik Andersenfac10d72000-02-07 05:29:42 +000063
Erik Andersen5b911dd2000-02-23 22:49:58 +000064
Erik Andersenfac10d72000-02-07 05:29:42 +000065/* These functions are here because the getmntent functions do not appear
66 * to be re-entrant, which leads to all sorts of problems when we try to
67 * use them recursively - randolph
Erik Andersen5b911dd2000-02-23 22:49:58 +000068 *
69 * TODO: Perhaps switch to using Glibc's getmntent_r
70 * -Erik
Erik Andersenfac10d72000-02-07 05:29:42 +000071 */
72void mtab_read(void)
73{
Erik Andersene49d5ec2000-02-08 19:58:47 +000074 struct _mtab_entry_t *entry = NULL;
75 struct mntent *e;
76 FILE *fp;
77
78 if (mtab_cache != NULL)
79 return;
80
81 if ((fp = setmntent(mtab_file, "r")) == NULL) {
Mark Whitleyf57c9442000-12-07 19:56:48 +000082 error_msg("Cannot open %s\n", mtab_file);
Erik Andersene49d5ec2000-02-08 19:58:47 +000083 return;
84 }
85 while ((e = getmntent(fp))) {
Erik Andersen0d068a22000-03-21 22:32:57 +000086 entry = xmalloc(sizeof(struct _mtab_entry_t));
Erik Andersene49d5ec2000-02-08 19:58:47 +000087 entry->device = strdup(e->mnt_fsname);
88 entry->mountpt = strdup(e->mnt_dir);
89 entry->next = mtab_cache;
90 mtab_cache = entry;
91 }
92 endmntent(fp);
Erik Andersenfac10d72000-02-07 05:29:42 +000093}
94
95char *mtab_getinfo(const char *match, const char which)
96{
Erik Andersene49d5ec2000-02-08 19:58:47 +000097 struct _mtab_entry_t *cur = mtab_cache;
98
99 while (cur) {
100 if (strcmp(cur->mountpt, match) == 0 ||
101 strcmp(cur->device, match) == 0) {
102 if (which == MTAB_GETMOUNTPT) {
103 return cur->mountpt;
104 } else {
Erik Andersenfac10d72000-02-07 05:29:42 +0000105#if !defined BB_MTAB
Erik Andersene49d5ec2000-02-08 19:58:47 +0000106 if (strcmp(cur->device, "/dev/root") == 0) {
Erik Andersenec5bd902000-03-22 07:12:05 +0000107 /* Adjusts device to be the real root device,
108 * or leaves device alone if it can't find it */
109 find_real_root_device_name( cur->device);
110 return ( cur->device);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000111 }
Erik Andersenfac10d72000-02-07 05:29:42 +0000112#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000113 return cur->device;
114 }
115 }
116 cur = cur->next;
Erik Andersenfac10d72000-02-07 05:29:42 +0000117 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000118 return NULL;
Erik Andersenfac10d72000-02-07 05:29:42 +0000119}
120
121char *mtab_first(void **iter)
122{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000123 struct _mtab_entry_t *mtab_iter;
124
125 if (!iter)
126 return NULL;
127 mtab_iter = mtab_cache;
128 *iter = (void *) mtab_iter;
129 return mtab_next(iter);
Erik Andersenfac10d72000-02-07 05:29:42 +0000130}
131
132char *mtab_next(void **iter)
133{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000134 char *mp;
135
136 if (iter == NULL || *iter == NULL)
137 return NULL;
138 mp = ((struct _mtab_entry_t *) (*iter))->mountpt;
139 *iter = (void *) ((struct _mtab_entry_t *) (*iter))->next;
140 return mp;
Erik Andersenfac10d72000-02-07 05:29:42 +0000141}
142
Erik Andersen298854f2000-03-23 01:09:18 +0000143/* Don't bother to clean up, since exit() does that
144 * automagically, so we can save a few bytes */
Eric Andersenb040d4f2000-07-25 18:01:20 +0000145#ifdef BB_FEATURE_CLEAN_UP
Erik Andersenfac10d72000-02-07 05:29:42 +0000146void mtab_free(void)
147{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000148 struct _mtab_entry_t *this, *next;
Erik Andersenfac10d72000-02-07 05:29:42 +0000149
Erik Andersene49d5ec2000-02-08 19:58:47 +0000150 this = mtab_cache;
151 while (this) {
152 next = this->next;
153 if (this->device)
154 free(this->device);
155 if (this->mountpt)
156 free(this->mountpt);
157 free(this);
158 this = next;
159 }
Erik Andersenfac10d72000-02-07 05:29:42 +0000160}
Erik Andersen298854f2000-03-23 01:09:18 +0000161#endif
Erik Andersene132f4b2000-02-09 04:16:43 +0000162
163static int do_umount(const char *name, int useMtab)
164{
165 int status;
166 char *blockDevice = mtab_getinfo(name, MTAB_GETDEVICE);
167
168 if (blockDevice && strcmp(blockDevice, name) == 0)
169 name = mtab_getinfo(blockDevice, MTAB_GETMOUNTPT);
170
171 status = umount(name);
172
173#if defined BB_FEATURE_MOUNT_LOOP
Erik Andersence917322000-03-13 04:07:02 +0000174 if (freeLoop == TRUE && blockDevice != NULL && !strncmp("/dev/loop", blockDevice, 9))
Erik Andersene132f4b2000-02-09 04:16:43 +0000175 /* this was a loop device, delete it */
176 del_loop(blockDevice);
177#endif
Erik Andersen6c5f2c62000-05-05 19:49:33 +0000178#if defined BB_FEATURE_MOUNT_FORCE
179 if (status != 0 && doForce == TRUE) {
180 status = umount2(blockDevice, MNT_FORCE);
181 if (status != 0) {
Mark Whitleyf57c9442000-12-07 19:56:48 +0000182 error_msg_and_die("forced umount of %s failed!\n", blockDevice);
Erik Andersen6c5f2c62000-05-05 19:49:33 +0000183 }
184 }
185#endif
Erik Andersene132f4b2000-02-09 04:16:43 +0000186 if (status != 0 && doRemount == TRUE && errno == EBUSY) {
187 status = mount(blockDevice, name, NULL,
188 MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL);
189 if (status == 0) {
Mark Whitleyf57c9442000-12-07 19:56:48 +0000190 error_msg("%s busy - remounted read-only\n", blockDevice);
Erik Andersene132f4b2000-02-09 04:16:43 +0000191 } else {
Mark Whitleyf57c9442000-12-07 19:56:48 +0000192 error_msg("Cannot remount %s read-only\n", blockDevice);
Erik Andersene132f4b2000-02-09 04:16:43 +0000193 }
194 }
Erik Andersene132f4b2000-02-09 04:16:43 +0000195 if (status == 0) {
196#if defined BB_MTAB
197 if (useMtab == TRUE)
198 erase_mtab(name);
199#endif
200 return (TRUE);
201 }
202 return (FALSE);
203}
204
205static int umount_all(int useMtab)
206{
207 int status = TRUE;
208 char *mountpt;
209 void *iter;
210
211 for (mountpt = mtab_first(&iter); mountpt; mountpt = mtab_next(&iter)) {
212 /* Never umount /proc on a umount -a */
213 if (strstr(mountpt, "proc")!= NULL)
214 continue;
215 status = do_umount(mountpt, useMtab);
216 if (status != 0) {
217 /* Don't bother retrying the umount on busy devices */
218 if (errno == EBUSY) {
219 perror(mountpt);
220 continue;
221 }
222 status = do_umount(mountpt, useMtab);
223 if (status != 0) {
224 printf("Couldn't umount %s on %s: %s\n",
225 mountpt, mtab_getinfo(mountpt, MTAB_GETDEVICE),
226 strerror(errno));
227 }
228 }
229 }
230 return (status);
231}
232
233extern int umount_main(int argc, char **argv)
234{
235 if (argc < 2) {
236 usage(umount_usage);
237 }
Eric Andersenb040d4f2000-07-25 18:01:20 +0000238#ifdef BB_FEATURE_CLEAN_UP
239 atexit(mtab_free);
240#endif
Erik Andersene132f4b2000-02-09 04:16:43 +0000241
242 /* Parse any options */
243 while (--argc > 0 && **(++argv) == '-') {
244 while (*++(*argv))
245 switch (**argv) {
246 case 'a':
247 umountAll = TRUE;
248 break;
Erik Andersence917322000-03-13 04:07:02 +0000249#if defined BB_FEATURE_MOUNT_LOOP
Erik Andersen6c5f2c62000-05-05 19:49:33 +0000250 case 'l':
Erik Andersence917322000-03-13 04:07:02 +0000251 freeLoop = FALSE;
252 break;
253#endif
Erik Andersene132f4b2000-02-09 04:16:43 +0000254#ifdef BB_MTAB
255 case 'n':
256 useMtab = FALSE;
257 break;
258#endif
Erik Andersen6c5f2c62000-05-05 19:49:33 +0000259#ifdef BB_FEATURE_MOUNT_FORCE
260 case 'f':
261 doForce = TRUE;
262 break;
263#endif
Erik Andersene132f4b2000-02-09 04:16:43 +0000264 case 'r':
265 doRemount = TRUE;
266 break;
Erik Andersen983b51b2000-04-04 18:14:25 +0000267 case 'v':
268 break; /* ignore -v */
Erik Andersene132f4b2000-02-09 04:16:43 +0000269 default:
270 usage(umount_usage);
271 }
272 }
273
274 mtab_read();
275 if (umountAll == TRUE) {
Matt Kraai3e856ce2000-12-01 02:55:13 +0000276 if (umount_all(useMtab) == TRUE)
277 return EXIT_SUCCESS;
278 else
279 return EXIT_FAILURE;
Erik Andersene132f4b2000-02-09 04:16:43 +0000280 }
Matt Kraai92ed8a32000-12-06 15:55:23 +0000281 if (do_umount(*argv, useMtab) == TRUE)
Matt Kraai3e856ce2000-12-01 02:55:13 +0000282 return EXIT_SUCCESS;
Eric Andersene1e23ee2000-06-19 18:38:51 +0000283 perror("umount");
Matt Kraai3e856ce2000-12-01 02:55:13 +0000284 return EXIT_FAILURE;
Erik Andersene132f4b2000-02-09 04:16:43 +0000285}
286