summaryrefslogtreecommitdiff
path: root/util-linux/mount.c
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2006-03-14 18:16:25 +0000
committerRob Landley <rob@landley.net>2006-03-14 18:16:25 +0000
commitdc0955b603547dad03e5a9d65f6ab50e0d935aba (patch)
treed176f2a516f6f92aad5c8a35e082e690f29d637e /util-linux/mount.c
parent0b22c1c962ff57e68035413d7790dd2b137a2aeb (diff)
downloadbusybox-w32-dc0955b603547dad03e5a9d65f6ab50e0d935aba.tar.gz
busybox-w32-dc0955b603547dad03e5a9d65f6ab50e0d935aba.tar.bz2
busybox-w32-dc0955b603547dad03e5a9d65f6ab50e0d935aba.zip
The new, new mount rewrite. (Mount double prime?) Still being debugged, but
the new infrastructure is reentrant so in theory it's capable of handling mount -a sanely. It can also re-use existing flags with remount, handle -t auto, mount -a -t, and several smaller bugfixes.
Diffstat (limited to 'util-linux/mount.c')
-rw-r--r--util-linux/mount.c660
1 files changed, 408 insertions, 252 deletions
diff --git a/util-linux/mount.c b/util-linux/mount.c
index 68542f9bc..c5aec74fa 100644
--- a/util-linux/mount.c
+++ b/util-linux/mount.c
@@ -4,11 +4,24 @@
4 * 4 *
5 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>. 5 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
6 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
7 * Copyright (C) 2005 by Rob Landley <rob@landley.net> 7 * Copyright (C) 2005-2006 by Rob Landley <rob@landley.net>
8 * 8 *
9 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 9 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
10 */ 10 */
11 11
12/* todo:
13 * bb_getopt_ulflags();
14 */
15
16/* Design notes: There is no spec for this. Remind me to write one.
17
18 mount_main() calls singlemount() which calls mount_it_now().
19
20 mount_main() can loop through /etc/fstab for mount -a
21 singlemount() can loop through /etc/filesystems for fstype detection.
22 mount_it_now() does the actual mount.
23*/
24
12#include <limits.h> 25#include <limits.h>
13#include <stdlib.h> 26#include <stdlib.h>
14#include <unistd.h> 27#include <unistd.h>
@@ -29,18 +42,28 @@
29#ifndef MS_MOVE 42#ifndef MS_MOVE
30#define MS_MOVE 8192 43#define MS_MOVE 8192
31#endif 44#endif
45#ifndef MS_SILENT
46#define MS_SILENT 32768
47#endif
32 48
33/* Consume standard mount options (from -o options or --options). 49// Not real flags, but we want to be able to check for this.
34 * Set appropriate flags and collect unrecognized ones as a comma separated 50#define MOUNT_NOAUTO (1<<29)
35 * string to pass to kernel */ 51#define MOUNT_SWAP (1<<30)
52/* Standard mount options (from -o options or --options), with corresponding
53 * flags */
36 54
37struct { 55struct {
38 const char *name; 56 const char *name;
39 long flags; 57 long flags;
40} static const mount_options[] = { 58} static const mount_options[] = {
59 // NOP flags.
60
41 {"loop", 0}, 61 {"loop", 0},
42 {"defaults", 0}, 62 {"defaults", 0},
43 {"noauto", 0}, 63 {"quiet", 0},
64
65 // vfs flags
66
44 {"ro", MS_RDONLY}, 67 {"ro", MS_RDONLY},
45 {"rw", ~MS_RDONLY}, 68 {"rw", ~MS_RDONLY},
46 {"nosuid", MS_NOSUID}, 69 {"nosuid", MS_NOSUID},
@@ -51,336 +74,469 @@ struct {
51 {"noexec", MS_NOEXEC}, 74 {"noexec", MS_NOEXEC},
52 {"sync", MS_SYNCHRONOUS}, 75 {"sync", MS_SYNCHRONOUS},
53 {"async", ~MS_SYNCHRONOUS}, 76 {"async", ~MS_SYNCHRONOUS},
54 {"remount", MS_REMOUNT},
55 {"atime", ~MS_NOATIME}, 77 {"atime", ~MS_NOATIME},
56 {"noatime", MS_NOATIME}, 78 {"noatime", MS_NOATIME},
57 {"diratime", ~MS_NODIRATIME}, 79 {"diratime", ~MS_NODIRATIME},
58 {"nodiratime", MS_NODIRATIME}, 80 {"nodiratime", MS_NODIRATIME},
81 {"loud", ~MS_SILENT},
82
83 // action flags
84
85 {"remount", MS_REMOUNT},
59 {"bind", MS_BIND}, 86 {"bind", MS_BIND},
60 {"move", MS_MOVE} 87 {"move", MS_MOVE},
88 {"noauto",MOUNT_NOAUTO},
89 {"swap",MOUNT_SWAP}
61}; 90};
62 91
63/* Uses the mount_options list above */ 92/* Append mount options to string */
64static void parse_mount_options(char *options, int *flags, char **strflags) 93static void append_mount_options(char **oldopts, char *newopts)
94{
95 if(*oldopts && **oldopts) {
96 char *temp=bb_xasprintf("%s,%s",*oldopts,newopts);
97 free(*oldopts);
98 *oldopts=temp;
99 } else {
100 if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
101 *oldopts = bb_xstrdup(newopts);
102 }
103}
104
105/* Use the mount_options list to parse options into flags.
106 * Return list of unrecognized options in *strflags if strflags!=NULL */
107static int parse_mount_options(char *options, char **unrecognized)
65{ 108{
109 int flags = MS_SILENT;
110
66 // Loop through options 111 // Loop through options
67 for(;;) { 112 for (;;) {
68 int i; 113 int i;
69 char *comma = strchr(options, ','); 114 char *comma = strchr(options, ',');
70 115
71 if(comma) *comma = 0; 116 if (comma) *comma = 0;
72 117
73 // Find this option in mount_options 118 // Find this option in mount_options
74 for(i = 0; i < (sizeof(mount_options) / sizeof(*mount_options)); i++) { 119 for (i = 0; i < (sizeof(mount_options) / sizeof(*mount_options)); i++) {
75 if(!strcasecmp(mount_options[i].name, options)) { 120 if (!strcasecmp(mount_options[i].name, options)) {
76 long fl = mount_options[i].flags; 121 long fl = mount_options[i].flags;
77 if(fl < 0) *flags &= fl; 122 if(fl < 0) flags &= fl;
78 else *flags |= fl; 123 else flags |= fl;
79 break; 124 break;
80 } 125 }
81 } 126 }
82 // Unrecognized mount option? 127 // If unrecognized not NULL, append unrecognized mount options */
83 if(i == (sizeof(mount_options) / sizeof(*mount_options))) { 128 if (unrecognized
129 && i == (sizeof(mount_options) / sizeof(*mount_options)))
130 {
84 // Add it to strflags, to pass on to kernel 131 // Add it to strflags, to pass on to kernel
85 i = *strflags ? strlen(*strflags) : 0; 132 i = *unrecognized ? strlen(*unrecognized) : 0;
86 *strflags = xrealloc(*strflags, i+strlen(options)+2); 133 *unrecognized = xrealloc(*unrecognized, i+strlen(options)+2);
134
87 // Comma separated if it's not the first one 135 // Comma separated if it's not the first one
88 if(i) (*strflags)[i++] = ','; 136 if (i) (*unrecognized)[i++] = ',';
89 strcpy((*strflags)+i, options); 137 strcpy((*unrecognized)+i, options);
90 } 138 }
139
91 // Advance to next option, or finish 140 // Advance to next option, or finish
92 if(comma) { 141 if(comma) {
93 *comma = ','; 142 *comma = ',';
94 options = ++comma; 143 options = ++comma;
95 } else break; 144 } else break;
96 } 145 }
146
147 return flags;
97} 148}
98 149
99/* This does the work */ 150// Return a list of all block device backed filesystems
100 151
101extern int mount_main(int argc, char **argv) 152static llist_t *get_block_backed_filesystems(void)
102{ 153{
103 char *string_flags = 0, *fsType = 0, *blockDevice = 0, *directory = 0, 154 char *fs, *buf,
104 *loopFile = 0, *buf = 0, 155 *filesystems[] = {"/etc/filesystems", "/proc/filesystems", 0};
105 *files[] = {"/etc/filesystems", "/proc/filesystems", 0}; 156 llist_t *list = 0;
106 int i, opt, all = FALSE, fakeIt = FALSE, allowWrite = FALSE, 157 int i;
107 rc = 1, useMtab = ENABLE_FEATURE_MTAB_SUPPORT; 158 FILE *f;
108 int flags=0xc0ed0000; // Needed for linux 2.2, ignored by 2.4 and 2.6. 159
109 FILE *file = 0,*f = 0; 160 for(i = 0; filesystems[i]; i++) {
110 char path[PATH_MAX*2]; 161 if(!(f = fopen(filesystems[i], "r"))) continue;
111 struct mntent m; 162
112 struct stat statbuf; 163 for(fs = buf = 0; (fs = buf = bb_get_chomped_line_from_file(f));
164 free(buf))
165 {
166 if(!strncmp(buf,"nodev",5) && isspace(buf[5])) continue;
167
168 while(isspace(*fs)) fs++;
169 if(*fs=='#' || *fs=='*') continue;
170 if(!*fs) continue;
171
172 list=llist_add_to_end(list,bb_xstrdup(fs));
173 }
174 if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
175 }
113 176
114 /* parse long options, like --bind and --move. Note that -o option 177 return list;
115 * and --option are synonymous. Yes, this means --remount,rw works. */ 178}
116 179
117 for(i = opt = 0; i < argc; i++) { 180llist_t *fslist = 0;
118 if(argv[i][0] == '-' && argv[i][1] == '-')
119 parse_mount_options(argv[i]+2, &flags, &string_flags);
120 else argv[opt++] = argv[i];
121 }
122 argc = opt;
123 181
124 // Parse remaining options 182void delete_block_backed_filesystems(void);
183#if ENABLE_FEATURE_CLEAN_UP
184static void delete_block_backed_filesystems(void)
185{
186 llist_free(fslist);
187}
188#endif
125 189
126 while((opt = getopt(argc, argv, "o:t:rwafnv")) > 0) { 190#if ENABLE_FEATURE_MTAB_SUPPORT
127 switch (opt) { 191static int useMtab;
128 case 'o': 192#else
129 parse_mount_options(optarg, &flags, &string_flags); 193#define useMtab 0
130 break; 194#endif
131 case 't': 195
132 fsType = optarg; 196// Perform actual mount of specific filesystem at specific location.
133 break; 197
134 case 'r': 198static int mount_it_now(struct mntent *mp, int vfsflags)
135 flags |= MS_RDONLY; 199{
136 break; 200 int rc;
137 case 'w': 201 char *filteropts = 0;
138 allowWrite=TRUE; 202
139 break; 203 parse_mount_options(mp->mnt_opts, &filteropts);
140 case 'a': 204 // Mount, with fallback to read-only if necessary.
141 all = TRUE; 205
142 break; 206 for(;;) {
143 case 'f': 207 rc = mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
144 fakeIt = TRUE; 208 vfsflags, filteropts);
145 break; 209 if(!rc || (vfsflags&MS_RDONLY) || (errno!=EACCES && errno!=EROFS))
146 case 'n':
147 useMtab = FALSE;
148 break; 210 break;
149 case 'v': 211 bb_error_msg("%s is write-protected, mounting read-only",
150 break; // ignore -v 212 mp->mnt_fsname);
151 default: 213 vfsflags |= MS_RDONLY;
152 bb_show_usage();
153 }
154 } 214 }
155 215
156 // If we have no arguments, show currently mounted filesystems 216 free(filteropts);
157 217
158 if(!all && (optind == argc)) { 218 // Abort entirely if permission denied.
159 FILE *mountTable = setmntent(bb_path_mtab_file, "r");
160 219
161 if(!mountTable) bb_perror_msg_and_die(bb_path_mtab_file); 220 if (rc && errno == EPERM)
221 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
162 222
163 while (getmntent_r(mountTable,&m,path,sizeof(path))) { 223 /* If the mount was successful, and we're maintaining an old-style
164 blockDevice = m.mnt_fsname; 224 * mtab file by hand, add the new entry to it now. */
225
226 if(ENABLE_FEATURE_MTAB_SUPPORT && useMtab && !rc) {
227 FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
228 int i;
165 229
166 // Clean up display a little bit regarding root device 230 if(!mountTable)
167 if(!strcmp(blockDevice, "rootfs")) continue; 231 bb_error_msg("No %s\n",bb_path_mtab_file);
168 if(!strcmp(blockDevice, "/dev/root"))
169 blockDevice = find_block_device("/");
170 232
171 if(!fsType || !strcmp(m.mnt_type, fsType)) 233 // Add vfs string flags
172 printf("%s on %s type %s (%s)\n", blockDevice, m.mnt_dir, 234
173 m.mnt_type, m.mnt_opts); 235 for(i=0; mount_options[i].flags != MS_REMOUNT; i++)
174 if(ENABLE_FEATURE_CLEAN_UP && blockDevice != m.mnt_fsname) 236 if (mount_options[i].flags > 0)
175 free(blockDevice); 237 append_mount_options(&(mp->mnt_opts),
176 } 238// Shut up about the darn const. It's not important. I don't care.
239 (char *)mount_options[i].name);
240
241 // Remove trailing / (if any) from directory we mounted on
242
243 i = strlen(mp->mnt_dir);
244 if(i>1 && mp->mnt_dir[i-1] == '/') mp->mnt_dir[i-1] = 0;
245
246 // Write and close.
247
248 if(!mp->mnt_type || !*mp->mnt_type) mp->mnt_type="--bind";
249 addmntent(mountTable, mp);
177 endmntent(mountTable); 250 endmntent(mountTable);
178 return EXIT_SUCCESS; 251 if (ENABLE_FEATURE_CLEAN_UP)
252 if(strcmp(mp->mnt_type,"--bind")) mp->mnt_type = 0;
179 } 253 }
254
255 return rc;
256}
180 257
181 /* The next argument is what to mount. if there's an argument after that
182 * it's where to mount it. If we're not mounting all, and we have both
183 * of these arguments, jump straight to the actual mount. */
184 258
185 statbuf.st_mode=0; 259// Mount one directory. Handles NFS, loopback, autobind, and filesystem type
186 if(optind < argc) 260// detection. Returns 0 for success, nonzero for failure.
187 blockDevice = !stat(argv[optind], &statbuf) ?
188 bb_simplify_path(argv[optind]) :
189 (ENABLE_FEATURE_CLEAN_UP ? strdup(argv[optind]) : argv[optind]);
190 if(optind+1 < argc) directory = bb_simplify_path(argv[optind+1]);
191 261
192 // If we don't have to loop through fstab, skip ahead a bit. 262static int singlemount(struct mntent *mp)
263{
264 int rc = 0, vfsflags;
265 char *loopFile = 0;
266 llist_t *fl = 0;
267 struct stat st;
268
269 vfsflags = parse_mount_options(mp->mnt_opts, 0);
270
271 // Might this be an NFS filesystem?
272
273 if (ENABLE_FEATURE_MOUNT_NFS &&
274 (!mp->mnt_type || !strcmp(mp->mnt_type,"nfs")) &&
275 strchr(mp->mnt_fsname, ':') != NULL)
276 {
277 char *options=0;
278 parse_mount_options(mp->mnt_opts, &options);
279 if (nfsmount(mp->mnt_fsname, mp->mnt_dir, &vfsflags, &options, 1)) {
280 bb_perror_msg("nfsmount failed");
281 return 1;
282 }
283
284 // Strangely enough, nfsmount() doesn't actually mount() anything.
193 285
194 if(!all && optind+1!=argc) goto singlemount; 286 else return mount_it_now(mp, vfsflags);
287 }
195 288
196 // Loop through /etc/fstab entries to look up this entry. 289 // Look at the file. (Not found isn't a failure for remount.)
290
291 if (lstat(mp->mnt_fsname, &st));
292
293 if (!(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) {
294 // Do we need to allocate a loopback device for it?
295
296 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
297 loopFile = mp->mnt_fsname;
298 mp->mnt_fsname = 0;
299 switch(set_loop(&(mp->mnt_fsname), loopFile, 0)) {
300 case 0:
301 case 1:
302 break;
303 default:
304 bb_error_msg( errno == EPERM || errno == EACCES
305 ? bb_msg_perm_denied_are_you_root
306 : "Couldn't setup loop device");
307 return errno;
308 }
309
310 // Autodetect bind mounts
197 311
198 if(!(file=setmntent("/etc/fstab","r"))) 312 } else if (S_ISDIR(st.st_mode) && !mp->mnt_type) vfsflags |= MS_BIND;
199 bb_perror_msg_and_die("\nCannot read /etc/fstab"); 313 }
200 for(;;) {
201 314
202 // Get next fstab entry 315 /* If we know the fstype (or don't need to), jump straight
316 * to the actual mount. */
203 317
204 if(!getmntent_r(file,&m,path,sizeof(path))) { 318 if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
205 if(!all) 319 rc = mount_it_now(mp, vfsflags);
206 bb_perror_msg("Can't find %s in /etc/fstab\n", blockDevice);
207 break;
208 }
209 320
210 // If we're mounting all and all doesn't mount this one, skip it. 321 // Loop through filesystem types until mount succeeds or we run out
211 322
212 if(all) { 323 else for (fl = fslist; fl; fl = fl->link) {
213 if(strstr(m.mnt_opts,"noauto") || strstr(m.mnt_type,"swap")) 324 mp->mnt_type = fl->data;
214 continue;
215 flags=0;
216 325
217 /* If we're mounting something specific and this isn't it, skip it. 326 if (!(rc = mount_it_now(mp,vfsflags))) break;
218 * Note we must match both the exact text in fstab (ala "proc") or
219 * a full path from root */
220 327
221 } else if(strcmp(blockDevice,m.mnt_fsname) && 328 mp->mnt_type = 0;
222 strcmp(argv[optind],m.mnt_fsname) && 329 }
223 strcmp(blockDevice,m.mnt_dir) &&
224 strcmp(argv[optind],m.mnt_dir)) continue;
225 330
226 /* Parse flags from /etc/fstab (unless this is a single mount 331 // Mount failed. Clean up
227 * overriding fstab -- note the "all" test above zeroed the flags, 332 if (rc && loopFile) {
228 * to prevent flags from previous entries affecting this one, so 333 del_loop(mp->mnt_fsname);
229 * the only way we could get here with nonzero flags is a single 334 if(ENABLE_FEATURE_CLEAN_UP) free(loopFile);
230 * mount). */ 335 }
336 return rc;
337}
231 338
232 if(!flags) {
233 if(ENABLE_FEATURE_CLEAN_UP) free(string_flags);
234 string_flags=NULL;
235 parse_mount_options(m.mnt_opts, &flags, &string_flags);
236 }
237 339
238 /* Fill out remaining fields with info from mtab */ 340// Parse options, if necessary parse fstab/mtab, and call singlemount for
341// each directory to be mounted.
239 342
240 if(ENABLE_FEATURE_CLEAN_UP) { 343int mount_main(int argc, char **argv)
241 free(blockDevice); 344{
242 blockDevice=strdup(m.mnt_fsname); 345 char *cmdopts = bb_xstrdup(""), *fstabname, *fstype=0, *storage_path=0;
243 free(directory); 346 FILE *fstab;
244 directory=strdup(m.mnt_dir); 347 int i, opt, all = FALSE, rc = 1;
245 } else { 348 struct mntent mtpair[2], *mtcur = mtpair;
246 blockDevice=m.mnt_fsname; 349
247 directory=m.mnt_dir; 350 /* parse long options, like --bind and --move. Note that -o option
248 } 351 * and --option are synonymous. Yes, this means --remount,rw works. */
249 fsType=m.mnt_type;
250 352
251 /* Ok, we're ready to actually mount a specific source on a specific 353 for (i = opt = 0; i < argc; i++) {
252 * directory now. */ 354 if (argv[i][0] == '-' && argv[i][1] == '-') {
355 append_mount_options(&cmdopts,argv[i]+2);
356 } else argv[opt++] = argv[i];
357 }
358 argc = opt;
253 359
254singlemount: 360 // Parse remaining options
255 361
256 // If they said -w, override fstab 362 while ((opt = getopt(argc, argv, "o:t:rwavnf")) > 0) {
363 switch (opt) {
364 case 'o':
365 append_mount_options(&cmdopts, optarg);
366 break;
367 case 't':
368 fstype = optarg;
369 break;
370 case 'r':
371 append_mount_options(&cmdopts, "ro");
372 break;
373 case 'w':
374 append_mount_options(&cmdopts, "rw");
375 break;
376 case 'a':
377 all = TRUE;
378 break;
379 case 'n':
380 USE_FEATURE_MTAB_SUPPORT(useMtab = FALSE;)
381 break;
382 case 'f':
383 USE_FEATURE_MTAB_SUPPORT(fakeIt = FALSE;)
384 break;
385 case 'v':
386 break; // ignore -v
387 default:
388 bb_show_usage();
389 }
390 }
391
392 // Ignore type "auto".
257 393
258 if(allowWrite) flags&=~MS_RDONLY; 394 if (fstype && !strcmp(fstype, "auto")) fstype = NULL;
259 395
260 // Might this be an NFS filesystem? 396 // Three or more non-option arguments? Die with a usage message.
261 397
262 if(ENABLE_FEATURE_MOUNT_NFS && (!fsType || !strcmp(fsType,"nfs")) && 398 if (optind-argc>2) bb_show_usage();
263 strchr(blockDevice, ':') != NULL) 399
264 { 400 // If we have no arguments, show currently mounted filesystems
265 if(nfsmount(blockDevice, directory, &flags, &string_flags, 1)) 401
266 bb_perror_msg("nfsmount failed"); 402 if (optind == argc) {
267 else { 403 if (!all) {
268 rc = 0; 404 FILE *mountTable = setmntent(bb_path_mtab_file, "r");
269 fsType="nfs";
270 // Strangely enough, nfsmount() doesn't actually mount()
271 goto mount_it_now;
272 }
273 } else {
274 405
275 // Do we need to allocate a loopback device? 406 if(!mountTable) bb_error_msg_and_die("No %s",bb_path_mtab_file);
276 407
277 if(ENABLE_FEATURE_MOUNT_LOOP && !fakeIt && S_ISREG(statbuf.st_mode)) 408 while (getmntent_r(mountTable,mtpair,bb_common_bufsiz1,
409 sizeof(bb_common_bufsiz1)))
278 { 410 {
279 loopFile = blockDevice; 411 // Don't show rootfs.
280 blockDevice = 0; 412 if (!strcmp(mtpair->mnt_fsname, "rootfs")) continue;
281 switch(set_loop(&blockDevice, loopFile, 0)) { 413
282 case 0: 414 if (!fstype || !strcmp(mtpair->mnt_type, fstype))
283 case 1: 415 printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
284 break; 416 mtpair->mnt_dir, mtpair->mnt_type,
285 default: 417 mtpair->mnt_opts);
286 bb_error_msg_and_die(
287 errno == EPERM || errno == EACCES ?
288 bb_msg_perm_denied_are_you_root :
289 "Couldn't setup loop device");
290 break;
291 }
292 } 418 }
419 if (ENABLE_FEATURE_CLEAN_UP) endmntent(mountTable);
420 return EXIT_SUCCESS;
421 }
422 }
293 423
294 /* If we know the fstype (or don't need to), jump straight 424 /* Initialize list of block backed filesystems */
295 * to the actual mount. */ 425
426 fslist = get_block_backed_filesystems();
427 if (ENABLE_FEATURE_CLEAN_UP) atexit(delete_block_backed_filesystems);
428
429 // When we have two arguments, the second is the directory and we can
430 // skip looking at fstab entirely. We can always abspath() the directory
431 // argument when we get it.
432
433 if (optind+2 == argc) {
434 mtpair->mnt_fsname = argv[optind];
435 mtpair->mnt_dir = argv[optind+1];
436 mtpair->mnt_type = fstype;
437 mtpair->mnt_opts = cmdopts;
438 rc = singlemount(mtpair);
439 goto clean_up;
440 }
296 441
297 if(fsType || (flags & (MS_REMOUNT | MS_BIND | MS_MOVE))) 442 // If we have at least one argument, it's the storage location
298 goto mount_it_now; 443
299 } 444 if (optind < argc) storage_path = bb_simplify_path(argv[optind]);
445
446 // Open either fstab or mtab
447
448 if (parse_mount_options(cmdopts,0) & MS_REMOUNT)
449 fstabname = (char *)bb_path_mtab_file; // Again with the evil const.
450 else fstabname="/etc/fstab";
451
452 if (!(fstab=setmntent(fstabname,"r")))
453 bb_perror_msg_and_die("Cannot read %s",fstabname);
454
455 // Loop through entries until we find what we're looking for.
456
457 memset(mtpair,0,sizeof(mtpair));
458 for (;;) {
459 struct mntent *mtnext = mtpair + (mtcur==mtpair ? 1 : 0);
300 460
301 // Loop through filesystem types until mount succeeds or we run out 461 // Get next fstab entry
302 462
303 for(i = 0; files[i] && rc; i++) { 463 if (!getmntent_r(fstab, mtcur, bb_common_bufsiz1,
304 f = fopen(files[i], "r"); 464 sizeof(bb_common_bufsiz1)))
305 if(!f) continue; 465 {
306 // Get next block device backed filesystem 466 // Were we looking for something specific?
307 for(buf = 0; (buf = fsType = bb_get_chomped_line_from_file(f)); 467
308 free(buf)) 468 if (optind != argc) {
309 { 469
310 // Skip funky entries in /proc 470 // If we didn't find anything, complain.
311 if(!strncmp(buf,"nodev",5) && isspace(buf[5])) continue; 471
312 472 if (!mtnext->mnt_fsname)
313 while(isspace(*fsType)) fsType++; 473 bb_error_msg_and_die("Can't find %s in %s",
314 if(*buf=='#' || *buf=='*') continue; 474 argv[optind], fstabname);
315 if(!*fsType) continue; 475
316mount_it_now: 476 // Mount the last thing we found.
317 // Okay, try to mount 477
318 478 mtcur = mtnext;
319 if (!fakeIt) { 479 mtcur->mnt_opts=bb_xstrdup(mtcur->mnt_opts);
320 for(;;) { 480 append_mount_options(&(mtcur->mnt_opts),cmdopts);
321 rc = mount(blockDevice, directory, fsType, flags, string_flags); 481 rc = singlemount(mtcur);
322 if(!rc || (flags&MS_RDONLY) || (errno!=EACCES && errno!=EROFS)) 482 free(mtcur->mnt_opts);
323 break;
324 bb_error_msg("%s is write-protected, mounting read-only", blockDevice);
325 flags|=MS_RDONLY;
326 }
327 }
328 if(!rc || !f) break;
329 } 483 }
330 if(!f) break; 484 break;
331 fclose(f);
332 // goto mount_it_now with -a can jump past the initialization
333 f=0;
334 if(!rc) break;
335 } 485 }
486
487 /* If we're trying to mount something specific and this isn't it,
488 * skip it. Note we must match both the exact text in fstab (ala
489 * "proc") or a full path from root */
490
491 if (optind != argc) {
492
493 // Is this what we're looking for?
494
495 if(strcmp(argv[optind],mtcur->mnt_fsname) &&
496 strcmp(storage_path,mtcur->mnt_fsname) &&
497 strcmp(argv[optind],mtcur->mnt_dir) &&
498 strcmp(storage_path,mtcur->mnt_dir)) continue;
499
500 // Remember this entry. Something later may have overmounted
501 // it, and we want the _last_ match.
502
503 mtcur = mtnext;
504
505 // If we're mounting all.
336 506
337 /* If the mount was successful, and we're maintaining an old-style
338 * mtab file by hand, add new entry to it now. */
339 if((!rc || fakeIt) && useMtab) {
340 FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
341
342 if(!mountTable) bb_perror_msg(bb_path_mtab_file);
343 else {
344 // Remove trailing / (if any) from directory we mounted on
345 int length=strlen(directory);
346 if(length>1 && directory[length-1] == '/')
347 directory[length-1]=0;
348
349 // Fill out structure (should be ok to re-use existing one).
350 m.mnt_fsname=blockDevice;
351 m.mnt_dir=directory;
352 m.mnt_type=fsType ? : "--bind";
353 m.mnt_opts=string_flags ? :
354 ((flags & MS_RDONLY) ? "ro" : "rw");
355 m.mnt_freq = 0;
356 m.mnt_passno = 0;
357
358 // Write and close
359 addmntent(mountTable, &m);
360 endmntent(mountTable);
361 }
362 } else { 507 } else {
363 // Mount failed. Clean up 508
364 if(loopFile) { 509 // Do we need to match a filesystem type?
365 del_loop(blockDevice); 510 if (fstype && strcmp(mtcur->mnt_type,fstype)) continue;
366 if(ENABLE_FEATURE_CLEAN_UP) free(loopFile); 511
512 // Skip noauto and swap anyway.
513
514 if (parse_mount_options(mtcur->mnt_opts,0)
515 & (MOUNT_NOAUTO | MOUNT_SWAP)) continue;
516
517 // Mount this thing.
518
519 rc = singlemount(mtcur);
520 if (rc) {
521 // Don't whine about already mounted fs when mounting all.
522 if (errno == EBUSY) rc = 0;
523 else break;
367 } 524 }
368 // Don't whine about already mounted fs when mounting all.
369 if(rc<0 && errno == EBUSY && all) rc = 0;
370 else if (errno == EPERM)
371 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
372 } 525 }
373 // We couldn't free this earlier becase fsType could be in buf.
374 if(ENABLE_FEATURE_CLEAN_UP) free(buf);
375 if(!all) break;
376 } 526 }
527 if (ENABLE_FEATURE_CLEAN_UP) endmntent(fstab);
528
529clean_up:
377 530
378 if(file) endmntent(file); 531 if (ENABLE_FEATURE_CLEAN_UP) {
379 if(rc) bb_perror_msg("Mounting %s on %s failed", blockDevice, directory); 532 free(storage_path);
380 if(ENABLE_FEATURE_CLEAN_UP) { 533 free(cmdopts);
381 free(blockDevice); 534 free(fstype);
382 free(directory);
383 } 535 }
536
537 if(rc)
538 bb_perror_msg("Mounting %s on %s failed",
539 mtcur->mnt_fsname, mtcur->mnt_dir);
384 540
385 return rc; 541 return rc;
386} 542}