LCOV - code coverage report
Current view: top level - mount - mount-tool.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 33 875 3.8 %
Date: 2019-08-22 15:41:25 Functions: 11 35 31.4 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <getopt.h>
       4             : 
       5             : #include "sd-bus.h"
       6             : #include "sd-device.h"
       7             : 
       8             : #include "bus-error.h"
       9             : #include "bus-unit-util.h"
      10             : #include "bus-util.h"
      11             : #include "bus-wait-for-jobs.h"
      12             : #include "device-util.h"
      13             : #include "dirent-util.h"
      14             : #include "escape.h"
      15             : #include "fd-util.h"
      16             : #include "fileio.h"
      17             : #include "format-util.h"
      18             : #include "fs-util.h"
      19             : #include "fstab-util.h"
      20             : #include "libmount-util.h"
      21             : #include "main-func.h"
      22             : #include "mount-util.h"
      23             : #include "mountpoint-util.h"
      24             : #include "pager.h"
      25             : #include "parse-util.h"
      26             : #include "path-util.h"
      27             : #include "pretty-print.h"
      28             : #include "sort-util.h"
      29             : #include "spawn-polkit-agent.h"
      30             : #include "stat-util.h"
      31             : #include "strv.h"
      32             : #include "terminal-util.h"
      33             : #include "unit-def.h"
      34             : #include "unit-name.h"
      35             : #include "user-util.h"
      36             : 
      37             : enum {
      38             :         ACTION_DEFAULT,
      39             :         ACTION_MOUNT,
      40             :         ACTION_AUTOMOUNT,
      41             :         ACTION_UMOUNT,
      42             :         ACTION_LIST,
      43             : } arg_action = ACTION_DEFAULT;
      44             : 
      45             : static bool arg_no_block = false;
      46             : static PagerFlags arg_pager_flags = 0;
      47             : static bool arg_ask_password = true;
      48             : static bool arg_quiet = false;
      49             : static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
      50             : static bool arg_user = false;
      51             : static const char *arg_host = NULL;
      52             : static bool arg_discover = false;
      53             : static char *arg_mount_what = NULL;
      54             : static char *arg_mount_where = NULL;
      55             : static char *arg_mount_type = NULL;
      56             : static char *arg_mount_options = NULL;
      57             : static char *arg_description = NULL;
      58             : static char **arg_property = NULL;
      59             : static usec_t arg_timeout_idle = USEC_INFINITY;
      60             : static bool arg_timeout_idle_set = false;
      61             : static char **arg_automount_property = NULL;
      62             : static int arg_bind_device = -1;
      63             : static uid_t arg_uid = UID_INVALID;
      64             : static gid_t arg_gid = GID_INVALID;
      65             : static bool arg_fsck = true;
      66             : static bool arg_aggressive_gc = false;
      67             : 
      68           4 : STATIC_DESTRUCTOR_REGISTER(arg_mount_what, freep);
      69           4 : STATIC_DESTRUCTOR_REGISTER(arg_mount_where, freep);
      70           4 : STATIC_DESTRUCTOR_REGISTER(arg_mount_type, freep);
      71           4 : STATIC_DESTRUCTOR_REGISTER(arg_mount_options, freep);
      72           4 : STATIC_DESTRUCTOR_REGISTER(arg_description, freep);
      73           4 : STATIC_DESTRUCTOR_REGISTER(arg_property, strv_freep);
      74           4 : STATIC_DESTRUCTOR_REGISTER(arg_automount_property, strv_freep);
      75             : 
      76           3 : static int help(void) {
      77           3 :         _cleanup_free_ char *link = NULL;
      78             :         int r;
      79             : 
      80           3 :         r = terminal_urlify_man("systemd-mount", "1", &link);
      81           3 :         if (r < 0)
      82           0 :                 return log_oom();
      83             : 
      84           3 :         printf("systemd-mount [OPTIONS...] WHAT [WHERE]\n"
      85             :                "systemd-mount [OPTIONS...] --list\n"
      86             :                "%s [OPTIONS...] %sWHAT|WHERE...\n\n"
      87             :                "Establish a mount or auto-mount point transiently.\n\n"
      88             :                "  -h --help                       Show this help\n"
      89             :                "     --version                    Show package version\n"
      90             :                "     --no-block                   Do not wait until operation finished\n"
      91             :                "     --no-pager                   Do not pipe output into a pager\n"
      92             :                "     --no-ask-password            Do not prompt for password\n"
      93             :                "  -q --quiet                      Suppress information messages during runtime\n"
      94             :                "     --user                       Run as user unit\n"
      95             :                "  -H --host=[USER@]HOST           Operate on remote host\n"
      96             :                "  -M --machine=CONTAINER          Operate on local container\n"
      97             :                "     --discover                   Discover mount device metadata\n"
      98             :                "  -t --type=TYPE                  File system type\n"
      99             :                "  -o --options=OPTIONS            Mount options\n"
     100             :                "     --owner=USER                 Add uid= and gid= options for USER\n"
     101             :                "     --fsck=no                    Don't run file system check before mount\n"
     102             :                "     --description=TEXT           Description for unit\n"
     103             :                "  -p --property=NAME=VALUE        Set mount unit property\n"
     104             :                "  -A --automount=BOOL             Create an auto-mount point\n"
     105             :                "     --timeout-idle-sec=SEC       Specify automount idle timeout\n"
     106             :                "     --automount-property=NAME=VALUE\n"
     107             :                "                                  Set automount unit property\n"
     108             :                "     --bind-device                Bind automount unit to device\n"
     109             :                "     --list                       List mountable block devices\n"
     110             :                "  -u --umount                     Unmount mount points\n"
     111             :                "  -G --collect                    Unload unit after it stopped, even when failed\n"
     112             :                "\nSee the %s for details.\n"
     113             :                , program_invocation_short_name
     114           3 :                , streq(program_invocation_short_name, "systemd-umount") ? "" : "--umount "
     115             :                , link
     116             :         );
     117             : 
     118           3 :         return 0;
     119             : }
     120             : 
     121           4 : static int parse_argv(int argc, char *argv[]) {
     122             : 
     123             :         enum {
     124             :                 ARG_VERSION = 0x100,
     125             :                 ARG_NO_BLOCK,
     126             :                 ARG_NO_PAGER,
     127             :                 ARG_NO_ASK_PASSWORD,
     128             :                 ARG_USER,
     129             :                 ARG_SYSTEM,
     130             :                 ARG_DISCOVER,
     131             :                 ARG_MOUNT_TYPE,
     132             :                 ARG_MOUNT_OPTIONS,
     133             :                 ARG_OWNER,
     134             :                 ARG_FSCK,
     135             :                 ARG_DESCRIPTION,
     136             :                 ARG_TIMEOUT_IDLE,
     137             :                 ARG_AUTOMOUNT,
     138             :                 ARG_AUTOMOUNT_PROPERTY,
     139             :                 ARG_BIND_DEVICE,
     140             :                 ARG_LIST,
     141             :         };
     142             : 
     143             :         static const struct option options[] = {
     144             :                 { "help",               no_argument,       NULL, 'h'                    },
     145             :                 { "version",            no_argument,       NULL, ARG_VERSION            },
     146             :                 { "no-block",           no_argument,       NULL, ARG_NO_BLOCK           },
     147             :                 { "no-pager",           no_argument,       NULL, ARG_NO_PAGER           },
     148             :                 { "no-ask-password",    no_argument,       NULL, ARG_NO_ASK_PASSWORD    },
     149             :                 { "quiet",              no_argument,       NULL, 'q'                    },
     150             :                 { "user",               no_argument,       NULL, ARG_USER               },
     151             :                 { "system",             no_argument,       NULL, ARG_SYSTEM             },
     152             :                 { "host",               required_argument, NULL, 'H'                    },
     153             :                 { "machine",            required_argument, NULL, 'M'                    },
     154             :                 { "discover",           no_argument,       NULL, ARG_DISCOVER           },
     155             :                 { "type",               required_argument, NULL, 't'                    },
     156             :                 { "options",            required_argument, NULL, 'o'                    },
     157             :                 { "owner",              required_argument, NULL, ARG_OWNER              },
     158             :                 { "fsck",               required_argument, NULL, ARG_FSCK               },
     159             :                 { "description",        required_argument, NULL, ARG_DESCRIPTION        },
     160             :                 { "property",           required_argument, NULL, 'p'                    },
     161             :                 { "automount",          required_argument, NULL, ARG_AUTOMOUNT          },
     162             :                 { "timeout-idle-sec",   required_argument, NULL, ARG_TIMEOUT_IDLE       },
     163             :                 { "automount-property", required_argument, NULL, ARG_AUTOMOUNT_PROPERTY },
     164             :                 { "bind-device",        no_argument,       NULL, ARG_BIND_DEVICE        },
     165             :                 { "list",               no_argument,       NULL, ARG_LIST               },
     166             :                 { "umount",             no_argument,       NULL, 'u'                    },
     167             :                 { "unmount",            no_argument,       NULL, 'u'                    },
     168             :                 { "collect",            no_argument,       NULL, 'G'                    },
     169             :                 {},
     170             :         };
     171             : 
     172             :         int r, c;
     173             : 
     174           4 :         assert(argc >= 0);
     175           4 :         assert(argv);
     176             : 
     177           4 :         if (strstr(program_invocation_short_name, "systemd-umount"))
     178           0 :                         arg_action = ACTION_UMOUNT;
     179             : 
     180           4 :         while ((c = getopt_long(argc, argv, "hqH:M:t:o:p:AuG", options, NULL)) >= 0)
     181             : 
     182           4 :                 switch (c) {
     183             : 
     184           3 :                 case 'h':
     185           3 :                         return help();
     186             : 
     187           0 :                 case ARG_VERSION:
     188           0 :                         return version();
     189             : 
     190           0 :                 case ARG_NO_BLOCK:
     191           0 :                         arg_no_block = true;
     192           0 :                         break;
     193             : 
     194           0 :                 case ARG_NO_PAGER:
     195           0 :                         arg_pager_flags |= PAGER_DISABLE;
     196           0 :                         break;
     197             : 
     198           0 :                 case ARG_NO_ASK_PASSWORD:
     199           0 :                         arg_ask_password = false;
     200           0 :                         break;
     201             : 
     202           0 :                 case 'q':
     203           0 :                         arg_quiet = true;
     204           0 :                         break;
     205             : 
     206           0 :                 case ARG_USER:
     207           0 :                         arg_user = true;
     208           0 :                         break;
     209             : 
     210           0 :                 case ARG_SYSTEM:
     211           0 :                         arg_user = false;
     212           0 :                         break;
     213             : 
     214           0 :                 case 'H':
     215           0 :                         arg_transport = BUS_TRANSPORT_REMOTE;
     216           0 :                         arg_host = optarg;
     217           0 :                         break;
     218             : 
     219           0 :                 case 'M':
     220           0 :                         arg_transport = BUS_TRANSPORT_MACHINE;
     221           0 :                         arg_host = optarg;
     222           0 :                         break;
     223             : 
     224           0 :                 case ARG_DISCOVER:
     225           0 :                         arg_discover = true;
     226           0 :                         break;
     227             : 
     228           0 :                 case 't':
     229           0 :                         if (free_and_strdup(&arg_mount_type, optarg) < 0)
     230           0 :                                 return log_oom();
     231           0 :                         break;
     232             : 
     233           0 :                 case 'o':
     234           0 :                         if (free_and_strdup(&arg_mount_options, optarg) < 0)
     235           0 :                                 return log_oom();
     236           0 :                         break;
     237             : 
     238           0 :                 case ARG_OWNER: {
     239           0 :                         const char *user = optarg;
     240             : 
     241           0 :                         r = get_user_creds(&user, &arg_uid, &arg_gid, NULL, NULL, 0);
     242           0 :                         if (r < 0)
     243           0 :                                 return log_error_errno(r,
     244             :                                                        r == -EBADMSG ? "UID or GID of user %s are invalid."
     245             :                                                                      : "Cannot use \"%s\" as owner: %m",
     246             :                                                        optarg);
     247           0 :                         break;
     248             :                 }
     249             : 
     250           0 :                 case ARG_FSCK:
     251           0 :                         r = parse_boolean(optarg);
     252           0 :                         if (r < 0)
     253           0 :                                 return log_error_errno(r, "Failed to parse --fsck= argument: %s", optarg);
     254             : 
     255           0 :                         arg_fsck = r;
     256           0 :                         break;
     257             : 
     258           0 :                 case ARG_DESCRIPTION:
     259           0 :                         if (free_and_strdup(&arg_description, optarg) < 0)
     260           0 :                                 return log_oom();
     261           0 :                         break;
     262             : 
     263           0 :                 case 'p':
     264           0 :                         if (strv_extend(&arg_property, optarg) < 0)
     265           0 :                                 return log_oom();
     266             : 
     267           0 :                         break;
     268             : 
     269           0 :                 case 'A':
     270           0 :                         arg_action = ACTION_AUTOMOUNT;
     271           0 :                         break;
     272             : 
     273           0 :                 case ARG_AUTOMOUNT:
     274           0 :                         r = parse_boolean(optarg);
     275           0 :                         if (r < 0)
     276           0 :                                 return log_error_errno(r, "--automount= expects a valid boolean parameter: %s", optarg);
     277             : 
     278           0 :                         arg_action = r ? ACTION_AUTOMOUNT : ACTION_MOUNT;
     279           0 :                         break;
     280             : 
     281           0 :                 case ARG_TIMEOUT_IDLE:
     282           0 :                         r = parse_sec(optarg, &arg_timeout_idle);
     283           0 :                         if (r < 0)
     284           0 :                                 return log_error_errno(r, "Failed to parse timeout: %s", optarg);
     285             : 
     286           0 :                         break;
     287             : 
     288           0 :                 case ARG_AUTOMOUNT_PROPERTY:
     289           0 :                         if (strv_extend(&arg_automount_property, optarg) < 0)
     290           0 :                                 return log_oom();
     291             : 
     292           0 :                         break;
     293             : 
     294           0 :                 case ARG_BIND_DEVICE:
     295           0 :                         arg_bind_device = true;
     296           0 :                         break;
     297             : 
     298           0 :                 case ARG_LIST:
     299           0 :                         arg_action = ACTION_LIST;
     300           0 :                         break;
     301             : 
     302           0 :                 case 'u':
     303           0 :                         arg_action = ACTION_UMOUNT;
     304           0 :                         break;
     305             : 
     306           0 :                 case 'G':
     307           0 :                         arg_aggressive_gc = true;
     308           0 :                         break;
     309             : 
     310           1 :                 case '?':
     311           1 :                         return -EINVAL;
     312             : 
     313           0 :                 default:
     314           0 :                         assert_not_reached("Unhandled option");
     315             :                 }
     316             : 
     317           0 :         if (arg_user && arg_transport != BUS_TRANSPORT_LOCAL)
     318           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     319             :                                        "Execution in user context is not supported on non-local systems.");
     320             : 
     321           0 :         if (arg_action == ACTION_LIST) {
     322           0 :                 if (optind < argc)
     323           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     324             :                                                "Too many arguments.");
     325             : 
     326           0 :                 if (arg_transport != BUS_TRANSPORT_LOCAL)
     327           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
     328             :                                                "Listing devices only supported locally.");
     329           0 :         } else if (arg_action == ACTION_UMOUNT) {
     330           0 :                 if (optind >= argc)
     331           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     332             :                                                "At least one argument required.");
     333             : 
     334           0 :                 if (arg_transport != BUS_TRANSPORT_LOCAL) {
     335             :                         int i;
     336             : 
     337           0 :                         for (i = optind; i < argc; i++)
     338           0 :                                 if (!path_is_absolute(argv[i]) )
     339           0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     340             :                                                                "Only absolute path is supported: %s", argv[i]);
     341             :                 }
     342             :         } else {
     343           0 :                 if (optind >= argc)
     344           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     345             :                                                "At least one argument required.");
     346             : 
     347           0 :                 if (argc > optind+2)
     348           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     349             :                                                "At most two arguments required.");
     350             : 
     351           0 :                 if (arg_mount_type && (fstype_is_api_vfs(arg_mount_type) || fstype_is_network(arg_mount_type))) {
     352           0 :                         arg_mount_what = strdup(argv[optind]);
     353           0 :                         if (!arg_mount_what)
     354           0 :                                 return log_oom();
     355             : 
     356           0 :                 } else if (arg_transport == BUS_TRANSPORT_LOCAL) {
     357           0 :                         _cleanup_free_ char *u = NULL;
     358             : 
     359           0 :                         u = fstab_node_to_udev_node(argv[optind]);
     360           0 :                         if (!u)
     361           0 :                                 return log_oom();
     362             : 
     363           0 :                         r = chase_symlinks(u, NULL, 0, &arg_mount_what);
     364           0 :                         if (r < 0)
     365           0 :                                 return log_error_errno(r, "Failed to make path %s absolute: %m", u);
     366             :                 } else {
     367           0 :                         arg_mount_what = strdup(argv[optind]);
     368           0 :                         if (!arg_mount_what)
     369           0 :                                 return log_oom();
     370             : 
     371           0 :                         path_simplify(arg_mount_what, false);
     372             : 
     373           0 :                         if (!path_is_absolute(arg_mount_what))
     374           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     375             :                                                        "Only absolute path is supported: %s", arg_mount_what);
     376             :                 }
     377             : 
     378           0 :                 if (argc > optind+1) {
     379           0 :                         if (arg_transport == BUS_TRANSPORT_LOCAL) {
     380           0 :                                 r = chase_symlinks(argv[optind+1], NULL, CHASE_NONEXISTENT, &arg_mount_where);
     381           0 :                                 if (r < 0)
     382           0 :                                         return log_error_errno(r, "Failed to make path %s absolute: %m", argv[optind+1]);
     383             :                         } else {
     384           0 :                                 arg_mount_where = strdup(argv[optind+1]);
     385           0 :                                 if (!arg_mount_where)
     386           0 :                                         return log_oom();
     387             : 
     388           0 :                                 path_simplify(arg_mount_where, false);
     389             : 
     390           0 :                                 if (!path_is_absolute(arg_mount_where))
     391           0 :                                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     392             :                                                                "Only absolute path is supported: %s", arg_mount_where);
     393             :                         }
     394             :                 } else
     395           0 :                         arg_discover = true;
     396             : 
     397           0 :                 if (arg_discover && arg_transport != BUS_TRANSPORT_LOCAL)
     398           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
     399             :                                                "Automatic mount location discovery is only supported locally.");
     400             :         }
     401             : 
     402           0 :         return 1;
     403             : }
     404             : 
     405           0 : static int transient_unit_set_properties(sd_bus_message *m, UnitType t, char **properties) {
     406             :         int r;
     407             : 
     408           0 :         if (!isempty(arg_description)) {
     409           0 :                 r = sd_bus_message_append(m, "(sv)", "Description", "s", arg_description);
     410           0 :                 if (r < 0)
     411           0 :                         return r;
     412             :         }
     413             : 
     414           0 :         if (arg_bind_device && is_device_path(arg_mount_what)) {
     415           0 :                 _cleanup_free_ char *device_unit = NULL;
     416             : 
     417           0 :                 r = unit_name_from_path(arg_mount_what, ".device", &device_unit);
     418           0 :                 if (r < 0)
     419           0 :                         return r;
     420             : 
     421           0 :                 r = sd_bus_message_append(m, "(sv)(sv)",
     422             :                                           "After", "as", 1, device_unit,
     423             :                                           "BindsTo", "as", 1, device_unit);
     424           0 :                 if (r < 0)
     425           0 :                         return r;
     426             :         }
     427             : 
     428           0 :         if (arg_aggressive_gc) {
     429           0 :                 r = sd_bus_message_append(m, "(sv)", "CollectMode", "s", "inactive-or-failed");
     430           0 :                 if (r < 0)
     431           0 :                         return r;
     432             :         }
     433             : 
     434           0 :         r = bus_append_unit_property_assignment_many(m, t, properties);
     435           0 :         if (r < 0)
     436           0 :                 return r;
     437             : 
     438           0 :         return 0;
     439             : }
     440             : 
     441           0 : static int transient_mount_set_properties(sd_bus_message *m) {
     442           0 :         _cleanup_free_ char *options = NULL;
     443             :         int r;
     444             : 
     445           0 :         assert(m);
     446             : 
     447           0 :         r = transient_unit_set_properties(m, UNIT_MOUNT, arg_property);
     448           0 :         if (r < 0)
     449           0 :                 return r;
     450             : 
     451           0 :         if (arg_mount_what) {
     452           0 :                 r = sd_bus_message_append(m, "(sv)", "What", "s", arg_mount_what);
     453           0 :                 if (r < 0)
     454           0 :                         return r;
     455             :         }
     456             : 
     457           0 :         if (arg_mount_type) {
     458           0 :                 r = sd_bus_message_append(m, "(sv)", "Type", "s", arg_mount_type);
     459           0 :                 if (r < 0)
     460           0 :                         return r;
     461             :         }
     462             : 
     463             :         /* Prepend uid=…,gid=… if arg_uid is set */
     464           0 :         if (arg_uid != UID_INVALID) {
     465           0 :                 r = asprintf(&options,
     466             :                              "uid=" UID_FMT ",gid=" GID_FMT "%s%s",
     467             :                              arg_uid, arg_gid,
     468           0 :                              arg_mount_options ? "," : "", strempty(arg_mount_options));
     469           0 :                 if (r < 0)
     470           0 :                         return -ENOMEM;
     471             :         }
     472             : 
     473           0 :         if (options || arg_mount_options) {
     474           0 :                 log_debug("Using mount options: %s", options ?: arg_mount_options);
     475             : 
     476           0 :                 r = sd_bus_message_append(m, "(sv)", "Options", "s", options ?: arg_mount_options);
     477           0 :                 if (r < 0)
     478           0 :                         return r;
     479             :         } else
     480           0 :                 log_debug("Not using any mount options");
     481             : 
     482           0 :         if (arg_fsck) {
     483           0 :                 _cleanup_free_ char *fsck = NULL;
     484             : 
     485           0 :                 r = unit_name_from_path_instance("systemd-fsck", arg_mount_what, ".service", &fsck);
     486           0 :                 if (r < 0)
     487           0 :                         return r;
     488             : 
     489           0 :                 r = sd_bus_message_append(m,
     490             :                                           "(sv)(sv)",
     491             :                                           "Requires", "as", 1, fsck,
     492             :                                           "After", "as", 1, fsck);
     493           0 :                 if (r < 0)
     494           0 :                         return r;
     495             :         }
     496             : 
     497           0 :         return 0;
     498             : }
     499             : 
     500           0 : static int transient_automount_set_properties(sd_bus_message *m) {
     501             :         int r;
     502             : 
     503           0 :         assert(m);
     504             : 
     505           0 :         r = transient_unit_set_properties(m, UNIT_AUTOMOUNT, arg_automount_property);
     506           0 :         if (r < 0)
     507           0 :                 return r;
     508             : 
     509           0 :         if (arg_timeout_idle != USEC_INFINITY) {
     510           0 :                 r = sd_bus_message_append(m, "(sv)", "TimeoutIdleUSec", "t", arg_timeout_idle);
     511           0 :                 if (r < 0)
     512           0 :                         return r;
     513             :         }
     514             : 
     515           0 :         return 0;
     516             : }
     517             : 
     518           0 : static int start_transient_mount(
     519             :                 sd_bus *bus,
     520             :                 char **argv) {
     521             : 
     522           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
     523           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     524           0 :         _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
     525           0 :         _cleanup_free_ char *mount_unit = NULL;
     526             :         int r;
     527             : 
     528           0 :         if (!arg_no_block) {
     529           0 :                 r = bus_wait_for_jobs_new(bus, &w);
     530           0 :                 if (r < 0)
     531           0 :                         return log_error_errno(r, "Could not watch jobs: %m");
     532             :         }
     533             : 
     534           0 :         r = unit_name_from_path(arg_mount_where, ".mount", &mount_unit);
     535           0 :         if (r < 0)
     536           0 :                 return log_error_errno(r, "Failed to make mount unit name: %m");
     537             : 
     538           0 :         r = sd_bus_message_new_method_call(
     539             :                         bus,
     540             :                         &m,
     541             :                         "org.freedesktop.systemd1",
     542             :                         "/org/freedesktop/systemd1",
     543             :                         "org.freedesktop.systemd1.Manager",
     544             :                         "StartTransientUnit");
     545           0 :         if (r < 0)
     546           0 :                 return bus_log_create_error(r);
     547             : 
     548           0 :         r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
     549           0 :         if (r < 0)
     550           0 :                 return bus_log_create_error(r);
     551             : 
     552             :         /* Name and mode */
     553           0 :         r = sd_bus_message_append(m, "ss", mount_unit, "fail");
     554           0 :         if (r < 0)
     555           0 :                 return bus_log_create_error(r);
     556             : 
     557             :         /* Properties */
     558           0 :         r = sd_bus_message_open_container(m, 'a', "(sv)");
     559           0 :         if (r < 0)
     560           0 :                 return bus_log_create_error(r);
     561             : 
     562           0 :         r = transient_mount_set_properties(m);
     563           0 :         if (r < 0)
     564           0 :                 return bus_log_create_error(r);
     565             : 
     566           0 :         r = sd_bus_message_close_container(m);
     567           0 :         if (r < 0)
     568           0 :                 return bus_log_create_error(r);
     569             : 
     570             :         /* Auxiliary units */
     571           0 :         r = sd_bus_message_append(m, "a(sa(sv))", 0);
     572           0 :         if (r < 0)
     573           0 :                 return bus_log_create_error(r);
     574             : 
     575           0 :         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
     576             : 
     577           0 :         r = sd_bus_call(bus, m, 0, &error, &reply);
     578           0 :         if (r < 0)
     579           0 :                 return log_error_errno(r, "Failed to start transient mount unit: %s", bus_error_message(&error, r));
     580             : 
     581           0 :         if (w) {
     582             :                 const char *object;
     583             : 
     584           0 :                 r = sd_bus_message_read(reply, "o", &object);
     585           0 :                 if (r < 0)
     586           0 :                         return bus_log_parse_error(r);
     587             : 
     588           0 :                 r = bus_wait_for_jobs_one(w, object, arg_quiet);
     589           0 :                 if (r < 0)
     590           0 :                         return r;
     591             :         }
     592             : 
     593           0 :         if (!arg_quiet)
     594           0 :                 log_info("Started unit %s%s%s for mount point: %s%s%s",
     595             :                          ansi_highlight(), mount_unit, ansi_normal(),
     596             :                          ansi_highlight(), arg_mount_where, ansi_normal());
     597             : 
     598           0 :         return 0;
     599             : }
     600             : 
     601           0 : static int start_transient_automount(
     602             :                 sd_bus *bus,
     603             :                 char **argv) {
     604             : 
     605           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
     606           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     607           0 :         _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
     608           0 :         _cleanup_free_ char *automount_unit = NULL, *mount_unit = NULL;
     609             :         int r;
     610             : 
     611           0 :         if (!arg_no_block) {
     612           0 :                 r = bus_wait_for_jobs_new(bus, &w);
     613           0 :                 if (r < 0)
     614           0 :                         return log_error_errno(r, "Could not watch jobs: %m");
     615             :         }
     616             : 
     617           0 :         r = unit_name_from_path(arg_mount_where, ".automount", &automount_unit);
     618           0 :         if (r < 0)
     619           0 :                 return log_error_errno(r, "Failed to make automount unit name: %m");
     620             : 
     621           0 :         r = unit_name_from_path(arg_mount_where, ".mount", &mount_unit);
     622           0 :         if (r < 0)
     623           0 :                 return log_error_errno(r, "Failed to make mount unit name: %m");
     624             : 
     625           0 :         r = sd_bus_message_new_method_call(
     626             :                         bus,
     627             :                         &m,
     628             :                         "org.freedesktop.systemd1",
     629             :                         "/org/freedesktop/systemd1",
     630             :                         "org.freedesktop.systemd1.Manager",
     631             :                         "StartTransientUnit");
     632           0 :         if (r < 0)
     633           0 :                 return bus_log_create_error(r);
     634             : 
     635           0 :         r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
     636           0 :         if (r < 0)
     637           0 :                 return bus_log_create_error(r);
     638             : 
     639             :         /* Name and mode */
     640           0 :         r = sd_bus_message_append(m, "ss", automount_unit, "fail");
     641           0 :         if (r < 0)
     642           0 :                 return bus_log_create_error(r);
     643             : 
     644             :         /* Properties */
     645           0 :         r = sd_bus_message_open_container(m, 'a', "(sv)");
     646           0 :         if (r < 0)
     647           0 :                 return bus_log_create_error(r);
     648             : 
     649           0 :         r = transient_automount_set_properties(m);
     650           0 :         if (r < 0)
     651           0 :                 return bus_log_create_error(r);
     652             : 
     653           0 :         r = sd_bus_message_close_container(m);
     654           0 :         if (r < 0)
     655           0 :                 return bus_log_create_error(r);
     656             : 
     657             :         /* Auxiliary units */
     658           0 :         r = sd_bus_message_open_container(m, 'a', "(sa(sv))");
     659           0 :         if (r < 0)
     660           0 :                 return bus_log_create_error(r);
     661             : 
     662           0 :         r = sd_bus_message_open_container(m, 'r', "sa(sv)");
     663           0 :         if (r < 0)
     664           0 :                 return bus_log_create_error(r);
     665             : 
     666           0 :         r = sd_bus_message_append(m, "s", mount_unit);
     667           0 :         if (r < 0)
     668           0 :                 return bus_log_create_error(r);
     669             : 
     670           0 :         r = sd_bus_message_open_container(m, 'a', "(sv)");
     671           0 :         if (r < 0)
     672           0 :                 return bus_log_create_error(r);
     673             : 
     674           0 :         r = transient_mount_set_properties(m);
     675           0 :         if (r < 0)
     676           0 :                 return bus_log_create_error(r);
     677             : 
     678           0 :         r = sd_bus_message_close_container(m);
     679           0 :         if (r < 0)
     680           0 :                 return bus_log_create_error(r);
     681             : 
     682           0 :         r = sd_bus_message_close_container(m);
     683           0 :         if (r < 0)
     684           0 :                 return bus_log_create_error(r);
     685             : 
     686           0 :         r = sd_bus_message_close_container(m);
     687           0 :         if (r < 0)
     688           0 :                 return bus_log_create_error(r);
     689             : 
     690           0 :         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
     691             : 
     692           0 :         r = sd_bus_call(bus, m, 0, &error, &reply);
     693           0 :         if (r < 0)
     694           0 :                 return log_error_errno(r, "Failed to start transient automount unit: %s", bus_error_message(&error, r));
     695             : 
     696           0 :         if (w) {
     697             :                 const char *object;
     698             : 
     699           0 :                 r = sd_bus_message_read(reply, "o", &object);
     700           0 :                 if (r < 0)
     701           0 :                         return bus_log_parse_error(r);
     702             : 
     703           0 :                 r = bus_wait_for_jobs_one(w, object, arg_quiet);
     704           0 :                 if (r < 0)
     705           0 :                         return r;
     706             :         }
     707             : 
     708           0 :         if (!arg_quiet)
     709           0 :                 log_info("Started unit %s%s%s for mount point: %s%s%s",
     710             :                          ansi_highlight(), automount_unit, ansi_normal(),
     711             :                          ansi_highlight(), arg_mount_where, ansi_normal());
     712             : 
     713           0 :         return 0;
     714             : }
     715             : 
     716           0 : static int find_mount_points(const char *what, char ***list) {
     717           0 :         _cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL;
     718           0 :         _cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL;
     719           0 :         _cleanup_strv_free_ char **l = NULL;
     720           0 :         size_t bufsize = 0, n = 0;
     721             :         int r;
     722             : 
     723           0 :         assert(what);
     724           0 :         assert(list);
     725             : 
     726             :         /* Returns all mount points obtained from /proc/self/mountinfo in *list,
     727             :          * and the number of mount points as return value. */
     728             : 
     729           0 :         r = libmount_parse(NULL, NULL, &table, &iter);
     730           0 :         if (r < 0)
     731           0 :                 return log_error_errno(r, "Failed to parse /proc/self/mountinfo: %m");
     732             : 
     733           0 :         for (;;) {
     734             :                 struct libmnt_fs *fs;
     735             :                 const char *source, *target;
     736             : 
     737           0 :                 r = mnt_table_next_fs(table, iter, &fs);
     738           0 :                 if (r == 1)
     739           0 :                         break;
     740           0 :                 if (r < 0)
     741           0 :                         return log_error_errno(r, "Failed to get next entry from /proc/self/mountinfo: %m");
     742             : 
     743           0 :                 source = mnt_fs_get_source(fs);
     744           0 :                 target = mnt_fs_get_target(fs);
     745           0 :                 if (!source || !target)
     746           0 :                         continue;
     747             : 
     748           0 :                 if (!path_equal(source, what))
     749           0 :                         continue;
     750             : 
     751             :                 /* one extra slot is needed for the terminating NULL */
     752           0 :                 if (!GREEDY_REALLOC0(l, bufsize, n + 2))
     753           0 :                         return log_oom();
     754             : 
     755           0 :                 l[n] = strdup(target);
     756           0 :                 if (!l[n])
     757           0 :                         return log_oom();
     758           0 :                 n++;
     759             :         }
     760             : 
     761           0 :         if (!GREEDY_REALLOC0(l, bufsize, n + 1))
     762           0 :                 return log_oom();
     763             : 
     764           0 :         *list = TAKE_PTR(l);
     765           0 :         return n;
     766             : }
     767             : 
     768           0 : static int find_loop_device(const char *backing_file, char **loop_dev) {
     769           0 :         _cleanup_closedir_ DIR *d = NULL;
     770             :         struct dirent *de;
     771           0 :         _cleanup_free_ char *l = NULL;
     772             : 
     773           0 :         assert(backing_file);
     774           0 :         assert(loop_dev);
     775             : 
     776           0 :         d = opendir("/sys/devices/virtual/block");
     777           0 :         if (!d)
     778           0 :                 return -errno;
     779             : 
     780           0 :         FOREACH_DIRENT(de, d, return -errno) {
     781           0 :                 _cleanup_free_ char *sys = NULL, *fname = NULL;
     782             :                 int r;
     783             : 
     784           0 :                 dirent_ensure_type(d, de);
     785             : 
     786           0 :                 if (de->d_type != DT_DIR)
     787           0 :                         continue;
     788             : 
     789           0 :                 if (!startswith(de->d_name, "loop"))
     790           0 :                         continue;
     791             : 
     792           0 :                 sys = path_join("/sys/devices/virtual/block", de->d_name, "loop/backing_file");
     793           0 :                 if (!sys)
     794           0 :                         return -ENOMEM;
     795             : 
     796           0 :                 r = read_one_line_file(sys, &fname);
     797           0 :                 if (r < 0) {
     798           0 :                         log_debug_errno(r, "Failed to read %s, ignoring: %m", sys);
     799           0 :                         continue;
     800             :                 }
     801             : 
     802           0 :                 if (files_same(fname, backing_file, 0) <= 0)
     803           0 :                         continue;
     804             : 
     805           0 :                 l = path_join("/dev", de->d_name);
     806           0 :                 if (!l)
     807           0 :                         return -ENOMEM;
     808             : 
     809           0 :                 break;
     810             :         }
     811             : 
     812           0 :         if (!l)
     813           0 :                 return -ENXIO;
     814             : 
     815           0 :         *loop_dev = TAKE_PTR(l);
     816             : 
     817           0 :         return 0;
     818             : }
     819             : 
     820           0 : static int stop_mount(
     821             :                 sd_bus *bus,
     822             :                 const char *where,
     823             :                 const char *suffix) {
     824             : 
     825           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
     826           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     827           0 :         _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
     828           0 :         _cleanup_free_ char *mount_unit = NULL;
     829             :         int r;
     830             : 
     831           0 :         if (!arg_no_block) {
     832           0 :                 r = bus_wait_for_jobs_new(bus, &w);
     833           0 :                 if (r < 0)
     834           0 :                         return log_error_errno(r, "Could not watch jobs: %m");
     835             :         }
     836             : 
     837           0 :         r = unit_name_from_path(where, suffix, &mount_unit);
     838           0 :         if (r < 0)
     839           0 :                 return log_error_errno(r, "Failed to make %s unit name from path %s: %m", suffix + 1, where);
     840             : 
     841           0 :         r = sd_bus_message_new_method_call(
     842             :                         bus,
     843             :                         &m,
     844             :                         "org.freedesktop.systemd1",
     845             :                         "/org/freedesktop/systemd1",
     846             :                         "org.freedesktop.systemd1.Manager",
     847             :                         "StopUnit");
     848           0 :         if (r < 0)
     849           0 :                 return bus_log_create_error(r);
     850             : 
     851           0 :         r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
     852           0 :         if (r < 0)
     853           0 :                 return bus_log_create_error(r);
     854             : 
     855             :         /* Name and mode */
     856           0 :         r = sd_bus_message_append(m, "ss", mount_unit, "fail");
     857           0 :         if (r < 0)
     858           0 :                 return bus_log_create_error(r);
     859             : 
     860           0 :         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
     861             : 
     862           0 :         r = sd_bus_call(bus, m, 0, &error, &reply);
     863           0 :         if (r < 0) {
     864           0 :                 if (streq(suffix, ".automount") &&
     865           0 :                     sd_bus_error_has_name(&error, "org.freedesktop.systemd1.NoSuchUnit"))
     866           0 :                         return 0;
     867           0 :                 return log_error_errno(r, "Failed to stop %s unit: %s", suffix + 1, bus_error_message(&error, r));
     868             :         }
     869             : 
     870           0 :         if (w) {
     871             :                 const char *object;
     872             : 
     873           0 :                 r = sd_bus_message_read(reply, "o", &object);
     874           0 :                 if (r < 0)
     875           0 :                         return bus_log_parse_error(r);
     876             : 
     877           0 :                 r = bus_wait_for_jobs_one(w, object, arg_quiet);
     878           0 :                 if (r < 0)
     879           0 :                         return r;
     880             :         }
     881             : 
     882           0 :         if (!arg_quiet)
     883           0 :                 log_info("Stopped unit %s%s%s for mount point: %s%s%s",
     884             :                          ansi_highlight(), mount_unit, ansi_normal(),
     885             :                          ansi_highlight(), where, ansi_normal());
     886             : 
     887           0 :         return 0;
     888             : }
     889             : 
     890           0 : static int stop_mounts(
     891             :                 sd_bus *bus,
     892             :                 const char *where) {
     893             : 
     894             :         int r;
     895             : 
     896           0 :         if (path_equal(where, "/"))
     897           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     898             :                                        "Refusing to operate on root directory: %s", where);
     899             : 
     900           0 :         if (!path_is_normalized(where))
     901           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     902             :                                        "Path contains non-normalized components: %s", where);
     903             : 
     904           0 :         r = stop_mount(bus, where, ".mount");
     905           0 :         if (r < 0)
     906           0 :                 return r;
     907             : 
     908           0 :         r = stop_mount(bus, where, ".automount");
     909           0 :         if (r < 0)
     910           0 :                 return r;
     911             : 
     912           0 :         return 0;
     913             : }
     914             : 
     915           0 : static int umount_by_device(sd_bus *bus, const char *what) {
     916           0 :         _cleanup_(sd_device_unrefp) sd_device *d = NULL;
     917           0 :         _cleanup_strv_free_ char **list = NULL;
     918             :         struct stat st;
     919             :         const char *v;
     920             :         char **l;
     921           0 :         int r, r2 = 0;
     922             : 
     923           0 :         assert(what);
     924             : 
     925           0 :         if (stat(what, &st) < 0)
     926           0 :                 return log_error_errno(errno, "Can't stat %s: %m", what);
     927             : 
     928           0 :         if (!S_ISBLK(st.st_mode)) {
     929           0 :                 log_error("Not a block device: %s", what);
     930           0 :                 return -ENOTBLK;
     931             :         }
     932             : 
     933           0 :         r = sd_device_new_from_devnum(&d, 'b', st.st_rdev);
     934           0 :         if (r < 0)
     935           0 :                 return log_error_errno(r, "Failed to get device from device number: %m");
     936             : 
     937           0 :         r = sd_device_get_property_value(d, "ID_FS_USAGE", &v);
     938           0 :         if (r < 0)
     939           0 :                 return log_device_error_errno(d, r, "Failed to get device property: %m");
     940             : 
     941           0 :         if (!streq(v, "filesystem")) {
     942           0 :                 log_device_error(d, "%s does not contain a known file system.", what);
     943           0 :                 return -EINVAL;
     944             :         }
     945             : 
     946           0 :         if (sd_device_get_property_value(d, "SYSTEMD_MOUNT_WHERE", &v) >= 0)
     947           0 :                 r2 = stop_mounts(bus, v);
     948             : 
     949           0 :         r = find_mount_points(what, &list);
     950           0 :         if (r < 0)
     951           0 :                 return r;
     952             : 
     953           0 :         for (l = list; *l; l++) {
     954           0 :                 r = stop_mounts(bus, *l);
     955           0 :                 if (r < 0)
     956           0 :                         r2 = r;
     957             :         }
     958             : 
     959           0 :         return r2;
     960             : }
     961             : 
     962           0 : static int umount_loop(sd_bus *bus, const char *backing_file) {
     963           0 :         _cleanup_free_ char *loop_dev = NULL;
     964             :         int r;
     965             : 
     966           0 :         assert(backing_file);
     967             : 
     968           0 :         r = find_loop_device(backing_file, &loop_dev);
     969           0 :         if (r < 0)
     970           0 :                 return log_error_errno(r, r == -ENXIO ? "File %s is not mounted." : "Can't get loop device for %s: %m", backing_file);
     971             : 
     972           0 :         return umount_by_device(bus, loop_dev);
     973             : }
     974             : 
     975           0 : static int action_umount(
     976             :                 sd_bus *bus,
     977             :                 int argc,
     978             :                 char **argv) {
     979             : 
     980           0 :         int i, r, r2 = 0;
     981             : 
     982           0 :         if (arg_transport != BUS_TRANSPORT_LOCAL) {
     983           0 :                 for (i = optind; i < argc; i++) {
     984           0 :                         _cleanup_free_ char *p = NULL;
     985             : 
     986           0 :                         p = strdup(argv[i]);
     987           0 :                         if (!p)
     988           0 :                                 return log_oom();
     989             : 
     990           0 :                         path_simplify(p, false);
     991             : 
     992           0 :                         r = stop_mounts(bus, p);
     993           0 :                         if (r < 0)
     994           0 :                                 r2 = r;
     995             :                 }
     996           0 :                 return r2;
     997             :         }
     998             : 
     999           0 :         for (i = optind; i < argc; i++) {
    1000           0 :                 _cleanup_free_ char *u = NULL, *p = NULL;
    1001             :                 struct stat st;
    1002             : 
    1003           0 :                 u = fstab_node_to_udev_node(argv[i]);
    1004           0 :                 if (!u)
    1005           0 :                         return log_oom();
    1006             : 
    1007           0 :                 r = chase_symlinks(u, NULL, 0, &p);
    1008           0 :                 if (r < 0) {
    1009           0 :                         r2 = log_error_errno(r, "Failed to make path %s absolute: %m", argv[i]);
    1010           0 :                         continue;
    1011             :                 }
    1012             : 
    1013           0 :                 if (stat(p, &st) < 0)
    1014           0 :                         return log_error_errno(errno, "Can't stat %s (from %s): %m", p, argv[i]);
    1015             : 
    1016           0 :                 if (S_ISBLK(st.st_mode))
    1017           0 :                         r = umount_by_device(bus, p);
    1018           0 :                 else if (S_ISREG(st.st_mode))
    1019           0 :                         r = umount_loop(bus, p);
    1020           0 :                 else if (S_ISDIR(st.st_mode))
    1021           0 :                         r = stop_mounts(bus, p);
    1022             :                 else {
    1023           0 :                         log_error("Invalid file type: %s (from %s)", p, argv[i]);
    1024           0 :                         r = -EINVAL;
    1025             :                 }
    1026             : 
    1027           0 :                 if (r < 0)
    1028           0 :                         r2 = r;
    1029             :         }
    1030             : 
    1031           0 :         return r2;
    1032             : }
    1033             : 
    1034           0 : static int acquire_mount_type(sd_device *d) {
    1035             :         const char *v;
    1036             : 
    1037           0 :         assert(d);
    1038             : 
    1039           0 :         if (arg_mount_type)
    1040           0 :                 return 0;
    1041             : 
    1042           0 :         if (sd_device_get_property_value(d, "ID_FS_TYPE", &v) < 0)
    1043           0 :                 return 0;
    1044             : 
    1045           0 :         arg_mount_type = strdup(v);
    1046           0 :         if (!arg_mount_type)
    1047           0 :                 return log_oom();
    1048             : 
    1049           0 :         log_debug("Discovered type=%s", arg_mount_type);
    1050           0 :         return 1;
    1051             : }
    1052             : 
    1053           0 : static int acquire_mount_options(sd_device *d) {
    1054             :         const char *v;
    1055             : 
    1056           0 :         assert(d);
    1057             : 
    1058           0 :         if (arg_mount_options)
    1059           0 :                 return 0;
    1060             : 
    1061           0 :         if (sd_device_get_property_value(d, "SYSTEMD_MOUNT_OPTIONS", &v) < 0)
    1062           0 :                 return 0;
    1063             : 
    1064           0 :         arg_mount_options = strdup(v);
    1065           0 :         if (!arg_mount_options)
    1066           0 :                 return log_oom();
    1067             : 
    1068           0 :         log_debug("Discovered options=%s", arg_mount_options);
    1069           0 :         return 1;
    1070             : }
    1071             : 
    1072           0 : static const char *get_model(sd_device *d) {
    1073             :         const char *model;
    1074             : 
    1075           0 :         assert(d);
    1076             : 
    1077           0 :         if (sd_device_get_property_value(d, "ID_MODEL_FROM_DATABASE", &model) >= 0)
    1078           0 :                 return model;
    1079             : 
    1080           0 :         if (sd_device_get_property_value(d, "ID_MODEL", &model) >= 0)
    1081           0 :                 return model;
    1082             : 
    1083           0 :         return NULL;
    1084             : }
    1085             : 
    1086           0 : static const char* get_label(sd_device *d) {
    1087             :         const char *label;
    1088             : 
    1089           0 :         assert(d);
    1090             : 
    1091           0 :         if (sd_device_get_property_value(d, "ID_FS_LABEL", &label) >= 0)
    1092           0 :                 return label;
    1093             : 
    1094           0 :         if (sd_device_get_property_value(d, "ID_PART_ENTRY_NAME", &label) >= 0)
    1095           0 :                 return label;
    1096             : 
    1097           0 :         return NULL;
    1098             : }
    1099             : 
    1100           0 : static int acquire_mount_where(sd_device *d) {
    1101             :         const char *v;
    1102             : 
    1103           0 :         if (arg_mount_where)
    1104           0 :                 return 0;
    1105             : 
    1106           0 :         if (sd_device_get_property_value(d, "SYSTEMD_MOUNT_WHERE", &v) < 0) {
    1107           0 :                 _cleanup_free_ char *escaped = NULL;
    1108             :                 const char *name;
    1109             : 
    1110           0 :                 name = get_label(d);
    1111           0 :                 if (!name)
    1112           0 :                         name = get_model(d);
    1113           0 :                 if (!name) {
    1114             :                         const char *dn;
    1115             : 
    1116           0 :                         if (sd_device_get_devname(d, &dn) < 0)
    1117           0 :                                 return 0;
    1118             : 
    1119           0 :                         name = basename(dn);
    1120             :                 }
    1121             : 
    1122           0 :                 escaped = xescape(name, "\\");
    1123           0 :                 if (!escaped)
    1124           0 :                         return log_oom();
    1125           0 :                 if (!filename_is_valid(escaped))
    1126           0 :                         return 0;
    1127             : 
    1128           0 :                 arg_mount_where = path_join("/run/media/system", escaped);
    1129             :         } else
    1130           0 :                 arg_mount_where = strdup(v);
    1131             : 
    1132           0 :         if (!arg_mount_where)
    1133           0 :                 return log_oom();
    1134             : 
    1135           0 :         log_debug("Discovered where=%s", arg_mount_where);
    1136           0 :         return 1;
    1137             : }
    1138             : 
    1139           0 : static int acquire_mount_where_for_loop_dev(const char *loop_dev) {
    1140           0 :         _cleanup_strv_free_ char **list = NULL;
    1141             :         int r;
    1142             : 
    1143           0 :         if (arg_mount_where)
    1144           0 :                 return 0;
    1145             : 
    1146           0 :         r = find_mount_points(loop_dev, &list);
    1147           0 :         if (r < 0)
    1148           0 :                 return r;
    1149           0 :         else if (r == 0)
    1150           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1151             :                                        "Can't find mount point of %s. It is expected that %s is already mounted on a place.",
    1152             :                                        loop_dev, loop_dev);
    1153           0 :         else if (r >= 2)
    1154           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1155             :                                        "%s is mounted on %d places. It is expected that %s is mounted on a place.",
    1156             :                                        loop_dev, r, loop_dev);
    1157             : 
    1158           0 :         arg_mount_where = strdup(list[0]);
    1159           0 :         if (!arg_mount_where)
    1160           0 :                 return log_oom();
    1161             : 
    1162           0 :         log_debug("Discovered where=%s", arg_mount_where);
    1163           0 :         return 1;
    1164             : }
    1165             : 
    1166           0 : static int acquire_description(sd_device *d) {
    1167             :         const char *model, *label;
    1168             : 
    1169           0 :         if (arg_description)
    1170           0 :                 return 0;
    1171             : 
    1172           0 :         model = get_model(d);
    1173             : 
    1174           0 :         label = get_label(d);
    1175           0 :         if (!label)
    1176           0 :                 (void) sd_device_get_property_value(d, "ID_PART_ENTRY_NUMBER", &label);
    1177             : 
    1178           0 :         if (model && label)
    1179           0 :                 arg_description = strjoin(model, " ", label);
    1180           0 :         else if (label)
    1181           0 :                 arg_description = strdup(label);
    1182           0 :         else if (model)
    1183           0 :                 arg_description = strdup(model);
    1184             :         else
    1185           0 :                 return 0;
    1186             : 
    1187           0 :         if (!arg_description)
    1188           0 :                 return log_oom();
    1189             : 
    1190           0 :         log_debug("Discovered description=%s", arg_description);
    1191           0 :         return 1;
    1192             : }
    1193             : 
    1194           0 : static int acquire_removable(sd_device *d) {
    1195             :         const char *v;
    1196             : 
    1197             :         /* Shortcut this if there's no reason to check it */
    1198           0 :         if (arg_action != ACTION_DEFAULT && arg_timeout_idle_set && arg_bind_device >= 0)
    1199           0 :                 return 0;
    1200             : 
    1201             :         for (;;) {
    1202           0 :                 if (sd_device_get_sysattr_value(d, "removable", &v) > 0)
    1203           0 :                         break;
    1204             : 
    1205           0 :                 if (sd_device_get_parent(d, &d) < 0)
    1206           0 :                         return 0;
    1207             : 
    1208           0 :                 if (sd_device_get_subsystem(d, &v) < 0 || !streq(v, "block"))
    1209           0 :                         return 0;
    1210             :         }
    1211             : 
    1212           0 :         if (parse_boolean(v) <= 0)
    1213           0 :                 return 0;
    1214             : 
    1215           0 :         log_debug("Discovered removable device.");
    1216             : 
    1217           0 :         if (arg_action == ACTION_DEFAULT) {
    1218           0 :                 log_debug("Automatically turning on automount.");
    1219           0 :                 arg_action = ACTION_AUTOMOUNT;
    1220             :         }
    1221             : 
    1222           0 :         if (!arg_timeout_idle_set) {
    1223           0 :                 log_debug("Setting idle timeout to 1s.");
    1224           0 :                 arg_timeout_idle = USEC_PER_SEC;
    1225             :         }
    1226             : 
    1227           0 :         if (arg_bind_device < 0) {
    1228           0 :                 log_debug("Binding automount unit to device.");
    1229           0 :                 arg_bind_device = true;
    1230             :         }
    1231             : 
    1232           0 :         return 1;
    1233             : }
    1234             : 
    1235           0 : static int discover_loop_backing_file(void) {
    1236           0 :         _cleanup_(sd_device_unrefp) sd_device *d = NULL;
    1237           0 :         _cleanup_free_ char *loop_dev = NULL;
    1238             :         struct stat st;
    1239             :         const char *v;
    1240             :         int r;
    1241             : 
    1242           0 :         r = find_loop_device(arg_mount_what, &loop_dev);
    1243           0 :         if (r < 0 && r != -ENXIO)
    1244           0 :                 return log_error_errno(errno, "Can't get loop device for %s: %m", arg_mount_what);
    1245             : 
    1246           0 :         if (r == -ENXIO) {
    1247           0 :                 _cleanup_free_ char *escaped = NULL;
    1248             : 
    1249           0 :                 if (arg_mount_where)
    1250           0 :                         return 0;
    1251             : 
    1252           0 :                 escaped = xescape(basename(arg_mount_what), "\\");
    1253           0 :                 if (!escaped)
    1254           0 :                         return log_oom();
    1255           0 :                 if (!filename_is_valid(escaped)) {
    1256           0 :                         log_error("Escaped name %s is not a valid filename.", escaped);
    1257           0 :                         return -EINVAL;
    1258             :                 }
    1259             : 
    1260           0 :                 arg_mount_where = path_join("/run/media/system", escaped);
    1261           0 :                 if (!arg_mount_where)
    1262           0 :                         return log_oom();
    1263             : 
    1264           0 :                 log_debug("Discovered where=%s", arg_mount_where);
    1265           0 :                 return 0;
    1266             :         }
    1267             : 
    1268           0 :         if (stat(loop_dev, &st) < 0)
    1269           0 :                 return log_error_errno(errno, "Can't stat %s: %m", loop_dev);
    1270             : 
    1271           0 :         if (!S_ISBLK(st.st_mode)) {
    1272           0 :                 log_error("Invalid file type: %s", loop_dev);
    1273           0 :                 return -EINVAL;
    1274             :         }
    1275             : 
    1276           0 :         r = sd_device_new_from_devnum(&d, 'b', st.st_rdev);
    1277           0 :         if (r < 0)
    1278           0 :                 return log_error_errno(r, "Failed to get device from device number: %m");
    1279             : 
    1280           0 :         if (sd_device_get_property_value(d, "ID_FS_USAGE", &v) < 0 || !streq(v, "filesystem")) {
    1281           0 :                 log_device_error(d, "%s does not contain a known file system.", arg_mount_what);
    1282           0 :                 return -EINVAL;
    1283             :         }
    1284             : 
    1285           0 :         r = acquire_mount_type(d);
    1286           0 :         if (r < 0)
    1287           0 :                 return r;
    1288             : 
    1289           0 :         r = acquire_mount_options(d);
    1290           0 :         if (r < 0)
    1291           0 :                 return r;
    1292             : 
    1293           0 :         r = acquire_mount_where_for_loop_dev(loop_dev);
    1294           0 :         if (r < 0)
    1295           0 :                 return r;
    1296             : 
    1297           0 :         r = acquire_description(d);
    1298           0 :         if (r < 0)
    1299           0 :                 return r;
    1300             : 
    1301           0 :         return 0;
    1302             : }
    1303             : 
    1304           0 : static int discover_device(void) {
    1305           0 :         _cleanup_(sd_device_unrefp) sd_device *d = NULL;
    1306             :         struct stat st;
    1307             :         const char *v;
    1308             :         int r;
    1309             : 
    1310           0 :         if (stat(arg_mount_what, &st) < 0)
    1311           0 :                 return log_error_errno(errno, "Can't stat %s: %m", arg_mount_what);
    1312             : 
    1313           0 :         if (S_ISREG(st.st_mode))
    1314           0 :                 return discover_loop_backing_file();
    1315             : 
    1316           0 :         if (!S_ISBLK(st.st_mode)) {
    1317           0 :                 log_error("Invalid file type: %s", arg_mount_what);
    1318           0 :                 return -EINVAL;
    1319             :         }
    1320             : 
    1321           0 :         r = sd_device_new_from_devnum(&d, 'b', st.st_rdev);
    1322           0 :         if (r < 0)
    1323           0 :                 return log_error_errno(r, "Failed to get device from device number: %m");
    1324             : 
    1325           0 :         if (sd_device_get_property_value(d, "ID_FS_USAGE", &v) < 0 || !streq(v, "filesystem")) {
    1326           0 :                 log_error("%s does not contain a known file system.", arg_mount_what);
    1327           0 :                 return -EINVAL;
    1328             :         }
    1329             : 
    1330           0 :         r = acquire_mount_type(d);
    1331           0 :         if (r < 0)
    1332           0 :                 return r;
    1333             : 
    1334           0 :         r = acquire_mount_options(d);
    1335           0 :         if (r < 0)
    1336           0 :                 return r;
    1337             : 
    1338           0 :         r = acquire_mount_where(d);
    1339           0 :         if (r < 0)
    1340           0 :                 return r;
    1341             : 
    1342           0 :         r = acquire_description(d);
    1343           0 :         if (r < 0)
    1344           0 :                 return r;
    1345             : 
    1346           0 :         r = acquire_removable(d);
    1347           0 :         if (r < 0)
    1348           0 :                 return r;
    1349             : 
    1350           0 :         return 0;
    1351             : }
    1352             : 
    1353             : enum {
    1354             :         COLUMN_NODE,
    1355             :         COLUMN_PATH,
    1356             :         COLUMN_MODEL,
    1357             :         COLUMN_WWN,
    1358             :         COLUMN_FSTYPE,
    1359             :         COLUMN_LABEL,
    1360             :         COLUMN_UUID,
    1361             :         _COLUMN_MAX,
    1362             : };
    1363             : 
    1364             : struct item {
    1365             :         char* columns[_COLUMN_MAX];
    1366             : };
    1367             : 
    1368           0 : static int compare_item(const struct item *a, const struct item *b) {
    1369           0 :         if (a->columns[COLUMN_NODE] == b->columns[COLUMN_NODE])
    1370           0 :                 return 0;
    1371           0 :         if (!a->columns[COLUMN_NODE])
    1372           0 :                 return 1;
    1373           0 :         if (!b->columns[COLUMN_NODE])
    1374           0 :                 return -1;
    1375             : 
    1376           0 :         return path_compare(a->columns[COLUMN_NODE], b->columns[COLUMN_NODE]);
    1377             : }
    1378             : 
    1379           0 : static int list_devices(void) {
    1380             : 
    1381             :         static const char * const titles[_COLUMN_MAX] = {
    1382             :                 [COLUMN_NODE] = "NODE",
    1383             :                 [COLUMN_PATH] = "PATH",
    1384             :                 [COLUMN_MODEL] = "MODEL",
    1385             :                 [COLUMN_WWN] = "WWN",
    1386             :                 [COLUMN_FSTYPE] = "TYPE",
    1387             :                 [COLUMN_LABEL] = "LABEL",
    1388             :                 [COLUMN_UUID] = "UUID"
    1389             :         };
    1390             : 
    1391           0 :         _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
    1392           0 :         size_t n_allocated = 0, n = 0, i;
    1393             :         size_t column_width[_COLUMN_MAX];
    1394           0 :         struct item *items = NULL;
    1395             :         sd_device *d;
    1396             :         unsigned c;
    1397             :         int r;
    1398             : 
    1399           0 :         for (c = 0; c < _COLUMN_MAX; c++)
    1400           0 :                 column_width[c] = strlen(titles[c]);
    1401             : 
    1402           0 :         r = sd_device_enumerator_new(&e);
    1403           0 :         if (r < 0)
    1404           0 :                 return log_oom();
    1405             : 
    1406           0 :         r = sd_device_enumerator_add_match_subsystem(e, "block", true);
    1407           0 :         if (r < 0)
    1408           0 :                 return log_error_errno(r, "Failed to add block match: %m");
    1409             : 
    1410           0 :         r = sd_device_enumerator_add_match_property(e, "ID_FS_USAGE", "filesystem");
    1411           0 :         if (r < 0)
    1412           0 :                 return log_error_errno(r, "Failed to add property match: %m");
    1413             : 
    1414           0 :         FOREACH_DEVICE(e, d) {
    1415             :                 struct item *j;
    1416             : 
    1417           0 :                 if (!GREEDY_REALLOC0(items, n_allocated, n+1)) {
    1418           0 :                         r = log_oom();
    1419           0 :                         goto finish;
    1420             :                 }
    1421             : 
    1422           0 :                 j = items + n++;
    1423             : 
    1424           0 :                 for (c = 0; c < _COLUMN_MAX; c++) {
    1425           0 :                         const char *x = NULL;
    1426             :                         size_t k;
    1427             : 
    1428           0 :                         switch (c) {
    1429             : 
    1430           0 :                         case COLUMN_NODE:
    1431           0 :                                 (void) sd_device_get_devname(d, &x);
    1432           0 :                                 break;
    1433             : 
    1434           0 :                         case COLUMN_PATH:
    1435           0 :                                 (void) sd_device_get_property_value(d, "ID_PATH", &x);
    1436           0 :                                 break;
    1437             : 
    1438           0 :                         case COLUMN_MODEL:
    1439           0 :                                 x = get_model(d);
    1440           0 :                                 break;
    1441             : 
    1442           0 :                         case COLUMN_WWN:
    1443           0 :                                 (void) sd_device_get_property_value(d, "ID_WWN", &x);
    1444           0 :                                 break;
    1445             : 
    1446           0 :                         case COLUMN_FSTYPE:
    1447           0 :                                 (void) sd_device_get_property_value(d, "ID_FS_TYPE", &x);
    1448           0 :                                 break;
    1449             : 
    1450           0 :                         case COLUMN_LABEL:
    1451           0 :                                 x = get_label(d);
    1452           0 :                                 break;
    1453             : 
    1454           0 :                         case COLUMN_UUID:
    1455           0 :                                 (void) sd_device_get_property_value(d, "ID_FS_UUID", &x);
    1456           0 :                                 break;
    1457             :                         }
    1458             : 
    1459           0 :                         if (isempty(x))
    1460           0 :                                 continue;
    1461             : 
    1462           0 :                         j->columns[c] = strdup(x);
    1463           0 :                         if (!j->columns[c]) {
    1464           0 :                                 r = log_oom();
    1465           0 :                                 goto finish;
    1466             :                         }
    1467             : 
    1468           0 :                         k = strlen(x);
    1469           0 :                         if (k > column_width[c])
    1470           0 :                                 column_width[c] = k;
    1471             :                 }
    1472             :         }
    1473             : 
    1474           0 :         if (n == 0) {
    1475           0 :                 log_info("No devices found.");
    1476           0 :                 goto finish;
    1477             :         }
    1478             : 
    1479           0 :         typesafe_qsort(items, n, compare_item);
    1480             : 
    1481           0 :         (void) pager_open(arg_pager_flags);
    1482             : 
    1483           0 :         fputs(ansi_underline(), stdout);
    1484           0 :         for (c = 0; c < _COLUMN_MAX; c++) {
    1485           0 :                 if (c > 0)
    1486           0 :                         fputc(' ', stdout);
    1487             : 
    1488           0 :                 printf("%-*s", (int) column_width[c], titles[c]);
    1489             :         }
    1490           0 :         fputs(ansi_normal(), stdout);
    1491           0 :         fputc('\n', stdout);
    1492             : 
    1493           0 :         for (i = 0; i < n; i++) {
    1494           0 :                 for (c = 0; c < _COLUMN_MAX; c++) {
    1495           0 :                         if (c > 0)
    1496           0 :                                 fputc(' ', stdout);
    1497             : 
    1498           0 :                         printf("%-*s", (int) column_width[c], strna(items[i].columns[c]));
    1499             :                 }
    1500           0 :                 fputc('\n', stdout);
    1501             :         }
    1502             : 
    1503           0 :         r = 0;
    1504             : 
    1505           0 : finish:
    1506           0 :         for (i = 0; i < n; i++)
    1507           0 :                 for (c = 0; c < _COLUMN_MAX; c++)
    1508           0 :                         free(items[i].columns[c]);
    1509             : 
    1510           0 :         free(items);
    1511           0 :         return r;
    1512             : }
    1513             : 
    1514           4 : static int run(int argc, char* argv[]) {
    1515           4 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    1516             :         int r;
    1517             : 
    1518           4 :         log_show_color(true);
    1519           4 :         log_parse_environment();
    1520           4 :         log_open();
    1521             : 
    1522           4 :         r = parse_argv(argc, argv);
    1523           4 :         if (r <= 0)
    1524           4 :                 return r;
    1525             : 
    1526           0 :         if (arg_action == ACTION_LIST)
    1527           0 :                 return list_devices();
    1528             : 
    1529           0 :         r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus);
    1530           0 :         if (r < 0)
    1531           0 :                 return log_error_errno(r, "Failed to create bus connection: %m");
    1532             : 
    1533           0 :         if (arg_action == ACTION_UMOUNT)
    1534           0 :                 return action_umount(bus, argc, argv);
    1535             : 
    1536           0 :         if ((!arg_mount_type || !fstype_is_network(arg_mount_type))
    1537           0 :             && !path_is_normalized(arg_mount_what)) {
    1538           0 :                 log_error("Path contains non-normalized components: %s", arg_mount_what);
    1539           0 :                 return -EINVAL;
    1540             :         }
    1541             : 
    1542           0 :         if (arg_discover) {
    1543           0 :                 r = discover_device();
    1544           0 :                 if (r < 0)
    1545           0 :                         return r;
    1546             :         }
    1547             : 
    1548           0 :         if (!arg_mount_where) {
    1549           0 :                 log_error("Can't figure out where to mount %s.", arg_mount_what);
    1550           0 :                 return -EINVAL;
    1551             :         }
    1552             : 
    1553           0 :         if (path_equal(arg_mount_where, "/")) {
    1554           0 :                 log_error("Refusing to operate on root directory.");
    1555           0 :                 return -EINVAL;
    1556             :         }
    1557             : 
    1558           0 :         if (!path_is_normalized(arg_mount_where)) {
    1559           0 :                 log_error("Path contains non-normalized components: %s", arg_mount_where);
    1560           0 :                 return -EINVAL;
    1561             :         }
    1562             : 
    1563           0 :         if (streq_ptr(arg_mount_type, "auto"))
    1564           0 :                 arg_mount_type = mfree(arg_mount_type);
    1565           0 :         if (streq_ptr(arg_mount_options, "defaults"))
    1566           0 :                 arg_mount_options = mfree(arg_mount_options);
    1567             : 
    1568           0 :         if (!is_device_path(arg_mount_what))
    1569           0 :                 arg_fsck = false;
    1570             : 
    1571           0 :         if (arg_fsck && arg_mount_type && arg_transport == BUS_TRANSPORT_LOCAL) {
    1572           0 :                 r = fsck_exists(arg_mount_type);
    1573           0 :                 if (r < 0)
    1574           0 :                         log_warning_errno(r, "Couldn't determine whether fsck for %s exists, proceeding anyway.", arg_mount_type);
    1575           0 :                 else if (r == 0) {
    1576           0 :                         log_debug("Disabling file system check as fsck for %s doesn't exist.", arg_mount_type);
    1577           0 :                         arg_fsck = false; /* fsck doesn't exist, let's not attempt it */
    1578             :                 }
    1579             :         }
    1580             : 
    1581             :         /* The kernel (properly) refuses mounting file systems with unknown uid=,gid= options,
    1582             :          * but not for all filesystem types. Let's try to catch the cases where the option
    1583             :          * would be used if the file system does not support it. It is also possible to
    1584             :          * autodetect the file system, but that's only possible with disk-based file systems
    1585             :          * which incidentally seem to be implemented more carefully and reject unknown options,
    1586             :          * so it's probably OK that we do the check only when the type is specified.
    1587             :          */
    1588           0 :         if (arg_mount_type &&
    1589           0 :             !streq(arg_mount_type, "auto") &&
    1590           0 :             arg_uid != UID_INVALID &&
    1591           0 :             !fstype_can_uid_gid(arg_mount_type)) {
    1592           0 :                 log_error("File system type %s is not known to support uid=/gid=, refusing.",
    1593             :                           arg_mount_type);
    1594           0 :                 return -EOPNOTSUPP;
    1595             :         }
    1596             : 
    1597           0 :         switch (arg_action) {
    1598             : 
    1599           0 :         case ACTION_MOUNT:
    1600             :         case ACTION_DEFAULT:
    1601           0 :                 r = start_transient_mount(bus, argv + optind);
    1602           0 :                 break;
    1603             : 
    1604           0 :         case ACTION_AUTOMOUNT:
    1605           0 :                 r = start_transient_automount(bus, argv + optind);
    1606           0 :                 break;
    1607             : 
    1608           0 :         default:
    1609           0 :                 assert_not_reached("Unexpected action.");
    1610             :         }
    1611             : 
    1612           0 :         return r;
    1613             : }
    1614             : 
    1615           4 : DEFINE_MAIN_FUNCTION(run);

Generated by: LCOV version 1.14