]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - sys-utils/mount.c
sys-utils: cleanup license lines, add SPDX
[thirdparty/util-linux.git] / sys-utils / mount.c
index 765e1170ec6ba56c2f4beb7703e88142bd159b30..50e66de586903f0f4bdd0c13504981a1057f80ef 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
  * mount(8) -- mount a filesystem
  *
  * Copyright (C) 2011 Red Hat, Inc. All rights reserved.
@@ -8,17 +10,7 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
@@ -38,6 +30,7 @@
 #include "strutils.h"
 #include "closestream.h"
 #include "canonicalize.h"
+#include "pathnames.h"
 
 #define XALLOC_EXIT_CODE MNT_EX_SYSERR
 #include "xalloc.h"
@@ -54,13 +47,8 @@ static void suid_drop(struct libmnt_context *cxt)
        const uid_t ruid = getuid();
        const uid_t euid = geteuid();
 
-       if (ruid != 0 && euid == 0) {
-               if (setgid(getgid()) < 0)
-                       err(MNT_EX_FAIL, _("setgid() failed"));
-
-               if (setuid(getuid()) < 0)
-                       err(MNT_EX_FAIL, _("setuid() failed"));
-       }
+       if (ruid != 0 && euid == 0 && drop_permissions() != 0)
+               err(MNT_EX_FAIL, _("drop permissions failed"));
 
        /* be paranoid and check it, setuid(0) has to fail */
        if (ruid != 0 && setuid(0) == 0)
@@ -128,6 +116,8 @@ static void print_all(struct libmnt_context *cxt, char *pattern, int show_label)
        struct libmnt_fs *fs;
        struct libmnt_cache *cache = NULL;
 
+       mnt_context_enable_noautofs(cxt, 1);
+
        if (mnt_context_get_mtab(cxt, &tb))
                err(MNT_EX_SYSERR, _("failed to read mtab"));
 
@@ -146,7 +136,7 @@ static void print_all(struct libmnt_context *cxt, char *pattern, int show_label)
                if (type && pattern && !mnt_match_fstype(type, pattern))
                        continue;
 
-               if (!mnt_fs_is_pseudofs(fs) && !mnt_fs_is_netfs(fs))
+               if (mnt_fs_is_regularfs(fs))
                        xsrc = mnt_pretty_path(src, cache);
                printf ("%s on ", xsrc ? xsrc : src);
                safe_fputs(mnt_fs_get_target(fs));
@@ -319,11 +309,7 @@ static void selinux_warning(struct libmnt_context *cxt, const char *tgt)
 {
 
        if (tgt && mnt_context_is_verbose(cxt) && is_selinux_enabled() > 0) {
-# ifdef HAVE_SELINUX_CONTEXT_T
-               security_context_t raw = NULL, def = NULL;      /* deprecated */
-# else
-               char *raw = NULL, *def = NULL;                  /* since libselinux >= 3.1 */
-# endif
+               char *raw = NULL, *def = NULL;
 
                if (getfilecon(tgt, &raw) > 0
                    && security_get_initial_context("file", &def) == 0) {
@@ -345,6 +331,31 @@ static void selinux_warning(struct libmnt_context *cxt, const char *tgt)
 # define selinux_warning(_x, _y)
 #endif
 
+
+#ifdef USE_SYSTEMD
+static void systemd_hint(void)
+{
+       static int fstab_check_done = 0;
+
+       if (fstab_check_done == 0) {
+               struct stat a, b;
+
+               if (isatty(STDERR_FILENO) &&
+                   stat(_PATH_SD_UNITSLOAD, &a) == 0 &&
+                   stat(_PATH_MNTTAB, &b) == 0 &&
+                   cmp_stat_mtime(&a, &b, <))
+                       printf(_(
+       "mount: (hint) your fstab has been modified, but systemd still uses\n"
+       "       the old version; use 'systemctl daemon-reload' to reload.\n"));
+
+               fstab_check_done = 1;
+       }
+}
+#else
+# define systemd_hint()
+#endif
+
+
 /*
  * Returns exit status (MNT_EX_*) and/or prints error message.
  */
@@ -363,11 +374,18 @@ static int mk_exit_code(struct libmnt_context *cxt, int rc)
                if (!spec)
                        spec = "???";
                warnx("%s: %s.", spec, buf);
+
+               if (mnt_context_syscall_called(cxt) &&
+                   mnt_context_get_syscall_errno(cxt) != 0)
+                       fprintf(stderr, _("       dmesg(1) may have more information after failed mount system call.\n"));
        }
 
        if (rc == MNT_EX_SUCCESS && mnt_context_get_status(cxt) == 1) {
                selinux_warning(cxt, tgt);
        }
+
+       systemd_hint();
+
        return rc;
 }
 
@@ -425,12 +443,20 @@ static int sanitize_paths(struct libmnt_context *cxt)
        return 0;
 }
 
-static void append_option(struct libmnt_context *cxt, const char *opt)
+static void append_option(struct libmnt_context *cxt, const char *opt, const char *arg)
 {
+       char *o = NULL;
+
        if (opt && (*opt == '=' || *opt == '\'' || *opt == '\"' || isblank(*opt)))
                errx(MNT_EX_USAGE, _("unsupported option format: %s"), opt);
-       if (mnt_context_append_options(cxt, opt))
-               err(MNT_EX_SYSERR, _("failed to append option '%s'"), opt);
+
+       if (arg && *arg)
+               xasprintf(&o, "%s=\"%s\"", opt, arg);
+
+       if (mnt_context_append_options(cxt, o ? : opt))
+               err(MNT_EX_SYSERR, _("failed to append option '%s'"), o ? : opt);
+
+       free(o);
 }
 
 static int has_remount_flag(struct libmnt_context *cxt)
@@ -446,6 +472,7 @@ static int has_remount_flag(struct libmnt_context *cxt)
 static void __attribute__((__noreturn__)) usage(void)
 {
        FILE *out = stdout;
+
        fputs(USAGE_HEADER, out);
        fprintf(out, _(
                " %1$s [-lhV]\n"
@@ -459,78 +486,71 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(_("Mount a filesystem.\n"), out);
 
        fputs(USAGE_OPTIONS, out);
-       fprintf(out, _(
-       " -a, --all               mount all filesystems mentioned in fstab\n"
-       " -c, --no-canonicalize   don't canonicalize paths\n"
-       " -f, --fake              dry run; skip the mount(2) syscall\n"
-       " -F, --fork              fork off for each device (use with -a)\n"
-       " -T, --fstab <path>      alternative file to /etc/fstab\n"));
-       fprintf(out, _(
-       " -i, --internal-only     don't call the mount.<type> helpers\n"));
-       fprintf(out, _(
-       " -l, --show-labels       show also filesystem labels\n"));
-       fprintf(out, _(
-       " -n, --no-mtab           don't write to /etc/mtab\n"));
-       fprintf(out, _(
-       "     --options-mode <mode>\n"
-       "                         what to do with options loaded from fstab\n"
-       "     --options-source <source>\n"
-       "                         mount options source\n"
-       "     --options-source-force\n"
-       "                         force use of options from fstab/mtab\n"));
-       fprintf(out, _(
-       " -o, --options <list>    comma-separated list of mount options\n"
-       " -O, --test-opts <list>  limit the set of filesystems (use with -a)\n"
-       " -r, --read-only         mount the filesystem read-only (same as -o ro)\n"
-       " -t, --types <list>      limit the set of filesystem types\n"));
-       fprintf(out, _(
-       "     --source <src>      explicitly specifies source (path, label, uuid)\n"
-       "     --target <target>   explicitly specifies mountpoint\n"));
-       fprintf(out, _(
-       "     --target-prefix <path>\n"
-       "                         specifies path use for all mountpoints\n"));
-       fprintf(out, _(
-       " -v, --verbose           say what is being done\n"));
-       fprintf(out, _(
-       " -w, --rw, --read-write  mount the filesystem read-write (default)\n"));
-       fprintf(out, _(
-       " -N, --namespace <ns>    perform mount in another namespace\n"));
+       fputs(_(" -a, --all               mount all filesystems mentioned in fstab\n"), out);
+       fputs(_(" -c, --no-canonicalize   don't canonicalize paths\n"), out);
+       fputs(_(" -f, --fake              dry run; skip the mount(2) syscall\n"), out);
+       fputs(_(" -F, --fork              fork off for each device (use with -a)\n"), out);
+       fputs(_(" -T, --fstab <path>      alternative file to /etc/fstab\n"), out);
+       fputs(_(" -i, --internal-only     don't call the mount.<type> helpers\n"), out);
+       fputs(_(" -l, --show-labels       show also filesystem labels\n"), out);
+       fputs(_("     --map-groups <inner>:<outer>:<count>\n"
+               "                         add the specified GID map to an ID-mapped mount\n"), out);
+       fputs(_("     --map-users <inner>:<outer>:<count>\n"
+               "                         add the specified UID map to an ID-mapped mount\n"), out);
+       fputs(_("     --map-users /proc/<pid>/ns/user\n"
+               "                         specify the user namespace for an ID-mapped mount\n"), out);
+       fputs(_(" -m, --mkdir[=<mode>]    alias to '-o X-mount.mkdir[=<mode>]'\n"), out);
+       fputs(_(" -n, --no-mtab           don't write to /etc/mtab\n"), out);
+       fputs(_("     --options-mode <mode>\n"
+               "                         what to do with options loaded from fstab\n"), out);
+       fputs(_("     --options-source <source>\n"
+               "                         mount options source\n"), out);
+       fputs(_("     --options-source-force\n"
+               "                         force use of options from fstab/mtab\n"), out);
+       fputs(_("     --onlyonce          check if filesystem is already mounted\n"), out);
+       fputs(_(" -o, --options <list>    comma-separated list of mount options\n"), out);
+       fputs(_(" -O, --test-opts <list>  limit the set of filesystems (use with -a)\n"), out);
+       fputs(_(" -r, --read-only         mount the filesystem read-only (same as -o ro)\n"), out);
+       fputs(_(" -t, --types <list>      limit the set of filesystem types\n"), out);
+       fputs(_("     --source <src>      explicitly specifies source (path, label, uuid)\n"), out);
+       fputs(_("     --target <target>   explicitly specifies mountpoint\n"), out);
+       fputs(_("     --target-prefix <path>\n"
+               "                         specifies path used for all mountpoints\n"), out);
+       fputs(_(" -v, --verbose           say what is being done\n"), out);
+       fputs(_(" -w, --rw, --read-write  mount the filesystem read-write (default)\n"), out);
+       fputs(_(" -N, --namespace <ns>    perform mount in another namespace\n"), out);
 
        fputs(USAGE_SEPARATOR, out);
-       printf(USAGE_HELP_OPTIONS(25));
-
-       fprintf(out, _(
-       "\nSource:\n"
-       " -L, --label <label>     synonym for LABEL=<label>\n"
-       " -U, --uuid <uuid>       synonym for UUID=<uuid>\n"
-       " LABEL=<label>           specifies device by filesystem label\n"
-       " UUID=<uuid>             specifies device by filesystem UUID\n"
-       " PARTLABEL=<label>       specifies device by partition label\n"
-       " PARTUUID=<uuid>         specifies device by partition UUID\n"
-       " ID=<id>                 specifies device by udev hardware ID\n"));
-
-       fprintf(out, _(
-       " <device>                specifies device by path\n"
-       " <directory>             mountpoint for bind mounts (see --bind/rbind)\n"
-       " <file>                  regular file for loopdev setup\n"));
+       fprintf(out, USAGE_HELP_OPTIONS(25));
 
-       fprintf(out, _(
-       "\nOperations:\n"
-       " -B, --bind              mount a subtree somewhere else (same as -o bind)\n"
-       " -M, --move              move a subtree to some other place\n"
-       " -R, --rbind             mount a subtree and all submounts somewhere else\n"));
-       fprintf(out, _(
-       " --make-shared           mark a subtree as shared\n"
-       " --make-slave            mark a subtree as slave\n"
-       " --make-private          mark a subtree as private\n"
-       " --make-unbindable       mark a subtree as unbindable\n"));
-       fprintf(out, _(
-       " --make-rshared          recursively mark a whole subtree as shared\n"
-       " --make-rslave           recursively mark a whole subtree as slave\n"
-       " --make-rprivate         recursively mark a whole subtree as private\n"
-       " --make-runbindable      recursively mark a whole subtree as unbindable\n"));
+       fputs(USAGE_SEPARATOR, out);
+       fputs(_("Source:\n"), out);
+       fputs(_(" -L, --label <label>     synonym for LABEL=<label>\n"), out);
+       fputs(_(" -U, --uuid <uuid>       synonym for UUID=<uuid>\n"), out);
+       fputs(_(" LABEL=<label>           specifies device by filesystem label\n"), out);
+       fputs(_(" UUID=<uuid>             specifies device by filesystem UUID\n"), out);
+       fputs(_(" PARTLABEL=<label>       specifies device by partition label\n"), out);
+       fputs(_(" PARTUUID=<uuid>         specifies device by partition UUID\n"), out);
+       fputs(_(" ID=<id>                 specifies device by udev hardware ID\n"), out);
+       fputs(_(" <device>                specifies device by path\n"), out);
+       fputs(_(" <directory>             mountpoint for bind mounts (see --bind/rbind)\n"), out);
+       fputs(_(" <file>                  regular file for loopdev setup\n"), out);
 
-       printf(USAGE_MAN_TAIL("mount(8)"));
+       fputs(USAGE_SEPARATOR, out);
+       fputs(_("Operations:\n"), out);
+       fputs(_(" -B, --bind              mount a subtree somewhere else (same as -o bind)\n"), out);
+       fputs(_(" -M, --move              move a subtree to some other place\n"), out);
+       fputs(_(" -R, --rbind             mount a subtree and all submounts somewhere else\n"), out);
+       fputs(_(" --make-shared           mark a subtree as shared\n"), out);
+       fputs(_(" --make-slave            mark a subtree as slave\n"), out);
+       fputs(_(" --make-private          mark a subtree as private\n"), out);
+       fputs(_(" --make-unbindable       mark a subtree as unbindable\n"), out);
+       fputs(_(" --make-rshared          recursively mark a whole subtree as shared\n"), out);
+       fputs(_(" --make-rslave           recursively mark a whole subtree as slave\n"), out);
+       fputs(_(" --make-rprivate         recursively mark a whole subtree as private\n"), out);
+       fputs(_(" --make-runbindable      recursively mark a whole subtree as unbindable\n"), out);
+
+       fprintf(out, USAGE_MAN_TAIL("mount(8)"));
 
        exit(MNT_EX_SUCCESS);
 }
@@ -593,6 +613,7 @@ int main(int argc, char **argv)
        int c, rc = MNT_EX_SUCCESS, all = 0, show_labels = 0;
        struct libmnt_context *cxt;
        struct libmnt_table *fstab = NULL;
+       char *idmap = NULL;
        char *srcbuf = NULL;
        char *types = NULL;
        int oper = 0, is_move = 0;
@@ -608,12 +629,15 @@ int main(int argc, char **argv)
                MOUNT_OPT_RSLAVE,
                MOUNT_OPT_RPRIVATE,
                MOUNT_OPT_RUNBINDABLE,
+               MOUNT_OPT_MAP_GROUPS,
+               MOUNT_OPT_MAP_USERS,
                MOUNT_OPT_TARGET,
                MOUNT_OPT_TARGET_PREFIX,
                MOUNT_OPT_SOURCE,
                MOUNT_OPT_OPTMODE,
                MOUNT_OPT_OPTSRC,
-               MOUNT_OPT_OPTSRC_FORCE
+               MOUNT_OPT_OPTSRC_FORCE,
+               MOUNT_OPT_ONLYONCE
        };
 
        static const struct option longopts[] = {
@@ -645,12 +669,16 @@ int main(int argc, char **argv)
                { "make-rslave",      no_argument,       NULL, MOUNT_OPT_RSLAVE      },
                { "make-rprivate",    no_argument,       NULL, MOUNT_OPT_RPRIVATE    },
                { "make-runbindable", no_argument,       NULL, MOUNT_OPT_RUNBINDABLE },
+               { "map-groups",       required_argument, NULL, MOUNT_OPT_MAP_GROUPS  },
+               { "map-users",        required_argument, NULL, MOUNT_OPT_MAP_USERS   },
+               { "mkdir",            optional_argument, NULL, 'm'                   },
                { "no-canonicalize",  no_argument,       NULL, 'c'                   },
                { "internal-only",    no_argument,       NULL, 'i'                   },
                { "show-labels",      no_argument,       NULL, 'l'                   },
                { "target",           required_argument, NULL, MOUNT_OPT_TARGET      },
                { "target-prefix",    required_argument, NULL, MOUNT_OPT_TARGET_PREFIX },
                { "source",           required_argument, NULL, MOUNT_OPT_SOURCE      },
+               { "onlyonce",         no_argument,       NULL, MOUNT_OPT_ONLYONCE    },
                { "options-mode",     required_argument, NULL, MOUNT_OPT_OPTMODE     },
                { "options-source",   required_argument, NULL, MOUNT_OPT_OPTSRC      },
                { "options-source-force",   no_argument, NULL, MOUNT_OPT_OPTSRC_FORCE},
@@ -680,7 +708,7 @@ int main(int argc, char **argv)
 
        mnt_context_set_tables_errcb(cxt, table_parser_errcb);
 
-       while ((c = getopt_long(argc, argv, "aBcfFhilL:Mno:O:rRsU:vVwt:T:N:",
+       while ((c = getopt_long(argc, argv, "aBcfFhilL:m::Mno:O:rRsU:vVwt:T:N:",
                                        longopts, NULL)) != -1) {
 
                /* only few options are allowed for non-root users */
@@ -712,14 +740,14 @@ int main(int argc, char **argv)
                        mnt_context_disable_mtab(cxt, TRUE);
                        break;
                case 'r':
-                       append_option(cxt, "ro");
+                       append_option(cxt, "ro", NULL);
                        mnt_context_enable_rwonly_mount(cxt, FALSE);
                        break;
                case 'v':
                        mnt_context_enable_verbose(cxt, TRUE);
                        break;
                case 'w':
-                       append_option(cxt, "rw");
+                       append_option(cxt, "rw", NULL);
                        mnt_context_enable_rwonly_mount(cxt, TRUE);
                        break;
                case 'o':
@@ -730,11 +758,11 @@ int main(int argc, char **argv)
 
                                mnt_optstr_remove_option(&o, "move");
                                if (o && *o)
-                                       append_option(cxt, o);
+                                       append_option(cxt, o, NULL);
                                oper = is_move = 1;
                                free(o);
                        } else
-                               append_option(cxt, optarg);
+                               append_option(cxt, optarg, NULL);
                        break;
                case 'O':
                        if (mnt_context_set_options_pattern(cxt, optarg))
@@ -766,15 +794,20 @@ int main(int argc, char **argv)
                        break;
                case 'B':
                        oper = 1;
-                       append_option(cxt, "bind");
+                       append_option(cxt, "bind", NULL);
                        break;
                case 'M':
                        oper = 1;
                        is_move = 1;
                        break;
+               case 'm':
+                       if (optarg && *optarg == '=')
+                               optarg++;
+                       append_option(cxt, "X-mount.mkdir", optarg);
+                       break;
                case 'R':
                        oper = 1;
-                       append_option(cxt, "rbind");
+                       append_option(cxt, "rbind", NULL);
                        break;
                case 'N':
                {
@@ -789,37 +822,54 @@ int main(int argc, char **argv)
                        break;
                }
                case MOUNT_OPT_SHARED:
-                       append_option(cxt, "shared");
+                       append_option(cxt, "shared", NULL);
                        propa = 1;
                        break;
                case MOUNT_OPT_SLAVE:
-                       append_option(cxt, "slave");
+                       append_option(cxt, "slave", NULL);
                        propa = 1;
                        break;
                case MOUNT_OPT_PRIVATE:
-                       append_option(cxt, "private");
+                       append_option(cxt, "private", NULL);
                        propa = 1;
                        break;
                case MOUNT_OPT_UNBINDABLE:
-                       append_option(cxt, "unbindable");
+                       append_option(cxt, "unbindable", NULL);
                        propa = 1;
                        break;
                case MOUNT_OPT_RSHARED:
-                       append_option(cxt, "rshared");
+                       append_option(cxt, "rshared", NULL);
                        propa = 1;
                        break;
                case MOUNT_OPT_RSLAVE:
-                       append_option(cxt, "rslave");
+                       append_option(cxt, "rslave", NULL);
                        propa = 1;
                        break;
                case MOUNT_OPT_RPRIVATE:
-                       append_option(cxt, "rprivate");
+                       append_option(cxt, "rprivate", NULL);
                        propa = 1;
                        break;
                case MOUNT_OPT_RUNBINDABLE:
-                       append_option(cxt, "runbindable");
+                       append_option(cxt, "runbindable", NULL);
                        propa = 1;
                        break;
+               case MOUNT_OPT_MAP_GROUPS:
+               case MOUNT_OPT_MAP_USERS:
+                       if (*optarg == '=')
+                               optarg++;
+                       if (idmap && (*idmap == '/' || *optarg == '/')) {
+                               warnx(_("bad usage"));
+                               errtryhelp(MNT_EX_USAGE);
+                       } else if (*optarg == '/') {
+                               idmap = xstrdup(optarg);
+                       } else {
+                               char *tmp;
+                               xasprintf(&tmp, "%s%s%s%s", idmap ? idmap : "", idmap ? " " : "",
+                                       c == MOUNT_OPT_MAP_GROUPS ? "g:" : "u:", optarg);
+                               free(idmap);
+                               idmap = tmp;
+                       }
+                       break;
                case MOUNT_OPT_TARGET:
                        mnt_context_disable_swapmatch(cxt, 1);
                        mnt_context_set_target(cxt, optarg);
@@ -851,7 +901,9 @@ int main(int argc, char **argv)
                case MOUNT_OPT_OPTSRC_FORCE:
                        optmode |= MNT_OMODE_FORCE;
                        break;
-
+               case MOUNT_OPT_ONLYONCE:
+                       mnt_context_enable_onlyonce(cxt, 1);
+                       break;
                case 'h':
                        mnt_free_context(cxt);
                        usage();
@@ -866,6 +918,9 @@ int main(int argc, char **argv)
        argc -= optind;
        argv += optind;
 
+       if (idmap)
+               append_option(cxt, "X-mount.idmap", idmap);
+
        optmode |= optmode_mode | optmode_src;
        if (optmode) {
                if (!optmode_mode)