]> git.ipfire.org Git - thirdparty/util-linux.git/blob - mount/mount.c
Imported from util-linux-2.10s tarball.
[thirdparty/util-linux.git] / mount / mount.c
1 /*
2 * A mount(8) for Linux 0.99.
3 * mount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
4 *
5 * Wed Sep 14 22:43:00 1994: Mitchum DSouza
6 * (mitch@mrc-applied-psychology.cambridge.ac.uk) added support for mounting
7 * the "loop" device.
8 *
9 * Wed Sep 14 22:55:10 1994: Sander van Malssen (svm@kozmix.hacktic.nl)
10 * added support for remounting readonly file systems readonly.
11 *
12 * Wed Feb 8 12:27:00 1995: Andries.Brouwer@cwi.nl fixed up error messages.
13 * Sat Jun 3 20:44:38 1995: Patches from Andries.Brouwer@cwi.nl applied.
14 * Tue Sep 26 22:38:20 1995: aeb@cwi.nl, many changes
15 * Fri Feb 23 13:47:00 1996: aeb@cwi.nl, loop device related changes
16 *
17 * Since then, many changes - aeb.
18 *
19 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
20 * Implemented the "bg", "fg" and "retry" mount options for NFS.
21 *
22 * Tue Aug 4 15:54:31 1998: aeb@cwi.nl:
23 * Open fd 0,1,2 so that printf's do not clobber /etc/mtab or so.
24 * Mangle filenames with embedded spaces. Add ufsmagic. Add locking.
25 * Avoid unnecessary error messages about /proc.
26 * Improve support for noncanonical names in /etc/fstab.
27 * Add support for volume labels and UUIDs.
28 *
29 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
30 * - added Native Language Support
31 * 1999-03-21 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
32 * - fixed strerr(errno) in gettext calls
33 * 1999-07-05 Hirokazu Takahashi <h-takaha@sss.abk.nec.co.jp>
34 * - fixed use of nouser option
35 * 1999-09-09 Michael K. Johnson <johnsonm@redhat.com>
36 * - added `owner' mount option
37 * 2000-05-11 Mark A. Peloquin <peloquin@us.ibm.com>
38 * - check_special_mountprog now returns correct status
39 * 2000-11-08 aeb: accept nonnumeric uid=, gid= options
40 */
41
42 #include <unistd.h>
43 #include <ctype.h>
44 #include <errno.h>
45 #include <string.h>
46 #include <getopt.h>
47 #include <stdio.h>
48
49 #include <pwd.h>
50 #include <grp.h>
51
52 #include <sys/types.h>
53 #include <sys/ioctl.h>
54 #include <sys/stat.h>
55 #include <sys/wait.h>
56 #include <sys/mount.h>
57
58 #include "mount_constants.h"
59 #include "sundries.h"
60 #include "mntent.h"
61 #include "fstab.h"
62 #include "lomount.h"
63 #include "loop.h"
64 #include "linux_fs.h" /* for BLKGETSIZE */
65 #include "mount_guess_rootdev.h"
66 #include "mount_guess_fstype.h"
67 #include "mount_by_label.h"
68 #include "getusername.h"
69 #include "nls.h"
70
71 #define DO_PS_FIDDLING
72
73 #ifdef DO_PS_FIDDLING
74 #include "setproctitle.h"
75 #endif
76
77 /* True for fake mount (-f). */
78 static int fake = 0;
79
80 /* Don't write a entry in /etc/mtab (-n). */
81 static int nomtab = 0;
82
83 /* True for explicit readonly (-r). */
84 static int readonly = 0;
85
86 /* Nonzero for chatty (-v). */
87 int verbose = 0;
88
89 /* Nonzero for sloppy (-s). */
90 int sloppy = 0;
91
92 /* True for explicit read/write (-w). */
93 static int readwrite = 0;
94
95 /* True for all mount (-a). */
96 int all = 0;
97
98 /* True for fork() during all mount (-F). */
99 static int optfork = 0;
100
101 /* Add volumelabel in a listing of mounted devices (-l). */
102 static int list_with_volumelabel = 0;
103
104 /* Nonzero for mount --bind */
105 static int bind = 0;
106
107 /* Nonzero for mount {--replace|--before|--after|--over} */
108 static int mounttype = 0;
109
110 /* True if ruid != euid. */
111 static int suid = 0;
112
113 /* Map from -o and fstab option strings to the flag argument to mount(2). */
114 struct opt_map {
115 const char *opt; /* option name */
116 int skip; /* skip in mtab option string */
117 int inv; /* true if flag value should be inverted */
118 int mask; /* flag mask value */
119 };
120
121 /* Custom mount options for our own purposes. */
122 /* Maybe these should now be freed for kernel use again */
123 #define MS_NOAUTO 0x80000000
124 #define MS_USERS 0x40000000
125 #define MS_USER 0x20000000
126 #define MS_OWNER 0x10000000
127 #define MS_LOOP 0x00010000
128
129 /* Options that we keep the mount system call from seeing. */
130 #define MS_NOSYS (MS_NOAUTO|MS_USERS|MS_USER|MS_LOOP)
131
132 /* Options that we keep from appearing in the options field in the mtab. */
133 #define MS_NOMTAB (MS_REMOUNT|MS_NOAUTO|MS_USERS|MS_USER)
134
135 /* Options that we make ordinary users have by default. */
136 #define MS_SECURE (MS_NOEXEC|MS_NOSUID|MS_NODEV)
137
138 /* Options that we make owner-mounted devices have by default */
139 #define MS_OWNERSECURE (MS_NOSUID|MS_NODEV)
140
141 static const struct opt_map opt_map[] = {
142 { "defaults", 0, 0, 0 }, /* default options */
143 { "ro", 1, 0, MS_RDONLY }, /* read-only */
144 { "rw", 1, 1, MS_RDONLY }, /* read-write */
145 { "exec", 0, 1, MS_NOEXEC }, /* permit execution of binaries */
146 { "noexec", 0, 0, MS_NOEXEC }, /* don't execute binaries */
147 { "suid", 0, 1, MS_NOSUID }, /* honor suid executables */
148 { "nosuid", 0, 0, MS_NOSUID }, /* don't honor suid executables */
149 { "dev", 0, 1, MS_NODEV }, /* interpret device files */
150 { "nodev", 0, 0, MS_NODEV }, /* don't interpret devices */
151 { "sync", 0, 0, MS_SYNCHRONOUS}, /* synchronous I/O */
152 { "async", 0, 1, MS_SYNCHRONOUS}, /* asynchronous I/O */
153 { "remount", 0, 0, MS_REMOUNT}, /* Alter flags of mounted FS */
154 { "bind", 0, 0, MS_BIND }, /* Remount part of tree elsewhere */
155 { "auto", 0, 1, MS_NOAUTO }, /* Can be mounted using -a */
156 { "noauto", 0, 0, MS_NOAUTO }, /* Can only be mounted explicitly */
157 { "users", 0, 0, MS_USERS }, /* Allow ordinary user to mount */
158 { "nousers", 0, 1, MS_USERS }, /* Forbid ordinary user to mount */
159 { "user", 0, 0, MS_USER }, /* Allow ordinary user to mount */
160 { "nouser", 0, 1, MS_USER }, /* Forbid ordinary user to mount */
161 { "owner", 0, 0, MS_OWNER }, /* Let the owner of the device mount */
162 { "noowner", 0, 1, MS_OWNER }, /* Device owner has no special privs */
163 /* add new options here */
164 #ifdef MS_NOSUB
165 { "sub", 0, 1, MS_NOSUB }, /* allow submounts */
166 { "nosub", 0, 0, MS_NOSUB }, /* don't allow submounts */
167 #endif
168 #ifdef MS_SILENT
169 { "quiet", 0, 0, MS_SILENT }, /* be quiet */
170 { "loud", 0, 1, MS_SILENT }, /* print out messages. */
171 #endif
172 #ifdef MS_MANDLOCK
173 { "mand", 0, 0, MS_MANDLOCK }, /* Allow mandatory locks on this FS */
174 { "nomand", 0, 1, MS_MANDLOCK }, /* Forbid mandatory locks on this FS */
175 #endif
176 { "loop", 1, 0, MS_LOOP }, /* use a loop device */
177 #ifdef MS_NOATIME
178 { "atime", 0, 1, MS_NOATIME }, /* Update access time */
179 { "noatime", 0, 0, MS_NOATIME }, /* Do not update access time */
180 #endif
181 #ifdef MS_NODIRATIME
182 { "diratime", 0, 1, MS_NODIRATIME }, /* Update dir access times */
183 { "nodiratime", 0, 0, MS_NODIRATIME },/* Do not update dir access times */
184 #endif
185 { NULL, 0, 0, 0 }
186 };
187
188 static char *opt_loopdev, *opt_vfstype, *opt_offset, *opt_encryption,
189 *opt_speed;
190
191 static struct string_opt_map {
192 char *tag;
193 int skip;
194 char **valptr;
195 } string_opt_map[] = {
196 { "loop=", 0, &opt_loopdev },
197 { "vfs=", 1, &opt_vfstype },
198 { "offset=", 0, &opt_offset },
199 { "encryption=", 0, &opt_encryption },
200 { "speed=", 0, &opt_speed },
201 { NULL, 0, NULL }
202 };
203
204 static void
205 clear_string_opts(void) {
206 struct string_opt_map *m;
207
208 for (m = &string_opt_map[0]; m->tag; m++)
209 *(m->valptr) = NULL;
210 }
211
212 static int
213 parse_string_opt(char *s) {
214 struct string_opt_map *m;
215 int lth;
216
217 for (m = &string_opt_map[0]; m->tag; m++) {
218 lth = strlen(m->tag);
219 if (!strncmp(s, m->tag, lth)) {
220 *(m->valptr) = xstrdup(s + lth);
221 return 1;
222 }
223 }
224 return 0;
225 }
226
227 int mount_quiet=0;
228
229 /* Report on a single mount. */
230 static void
231 print_one (const struct mntent *me) {
232 if (mount_quiet)
233 return;
234 printf ("%s on %s", me->mnt_fsname, me->mnt_dir);
235 if (me->mnt_type != NULL && *(me->mnt_type) != '\0')
236 printf (" type %s", me->mnt_type);
237 if (me->mnt_opts != NULL)
238 printf (" (%s)", me->mnt_opts);
239 if (list_with_volumelabel) {
240 const char *label;
241 label = get_volume_label_by_spec(me->mnt_fsname);
242 if (label)
243 printf (" [%s]", label);
244 }
245 printf ("\n");
246 }
247
248 /* Report on everything in mtab (of the specified types if any). */
249 static int
250 print_all (string_list types) {
251 struct mntentchn *mc, *mc0;
252
253 mc0 = mtab_head();
254 for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt) {
255 if (matching_type (mc->m.mnt_type, types))
256 print_one (&(mc->m));
257 }
258 exit (0);
259 }
260
261
262 /*
263 * Look for OPT in opt_map table and return mask value.
264 * If OPT isn't found, tack it onto extra_opts (which is non-NULL).
265 * For the options uid= and gid= replace user or group name by its value.
266 */
267 static inline void
268 parse_opt (const char *opt, int *mask, char *extra_opts) {
269 const struct opt_map *om;
270
271 for (om = opt_map; om->opt != NULL; om++)
272 if (streq (opt, om->opt)) {
273 if (om->inv)
274 *mask &= ~om->mask;
275 else
276 *mask |= om->mask;
277 if ((om->mask == MS_USER || om->mask == MS_USERS)
278 && !om->inv)
279 *mask |= MS_SECURE;
280 if ((om->mask == MS_OWNER) && !om->inv)
281 *mask |= MS_OWNERSECURE;
282 #ifdef MS_SILENT
283 if (om->mask == MS_SILENT && om->inv) {
284 mount_quiet = 1;
285 verbose = 0;
286 }
287 #endif
288 return;
289 }
290
291 if (*extra_opts)
292 strcat(extra_opts, ",");
293
294 /* convert nonnumeric ids to numeric */
295 if (!strncmp(opt, "uid=", 4) && !isdigit(opt[4])) {
296 struct passwd *pw = getpwnam(opt+4);
297 char uidbuf[20];
298
299 if (pw) {
300 sprintf(uidbuf, "uid=%d", pw->pw_uid);
301 strcat(extra_opts, uidbuf);
302 return;
303 }
304 }
305 if (!strncmp(opt, "gid=", 4) && !isdigit(opt[4])) {
306 struct group *gr = getgrnam(opt+4);
307 char gidbuf[20];
308
309 if (gr) {
310 sprintf(gidbuf, "gid=%d", gr->gr_gid);
311 strcat(extra_opts, gidbuf);
312 return;
313 }
314 }
315
316 strcat(extra_opts, opt);
317 }
318
319 /* Take -o options list and compute 4th and 5th args to mount(2). flags
320 gets the standard options (indicated by bits) and extra_opts all the rest */
321 static void
322 parse_opts (char *opts, int *flags, char **extra_opts) {
323 char *opt;
324
325 *flags = 0;
326 *extra_opts = NULL;
327
328 clear_string_opts();
329
330 if (opts != NULL) {
331 *extra_opts = xmalloc (strlen (opts) + 1);
332 **extra_opts = '\0';
333
334 for (opt = strtok (opts, ","); opt; opt = strtok (NULL, ","))
335 if (!parse_string_opt (opt))
336 parse_opt (opt, flags, *extra_opts);
337 }
338
339 if (readonly)
340 *flags |= MS_RDONLY;
341 if (readwrite)
342 *flags &= ~MS_RDONLY;
343 *flags |= mounttype;
344 if (bind)
345 *flags |= MS_BIND;
346 }
347
348 /* Try to build a canonical options string. */
349 static char *
350 fix_opts_string (int flags, const char *extra_opts, const char *user) {
351 const struct opt_map *om;
352 const struct string_opt_map *m;
353 char *new_opts;
354
355 new_opts = (flags & MS_RDONLY) ? "ro" : "rw";
356 for (om = opt_map; om->opt != NULL; om++) {
357 if (om->skip)
358 continue;
359 if (om->inv || !om->mask || (flags & om->mask) != om->mask)
360 continue;
361 new_opts = xstrconcat3(new_opts, ",", om->opt);
362 flags &= ~om->mask;
363 }
364 for (m = &string_opt_map[0]; m->tag; m++) {
365 if (!m->skip && *(m->valptr))
366 new_opts = xstrconcat4(new_opts, ",", m->tag, *(m->valptr));
367 }
368 if (extra_opts && *extra_opts) {
369 new_opts = xstrconcat3(new_opts, ",", extra_opts);
370 }
371 if (user) {
372 new_opts = xstrconcat3(new_opts, ",user=", user);
373 }
374 return new_opts;
375 }
376
377 static int
378 already (const char *spec, const char *node) {
379 struct mntentchn *mc;
380 int ret = 1;
381
382 if ((mc = getmntfile(node)) != NULL)
383 error (_("mount: according to mtab, %s is already mounted on %s"),
384 mc->m.mnt_fsname, node);
385 else if (spec && strcmp (spec, "none") &&
386 (mc = getmntfile(spec)) != NULL)
387 error (_("mount: according to mtab, %s is mounted on %s"),
388 spec, mc->m.mnt_dir);
389 else
390 ret = 0;
391 return ret;
392 }
393
394 /* Create mtab with a root entry. */
395 static void
396 create_mtab (void) {
397 struct mntentchn *fstab;
398 struct mntent mnt;
399 int flags;
400 char *extra_opts;
401 mntFILE *mfp;
402
403 lock_mtab();
404
405 mfp = my_setmntent (MOUNTED, "a+");
406 if (mfp == NULL || mfp->mntent_fp == NULL) {
407 int errsv = errno;
408 die (EX_FILEIO, _("mount: can't open %s for writing: %s"),
409 MOUNTED, strerror (errsv));
410 }
411
412 /* Find the root entry by looking it up in fstab */
413 if ((fstab = getfsfile ("/")) || (fstab = getfsfile ("root"))) {
414 parse_opts (xstrdup (fstab->m.mnt_opts), &flags, &extra_opts);
415 mnt.mnt_dir = "/";
416 mnt.mnt_fsname = canonicalize (fstab->m.mnt_fsname);
417 mnt.mnt_type = fstab->m.mnt_type;
418 mnt.mnt_opts = fix_opts_string (flags, extra_opts, NULL);
419 mnt.mnt_freq = mnt.mnt_passno = 0;
420
421 if (my_addmntent (mfp, &mnt) == 1) {
422 int errsv = errno;
423 die (EX_FILEIO, _("mount: error writing %s: %s"),
424 MOUNTED, strerror (errsv));
425 }
426 }
427 if (fchmod (fileno (mfp->mntent_fp), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0)
428 if (errno != EROFS) {
429 int errsv = errno;
430 die (EX_FILEIO, _("mount: error changing mode of %s: %s"),
431 MOUNTED, strerror (errsv));
432 }
433 my_endmntent (mfp);
434
435 unlock_mtab();
436 }
437
438 /* count successful mount system calls */
439 static int mountcount = 0;
440
441 /*
442 * do_mount_syscall()
443 * Mount a single file system. Keep track of successes.
444 * returns: 0: OK, -1: error in errno
445 */
446 static int
447 do_mount_syscall (struct mountargs *args) {
448 int ret = mount (args->spec, args->node, args->type,
449 MS_MGC_VAL | (args->flags), args->data);
450 if (ret == 0)
451 mountcount++;
452 return ret;
453 }
454
455 /*
456 * guess_fstype_and_mount()
457 * Mount a single file system. Guess the type when unknown.
458 * returns: 0: OK, -1: error in errno, 1: other error
459 * don't exit on non-fatal errors.
460 */
461 static int
462 guess_fstype_and_mount (char *spec, char *node, char **type,
463 int flags, char *mount_opts) {
464 struct mountargs args = { spec, node, NULL, flags & ~MS_NOSYS, mount_opts };
465
466 if (*type && strcasecmp (*type, "auto") == 0)
467 *type = NULL;
468
469 if (!*type && (flags & MS_BIND))
470 *type = "none"; /* random, but not "bind" */
471
472 if (!*type && !(flags & MS_REMOUNT)) {
473 *type = guess_fstype_from_superblock(spec);
474 if (*type && !strcmp(*type, "swap")) {
475 error(_("%s looks like swapspace - not mounted"), spec);
476 *type = NULL;
477 return 1;
478 }
479 }
480
481 if (*type || (flags & MS_REMOUNT)) {
482 args.type = *type;
483 return do_mount_syscall (&args);
484 }
485
486 return procfsloop(do_mount_syscall, &args, type);
487 }
488
489 /*
490 * suid_check()
491 * Die if the user is not allowed to do this.
492 */
493 static void
494 suid_check(char *spec, char *node, int *flags, char **user) {
495 if (suid) {
496 /* RedHat patch: allow owners to mount when fstab contains
497 the owner option. Note that this should never be used
498 in a high security environment, but may be useful to give
499 people at the console the possibility of mounting a floppy. */
500 if (*flags & MS_OWNER) {
501 if (!strncmp(spec, "/dev/", 5)) {
502 struct stat sb;
503
504 if (!stat(spec, &sb)) {
505 if (getuid() == sb.st_uid)
506 *flags |= MS_USER;
507 }
508 }
509 }
510 /* James Kehl <mkehl@gil.com.au> came with a similar patch:
511 allow an arbitrary user to mount when he is the owner of
512 the mount-point and has write-access to the device.
513 This is even less secure. Let me skip it for the time being;
514 there should be an explicit fstab line allowing such things. */
515
516 if (!(*flags & (MS_USER | MS_USERS))) {
517 if (already (spec, node))
518 die (EX_USAGE, _("mount failed"));
519 else
520 die (EX_USAGE, _("mount: only root can mount %s on %s"), spec, node);
521 }
522 if (*flags & MS_USER)
523 *user = getusername();
524 }
525
526 if (*flags & MS_OWNER)
527 *flags &= ~MS_OWNER;
528 }
529
530 static int
531 loop_check(char **spec, char **type, int *flags,
532 int *loop, char **loopdev, char **loopfile) {
533 int looptype, offset;
534
535 /*
536 * In the case of a loop mount, either type is of the form lo@/dev/loop5
537 * or the option "-o loop=/dev/loop5" or just "-o loop" is given, or
538 * mount just has to figure things out for itself from the fact that
539 * spec is not a block device. We do not test for a block device
540 * immediately: maybe later other types of mountable objects will occur.
541 */
542
543 *loopdev = opt_loopdev;
544
545 looptype = (*type && strncmp("lo@", *type, 3) == 0);
546 if (looptype) {
547 if (*loopdev)
548 error(_("mount: loop device specified twice"));
549 *loopdev = *type + 3;
550 *type = opt_vfstype;
551 } else if (opt_vfstype) {
552 if (*type)
553 error(_("mount: type specified twice"));
554 else
555 *type = opt_vfstype;
556 }
557
558 *loop = ((*flags & MS_LOOP) || *loopdev || opt_offset || opt_encryption);
559 *loopfile = *spec;
560
561 if (*loop) {
562 *flags |= MS_LOOP;
563 if (fake) {
564 if (verbose)
565 printf(_("mount: skipping the setup of a loop device\n"));
566 } else {
567 int loopro = (*flags & MS_RDONLY);
568
569 if (!*loopdev || !**loopdev)
570 *loopdev = find_unused_loop_device();
571 if (!*loopdev)
572 return EX_SYSERR; /* no more loop devices */
573 if (verbose)
574 printf(_("mount: going to use the loop device %s\n"), *loopdev);
575 offset = opt_offset ? strtoul(opt_offset, NULL, 0) : 0;
576 if (set_loop (*loopdev, *loopfile, offset, opt_encryption, &loopro)) {
577 if (verbose)
578 printf(_("mount: failed setting up loop device\n"));
579 return EX_FAIL;
580 }
581 if (verbose > 1)
582 printf(_("mount: setup loop device successfully\n"));
583 *spec = *loopdev;
584 if (loopro)
585 *flags |= MS_RDONLY;
586 }
587 }
588
589 return 0;
590 }
591
592 static void
593 update_mtab_entry(char *spec, char *node, char *type, char *opts,
594 int flags, int freq, int pass) {
595 struct mntent mnt;
596
597 mnt.mnt_fsname = canonicalize (spec);
598 mnt.mnt_dir = canonicalize (node);
599 mnt.mnt_type = type;
600 mnt.mnt_opts = opts;
601 mnt.mnt_freq = freq;
602 mnt.mnt_passno = pass;
603
604 /* We get chatty now rather than after the update to mtab since the
605 mount succeeded, even if the write to /etc/mtab should fail. */
606 if (verbose)
607 print_one (&mnt);
608
609 if (!nomtab && mtab_is_writable()) {
610 if (flags & MS_REMOUNT)
611 update_mtab (mnt.mnt_dir, &mnt);
612 else {
613 mntFILE *mfp;
614
615 lock_mtab();
616 mfp = my_setmntent(MOUNTED, "a+");
617 if (mfp == NULL || mfp->mntent_fp == NULL) {
618 int errsv = errno;
619 error(_("mount: can't open %s: %s"), MOUNTED,
620 strerror (errsv));
621 } else {
622 if ((my_addmntent (mfp, &mnt)) == 1) {
623 int errsv = errno;
624 error(_("mount: error writing %s: %s"), MOUNTED,
625 strerror (errsv));
626 }
627 my_endmntent(mfp);
628 }
629 unlock_mtab();
630 }
631 }
632 }
633
634 static void
635 cdrom_setspeed(char *spec) {
636 #define CDROM_SELECT_SPEED 0x5322 /* Set the CD-ROM speed */
637 if (opt_speed) {
638 int cdrom;
639 int speed = atoi(opt_speed);
640
641 if ((cdrom = open(spec, O_RDONLY | O_NONBLOCK)) < 0)
642 die(EX_FAIL, _("mount: cannot not open %s for setting speed"),
643 spec);
644 if (ioctl(cdrom, CDROM_SELECT_SPEED, speed) < 0)
645 die(EX_FAIL, _("mount: cannot set speed: %s"),
646 strerror(errno));
647 close(cdrom);
648 }
649 }
650
651 /*
652 * check_special_mountprog()
653 * If there is a special mount program for this type, exec it.
654 * returns: 0: no exec was done, 1: exec was done, status has result
655 */
656 #define ALWAYS_STAT
657
658 static int
659 check_special_mountprog(char *spec, char *node, char *type, int flags,
660 char *extra_opts, int *status) {
661 char mountprog[120];
662 struct stat statbuf;
663 int res;
664
665 if (type &&
666 #ifndef ALWAYS_STAT
667 (streq (type, "smb") || streq (type, "ncp")
668 /* these are incorrect but perhaps used by smbmount or so */
669 || streq (type, "smbfs") || streq (type, "ncpfs")
670 )
671 #else
672 (strlen (type) < 100)
673 #endif
674 ) {
675 sprintf(mountprog, "/sbin/mount.%s", type);
676 if (stat(mountprog, &statbuf) == 0) {
677 res = fork();
678 if (res == 0) {
679 char *oo, *mountargs[10];
680 int i = 0;
681
682 setuid(getuid());
683 setgid(getgid());
684 oo = fix_opts_string (flags, extra_opts, NULL);
685 mountargs[i++] = mountprog;
686 mountargs[i++] = spec;
687 mountargs[i++] = node;
688 if (nomtab)
689 mountargs[i++] = "-n";
690 if (verbose)
691 mountargs[i++] = "-v";
692 if (oo && *oo) {
693 mountargs[i++] = "-o";
694 mountargs[i++] = oo;
695 }
696 mountargs[i] = NULL;
697 execv(mountprog, mountargs);
698 exit(1); /* exec failed */
699 } else if (res != -1) {
700 int st;
701 wait(&st);
702 *status = (WIFEXITED(st) ? WEXITSTATUS(st) : EX_SYSERR);
703 return 1;
704 } else {
705 int errsv = errno;
706 error(_("mount: cannot fork: %s"), strerror(errsv));
707 }
708 }
709 }
710 return 0;
711 }
712
713 /*
714 * try_mount_one()
715 * Try to mount one file system. When "bg" is 1, this is a retry
716 * in the background. One additional exit code EX_BG is used here.
717 * It is used to instruct the caller to retry the mount in the
718 * background.
719 * returns: 0: OK, EX_SYSERR, EX_FAIL, return code from nfsmount,
720 * return status from wait
721 */
722 static int
723 try_mount_one (const char *spec0, const char *node0, char *type0,
724 const char *opts0, int freq, int pass, int bg, int ro) {
725 int res, status;
726 int mnt5_res = 0; /* only for gcc */
727 int mnt_err;
728 int flags;
729 char *extra_opts; /* written in mtab */
730 char *mount_opts; /* actually used on system call */
731 const char *opts;
732 char *spec, *node, *type;
733 char *user = 0;
734 int loop = 0;
735 char *loopdev = 0, *loopfile = 0;
736 struct stat statbuf;
737
738 spec = xstrdup(spec0);
739 node = xstrdup(node0);
740 type = xstrdup(type0);
741 opts = xstrdup(opts0);
742
743 parse_opts (xstrdup (opts), &flags, &extra_opts);
744
745 suid_check (spec, node, &flags, &user);
746
747 /* quietly succeed for fstab entries that don't get mounted automatically */
748 if (all && (flags & MS_NOAUTO))
749 return 0;
750
751 mount_opts = extra_opts;
752
753 if (opt_speed)
754 cdrom_setspeed(spec);
755
756 if (!(flags & MS_REMOUNT)) {
757 /* don't set up a (new) loop device if we only remount - this left
758 * stale assignments of files to loop devices. Nasty when used for
759 * encryption.
760 */
761 res = loop_check (&spec, &type, &flags, &loop, &loopdev, &loopfile);
762 if (res)
763 return res;
764 }
765
766 /*
767 * Call mount.TYPE for types that require a separate mount program.
768 * For the moment these types are ncp and smb.
769 */
770 if (check_special_mountprog (spec, node, type, flags, extra_opts, &status))
771 return status;
772
773 if (!fake && type && streq (type, "nfs")) {
774 #ifdef HAVE_NFS
775 retry_nfs:
776 mnt_err = nfsmount (spec, node, &flags, &extra_opts, &mount_opts, bg);
777 if (mnt_err)
778 return mnt_err;
779 #else
780 die (EX_SOFTWARE, _("mount: this version was compiled "
781 "without support for the type `nfs'"));
782 #endif
783 }
784
785 block_signals (SIG_BLOCK);
786
787 if (!fake)
788 mnt5_res = guess_fstype_and_mount (spec, node, &type, flags & ~MS_NOSYS,
789 mount_opts);
790
791 if (fake || mnt5_res == 0) {
792 /* Mount succeeded, report this (if verbose) and write mtab entry. */
793 if (loop)
794 opt_loopdev = loopdev;
795
796 update_mtab_entry(loop ? loopfile : spec,
797 node,
798 type ? type : "unknown",
799 fix_opts_string (flags & ~MS_NOMTAB, extra_opts, user),
800 flags,
801 freq,
802 pass);
803
804 block_signals (SIG_UNBLOCK);
805 return 0;
806 }
807
808 mnt_err = errno;
809
810 if (loop)
811 del_loop(spec);
812
813 block_signals (SIG_UNBLOCK);
814
815 #ifdef HAVE_NFS
816 if (mnt_err && type && streq (type, "nfs")) {
817 extern int nfs_mount_version;
818 if (nfs_mount_version == 4) {
819 if (verbose)
820 printf(_("mount: failed with nfs mount version 4, trying 3..\n"));
821 nfs_mount_version = 3;
822 goto retry_nfs;
823 }
824 }
825 #endif
826
827 /* Mount failed, complain, but don't die. */
828
829 if (type == 0) {
830 if (suid)
831 error (_("mount: I could not determine the filesystem type, "
832 "and none was specified"));
833 else
834 error (_("mount: you must specify the filesystem type"));
835 } else if (mnt5_res != -1) {
836 /* should not happen */
837 error (_("mount: mount failed"));
838 } else {
839 switch (mnt_err) {
840 case EPERM:
841 if (geteuid() == 0) {
842 if (stat (node, &statbuf) || !S_ISDIR(statbuf.st_mode))
843 error (_("mount: mount point %s is not a directory"), node);
844 else
845 error (_("mount: permission denied"));
846 } else
847 error (_("mount: must be superuser to use mount"));
848 break;
849 case EBUSY:
850 if (flags & MS_REMOUNT) {
851 error (_("mount: %s is busy"), node);
852 } else if (!strcmp(type, "proc") && !strcmp(node, "/proc")) {
853 /* heuristic: if /proc/version exists, then probably proc is mounted */
854 if (stat ("/proc/version", &statbuf)) /* proc mounted? */
855 error (_("mount: %s is busy"), node); /* no */
856 else if(!all || verbose) /* yes, don't mention it */
857 error (_("mount: proc already mounted"));
858 } else {
859 error (_("mount: %s already mounted or %s busy"), spec, node);
860 already (spec, node);
861 }
862 break;
863 case ENOENT:
864 if (lstat (node, &statbuf))
865 error (_("mount: mount point %s does not exist"), node);
866 else if (stat (node, &statbuf))
867 error (_("mount: mount point %s is a symbolic link to nowhere"),
868 node);
869 else if (stat (spec, &statbuf))
870 error (_("mount: special device %s does not exist"), spec);
871 else {
872 errno = mnt_err;
873 perror("mount");
874 }
875 break;
876 case ENOTDIR:
877 if (stat (node, &statbuf) || ! S_ISDIR(statbuf.st_mode))
878 error (_("mount: mount point %s is not a directory"), node);
879 else if (stat (spec, &statbuf) && errno == ENOTDIR)
880 error (_("mount: special device %s does not exist\n"
881 " (a path prefix is not a directory)\n"), spec);
882 else {
883 errno = mnt_err;
884 perror("mount");
885 }
886 break;
887 case EINVAL:
888 { int fd;
889 long size;
890 int warned=0;
891
892 if (flags & MS_REMOUNT) {
893 error (_("mount: %s not mounted already, or bad option"), node);
894 } else {
895 error (_("mount: wrong fs type, bad option, bad superblock on %s,\n"
896 " or too many mounted file systems"),
897 spec);
898
899 if (stat (spec, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)
900 && (fd = open(spec, O_RDONLY | O_NONBLOCK)) >= 0) {
901 if(ioctl(fd, BLKGETSIZE, &size) == 0) {
902 if (size == 0) {
903 warned++;
904 error (" (could this be the IDE device where you in fact use\n"
905 " ide-scsi so that sr0 or sda or so is needed?)");
906 }
907 if (size && size <= 2) {
908 warned++;
909 error (" (aren't you trying to mount an extended partition,\n"
910 " instead of some logical partition inside?)");
911 }
912 close(fd);
913 }
914 #if 0
915 /* 0xf for SCSI, 0x3f for IDE. One might check /proc/partitions
916 to see whether this thing really is partitioned.
917 Do not suggest partitions for /dev/fd0. */
918 if (!warned && (statbuf.st_rdev & 0xf) == 0) {
919 warned++;
920 error (" (could this be the whole disk device\n"
921 " where you need a partition?)");
922 }
923 #endif
924 }
925 }
926 break;
927 }
928 case EMFILE:
929 error (_("mount table full")); break;
930 case EIO:
931 error (_("mount: %s: can't read superblock"), spec); break;
932 case ENODEV:
933 { int pfs;
934 if ((pfs = is_in_procfs(type)) == 1 || !strcmp(type, "guess"))
935 error(_("mount: %s: unknown device"), spec);
936 else if (pfs == 0) {
937 char *lowtype, *p;
938 int u;
939
940 error (_("mount: fs type %s not supported by kernel"), type);
941
942 /* maybe this loser asked for FAT or ISO9660 or isofs */
943 lowtype = xstrdup(type);
944 u = 0;
945 for(p=lowtype; *p; p++) {
946 if(tolower(*p) != *p) {
947 *p = tolower(*p);
948 u++;
949 }
950 }
951 if (u && is_in_procfs(lowtype) == 1)
952 error (_("mount: probably you meant %s"), lowtype);
953 else if (!strncmp(lowtype, "iso", 3) && is_in_procfs("iso9660") == 1)
954 error (_("mount: maybe you meant iso9660 ?"));
955 free(lowtype);
956 } else
957 error (_("mount: %s has wrong device number or fs type %s not supported"),
958 spec, type);
959 break;
960 }
961 case ENOTBLK:
962 if (stat (spec, &statbuf)) /* strange ... */
963 error (_("mount: %s is not a block device, and stat fails?"), spec);
964 else if (S_ISBLK(statbuf.st_mode))
965 error (_("mount: the kernel does not recognize %s as a block device\n"
966 " (maybe `insmod driver'?)"), spec);
967 else if (S_ISREG(statbuf.st_mode))
968 error (_("mount: %s is not a block device (maybe try `-o loop'?)"),
969 spec);
970 else
971 error (_("mount: %s is not a block device"), spec);
972 break;
973 case ENXIO:
974 error (_("mount: %s is not a valid block device"), spec); break;
975 case EACCES: /* pre-linux 1.1.38, 1.1.41 and later */
976 case EROFS: /* linux 1.1.38 and later */
977 { char *bd = (loop ? "" : _("block device "));
978 if (ro || (flags & MS_RDONLY)) {
979 error (_("mount: cannot mount %s%s read-only"),
980 bd, spec);
981 break;
982 } else if (readwrite) {
983 error (_("mount: %s%s is write-protected but explicit `-w' flag given"),
984 bd, spec);
985 break;
986 } else {
987 if (loop) {
988 opts = opts0;
989 type = type0;
990 }
991 if (opts) {
992 char *opts1 = realloc(xstrdup(opts), strlen(opts)+4);
993 strcat(opts1, ",ro");
994 opts = opts1;
995 } else
996 opts = "ro";
997 if (type && !strcmp(type, "guess"))
998 type = 0;
999 error (_("mount: %s%s is write-protected, mounting read-only"),
1000 bd, spec0);
1001 return try_mount_one (spec0, node0, type, opts, freq, pass, bg, 1);
1002 }
1003 break;
1004 }
1005 default:
1006 error ("mount: %s", strerror (mnt_err)); break;
1007 }
1008 }
1009 return EX_FAIL;
1010 }
1011
1012 /*
1013 * set_proc_name()
1014 * Update the argument vector, so that this process may be easily
1015 * identified in a "ps" listing.
1016 */
1017 static void
1018 set_proc_name (const char *spec)
1019 {
1020 #ifdef DO_PS_FIDDLING
1021 setproctitle ("mount", spec);
1022 #endif
1023 }
1024
1025 static char *
1026 subst_string(const char *s, const char *sub, int sublen, const char *repl) {
1027 char *n;
1028
1029 n = (char *) xmalloc(strlen(s)-sublen+strlen(repl)+1);
1030 strncpy (n, s, sub-s);
1031 strcpy (n + (sub-s), repl);
1032 strcat (n, sub+sublen);
1033 return n;
1034 }
1035
1036 static const char *
1037 usersubst(const char *opts) {
1038 char *s, *w;
1039 char id[40];
1040
1041 s = "uid=useruid";
1042 if (opts && (w = strstr(opts, s)) != NULL) {
1043 sprintf(id, "uid=%d", getuid());
1044 opts = subst_string(opts, w, strlen(s), id);
1045 }
1046 s = "gid=usergid";
1047 if (opts && (w = strstr(opts, s)) != NULL) {
1048 sprintf(id, "gid=%d", getgid());
1049 opts = subst_string(opts, w, strlen(s), id);
1050 }
1051 return opts;
1052 }
1053
1054
1055 /*
1056 * Return 0 for success (either mounted sth or -a and NOAUTO was given)
1057 */
1058 static int
1059 mount_one (const char *spec, const char *node, char *type, const char *opts,
1060 char *cmdlineopts, int freq, int pass) {
1061 int status;
1062 int status2;
1063 int specset = 0;
1064 char *nspec;
1065
1066 /* Substitute values in opts, if required */
1067 opts = usersubst(opts);
1068
1069 /* Merge the fstab and command line options. */
1070 if (opts == NULL)
1071 opts = cmdlineopts;
1072 else if (cmdlineopts != NULL)
1073 opts = xstrconcat3(opts, ",", cmdlineopts);
1074
1075 if (!strncmp(spec, "UUID=", 5)) {
1076 nspec = get_spec_by_uuid(spec+5);
1077 specset = 1;
1078 } else if (!strncmp(spec, "LABEL=", 6)) {
1079 nspec = get_spec_by_volume_label(spec+6);
1080 specset = 2;
1081 } else
1082 nspec = 0; /* just for gcc */
1083
1084 if (specset) {
1085 if (nspec) {
1086 spec = nspec;
1087 if (verbose > 1)
1088 printf(_("mount: going to mount %s by %s\n"), spec,
1089 (specset==1) ? _("UUID") : _("label"));
1090 } else if(!all)
1091 die (EX_USAGE, _("mount: no such partition found"));
1092 /* if -a then we may be rescued by a noauto option */
1093 }
1094
1095 if (type == NULL && !bind) {
1096 if (strchr (spec, ':') != NULL) {
1097 type = "nfs";
1098 if (verbose)
1099 printf(_("mount: no type was given - "
1100 "I'll assume nfs because of the colon\n"));
1101 }
1102 }
1103
1104 /*
1105 * Try to mount the file system. When the exit status is EX_BG,
1106 * we will retry in the background. Otherwise, we're done.
1107 */
1108 status = try_mount_one (spec, node, type, opts, freq, pass, 0, 0);
1109 if (status != EX_BG)
1110 return status;
1111
1112 /*
1113 * Retry in the background.
1114 */
1115 printf (_("mount: backgrounding \"%s\"\n"), spec);
1116 fflush( stdout ); /* prevent duplicate output */
1117 if (fork() > 0)
1118 return 0; /* parent returns "success" */
1119 spec = xstrdup(spec); /* arguments will be destroyed */
1120 node = xstrdup(node); /* by set_proc_name() */
1121 type = xstrdup(type);
1122 opts = xstrdup(opts);
1123 set_proc_name (spec); /* make a nice "ps" listing */
1124 status2 = try_mount_one (spec, node, type, opts, freq, pass, 1, 0);
1125 if (verbose && status2)
1126 printf (_("mount: giving up \"%s\"\n"), spec);
1127 exit (0); /* child stops here */
1128 }
1129
1130 /* Check if an fsname/dir pair was already in the old mtab. */
1131 static int
1132 mounted (char *spec, char *node) {
1133 struct mntentchn *mc, *mc0;
1134 char *nspec = NULL;
1135
1136 if (!strncmp(spec, "UUID=", 5))
1137 nspec = get_spec_by_uuid(spec+5);
1138 else if (!strncmp(spec, "LABEL=", 6))
1139 nspec = get_spec_by_volume_label(spec+6);
1140
1141 if (nspec)
1142 spec = nspec;
1143
1144 spec = canonicalize (spec);
1145 node = canonicalize (node);
1146
1147 mc0 = mtab_head();
1148 for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt)
1149 if (streq (spec, mc->m.mnt_fsname) && streq (node, mc->m.mnt_dir))
1150 return 1;
1151 return 0;
1152 }
1153
1154 /* Mount all filesystems of the specified types except swap and root. */
1155 /* With the --fork option: fork and let different incarnations of
1156 mount handle different filesystems. However, try to avoid several
1157 simultaneous mounts on the same physical disk, since that is very slow. */
1158 #define DISKMAJOR(m) (((int) m) & ~0xf)
1159
1160 static int
1161 mount_all (string_list types, char *options) {
1162 struct mntentchn *mc, *mc0, *mtmp;
1163 int status = 0;
1164 struct stat statbuf;
1165 struct child {
1166 pid_t pid;
1167 char *group;
1168 struct mntentchn *mec;
1169 struct mntentchn *meclast;
1170 struct child *nxt;
1171 } childhead, *childtail, *cp;
1172 char major[22];
1173 char *g, *colon;
1174
1175 /* build a chain of what we have to do, or maybe
1176 several chains, one for each major or NFS host */
1177 childhead.nxt = 0;
1178 childtail = &childhead;
1179 mc0 = fstab_head();
1180 for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt) {
1181 if (matching_type (mc->m.mnt_type, types)
1182 && !streq (mc->m.mnt_dir, "/")
1183 && !streq (mc->m.mnt_dir, "root")) {
1184 if (mounted (mc->m.mnt_fsname, mc->m.mnt_dir)) {
1185 if (verbose)
1186 printf(_("mount: %s already mounted on %s\n"),
1187 mc->m.mnt_fsname, mc->m.mnt_dir);
1188 } else {
1189 mtmp = (struct mntentchn *) xmalloc(sizeof(*mtmp));
1190 *mtmp = *mc;
1191 mtmp->nxt = 0;
1192 g = NULL;
1193 if (optfork) {
1194 if (stat(mc->m.mnt_fsname, &statbuf) == 0 &&
1195 S_ISBLK(statbuf.st_mode)) {
1196 sprintf(major, "#%x", DISKMAJOR(statbuf.st_rdev));
1197 g = major;
1198 }
1199 #ifdef HAVE_NFS
1200 if (strcmp(mc->m.mnt_type, "nfs") == 0) {
1201 g = xstrdup(mc->m.mnt_fsname);
1202 colon = strchr(g, ':');
1203 if (colon)
1204 *colon = '\0';
1205 }
1206 #endif
1207 }
1208 if (g) {
1209 for (cp = childhead.nxt; cp; cp = cp->nxt)
1210 if (cp->group && strcmp(cp->group, g) == 0) {
1211 cp->meclast->nxt = mtmp;
1212 cp->meclast = mtmp;
1213 goto fnd;
1214 }
1215 }
1216 cp = (struct child *) xmalloc(sizeof *cp);
1217 cp->nxt = 0;
1218 cp->mec = cp->meclast = mtmp;
1219 cp->group = xstrdup(g);
1220 cp->pid = 0;
1221 childtail->nxt = cp;
1222 childtail = cp;
1223 fnd:;
1224 }
1225 }
1226 }
1227
1228 /* now do everything */
1229 for (cp = childhead.nxt; cp; cp = cp->nxt) {
1230 pid_t p = -1;
1231 if (optfork) {
1232 p = fork();
1233 if (p == -1) {
1234 int errsv = errno;
1235 error(_("mount: cannot fork: %s"), strerror (errsv));
1236 }
1237 else if (p != 0)
1238 cp->pid = p;
1239 }
1240
1241 /* if child, or not forked, do the mounting */
1242 if (p == 0 || p == -1) {
1243 for (mc = cp->mec; mc; mc = mc->nxt)
1244 status |= mount_one (mc->m.mnt_fsname, mc->m.mnt_dir,
1245 mc->m.mnt_type, mc->m.mnt_opts,
1246 options, 0, 0);
1247 if (mountcount)
1248 status |= EX_SOMEOK;
1249 if (p == 0)
1250 exit(status);
1251 }
1252 }
1253
1254 /* wait for children, if any */
1255 while ((cp = childhead.nxt) != NULL) {
1256 childhead.nxt = cp->nxt;
1257 if (cp->pid) {
1258 int ret;
1259 keep_waiting:
1260 if(waitpid(cp->pid, &ret, 0) == -1) {
1261 if (errno == EINTR)
1262 goto keep_waiting;
1263 perror("waitpid");
1264 } else if (WIFEXITED(ret))
1265 status |= WEXITSTATUS(ret);
1266 else
1267 status |= EX_SYSERR;
1268 }
1269 }
1270 if (mountcount)
1271 status |= EX_SOMEOK;
1272 return status;
1273 }
1274
1275 extern char version[];
1276 static struct option longopts[] = {
1277 { "all", 0, 0, 'a' },
1278 { "fake", 0, 0, 'f' },
1279 { "fork", 0, 0, 'F' },
1280 { "help", 0, 0, 'h' },
1281 { "no-mtab", 0, 0, 'n' },
1282 { "read-only", 0, 0, 'r' },
1283 { "ro", 0, 0, 'r' },
1284 { "verbose", 0, 0, 'v' },
1285 { "version", 0, 0, 'V' },
1286 { "read-write", 0, 0, 'w' },
1287 { "rw", 0, 0, 'w' },
1288 { "options", 1, 0, 'o' },
1289 { "types", 1, 0, 't' },
1290 { "bind", 0, 0, 128 },
1291 { "replace", 0, 0, 129 },
1292 { "after", 0, 0, 130 },
1293 { "before", 0, 0, 131 },
1294 { "over", 0, 0, 132 },
1295 { NULL, 0, 0, 0 }
1296 };
1297
1298 /* Keep the usage message at max 22 lines, each at most 70 chars long.
1299 The user should not need a pager to read it. */
1300 static void
1301 usage (FILE *fp, int n) {
1302 fprintf(fp, _(
1303 "Usage: mount -V : print version\n"
1304 " mount -h : print this help\n"
1305 " mount : list mounted filesystems\n"
1306 " mount -l : idem, including volume labels\n"
1307 "So far the informational part. Next the mounting.\n"
1308 "The command is `mount [-t fstype] something somewhere'.\n"
1309 "Details found in /etc/fstab may be omitted.\n"
1310 " mount -a : mount all stuff from /etc/fstab\n"
1311 " mount device : mount device at the known place\n"
1312 " mount directory : mount known device here\n"
1313 " mount -t type dev dir : ordinary mount command\n"
1314 "Note that one does not really mount a device, one mounts\n"
1315 "a filesystem (of the given type) found on the device.\n"
1316 "One can also mount an already visible directory tree elsewhere:\n"
1317 " mount --bind olddir newdir\n"
1318 "A device can be given by name, say /dev/hda1 or /dev/cdrom,\n"
1319 "or by label, using -L label or by uuid, using -U uuid .\n"
1320 "Union or stack mounts are specified using one of\n"
1321 " --replace, --after, --before, --over\n"
1322 "Other options: [-nfFrsvw] [-o options].\n"
1323 "For many more details, say man 8 mount .\n"
1324 ));
1325 unlock_mtab();
1326 exit (n);
1327 }
1328
1329 int
1330 main (int argc, char *argv[]) {
1331 int c, result = 0, specseen;
1332 char *options = NULL, *spec, *node;
1333 char *volumelabel = NULL;
1334 char *uuid = NULL;
1335 string_list types = NULL;
1336 struct mntentchn *mc;
1337 int fd;
1338
1339 setlocale(LC_ALL, "");
1340 bindtextdomain(PACKAGE, LOCALEDIR);
1341 textdomain(PACKAGE);
1342
1343 /* People report that a mount called from init without console
1344 writes error messages to /etc/mtab
1345 Let us try to avoid getting fd's 0,1,2 */
1346 while((fd = open("/dev/null", O_RDWR)) == 0 || fd == 1 || fd == 2) ;
1347 if (fd > 2)
1348 close(fd);
1349
1350 #ifdef DO_PS_FIDDLING
1351 initproctitle(argc, argv);
1352 #endif
1353
1354 while ((c = getopt_long (argc, argv, "afFhlL:no:rsU:vVwt:",
1355 longopts, NULL)) != EOF) {
1356 switch (c) {
1357 case 'a': /* mount everything in fstab */
1358 ++all;
1359 break;
1360 case 'f': /* fake: don't actually call mount(2) */
1361 ++fake;
1362 break;
1363 case 'F':
1364 ++optfork;
1365 break;
1366 case 'h': /* help */
1367 usage (stdout, 0);
1368 break;
1369 case 'l':
1370 list_with_volumelabel = 1;
1371 break;
1372 case 'L':
1373 volumelabel = optarg;
1374 break;
1375 case 'n': /* do not write /etc/mtab */
1376 ++nomtab;
1377 break;
1378 case 'o': /* specify mount options */
1379 if (options)
1380 options = xstrconcat3(options, ",", optarg);
1381 else
1382 options = xstrdup(optarg);
1383 break;
1384 case 'r': /* mount readonly */
1385 readonly = 1;
1386 readwrite = 0;
1387 break;
1388 case 's': /* allow sloppy mount options */
1389 sloppy = 1;
1390 break;
1391 case 't': /* specify file system types */
1392 types = parse_list (optarg);
1393 break;
1394 case 'U':
1395 uuid = optarg;
1396 break;
1397 case 'v': /* be chatty - more so if repeated */
1398 ++verbose;
1399 break;
1400 case 'V': /* version */
1401 printf ("mount: %s\n", version);
1402 exit (0);
1403 case 'w': /* mount read/write */
1404 readwrite = 1;
1405 readonly = 0;
1406 break;
1407 case 0:
1408 break;
1409
1410 case 128: /* bind */
1411 ++bind;
1412 break;
1413 case 129: /* replace */
1414 mounttype = MS_REPLACE;
1415 break;
1416 case 130: /* after */
1417 mounttype = MS_AFTER;
1418 break;
1419 case 131: /* before */
1420 mounttype = MS_BEFORE;
1421 break;
1422 case 132: /* over */
1423 mounttype = MS_OVER;
1424 break;
1425
1426 case '?':
1427 default:
1428 usage (stderr, EX_USAGE);
1429 }
1430 }
1431
1432 argc -= optind;
1433 argv += optind;
1434
1435 specseen = (uuid || volumelabel) ? 1 : 0; /* yes, .. i know */
1436
1437 if (argc+specseen == 0 && !all) {
1438 if (options || mounttype || bind)
1439 usage (stderr, EX_USAGE);
1440 return print_all (types);
1441 }
1442
1443 if (getuid () != geteuid ()) {
1444 suid = 1;
1445 if (types || options || readwrite || nomtab || all || fake ||
1446 bind || mounttype || (argc + specseen) != 1)
1447 die (EX_USAGE, _("mount: only root can do that"));
1448 }
1449
1450 if (!nomtab && mtab_does_not_exist()) {
1451 if (verbose > 1)
1452 printf(_("mount: no %s found - creating it..\n"),
1453 MOUNTED);
1454 create_mtab ();
1455 }
1456
1457 if (specseen) {
1458 if (uuid)
1459 spec = get_spec_by_uuid(uuid);
1460 else
1461 spec = get_spec_by_volume_label(volumelabel);
1462 if (!spec)
1463 die (EX_USAGE, _("mount: no such partition found"));
1464 if (verbose)
1465 printf(_("mount: mounting %s\n"), spec);
1466 } else
1467 spec = NULL; /* just for gcc */
1468
1469 switch (argc+specseen) {
1470 case 0:
1471 /* mount -a */
1472 result = mount_all (types, options);
1473 if (result == 0 && verbose)
1474 error(_("not mounted anything"));
1475 break;
1476
1477 case 1:
1478 /* mount [-nfrvw] [-o options] special | node */
1479 if (types != NULL)
1480 usage (stderr, EX_USAGE);
1481 if (specseen) {
1482 /* We know the device. Where shall we mount it? */
1483 mc = (uuid ? getfsuuidspec (uuid)
1484 : getfsvolspec (volumelabel));
1485 if (mc == NULL)
1486 mc = getfsspec (spec);
1487 if (mc == NULL)
1488 die (EX_USAGE,
1489 _("mount: cannot find %s in %s"),
1490 spec, _PATH_FSTAB);
1491 mc->m.mnt_fsname = spec;
1492 } else {
1493 /* Try to find the other pathname in fstab. */
1494 spec = canonicalize (*argv);
1495 if ((mc = getfsspec (spec)) == NULL &&
1496 (mc = getfsfile (spec)) == NULL &&
1497 /* Try noncanonical name in fstab
1498 perhaps /dev/cdrom or /dos is a symlink */
1499 (mc = getfsspec (*argv)) == NULL &&
1500 (mc = getfsfile (*argv)) == NULL &&
1501 /* Try mtab - maybe this was a remount */
1502 (mc = getmntfile (spec)) == NULL)
1503 die (EX_USAGE,
1504 _("mount: can't find %s in %s or %s"),
1505 spec, _PATH_FSTAB, MOUNTED);
1506 /* Earlier mtab was tried first, but this would
1507 sometimes try the wrong mount in case mtab had
1508 the root device entry wrong. */
1509 }
1510
1511 result = mount_one (xstrdup (mc->m.mnt_fsname),
1512 xstrdup (mc->m.mnt_dir),
1513 xstrdup (mc->m.mnt_type),
1514 mc->m.mnt_opts, options, 0, 0);
1515 break;
1516
1517 case 2:
1518 /* mount [-nfrvw] [-t vfstype] [-o options] special node */
1519 if (specseen) {
1520 /* we have spec already */
1521 node = argv[0];
1522 } else {
1523 spec = argv[0];
1524 node = argv[1];
1525 }
1526 if (types == NULL)
1527 result = mount_one (spec, node, NULL, NULL,
1528 options, 0, 0);
1529 else if (cdr (types) == NULL)
1530 result = mount_one (spec, node, car (types), NULL,
1531 options, 0, 0);
1532 else
1533 usage (stderr, EX_USAGE);
1534 break;
1535
1536 default:
1537 usage (stderr, EX_USAGE);
1538 }
1539
1540 if (result == EX_SOMEOK)
1541 result = 0;
1542 exit (result);
1543 }