Upload Tizen:Base source
[framework/base/util-linux-ng.git] / mount / mount.c
1 /*
2  * A mount(8) for Linux.
3  *
4  * Modifications by many people. Distributed under GPL.
5  */
6
7 #include <unistd.h>
8 #include <ctype.h>
9 #include <errno.h>
10 #include <string.h>
11 #include <getopt.h>
12 #include <stdio.h>
13
14 #include <pwd.h>
15 #include <grp.h>
16
17 #include <sys/types.h>
18 #include <sys/ioctl.h>
19 #include <sys/stat.h>
20 #include <sys/wait.h>
21 #include <sys/mount.h>
22
23 #include <mntent.h>
24
25 #ifdef HAVE_LIBSELINUX
26 #include <selinux/selinux.h>
27 #include <selinux/context.h>
28 #endif
29
30 #include "pathnames.h"
31 #include "fsprobe.h"
32 #include "devname.h"
33 #include "mount_constants.h"
34 #include "sundries.h"
35 #include "xmalloc.h"
36 #include "mount_mntent.h"
37 #include "fstab.h"
38 #include "lomount.h"
39 #include "loop.h"
40 #include "getusername.h"
41 #include "env.h"
42 #include "nls.h"
43 #include "blkdev.h"
44
45 #define DO_PS_FIDDLING
46
47 #ifdef DO_PS_FIDDLING
48 #include "setproctitle.h"
49 #endif
50
51 /* True for fake mount (-f).  */
52 static int fake = 0;
53
54 /* True if we are allowed to call /sbin/mount.${FSTYPE} */
55 static int external_allowed = 1;
56
57 /* Don't write an entry in /etc/mtab (-n).  */
58 static int nomtab = 0;
59
60 /* True for explicit readonly (-r).  */
61 static int readonly = 0;
62
63 /* Nonzero for sloppy (-s).  */
64 static int sloppy = 0;
65
66 /* True for explicit read/write (-w).  */
67 static int readwrite = 0;
68
69 /* True for all mount (-a).  */
70 static int mount_all = 0;
71
72 /* True for fork() during all mount (-F).  */
73 static int optfork = 0;
74
75 /* Add volumelabel in a listing of mounted devices (-l). */
76 static int list_with_volumelabel = 0;
77
78 /* Nonzero for mount {bind|move|make-shared|make-private|
79  *                              make-unbindable|make-slave}
80  */
81 static int mounttype = 0;
82
83 /* True if (ruid != euid) or (0 != ruid), i.e. only "user" mounts permitted.  */
84 static int restricted = 1;
85
86 /* Contains the fd to read the passphrase from, if any. */
87 static int pfd = -1;
88
89 /* mount(2) options */
90 struct mountargs {
91        const char *spec;
92        const char *node;
93        const char *type;
94        int flags;
95        void *data;
96 };
97
98 /* Map from -o and fstab option strings to the flag argument to mount(2).  */
99 struct opt_map {
100   const char *opt;              /* option name */
101   int  skip;                    /* skip in mtab option string */
102   int  inv;                     /* true if flag value should be inverted */
103   int  mask;                    /* flag mask value */
104 };
105
106 /* Custom mount options for our own purposes.  */
107 /* Maybe these should now be freed for kernel use again */
108 #define MS_NOAUTO       0x80000000
109 #define MS_USERS        0x40000000
110 #define MS_USER         0x20000000
111 #define MS_OWNER        0x10000000
112 #define MS_GROUP        0x08000000
113 #define MS_COMMENT      0x02000000
114 #define MS_LOOP         0x00010000
115
116 /* Options that we keep the mount system call from seeing.  */
117 #define MS_NOSYS        (MS_NOAUTO|MS_USERS|MS_USER|MS_COMMENT|MS_LOOP)
118
119 /* Options that we keep from appearing in the options field in the mtab.  */
120 #define MS_NOMTAB       (MS_REMOUNT|MS_NOAUTO|MS_USERS|MS_USER)
121
122 #define MS_PROPAGATION  (MS_SHARED|MS_SLAVE|MS_UNBINDABLE|MS_PRIVATE)
123
124 /* Options that we make ordinary users have by default.  */
125 #define MS_SECURE       (MS_NOEXEC|MS_NOSUID|MS_NODEV)
126
127 /* Options that we make owner-mounted devices have by default */
128 #define MS_OWNERSECURE  (MS_NOSUID|MS_NODEV)
129
130 static const struct opt_map opt_map[] = {
131   { "defaults", 0, 0, 0         },      /* default options */
132   { "ro",       1, 0, MS_RDONLY },      /* read-only */
133   { "rw",       1, 1, MS_RDONLY },      /* read-write */
134   { "exec",     0, 1, MS_NOEXEC },      /* permit execution of binaries */
135   { "noexec",   0, 0, MS_NOEXEC },      /* don't execute binaries */
136   { "suid",     0, 1, MS_NOSUID },      /* honor suid executables */
137   { "nosuid",   0, 0, MS_NOSUID },      /* don't honor suid executables */
138   { "dev",      0, 1, MS_NODEV  },      /* interpret device files  */
139   { "nodev",    0, 0, MS_NODEV  },      /* don't interpret devices */
140   { "sync",     0, 0, MS_SYNCHRONOUS},  /* synchronous I/O */
141   { "async",    0, 1, MS_SYNCHRONOUS},  /* asynchronous I/O */
142   { "dirsync",  0, 0, MS_DIRSYNC},      /* synchronous directory modifications */
143   { "remount",  0, 0, MS_REMOUNT},      /* Alter flags of mounted FS */
144   { "bind",     0, 0, MS_BIND   },      /* Remount part of tree elsewhere */
145   { "rbind",    0, 0, MS_BIND|MS_REC }, /* Idem, plus mounted subtrees */
146   { "auto",     0, 1, MS_NOAUTO },      /* Can be mounted using -a */
147   { "noauto",   0, 0, MS_NOAUTO },      /* Can  only be mounted explicitly */
148   { "users",    0, 0, MS_USERS  },      /* Allow ordinary user to mount */
149   { "nousers",  0, 1, MS_USERS  },      /* Forbid ordinary user to mount */
150   { "user",     0, 0, MS_USER   },      /* Allow ordinary user to mount */
151   { "nouser",   0, 1, MS_USER   },      /* Forbid ordinary user to mount */
152   { "owner",    0, 0, MS_OWNER  },      /* Let the owner of the device mount */
153   { "noowner",  0, 1, MS_OWNER  },      /* Device owner has no special privs */
154   { "group",    0, 0, MS_GROUP  },      /* Let the group of the device mount */
155   { "nogroup",  0, 1, MS_GROUP  },      /* Device group has no special privs */
156   { "_netdev",  0, 0, MS_COMMENT},      /* Device requires network */
157   { "comment",  0, 0, MS_COMMENT},      /* fstab comment only (kudzu,_netdev)*/
158
159   /* add new options here */
160 #ifdef MS_NOSUB
161   { "sub",      0, 1, MS_NOSUB  },      /* allow submounts */
162   { "nosub",    0, 0, MS_NOSUB  },      /* don't allow submounts */
163 #endif
164 #ifdef MS_SILENT
165   { "quiet",    0, 0, MS_SILENT    },   /* be quiet  */
166   { "loud",     0, 1, MS_SILENT    },   /* print out messages. */
167 #endif
168 #ifdef MS_MANDLOCK
169   { "mand",     0, 0, MS_MANDLOCK },    /* Allow mandatory locks on this FS */
170   { "nomand",   0, 1, MS_MANDLOCK },    /* Forbid mandatory locks on this FS */
171 #endif
172   { "loop",     1, 0, MS_LOOP   },      /* use a loop device */
173 #ifdef MS_NOATIME
174   { "atime",    0, 1, MS_NOATIME },     /* Update access time */
175   { "noatime",  0, 0, MS_NOATIME },     /* Do not update access time */
176 #endif
177 #ifdef MS_I_VERSION
178   { "iversion", 0, 0, MS_I_VERSION },   /* Update inode I_version time */
179   { "noiversion", 0, 1, MS_I_VERSION }, /* Don't update inode I_version 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 #ifdef MS_RELATIME
186   { "relatime", 0, 0, MS_RELATIME },   /* Update access times relative to
187                                           mtime/ctime */
188   { "norelatime", 0, 1, MS_RELATIME }, /* Update access time without regard
189                                           to mtime/ctime */
190 #endif
191 #ifdef MS_STRICTATIME
192   { "strictatime", 0, 0, MS_STRICTATIME }, /* Strict atime semantics */
193   { "nostrictatime", 0, 1, MS_STRICTATIME }, /* kernel default atime */
194 #endif
195   { "nofail",   0, 0, MS_COMMENT},      /* Do not fail if ENOENT on dev */
196   { NULL,       0, 0, 0         }
197 };
198
199 static int opt_nofail = 0;
200
201 static const char *opt_loopdev, *opt_vfstype, *opt_offset, *opt_sizelimit,
202         *opt_encryption, *opt_speed, *opt_comment, *opt_uhelper;
203
204 static int mounted (const char *spec0, const char *node0);
205 static int check_special_mountprog(const char *spec, const char *node,
206                 const char *type, int flags, char *extra_opts, int *status);
207
208 static struct string_opt_map {
209   char *tag;
210   int skip;
211   const char **valptr;
212 } string_opt_map[] = {
213   { "loop=",    0, &opt_loopdev },
214   { "vfs=",     1, &opt_vfstype },
215   { "offset=",  0, &opt_offset },
216   { "sizelimit=",  0, &opt_sizelimit },
217   { "encryption=", 0, &opt_encryption },
218   { "speed=", 0, &opt_speed },
219   { "comment=", 1, &opt_comment },
220   { "uhelper=", 0, &opt_uhelper },
221   { NULL, 0, NULL }
222 };
223
224 static void
225 clear_string_opts(void) {
226         struct string_opt_map *m;
227
228         for (m = &string_opt_map[0]; m->tag; m++)
229                 *(m->valptr) = NULL;
230 }
231
232 static int
233 parse_string_opt(char *s) {
234         struct string_opt_map *m;
235         int lth;
236
237         for (m = &string_opt_map[0]; m->tag; m++) {
238                 lth = strlen(m->tag);
239                 if (!strncmp(s, m->tag, lth)) {
240                         *(m->valptr) = xstrdup(s + lth);
241                         return 1;
242                 }
243         }
244         return 0;
245 }
246
247 /* Report on a single mount.  */
248 static void
249 print_one (const struct my_mntent *me) {
250         if (mount_quiet)
251                 return;
252         printf ("%s on %s", me->mnt_fsname, me->mnt_dir);
253         if (me->mnt_type != NULL && *(me->mnt_type) != '\0')
254                 printf (" type %s", me->mnt_type);
255         if (me->mnt_opts != NULL)
256                 printf (" (%s)", me->mnt_opts);
257         if (list_with_volumelabel && is_pseudo_fs(me->mnt_type) == 0) {
258                 const char *devname = spec_to_devname(me->mnt_fsname);
259
260                 if (devname) {
261                         const char *label;
262
263                         label = fsprobe_get_label_by_devname(devname);
264                         my_free(devname);
265
266                         if (label) {
267                                 printf (" [%s]", label);
268                                 my_free(label);
269                         }
270                 }
271         }
272         printf ("\n");
273 }
274
275 /* Report on everything in mtab (of the specified types if any).  */
276 static int
277 print_all (char *types) {
278      struct mntentchn *mc, *mc0;
279
280      mc0 = mtab_head();
281      for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt) {
282           if (matching_type (mc->m.mnt_type, types))
283                print_one (&(mc->m));
284      }
285      exit (0);
286 }
287
288 /* reallocates its first arg */
289 static char *
290 append_opt(char *s, const char *opt, const char *val)
291 {
292         if (!opt)
293                 return s;
294         if (!s) {
295                 if (!val)
296                        return xstrdup(opt);             /* opt */
297
298                 return xstrconcat3(NULL, opt, val);     /* opt=val */
299         }
300         if (!val)
301                 return xstrconcat3(s, ",", opt);        /* s,opt */
302
303         return xstrconcat4(s, ",", opt, val);           /* s,opt=val */
304 }
305
306 static char *
307 append_numopt(char *s, const char *opt, long num)
308 {
309         char buf[32];
310
311         snprintf(buf, sizeof(buf), "%ld", num);
312         return append_opt(s, opt, buf);
313 }
314
315 #ifdef HAVE_LIBSELINUX
316 /* strip quotes from a "string"
317  * Warning: This function modify the "str" argument.
318  */
319 static char *
320 strip_quotes(char *str)
321 {
322         char *end = NULL;
323
324         if (*str != '"')
325                 return str;
326
327         end = strrchr(str, '"');
328         if (end == NULL || end == str)
329                 die (EX_USAGE, _("mount: improperly quoted option string '%s'"), str);
330
331         *end = '\0';
332         return str+1;
333 }
334
335 /* translates SELinux context from human to raw format and
336  * appends it to the mount extra options.
337  *
338  * returns -1 on error and 0 on success
339  */
340 static int
341 append_context(const char *optname, char *optdata, char **extra_opts)
342 {
343         security_context_t raw = NULL;
344         char *data = NULL;
345
346         if (is_selinux_enabled() != 1)
347                 /* ignore the option if we running without selinux */
348                 return 0;
349
350         if (optdata==NULL || *optdata=='\0' || optname==NULL)
351                 return -1;
352
353         /* TODO: use strip_quotes() for all mount options? */
354         data = *optdata =='"' ? strip_quotes(optdata) : optdata;
355
356         if (selinux_trans_to_raw_context(
357                         (security_context_t) data, &raw) == -1 ||
358                         raw == NULL)
359                 return -1;
360
361         if (verbose)
362                 printf(_("mount: translated %s '%s' to '%s'\n"),
363                                 optname, data, (char *) raw);
364
365         *extra_opts = append_opt(*extra_opts, optname, NULL);
366         *extra_opts = xstrconcat4(*extra_opts, "\"", (char *) raw, "\"");
367
368         freecon(raw);
369         return 0;
370 }
371 #endif
372
373 /*
374  * Look for OPT in opt_map table and return mask value.
375  * If OPT isn't found, tack it onto extra_opts (which is non-NULL).
376  * For the options uid= and gid= replace user or group name by its value.
377  */
378 static inline void
379 parse_opt(char *opt, int *mask, char **extra_opts) {
380         const struct opt_map *om;
381
382         for (om = opt_map; om->opt != NULL; om++)
383                 if (streq (opt, om->opt)) {
384                         if (om->inv)
385                                 *mask &= ~om->mask;
386                         else
387                                 *mask |= om->mask;
388                         if ((om->mask == MS_USER || om->mask == MS_USERS)
389                             && !om->inv)
390                                 *mask |= MS_SECURE;
391                         if ((om->mask == MS_OWNER || om->mask == MS_GROUP)
392                             && !om->inv)
393                                 *mask |= MS_OWNERSECURE;
394 #ifdef MS_SILENT
395                         if (om->mask == MS_SILENT && om->inv)  {
396                                 mount_quiet = 1;
397                                 verbose = 0;
398                         }
399 #endif
400                         if (streq(opt, "nofail"))
401                                 opt_nofail = 1;
402                         return;
403                 }
404
405         /* convert nonnumeric ids to numeric */
406         if (!strncmp(opt, "uid=", 4) && !isdigit(opt[4])) {
407                 struct passwd *pw = getpwnam(opt+4);
408
409                 if (pw) {
410                         *extra_opts = append_numopt(*extra_opts,
411                                                 "uid=", pw->pw_uid);
412                         return;
413                 }
414         }
415         if (!strncmp(opt, "gid=", 4) && !isdigit(opt[4])) {
416                 struct group *gr = getgrnam(opt+4);
417
418                 if (gr) {
419                         *extra_opts = append_numopt(*extra_opts,
420                                                 "gid=", gr->gr_gid);
421                         return;
422                 }
423         }
424
425 #ifdef HAVE_LIBSELINUX
426         if (strncmp(opt, "context=", 8) == 0 && *(opt+8)) {
427                 if (append_context("context=", opt+8, extra_opts) == 0)
428                         return;
429         }
430         if (strncmp(opt, "fscontext=", 10) == 0 && *(opt+10)) {
431                 if (append_context("fscontext=", opt+10, extra_opts) == 0)
432                         return;
433         }
434         if (strncmp(opt, "defcontext=", 11) == 0 && *(opt+11)) {
435                 if (append_context("defcontext=", opt+11, extra_opts) == 0)
436                         return;
437         }
438         if (strncmp(opt, "rootcontext=", 12) == 0 && *(opt+12)) {
439                 if (append_context("rootcontext=", opt+12, extra_opts) == 0)
440                         return;
441         }
442 #endif
443         *extra_opts = append_opt(*extra_opts, opt, NULL);
444 }
445
446 /* Take -o options list and compute 4th and 5th args to mount(2).  flags
447    gets the standard options (indicated by bits) and extra_opts all the rest */
448 static void
449 parse_opts (const char *options, int *flags, char **extra_opts) {
450         *flags = 0;
451         *extra_opts = NULL;
452
453         clear_string_opts();
454
455         if (options != NULL) {
456                 char *opts = xstrdup(options);
457                 int open_quote = 0;
458                 char *opt, *p;
459
460                 for (p=opts, opt=NULL; p && *p; p++) {
461                         if (!opt)
462                                 opt = p;                /* begin of the option item */
463                         if (*p == '"')
464                                 open_quote ^= 1;        /* reverse the status */
465                         if (open_quote)
466                                 continue;               /* still in quoted block */
467                         if (*p == ',')
468                                 *p = '\0';              /* terminate the option item */
469                         /* end of option item or last item */
470                         if (*p == '\0' || *(p+1) == '\0') {
471                                 if (!parse_string_opt(opt))
472                                         parse_opt(opt, flags, extra_opts);
473                                 opt = NULL;
474                         }
475                 }
476                 free(opts);
477         }
478
479         if (readonly)
480                 *flags |= MS_RDONLY;
481         if (readwrite)
482                 *flags &= ~MS_RDONLY;
483
484         if (mounttype & MS_PROPAGATION)
485                 *flags &= ~MS_BIND;
486         *flags |= mounttype;
487 }
488
489 /* Try to build a canonical options string.  */
490 static char *
491 fix_opts_string (int flags, const char *extra_opts, const char *user) {
492         const struct opt_map *om;
493         const struct string_opt_map *m;
494         char *new_opts;
495
496         new_opts = append_opt(NULL, (flags & MS_RDONLY) ? "ro" : "rw", NULL);
497         for (om = opt_map; om->opt != NULL; om++) {
498                 if (om->skip)
499                         continue;
500                 if (om->inv || !om->mask || (flags & om->mask) != om->mask)
501                         continue;
502                 new_opts = append_opt(new_opts, om->opt, NULL);
503                 flags &= ~om->mask;
504         }
505         for (m = &string_opt_map[0]; m->tag; m++) {
506                 if (!m->skip && *(m->valptr))
507                         new_opts = append_opt(new_opts, m->tag, *(m->valptr));
508         }
509         if (extra_opts && *extra_opts)
510                 new_opts = append_opt(new_opts, extra_opts, NULL);
511
512         if (user)
513                 new_opts = append_opt(new_opts, "user=", user);
514
515         return new_opts;
516 }
517
518 static int
519 already (const char *spec0, const char *node0) {
520         struct mntentchn *mc;
521         int ret = 1;
522         char *spec = canonicalize_spec(spec0);
523         char *node = canonicalize(node0);
524
525         if ((mc = getmntfile(node)) != NULL)
526                 error (_("mount: according to mtab, "
527                          "%s is already mounted on %s"),
528                        mc->m.mnt_fsname, node);
529         else if (spec && strcmp (spec, "none") &&
530                  (mc = getmntfile(spec)) != NULL)
531                 error (_("mount: according to mtab, %s is mounted on %s"),
532                        spec, mc->m.mnt_dir);
533         else
534                 ret = 0;
535
536         free(spec);
537         free(node);
538
539         return ret;
540 }
541
542 /* Create mtab with a root entry.  */
543 static void
544 create_mtab (void) {
545         struct mntentchn *fstab;
546         struct my_mntent mnt;
547         int flags;
548         mntFILE *mfp;
549
550         lock_mtab();
551
552         mfp = my_setmntent (_PATH_MOUNTED, "a+");
553         if (mfp == NULL || mfp->mntent_fp == NULL) {
554                 int errsv = errno;
555                 die (EX_FILEIO, _("mount: can't open %s for writing: %s"),
556                      _PATH_MOUNTED, strerror (errsv));
557         }
558
559         /* Find the root entry by looking it up in fstab */
560         if ((fstab = getfs_by_dir ("/")) || (fstab = getfs_by_dir ("root"))) {
561                 char *extra_opts;
562                 parse_opts (fstab->m.mnt_opts, &flags, &extra_opts);
563                 mnt.mnt_dir = "/";
564                 mnt.mnt_fsname = spec_to_devname(fstab->m.mnt_fsname);
565                 mnt.mnt_type = fstab->m.mnt_type;
566                 mnt.mnt_opts = fix_opts_string (flags, extra_opts, NULL);
567                 mnt.mnt_freq = mnt.mnt_passno = 0;
568                 free(extra_opts);
569
570                 if (my_addmntent (mfp, &mnt) == 1) {
571                         int errsv = errno;
572                         die (EX_FILEIO, _("mount: error writing %s: %s"),
573                              _PATH_MOUNTED, strerror (errsv));
574                 }
575         }
576         if (fchmod (fileno (mfp->mntent_fp), 0644) < 0)
577                 if (errno != EROFS) {
578                         int errsv = errno;
579                         die (EX_FILEIO,
580                              _("mount: error changing mode of %s: %s"),
581                              _PATH_MOUNTED, strerror (errsv));
582                 }
583         my_endmntent (mfp);
584
585         unlock_mtab();
586
587         reset_mtab_info();
588 }
589
590 /* count successful mount system calls */
591 static int mountcount = 0;
592
593 /*
594  * do_mount_syscall()
595  *      Mount a single file system. Keep track of successes.
596  * returns: 0: OK, -1: error in errno
597  */
598 static int
599 do_mount_syscall (struct mountargs *args) {
600         int flags = args->flags;
601
602         if ((flags & MS_MGC_MSK) == 0)
603                 flags |= MS_MGC_VAL;
604
605         if (verbose > 2)
606                 printf("mount: mount(2) syscall: source: \"%s\", target: \"%s\", "
607                         "filesystemtype: \"%s\", mountflags: %d, data: %s\n",
608                         args->spec, args->node, args->type, flags, (char *) args->data);
609
610         return mount (args->spec, args->node, args->type, flags, args->data);
611 }
612
613 /*
614  * do_mount()
615  *      Mount a single file system, possibly invoking an external handler to
616  *      do so. Keep track of successes.
617  * returns: 0: OK, -1: error in errno
618  */
619 static int
620 do_mount (struct mountargs *args, int *special, int *status) {
621         int ret;
622         if (check_special_mountprog(args->spec, args->node, args->type,
623                                     args->flags, args->data, status)) {
624                 *special = 1;
625                 ret = 0;
626         } else
627                 ret = do_mount_syscall(args);
628
629         if (ret == 0)
630                 mountcount++;
631         return ret;
632 }
633
634 /*
635  * check_special_mountprog()
636  *      If there is a special mount program for this type, exec it.
637  * returns: 0: no exec was done, 1: exec was done, status has result
638  */
639 static int
640 check_special_mountprog(const char *spec, const char *node, const char *type, int flags,
641                         char *extra_opts, int *status) {
642   char mountprog[120];
643   struct stat statbuf;
644   int res;
645
646   if (!external_allowed)
647       return 0;
648
649   if (type == NULL || strcmp(type, "none") == 0)
650           return 0;
651
652   if (strlen(type) < 100) {
653        sprintf(mountprog, "/sbin/mount.%s", type);
654        if (stat(mountprog, &statbuf) == 0) {
655             if (verbose)
656                  fflush(stdout);
657             res = fork();
658             if (res == 0) {
659                  char *oo, *mountargs[10];
660                  int i = 0;
661
662                  if(setgid(getgid()) < 0)
663                          die(EX_FAIL, _("mount: cannot set group id: %s"), strerror(errno));
664
665                  if(setuid(getuid()) < 0)
666                          die(EX_FAIL, _("mount: cannot set user id: %s"), strerror(errno));
667
668                  oo = fix_opts_string (flags, extra_opts, NULL);
669                  mountargs[i++] = mountprog;                            /* 1 */
670                  mountargs[i++] = (char *) spec;                        /* 2 */
671                  mountargs[i++] = (char *) node;                        /* 3 */
672                  if (sloppy && strncmp(type, "nfs", 3) == 0)
673                       mountargs[i++] = "-s";                            /* 4 */
674                  if (fake)
675                       mountargs[i++] = "-f";                            /* 5 */
676                  if (nomtab)
677                       mountargs[i++] = "-n";                            /* 6 */
678                  if (verbose)
679                       mountargs[i++] = "-v";                            /* 7 */
680                  if (oo && *oo) {
681                       mountargs[i++] = "-o";                            /* 8 */
682                       mountargs[i++] = oo;                              /* 9 */
683                  }
684                  mountargs[i] = NULL;                                   /* 10 */
685
686                  if (verbose > 2) {
687                         i = 0;
688                         while(mountargs[i]) {
689                                 printf("mount: external mount: argv[%d] = \"%s\"\n",
690                                         i, mountargs[i]);
691                                 i++;
692                         }
693                         fflush(stdout);
694                  }
695
696                  execv(mountprog, mountargs);
697                  exit(1);       /* exec failed */
698             } else if (res != -1) {
699                  int st;
700                  wait(&st);
701                  *status = (WIFEXITED(st) ? WEXITSTATUS(st) : EX_SYSERR);
702                  return 1;
703             } else {
704                  int errsv = errno;
705                  error(_("mount: cannot fork: %s"), strerror(errsv));
706             }
707        }
708   }
709   return 0;
710 }
711
712
713 /* list of already tested filesystems by procfsloop_mount() */
714 static struct tried {
715         struct tried *next;
716         char *type;
717 } *tried = NULL;
718
719 static int
720 was_tested(const char *fstype) {
721         struct tried *t;
722
723         if (fsprobe_known_fstype(fstype))
724                 return 1;
725         for (t = tried; t; t = t->next) {
726                 if (!strcmp(t->type, fstype))
727                         return 1;
728         }
729         return 0;
730 }
731
732 static void
733 set_tested(const char *fstype) {
734         struct tried *t = xmalloc(sizeof(struct tried));
735
736         t->next = tried;
737         t->type = xstrdup(fstype);
738         tried = t;
739 }
740
741 static void
742 free_tested(void) {
743         struct tried *t, *tt;
744
745         t = tried;
746         while(t) {
747                 free(t->type);
748                 tt = t->next;
749                 free(t);
750                 t = tt;
751         }
752         tried = NULL;
753 }
754
755 static char *
756 procfsnext(FILE *procfs) {
757    char line[100];
758    char fsname[100];
759
760    while (fgets(line, sizeof(line), procfs)) {
761       if (sscanf (line, "nodev %[^\n]\n", fsname) == 1) continue;
762       if (sscanf (line, " %[^ \n]\n", fsname) != 1) continue;
763       return xstrdup(fsname);
764    }
765    return 0;
766 }
767
768 /* Only use /proc/filesystems here, this is meant to test what
769    the kernel knows about, so /etc/filesystems is irrelevant.
770    Return: 1: yes, 0: no, -1: cannot open procfs */
771 static int
772 known_fstype_in_procfs(const char *type)
773 {
774     FILE *procfs;
775     char *fsname;
776     int ret = -1;
777
778     procfs = fopen(_PATH_PROC_FILESYSTEMS, "r");
779     if (procfs) {
780         ret = 0;
781         while ((fsname = procfsnext(procfs)) != NULL)
782             if (!strcmp(fsname, type)) {
783                 ret = 1;
784                 break;
785             }
786         fclose(procfs);
787         procfs = NULL;
788     }
789     return ret;
790 }
791
792 /* Try all types in FILESYSTEMS, except those in *types,
793    in case *types starts with "no" */
794 /* return: 0: OK, -1: error in errno, 1: type not found */
795 /* when 0 or -1 is returned, *types contains the type used */
796 /* when 1 is returned, *types is NULL */
797 static int
798 procfsloop_mount(int (*mount_fn)(struct mountargs *, int *, int *),
799                          struct mountargs *args,
800                          const char **types,
801                          int *special, int *status)
802 {
803         char *files[2] = { _PATH_FILESYSTEMS, _PATH_PROC_FILESYSTEMS };
804         FILE *procfs;
805         char *fsname;
806         const char *notypes = NULL;
807         int no = 0;
808         int ret = 1;
809         int errsv = 0;
810         int i;
811
812         if (*types && !strncmp(*types, "no", 2)) {
813                 no = 1;
814                 notypes = (*types) + 2;
815         }
816         *types = NULL;
817
818         /* Use _PATH_PROC_FILESYSTEMS only when _PATH_FILESYSTEMS
819          * (/etc/filesystems) does not exist.  In some cases trying a
820          * filesystem that the kernel knows about on the wrong data will crash
821          * the kernel; in such cases _PATH_FILESYSTEMS can be used to list the
822          * filesystems that we are allowed to try, and in the order they should
823          * be tried.  End _PATH_FILESYSTEMS with a line containing a single '*'
824          * only, if _PATH_PROC_FILESYSTEMS should be tried afterwards.
825          */
826         for (i=0; i<2; i++) {
827                 procfs = fopen(files[i], "r");
828                 if (!procfs)
829                         continue;
830                 while ((fsname = procfsnext(procfs)) != NULL) {
831                         if (!strcmp(fsname, "*")) {
832                                 fclose(procfs);
833                                 goto nexti;
834                         }
835                         if (was_tested (fsname))
836                                 continue;
837                         if (no && matching_type(fsname, notypes))
838                                 continue;
839                         set_tested (fsname);
840                         args->type = fsname;
841                         if (verbose)
842                                 printf(_("Trying %s\n"), fsname);
843                         if ((*mount_fn) (args, special, status) == 0) {
844                                 *types = fsname;
845                                 ret = 0;
846                                 break;
847                         } else if (errno != EINVAL &&
848                                    known_fstype_in_procfs(fsname) == 1) {
849                                 *types = "guess";
850                                 ret = -1;
851                                 errsv = errno;
852                                 break;
853                         }
854                 }
855                 free_tested();
856                 fclose(procfs);
857                 errno = errsv;
858                 return ret;
859         nexti:;
860         }
861         return 1;
862 }
863
864 static const char *
865 guess_fstype_by_devname(const char *devname)
866 {
867    const char *type = fsprobe_get_fstype_by_devname(devname);
868
869    if (verbose) {
870       printf (_("mount: you didn't specify a filesystem type for %s\n"), devname);
871
872       if (!type)
873          printf (_("       I will try all types mentioned in %s or %s\n"),
874                       _PATH_FILESYSTEMS, _PATH_PROC_FILESYSTEMS);
875       else if (!strcmp(type, MNTTYPE_SWAP))
876          printf (_("       and it looks like this is swapspace\n"));
877       else
878          printf (_("       I will try type %s\n"), type);
879    }
880    return type;
881 }
882
883 /*
884  * guess_fstype_and_mount()
885  *      Mount a single file system. Guess the type when unknown.
886  * returns: 0: OK, -1: error in errno, 1: other error
887  *      don't exit on non-fatal errors.
888  *      on return types is filled with the type used.
889  */
890 static int
891 guess_fstype_and_mount(const char *spec, const char *node, const char **types,
892                        int flags, char *mount_opts, int *special, int *status) {
893    struct mountargs args = { spec, node, NULL, flags & ~MS_NOSYS, mount_opts };
894
895    if (*types && strcasecmp (*types, "auto") == 0)
896       *types = NULL;
897
898    if (!*types && !(flags & MS_REMOUNT)) {
899       *types = guess_fstype_by_devname(spec);
900       if (*types) {
901           if (!strcmp(*types, MNTTYPE_SWAP)) {
902               error(_("%s looks like swapspace - not mounted"), spec);
903               *types = NULL;
904               return 1;
905           } else {
906               args.type = *types;
907               return do_mount (&args, special, status);
908           }
909       }
910    }
911
912    /* Accept a comma-separated list of types, and try them one by one */
913    /* A list like "nonfs,.." indicates types not to use */
914    if (*types && strncmp(*types, "no", 2) && strchr(*types,',')) {
915       char *t = strdup(*types);
916       char *p;
917
918       while((p = strchr(t,',')) != NULL) {
919          *p = 0;
920          args.type = *types = t;
921          if (do_mount (&args, special, status) == 0)
922             return 0;
923          t = p+1;
924       }
925       /* do last type below */
926       *types = t;
927    }
928
929    if (*types || (flags & MS_REMOUNT)) {
930       args.type = *types;
931       return do_mount (&args, special, status);
932    }
933
934    return procfsloop_mount(do_mount, &args, types, special, status);
935 }
936
937 /*
938  * restricted_check()
939  *      Die if the user is not allowed to do this.
940  */
941 static void
942 restricted_check(const char *spec, const char *node, int *flags, char **user) {
943   if (restricted) {
944       /*
945        * MS_OWNER: Allow owners to mount when fstab contains
946        * the owner option.  Note that this should never be used
947        * in a high security environment, but may be useful to give
948        * people at the console the possibility of mounting a floppy.
949        * MS_GROUP: Allow members of device group to mount. (Martin Dickopp)
950        */
951       if (*flags & (MS_OWNER | MS_GROUP)) {
952           struct stat sb;
953
954           if (!strncmp(spec, "/dev/", 5) && stat(spec, &sb) == 0) {
955
956               if (*flags & MS_OWNER) {
957                   if (getuid() == sb.st_uid)
958                       *flags |= MS_USER;
959               }
960
961               if (*flags & MS_GROUP) {
962                   if (getgid() == sb.st_gid)
963                       *flags |= MS_USER;
964                   else {
965                       int n = getgroups(0, NULL);
966
967                       if (n > 0) {
968                               gid_t *groups = xmalloc(n * sizeof(*groups));
969                               if (getgroups(n, groups) == n) {
970                                       int i;
971                                       for (i = 0; i < n; i++) {
972                                               if (groups[i] == sb.st_gid) {
973                                                       *flags |= MS_USER;
974                                                       break;
975                                               }
976                                       }
977                               }
978                               free(groups);
979                       }
980                   }
981               }
982           }
983       }
984
985       /* James Kehl <mkehl@gil.com.au> came with a similar patch:
986          allow an arbitrary user to mount when he is the owner of
987          the mount-point and has write-access to the device.
988          This is even less secure. Let me skip it for the time being;
989          there should be an explicit fstab line allowing such things. */
990
991       if (!(*flags & (MS_USER | MS_USERS))) {
992           if (already (spec, node))
993             die (EX_USAGE, _("mount failed"));
994           else
995             die (EX_USAGE, _("mount: only root can mount %s on %s"), spec, node);
996       }
997       if (*flags & MS_USER)
998           *user = getusername();
999   }
1000
1001   *flags &= ~(MS_OWNER | MS_GROUP);
1002 }
1003
1004 /* Check, if there already exists a mounted loop device on the mountpoint node
1005  * with the same parameters.
1006  */
1007 static int
1008 is_mounted_same_loopfile(const char *node0, const char *loopfile, unsigned long long offset)
1009 {
1010         struct mntentchn *mnt = NULL;
1011         char *node;
1012         int res = 0;
1013
1014         node = canonicalize(node0);
1015
1016         /* Search for mountpoint node in mtab,
1017          * procceed if any of these has the loop option set or
1018          * the device is a loop device
1019          */
1020         mnt = getmntdirbackward(node, mnt);
1021         if (!mnt) {
1022                 free(node);
1023                 return 0;
1024         }
1025         for(; mnt && res == 0; mnt = getmntdirbackward(node, mnt)) {
1026                 char *p;
1027
1028                 if (strncmp(mnt->m.mnt_fsname, "/dev/loop", 9) == 0)
1029                         res = loopfile_used_with((char *) mnt->m.mnt_fsname,
1030                                         loopfile, offset);
1031
1032                 else if ((p = strstr(mnt->m.mnt_opts, "loop="))) {
1033                         char *dev = xstrdup(p+5);
1034                         if ((p = strchr(dev, ',')))
1035                                 *p = '\0';
1036                         res = loopfile_used_with(dev, loopfile, offset);
1037                         free(dev);
1038                 }
1039         }
1040
1041         free(node);
1042         return res;
1043 }
1044
1045 static int
1046 loop_check(const char **spec, const char **type, int *flags,
1047            int *loop, const char **loopdev, const char **loopfile,
1048            const char *node) {
1049   int looptype;
1050   unsigned long long offset, sizelimit;
1051
1052   /*
1053    * In the case of a loop mount, either type is of the form lo@/dev/loop5
1054    * or the option "-o loop=/dev/loop5" or just "-o loop" is given, or
1055    * mount just has to figure things out for itself from the fact that
1056    * spec is not a block device. We do not test for a block device
1057    * immediately: maybe later other types of mountable objects will occur.
1058    */
1059
1060   *loopdev = opt_loopdev;
1061
1062   looptype = (*type && strncmp("lo@", *type, 3) == 0);
1063   if (looptype) {
1064     if (*loopdev)
1065       error(_("mount: loop device specified twice"));
1066     *loopdev = *type + 3;
1067     *type = opt_vfstype;
1068   } else if (opt_vfstype) {
1069     if (*type)
1070       error(_("mount: type specified twice"));
1071     else
1072       *type = opt_vfstype;
1073   }
1074
1075   *loop = ((*flags & MS_LOOP) || *loopdev || opt_offset || opt_sizelimit || opt_encryption);
1076   *loopfile = *spec;
1077
1078   if (*loop) {
1079     *flags |= MS_LOOP;
1080     if (fake) {
1081       if (verbose)
1082         printf(_("mount: skipping the setup of a loop device\n"));
1083     } else {
1084       int loop_opts = SETLOOP_AUTOCLEAR; /* always attempt autoclear */
1085       int res;
1086
1087       if (*flags & MS_RDONLY)
1088         loop_opts |= SETLOOP_RDONLY;
1089
1090       offset = opt_offset ? strtoull(opt_offset, NULL, 0) : 0;
1091       sizelimit = opt_sizelimit ? strtoull(opt_sizelimit, NULL, 0) : 0;
1092
1093       if (is_mounted_same_loopfile(node, *loopfile, offset)) {
1094         error(_("mount: according to mtab %s is already mounted on %s as loop"), *loopfile, node);
1095         return EX_FAIL;
1096       }
1097
1098       do {
1099         if (!*loopdev || !**loopdev)
1100           *loopdev = find_unused_loop_device();
1101         if (!*loopdev)
1102           return EX_SYSERR;     /* no more loop devices */
1103         if (verbose)
1104           printf(_("mount: going to use the loop device %s\n"), *loopdev);
1105
1106         if ((res = set_loop(*loopdev, *loopfile, offset, sizelimit,
1107                             opt_encryption, pfd, &loop_opts))) {
1108           if (res == 2) {
1109              /* loop dev has been grabbed by some other process,
1110                 try again, if not given explicitly */
1111              if (!opt_loopdev) {
1112                if (verbose)
1113                  printf(_("mount: stolen loop=%s ...trying again\n"), *loopdev);
1114                my_free(*loopdev);
1115                *loopdev = NULL;
1116                continue;
1117              }
1118              error(_("mount: stolen loop=%s"), *loopdev);
1119              return EX_FAIL;
1120
1121           } else {
1122              if (verbose)
1123                printf(_("mount: failed setting up loop device\n"));
1124              if (!opt_loopdev) {
1125                my_free(*loopdev);
1126                *loopdev = NULL;
1127              }
1128              return EX_FAIL;
1129           }
1130         }
1131       } while (!*loopdev);
1132
1133       if (verbose > 1)
1134         printf(_("mount: setup loop device successfully\n"));
1135       *spec = *loopdev;
1136
1137       if (loop_opts & SETLOOP_RDONLY)
1138         *flags |= MS_RDONLY;
1139
1140       if (loop_opts & SETLOOP_AUTOCLEAR)
1141         /* Prevent recording loop dev in mtab for cleanup on umount */
1142         *loop = 0;
1143     }
1144   }
1145
1146   return 0;
1147 }
1148
1149 static void
1150 update_mtab_entry(const char *spec, const char *node, const char *type,
1151                   const char *opts, int flags, int freq, int pass) {
1152         struct my_mntent mnt;
1153
1154         mnt.mnt_fsname = is_pseudo_fs(type) ? xstrdup(spec) : canonicalize(spec);
1155         mnt.mnt_dir = canonicalize (node);
1156         mnt.mnt_type = type;
1157         mnt.mnt_opts = opts;
1158         mnt.mnt_freq = freq;
1159         mnt.mnt_passno = pass;
1160
1161         /* We get chatty now rather than after the update to mtab since the
1162            mount succeeded, even if the write to /etc/mtab should fail.  */
1163         if (verbose)
1164                 print_one (&mnt);
1165
1166         if (!nomtab && mtab_does_not_exist()) {
1167                 if (verbose > 1)
1168                         printf(_("mount: no %s found - creating it..\n"),
1169                                _PATH_MOUNTED);
1170                 create_mtab ();
1171         }
1172
1173         if (!nomtab && mtab_is_writable()) {
1174                 if (flags & MS_REMOUNT)
1175                         update_mtab (mnt.mnt_dir, &mnt);
1176                 else if (flags & MS_MOVE)
1177                         update_mtab(mnt.mnt_fsname, &mnt);
1178                 else {
1179                         mntFILE *mfp;
1180
1181                         lock_mtab();
1182                         mfp = my_setmntent(_PATH_MOUNTED, "a+");
1183                         if (mfp == NULL || mfp->mntent_fp == NULL) {
1184                                 int errsv = errno;
1185                                 error(_("mount: can't open %s: %s"), _PATH_MOUNTED,
1186                                       strerror (errsv));
1187                         } else {
1188                                 if ((my_addmntent (mfp, &mnt)) == 1) {
1189                                         int errsv = errno;
1190                                         error(_("mount: error writing %s: %s"),
1191                                               _PATH_MOUNTED, strerror (errsv));
1192                                 }
1193                         }
1194                         my_endmntent(mfp);
1195                         unlock_mtab();
1196                 }
1197         }
1198         my_free(mnt.mnt_fsname);
1199         my_free(mnt.mnt_dir);
1200 }
1201
1202 static void
1203 set_pfd(char *s) {
1204         if (!isdigit(*s))
1205                 die(EX_USAGE,
1206                     _("mount: argument to -p or --pass-fd must be a number"));
1207         pfd = atoi(optarg);
1208 }
1209
1210 static void
1211 cdrom_setspeed(const char *spec) {
1212 #define CDROM_SELECT_SPEED      0x5322  /* Set the CD-ROM speed */
1213         if (opt_speed) {
1214                 int cdrom;
1215                 int speed = atoi(opt_speed);
1216
1217                 if ((cdrom = open(spec, O_RDONLY | O_NONBLOCK)) < 0)
1218                         die(EX_FAIL,
1219                             _("mount: cannot open %s for setting speed"),
1220                             spec);
1221                 if (ioctl(cdrom, CDROM_SELECT_SPEED, speed) < 0)
1222                         die(EX_FAIL, _("mount: cannot set speed: %s"),
1223                             strerror(errno));
1224                 close(cdrom);
1225         }
1226 }
1227
1228 /*
1229  * try_mount_one()
1230  *      Try to mount one file system.
1231  *
1232  * returns: 0: OK, EX_SYSERR, EX_FAIL, return code from nfsmount,
1233  *      return status from wait
1234  */
1235 static int
1236 try_mount_one (const char *spec0, const char *node0, const char *types0,
1237                const char *opts0, int freq, int pass, int ro) {
1238   int res = 0, status = 0, special = 0;
1239   int mnt5_res = 0;             /* only for gcc */
1240   int mnt_err;
1241   int flags;
1242   char *extra_opts;             /* written in mtab */
1243   char *mount_opts;             /* actually used on system call */
1244   const char *opts, *spec, *node, *types;
1245   char *user = 0;
1246   int loop = 0;
1247   const char *loopdev = 0, *loopfile = 0;
1248   struct stat statbuf;
1249   int retries = 0;      /* Nr of retries for mount in case of ENOMEDIUM */
1250
1251   /* copies for freeing on exit */
1252   const char *opts1, *spec1, *node1, *types1, *extra_opts1;
1253
1254   if (verbose > 2) {
1255           printf("mount: spec:  \"%s\"\n", spec0);
1256           printf("mount: node:  \"%s\"\n", node0);
1257           printf("mount: types: \"%s\"\n", types0);
1258           printf("mount: opts:  \"%s\"\n", opts0);
1259   }
1260
1261   spec = spec1 = xstrdup(spec0);
1262   node = node1 = xstrdup(node0);
1263   types = types1 = xstrdup(types0);
1264   opts = opts1 = xstrdup(opts0);
1265
1266   parse_opts (opts, &flags, &extra_opts);
1267   extra_opts1 = extra_opts;
1268
1269   /* quietly succeed for fstab entries that don't get mounted automatically */
1270   if (mount_all && (flags & MS_NOAUTO))
1271       goto out;
1272
1273   restricted_check(spec, node, &flags, &user);
1274
1275   /* The "mount -f" checks for for existing record in /etc/mtab (with
1276    * regular non-fake mount this is usually done by kernel)
1277    */
1278   if (!(flags & MS_REMOUNT) && fake && mounted (spec, node))
1279       die(EX_USAGE, _("mount: according to mtab, "
1280                       "%s is already mounted on %s\n"),
1281                       spec, node);
1282
1283   mount_opts = extra_opts;
1284
1285   if (opt_speed)
1286       cdrom_setspeed(spec);
1287
1288   if (!(flags & MS_REMOUNT)) {
1289       /*
1290        * Don't set up a (new) loop device if we only remount - this left
1291        * stale assignments of files to loop devices. Nasty when used for
1292        * encryption.
1293        */
1294       res = loop_check(&spec, &types, &flags, &loop, &loopdev, &loopfile, node);
1295       if (res)
1296           goto out;
1297   }
1298
1299   if (loop)
1300       opt_loopdev = loopdev;
1301
1302   if (flags & (MS_BIND | MS_MOVE | MS_PROPAGATION))
1303       types = "none";
1304
1305   /*
1306    * Call mount.TYPE for types that require a separate mount program.
1307    * For the moment these types are ncpfs and smbfs. Maybe also vxfs.
1308    * All such special things must occur isolated in the types string.
1309    */
1310   if (check_special_mountprog(spec, node, types, flags, extra_opts, &status)) {
1311       res = status;
1312       goto out;
1313   }
1314
1315 mount_retry:
1316   block_signals (SIG_BLOCK);
1317
1318   if (!fake) {
1319     mnt5_res = guess_fstype_and_mount (spec, node, &types, flags & ~MS_NOSYS,
1320                                        mount_opts, &special, &status);
1321
1322     if (special) {
1323       block_signals (SIG_UNBLOCK);
1324       res = status;
1325       goto out;
1326     }
1327   }
1328
1329   if (fake || mnt5_res == 0) {
1330       /* Mount succeeded, report this (if verbose) and write mtab entry.  */
1331
1332       if (!(mounttype & MS_PROPAGATION)) {
1333               update_mtab_entry(loop ? loopfile : spec,
1334                         node,
1335                         types ? types : "unknown",
1336                         fix_opts_string (flags & ~MS_NOMTAB, extra_opts, user),
1337                         flags,
1338                         freq,
1339                         pass);
1340       }
1341
1342       block_signals (SIG_UNBLOCK);
1343       res = 0;
1344       goto out;
1345   }
1346
1347   mnt_err = errno;
1348
1349   if (loop)
1350         del_loop(spec);
1351
1352   block_signals (SIG_UNBLOCK);
1353
1354   /* Mount failed, complain, but don't die.  */
1355
1356   if (types == 0) {
1357     if (restricted)
1358       error (_("mount: I could not determine the filesystem type, "
1359                "and none was specified"));
1360     else
1361       error (_("mount: you must specify the filesystem type"));
1362   } else if (mnt5_res != -1) {
1363       /* should not happen */
1364       error (_("mount: mount failed"));
1365   } else {
1366    switch (mnt_err) {
1367     case EPERM:
1368       if (geteuid() == 0) {
1369            if (stat (node, &statbuf) || !S_ISDIR(statbuf.st_mode))
1370                 error (_("mount: mount point %s is not a directory"), node);
1371            else
1372                 error (_("mount: permission denied"));
1373       } else
1374         error (_("mount: must be superuser to use mount"));
1375       break;
1376     case EBUSY:
1377       if (flags & MS_REMOUNT) {
1378         error (_("mount: %s is busy"), node);
1379       } else if (!strcmp(types, "proc") && !strcmp(node, "/proc")) {
1380         /* heuristic: if /proc/version exists, then probably proc is mounted */
1381         if (stat ("/proc/version", &statbuf))   /* proc mounted? */
1382            error (_("mount: %s is busy"), node);   /* no */
1383         else if (!mount_all || verbose)            /* yes, don't mention it */
1384            error (_("mount: proc already mounted"));
1385       } else {
1386         error (_("mount: %s already mounted or %s busy"), spec, node);
1387         already (spec, node);
1388       }
1389       break;
1390     case ENOENT:
1391       if (lstat (node, &statbuf))
1392            error (_("mount: mount point %s does not exist"), node);
1393       else if (stat (node, &statbuf))
1394            error (_("mount: mount point %s is a symbolic link to nowhere"),
1395                   node);
1396       else if (stat (spec, &statbuf)) {
1397            if (opt_nofail)
1398                 goto out;
1399            error (_("mount: special device %s does not exist"), spec);
1400       } else {
1401            errno = mnt_err;
1402            perror("mount");
1403       }
1404       break;
1405     case ENOTDIR:
1406       if (stat (node, &statbuf) || ! S_ISDIR(statbuf.st_mode))
1407            error (_("mount: mount point %s is not a directory"), node);
1408       else if (stat (spec, &statbuf) && errno == ENOTDIR) {
1409            if (opt_nofail)
1410               goto out;
1411            error (_("mount: special device %s does not exist\n"
1412                     "       (a path prefix is not a directory)\n"), spec);
1413       } else {
1414            errno = mnt_err;
1415            perror("mount");
1416       }
1417       break;
1418     case EINVAL:
1419     { int fd;
1420       unsigned long long size = 0;
1421
1422       if (flags & MS_REMOUNT) {
1423         error (_("mount: %s not mounted already, or bad option"), node);
1424       } else {
1425         error (_("mount: wrong fs type, bad option, bad superblock on %s,\n"
1426                "       missing codepage or helper program, or other error"),
1427                spec);
1428
1429         if (stat(spec, &statbuf) < 0) {
1430           if (errno == ENOENT)         /* network FS? */
1431             error(_(
1432                "       (for several filesystems (e.g. nfs, cifs) you might\n"
1433                "       need a /sbin/mount.<type> helper program)"));
1434
1435         } else if (S_ISBLK(statbuf.st_mode)
1436                          && (fd = open(spec, O_RDONLY | O_NONBLOCK)) >= 0) {
1437
1438           if (blkdev_get_size(fd, &size) == 0) {
1439             if (size == 0 && !loop)
1440               error(_(
1441                  "       (could this be the IDE device where you in fact use\n"
1442                  "       ide-scsi so that sr0 or sda or so is needed?)"));
1443
1444             if (size && size <= 2)
1445               error(_(
1446                   "       (aren't you trying to mount an extended partition,\n"
1447                   "       instead of some logical partition inside?)"));
1448
1449             close(fd);
1450           }
1451         }
1452         error(_(
1453                 "       In some cases useful info is found in syslog - try\n"
1454                 "       dmesg | tail  or so\n"));
1455       }
1456       break;
1457     }
1458     case EMFILE:
1459       error (_("mount table full")); break;
1460     case EIO:
1461       error (_("mount: %s: can't read superblock"), spec); break;
1462     case ENODEV:
1463     {
1464       int pfs = known_fstype_in_procfs(types);
1465
1466       if (pfs == 1 || !strcmp(types, "guess"))
1467         error(_("mount: %s: unknown device"), spec);
1468       else if (pfs == 0) {
1469         char *lowtype, *p;
1470         int u;
1471
1472         error (_("mount: unknown filesystem type '%s'"), types);
1473
1474         /* maybe this loser asked for FAT or ISO9660 or isofs */
1475         lowtype = xstrdup(types);
1476         u = 0;
1477         for(p=lowtype; *p; p++) {
1478           if(tolower(*p) != *p) {
1479             *p = tolower(*p);
1480             u++;
1481           }
1482         }
1483         if (u && known_fstype_in_procfs(lowtype) == 1)
1484           error (_("mount: probably you meant %s"), lowtype);
1485         else if (!strncmp(lowtype, "iso", 3) &&
1486                         known_fstype_in_procfs("iso9660") == 1)
1487           error (_("mount: maybe you meant 'iso9660'?"));
1488         else if (!strncmp(lowtype, "fat", 3) &&
1489                         known_fstype_in_procfs("vfat") == 1)
1490           error (_("mount: maybe you meant 'vfat'?"));
1491         free(lowtype);
1492       } else
1493         error (_("mount: %s has wrong device number or fs type %s not supported"),
1494                spec, types);
1495       break;
1496     }
1497     case ENOTBLK:
1498       if (opt_nofail)
1499         goto out;
1500       if (stat (spec, &statbuf)) /* strange ... */
1501         error (_("mount: %s is not a block device, and stat fails?"), spec);
1502       else if (S_ISBLK(statbuf.st_mode))
1503         error (_("mount: the kernel does not recognize %s as a block device\n"
1504                "       (maybe `insmod driver'?)"), spec);
1505       else if (S_ISREG(statbuf.st_mode))
1506         error (_("mount: %s is not a block device (maybe try `-o loop'?)"),
1507                  spec);
1508       else
1509         error (_("mount: %s is not a block device"), spec);
1510       break;
1511     case ENXIO:
1512       if (opt_nofail)
1513         goto out;
1514       error (_("mount: %s is not a valid block device"), spec); break;
1515     case EACCES:  /* pre-linux 1.1.38, 1.1.41 and later */
1516     case EROFS:   /* linux 1.1.38 and later */
1517     { char *bd = (loop ? "" : _("block device "));
1518       if (ro || (flags & MS_RDONLY)) {
1519           error (_("mount: cannot mount %s%s read-only"),
1520                  bd, spec);
1521           break;
1522       } else if (readwrite) {
1523           error (_("mount: %s%s is write-protected but explicit `-w' flag given"),
1524                  bd, spec);
1525           break;
1526       } else if (flags & MS_REMOUNT) {
1527           error (_("mount: cannot remount %s%s read-write, is write-protected"),
1528                  bd, spec);
1529           break;
1530       } else {
1531          opts = opts0;
1532          types = types0;
1533
1534          if (opts) {
1535              char *opts2 = append_opt(xstrdup(opts), "ro", NULL);
1536              my_free(opts1);
1537              opts = opts1 = opts2;
1538          } else
1539              opts = "ro";
1540          if (types && !strcmp(types, "guess"))
1541              types = 0;
1542          error (_("mount: %s%s is write-protected, mounting read-only"),
1543                 bd, spec0);
1544          res = try_mount_one (spec0, node0, types, opts, freq, pass, 1);
1545          goto out;
1546       }
1547       break;
1548     }
1549     case ENOMEDIUM:
1550       if (retries < CRDOM_NOMEDIUM_RETRIES) {
1551               if (verbose)
1552                       printf(_("mount: no medium found on %s ...trying again\n"),
1553                                  spec);
1554               sleep(3);
1555               ++retries;
1556               goto mount_retry;
1557       }
1558       error(_("mount: no medium found on %s"), spec);
1559       break;
1560     default:
1561       error ("mount: %s", strerror (mnt_err)); break;
1562     }
1563   }
1564   res = EX_FAIL;
1565
1566  out:
1567
1568 #if defined(HAVE_LIBSELINUX) && defined(HAVE_SECURITY_GET_INITIAL_CONTEXT)
1569   if (res != EX_FAIL && verbose && is_selinux_enabled() > 0) {
1570       security_context_t raw = NULL, def = NULL;
1571
1572       if (getfilecon(node, &raw) > 0 &&
1573                      security_get_initial_context("file", &def) == 0) {
1574
1575           if (!selinux_file_context_cmp(raw, def))
1576               printf(_("mount: %s does not contain SELinux labels.\n"
1577                    "       You just mounted an file system that supports labels which does not\n"
1578                    "       contain labels, onto an SELinux box. It is likely that confined\n"
1579                    "       applications will generate AVC messages and not be allowed access to\n"
1580                    "       this file system.  For more details see restorecon(8) and mount(8).\n"),
1581                    node);
1582       }
1583       freecon(raw);
1584       freecon(def);
1585   }
1586 #endif
1587
1588   my_free(extra_opts1);
1589   my_free(spec1);
1590   my_free(node1);
1591   my_free(opts1);
1592   my_free(types1);
1593
1594   return res;
1595 }
1596
1597 static char *
1598 subst_string(const char *s, const char *sub, int sublen, const char *repl) {
1599         char *n;
1600
1601         n = (char *) xmalloc(strlen(s)-sublen+strlen(repl)+1);
1602         strncpy (n, s, sub-s);
1603         strcpy (n + (sub-s), repl);
1604         strcat (n, sub+sublen);
1605         return n;
1606 }
1607
1608 static char *
1609 usersubst(const char *opts) {
1610         char *s, *w;
1611         char id[40];
1612
1613         if (!opts)
1614                 return NULL;
1615
1616         s = "uid=useruid";
1617         if (opts && (w = strstr(opts, s)) != NULL) {
1618                 sprintf(id, "uid=%d", getuid());
1619                 opts = subst_string(opts, w, strlen(s), id);
1620         }
1621         s = "gid=usergid";
1622         if (opts && (w = strstr(opts, s)) != NULL) {
1623                 sprintf(id, "gid=%d", getgid());
1624                 opts = subst_string(opts, w, strlen(s), id);
1625         }
1626         return xstrdup(opts);
1627 }
1628
1629 static int
1630 is_existing_file (const char *s) {
1631         struct stat statbuf;
1632
1633         return (stat(s, &statbuf) == 0);
1634 }
1635
1636 /*
1637  * Return 0 for success (either mounted sth or -a and NOAUTO was given)
1638  */
1639 static int
1640 mount_one (const char *spec, const char *node, const char *types,
1641            const char *fstabopts, char *cmdlineopts, int freq, int pass) {
1642         const char *nspec;
1643         char *opts;
1644
1645         /* Substitute values in opts, if required */
1646         opts = usersubst(fstabopts);
1647
1648         /* Merge the fstab and command line options.  */
1649         opts = append_opt(opts, cmdlineopts, NULL);
1650
1651         if (types == NULL && !mounttype && !is_existing_file(spec)) {
1652                 if (strchr (spec, ':') != NULL) {
1653                         types = "nfs";
1654                         if (verbose)
1655                                 printf(_("mount: no type was given - "
1656                                          "I'll assume nfs because of "
1657                                          "the colon\n"));
1658                 } else if(!strncmp(spec, "//", 2)) {
1659                         types = "cifs";
1660                         if (verbose)
1661                                 printf(_("mount: no type was given - "
1662                                          "I'll assume cifs because of "
1663                                          "the // prefix\n"));
1664                 }
1665         }
1666
1667         /* Handle possible LABEL= and UUID= forms of spec */
1668         if (types == NULL || (strncmp(types, "nfs", 3) &&
1669                               strncmp(types, "cifs", 4) &&
1670                               strncmp(types, "smbfs", 5))) {
1671                 nspec = spec_to_devname(spec);
1672                 if (nspec)
1673                         spec = nspec;
1674         }
1675
1676         return try_mount_one (spec, node, types, opts, freq, pass, 0);
1677 }
1678
1679 /* Check if an fsname/dir pair was already in the old mtab.  */
1680 static int
1681 mounted (const char *spec0, const char *node0) {
1682         struct mntentchn *mc, *mc0;
1683         const char *spec, *node;
1684         int ret = 0;
1685
1686         /* Handle possible UUID= and LABEL= in spec */
1687         spec = spec_to_devname(spec0);
1688         if (!spec)
1689                 return ret;
1690
1691         node = canonicalize(node0);
1692
1693         mc0 = mtab_head();
1694         for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt)
1695                 if (streq (spec, mc->m.mnt_fsname) &&
1696                     streq (node, mc->m.mnt_dir)) {
1697                         ret = 1;
1698                         break;
1699                 }
1700
1701         my_free(spec);
1702         my_free(node);
1703
1704         return ret;
1705 }
1706
1707 /* avoid using stat() on things we are not going to mount anyway.. */
1708 static int
1709 has_noauto (const char *opts) {
1710         char *s;
1711
1712         if (!opts)
1713                 return 0;
1714         s = strstr(opts, "noauto");
1715         if (!s)
1716                 return 0;
1717         return (s == opts || s[-1] == ',') && (s[6] == 0 || s[6] == ',');
1718 }
1719
1720 /* Mount all filesystems of the specified types except swap and root.  */
1721 /* With the --fork option: fork and let different incarnations of
1722    mount handle different filesystems.  However, try to avoid several
1723    simultaneous mounts on the same physical disk, since that is very slow. */
1724 #define DISKMAJOR(m)    (((int) m) & ~0xf)
1725
1726 static int
1727 do_mount_all (char *types, char *options, char *test_opts) {
1728         struct mntentchn *mc, *mc0, *mtmp;
1729         int status = 0;
1730         struct stat statbuf;
1731         struct child {
1732                 pid_t pid;
1733                 char *group;
1734                 struct mntentchn *mec;
1735                 struct mntentchn *meclast;
1736                 struct child *nxt;
1737         } childhead, *childtail, *cp;
1738         char major[22];
1739         char *g, *colon;
1740
1741         /* build a chain of what we have to do, or maybe
1742            several chains, one for each major or NFS host */
1743         childhead.nxt = 0;
1744         childtail = &childhead;
1745         mc0 = fstab_head();
1746         for (mc = mc0->nxt; mc && mc != mc0; mc = mc->nxt) {
1747                 if (has_noauto (mc->m.mnt_opts))
1748                         continue;
1749                 if (matching_type (mc->m.mnt_type, types)
1750                     && matching_opts (mc->m.mnt_opts, test_opts)
1751                     && !streq (mc->m.mnt_dir, "/")
1752                     && !streq (mc->m.mnt_dir, "root")) {
1753
1754                         if (mounted (mc->m.mnt_fsname, mc->m.mnt_dir)) {
1755                                 if (verbose)
1756                                         printf(_("mount: %s already mounted "
1757                                                  "on %s\n"),
1758                                                mc->m.mnt_fsname,
1759                                                mc->m.mnt_dir);
1760                                 continue;
1761                         }
1762
1763                         mtmp = (struct mntentchn *) xmalloc(sizeof(*mtmp));
1764                         *mtmp = *mc;
1765                         mtmp->nxt = 0;
1766                         g = NULL;
1767                         if (optfork) {
1768                                 if (stat(mc->m.mnt_fsname, &statbuf) == 0 &&
1769                                     S_ISBLK(statbuf.st_mode)) {
1770                                         sprintf(major, "#%x",
1771                                                 DISKMAJOR(statbuf.st_rdev));
1772                                         g = major;
1773                                 }
1774                                 if (strcmp(mc->m.mnt_type, "nfs") == 0) {
1775                                         g = xstrdup(mc->m.mnt_fsname);
1776                                         colon = strchr(g, ':');
1777                                         if (colon)
1778                                                 *colon = '\0';
1779                                 }
1780                         }
1781                         if (g) {
1782                                 for (cp = childhead.nxt; cp; cp = cp->nxt)
1783                                         if (cp->group &&
1784                                             strcmp(cp->group, g) == 0) {
1785                                                 cp->meclast->nxt = mtmp;
1786                                                 cp->meclast = mtmp;
1787                                                 goto fnd;
1788                                         }
1789                         }
1790                         cp = (struct child *) xmalloc(sizeof *cp);
1791                         cp->nxt = 0;
1792                         cp->mec = cp->meclast = mtmp;
1793                         cp->group = xstrdup(g);
1794                         cp->pid = 0;
1795                         childtail->nxt = cp;
1796                         childtail = cp;
1797                 fnd:;
1798
1799                 }
1800         }
1801                               
1802         /* now do everything */
1803         for (cp = childhead.nxt; cp; cp = cp->nxt) {
1804                 pid_t p = -1;
1805                 if (optfork) {
1806                         p = fork();
1807                         if (p == -1) {
1808                                 int errsv = errno;
1809                                 error(_("mount: cannot fork: %s"),
1810                                       strerror (errsv));
1811                         }
1812                         else if (p != 0)
1813                                 cp->pid = p;
1814                 }
1815
1816                 /* if child, or not forked, do the mounting */
1817                 if (p == 0 || p == -1) {
1818                         for (mc = cp->mec; mc; mc = mc->nxt) {
1819                                 status |= mount_one (mc->m.mnt_fsname,
1820                                                      mc->m.mnt_dir,
1821                                                      mc->m.mnt_type,
1822                                                      mc->m.mnt_opts,
1823                                                      options, 0, 0);
1824                         }
1825                         if (mountcount)
1826                                 status |= EX_SOMEOK;
1827                         if (p == 0)
1828                                 exit(status);
1829                 }
1830         }
1831
1832         /* wait for children, if any */
1833         while ((cp = childhead.nxt) != NULL) {
1834                 childhead.nxt = cp->nxt;
1835                 if (cp->pid) {
1836                         int ret;
1837                 keep_waiting:
1838                         if(waitpid(cp->pid, &ret, 0) == -1) {
1839                                 if (errno == EINTR)
1840                                         goto keep_waiting;
1841                                 perror("waitpid");
1842                         } else if (WIFEXITED(ret))
1843                                 status |= WEXITSTATUS(ret);
1844                         else
1845                                 status |= EX_SYSERR;
1846                 }
1847         }
1848         if (mountcount)
1849                 status |= EX_SOMEOK;
1850         return status;
1851 }
1852
1853 static struct option longopts[] = {
1854         { "all", 0, 0, 'a' },
1855         { "fake", 0, 0, 'f' },
1856         { "fork", 0, 0, 'F' },
1857         { "help", 0, 0, 'h' },
1858         { "no-mtab", 0, 0, 'n' },
1859         { "read-only", 0, 0, 'r' },
1860         { "ro", 0, 0, 'r' },
1861         { "verbose", 0, 0, 'v' },
1862         { "version", 0, 0, 'V' },
1863         { "read-write", 0, 0, 'w' },
1864         { "rw", 0, 0, 'w' },
1865         { "options", 1, 0, 'o' },
1866         { "test-opts", 1, 0, 'O' },
1867         { "pass-fd", 1, 0, 'p' },
1868         { "types", 1, 0, 't' },
1869         { "bind", 0, 0, 'B' },
1870         { "move", 0, 0, 'M' },
1871         { "guess-fstype", 1, 0, 134 },
1872         { "rbind", 0, 0, 'R' },
1873         { "make-shared", 0, 0, 136 },
1874         { "make-slave", 0, 0, 137 },
1875         { "make-private", 0, 0, 138 },
1876         { "make-unbindable", 0, 0, 139 },
1877         { "make-rshared", 0, 0, 140 },
1878         { "make-rslave", 0, 0, 141 },
1879         { "make-rprivate", 0, 0, 142 },
1880         { "make-runbindable", 0, 0, 143 },
1881         { "internal-only", 0, 0, 'i' },
1882         { NULL, 0, 0, 0 }
1883 };
1884
1885 /* Keep the usage message at max 22 lines, each at most 70 chars long.
1886    The user should not need a pager to read it. */
1887 static void
1888 usage (FILE *fp, int n) {
1889         fprintf(fp, _(
1890           "Usage: mount -V                 : print version\n"
1891           "       mount -h                 : print this help\n"
1892           "       mount                    : list mounted filesystems\n"
1893           "       mount -l                 : idem, including volume labels\n"
1894           "So far the informational part. Next the mounting.\n"
1895           "The command is `mount [-t fstype] something somewhere'.\n"
1896           "Details found in /etc/fstab may be omitted.\n"
1897           "       mount -a [-t|-O] ...     : mount all stuff from /etc/fstab\n"
1898           "       mount device             : mount device at the known place\n"
1899           "       mount directory          : mount known device here\n"
1900           "       mount -t type dev dir    : ordinary mount command\n"
1901           "Note that one does not really mount a device, one mounts\n"
1902           "a filesystem (of the given type) found on the device.\n"
1903           "One can also mount an already visible directory tree elsewhere:\n"
1904           "       mount --bind olddir newdir\n"
1905           "or move a subtree:\n"
1906           "       mount --move olddir newdir\n"
1907           "One can change the type of mount containing the directory dir:\n"
1908           "       mount --make-shared dir\n"
1909           "       mount --make-slave dir\n"
1910           "       mount --make-private dir\n"
1911           "       mount --make-unbindable dir\n"
1912           "One can change the type of all the mounts in a mount subtree\n"
1913           "containing the directory dir:\n"
1914           "       mount --make-rshared dir\n"
1915           "       mount --make-rslave dir\n"
1916           "       mount --make-rprivate dir\n"
1917           "       mount --make-runbindable dir\n"
1918           "A device can be given by name, say /dev/hda1 or /dev/cdrom,\n"
1919           "or by label, using  -L label  or by uuid, using  -U uuid .\n"
1920           "Other options: [-nfFrsvw] [-o options] [-p passwdfd].\n"
1921           "For many more details, say  man 8 mount .\n"
1922         ));
1923
1924         unlock_mtab();
1925         exit (n);
1926 }
1927
1928 /* returns mount entry from fstab */
1929 static struct mntentchn *
1930 getfs(const char *spec, const char *uuid, const char *label)
1931 {
1932         struct mntentchn *mc = NULL;
1933         const char *devname = NULL;
1934
1935         if (!spec && !uuid && !label)
1936                 return NULL;
1937
1938         /*
1939          * A) 99% of all cases, the spec on cmdline matches
1940          *    with spec in fstab
1941          */
1942         if (uuid)
1943                 mc = getfs_by_uuid(uuid);
1944         else if (label)
1945                 mc = getfs_by_label(label);
1946         else {
1947                 mc = getfs_by_spec(spec);
1948
1949                 if (!mc)
1950                         mc = getfs_by_dir(spec);
1951         }
1952         if (mc)
1953                 return mc;
1954
1955         /*
1956          * B) UUID or LABEL on cmdline, but devname in fstab
1957          */
1958         if (uuid)
1959                 devname = fsprobe_get_devname_by_uuid(uuid);
1960         else if (label)
1961                 devname = fsprobe_get_devname_by_label(label);
1962         else
1963                 devname = spec_to_devname(spec);
1964
1965         if (devname)
1966                 mc = getfs_by_devname(devname);
1967
1968         /*
1969          * C) mixed
1970          */
1971         if (!mc && devname) {
1972                 const char *id = NULL;
1973
1974                 if (!label && (!spec || strncmp(spec, "LABEL=", 6))) {
1975                         id = fsprobe_get_label_by_devname(devname);
1976                         if (id)
1977                                 mc = getfs_by_label(id);
1978                 }
1979                 if (!mc && !uuid && (!spec || strncmp(spec, "UUID=", 5))) {
1980                         id = fsprobe_get_uuid_by_devname(devname);
1981                         if (id)
1982                                 mc = getfs_by_uuid(id);
1983                 }
1984                 my_free(id);
1985
1986                 if (mc) {
1987                         /* use real device name to avoid repetitional
1988                          * conversion from LABEL/UUID to devname
1989                          */
1990                         my_free(mc->m.mnt_fsname);
1991                         mc->m.mnt_fsname = xstrdup(devname);
1992                 }
1993         }
1994
1995         /*
1996          * D) remount -- try /etc/mtab
1997          *    Earlier mtab was tried first, but this would sometimes try the
1998          *    wrong mount in case mtab had the root device entry wrong.
1999          */
2000         if (!mc && (devname || spec))
2001                 mc = getmntfile (devname ? devname : spec);
2002
2003         my_free(devname);
2004         return mc;
2005 }
2006
2007
2008 static void
2009 print_version(int rc) {
2010         printf( "mount from %s (with "
2011 #ifdef HAVE_LIBBLKID
2012                 "libblkid"
2013 #else
2014                 "libvolume_id"
2015 #endif
2016 #ifdef HAVE_LIBSELINUX
2017                 " and selinux"
2018 #endif
2019                 " support)\n", PACKAGE_STRING);
2020         exit(rc);
2021 }
2022
2023 int
2024 main(int argc, char *argv[]) {
2025         int c, result = 0, specseen;
2026         char *options = NULL, *test_opts = NULL, *node;
2027         const char *spec = NULL;
2028         char *label = NULL;
2029         char *uuid = NULL;
2030         char *types = NULL;
2031         char *p;
2032         struct mntentchn *mc;
2033         int fd;
2034
2035         sanitize_env();
2036         setlocale(LC_ALL, "");
2037         bindtextdomain(PACKAGE, LOCALEDIR);
2038         textdomain(PACKAGE);
2039
2040         progname = argv[0];
2041         if ((p = strrchr(progname, '/')) != NULL)
2042                 progname = p+1;
2043
2044         umask(022);
2045
2046         /* People report that a mount called from init without console
2047            writes error messages to /etc/mtab
2048            Let us try to avoid getting fd's 0,1,2 */
2049         while((fd = open("/dev/null", O_RDWR)) == 0 || fd == 1 || fd == 2) ;
2050         if (fd > 2)
2051                 close(fd);
2052
2053         fsprobe_init();
2054
2055 #ifdef DO_PS_FIDDLING
2056         initproctitle(argc, argv);
2057 #endif
2058
2059         while ((c = getopt_long (argc, argv, "aBfFhilL:Mno:O:p:rRsU:vVwt:",
2060                                  longopts, NULL)) != -1) {
2061                 switch (c) {
2062                 case 'a':              /* mount everything in fstab */
2063                         ++mount_all;
2064                         break;
2065                 case 'B': /* bind */
2066                         mounttype = MS_BIND;
2067                         break;
2068                 case 'f':              /* fake: don't actually call mount(2) */
2069                         ++fake;
2070                         break;
2071                 case 'F':
2072                         ++optfork;
2073                         break;
2074                 case 'h':               /* help */
2075                         usage (stdout, 0);
2076                         break;
2077                 case 'i':
2078                         external_allowed = 0;
2079                         break;
2080                 case 'l':
2081                         list_with_volumelabel = 1;
2082                         break;
2083                 case 'L':
2084                         label = optarg;
2085                         break;
2086                 case 'M': /* move */
2087                         mounttype = MS_MOVE;
2088                         break;
2089                 case 'n':               /* do not write /etc/mtab */
2090                         ++nomtab;
2091                         break;
2092                 case 'o':               /* specify mount options */
2093                         options = append_opt(options, optarg, NULL);
2094                         break;
2095                 case 'O':               /* with -t: mount only if (not) opt */
2096                         test_opts = append_opt(test_opts, optarg, NULL);
2097                         break;
2098                 case 'p':               /* fd on which to read passwd */
2099                         set_pfd(optarg);
2100                         break;
2101                 case 'r':               /* mount readonly */
2102                         readonly = 1;
2103                         readwrite = 0;
2104                         break;
2105                 case 'R': /* rbind */
2106                         mounttype = (MS_BIND | MS_REC);
2107                         break;
2108                 case 's':               /* allow sloppy mount options */
2109                         sloppy = 1;
2110                         break;
2111                 case 't':               /* specify file system types */
2112                         types = optarg;
2113                         break;
2114                 case 'U':
2115                         uuid = optarg;
2116                         break;
2117                 case 'v':               /* be chatty - more so if repeated */
2118                         ++verbose;
2119                         break;
2120                 case 'V':               /* version */
2121                         print_version(EXIT_SUCCESS);
2122                         break;
2123                 case 'w':               /* mount read/write */
2124                         readwrite = 1;
2125                         readonly = 0;
2126                         break;
2127                 case 0:
2128                         break;
2129
2130                 case 134:
2131                         /* undocumented, may go away again:
2132                            call: mount --guess-fstype device
2133                            use only for testing purposes -
2134                            the guessing is not reliable at all */
2135                     {
2136                         const char *fstype;
2137                         fstype = fsprobe_get_fstype_by_devname(optarg);
2138                         printf("%s\n", fstype ? fstype : "unknown");
2139                         exit(fstype ? 0 : EX_FAIL);
2140                     }
2141
2142                 case 136:
2143                         mounttype = MS_SHARED;
2144                         break;
2145
2146                 case 137:
2147                         mounttype = MS_SLAVE;
2148                         break;
2149
2150                 case 138:
2151                         mounttype = MS_PRIVATE;
2152                         break;
2153
2154                 case 139:
2155                         mounttype = MS_UNBINDABLE;
2156                         break;
2157
2158                 case 140:
2159                         mounttype = (MS_SHARED | MS_REC);
2160                         break;
2161
2162                 case 141:
2163                         mounttype = (MS_SLAVE | MS_REC);
2164                         break;
2165
2166                 case 142:
2167                         mounttype = (MS_PRIVATE | MS_REC);
2168                         break;
2169
2170                 case 143:
2171                         mounttype = (MS_UNBINDABLE | MS_REC);
2172                         break;
2173
2174                 case '?':
2175                 default:
2176                         usage (stderr, EX_USAGE);
2177                 }
2178         }
2179
2180         if (verbose > 2) {
2181                 printf("mount: fstab path: \"%s\"\n", _PATH_MNTTAB);
2182                 printf("mount: mtab path:  \"%s\"\n", _PATH_MOUNTED);
2183                 printf("mount: lock path:  \"%s\"\n", _PATH_MOUNTED_LOCK);
2184                 printf("mount: temp path:  \"%s\"\n", _PATH_MOUNTED_TMP);
2185                 printf("mount: UID:        %d\n", getuid());
2186                 printf("mount: eUID:       %d\n", geteuid());
2187         }
2188
2189         argc -= optind;
2190         argv += optind;
2191
2192         specseen = (uuid || label) ? 1 : 0;     /* yes, .. i know */
2193
2194         if (argc+specseen == 0 && !mount_all) {
2195                 if (options || mounttype)
2196                         usage (stderr, EX_USAGE);
2197                 return print_all (types);
2198         }
2199
2200         {
2201                 const uid_t ruid = getuid();
2202                 const uid_t euid = geteuid();
2203
2204                 /* if we're really root and aren't running setuid */
2205                 if (((uid_t)0 == ruid) && (ruid == euid)) {
2206                         restricted = 0;
2207                 }
2208         }
2209
2210         if (restricted &&
2211             (types || options || readwrite || nomtab || mount_all ||
2212              fake || mounttype || (argc + specseen) != 1)) {
2213                 die (EX_USAGE, _("mount: only root can do that"));
2214         }
2215
2216         atexit(unlock_mtab);
2217
2218         switch (argc+specseen) {
2219         case 0:
2220                 /* mount -a */
2221                 result = do_mount_all (types, options, test_opts);
2222                 if (result == 0 && verbose && !fake)
2223                         error(_("nothing was mounted"));
2224                 break;
2225
2226         case 1:
2227                 /* mount [-nfrvw] [-o options] special | node
2228                  * mount -L label  (or -U uuid)
2229                  * (/etc/fstab is necessary)
2230                  */
2231                 if (types != NULL)
2232                         usage (stderr, EX_USAGE);
2233
2234                 if (uuid || label)
2235                         mc = getfs(NULL, uuid, label);
2236                 else
2237                         mc = getfs(*argv, NULL, NULL);
2238
2239                 if (!mc) {
2240                         if (uuid || label)
2241                                 die (EX_USAGE, _("mount: no such partition found"));
2242
2243                         die (EX_USAGE,
2244                              _("mount: can't find %s in %s or %s"),
2245                              *argv, _PATH_MNTTAB, _PATH_MOUNTED);
2246                 }
2247
2248                 result = mount_one (xstrdup (mc->m.mnt_fsname),
2249                                     xstrdup (mc->m.mnt_dir),
2250                                     xstrdup (mc->m.mnt_type),
2251                                     mc->m.mnt_opts, options, 0, 0);
2252                 break;
2253
2254         case 2:
2255                 /* mount special node  (/etc/fstab is not necessary) */
2256                 if (specseen) {
2257                         /* mount -L label node   (or -U uuid) */
2258                         spec = uuid ?   fsprobe_get_devname_by_uuid(uuid) :
2259                                         fsprobe_get_devname_by_label(label);
2260                         node = argv[0];
2261                 } else {
2262                         /* mount special node */
2263                         spec = argv[0];
2264                         node = argv[1];
2265                 }
2266                 if (!spec)
2267                         die (EX_USAGE, _("mount: no such partition found"));
2268
2269                 result = mount_one (spec, node, types, NULL, options, 0, 0);
2270                 break;
2271
2272         default:
2273                 usage (stderr, EX_USAGE);
2274         }
2275
2276         if (result == EX_SOMEOK)
2277                 result = 0;
2278
2279         fsprobe_exit();
2280
2281         exit (result);
2282 }