~ubuntu-branches/ubuntu/precise/util-linux/precise-proposed

« back to all changes in this revision

Viewing changes to mount/mount.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Langasek
  • Date: 2011-06-20 22:31:50 UTC
  • mfrom: (1.6.3 upstream) (4.5.1 sid)
  • Revision ID: james.westby@ubuntu.com-20110620223150-lz8wrv0946ihcz3z
Tags: 2.19.1-2ubuntu1
* Merge from Debian unstable, remaining changes:
  - Build for multiarch.
  - Add pre-depends on multiarch-support.
  - configure.ac: don't try to be clever about extracting a path name from
    $libdir to append to /usr in a way that's not overridable; instead,
    reuse the built-in configurable libexecdir.
  - Fix up the .pc.in files to know about libexecdir, so our substitutions
    don't leave us with unusable pkg-config files.
  - Install custom blkid.conf to use /dev/.blkid.tab since we don't
    expect device names to survive a reboot
  - Mention mountall(8) in fstab(5) manpages, along with its special
    options.
  - Since upstart is required in Ubuntu, the hwclock.sh init script is not
    called on startup and the hwclockfirst.sh init script is removed.
  - Drop depends on initscripts for the above.
  - Replace hwclock udev rule with an Upstart job.
  - For the case where mount is called with a directory to mount, look
    that directory up in mountall's /lib/init/fstab if we couldn't find
    it mentioned anywhere else.  This means "mount /proc", "mount /sys",
    etc. work.
  - mount.8 points to the cifs-utils package, not the obsolete smbfs one. 
* Dropped changes:
  - mount.preinst: lsb_release has been fixed in lucid and above to be
    usable without configuration, so we don't have to diverge from Debian
    here anymore.
* Changes merged upstream:
  - sfdisk support for '+' with '-N'
  - mount/umount.c: fix a segfault on umount with empty mtab entry
  - Fix arbitrary unmount with fuse security issue

Show diffs side-by-side

added added

removed removed

Lines of Context:
41
41
#include "env.h"
42
42
#include "nls.h"
43
43
#include "blkdev.h"
 
44
#include "strutils.h"
44
45
 
45
46
#define DO_PS_FIDDLING
46
47
 
92
93
/* Contains the fd to read the passphrase from, if any. */
93
94
static int pfd = -1;
94
95
 
 
96
#ifdef HAVE_LIBMOUNT_MOUNT
 
97
static struct libmnt_update *mtab_update;
 
98
static char *mtab_opts;
 
99
static unsigned long mtab_flags;
 
100
 
 
101
static void prepare_mtab_entry(const char *spec, const char *node,
 
102
                        const char *type, const char *opts, unsigned long flags);
 
103
#endif
 
104
 
95
105
/* Contains the preferred keysize in bits we want to use */
96
106
static int keysz = 0;
97
107
 
264
274
/* Report on a single mount.  */
265
275
static void
266
276
print_one (const struct my_mntent *me) {
 
277
 
 
278
        char *fsname = NULL;
 
279
 
267
280
        if (mount_quiet)
268
281
                return;
269
 
        printf ("%s on %s", me->mnt_fsname, me->mnt_dir);
 
282
 
 
283
        /* users assume backing file name rather than /dev/loopN in
 
284
         * mount(8) output if the device has been initialized by mount(8).
 
285
         */
 
286
        if (strncmp(me->mnt_fsname, "/dev/loop", 9) == 0 &&
 
287
            is_loop_autoclear(me->mnt_fsname))
 
288
                fsname = loopdev_get_loopfile(me->mnt_fsname);
 
289
 
 
290
        if (!fsname)
 
291
                fsname = (char *) me->mnt_fsname;
 
292
 
 
293
        printf ("%s on %s", fsname, me->mnt_dir);
270
294
        if (me->mnt_type != NULL && *(me->mnt_type) != '\0')
271
295
                printf (" type %s", me->mnt_type);
272
296
        if (me->mnt_opts != NULL)
329
353
}
330
354
 
331
355
static char *
332
 
append_numopt(char *s, const char *opt, long num)
 
356
append_numopt(char *s, const char *opt, unsigned int num)
333
357
{
334
358
        char buf[32];
335
359
 
336
 
        snprintf(buf, sizeof(buf), "%ld", num);
 
360
        snprintf(buf, sizeof(buf), "%u", num);
337
361
        return append_opt(s, opt, buf);
338
362
}
339
363
 
393
417
        freecon(raw);
394
418
        return 0;
395
419
}
 
420
 
 
421
/* returns newly allocated string without *context= options */
 
422
static char *remove_context_options(char *opts)
 
423
{
 
424
        char *begin = NULL, *end = NULL, *p;
 
425
        int open_quote = 0, changed = 0;
 
426
 
 
427
        if (!opts)
 
428
                return NULL;
 
429
 
 
430
        opts = xstrdup(opts);
 
431
 
 
432
        for (p = opts; p && *p; p++) {
 
433
                if (!begin)
 
434
                        begin = p;              /* begin of the option item */
 
435
                if (*p == '"')
 
436
                        open_quote ^= 1;        /* reverse the status */
 
437
                if (open_quote)
 
438
                        continue;               /* still in quoted block */
 
439
                if (*p == ',')
 
440
                        end = p;                /* terminate the option item */
 
441
                else if (*(p + 1) == '\0')
 
442
                        end = p + 1;            /* end of optstr */
 
443
                if (!begin || !end)
 
444
                        continue;
 
445
 
 
446
                if (strncmp(begin, "context=", 8) == 0 ||
 
447
                    strncmp(begin, "fscontext=", 10) == 0 ||
 
448
                    strncmp(begin, "defcontext=", 11) == 0 ||
 
449
                    strncmp(begin, "rootcontext=", 12) == 0) {
 
450
                        size_t sz;
 
451
 
 
452
                        if ((begin == opts || *(begin - 1) == ',') && *end == ',')
 
453
                                end++;
 
454
                        sz = strlen(end);
 
455
 
 
456
                        memmove(begin, end, sz + 1);
 
457
                        if (!*begin && *(begin - 1) == ',')
 
458
                                *(begin - 1) = '\0';
 
459
 
 
460
                        p = begin;
 
461
                        changed = 1;
 
462
                }
 
463
        }
 
464
 
 
465
        if (changed && verbose)
 
466
                printf (_("mount: SELinux *context= options are ignore on remount.\n"));
 
467
 
 
468
        return opts;
 
469
}
 
470
 
 
471
static int has_context_option(char *opts)
 
472
{
 
473
        if (get_option("context=", opts, NULL) ||
 
474
            get_option("fscontext=", opts, NULL) ||
 
475
            get_option("defcontext=", opts, NULL) ||
 
476
            get_option("rootcontext=", opts, NULL))
 
477
                return 1;
 
478
 
 
479
        return 0;
 
480
}
 
481
 
396
482
#endif
397
483
 
398
484
/*
506
592
        if (readwrite)
507
593
                *flags &= ~MS_RDONLY;
508
594
 
509
 
        if (mounttype & MS_PROPAGATION)
510
 
                *flags &= ~MS_BIND;
511
595
        *flags |= mounttype;
 
596
 
 
597
        /* The propagation flags should not be used together with any other flags */
 
598
        if (*flags & MS_PROPAGATION)
 
599
                *flags &= MS_PROPAGATION;
512
600
}
513
601
 
514
602
/* Try to build a canonical options string.  */
648
736
                                    args->flags, args->data, status)) {
649
737
                *special = 1;
650
738
                ret = 0;
651
 
        } else
 
739
        } else {
 
740
#ifdef HAVE_LIBMOUNT_MOUNT
 
741
                prepare_mtab_entry(args->spec, args->node, args->type,
 
742
                                mtab_opts, mtab_flags);
 
743
#endif
652
744
                ret = do_mount_syscall(args);
653
 
 
 
745
        }
654
746
        if (ret == 0)
655
747
                mountcount++;
656
748
        return ret;
664
756
static int
665
757
check_special_mountprog(const char *spec, const char *node, const char *type, int flags,
666
758
                        char *extra_opts, int *status) {
667
 
  char mountprog[120];
668
 
  struct stat statbuf;
669
 
  int res;
670
 
 
671
 
  if (!external_allowed)
672
 
      return 0;
673
 
 
674
 
  if (type == NULL || strcmp(type, "none") == 0)
675
 
          return 0;
676
 
 
677
 
  if (strlen(type) < 100) {
678
 
       sprintf(mountprog, "/sbin/mount.%s", type);
679
 
       if (stat(mountprog, &statbuf) == 0) {
680
 
            if (verbose)
681
 
                 fflush(stdout);
682
 
            res = fork();
683
 
            if (res == 0) {
684
 
                 char *oo, *mountargs[10];
685
 
                 int i = 0;
686
 
 
687
 
                 if(setgid(getgid()) < 0)
688
 
                         die(EX_FAIL, _("mount: cannot set group id: %s"), strerror(errno));
689
 
 
690
 
                 if(setuid(getuid()) < 0)
691
 
                         die(EX_FAIL, _("mount: cannot set user id: %s"), strerror(errno));
692
 
 
693
 
                 oo = fix_opts_string (flags, extra_opts, NULL);
694
 
                 mountargs[i++] = mountprog;                            /* 1 */
695
 
                 mountargs[i++] = (char *) spec;                        /* 2 */
696
 
                 mountargs[i++] = (char *) node;                        /* 3 */
697
 
                 if (sloppy && strncmp(type, "nfs", 3) == 0)
698
 
                      mountargs[i++] = "-s";                            /* 4 */
699
 
                 if (fake)
700
 
                      mountargs[i++] = "-f";                            /* 5 */
701
 
                 if (nomtab)
702
 
                      mountargs[i++] = "-n";                            /* 6 */
703
 
                 if (verbose)
704
 
                      mountargs[i++] = "-v";                            /* 7 */
705
 
                 if (oo && *oo) {
706
 
                      mountargs[i++] = "-o";                            /* 8 */
707
 
                      mountargs[i++] = oo;                              /* 9 */
708
 
                 }
709
 
                 mountargs[i] = NULL;                                   /* 10 */
710
 
 
711
 
                 if (verbose > 2) {
712
 
                        i = 0;
713
 
                        while(mountargs[i]) {
714
 
                                printf("mount: external mount: argv[%d] = \"%s\"\n",
715
 
                                        i, mountargs[i]);
716
 
                                i++;
717
 
                        }
 
759
        char search_path[] = FS_SEARCH_PATH;
 
760
        char *path, mountprog[150];
 
761
        struct stat statbuf;
 
762
        int res;
 
763
 
 
764
        if (!external_allowed)
 
765
                return 0;
 
766
 
 
767
        if (type == NULL || strcmp(type, "none") == 0)
 
768
                return 0;
 
769
 
 
770
        path = strtok(search_path, ":");
 
771
        while (path) {
 
772
                int type_opt = 0;
 
773
 
 
774
                res = snprintf(mountprog, sizeof(mountprog), "%s/mount.%s",
 
775
                               path, type);
 
776
                path = strtok(NULL, ":");
 
777
                if (res >= sizeof(mountprog) || res < 0)
 
778
                        continue;
 
779
 
 
780
                res = stat(mountprog, &statbuf);
 
781
                if (res == -1 && errno == ENOENT && strchr(type, '.')) {
 
782
                        /* If type ends with ".subtype" try without it */
 
783
                        *strrchr(mountprog, '.') = '\0';
 
784
                        type_opt = 1;
 
785
                        res = stat(mountprog, &statbuf);
 
786
                }
 
787
                if (res)
 
788
                        continue;
 
789
 
 
790
                if (verbose)
718
791
                        fflush(stdout);
719
 
                 }
720
 
 
721
 
                 execv(mountprog, mountargs);
722
 
                 exit(1);       /* exec failed */
723
 
            } else if (res != -1) {
724
 
                 int st;
725
 
                 wait(&st);
726
 
                 *status = (WIFEXITED(st) ? WEXITSTATUS(st) : EX_SYSERR);
727
 
                 return 1;
728
 
            } else {
729
 
                 int errsv = errno;
730
 
                 error(_("mount: cannot fork: %s"), strerror(errsv));
731
 
            }
732
 
       }
733
 
  }
734
 
  return 0;
 
792
 
 
793
                switch (fork()) {
 
794
                case 0: { /* child */
 
795
                        char *oo, *mountargs[12];
 
796
                        int i = 0;
 
797
 
 
798
                        if (setgid(getgid()) < 0)
 
799
                                die(EX_FAIL, _("mount: cannot set group id: %s"), strerror(errno));
 
800
 
 
801
                        if (setuid(getuid()) < 0)
 
802
                                die(EX_FAIL, _("mount: cannot set user id: %s"), strerror(errno));
 
803
 
 
804
                        oo = fix_opts_string (flags, extra_opts, NULL);
 
805
                        mountargs[i++] = mountprog;                     /* 1 */
 
806
                        mountargs[i++] = (char *) spec;                 /* 2 */
 
807
                        mountargs[i++] = (char *) node;                 /* 3 */
 
808
                        if (sloppy && strncmp(type, "nfs", 3) == 0)
 
809
                                mountargs[i++] = "-s";                  /* 4 */
 
810
                        if (fake)
 
811
                                mountargs[i++] = "-f";                  /* 5 */
 
812
                        if (nomtab)
 
813
                                mountargs[i++] = "-n";                  /* 6 */
 
814
                        if (verbose)
 
815
                                mountargs[i++] = "-v";                  /* 7 */
 
816
                        if (oo && *oo) {
 
817
                                mountargs[i++] = "-o";                  /* 8 */
 
818
                                mountargs[i++] = oo;                    /* 9 */
 
819
                        }
 
820
                        if (type_opt) {
 
821
                                mountargs[i++] = "-t";                  /* 10 */
 
822
                                mountargs[i++] = (char *) type;         /* 11 */
 
823
                        }
 
824
                        mountargs[i] = NULL;                            /* 12 */
 
825
 
 
826
                        if (verbose > 2) {
 
827
                                i = 0;
 
828
                                while (mountargs[i]) {
 
829
                                        printf("mount: external mount: argv[%d] = \"%s\"\n",
 
830
                                                i, mountargs[i]);
 
831
                                        i++;
 
832
                                }
 
833
                                fflush(stdout);
 
834
                        }
 
835
 
 
836
                        execv(mountprog, mountargs);
 
837
                        exit(1);        /* exec failed */
 
838
                }
 
839
 
 
840
                default: { /* parent */
 
841
                        int st;
 
842
                        wait(&st);
 
843
                        *status = (WIFEXITED(st) ? WEXITSTATUS(st) : EX_SYSERR);
 
844
                        return 1;
 
845
                }
 
846
 
 
847
                case -1: { /* error */
 
848
                        int errsv = errno;
 
849
                        error(_("mount: cannot fork: %s"), strerror(errsv));
 
850
                }
 
851
                }
 
852
        }
 
853
 
 
854
        return 0;
735
855
}
736
856
 
737
857
 
745
865
was_tested(const char *fstype) {
746
866
        struct tried *t;
747
867
 
748
 
        if (fsprobe_known_fstype(fstype))
749
 
                return 1;
750
868
        for (t = tried; t; t = t->next) {
751
869
                if (!strcmp(t->type, fstype))
752
870
                        return 1;
887
1005
}
888
1006
 
889
1007
static const char *
890
 
guess_fstype_by_devname(const char *devname)
 
1008
guess_fstype_by_devname(const char *devname, int *ambivalent)
891
1009
{
892
 
   const char *type = fsprobe_get_fstype_by_devname(devname);
 
1010
   const char *type = fsprobe_get_fstype_by_devname_ambi(devname, ambivalent);
893
1011
 
894
1012
   if (verbose) {
895
1013
      printf (_("mount: you didn't specify a filesystem type for %s\n"), devname);
916
1034
guess_fstype_and_mount(const char *spec, const char *node, const char **types,
917
1035
                       int flags, char *mount_opts, int *special, int *status) {
918
1036
   struct mountargs args = { spec, node, NULL, flags & ~MS_NOSYS, mount_opts };
 
1037
   int ambivalent = 0;
919
1038
 
920
1039
   if (*types && strcasecmp (*types, "auto") == 0)
921
1040
      *types = NULL;
922
1041
 
923
1042
   if (!*types && !(flags & MS_REMOUNT)) {
924
 
      *types = guess_fstype_by_devname(spec);
 
1043
      *types = guess_fstype_by_devname(spec, &ambivalent);
925
1044
      if (*types) {
926
1045
          if (!strcmp(*types, MNTTYPE_SWAP)) {
927
1046
              error(_("%s looks like swapspace - not mounted"), spec);
931
1050
              args.type = *types;
932
1051
              return do_mount (&args, special, status);
933
1052
          }
 
1053
      } else if (ambivalent) {
 
1054
          error(_("mount: %s: more filesystems detected. This should not happen,\n"
 
1055
                  "       use -t <type> to explicitly specify the filesystem type or\n"
 
1056
                  "       use wipefs(8) to clean up the device.\n"), spec);
 
1057
          return 1;
934
1058
      }
935
1059
   }
936
1060
 
1068
1192
}
1069
1193
 
1070
1194
static int
 
1195
parse_offset(const char **opt, uintmax_t *val)
 
1196
{
 
1197
        char *tmp;
 
1198
 
 
1199
        if (strtosize(*opt, val))
 
1200
                return -1;
 
1201
 
 
1202
        tmp = xmalloc(32);
 
1203
        snprintf(tmp, 32, "%jd", *val);
 
1204
        my_free(*opt);
 
1205
        *opt = tmp;
 
1206
        return 0;
 
1207
}
 
1208
 
 
1209
static int
1071
1210
loop_check(const char **spec, const char **type, int *flags,
1072
1211
           int *loop, const char **loopdev, const char **loopfile,
1073
1212
           const char *node) {
1074
1213
  int looptype;
1075
 
  unsigned long long offset, sizelimit;
 
1214
  uintmax_t offset = 0, sizelimit = 0;
1076
1215
 
1077
1216
  /*
1078
1217
   * In the case of a loop mount, either type is of the form lo@/dev/loop5
1100
1239
  *loop = ((*flags & MS_LOOP) || *loopdev || opt_offset || opt_sizelimit || opt_encryption || opt_keybits);
1101
1240
  *loopfile = *spec;
1102
1241
 
 
1242
  /* Automatically create a loop device from a regular file if a filesystem
 
1243
   * is not specified or the filesystem is known for libblkid (these
 
1244
   * filesystems work with block devices only).
 
1245
   *
 
1246
   * Note that there is not a restriction (on kernel side) that prevents regular
 
1247
   * file as a mount(2) source argument. A filesystem that is able to mount
 
1248
   * regular files could be implemented.
 
1249
   */
 
1250
  if (!*loop && !(*flags & (MS_BIND | MS_MOVE | MS_PROPAGATION)) &&
 
1251
      (!*type || strcmp(*type, "auto") == 0 || fsprobe_known_fstype(*type))) {
 
1252
 
 
1253
    struct stat st;
 
1254
    if (stat(*loopfile, &st) == 0)
 
1255
      *loop = S_ISREG(st.st_mode);
 
1256
  }
 
1257
 
1103
1258
  if (*loop) {
1104
1259
    *flags |= MS_LOOP;
1105
1260
    if (fake) {
1106
1261
      if (verbose)
1107
1262
        printf(_("mount: skipping the setup of a loop device\n"));
1108
1263
    } else {
1109
 
      int loop_opts = SETLOOP_AUTOCLEAR; /* always attempt autoclear */
 
1264
      int loop_opts = 0;
1110
1265
      int res;
1111
1266
 
 
1267
      /* since 2.6.37 we don't have to store backing filename to mtab
 
1268
       * because kernel provides the name in /sys
 
1269
       */
 
1270
      if (get_linux_version() >= KERNEL_VERSION(2, 6, 37) ||
 
1271
          mtab_is_writable() == 0) {
 
1272
 
 
1273
        if (verbose)
 
1274
          printf(_("mount: enabling autoclear loopdev flag\n"));
 
1275
        loop_opts = SETLOOP_AUTOCLEAR;
 
1276
      }
 
1277
 
1112
1278
      if (*flags & MS_RDONLY)
1113
1279
        loop_opts |= SETLOOP_RDONLY;
1114
1280
 
1115
 
      offset = opt_offset ? strtoull(opt_offset, NULL, 0) : 0;
1116
 
      sizelimit = opt_sizelimit ? strtoull(opt_sizelimit, NULL, 0) : 0;
 
1281
      if (opt_offset && parse_offset(&opt_offset, &offset)) {
 
1282
        error(_("mount: invalid offset '%s' specified"), opt_offset);
 
1283
        return EX_FAIL;
 
1284
      }
 
1285
      if (opt_sizelimit && parse_offset(&opt_sizelimit, &sizelimit)) {
 
1286
        error(_("mount: invalid sizelimit '%s' specified"), opt_sizelimit);
 
1287
        return EX_FAIL;
 
1288
      }
1117
1289
 
1118
1290
      if (is_mounted_same_loopfile(node, *loopfile, offset)) {
1119
1291
        error(_("mount: according to mtab %s is already mounted on %s as loop"), *loopfile, node);
1174
1346
  return 0;
1175
1347
}
1176
1348
 
 
1349
 
 
1350
#ifdef HAVE_LIBMOUNT_MOUNT
 
1351
static void
 
1352
verbose_mount_info(const char *spec, const char *node, const char *type,
 
1353
                  const char *opts, int flags)
 
1354
{
 
1355
        struct my_mntent mnt;
 
1356
 
 
1357
        mnt.mnt_fsname = is_pseudo_fs(type) ? spec : canonicalize(spec);
 
1358
        mnt.mnt_dir = canonicalize (node);
 
1359
        mnt.mnt_type = type;
 
1360
        mnt.mnt_opts = opts;
 
1361
 
 
1362
        print_one (&mnt);
 
1363
 
 
1364
        if (spec != mnt.mnt_fsname)
 
1365
                my_free(mnt.mnt_fsname);
 
1366
        my_free(mnt.mnt_dir);
 
1367
}
 
1368
 
 
1369
static void
 
1370
prepare_mtab_entry(const char *spec, const char *node, const char *type,
 
1371
                                          const char *opts, unsigned long flags)
 
1372
{
 
1373
        struct libmnt_fs *fs = mnt_new_fs();
 
1374
        int rc = -1;
 
1375
 
 
1376
        if (!mtab_update)
 
1377
                mtab_update = mnt_new_update();
 
1378
 
 
1379
        if (mtab_update && fs) {
 
1380
                const char *cn_spec = is_pseudo_fs(type) ? spec : canonicalize(spec);
 
1381
                const char *cn_node = canonicalize(node);
 
1382
 
 
1383
                mnt_fs_set_source(fs, cn_spec);
 
1384
                mnt_fs_set_target(fs, cn_node);
 
1385
                mnt_fs_set_fstype(fs, type);
 
1386
                mnt_fs_set_options(fs, opts);
 
1387
 
 
1388
                rc = mnt_update_set_fs(mtab_update, flags, NULL, fs);
 
1389
 
 
1390
                if (spec != cn_spec)
 
1391
                        my_free(cn_spec);
 
1392
                my_free(cn_node);
 
1393
        }
 
1394
 
 
1395
        mnt_free_fs(fs);
 
1396
 
 
1397
        if (rc) {
 
1398
                mnt_free_update(mtab_update);
 
1399
                mtab_update = NULL;
 
1400
        }
 
1401
}
 
1402
 
 
1403
static void update_mtab_entry(int flags)
 
1404
{
 
1405
        unsigned long fl;
 
1406
 
 
1407
        if (!mtab_update)
 
1408
                return;
 
1409
 
 
1410
        fl = mnt_update_get_mflags(mtab_update);
 
1411
 
 
1412
        if ((flags & MS_RDONLY) != (fl & MS_RDONLY))
 
1413
                mnt_update_force_rdonly(mtab_update, flags & MS_RDONLY);
 
1414
 
 
1415
        if (!nomtab) {
 
1416
                if (mtab_does_not_exist()) {
 
1417
                        if (verbose > 1)
 
1418
                                printf(_("mount: no %s found - creating it..\n"),
 
1419
                                       _PATH_MOUNTED);
 
1420
                        create_mtab ();
 
1421
                }
 
1422
 
 
1423
                mnt_update_table(mtab_update, NULL);
 
1424
        }
 
1425
 
 
1426
        mnt_free_update(mtab_update);
 
1427
        mtab_update = NULL;
 
1428
}
 
1429
 
 
1430
#else /*!HAVE_LIBMOUNT_MOUNT */
1177
1431
static void
1178
1432
update_mtab_entry(const char *spec, const char *node, const char *type,
1179
1433
                  const char *opts, int flags, int freq, int pass) {
1196
1450
                        printf(_("mount: no %s found - creating it..\n"),
1197
1451
                               _PATH_MOUNTED);
1198
1452
                create_mtab ();
 
1453
 
1199
1454
        }
1200
1455
 
1201
1456
        if (!nomtab && mtab_is_writable()) {
1203
1458
                        update_mtab (mnt.mnt_dir, &mnt);
1204
1459
                else if (flags & MS_MOVE)
1205
1460
                        update_mtab(mnt.mnt_fsname, &mnt);
1206
 
                else {
1207
 
                        mntFILE *mfp;
1208
 
 
1209
 
                        lock_mtab();
1210
 
                        mfp = my_setmntent(_PATH_MOUNTED, "a+");
1211
 
                        if (mfp == NULL || mfp->mntent_fp == NULL) {
1212
 
                                int errsv = errno;
1213
 
                                error(_("mount: can't open %s: %s"), _PATH_MOUNTED,
1214
 
                                      strerror (errsv));
1215
 
                        } else {
1216
 
                                if ((my_addmntent (mfp, &mnt)) == 1) {
1217
 
                                        int errsv = errno;
1218
 
                                        error(_("mount: error writing %s: %s"),
1219
 
                                              _PATH_MOUNTED, strerror (errsv));
1220
 
                                }
1221
 
                        }
1222
 
                        my_endmntent(mfp);
1223
 
                        unlock_mtab();
1224
 
                }
 
1461
                else
 
1462
                        update_mtab(NULL, &mnt);
1225
1463
        }
1226
1464
        my_free(mnt.mnt_fsname);
1227
1465
        my_free(mnt.mnt_dir);
1228
1466
}
 
1467
#endif /* !HAVE_LIBMOUNT_MOUNT */
1229
1468
 
1230
1469
static void
1231
1470
set_pfd(char *s) {
1254
1493
}
1255
1494
 
1256
1495
/*
1257
 
 * Check if @node is read-only filesystem by access() or futimens().
1258
 
 *
1259
 
 * Note that access(2) uses real-UID (= useless for suid programs)
1260
 
 * and euidaccess(2) does not check for read-only FS.
 
1496
 * Check if @path is on read-only filesystem independently on file permissions.
1261
1497
 */
1262
1498
static int
1263
 
is_readonly(const char *node)
 
1499
is_readonly(const char *path)
1264
1500
{
1265
 
        int res = 0;
 
1501
        if (access(path, W_OK) == 0)
 
1502
                return 0;
 
1503
        if (errno == EROFS)
 
1504
                return 1;
 
1505
        if (errno != EACCES)
 
1506
                return 0;
1266
1507
 
1267
 
        if (getuid() == geteuid()) {
1268
 
                if (access(node, W_OK) == -1 && errno == EROFS)
1269
 
                        res = 1;
1270
 
        }
1271
1508
#ifdef HAVE_FUTIMENS
1272
 
        else {
 
1509
        /*
 
1510
         * access(2) returns EACCES on read-only FS:
 
1511
         *
 
1512
         * - for set-uid application if one component of the path is not
 
1513
         *   accessible for the current rUID. (Note that euidaccess(2) does not
 
1514
         *   check for EROFS at all).
 
1515
         *
 
1516
         * - for read-write filesystem with read-only VFS node (aka -o remount,ro,bind)
 
1517
         */
 
1518
        {
1273
1519
                struct timespec times[2];
1274
 
                int fd = open(node, O_RDONLY);
1275
 
 
1276
 
                if (fd < 0)
1277
 
                        goto done;
1278
1520
 
1279
1521
                times[0].tv_nsec = UTIME_NOW;   /* atime */
1280
1522
                times[1].tv_nsec = UTIME_OMIT;  /* mtime */
1281
1523
 
1282
 
                if (futimens(fd, times) == -1 && errno == EROFS)
1283
 
                        res = 1;
1284
 
                close(fd);
 
1524
                if (utimensat(AT_FDCWD, path, times, 0) == -1)
 
1525
                        return errno == EROFS;
1285
1526
        }
1286
 
done:
1287
1527
#endif
1288
 
        return res;
 
1528
        return 0;
1289
1529
}
1290
1530
 
1291
1531
/*
1309
1549
  int loop = 0;
1310
1550
  const char *loopdev = 0, *loopfile = 0;
1311
1551
  struct stat statbuf;
1312
 
  int retries = 0;      /* Nr of retries for mount in case of ENOMEDIUM */
1313
1552
 
1314
1553
  /* copies for freeing on exit */
1315
1554
  const char *opts1, *spec1, *node1, *types1, *extra_opts1;
1328
1567
 
1329
1568
  parse_opts (opts, &flags, &extra_opts);
1330
1569
  extra_opts1 = extra_opts;
 
1570
  mount_opts = extra_opts;
1331
1571
 
1332
1572
  /* quietly succeed for fstab entries that don't get mounted automatically */
1333
1573
  if (mount_all && (flags & MS_NOAUTO))
1343
1583
                      "%s is already mounted on %s\n"),
1344
1584
                      spec, node);
1345
1585
 
1346
 
  mount_opts = extra_opts;
1347
 
 
1348
1586
  if (opt_speed)
1349
1587
      cdrom_setspeed(spec);
1350
1588
 
1365
1603
  if (flags & (MS_BIND | MS_MOVE | MS_PROPAGATION))
1366
1604
      types = "none";
1367
1605
 
 
1606
#ifdef HAVE_LIBSELINUX
 
1607
  if (flags & MS_REMOUNT) {
 
1608
      /*
 
1609
       * Linux kernel does not accept any selinux context option on remount
 
1610
       */
 
1611
      if (mount_opts)
 
1612
          mount_opts = remove_context_options(mount_opts);
 
1613
 
 
1614
  } else if (types && strcmp(types, "tmpfs") == 0 && is_selinux_enabled() > 0 &&
 
1615
           !has_context_option(mount_opts)) {
 
1616
      /*
 
1617
       * Add rootcontext= mount option for tmpfs
 
1618
       * https://bugzilla.redhat.com/show_bug.cgi?id=476964
 
1619
       */
 
1620
      security_context_t sc = NULL;
 
1621
 
 
1622
      if (getfilecon(node, &sc) > 0 && strcmp("unlabeled", sc))
 
1623
              append_context("rootcontext=", (char *) sc, &mount_opts);
 
1624
      freecon(sc);
 
1625
  }
 
1626
#endif
 
1627
 
1368
1628
  /*
1369
1629
   * Call mount.TYPE for types that require a separate mount program.
1370
1630
   * For the moment these types are ncpfs and smbfs. Maybe also vxfs.
1371
1631
   * All such special things must occur isolated in the types string.
1372
1632
   */
1373
 
  if (check_special_mountprog(spec, node, types, flags, extra_opts, &status)) {
 
1633
  if (check_special_mountprog(spec, node, types, flags, mount_opts, &status)) {
1374
1634
      res = status;
1375
1635
      goto out;
1376
1636
  }
1377
1637
 
1378
 
mount_retry:
 
1638
#ifdef HAVE_LIBMOUNT_MOUNT
 
1639
  mtab_opts = fix_opts_string(flags & ~MS_NOMTAB, extra_opts, user);
 
1640
  mtab_flags = flags;
 
1641
 
 
1642
  if (fake)
 
1643
    prepare_mtab_entry(spec, node, types, mtab_opts, mtab_flags);
 
1644
#endif
 
1645
 
1379
1646
  block_signals (SIG_BLOCK);
1380
1647
 
1381
1648
  if (!fake) {
1390
1657
  }
1391
1658
 
1392
1659
  /* Kernel allows to use MS_RDONLY for bind mounts, but the read-only request
1393
 
   * could be silently ignored. Check it to avoid 'ro' in ntab and 'rw' in
 
1660
   * could be silently ignored. Check it to avoid 'ro' in mtab and 'rw' in
1394
1661
   * /proc/mounts.
1395
1662
   */
1396
1663
  if (!fake && mnt5_res == 0 &&
1400
1667
      flags &= ~MS_RDONLY;
1401
1668
  }
1402
1669
 
 
1670
  /* Kernel can silently add MS_RDONLY flag when mounting file system that
 
1671
   * does not have write support. Check this to avoid 'ro' in /proc/mounts
 
1672
   * and 'rw' in mtab.
 
1673
   */
 
1674
  if (!fake && mnt5_res == 0 &&
 
1675
      !(flags & (MS_RDONLY | MS_PROPAGATION | MS_MOVE)) &&
 
1676
      is_readonly(node)) {
 
1677
 
 
1678
      printf(_("mount: warning: %s seems to be mounted read-only.\n"), node);
 
1679
      flags |= MS_RDONLY;
 
1680
  }
 
1681
 
1403
1682
  if (fake || mnt5_res == 0) {
 
1683
      char *mo = fix_opts_string (flags & ~MS_NOMTAB, extra_opts, user);
 
1684
      const char *tp = types ? types : "unknown";
 
1685
 
1404
1686
      /* Mount succeeded, report this (if verbose) and write mtab entry.  */
1405
 
 
1406
 
      if (!(mounttype & MS_PROPAGATION)) {
 
1687
#ifdef HAVE_LIBMOUNT_MOUNT
 
1688
      update_mtab_entry(flags);
 
1689
      if (verbose)
 
1690
              verbose_mount_info(loop ? loopfile : spec, node, tp, mo, flags);
 
1691
#else
 
1692
      if (!(mounttype & MS_PROPAGATION))
1407
1693
              update_mtab_entry(loop ? loopfile : spec,
1408
1694
                        node,
1409
 
                        types ? types : "unknown",
1410
 
                        fix_opts_string (flags & ~MS_NOMTAB, extra_opts, user),
 
1695
                        tp,
 
1696
                        mo,
1411
1697
                        flags,
1412
1698
                        freq,
1413
1699
                        pass);
1414
 
      }
 
1700
#endif
 
1701
      block_signals (SIG_UNBLOCK);
 
1702
      free(mo);
1415
1703
 
1416
 
      block_signals (SIG_UNBLOCK);
1417
1704
      res = 0;
1418
1705
      goto out;
1419
1706
  }
1621
1908
      break;
1622
1909
    }
1623
1910
    case ENOMEDIUM:
1624
 
      if (retries < CRDOM_NOMEDIUM_RETRIES) {
1625
 
              if (verbose)
1626
 
                      printf(_("mount: no medium found on %s ...trying again\n"),
1627
 
                                 spec);
1628
 
              sleep(3);
1629
 
              ++retries;
1630
 
              goto mount_retry;
1631
 
      }
1632
1911
      error(_("mount: no medium found on %s"), spec);
1633
1912
      break;
1634
1913
    default:
1659
1938
  }
1660
1939
#endif
1661
1940
 
 
1941
  if (extra_opts1 != mount_opts)
 
1942
          my_free(mount_opts);
1662
1943
  my_free(extra_opts1);
1663
1944
  my_free(spec1);
1664
1945
  my_free(node1);
1689
1970
 
1690
1971
        s = "uid=useruid";
1691
1972
        if (opts && (w = strstr(opts, s)) != NULL) {
1692
 
                sprintf(id, "uid=%d", getuid());
 
1973
                sprintf(id, "uid=%u", getuid());
1693
1974
                opts = subst_string(opts, w, strlen(s), id);
1694
1975
        }
1695
1976
        s = "gid=usergid";
1696
1977
        if (opts && (w = strstr(opts, s)) != NULL) {
1697
 
                sprintf(id, "gid=%d", getgid());
 
1978
                sprintf(id, "gid=%u", getgid());
1698
1979
                opts = subst_string(opts, w, strlen(s), id);
1699
1980
        }
1700
1981
        return xstrdup(opts);
1739
2020
        }
1740
2021
 
1741
2022
        /* Handle possible LABEL= and UUID= forms of spec */
1742
 
        if (types == NULL || (strncmp(types, "nfs", 3) &&
 
2023
        if (types == NULL || (strncmp(types, "9p", 2) &&
 
2024
                              strncmp(types, "nfs", 3) &&
1743
2025
                              strncmp(types, "cifs", 4) &&
1744
2026
                              strncmp(types, "smbfs", 5))) {
1745
2027
                nspec = spec_to_devname(spec);
1778
2060
        return ret;
1779
2061
}
1780
2062
 
 
2063
/* returns 0 if not mounted, 1 if mounted and -1 in case of error */
 
2064
static int
 
2065
is_fstab_entry_mounted(struct mntentchn *mc, int verbose)
 
2066
{
 
2067
        struct stat st;
 
2068
 
 
2069
        if (mounted(mc->m.mnt_fsname, mc->m.mnt_dir))
 
2070
                goto yes;
 
2071
 
 
2072
        /* extra care for loop devices */
 
2073
        if ((strstr(mc->m.mnt_opts, "loop=") ||
 
2074
             (stat(mc->m.mnt_fsname, &st) == 0 && S_ISREG(st.st_mode)))) {
 
2075
 
 
2076
                char *p = get_option_value(mc->m.mnt_opts, "offset=");
 
2077
                uintmax_t offset = 0;
 
2078
 
 
2079
                if (p && strtosize(p, &offset) != 0) {
 
2080
                        if (verbose)
 
2081
                                printf(_("mount: ignore %s "
 
2082
                                        "(unparsable offset= option)\n"),
 
2083
                                        mc->m.mnt_fsname);
 
2084
                        return -1;
 
2085
                }
 
2086
                free(p);
 
2087
                if (is_mounted_same_loopfile(mc->m.mnt_dir, mc->m.mnt_fsname, offset))
 
2088
                        goto yes;
 
2089
        }
 
2090
 
 
2091
        return 0;
 
2092
yes:
 
2093
        if (verbose)
 
2094
                printf(_("mount: %s already mounted on %s\n"),
 
2095
                               mc->m.mnt_fsname, mc->m.mnt_dir);
 
2096
        return 1;
 
2097
}
 
2098
 
1781
2099
/* avoid using stat() on things we are not going to mount anyway.. */
1782
2100
static int
1783
2101
has_noauto (const char *opts) {
1823
2141
                if (matching_type (mc->m.mnt_type, types)
1824
2142
                    && matching_opts (mc->m.mnt_opts, test_opts)
1825
2143
                    && !streq (mc->m.mnt_dir, "/")
1826
 
                    && !streq (mc->m.mnt_dir, "root")) {
1827
 
 
1828
 
                        if (mounted (mc->m.mnt_fsname, mc->m.mnt_dir)) {
1829
 
                                if (verbose)
1830
 
                                        printf(_("mount: %s already mounted "
1831
 
                                                 "on %s\n"),
1832
 
                                               mc->m.mnt_fsname,
1833
 
                                               mc->m.mnt_dir);
1834
 
                                continue;
1835
 
                        }
 
2144
                    && !streq (mc->m.mnt_dir, "root")
 
2145
                    && !is_fstab_entry_mounted(mc, verbose)) {
1836
2146
 
1837
2147
                        mtmp = (struct mntentchn *) xmalloc(sizeof(*mtmp));
1838
2148
                        *mtmp = *mc;
2071
2381
        /*
2072
2382
         * D) remount -- try /etc/mtab
2073
2383
         *    Earlier mtab was tried first, but this would sometimes try the
2074
 
         *    wrong mount in case mtab had the root device entry wrong.
 
2384
         *    wrong mount in case mtab had the root device entry wrong.  Try
 
2385
         *    the last occurrence first, since that is the visible mount.
2075
2386
         */
2076
2387
        if (!mc && (devname || spec))
2077
 
                mc = getmntfile (devname ? devname : spec);
 
2388
                mc = getmntfilebackward (devname ? devname : spec, NULL);
2078
2389
 
2079
2390
        /*
2080
2391
         * E) try /lib/init/fstab
2085
2396
        if (!mc && spec)
2086
2397
                mc = getmountalldir (spec);
2087
2398
 
2088
 
 
2089
2399
        my_free(devname);
2090
2400
        return mc;
2091
2401
}
2274
2584
                printf("mount: mtab path:  \"%s\"\n", _PATH_MOUNTED);
2275
2585
                printf("mount: lock path:  \"%s\"\n", _PATH_MOUNTED_LOCK);
2276
2586
                printf("mount: temp path:  \"%s\"\n", _PATH_MOUNTED_TMP);
2277
 
                printf("mount: UID:        %d\n", getuid());
2278
 
                printf("mount: eUID:       %d\n", geteuid());
 
2587
                printf("mount: UID:        %u\n", getuid());
 
2588
                printf("mount: eUID:       %u\n", geteuid());
2279
2589
        }
2280
2590
 
 
2591
#ifdef HAVE_LIBMOUNT_MOUNT
 
2592
        mnt_init_debug(0);
 
2593
#endif
2281
2594
        argc -= optind;
2282
2595
        argv += optind;
2283
2596
 
2306
2619
                        if (ruid == 0 && euid != 0)
2307
2620
                                /* user is root, but setuid to non-root */
2308
2621
                                die (EX_USAGE, _("mount: only root can do that "
2309
 
                                        "(effective UID is %d)"), euid);
 
2622
                                        "(effective UID is %u)"), euid);
2310
2623
 
2311
2624
                        die (EX_USAGE, _("mount: only root can do that"));
2312
2625
                }