]> git.ipfire.org Git - thirdparty/util-linux.git/blame - mount/mount.c
Imported from util-linux-2.8 tarball.
[thirdparty/util-linux.git] / mount / mount.c
CommitLineData
6dbe3af9
KZ
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 *
726f69e2 5 * Thu Jul 14 07:32:40 1994: faith@cs.unc.edu added changes from Adam
6dbe3af9
KZ
6 * J. Richter (adam@adam.yggdrasil.com) so that /proc/filesystems is used
7 * if no -t option is given. I modified his patches so that, if
8 * /proc/filesystems is not available, the behavior of mount is the same as
9 * it was previously.
10 *
11 * Wed Sep 14 22:43:00 1994: Mitchum DSouza
12 * (mitch@mrc-applied-psychology.cambridge.ac.uk) added support for mounting
13 * the "loop" device.
14 *
15 * Wed Sep 14 22:55:10 1994: Sander van Malssen (svm@kozmix.hacktic.nl)
16 * added support for remounting readonly file systems readonly.
17 *
18 * Wed Feb 8 09:23:18 1995: Mike Grupenhoff <kashmir@umiacs.UMD.EDU> added
19 * a probe of the superblock for the type before /proc/filesystems is
20 * checked.
21 *
22 * Wed Feb 8 12:27:00 1995: Andries.Brouwer@cwi.nl fixed up error messages.
726f69e2
KZ
23 * Sat Jun 3 20:44:38 1995: Patches from Andries.Brouwer@cwi.nl applied.
24 * Tue Sep 26 22:38:20 1995: aeb@cwi.nl, many changes
fd6b7a7f 25 * Fri Feb 23 13:47:00 1996: aeb@cwi.nl, loop device related changes
6dbe3af9 26 *
fd6b7a7f
KZ
27 * Fri Apr 5 01:13:33 1996: quinlan@bucknell.edu, fixed up iso9660 autodetect
28 *
29 * Since then, many changes - aeb.
2b6fc908
KZ
30 *
31 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
32 * Implemented the "bg", "fg" and "retry" mount options for NFS.
6dbe3af9
KZ
33 */
34
fd6b7a7f
KZ
35#include <unistd.h>
36#include <ctype.h>
37#include <errno.h>
38#include <string.h>
39#include <getopt.h>
2b6fc908 40#include <stdio.h>
6dbe3af9 41
fd6b7a7f
KZ
42#include <sys/types.h>
43#include <sys/ioctl.h>
44#include <sys/stat.h>
45#include <sys/wait.h>
46#include <sys/mount.h>
47
2b6fc908 48#include "mount_constants.h"
fd6b7a7f
KZ
49#include "sundries.h"
50#include "fstab.h"
51#include "lomount.h"
52#include "loop.h"
2b6fc908 53#include "linux_fs.h"
6dbe3af9 54
726f69e2
KZ
55#define PROC_FILESYSTEMS "/proc/filesystems"
56#define SIZE(a) (sizeof(a)/sizeof(a[0]))
57
2b6fc908
KZ
58#define DO_PS_FIDDLING
59
60#ifdef DO_PS_FIDDLING
61#define PROC_NAME "mount: "
62static int argc0;
63static char** argv0;
64static char** envp0;
65extern char** environ;
66#endif
67
6dbe3af9
KZ
68/* True for fake mount (-f). */
69int fake = 0;
70
71/* Don't write a entry in /etc/mtab (-n). */
72int nomtab = 0;
73
fd6b7a7f 74/* True for explicit readonly (-r). */
6dbe3af9
KZ
75int readonly = 0;
76
77/* Nonzero for chatty (-v). */
78int verbose = 0;
79
2b6fc908
KZ
80/* Nonzero for sloppy (-s). */
81int sloppy = 0;
82
fd6b7a7f 83/* True for explicit read/write (-w). */
6dbe3af9
KZ
84int readwrite = 0;
85
86/* True for all mount (-a). */
87int all = 0;
88
fd6b7a7f
KZ
89/* True for fork() during all mount (-F). */
90int optfork = 0;
91
6dbe3af9
KZ
92/* True if ruid != euid. */
93int suid = 0;
94
95/* Map from -o and fstab option strings to the flag argument to mount(2). */
96struct opt_map
97{
98 const char *opt; /* option name */
fd6b7a7f 99 int skip; /* skip in mtab option string */
6dbe3af9
KZ
100 int inv; /* true if flag value should be inverted */
101 int mask; /* flag mask value */
102};
103
104/* Custom mount options for our own purposes. */
fd6b7a7f
KZ
105/* We can use the high-order 16 bits, since the mount call
106 has MS_MGC_VAL there. */
6dbe3af9
KZ
107#define MS_NOAUTO 0x80000000
108#define MS_USER 0x40000000
fd6b7a7f 109#define MS_LOOP 0x00010000
6dbe3af9
KZ
110
111/* Options that we keep the mount system call from seeing. */
fd6b7a7f 112#define MS_NOSYS (MS_NOAUTO|MS_USER|MS_LOOP)
6dbe3af9
KZ
113
114/* Options that we keep from appearing in the options field in the mtab. */
115#define MS_NOMTAB (MS_REMOUNT|MS_NOAUTO|MS_USER)
116
117/* OPTIONS that we make ordinary users have by default. */
118#define MS_SECURE (MS_NOEXEC|MS_NOSUID|MS_NODEV)
119
fd6b7a7f
KZ
120const struct opt_map opt_map[] = {
121 { "defaults", 0, 0, 0 }, /* default options */
122 { "ro", 1, 0, MS_RDONLY }, /* read-only */
123 { "rw", 1, 1, MS_RDONLY }, /* read-write */
124 { "exec", 0, 1, MS_NOEXEC }, /* permit execution of binaries */
125 { "noexec", 0, 0, MS_NOEXEC }, /* don't execute binaries */
126 { "suid", 0, 1, MS_NOSUID }, /* honor suid executables */
127 { "nosuid", 0, 0, MS_NOSUID }, /* don't honor suid executables */
128 { "dev", 0, 1, MS_NODEV }, /* interpret device files */
129 { "nodev", 0, 0, MS_NODEV }, /* don't interpret devices */
130 { "sync", 0, 0, MS_SYNCHRONOUS}, /* synchronous I/O */
131 { "async", 0, 1, MS_SYNCHRONOUS}, /* asynchronous I/O */
132 { "remount", 0, 0, MS_REMOUNT}, /* Alter flags of mounted FS */
133 { "auto", 0, 1, MS_NOAUTO }, /* Can be mounted using -a */
134 { "noauto", 0, 0, MS_NOAUTO }, /* Can only be mounted explicitly */
135 { "user", 0, 0, MS_USER }, /* Allow ordinary user to mount */
136 { "nouser", 0, 1, MS_USER }, /* Forbid ordinary user to mount */
6dbe3af9
KZ
137 /* add new options here */
138#ifdef MS_NOSUB
fd6b7a7f
KZ
139 { "sub", 0, 1, MS_NOSUB }, /* allow submounts */
140 { "nosub", 0, 0, MS_NOSUB }, /* don't allow submounts */
141#endif
142#ifdef MS_SILENT
143 { "quiet", 0, 0, MS_SILENT }, /* be quiet */
144 { "loud", 0, 1, MS_SILENT }, /* print out messages. */
726f69e2 145#endif
fd6b7a7f
KZ
146#ifdef MS_MANDLOCK
147 { "mand", 0, 0, MS_MANDLOCK }, /* Allow mandatory locks on this FS */
148 { "nomand", 0, 1, MS_MANDLOCK }, /* Forbid mandatory locks on this FS */
6dbe3af9 149#endif
fd6b7a7f
KZ
150 { "loop", 1, 0, MS_LOOP }, /* use a loop device */
151#ifdef MS_NOATIME
152 { "atime", 0, 1, MS_NOATIME }, /* Update access time */
153 { "noatime", 0, 0, MS_NOATIME }, /* Do not update access time */
2b6fc908
KZ
154#endif
155#ifdef MS_NODIRATIME
156 { "diratime", 0, 1, MS_NODIRATIME }, /* Update dir access times */
157 { "nodiratime", 0, 0, MS_NODIRATIME },/* Do not update dir access times */
fd6b7a7f
KZ
158#endif
159 { NULL, 0, 0, 0 }
160};
161
162char *opt_loopdev, *opt_vfstype, *opt_offset, *opt_encryption;
163
164struct string_opt_map {
165 char *tag;
166 int skip;
167 char **valptr;
168} string_opt_map[] = {
169 { "loop=", 0, &opt_loopdev },
170 { "vfs=", 1, &opt_vfstype },
171 { "offset=", 0, &opt_offset },
172 { "encryption=", 0, &opt_encryption },
173 { NULL, 0, NULL }
6dbe3af9
KZ
174};
175
fd6b7a7f
KZ
176static void
177clear_string_opts(void) {
178 struct string_opt_map *m;
179
180 for (m = &string_opt_map[0]; m->tag; m++)
181 *(m->valptr) = NULL;
182}
183
184static int
185parse_string_opt(char *s) {
186 struct string_opt_map *m;
187 int lth;
188
189 for (m = &string_opt_map[0]; m->tag; m++) {
190 lth = strlen(m->tag);
191 if (!strncmp(s, m->tag, lth)) {
192 *(m->valptr) = xstrdup(s + lth);
193 return 1;
194 }
195 }
196 return 0;
197}
198
726f69e2 199int mount_quiet=0;
6dbe3af9
KZ
200
201/* Report on a single mount. */
202static void
fd6b7a7f
KZ
203print_one (const struct mntentchn *mc) {
204 if (mount_quiet)
205 return;
206 printf ("%s on %s", mc->mnt_fsname, mc->mnt_dir);
207 if (mc->mnt_type != NULL && *(mc->mnt_type) != '\0')
208 printf (" type %s", mc->mnt_type);
209 if (mc->mnt_opts != NULL)
210 printf (" (%s)", mc->mnt_opts);
211 printf ("\n");
6dbe3af9
KZ
212}
213
214/* Report on everything in mtab (of the specified types if any). */
215static int
216print_all (string_list types)
217{
fd6b7a7f 218 struct mntentchn *mc;
6dbe3af9 219
fd6b7a7f
KZ
220 for (mc = mtab_head()->nxt; mc; mc = mc->nxt) {
221 if (matching_type (mc->mnt_type, types))
222 print_one (mc);
223 }
224 exit (0);
6dbe3af9
KZ
225}
226
227
228/* Look for OPT in opt_map table and return mask value. If OPT isn't found,
fd6b7a7f 229 tack it onto extra_opts (which is non-NULL). */
6dbe3af9
KZ
230static inline void
231parse_opt (const char *opt, int *mask, char *extra_opts)
232{
233 const struct opt_map *om;
234
235 for (om = opt_map; om->opt != NULL; om++)
236 if (streq (opt, om->opt))
237 {
238 if (om->inv)
239 *mask &= ~om->mask;
240 else
241 *mask |= om->mask;
242 if (om->mask == MS_USER)
243 *mask |= MS_SECURE;
726f69e2
KZ
244#ifdef MS_SILENT
245 if (om->mask == MS_SILENT && om->inv) {
246 mount_quiet = 1;
247 verbose = 0;
248 }
249#endif
6dbe3af9
KZ
250 return;
251 }
252 if (*extra_opts)
253 strcat(extra_opts, ",");
254 strcat(extra_opts, opt);
255}
256
257/* Take -o options list and compute 4th and 5th args to mount(2). flags
258 gets the standard options and extra_opts anything we don't recognize. */
259static void
260parse_opts (char *opts, int *flags, char **extra_opts)
261{
262 char *opt;
263
264 *flags = 0;
265 *extra_opts = NULL;
266
fd6b7a7f
KZ
267 clear_string_opts();
268
6dbe3af9
KZ
269 if (opts != NULL)
270 {
271 *extra_opts = xmalloc (strlen (opts) + 1);
272 **extra_opts = '\0';
273
fd6b7a7f
KZ
274 for (opt = strtok (opts, ","); opt; opt = strtok (NULL, ","))
275 if (!parse_string_opt (opt))
276 parse_opt (opt, flags, *extra_opts);
6dbe3af9
KZ
277 }
278
279 if (readonly)
280 *flags |= MS_RDONLY;
281 if (readwrite)
282 *flags &= ~MS_RDONLY;
283}
284
285/* Try to build a canonical options string. */
286static char *
287fix_opts_string (int flags, char *extra_opts)
288{
289 const struct opt_map *om;
fd6b7a7f 290 const struct string_opt_map *m;
6dbe3af9 291 char *new_opts;
6dbe3af9
KZ
292
293 new_opts = (flags & MS_RDONLY) ? "ro" : "rw";
fd6b7a7f
KZ
294 for (om = opt_map; om->opt != NULL; om++) {
295 if (om->skip)
6dbe3af9
KZ
296 continue;
297 if (om->inv || !om->mask || (flags & om->mask) != om->mask)
298 continue;
fd6b7a7f 299 new_opts = xstrconcat3(new_opts, ",", om->opt);
6dbe3af9 300 flags &= ~om->mask;
fd6b7a7f
KZ
301 }
302 for (m = &string_opt_map[0]; m->tag; m++) {
303 if (!m->skip && *(m->valptr))
304 new_opts = xstrconcat4(new_opts, ",", m->tag, *(m->valptr));
305 }
306 if (extra_opts && *extra_opts) {
307 new_opts = xstrconcat3(new_opts, ",", extra_opts);
308 }
6dbe3af9
KZ
309 return new_opts;
310}
311
fd6b7a7f
KZ
312/* Most file system types can be recognized by a `magic' number
313 in the superblock. Note that the order of the tests is
314 significant: by coincidence a filesystem can have the
315 magic numbers for several file system types simultaneously.
316 For example, the romfs magic lives in the 1st sector;
317 xiafs does not touch the 1st sector and has its magic in
318 the 2nd sector; ext2 does not touch the first two sectors. */
319
fd6b7a7f
KZ
320static inline unsigned short
321swapped(unsigned short a) {
322 return (a>>8) | (a<<8);
323}
6dbe3af9
KZ
324
325/*
326 char *fstype(const char *device);
327
726f69e2 328 Probes the device and attempts to determine the type of filesystem
6dbe3af9
KZ
329 contained within.
330
331 Original routine by <jmorriso@bogomips.ww.ubc.ca>; made into a function
332 for mount(8) by Mike Grupenhoff <kashmir@umiacs.umd.edu>.
726f69e2
KZ
333 Read the superblock only once - aeb
334 Added a test for iso9660 - aeb
fd6b7a7f
KZ
335 Added a test for high sierra (iso9660) - quinlan@bucknell.edu
336 Corrected the test for xiafs - aeb
2b6fc908 337 Added romfs - aeb
6dbe3af9 338
fd6b7a7f 339 Currently supports: minix, ext, ext2, xiafs, iso9660, romfs
6dbe3af9 340*/
fd6b7a7f 341char *magic_known[] = { "minix", "ext", "ext2", "xiafs", "iso9660", "romfs" };
726f69e2
KZ
342
343static int
344tested(const char *device) {
345 char **m;
346
347 for (m = magic_known; m - magic_known < SIZE(magic_known); m++)
348 if (!strcmp(*m, device))
349 return 1;
350 return 0;
351}
6dbe3af9
KZ
352
353static char *
354fstype(const char *device)
355{
356 int fd;
fd6b7a7f 357 char *type = NULL;
726f69e2
KZ
358 union {
359 struct minix_super_block ms;
360 struct ext_super_block es;
361 struct ext2_super_block e2s;
726f69e2 362 } sb;
fd6b7a7f
KZ
363 union {
364 struct xiafs_super_block xiasb;
365 char romfs_magic[8];
366 } xsb;
367 union {
368 struct iso_volume_descriptor iso;
369 struct hs_volume_descriptor hs;
370 } isosb;
726f69e2
KZ
371 struct stat statbuf;
372
373 /* opening and reading an arbitrary unknown path can have
374 undesired side effects - first check that `device' refers
375 to a block device */
fd6b7a7f
KZ
376 if (stat (device, &statbuf) || !S_ISBLK(statbuf.st_mode))
377 return 0;
6dbe3af9
KZ
378
379 fd = open(device, O_RDONLY);
fd6b7a7f
KZ
380 if (fd < 0)
381 return 0;
726f69e2 382
2b6fc908 383 if (lseek(fd, 1024, SEEK_SET) != 1024
fd6b7a7f
KZ
384 || read(fd, (char *) &sb, sizeof(sb)) != sizeof(sb))
385 goto io_error;
6dbe3af9 386
2b6fc908
KZ
387 if (ext2magic(sb.e2s) == EXT2_SUPER_MAGIC
388 || ext2magic(sb.e2s) == EXT2_PRE_02B_MAGIC
389 || ext2magic(sb.e2s) == swapped(EXT2_SUPER_MAGIC))
fd6b7a7f
KZ
390 type = "ext2";
391
2b6fc908
KZ
392 else if (minixmagic(sb.ms) == MINIX_SUPER_MAGIC
393 || minixmagic(sb.ms) == MINIX_SUPER_MAGIC2)
fd6b7a7f
KZ
394 type = "minix";
395
2b6fc908 396 else if (extmagic(sb.es) == EXT_SUPER_MAGIC)
fd6b7a7f
KZ
397 type = "ext";
398
399 if (!type) {
400 if (lseek(fd, 0, SEEK_SET) != 0
401 || read(fd, (char *) &xsb, sizeof(xsb)) != sizeof(xsb))
402 goto io_error;
403
2b6fc908 404 if (xiafsmagic(xsb.xiasb) == _XIAFS_SUPER_MAGIC)
fd6b7a7f
KZ
405 type = "xiafs";
406 else if(!strncmp(xsb.romfs_magic, "-rom1fs-", 8))
407 type = "romfs";
6dbe3af9
KZ
408 }
409
fd6b7a7f
KZ
410 if (!type) {
411 if (lseek(fd, 0x8000, SEEK_SET) != 0x8000
412 || read(fd, (char *) &isosb, sizeof(isosb)) != sizeof(isosb))
413 goto io_error;
6dbe3af9 414
fd6b7a7f
KZ
415 if(strncmp(isosb.iso.id, ISO_STANDARD_ID, sizeof(isosb.iso.id)) == 0
416 || strncmp(isosb.hs.id, HS_STANDARD_ID, sizeof(isosb.hs.id)) == 0)
417 type = "iso9660";
726f69e2 418 }
6dbe3af9 419
726f69e2 420 close (fd);
fd6b7a7f
KZ
421 return(type);
422
423io_error:
424 perror(device);
425 close(fd);
426 return 0;
726f69e2 427}
6dbe3af9 428
726f69e2
KZ
429FILE *procfs;
430
431static void
432procclose(void) {
433 if (procfs)
434 fclose (procfs);
435 procfs = 0;
436}
437
438static int
439procopen(void) {
440 return ((procfs = fopen(PROC_FILESYSTEMS, "r")) != NULL);
441}
442
443static char *
444procnext(void) {
445 char line[100];
446 static char fsname[50];
447
448 while (fgets(line, sizeof(line), procfs)) {
449 if (sscanf (line, "nodev %[^\n]\n", fsname) == 1) continue;
450 if (sscanf (line, " %[^ \n]\n", fsname) != 1) continue;
451 return fsname;
452 }
453 return 0;
6dbe3af9
KZ
454}
455
726f69e2
KZ
456static int
457is_in_proc(char *type) {
458 char *fsname;
459
460 if (procopen()) {
461 while ((fsname = procnext()) != NULL)
462 if (!strcmp(fsname, type))
463 return 1;
464 }
465 return 0;
466}
467
468static int
469already (char *spec, char *node) {
fd6b7a7f 470 struct mntentchn *mc;
726f69e2
KZ
471 int ret = 1;
472
fd6b7a7f 473 if ((mc = getmntfile(node)) != NULL)
726f69e2 474 error ("mount: according to mtab, %s is already mounted on %s",
fd6b7a7f
KZ
475 mc->mnt_fsname, node);
476 else if ((mc = getmntfile(spec)) != NULL)
726f69e2 477 error ("mount: according to mtab, %s is mounted on %s",
fd6b7a7f 478 spec, mc->mnt_dir);
726f69e2
KZ
479 else
480 ret = 0;
481 return ret;
482}
6dbe3af9 483
fd6b7a7f
KZ
484/* Create mtab with a root entry. */
485static void
486create_mtab (void) {
487 struct mntentchn *fstab;
488 struct mntent mnt;
489 int flags;
490 char *extra_opts;
491 FILE *fp;
492
493 lock_mtab();
494
495 if ((fp = setmntent (MOUNTED, "a+")) == NULL)
496 die (EX_FILEIO, "mount: can't open %s for writing: %s",
497 MOUNTED, strerror (errno));
498
499 /* Find the root entry by looking it up in fstab */
500 if ((fstab = getfsfile ("/")) || (fstab = getfsfile ("root"))) {
501 parse_opts (xstrdup (fstab->mnt_opts), &flags, &extra_opts);
502 mnt.mnt_dir = "/";
503 mnt.mnt_fsname = canonicalize (fstab->mnt_fsname);
504 mnt.mnt_type = fstab->mnt_type;
505 mnt.mnt_opts = fix_opts_string (flags, extra_opts);
506 mnt.mnt_freq = mnt.mnt_passno = 0;
507
508 if (addmntent (fp, &mnt) == 1)
509 die (EX_FILEIO, "mount: error writing %s: %s",
510 MOUNTED, strerror (errno));
511 }
512 if (fchmod (fileno (fp), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0)
513 if (errno != EROFS)
514 die (EX_FILEIO, "mount: error changing mode of %s: %s",
515 MOUNTED, strerror (errno));
516 endmntent (fp);
517
518 unlock_mtab();
519}
520
521/* count successful mount system calls */
522static int mountcount = 0;
523
524static int
525mount5 (char *special, char *dir, char *type, int flags, void *data) {
526 int ret = mount (special, dir, type, 0xC0ED0000 | (flags), data);
527 if (ret == 0)
528 mountcount++;
529 return ret;
530}
531
6dbe3af9
KZ
532/* Mount a single file system. Return status,
533 so don't exit on non-fatal errors. */
534
535static int
536try_mount5 (char *spec, char *node, char **type, int flags, char *mount_opts) {
726f69e2 537 char *fsname;
6dbe3af9 538
fd6b7a7f 539 if (*type && strcasecmp (*type, "auto") == 0)
726f69e2
KZ
540 *type = NULL;
541
fd6b7a7f 542 if (!*type && !(flags & MS_REMOUNT)) {
726f69e2 543 *type = fstype(spec);
726f69e2
KZ
544 if (verbose) {
545 printf ("mount: you didn't specify a filesystem type for %s\n",
546 spec);
547 if (*type)
548 printf (" I will try type %s\n", *type);
549 else
550 printf (" I will try all types mentioned in %s\n",
551 PROC_FILESYSTEMS);
552 }
6dbe3af9 553 }
726f69e2 554
fd6b7a7f 555 if (*type || (flags & MS_REMOUNT))
726f69e2
KZ
556 return mount5 (spec, node, *type, flags & ~MS_NOSYS, mount_opts);
557
fd6b7a7f
KZ
558 if (!procopen())
559 return -1;
726f69e2
KZ
560 while ((fsname = procnext()) != NULL) {
561 if (tested (fsname))
562 continue;
6dbe3af9 563 if (mount5 (spec, node, fsname, flags & ~MS_NOSYS, mount_opts) == 0) {
726f69e2
KZ
564 *type = xstrdup(fsname);
565 procclose();
566 return 0;
567 } else if (errno != EINVAL) {
568 *type = "guess";
569 procclose();
570 return 1;
6dbe3af9
KZ
571 }
572 }
726f69e2
KZ
573 procclose();
574 *type = NULL;
575
6dbe3af9
KZ
576 return -1;
577}
578
2b6fc908
KZ
579/*
580 * try_mount_one()
581 * Try to mount one file system. When "bg" is 1, this is a retry
582 * in the background. One additional exit code EX_BG is used here.
583 * It is used to instruct the caller to retry the mount in the
584 * background.
585 */
6dbe3af9 586static int
2b6fc908
KZ
587try_mount_one (char *spec0, char *node0, char *type0, char *opts0,
588 int freq, int pass, int bg)
6dbe3af9 589{
fd6b7a7f 590 struct mntentchn mcn;
6dbe3af9
KZ
591 struct mntent mnt;
592 int mnt_err;
593 int flags;
fd6b7a7f
KZ
594 char *extra_opts; /* written in mtab */
595 char *mount_opts; /* actually used on system call */
726f69e2 596 static int added_ro = 0;
fd6b7a7f
KZ
597 int loop, looptype, offset;
598 char *spec, *node, *type, *opts, *loopdev, *loopfile;
2b6fc908 599 struct stat statbuf;
6dbe3af9 600
fd6b7a7f
KZ
601 spec = xstrdup(spec0);
602 node = xstrdup(node0);
603 type = xstrdup(type0);
604 opts = xstrdup(opts0);
605
6dbe3af9
KZ
606 parse_opts (xstrdup (opts), &flags, &extra_opts);
607
608 /* root may allow certain types of mounts by ordinary users */
726f69e2
KZ
609 if (suid && !(flags & MS_USER)) {
610 if (already (spec, node))
fd6b7a7f 611 die (EX_USAGE, "mount failed");
726f69e2 612 else
fd6b7a7f 613 die (EX_USAGE, "mount: only root can mount %s on %s", spec, node);
726f69e2 614 }
6dbe3af9
KZ
615
616 /* quietly succeed for fstab entries that don't get mounted automatically */
617 if (all && (flags & MS_NOAUTO))
618 return 0;
619
620 mount_opts = extra_opts;
621
fd6b7a7f 622 /*
2b6fc908
KZ
623 * In the case of a loop mount, either type is of the form lo@/dev/loop5
624 * or the option "-o loop=/dev/loop5" or just "-o loop" is given, or
625 * mount just has to figure things out for itself from the fact that
626 * spec is not a block device. We do not test for a block device
627 * immediately: maybe later other types of mountable objects will occur.
fd6b7a7f 628 */
2b6fc908 629
fd6b7a7f
KZ
630 loopdev = opt_loopdev;
631
632 looptype = (type && strncmp("lo@", type, 3) == 0);
633 if (looptype) {
634 if (loopdev)
635 error("mount: loop device specified twice");
636 loopdev = type+3;
637 type = opt_vfstype;
638 }
639 else if (opt_vfstype) {
640 if (type)
641 error("mount: type specified twice");
642 else
643 type = opt_vfstype;
644 }
6dbe3af9 645
fd6b7a7f
KZ
646 loop = ((flags & MS_LOOP) || loopdev || opt_offset || opt_encryption);
647 loopfile = spec;
648
649 if (loop) {
650 flags |= MS_LOOP;
651 if (fake) {
652 if (verbose)
653 printf("mount: skipping the setup of a loop device\n");
654 } else {
655 int loopro = (flags & MS_RDONLY);
656
657 if (!loopdev || !*loopdev)
658 loopdev = find_unused_loop_device();
659 if (!loopdev)
660 return EX_SYSERR; /* no more loop devices */
661 if (verbose)
662 printf("mount: going to use the loop device %s\n", loopdev);
663 offset = opt_offset ? strtoul(opt_offset, NULL, 0) : 0;
664 if (set_loop (loopdev, loopfile, offset, opt_encryption, &loopro))
665 return EX_FAIL;
666 spec = loopdev;
667 if (loopro)
668 flags |= MS_RDONLY;
669 }
6dbe3af9
KZ
670 }
671
2b6fc908 672 if (!fake && type && streq (type, "nfs")) {
6dbe3af9 673#ifdef HAVE_NFS
2b6fc908
KZ
674 mnt_err = nfsmount (spec, node, &flags, &extra_opts, &mount_opts, bg);
675 if (mnt_err)
676 return mnt_err;
6dbe3af9 677#else
fd6b7a7f
KZ
678 die (EX_SOFTWARE, "mount: this version was compiled "
679 "without support for the type `nfs'");
6dbe3af9 680#endif
2b6fc908 681 }
6dbe3af9 682
fd6b7a7f
KZ
683 /*
684 * Call mount.TYPE for types that require a separate
685 * mount program. For the moment these types are ncp and smb.
686 */
687 if (type)
688#ifndef ALWAYS_STAT
689 if (streq (type, "smb") || streq (type, "ncp"))
690#else
691 if (strlen (type) < 100)
692#endif
693 {
fd6b7a7f
KZ
694 char mountprog[120];
695
696 sprintf(mountprog, "/sbin/mount.%s", type);
697 if (stat(mountprog, &statbuf) == 0) {
698 if (fork() == 0) {
699 char *oo, *mountargs[10];
700 int i = 0;
701
702 setuid(getuid());
703 setgid(getgid());
704 oo = fix_opts_string (flags, extra_opts);
705 mountargs[i++] = mountprog;
706 mountargs[i++] = spec;
707 mountargs[i++] = node;
708 if (nomtab)
709 mountargs[i++] = "-n";
710 if (verbose)
711 mountargs[i++] = "-v";
712 if (oo && *oo) {
713 mountargs[i++] = "-o";
714 mountargs[i++] = oo;
715 }
716 mountargs[i] = NULL;
717 execv(mountprog, mountargs);
718 exit(1); /* exec failed */
719 } else if (fork() != -1) {
720 int status;
721 wait(&status);
722 return status;
723 } else
724 error("cannot fork: %s", strerror(errno));
725 }
726 }
727
6dbe3af9
KZ
728 block_signals (SIG_BLOCK);
729
730 if (fake
731 || (try_mount5 (spec, node, &type, flags & ~MS_NOSYS, mount_opts)) == 0)
fd6b7a7f 732 /* Mount succeeded, report this (if verbose) and write mtab entry. */
6dbe3af9 733 {
fd6b7a7f
KZ
734 if (loop)
735 opt_loopdev = loopdev;
736
737 mcn.mnt_fsname = mnt.mnt_fsname = canonicalize (loop ? loopfile : spec);
738 mcn.mnt_dir = mnt.mnt_dir = canonicalize (node);
739 mcn.mnt_type = mnt.mnt_type = type ? type : "unknown";
740 mcn.mnt_opts = mnt.mnt_opts = fix_opts_string (flags & ~MS_NOMTAB, extra_opts);
741 mcn.nxt = 0;
742 mnt.mnt_freq = freq;
743 mnt.mnt_passno = pass;
6dbe3af9 744
fd6b7a7f
KZ
745 /* We get chatty now rather than after the update to mtab since the
746 mount succeeded, even if the write to /etc/mtab should fail. */
747 if (verbose)
748 print_one (&mcn);
6dbe3af9 749
fd6b7a7f 750 if (!nomtab && mtab_is_writable()) {
6dbe3af9 751 if (flags & MS_REMOUNT)
fd6b7a7f
KZ
752 update_mtab (mnt.mnt_dir, &mnt);
753 else {
754 FILE *fp = setmntent(MOUNTED, "a+");
755 if (fp == NULL)
756 error("mount: can't open %s: %s", MOUNTED,
757 strerror (errno));
758 else {
759 if ((addmntent (fp, &mnt)) == 1)
760 error("mount: error writing %s: %s", MOUNTED,
761 strerror (errno));
762 endmntent(fp);
763 }
764 }
765 }
6dbe3af9
KZ
766
767 block_signals (SIG_UNBLOCK);
768 return 0;
769 }
770
fd6b7a7f
KZ
771 mnt_err = errno;
772
6dbe3af9
KZ
773 if (loop)
774 del_loop(spec);
775
6dbe3af9
KZ
776 block_signals (SIG_UNBLOCK);
777
778 /* Mount failed, complain, but don't die. */
726f69e2
KZ
779
780 if (type == 0)
781 error ("mount: you must specify the filesystem type");
782 else
6dbe3af9
KZ
783 switch (mnt_err)
784 {
785 case EPERM:
fd6b7a7f 786 if (geteuid() == 0) {
fd6b7a7f
KZ
787 if (stat (node, &statbuf) || !S_ISDIR(statbuf.st_mode))
788 error ("mount: mount point %s is not a directory", node);
789 else
790 error ("mount: permission denied");
791 } else
6dbe3af9
KZ
792 error ("mount: must be superuser to use mount");
793 break;
794 case EBUSY:
fd6b7a7f
KZ
795 if (flags & MS_REMOUNT) {
796 error ("mount: %s is busy", node);
797 } else {
798 error ("mount: %s already mounted or %s busy", spec, node);
799 already (spec, node);
800 }
6dbe3af9
KZ
801 break;
802 case ENOENT:
2b6fc908
KZ
803 if (lstat (node, &statbuf))
804 error ("mount: mount point %s does not exist", node);
805 else if (stat (node, &statbuf))
806 error ("mount: mount point %s is a symbolic link to nowhere",
807 node);
808 else if (stat (spec, &statbuf))
809 error ("mount: special device %s does not exist", spec);
810 else {
6dbe3af9
KZ
811 errno = mnt_err;
812 perror("mount");
726f69e2 813 }
2b6fc908 814 break;
6dbe3af9 815 case ENOTDIR:
fd6b7a7f
KZ
816 error ("mount: mount point %s is not a directory", node);
817 break;
6dbe3af9 818 case EINVAL:
fd6b7a7f 819 { int fd, size;
fd6b7a7f
KZ
820
821 if (flags & MS_REMOUNT) {
2b6fc908 822 error ("mount: %s not mounted already, or bad option", node);
fd6b7a7f
KZ
823 } else {
824 error ("mount: wrong fs type, bad option, bad superblock on %s,\n"
825 " or too many mounted file systems",
826 spec);
827
828 if (stat (spec, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)
829 && (fd = open(spec, O_RDONLY)) >= 0) {
830 if(ioctl(fd, BLKGETSIZE, &size) == 0 && size <= 2)
831 error (" (aren't you trying to mount an extended partition,\n"
2b6fc908 832 " instead of some logical partition inside?)");
fd6b7a7f
KZ
833 close(fd);
834 }
835 }
836 break;
837 }
6dbe3af9
KZ
838 case EMFILE:
839 error ("mount table full"); break;
840 case EIO:
841 error ("mount: %s: can't read superblock", spec); break;
842 case ENODEV:
fd6b7a7f 843 if (is_in_proc(type) || !strcmp(type, "guess"))
726f69e2 844 error("mount: %s has wrong major or minor number", spec);
fd6b7a7f
KZ
845 else if (procfs) {
846 char *lowtype, *p;
847 int u;
848
726f69e2 849 error ("mount: fs type %s not supported by kernel", type);
fd6b7a7f
KZ
850
851 /* maybe this loser asked for FAT or ISO9660 or isofs */
852 lowtype = xstrdup(type);
853 u = 0;
854 for(p=lowtype; *p; p++) {
855 if(tolower(*p) != *p) {
856 *p = tolower(*p);
857 u++;
858 }
859 }
860 if (u && is_in_proc(lowtype))
861 error ("mount: probably you meant %s", lowtype);
862 else if (!strncmp(lowtype, "iso", 3) && is_in_proc("iso9660"))
863 error ("mount: maybe you meant iso9660 ?");
864 free(lowtype);
865 } else
726f69e2
KZ
866 error ("mount: %s has wrong device number or fs type %s not supported",
867 spec, type);
868 break;
6dbe3af9 869 case ENOTBLK:
2b6fc908
KZ
870 if (stat (spec, &statbuf)) /* strange ... */
871 error ("mount: %s is not a block device, and stat fails?", spec);
872 else if (S_ISBLK(statbuf.st_mode))
873 error ("mount: the kernel does not recognize %s as a block device\n"
874 " (maybe `insmod driver'?)", spec);
875 else if (S_ISREG(statbuf.st_mode))
876 error ("mount: %s is not a block device (maybe try `-o loop'?)",
fd6b7a7f 877 spec);
2b6fc908
KZ
878 else
879 error ("mount: %s is not a block device", spec);
fd6b7a7f 880 break;
6dbe3af9
KZ
881 case ENXIO:
882 error ("mount: %s is not a valid block device", spec); break;
fd6b7a7f 883 case EACCES: /* pre-linux 1.1.38, 1.1.41 and later */
6dbe3af9 884 case EROFS: /* linux 1.1.38 and later */
726f69e2
KZ
885 if (added_ro) {
886 error ("mount: block device %s is not permitted on its filesystem",
887 spec);
6dbe3af9 888 break;
726f69e2
KZ
889 } else {
890 added_ro = 1;
fd6b7a7f
KZ
891 if (loop) {
892 opts = opts0;
893 type = type0;
894 }
726f69e2
KZ
895 if (opts) {
896 opts = realloc(xstrdup(opts), strlen(opts)+4);
6dbe3af9 897 strcat(opts, ",ro");
726f69e2
KZ
898 } else
899 opts = "ro";
900 if (type && !strcmp(type, "guess"))
901 type = 0;
fd6b7a7f
KZ
902 error ("mount: %s%s is write-protected, mounting read-only",
903 loop ? "" : "block device ", spec0);
2b6fc908 904 return try_mount_one (spec0, node0, type, opts, freq, pass, bg);
726f69e2 905 }
6dbe3af9
KZ
906 break;
907 default:
908 error ("mount: %s", strerror (mnt_err)); break;
909 }
fd6b7a7f 910 return EX_FAIL;
6dbe3af9
KZ
911}
912
2b6fc908
KZ
913/*
914 * set_proc_name()
915 * Update the argument vector, so that this process may be easily
916 * identified in a "ps" listing.
917 */
918static void
919set_proc_name (char *spec)
920{
921#ifdef DO_PS_FIDDLING
922 int i, l;
923
924 /*
925 * Move the environment so we can reuse the memory.
926 * (Code borrowed from sendmail.)
927 * WARNING: ugly assumptions on memory layout here; if this ever causes
928 * problems, #undef DO_PS_FIDDLING
929 */
930 for (i = 0; envp0[i] != NULL; i++)
931 continue;
932 environ = (char **) xmalloc(sizeof(char *) * (i + 1));
933 for (i = 0; envp0[i] != NULL; i++)
934 environ[i] = xstrdup(envp0[i]);
935 environ[i] = NULL;
936
937 if (i > 0)
938 l = envp0[i-1] + strlen(envp0[i-1]) - argv0[0];
939 else
940 l = argv0[argc0-1] + strlen(argv0[argc0-1]) - argv0[0];
941 if (l > sizeof(PROC_NAME)) {
942 strcpy(argv0[0], PROC_NAME);
943 strncpy(argv0[0] + sizeof(PROC_NAME) - 1, spec, l - sizeof(PROC_NAME) - 1);
944 argv0[1] = NULL;
945 }
946#endif
947}
948
949static int
950mount_one (char *spec, char *node, char *type, char *opts, char *cmdlineopts,
951 int freq, int pass)
952{
953 int status;
954 int status2;
955
956 /* Merge the fstab and command line options. */
957 if (opts == NULL)
958 opts = cmdlineopts;
959 else if (cmdlineopts != NULL)
960 opts = xstrconcat3(opts, ",", cmdlineopts);
961
962 if (type == NULL) {
963 if (strchr (spec, ':') != NULL) {
964 type = "nfs";
965 if (verbose)
966 printf("mount: no type was given - "
967 "I'll assume nfs because of the colon\n");
968 }
969 }
970
971 /*
972 * Try to mount the file system. When the exit status is EX_BG,
973 * we will retry in the background. Otherwise, we're done.
974 */
975 status = try_mount_one (spec, node, type, opts, freq, pass, 0);
976 if (status != EX_BG)
977 return status;
978
979 /*
980 * Retry in the background.
981 */
982 printf ("mount: backgrounding \"%s\"\n", spec);
983 fflush( stdout ); /* prevent duplicate output */
984 if (fork() > 0)
985 return 0; /* parent returns "success" */
986 spec = xstrdup(spec); /* arguments will be destroyed */
987 node = xstrdup(node); /* by set_proc_name() */
988 type = xstrdup(type);
989 opts = xstrdup(opts);
990 set_proc_name (spec); /* make a nice "ps" listing */
991 status2 = try_mount_one (spec, node, type, opts, freq, pass, 1);
992 if (verbose && status2)
993 printf ("mount: giving up \"%s\"\n", spec);
994 exit (0); /* child stops here */
995}
996
6dbe3af9
KZ
997/* Check if an fsname/dir pair was already in the old mtab. */
998static int
fd6b7a7f
KZ
999mounted (char *spec, char *node) {
1000 struct mntentchn *mc;
6dbe3af9 1001
fd6b7a7f
KZ
1002 spec = canonicalize (spec);
1003 node = canonicalize (node);
6dbe3af9 1004
fd6b7a7f
KZ
1005 for (mc = mtab_head()->nxt; mc; mc = mc->nxt)
1006 if (streq (spec, mc->mnt_fsname) && streq (node, mc->mnt_dir))
1007 return 1;
1008 return 0;
6dbe3af9
KZ
1009}
1010
fd6b7a7f
KZ
1011/* Mount all filesystems of the specified types except swap and root. */
1012/* With the --fork option: fork and let different incarnations of
1013 mount handle different filesystems. However, try to avoid several
1014 simultaneous mounts on the same physical disk, since that is very slow. */
2b6fc908 1015#define DISKMAJOR(m) (((int) m) & ~0xf)
6dbe3af9 1016
fd6b7a7f 1017static int
2b6fc908 1018mount_all (string_list types, char *options) {
fd6b7a7f 1019 struct mntentchn *mc, *mtmp;
2b6fc908 1020 int status = 0;
fd6b7a7f
KZ
1021 struct stat statbuf;
1022 struct child {
1023 pid_t pid;
2b6fc908 1024 char *group;
fd6b7a7f
KZ
1025 struct mntentchn *mec;
1026 struct mntentchn *meclast;
1027 struct child *nxt;
1028 } childhead, *childtail, *cp;
2b6fc908
KZ
1029 char major[22];
1030 char *g, *colon;
fd6b7a7f
KZ
1031
1032 /* build a chain of what we have to do, or maybe
2b6fc908 1033 several chains, one for each major or NFS host */
fd6b7a7f
KZ
1034 childhead.nxt = 0;
1035 childtail = &childhead;
1036 for (mc = fstab_head()->nxt; mc; mc = mc->nxt) {
1037 if (matching_type (mc->mnt_type, types)
1038 && !streq (mc->mnt_dir, "/")
1039 && !streq (mc->mnt_dir, "root")) {
1040 if (mounted (mc->mnt_fsname, mc->mnt_dir)) {
1041 if (verbose)
1042 printf("mount: %s already mounted on %s\n",
1043 mc->mnt_fsname, mc->mnt_dir);
1044 } else {
1045 mtmp = (struct mntentchn *) xmalloc(sizeof(*mtmp));
1046 *mtmp = *mc;
1047 mtmp->nxt = 0;
2b6fc908
KZ
1048 g = NULL;
1049 if (optfork) {
1050 if (stat(mc->mnt_fsname, &statbuf) == 0 &&
1051 S_ISBLK(statbuf.st_mode)) {
1052 sprintf(major, "#%x", DISKMAJOR(statbuf.st_rdev));
1053 g = major;
1054 }
1055#ifdef HAVE_NFS
1056 if (strcmp(mc->mnt_type, "nfs") == 0) {
1057 g = xstrdup(mc->mnt_fsname);
1058 colon = strchr(g, ':');
1059 if (colon)
1060 *colon = '\0';
1061 }
1062#endif
1063 }
1064 if (g) {
fd6b7a7f 1065 for (cp = childhead.nxt; cp; cp = cp->nxt)
2b6fc908 1066 if (cp->group && strcmp(cp->group, g) == 0) {
fd6b7a7f
KZ
1067 cp->meclast->nxt = mtmp;
1068 cp->meclast = mtmp;
1069 goto fnd;
1070 }
1071 }
1072 cp = (struct child *) xmalloc(sizeof *cp);
1073 cp->nxt = 0;
1074 cp->mec = cp->meclast = mtmp;
2b6fc908 1075 cp->group = xstrdup(g);
fd6b7a7f
KZ
1076 cp->pid = 0;
1077 childtail->nxt = cp;
1078 childtail = cp;
1079 fnd:;
1080 }
1081 }
1082 }
1083
1084 /* now do everything */
1085 for (cp = childhead.nxt; cp; cp = cp->nxt) {
1086 pid_t p = -1;
1087 if (optfork) {
1088 p = fork();
1089 if (p == -1)
1090 error("mount: cannot fork: %s", strerror (errno));
1091 else if (p != 0)
1092 cp->pid = p;
1093 }
1094
1095 /* if child, or not forked, do the mounting */
1096 if (p == 0 || p == -1) {
1097 for (mc = cp->mec; mc; mc = mc->nxt)
1098 status |= mount_one (mc->mnt_fsname, mc->mnt_dir,
2b6fc908
KZ
1099 mc->mnt_type, mc->mnt_opts,
1100 options, 0, 0);
fd6b7a7f
KZ
1101 if (mountcount)
1102 status |= EX_SOMEOK;
1103 if (p == 0)
1104 exit(status);
1105 }
1106 }
1107
1108 /* wait for children, if any */
1109 while ((cp = childhead.nxt) != NULL) {
1110 childhead.nxt = cp->nxt;
1111 if (cp->pid) {
1112 int ret;
1113 keep_waiting:
1114 if(waitpid(cp->pid, &ret, 0) == -1) {
1115 if (errno == EINTR)
1116 goto keep_waiting;
1117 perror("waitpid");
1118 } else if (WIFEXITED(ret))
1119 status |= WEXITSTATUS(ret);
1120 else
1121 status |= EX_SYSERR;
1122 }
1123 }
1124 if (mountcount)
1125 status |= EX_SOMEOK;
1126 return status;
6dbe3af9
KZ
1127}
1128
1129extern char version[];
1130static struct option longopts[] =
1131{
1132 { "all", 0, 0, 'a' },
1133 { "fake", 0, 0, 'f' },
fd6b7a7f 1134 { "fork", 0, 0, 'F' },
6dbe3af9
KZ
1135 { "help", 0, 0, 'h' },
1136 { "no-mtab", 0, 0, 'n' },
1137 { "read-only", 0, 0, 'r' },
1138 { "ro", 0, 0, 'r' },
1139 { "verbose", 0, 0, 'v' },
1140 { "version", 0, 0, 'V' },
1141 { "read-write", 0, 0, 'w' },
1142 { "rw", 0, 0, 'w' },
1143 { "options", 1, 0, 'o' },
1144 { "types", 1, 0, 't' },
1145 { NULL, 0, 0, 0 }
1146};
1147
1148const char *usage_string = "\
1149usage: mount [-hV]\n\
2b6fc908
KZ
1150 mount -a [-nfFrsvw] [-t vfstypes]\n\
1151 mount [-nfrsvw] [-o options] special | node\n\
1152 mount [-nfrsvw] [-t vfstype] [-o options] special node\n\
6dbe3af9
KZ
1153";
1154
1155static void
1156usage (FILE *fp, int n)
1157{
1158 fprintf (fp, "%s", usage_string);
726f69e2 1159 unlock_mtab();
6dbe3af9
KZ
1160 exit (n);
1161}
1162
1163int
fd6b7a7f
KZ
1164main (int argc, char *argv[]) {
1165 int c, result = 0;
1166 char *options = NULL, *spec;
6dbe3af9 1167 string_list types = NULL;
fd6b7a7f 1168 struct mntentchn *mc;
6dbe3af9 1169
2b6fc908
KZ
1170#ifdef DO_PS_FIDDLING
1171 argc0 = argc;
1172 argv0 = argv;
1173 envp0 = environ;
1174#endif
1175
1176 while ((c = getopt_long (argc, argv, "afFhno:rsvVwt:", longopts, NULL))
fd6b7a7f
KZ
1177 != EOF)
1178 switch (c) {
6dbe3af9
KZ
1179 case 'a': /* mount everything in fstab */
1180 ++all;
1181 break;
1182 case 'f': /* fake (don't actually do mount(2) call) */
1183 ++fake;
1184 break;
fd6b7a7f
KZ
1185 case 'F':
1186 ++optfork;
1187 break;
6dbe3af9
KZ
1188 case 'h': /* help */
1189 usage (stdout, 0);
1190 break;
1191 case 'n': /* mount without writing in /etc/mtab */
1192 ++nomtab;
1193 break;
fd6b7a7f
KZ
1194 case 'o': /* specify mount options */
1195 if (options)
1196 options = xstrconcat3(options, ",", optarg);
1197 else
1198 options = xstrdup(optarg);
1199 break;
6dbe3af9 1200 case 'r': /* mount readonly */
fd6b7a7f 1201 readonly = 1;
6dbe3af9
KZ
1202 readwrite = 0;
1203 break;
2b6fc908
KZ
1204 case 's': /* allow sloppy mount options */
1205 sloppy = 1;
1206 break;
fd6b7a7f
KZ
1207 case 't': /* specify file system types */
1208 types = parse_list (optarg);
1209 break;
1210 case 'v': /* be chatty - very chatty if repeated */
6dbe3af9
KZ
1211 ++verbose;
1212 break;
1213 case 'V': /* version */
726f69e2 1214 printf ("mount: %s\n", version);
6dbe3af9
KZ
1215 exit (0);
1216 case 'w': /* mount read/write */
fd6b7a7f 1217 readwrite = 1;
6dbe3af9
KZ
1218 readonly = 0;
1219 break;
6dbe3af9
KZ
1220 case 0:
1221 break;
1222 case '?':
1223 default:
fd6b7a7f
KZ
1224 usage (stderr, EX_USAGE);
1225 }
6dbe3af9
KZ
1226
1227 argc -= optind;
1228 argv += optind;
1229
2b6fc908 1230 if (argc == 0 && !all) {
6dbe3af9 1231 if (options)
fd6b7a7f 1232 usage (stderr, EX_USAGE);
2b6fc908 1233 return print_all (types);
fd6b7a7f 1234 }
6dbe3af9 1235
fd6b7a7f 1236 if (getuid () != geteuid ()) {
6dbe3af9
KZ
1237 suid = 1;
1238 if (types || options || readwrite || nomtab || all || fake || argc != 1)
fd6b7a7f
KZ
1239 die (EX_USAGE, "mount: only root can do that");
1240 }
6dbe3af9 1241
fd6b7a7f
KZ
1242 if (!nomtab && mtab_does_not_exist()) {
1243 if (verbose > 1)
1244 printf("mount: no %s found - creating it..\n", MOUNTED);
1245 create_mtab ();
1246 }
6dbe3af9 1247
fd6b7a7f 1248 switch (argc) {
6dbe3af9
KZ
1249 case 0:
1250 /* mount -a */
2b6fc908 1251 result = mount_all (types, options);
fd6b7a7f
KZ
1252 if (result == 0 && verbose)
1253 error("not mounted anything");
6dbe3af9
KZ
1254 break;
1255
1256 case 1:
1257 /* mount [-nfrvw] [-o options] special | node */
1258 if (types != NULL)
fd6b7a7f
KZ
1259 usage (stderr, EX_USAGE);
1260
6dbe3af9
KZ
1261 /* Try to find the other pathname in fstab. */
1262 spec = canonicalize (*argv);
fd6b7a7f
KZ
1263 if ((mc = getmntfile (spec)) == NULL &&
1264 (mc = getfsspec (spec)) == NULL && (mc = getfsfile (spec)) == NULL)
1265 die (EX_USAGE, "mount: can't find %s in %s or %s",
1266 spec, MOUNTED, _PATH_FSTAB);
1267
fd6b7a7f 1268 result = mount_one (xstrdup (mc->mnt_fsname), xstrdup (mc->mnt_dir),
2b6fc908 1269 xstrdup (mc->mnt_type), mc->mnt_opts, options, 0, 0);
6dbe3af9
KZ
1270 break;
1271
1272 case 2:
1273 /* mount [-nfrvw] [-t vfstype] [-o options] special node */
1274 if (types == NULL)
2b6fc908
KZ
1275 result = mount_one (argv[0], argv[1],
1276 NULL, NULL, options, 0, 0);
6dbe3af9 1277 else if (cdr (types) == NULL)
2b6fc908
KZ
1278 result = mount_one (argv[0], argv[1],
1279 car (types), NULL, options, 0, 0);
6dbe3af9 1280 else
fd6b7a7f 1281 usage (stderr, EX_USAGE);
6dbe3af9
KZ
1282 break;
1283
1284 default:
fd6b7a7f
KZ
1285 usage (stderr, EX_USAGE);
1286 }
6dbe3af9 1287
fd6b7a7f
KZ
1288 if (result == EX_SOMEOK)
1289 result = 0;
6dbe3af9
KZ
1290 exit (result);
1291}