264
274
/* Report on a single mount. */
266
276
print_one (const struct my_mntent *me) {
269
printf ("%s on %s", me->mnt_fsname, me->mnt_dir);
283
/* users assume backing file name rather than /dev/loopN in
284
* mount(8) output if the device has been initialized by mount(8).
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);
291
fsname = (char *) me->mnt_fsname;
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)
421
/* returns newly allocated string without *context= options */
422
static char *remove_context_options(char *opts)
424
char *begin = NULL, *end = NULL, *p;
425
int open_quote = 0, changed = 0;
430
opts = xstrdup(opts);
432
for (p = opts; p && *p; p++) {
434
begin = p; /* begin of the option item */
436
open_quote ^= 1; /* reverse the status */
438
continue; /* still in quoted block */
440
end = p; /* terminate the option item */
441
else if (*(p + 1) == '\0')
442
end = p + 1; /* end of optstr */
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) {
452
if ((begin == opts || *(begin - 1) == ',') && *end == ',')
456
memmove(begin, end, sz + 1);
457
if (!*begin && *(begin - 1) == ',')
465
if (changed && verbose)
466
printf (_("mount: SELinux *context= options are ignore on remount.\n"));
471
static int has_context_option(char *opts)
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))
665
757
check_special_mountprog(const char *spec, const char *node, const char *type, int flags,
666
758
char *extra_opts, int *status) {
671
if (!external_allowed)
674
if (type == NULL || strcmp(type, "none") == 0)
677
if (strlen(type) < 100) {
678
sprintf(mountprog, "/sbin/mount.%s", type);
679
if (stat(mountprog, &statbuf) == 0) {
684
char *oo, *mountargs[10];
687
if(setgid(getgid()) < 0)
688
die(EX_FAIL, _("mount: cannot set group id: %s"), strerror(errno));
690
if(setuid(getuid()) < 0)
691
die(EX_FAIL, _("mount: cannot set user id: %s"), strerror(errno));
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 */
700
mountargs[i++] = "-f"; /* 5 */
702
mountargs[i++] = "-n"; /* 6 */
704
mountargs[i++] = "-v"; /* 7 */
706
mountargs[i++] = "-o"; /* 8 */
707
mountargs[i++] = oo; /* 9 */
709
mountargs[i] = NULL; /* 10 */
713
while(mountargs[i]) {
714
printf("mount: external mount: argv[%d] = \"%s\"\n",
759
char search_path[] = FS_SEARCH_PATH;
760
char *path, mountprog[150];
764
if (!external_allowed)
767
if (type == NULL || strcmp(type, "none") == 0)
770
path = strtok(search_path, ":");
774
res = snprintf(mountprog, sizeof(mountprog), "%s/mount.%s",
776
path = strtok(NULL, ":");
777
if (res >= sizeof(mountprog) || res < 0)
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';
785
res = stat(mountprog, &statbuf);
721
execv(mountprog, mountargs);
722
exit(1); /* exec failed */
723
} else if (res != -1) {
726
*status = (WIFEXITED(st) ? WEXITSTATUS(st) : EX_SYSERR);
730
error(_("mount: cannot fork: %s"), strerror(errsv));
794
case 0: { /* child */
795
char *oo, *mountargs[12];
798
if (setgid(getgid()) < 0)
799
die(EX_FAIL, _("mount: cannot set group id: %s"), strerror(errno));
801
if (setuid(getuid()) < 0)
802
die(EX_FAIL, _("mount: cannot set user id: %s"), strerror(errno));
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 */
811
mountargs[i++] = "-f"; /* 5 */
813
mountargs[i++] = "-n"; /* 6 */
815
mountargs[i++] = "-v"; /* 7 */
817
mountargs[i++] = "-o"; /* 8 */
818
mountargs[i++] = oo; /* 9 */
821
mountargs[i++] = "-t"; /* 10 */
822
mountargs[i++] = (char *) type; /* 11 */
824
mountargs[i] = NULL; /* 12 */
828
while (mountargs[i]) {
829
printf("mount: external mount: argv[%d] = \"%s\"\n",
836
execv(mountprog, mountargs);
837
exit(1); /* exec failed */
840
default: { /* parent */
843
*status = (WIFEXITED(st) ? WEXITSTATUS(st) : EX_SYSERR);
847
case -1: { /* error */
849
error(_("mount: cannot fork: %s"), strerror(errsv));
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 };
920
1039
if (*types && strcasecmp (*types, "auto") == 0)
923
1042
if (!*types && !(flags & MS_REMOUNT)) {
924
*types = guess_fstype_by_devname(spec);
1043
*types = guess_fstype_by_devname(spec, &ambivalent);
926
1045
if (!strcmp(*types, MNTTYPE_SWAP)) {
927
1046
error(_("%s looks like swapspace - not mounted"), spec);
1195
parse_offset(const char **opt, uintmax_t *val)
1199
if (strtosize(*opt, val))
1203
snprintf(tmp, 32, "%jd", *val);
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) {
1075
unsigned long long offset, sizelimit;
1214
uintmax_t offset = 0, sizelimit = 0;
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;
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).
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.
1250
if (!*loop && !(*flags & (MS_BIND | MS_MOVE | MS_PROPAGATION)) &&
1251
(!*type || strcmp(*type, "auto") == 0 || fsprobe_known_fstype(*type))) {
1254
if (stat(*loopfile, &st) == 0)
1255
*loop = S_ISREG(st.st_mode);
1104
1259
*flags |= MS_LOOP;
1107
1262
printf(_("mount: skipping the setup of a loop device\n"));
1109
int loop_opts = SETLOOP_AUTOCLEAR; /* always attempt autoclear */
1267
/* since 2.6.37 we don't have to store backing filename to mtab
1268
* because kernel provides the name in /sys
1270
if (get_linux_version() >= KERNEL_VERSION(2, 6, 37) ||
1271
mtab_is_writable() == 0) {
1274
printf(_("mount: enabling autoclear loopdev flag\n"));
1275
loop_opts = SETLOOP_AUTOCLEAR;
1112
1278
if (*flags & MS_RDONLY)
1113
1279
loop_opts |= SETLOOP_RDONLY;
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);
1285
if (opt_sizelimit && parse_offset(&opt_sizelimit, &sizelimit)) {
1286
error(_("mount: invalid sizelimit '%s' specified"), opt_sizelimit);
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);
1350
#ifdef HAVE_LIBMOUNT_MOUNT
1352
verbose_mount_info(const char *spec, const char *node, const char *type,
1353
const char *opts, int flags)
1355
struct my_mntent mnt;
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;
1364
if (spec != mnt.mnt_fsname)
1365
my_free(mnt.mnt_fsname);
1366
my_free(mnt.mnt_dir);
1370
prepare_mtab_entry(const char *spec, const char *node, const char *type,
1371
const char *opts, unsigned long flags)
1373
struct libmnt_fs *fs = mnt_new_fs();
1377
mtab_update = mnt_new_update();
1379
if (mtab_update && fs) {
1380
const char *cn_spec = is_pseudo_fs(type) ? spec : canonicalize(spec);
1381
const char *cn_node = canonicalize(node);
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);
1388
rc = mnt_update_set_fs(mtab_update, flags, NULL, fs);
1390
if (spec != cn_spec)
1398
mnt_free_update(mtab_update);
1403
static void update_mtab_entry(int flags)
1410
fl = mnt_update_get_mflags(mtab_update);
1412
if ((flags & MS_RDONLY) != (fl & MS_RDONLY))
1413
mnt_update_force_rdonly(mtab_update, flags & MS_RDONLY);
1416
if (mtab_does_not_exist()) {
1418
printf(_("mount: no %s found - creating it..\n"),
1423
mnt_update_table(mtab_update, NULL);
1426
mnt_free_update(mtab_update);
1430
#else /*!HAVE_LIBMOUNT_MOUNT */
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) {
1203
1458
update_mtab (mnt.mnt_dir, &mnt);
1204
1459
else if (flags & MS_MOVE)
1205
1460
update_mtab(mnt.mnt_fsname, &mnt);
1210
mfp = my_setmntent(_PATH_MOUNTED, "a+");
1211
if (mfp == NULL || mfp->mntent_fp == NULL) {
1213
error(_("mount: can't open %s: %s"), _PATH_MOUNTED,
1216
if ((my_addmntent (mfp, &mnt)) == 1) {
1218
error(_("mount: error writing %s: %s"),
1219
_PATH_MOUNTED, strerror (errsv));
1462
update_mtab(NULL, &mnt);
1226
1464
my_free(mnt.mnt_fsname);
1227
1465
my_free(mnt.mnt_dir);
1467
#endif /* !HAVE_LIBMOUNT_MOUNT */
1231
1470
set_pfd(char *s) {
1257
* Check if @node is read-only filesystem by access() or futimens().
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.
1263
is_readonly(const char *node)
1499
is_readonly(const char *path)
1501
if (access(path, W_OK) == 0)
1505
if (errno != EACCES)
1267
if (getuid() == geteuid()) {
1268
if (access(node, W_OK) == -1 && errno == EROFS)
1271
1508
#ifdef HAVE_FUTIMENS
1510
* access(2) returns EACCES on read-only FS:
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).
1516
* - for read-write filesystem with read-only VFS node (aka -o remount,ro,bind)
1273
1519
struct timespec times[2];
1274
int fd = open(node, O_RDONLY);
1279
1521
times[0].tv_nsec = UTIME_NOW; /* atime */
1280
1522
times[1].tv_nsec = UTIME_OMIT; /* mtime */
1282
if (futimens(fd, times) == -1 && errno == EROFS)
1524
if (utimensat(AT_FDCWD, path, times, 0) == -1)
1525
return errno == EROFS;
1365
1603
if (flags & (MS_BIND | MS_MOVE | MS_PROPAGATION))
1366
1604
types = "none";
1606
#ifdef HAVE_LIBSELINUX
1607
if (flags & MS_REMOUNT) {
1609
* Linux kernel does not accept any selinux context option on remount
1612
mount_opts = remove_context_options(mount_opts);
1614
} else if (types && strcmp(types, "tmpfs") == 0 && is_selinux_enabled() > 0 &&
1615
!has_context_option(mount_opts)) {
1617
* Add rootcontext= mount option for tmpfs
1618
* https://bugzilla.redhat.com/show_bug.cgi?id=476964
1620
security_context_t sc = NULL;
1622
if (getfilecon(node, &sc) > 0 && strcmp("unlabeled", sc))
1623
append_context("rootcontext=", (char *) sc, &mount_opts);
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.
1373
if (check_special_mountprog(spec, node, types, flags, extra_opts, &status)) {
1633
if (check_special_mountprog(spec, node, types, flags, mount_opts, &status)) {
1638
#ifdef HAVE_LIBMOUNT_MOUNT
1639
mtab_opts = fix_opts_string(flags & ~MS_NOMTAB, extra_opts, user);
1643
prepare_mtab_entry(spec, node, types, mtab_opts, mtab_flags);
1379
1646
block_signals (SIG_BLOCK);
1400
1667
flags &= ~MS_RDONLY;
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
1674
if (!fake && mnt5_res == 0 &&
1675
!(flags & (MS_RDONLY | MS_PROPAGATION | MS_MOVE)) &&
1676
is_readonly(node)) {
1678
printf(_("mount: warning: %s seems to be mounted read-only.\n"), node);
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";
1404
1686
/* Mount succeeded, report this (if verbose) and write mtab entry. */
1406
if (!(mounttype & MS_PROPAGATION)) {
1687
#ifdef HAVE_LIBMOUNT_MOUNT
1688
update_mtab_entry(flags);
1690
verbose_mount_info(loop ? loopfile : spec, node, tp, mo, flags);
1692
if (!(mounttype & MS_PROPAGATION))
1407
1693
update_mtab_entry(loop ? loopfile : spec,
1409
types ? types : "unknown",
1410
fix_opts_string (flags & ~MS_NOMTAB, extra_opts, user),
1701
block_signals (SIG_UNBLOCK);
1416
block_signals (SIG_UNBLOCK);
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);
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);
1700
1981
return xstrdup(opts);
2063
/* returns 0 if not mounted, 1 if mounted and -1 in case of error */
2065
is_fstab_entry_mounted(struct mntentchn *mc, int verbose)
2069
if (mounted(mc->m.mnt_fsname, mc->m.mnt_dir))
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)))) {
2076
char *p = get_option_value(mc->m.mnt_opts, "offset=");
2077
uintmax_t offset = 0;
2079
if (p && strtosize(p, &offset) != 0) {
2081
printf(_("mount: ignore %s "
2082
"(unparsable offset= option)\n"),
2087
if (is_mounted_same_loopfile(mc->m.mnt_dir, mc->m.mnt_fsname, offset))
2094
printf(_("mount: %s already mounted on %s\n"),
2095
mc->m.mnt_fsname, mc->m.mnt_dir);
1781
2099
/* avoid using stat() on things we are not going to mount anyway.. */
1783
2101
has_noauto (const char *opts) {