LCOV - code coverage report
Current view: top level - core - automount.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 9 581 1.5 %
Date: 2019-08-23 13:36:53 Functions: 4 41 9.8 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 7 617 1.1 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <errno.h>
       4                 :            : #include <fcntl.h>
       5                 :            : #include <limits.h>
       6                 :            : #include <linux/auto_dev-ioctl.h>
       7                 :            : #include <linux/auto_fs4.h>
       8                 :            : #include <sys/epoll.h>
       9                 :            : #include <sys/mount.h>
      10                 :            : #include <sys/stat.h>
      11                 :            : #include <unistd.h>
      12                 :            : 
      13                 :            : #include "alloc-util.h"
      14                 :            : #include "async.h"
      15                 :            : #include "automount.h"
      16                 :            : #include "bus-error.h"
      17                 :            : #include "bus-util.h"
      18                 :            : #include "dbus-automount.h"
      19                 :            : #include "dbus-unit.h"
      20                 :            : #include "fd-util.h"
      21                 :            : #include "format-util.h"
      22                 :            : #include "io-util.h"
      23                 :            : #include "label.h"
      24                 :            : #include "mkdir.h"
      25                 :            : #include "mount-util.h"
      26                 :            : #include "mount.h"
      27                 :            : #include "mountpoint-util.h"
      28                 :            : #include "parse-util.h"
      29                 :            : #include "path-util.h"
      30                 :            : #include "process-util.h"
      31                 :            : #include "serialize.h"
      32                 :            : #include "special.h"
      33                 :            : #include "stdio-util.h"
      34                 :            : #include "string-table.h"
      35                 :            : #include "string-util.h"
      36                 :            : #include "unit-name.h"
      37                 :            : #include "unit.h"
      38                 :            : 
      39                 :            : static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = {
      40                 :            :         [AUTOMOUNT_DEAD] = UNIT_INACTIVE,
      41                 :            :         [AUTOMOUNT_WAITING] = UNIT_ACTIVE,
      42                 :            :         [AUTOMOUNT_RUNNING] = UNIT_ACTIVE,
      43                 :            :         [AUTOMOUNT_FAILED] = UNIT_FAILED
      44                 :            : };
      45                 :            : 
      46                 :            : struct expire_data {
      47                 :            :         int dev_autofs_fd;
      48                 :            :         int ioctl_fd;
      49                 :            : };
      50                 :            : 
      51                 :          0 : static void expire_data_free(struct expire_data *data) {
      52         [ #  # ]:          0 :         if (!data)
      53                 :          0 :                 return;
      54                 :            : 
      55                 :          0 :         safe_close(data->dev_autofs_fd);
      56                 :          0 :         safe_close(data->ioctl_fd);
      57                 :          0 :         free(data);
      58                 :            : }
      59                 :            : 
      60         [ #  # ]:          0 : DEFINE_TRIVIAL_CLEANUP_FUNC(struct expire_data*, expire_data_free);
      61                 :            : 
      62                 :            : static int open_dev_autofs(Manager *m);
      63                 :            : static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata);
      64                 :            : static int automount_start_expire(Automount *a);
      65                 :            : static void automount_stop_expire(Automount *a);
      66                 :            : static int automount_send_ready(Automount *a, Set *tokens, int status);
      67                 :            : 
      68                 :          0 : static void automount_init(Unit *u) {
      69                 :          0 :         Automount *a = AUTOMOUNT(u);
      70                 :            : 
      71         [ #  # ]:          0 :         assert(u);
      72         [ #  # ]:          0 :         assert(u->load_state == UNIT_STUB);
      73                 :            : 
      74                 :          0 :         a->pipe_fd = -1;
      75                 :          0 :         a->directory_mode = 0755;
      76         [ #  # ]:          0 :         UNIT(a)->ignore_on_isolate = true;
      77                 :          0 : }
      78                 :            : 
      79                 :          0 : static void unmount_autofs(Automount *a) {
      80                 :            :         int r;
      81                 :            : 
      82         [ #  # ]:          0 :         assert(a);
      83                 :            : 
      84         [ #  # ]:          0 :         if (a->pipe_fd < 0)
      85                 :          0 :                 return;
      86                 :            : 
      87                 :          0 :         a->pipe_event_source = sd_event_source_unref(a->pipe_event_source);
      88                 :          0 :         a->pipe_fd = safe_close(a->pipe_fd);
      89                 :            : 
      90                 :            :         /* If we reload/reexecute things we keep the mount point around */
      91   [ #  #  #  #  :          0 :         if (!IN_SET(UNIT(a)->manager->objective, MANAGER_RELOAD, MANAGER_REEXECUTE)) {
                   #  # ]
      92                 :            : 
      93                 :          0 :                 automount_send_ready(a, a->tokens, -EHOSTDOWN);
      94                 :          0 :                 automount_send_ready(a, a->expire_tokens, -EHOSTDOWN);
      95                 :            : 
      96         [ #  # ]:          0 :                 if (a->where) {
      97                 :          0 :                         r = repeat_unmount(a->where, MNT_DETACH);
      98         [ #  # ]:          0 :                         if (r < 0)
      99         [ #  # ]:          0 :                                 log_error_errno(r, "Failed to unmount: %m");
     100                 :            :                 }
     101                 :            :         }
     102                 :            : }
     103                 :            : 
     104                 :          0 : static void automount_done(Unit *u) {
     105                 :          0 :         Automount *a = AUTOMOUNT(u);
     106                 :            : 
     107         [ #  # ]:          0 :         assert(a);
     108                 :            : 
     109                 :          0 :         unmount_autofs(a);
     110                 :            : 
     111                 :          0 :         a->where = mfree(a->where);
     112                 :            : 
     113                 :          0 :         a->tokens = set_free(a->tokens);
     114                 :          0 :         a->expire_tokens = set_free(a->expire_tokens);
     115                 :            : 
     116                 :          0 :         a->expire_event_source = sd_event_source_unref(a->expire_event_source);
     117                 :          0 : }
     118                 :            : 
     119                 :          0 : static int automount_add_trigger_dependencies(Automount *a) {
     120                 :            :         Unit *x;
     121                 :            :         int r;
     122                 :            : 
     123         [ #  # ]:          0 :         assert(a);
     124                 :            : 
     125         [ #  # ]:          0 :         r = unit_load_related_unit(UNIT(a), ".mount", &x);
     126         [ #  # ]:          0 :         if (r < 0)
     127                 :          0 :                 return r;
     128                 :            : 
     129         [ #  # ]:          0 :         return unit_add_two_dependencies(UNIT(a), UNIT_BEFORE, UNIT_TRIGGERS, x, true, UNIT_DEPENDENCY_IMPLICIT);
     130                 :            : }
     131                 :            : 
     132                 :          0 : static int automount_add_mount_dependencies(Automount *a) {
     133                 :          0 :         _cleanup_free_ char *parent = NULL;
     134                 :            : 
     135         [ #  # ]:          0 :         assert(a);
     136                 :            : 
     137                 :          0 :         parent = dirname_malloc(a->where);
     138         [ #  # ]:          0 :         if (!parent)
     139                 :          0 :                 return -ENOMEM;
     140                 :            : 
     141         [ #  # ]:          0 :         return unit_require_mounts_for(UNIT(a), parent, UNIT_DEPENDENCY_IMPLICIT);
     142                 :            : }
     143                 :            : 
     144                 :          0 : static int automount_add_default_dependencies(Automount *a) {
     145                 :            :         int r;
     146                 :            : 
     147         [ #  # ]:          0 :         assert(a);
     148                 :            : 
     149   [ #  #  #  # ]:          0 :         if (!UNIT(a)->default_dependencies)
     150                 :          0 :                 return 0;
     151                 :            : 
     152   [ #  #  #  # ]:          0 :         if (!MANAGER_IS_SYSTEM(UNIT(a)->manager))
     153                 :          0 :                 return 0;
     154                 :            : 
     155         [ #  # ]:          0 :         r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
     156         [ #  # ]:          0 :         if (r < 0)
     157                 :          0 :                 return r;
     158                 :            : 
     159                 :          0 :         return 0;
     160                 :            : }
     161                 :            : 
     162                 :          0 : static int automount_verify(Automount *a) {
     163                 :          0 :         _cleanup_free_ char *e = NULL;
     164                 :            :         int r;
     165                 :            : 
     166         [ #  # ]:          0 :         assert(a);
     167                 :            : 
     168   [ #  #  #  # ]:          0 :         if (UNIT(a)->load_state != UNIT_LOADED)
     169                 :          0 :                 return 0;
     170                 :            : 
     171         [ #  # ]:          0 :         if (path_equal(a->where, "/")) {
     172   [ #  #  #  # ]:          0 :                 log_unit_error(UNIT(a), "Cannot have an automount unit for the root directory. Refusing.");
     173                 :          0 :                 return -ENOEXEC;
     174                 :            :         }
     175                 :            : 
     176                 :          0 :         r = unit_name_from_path(a->where, ".automount", &e);
     177         [ #  # ]:          0 :         if (r < 0)
     178   [ #  #  #  # ]:          0 :                 return log_unit_error_errno(UNIT(a), r, "Failed to generate unit name from path: %m");
     179                 :            : 
     180   [ #  #  #  # ]:          0 :         if (!unit_has_name(UNIT(a), e)) {
     181   [ #  #  #  # ]:          0 :                 log_unit_error(UNIT(a), "Where= setting doesn't match unit name. Refusing.");
     182                 :          0 :                 return -ENOEXEC;
     183                 :            :         }
     184                 :            : 
     185                 :          0 :         return 0;
     186                 :            : }
     187                 :            : 
     188                 :          0 : static int automount_set_where(Automount *a) {
     189                 :            :         int r;
     190                 :            : 
     191         [ #  # ]:          0 :         assert(a);
     192                 :            : 
     193         [ #  # ]:          0 :         if (a->where)
     194                 :          0 :                 return 0;
     195                 :            : 
     196         [ #  # ]:          0 :         r = unit_name_to_path(UNIT(a)->id, &a->where);
     197         [ #  # ]:          0 :         if (r < 0)
     198                 :          0 :                 return r;
     199                 :            : 
     200                 :          0 :         path_simplify(a->where, false);
     201                 :          0 :         return 1;
     202                 :            : }
     203                 :            : 
     204                 :          0 : static int automount_load(Unit *u) {
     205                 :          0 :         Automount *a = AUTOMOUNT(u);
     206                 :            :         int r;
     207                 :            : 
     208         [ #  # ]:          0 :         assert(u);
     209         [ #  # ]:          0 :         assert(u->load_state == UNIT_STUB);
     210                 :            : 
     211                 :            :         /* Load a .automount file */
     212                 :          0 :         r = unit_load_fragment_and_dropin(u);
     213         [ #  # ]:          0 :         if (r < 0)
     214                 :          0 :                 return r;
     215                 :            : 
     216         [ #  # ]:          0 :         if (u->load_state == UNIT_LOADED) {
     217                 :          0 :                 r = automount_set_where(a);
     218         [ #  # ]:          0 :                 if (r < 0)
     219                 :          0 :                         return r;
     220                 :            : 
     221                 :          0 :                 r = automount_add_trigger_dependencies(a);
     222         [ #  # ]:          0 :                 if (r < 0)
     223                 :          0 :                         return r;
     224                 :            : 
     225                 :          0 :                 r = automount_add_mount_dependencies(a);
     226         [ #  # ]:          0 :                 if (r < 0)
     227                 :          0 :                         return r;
     228                 :            : 
     229                 :          0 :                 r = automount_add_default_dependencies(a);
     230         [ #  # ]:          0 :                 if (r < 0)
     231                 :          0 :                         return r;
     232                 :            :         }
     233                 :            : 
     234                 :          0 :         return automount_verify(a);
     235                 :            : }
     236                 :            : 
     237                 :          0 : static void automount_set_state(Automount *a, AutomountState state) {
     238                 :            :         AutomountState old_state;
     239         [ #  # ]:          0 :         assert(a);
     240                 :            : 
     241         [ #  # ]:          0 :         if (a->state != state)
     242         [ #  # ]:          0 :                 bus_unit_send_pending_change_signal(UNIT(a), false);
     243                 :            : 
     244                 :          0 :         old_state = a->state;
     245                 :          0 :         a->state = state;
     246                 :            : 
     247         [ #  # ]:          0 :         if (state != AUTOMOUNT_RUNNING)
     248                 :          0 :                 automount_stop_expire(a);
     249                 :            : 
     250   [ #  #  #  # ]:          0 :         if (!IN_SET(state, AUTOMOUNT_WAITING, AUTOMOUNT_RUNNING))
     251                 :          0 :                 unmount_autofs(a);
     252                 :            : 
     253         [ #  # ]:          0 :         if (state != old_state)
     254   [ #  #  #  # ]:          0 :                 log_unit_debug(UNIT(a), "Changed %s -> %s", automount_state_to_string(old_state), automount_state_to_string(state));
     255                 :            : 
     256         [ #  # ]:          0 :         unit_notify(UNIT(a), state_translation_table[old_state], state_translation_table[state], 0);
     257                 :          0 : }
     258                 :            : 
     259                 :          0 : static int automount_coldplug(Unit *u) {
     260                 :          0 :         Automount *a = AUTOMOUNT(u);
     261                 :            :         int r;
     262                 :            : 
     263         [ #  # ]:          0 :         assert(a);
     264         [ #  # ]:          0 :         assert(a->state == AUTOMOUNT_DEAD);
     265                 :            : 
     266         [ #  # ]:          0 :         if (a->deserialized_state == a->state)
     267                 :          0 :                 return 0;
     268                 :            : 
     269   [ #  #  #  # ]:          0 :         if (IN_SET(a->deserialized_state, AUTOMOUNT_WAITING, AUTOMOUNT_RUNNING)) {
     270                 :            : 
     271                 :          0 :                 r = automount_set_where(a);
     272         [ #  # ]:          0 :                 if (r < 0)
     273                 :          0 :                         return r;
     274                 :            : 
     275                 :          0 :                 r = open_dev_autofs(u->manager);
     276         [ #  # ]:          0 :                 if (r < 0)
     277                 :          0 :                         return r;
     278                 :            : 
     279         [ #  # ]:          0 :                 assert(a->pipe_fd >= 0);
     280                 :            : 
     281                 :          0 :                 r = sd_event_add_io(u->manager->event, &a->pipe_event_source, a->pipe_fd, EPOLLIN, automount_dispatch_io, u);
     282         [ #  # ]:          0 :                 if (r < 0)
     283                 :          0 :                         return r;
     284                 :            : 
     285                 :          0 :                 (void) sd_event_source_set_description(a->pipe_event_source, "automount-io");
     286         [ #  # ]:          0 :                 if (a->deserialized_state == AUTOMOUNT_RUNNING) {
     287                 :          0 :                         r = automount_start_expire(a);
     288         [ #  # ]:          0 :                         if (r < 0)
     289   [ #  #  #  # ]:          0 :                                 log_unit_warning_errno(UNIT(a), r, "Failed to start expiration timer, ignoring: %m");
     290                 :            :                 }
     291                 :            : 
     292                 :          0 :                 automount_set_state(a, a->deserialized_state);
     293                 :            :         }
     294                 :            : 
     295                 :          0 :         return 0;
     296                 :            : }
     297                 :            : 
     298                 :          0 : static void automount_dump(Unit *u, FILE *f, const char *prefix) {
     299                 :            :         char time_string[FORMAT_TIMESPAN_MAX];
     300                 :          0 :         Automount *a = AUTOMOUNT(u);
     301                 :            : 
     302         [ #  # ]:          0 :         assert(a);
     303                 :            : 
     304                 :          0 :         fprintf(f,
     305                 :            :                 "%sAutomount State: %s\n"
     306                 :            :                 "%sResult: %s\n"
     307                 :            :                 "%sWhere: %s\n"
     308                 :            :                 "%sDirectoryMode: %04o\n"
     309                 :            :                 "%sTimeoutIdleUSec: %s\n",
     310                 :            :                 prefix, automount_state_to_string(a->state),
     311                 :            :                 prefix, automount_result_to_string(a->result),
     312                 :            :                 prefix, a->where,
     313                 :            :                 prefix, a->directory_mode,
     314                 :            :                 prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, a->timeout_idle_usec, USEC_PER_SEC));
     315                 :          0 : }
     316                 :            : 
     317                 :          0 : static void automount_enter_dead(Automount *a, AutomountResult f) {
     318         [ #  # ]:          0 :         assert(a);
     319                 :            : 
     320         [ #  # ]:          0 :         if (a->result == AUTOMOUNT_SUCCESS)
     321                 :          0 :                 a->result = f;
     322                 :            : 
     323         [ #  # ]:          0 :         unit_log_result(UNIT(a), a->result == AUTOMOUNT_SUCCESS, automount_result_to_string(a->result));
     324         [ #  # ]:          0 :         automount_set_state(a, a->result != AUTOMOUNT_SUCCESS ? AUTOMOUNT_FAILED : AUTOMOUNT_DEAD);
     325                 :          0 : }
     326                 :            : 
     327                 :          0 : static int open_dev_autofs(Manager *m) {
     328                 :            :         struct autofs_dev_ioctl param;
     329                 :            : 
     330         [ #  # ]:          0 :         assert(m);
     331                 :            : 
     332         [ #  # ]:          0 :         if (m->dev_autofs_fd >= 0)
     333                 :          0 :                 return m->dev_autofs_fd;
     334                 :            : 
     335                 :          0 :         (void) label_fix("/dev/autofs", 0);
     336                 :            : 
     337                 :          0 :         m->dev_autofs_fd = open("/dev/autofs", O_CLOEXEC|O_RDONLY);
     338         [ #  # ]:          0 :         if (m->dev_autofs_fd < 0)
     339         [ #  # ]:          0 :                 return log_error_errno(errno, "Failed to open /dev/autofs: %m");
     340                 :            : 
     341                 :          0 :         init_autofs_dev_ioctl(&param);
     342         [ #  # ]:          0 :         if (ioctl(m->dev_autofs_fd, AUTOFS_DEV_IOCTL_VERSION, &param) < 0) {
     343                 :          0 :                 m->dev_autofs_fd = safe_close(m->dev_autofs_fd);
     344                 :          0 :                 return -errno;
     345                 :            :         }
     346                 :            : 
     347         [ #  # ]:          0 :         log_debug("Autofs kernel version %i.%i", param.ver_major, param.ver_minor);
     348                 :            : 
     349                 :          0 :         return m->dev_autofs_fd;
     350                 :            : }
     351                 :            : 
     352                 :          0 : static int open_ioctl_fd(int dev_autofs_fd, const char *where, dev_t devid) {
     353                 :            :         struct autofs_dev_ioctl *param;
     354                 :            :         size_t l;
     355                 :            : 
     356         [ #  # ]:          0 :         assert(dev_autofs_fd >= 0);
     357         [ #  # ]:          0 :         assert(where);
     358                 :            : 
     359                 :          0 :         l = sizeof(struct autofs_dev_ioctl) + strlen(where) + 1;
     360                 :          0 :         param = alloca(l);
     361                 :            : 
     362                 :          0 :         init_autofs_dev_ioctl(param);
     363                 :          0 :         param->size = l;
     364                 :          0 :         param->ioctlfd = -1;
     365                 :          0 :         param->openmount.devid = devid;
     366                 :          0 :         strcpy(param->path, where);
     367                 :            : 
     368         [ #  # ]:          0 :         if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_OPENMOUNT, param) < 0)
     369                 :          0 :                 return -errno;
     370                 :            : 
     371         [ #  # ]:          0 :         if (param->ioctlfd < 0)
     372                 :          0 :                 return -EIO;
     373                 :            : 
     374                 :          0 :         (void) fd_cloexec(param->ioctlfd, true);
     375                 :          0 :         return param->ioctlfd;
     376                 :            : }
     377                 :            : 
     378                 :          0 : static int autofs_protocol(int dev_autofs_fd, int ioctl_fd) {
     379                 :            :         uint32_t major, minor;
     380                 :            :         struct autofs_dev_ioctl param;
     381                 :            : 
     382         [ #  # ]:          0 :         assert(dev_autofs_fd >= 0);
     383         [ #  # ]:          0 :         assert(ioctl_fd >= 0);
     384                 :            : 
     385                 :          0 :         init_autofs_dev_ioctl(&param);
     386                 :          0 :         param.ioctlfd = ioctl_fd;
     387                 :            : 
     388         [ #  # ]:          0 :         if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_PROTOVER, &param) < 0)
     389                 :          0 :                 return -errno;
     390                 :            : 
     391                 :          0 :         major = param.protover.version;
     392                 :            : 
     393                 :          0 :         init_autofs_dev_ioctl(&param);
     394                 :          0 :         param.ioctlfd = ioctl_fd;
     395                 :            : 
     396         [ #  # ]:          0 :         if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_PROTOSUBVER, &param) < 0)
     397                 :          0 :                 return -errno;
     398                 :            : 
     399                 :          0 :         minor = param.protosubver.sub_version;
     400                 :            : 
     401         [ #  # ]:          0 :         log_debug("Autofs protocol version %i.%i", major, minor);
     402                 :          0 :         return 0;
     403                 :            : }
     404                 :            : 
     405                 :          0 : static int autofs_set_timeout(int dev_autofs_fd, int ioctl_fd, usec_t usec) {
     406                 :            :         struct autofs_dev_ioctl param;
     407                 :            : 
     408         [ #  # ]:          0 :         assert(dev_autofs_fd >= 0);
     409         [ #  # ]:          0 :         assert(ioctl_fd >= 0);
     410                 :            : 
     411                 :          0 :         init_autofs_dev_ioctl(&param);
     412                 :          0 :         param.ioctlfd = ioctl_fd;
     413                 :            : 
     414         [ #  # ]:          0 :         if (usec == USEC_INFINITY)
     415                 :          0 :                 param.timeout.timeout = 0;
     416                 :            :         else
     417                 :            :                 /* Convert to seconds, rounding up. */
     418                 :          0 :                 param.timeout.timeout = DIV_ROUND_UP(usec, USEC_PER_SEC);
     419                 :            : 
     420         [ #  # ]:          0 :         if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_TIMEOUT, &param) < 0)
     421                 :          0 :                 return -errno;
     422                 :            : 
     423                 :          0 :         return 0;
     424                 :            : }
     425                 :            : 
     426                 :          0 : static int autofs_send_ready(int dev_autofs_fd, int ioctl_fd, uint32_t token, int status) {
     427                 :            :         struct autofs_dev_ioctl param;
     428                 :            : 
     429         [ #  # ]:          0 :         assert(dev_autofs_fd >= 0);
     430         [ #  # ]:          0 :         assert(ioctl_fd >= 0);
     431                 :            : 
     432                 :          0 :         init_autofs_dev_ioctl(&param);
     433                 :          0 :         param.ioctlfd = ioctl_fd;
     434                 :            : 
     435         [ #  # ]:          0 :         if (status != 0) {
     436                 :          0 :                 param.fail.token = token;
     437                 :          0 :                 param.fail.status = status;
     438                 :            :         } else
     439                 :          0 :                 param.ready.token = token;
     440                 :            : 
     441   [ #  #  #  # ]:          0 :         if (ioctl(dev_autofs_fd, status ? AUTOFS_DEV_IOCTL_FAIL : AUTOFS_DEV_IOCTL_READY, &param) < 0)
     442                 :          0 :                 return -errno;
     443                 :            : 
     444                 :          0 :         return 0;
     445                 :            : }
     446                 :            : 
     447                 :          0 : static int automount_send_ready(Automount *a, Set *tokens, int status) {
     448                 :          0 :         _cleanup_close_ int ioctl_fd = -1;
     449                 :            :         unsigned token;
     450                 :            :         int r;
     451                 :            : 
     452         [ #  # ]:          0 :         assert(a);
     453         [ #  # ]:          0 :         assert(status <= 0);
     454                 :            : 
     455         [ #  # ]:          0 :         if (set_isempty(tokens))
     456                 :          0 :                 return 0;
     457                 :            : 
     458         [ #  # ]:          0 :         ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id);
     459         [ #  # ]:          0 :         if (ioctl_fd < 0)
     460                 :          0 :                 return ioctl_fd;
     461                 :            : 
     462         [ #  # ]:          0 :         if (status != 0)
     463   [ #  #  #  # ]:          0 :                 log_unit_debug_errno(UNIT(a), status, "Sending failure: %m");
     464                 :            :         else
     465   [ #  #  #  # ]:          0 :                 log_unit_debug(UNIT(a), "Sending success.");
     466                 :            : 
     467                 :          0 :         r = 0;
     468                 :            : 
     469                 :            :         /* Autofs thankfully does not hand out 0 as a token */
     470         [ #  # ]:          0 :         while ((token = PTR_TO_UINT(set_steal_first(tokens)))) {
     471                 :            :                 int k;
     472                 :            : 
     473                 :            :                 /* Autofs fun fact:
     474                 :            :                  *
     475                 :            :                  * if you pass a positive status code here, kernels
     476                 :            :                  * prior to 4.12 will freeze! Yay! */
     477                 :            : 
     478         [ #  # ]:          0 :                 k = autofs_send_ready(UNIT(a)->manager->dev_autofs_fd,
     479                 :            :                                       ioctl_fd,
     480                 :            :                                       token,
     481                 :            :                                       status);
     482         [ #  # ]:          0 :                 if (k < 0)
     483                 :          0 :                         r = k;
     484                 :            :         }
     485                 :            : 
     486                 :          0 :         return r;
     487                 :            : }
     488                 :            : 
     489                 :          0 : static void automount_trigger_notify(Unit *u, Unit *other) {
     490                 :          0 :         Automount *a = AUTOMOUNT(u);
     491                 :            :         int r;
     492                 :            : 
     493         [ #  # ]:          0 :         assert(a);
     494         [ #  # ]:          0 :         assert(other);
     495                 :            : 
     496                 :            :         /* Filter out invocations with bogus state */
     497   [ #  #  #  # ]:          0 :         if (other->load_state != UNIT_LOADED || other->type != UNIT_MOUNT)
     498                 :          0 :                 return;
     499                 :            : 
     500                 :            :         /* Don't propagate state changes from the mount if we are already down */
     501   [ #  #  #  # ]:          0 :         if (!IN_SET(a->state, AUTOMOUNT_WAITING, AUTOMOUNT_RUNNING))
     502                 :          0 :                 return;
     503                 :            : 
     504                 :            :         /* Propagate start limit hit state */
     505         [ #  # ]:          0 :         if (other->start_limit_hit) {
     506                 :          0 :                 automount_enter_dead(a, AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT);
     507                 :          0 :                 return;
     508                 :            :         }
     509                 :            : 
     510                 :            :         /* Don't propagate anything if there's still a job queued */
     511         [ #  # ]:          0 :         if (other->job)
     512                 :          0 :                 return;
     513                 :            : 
     514                 :            :         /* The mount is successfully established */
     515   [ #  #  #  # ]:          0 :         if (IN_SET(MOUNT(other)->state, MOUNT_MOUNTED, MOUNT_REMOUNTING)) {
     516                 :          0 :                 (void) automount_send_ready(a, a->tokens, 0);
     517                 :            : 
     518                 :          0 :                 r = automount_start_expire(a);
     519         [ #  # ]:          0 :                 if (r < 0)
     520   [ #  #  #  # ]:          0 :                         log_unit_warning_errno(UNIT(a), r, "Failed to start expiration timer, ignoring: %m");
     521                 :            : 
     522                 :          0 :                 automount_set_state(a, AUTOMOUNT_RUNNING);
     523                 :            :         }
     524                 :            : 
     525   [ #  #  #  # ]:          0 :         if (IN_SET(MOUNT(other)->state,
     526                 :            :                    MOUNT_MOUNTING, MOUNT_MOUNTING_DONE,
     527                 :            :                    MOUNT_MOUNTED, MOUNT_REMOUNTING,
     528                 :            :                    MOUNT_REMOUNTING_SIGTERM, MOUNT_REMOUNTING_SIGKILL,
     529                 :            :                    MOUNT_UNMOUNTING_SIGTERM, MOUNT_UNMOUNTING_SIGKILL,
     530                 :            :                    MOUNT_FAILED)) {
     531                 :            : 
     532                 :          0 :                 (void) automount_send_ready(a, a->expire_tokens, -ENODEV);
     533                 :            :         }
     534                 :            : 
     535         [ #  # ]:          0 :         if (MOUNT(other)->state == MOUNT_DEAD)
     536                 :          0 :                 (void) automount_send_ready(a, a->expire_tokens, 0);
     537                 :            : 
     538                 :            :         /* The mount is in some unhappy state now, let's unfreeze any waiting clients */
     539   [ #  #  #  # ]:          0 :         if (IN_SET(MOUNT(other)->state,
     540                 :            :                    MOUNT_DEAD, MOUNT_UNMOUNTING,
     541                 :            :                    MOUNT_REMOUNTING_SIGTERM, MOUNT_REMOUNTING_SIGKILL,
     542                 :            :                    MOUNT_UNMOUNTING_SIGTERM, MOUNT_UNMOUNTING_SIGKILL,
     543                 :            :                    MOUNT_FAILED)) {
     544                 :            : 
     545                 :          0 :                 (void) automount_send_ready(a, a->tokens, -ENODEV);
     546                 :            : 
     547                 :          0 :                 automount_set_state(a, AUTOMOUNT_WAITING);
     548                 :            :         }
     549                 :            : }
     550                 :            : 
     551                 :          0 : static void automount_enter_waiting(Automount *a) {
     552         [ #  # ]:          0 :         _cleanup_close_ int ioctl_fd = -1;
     553                 :          0 :         int p[2] = { -1, -1 };
     554                 :            :         char name[STRLEN("systemd-") + DECIMAL_STR_MAX(pid_t) + 1];
     555                 :            :         char options[STRLEN("fd=,pgrp=,minproto=5,maxproto=5,direct")
     556                 :            :                      + DECIMAL_STR_MAX(int) + DECIMAL_STR_MAX(gid_t) + 1];
     557                 :          0 :         bool mounted = false;
     558                 :            :         int r, dev_autofs_fd;
     559                 :            :         struct stat st;
     560                 :            : 
     561         [ #  # ]:          0 :         assert(a);
     562         [ #  # ]:          0 :         assert(a->pipe_fd < 0);
     563         [ #  # ]:          0 :         assert(a->where);
     564                 :            : 
     565                 :          0 :         set_clear(a->tokens);
     566                 :            : 
     567         [ #  # ]:          0 :         r = unit_fail_if_noncanonical(UNIT(a), a->where);
     568         [ #  # ]:          0 :         if (r < 0)
     569                 :          0 :                 goto fail;
     570                 :            : 
     571                 :          0 :         (void) mkdir_p_label(a->where, 0555);
     572                 :            : 
     573         [ #  # ]:          0 :         unit_warn_if_dir_nonempty(UNIT(a), a->where);
     574                 :            : 
     575         [ #  # ]:          0 :         dev_autofs_fd = open_dev_autofs(UNIT(a)->manager);
     576         [ #  # ]:          0 :         if (dev_autofs_fd < 0) {
     577                 :          0 :                 r = dev_autofs_fd;
     578                 :          0 :                 goto fail;
     579                 :            :         }
     580                 :            : 
     581         [ #  # ]:          0 :         if (pipe2(p, O_CLOEXEC) < 0) {
     582                 :          0 :                 r = -errno;
     583                 :          0 :                 goto fail;
     584                 :            :         }
     585                 :          0 :         r = fd_nonblock(p[0], true);
     586         [ #  # ]:          0 :         if (r < 0)
     587                 :          0 :                 goto fail;
     588                 :            : 
     589         [ #  # ]:          0 :         xsprintf(options, "fd=%i,pgrp="PID_FMT",minproto=5,maxproto=5,direct", p[1], getpgrp());
     590         [ #  # ]:          0 :         xsprintf(name, "systemd-"PID_FMT, getpid_cached());
     591         [ #  # ]:          0 :         if (mount(name, a->where, "autofs", 0, options) < 0) {
     592                 :          0 :                 r = -errno;
     593                 :          0 :                 goto fail;
     594                 :            :         }
     595                 :            : 
     596                 :          0 :         mounted = true;
     597                 :            : 
     598                 :          0 :         p[1] = safe_close(p[1]);
     599                 :            : 
     600         [ #  # ]:          0 :         if (stat(a->where, &st) < 0) {
     601                 :          0 :                 r = -errno;
     602                 :          0 :                 goto fail;
     603                 :            :         }
     604                 :            : 
     605                 :          0 :         ioctl_fd = open_ioctl_fd(dev_autofs_fd, a->where, st.st_dev);
     606         [ #  # ]:          0 :         if (ioctl_fd < 0) {
     607                 :          0 :                 r = ioctl_fd;
     608                 :          0 :                 goto fail;
     609                 :            :         }
     610                 :            : 
     611                 :          0 :         r = autofs_protocol(dev_autofs_fd, ioctl_fd);
     612         [ #  # ]:          0 :         if (r < 0)
     613                 :          0 :                 goto fail;
     614                 :            : 
     615                 :          0 :         r = autofs_set_timeout(dev_autofs_fd, ioctl_fd, a->timeout_idle_usec);
     616         [ #  # ]:          0 :         if (r < 0)
     617                 :          0 :                 goto fail;
     618                 :            : 
     619         [ #  # ]:          0 :         r = sd_event_add_io(UNIT(a)->manager->event, &a->pipe_event_source, p[0], EPOLLIN, automount_dispatch_io, a);
     620         [ #  # ]:          0 :         if (r < 0)
     621                 :          0 :                 goto fail;
     622                 :            : 
     623                 :          0 :         (void) sd_event_source_set_description(a->pipe_event_source, "automount-io");
     624                 :            : 
     625                 :          0 :         a->pipe_fd = p[0];
     626                 :          0 :         a->dev_id = st.st_dev;
     627                 :            : 
     628                 :          0 :         automount_set_state(a, AUTOMOUNT_WAITING);
     629                 :            : 
     630                 :          0 :         return;
     631                 :            : 
     632                 :          0 : fail:
     633   [ #  #  #  # ]:          0 :         log_unit_error_errno(UNIT(a), r, "Failed to initialize automounter: %m");
     634                 :            : 
     635                 :          0 :         safe_close_pair(p);
     636                 :            : 
     637         [ #  # ]:          0 :         if (mounted) {
     638                 :          0 :                 r = repeat_unmount(a->where, MNT_DETACH);
     639         [ #  # ]:          0 :                 if (r < 0)
     640         [ #  # ]:          0 :                         log_error_errno(r, "Failed to unmount, ignoring: %m");
     641                 :            :         }
     642                 :            : 
     643                 :          0 :         automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
     644                 :            : }
     645                 :            : 
     646                 :          0 : static void *expire_thread(void *p) {
     647                 :            :         struct autofs_dev_ioctl param;
     648                 :          0 :         _cleanup_(expire_data_freep) struct expire_data *data = (struct expire_data*)p;
     649                 :            :         int r;
     650                 :            : 
     651         [ #  # ]:          0 :         assert(data->dev_autofs_fd >= 0);
     652         [ #  # ]:          0 :         assert(data->ioctl_fd >= 0);
     653                 :            : 
     654                 :          0 :         init_autofs_dev_ioctl(&param);
     655                 :          0 :         param.ioctlfd = data->ioctl_fd;
     656                 :            : 
     657                 :            :         do {
     658                 :          0 :                 r = ioctl(data->dev_autofs_fd, AUTOFS_DEV_IOCTL_EXPIRE, &param);
     659         [ #  # ]:          0 :         } while (r >= 0);
     660                 :            : 
     661         [ #  # ]:          0 :         if (errno != EAGAIN)
     662         [ #  # ]:          0 :                 log_warning_errno(errno, "Failed to expire automount, ignoring: %m");
     663                 :            : 
     664                 :          0 :         return NULL;
     665                 :            : }
     666                 :            : 
     667                 :          0 : static int automount_dispatch_expire(sd_event_source *source, usec_t usec, void *userdata) {
     668                 :          0 :         Automount *a = AUTOMOUNT(userdata);
     669                 :          0 :         _cleanup_(expire_data_freep) struct expire_data *data = NULL;
     670                 :            :         int r;
     671                 :            : 
     672         [ #  # ]:          0 :         assert(a);
     673         [ #  # ]:          0 :         assert(source == a->expire_event_source);
     674                 :            : 
     675                 :          0 :         data = new0(struct expire_data, 1);
     676         [ #  # ]:          0 :         if (!data)
     677                 :          0 :                 return log_oom();
     678                 :            : 
     679                 :          0 :         data->ioctl_fd = -1;
     680                 :            : 
     681         [ #  # ]:          0 :         data->dev_autofs_fd = fcntl(UNIT(a)->manager->dev_autofs_fd, F_DUPFD_CLOEXEC, 3);
     682         [ #  # ]:          0 :         if (data->dev_autofs_fd < 0)
     683   [ #  #  #  # ]:          0 :                 return log_unit_error_errno(UNIT(a), errno, "Failed to duplicate autofs fd: %m");
     684                 :            : 
     685         [ #  # ]:          0 :         data->ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id);
     686         [ #  # ]:          0 :         if (data->ioctl_fd < 0)
     687   [ #  #  #  # ]:          0 :                 return log_unit_error_errno(UNIT(a), data->ioctl_fd, "Couldn't open autofs ioctl fd: %m");
     688                 :            : 
     689                 :          0 :         r = asynchronous_job(expire_thread, data);
     690         [ #  # ]:          0 :         if (r < 0)
     691   [ #  #  #  # ]:          0 :                 return log_unit_error_errno(UNIT(a), r, "Failed to start expire job: %m");
     692                 :            : 
     693                 :          0 :         data = NULL;
     694                 :            : 
     695                 :          0 :         return automount_start_expire(a);
     696                 :            : }
     697                 :            : 
     698                 :          0 : static int automount_start_expire(Automount *a) {
     699                 :            :         int r;
     700                 :            :         usec_t timeout;
     701                 :            : 
     702         [ #  # ]:          0 :         assert(a);
     703                 :            : 
     704         [ #  # ]:          0 :         if (a->timeout_idle_usec == 0)
     705                 :          0 :                 return 0;
     706                 :            : 
     707                 :          0 :         timeout = now(CLOCK_MONOTONIC) + MAX(a->timeout_idle_usec/3, USEC_PER_SEC);
     708                 :            : 
     709         [ #  # ]:          0 :         if (a->expire_event_source) {
     710                 :          0 :                 r = sd_event_source_set_time(a->expire_event_source, timeout);
     711         [ #  # ]:          0 :                 if (r < 0)
     712                 :          0 :                         return r;
     713                 :            : 
     714                 :          0 :                 return sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_ONESHOT);
     715                 :            :         }
     716                 :            : 
     717                 :          0 :         r = sd_event_add_time(
     718         [ #  # ]:          0 :                         UNIT(a)->manager->event,
     719                 :            :                         &a->expire_event_source,
     720                 :            :                         CLOCK_MONOTONIC, timeout, 0,
     721                 :            :                         automount_dispatch_expire, a);
     722         [ #  # ]:          0 :         if (r < 0)
     723                 :          0 :                 return r;
     724                 :            : 
     725                 :          0 :         (void) sd_event_source_set_description(a->expire_event_source, "automount-expire");
     726                 :            : 
     727                 :          0 :         return 0;
     728                 :            : }
     729                 :            : 
     730                 :          0 : static void automount_stop_expire(Automount *a) {
     731         [ #  # ]:          0 :         assert(a);
     732                 :            : 
     733         [ #  # ]:          0 :         if (!a->expire_event_source)
     734                 :          0 :                 return;
     735                 :            : 
     736                 :          0 :         (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF);
     737                 :            : }
     738                 :            : 
     739                 :          0 : static void automount_enter_running(Automount *a) {
     740         [ #  # ]:          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     741                 :            :         Unit *trigger;
     742                 :            :         struct stat st;
     743                 :            :         int r;
     744                 :            : 
     745         [ #  # ]:          0 :         assert(a);
     746                 :            : 
     747                 :            :         /* If the user masked our unit in the meantime, fail */
     748   [ #  #  #  # ]:          0 :         if (UNIT(a)->load_state != UNIT_LOADED) {
     749   [ #  #  #  # ]:          0 :                 log_unit_error(UNIT(a), "Suppressing automount event since unit is no longer loaded.");
     750                 :          0 :                 goto fail;
     751                 :            :         }
     752                 :            : 
     753                 :            :         /* We don't take mount requests anymore if we are supposed to
     754                 :            :          * shut down anyway */
     755   [ #  #  #  # ]:          0 :         if (unit_stop_pending(UNIT(a))) {
     756   [ #  #  #  # ]:          0 :                 log_unit_debug(UNIT(a), "Suppressing automount request since unit stop is scheduled.");
     757                 :          0 :                 automount_send_ready(a, a->tokens, -EHOSTDOWN);
     758                 :          0 :                 automount_send_ready(a, a->expire_tokens, -EHOSTDOWN);
     759                 :          0 :                 return;
     760                 :            :         }
     761                 :            : 
     762                 :          0 :         (void) mkdir_p_label(a->where, a->directory_mode);
     763                 :            : 
     764                 :            :         /* Before we do anything, let's see if somebody is playing games with us? */
     765         [ #  # ]:          0 :         if (lstat(a->where, &st) < 0) {
     766   [ #  #  #  # ]:          0 :                 log_unit_warning_errno(UNIT(a), errno, "Failed to stat automount point: %m");
     767                 :          0 :                 goto fail;
     768                 :            :         }
     769                 :            : 
     770                 :            :         /* The mount unit may have been explicitly started before we got the
     771                 :            :          * autofs request. Ack it to unblock anything waiting on the mount point. */
     772   [ #  #  #  # ]:          0 :         if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id) {
     773   [ #  #  #  # ]:          0 :                 log_unit_info(UNIT(a), "Automount point already active?");
     774                 :          0 :                 automount_send_ready(a, a->tokens, 0);
     775                 :          0 :                 return;
     776                 :            :         }
     777                 :            : 
     778         [ #  # ]:          0 :         trigger = UNIT_TRIGGER(UNIT(a));
     779         [ #  # ]:          0 :         if (!trigger) {
     780   [ #  #  #  # ]:          0 :                 log_unit_error(UNIT(a), "Unit to trigger vanished.");
     781                 :          0 :                 goto fail;
     782                 :            :         }
     783                 :            : 
     784         [ #  # ]:          0 :         r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
     785         [ #  # ]:          0 :         if (r < 0) {
     786   [ #  #  #  # ]:          0 :                 log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r));
     787                 :          0 :                 goto fail;
     788                 :            :         }
     789                 :            : 
     790                 :          0 :         automount_set_state(a, AUTOMOUNT_RUNNING);
     791                 :          0 :         return;
     792                 :            : 
     793                 :          0 : fail:
     794                 :          0 :         automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
     795                 :            : }
     796                 :            : 
     797                 :          0 : static int automount_start(Unit *u) {
     798                 :          0 :         Automount *a = AUTOMOUNT(u);
     799                 :            :         int r;
     800                 :            : 
     801         [ #  # ]:          0 :         assert(a);
     802   [ #  #  #  # ]:          0 :         assert(IN_SET(a->state, AUTOMOUNT_DEAD, AUTOMOUNT_FAILED));
     803                 :            : 
     804         [ #  # ]:          0 :         if (path_is_mount_point(a->where, NULL, 0) > 0) {
     805         [ #  # ]:          0 :                 log_unit_error(u, "Path %s is already a mount point, refusing start.", a->where);
     806                 :          0 :                 return -EEXIST;
     807                 :            :         }
     808                 :            : 
     809                 :          0 :         r = unit_test_trigger_loaded(u);
     810         [ #  # ]:          0 :         if (r < 0)
     811                 :          0 :                 return r;
     812                 :            : 
     813                 :          0 :         r = unit_test_start_limit(u);
     814         [ #  # ]:          0 :         if (r < 0) {
     815                 :          0 :                 automount_enter_dead(a, AUTOMOUNT_FAILURE_START_LIMIT_HIT);
     816                 :          0 :                 return r;
     817                 :            :         }
     818                 :            : 
     819                 :          0 :         r = unit_acquire_invocation_id(u);
     820         [ #  # ]:          0 :         if (r < 0)
     821                 :          0 :                 return r;
     822                 :            : 
     823                 :          0 :         a->result = AUTOMOUNT_SUCCESS;
     824                 :          0 :         automount_enter_waiting(a);
     825                 :          0 :         return 1;
     826                 :            : }
     827                 :            : 
     828                 :          0 : static int automount_stop(Unit *u) {
     829                 :          0 :         Automount *a = AUTOMOUNT(u);
     830                 :            : 
     831         [ #  # ]:          0 :         assert(a);
     832   [ #  #  #  # ]:          0 :         assert(IN_SET(a->state, AUTOMOUNT_WAITING, AUTOMOUNT_RUNNING));
     833                 :            : 
     834                 :          0 :         automount_enter_dead(a, AUTOMOUNT_SUCCESS);
     835                 :          0 :         return 1;
     836                 :            : }
     837                 :            : 
     838                 :          0 : static int automount_serialize(Unit *u, FILE *f, FDSet *fds) {
     839                 :          0 :         Automount *a = AUTOMOUNT(u);
     840                 :            :         Iterator i;
     841                 :            :         void *p;
     842                 :            :         int r;
     843                 :            : 
     844         [ #  # ]:          0 :         assert(a);
     845         [ #  # ]:          0 :         assert(f);
     846         [ #  # ]:          0 :         assert(fds);
     847                 :            : 
     848                 :          0 :         (void) serialize_item(f, "state", automount_state_to_string(a->state));
     849                 :          0 :         (void) serialize_item(f, "result", automount_result_to_string(a->result));
     850                 :          0 :         (void) serialize_item_format(f, "dev-id", "%lu", (unsigned long) a->dev_id);
     851                 :            : 
     852         [ #  # ]:          0 :         SET_FOREACH(p, a->tokens, i)
     853                 :          0 :                 (void) serialize_item_format(f, "token", "%u", PTR_TO_UINT(p));
     854         [ #  # ]:          0 :         SET_FOREACH(p, a->expire_tokens, i)
     855                 :          0 :                 (void) serialize_item_format(f, "expire-token", "%u", PTR_TO_UINT(p));
     856                 :            : 
     857                 :          0 :         r = serialize_fd(f, fds, "pipe-fd", a->pipe_fd);
     858         [ #  # ]:          0 :         if (r < 0)
     859                 :          0 :                 return r;
     860                 :            : 
     861                 :          0 :         return 0;
     862                 :            : }
     863                 :            : 
     864                 :          0 : static int automount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
     865                 :          0 :         Automount *a = AUTOMOUNT(u);
     866                 :            :         int r;
     867                 :            : 
     868         [ #  # ]:          0 :         assert(a);
     869         [ #  # ]:          0 :         assert(fds);
     870                 :            : 
     871         [ #  # ]:          0 :         if (streq(key, "state")) {
     872                 :            :                 AutomountState state;
     873                 :            : 
     874                 :          0 :                 state = automount_state_from_string(value);
     875         [ #  # ]:          0 :                 if (state < 0)
     876         [ #  # ]:          0 :                         log_unit_debug(u, "Failed to parse state value: %s", value);
     877                 :            :                 else
     878                 :          0 :                         a->deserialized_state = state;
     879         [ #  # ]:          0 :         } else if (streq(key, "result")) {
     880                 :            :                 AutomountResult f;
     881                 :            : 
     882                 :          0 :                 f = automount_result_from_string(value);
     883         [ #  # ]:          0 :                 if (f < 0)
     884         [ #  # ]:          0 :                         log_unit_debug(u, "Failed to parse result value: %s", value);
     885         [ #  # ]:          0 :                 else if (f != AUTOMOUNT_SUCCESS)
     886                 :          0 :                         a->result = f;
     887                 :            : 
     888         [ #  # ]:          0 :         } else if (streq(key, "dev-id")) {
     889                 :            :                 unsigned long d;
     890                 :            : 
     891         [ #  # ]:          0 :                 if (safe_atolu(value, &d) < 0)
     892         [ #  # ]:          0 :                         log_unit_debug(u, "Failed to parse dev-id value: %s", value);
     893                 :            :                 else
     894                 :          0 :                         a->dev_id = (dev_t) d;
     895                 :            : 
     896         [ #  # ]:          0 :         } else if (streq(key, "token")) {
     897                 :            :                 unsigned token;
     898                 :            : 
     899         [ #  # ]:          0 :                 if (safe_atou(value, &token) < 0)
     900         [ #  # ]:          0 :                         log_unit_debug(u, "Failed to parse token value: %s", value);
     901                 :            :                 else {
     902                 :          0 :                         r = set_ensure_allocated(&a->tokens, NULL);
     903         [ #  # ]:          0 :                         if (r < 0) {
     904                 :          0 :                                 log_oom();
     905                 :          0 :                                 return 0;
     906                 :            :                         }
     907                 :            : 
     908                 :          0 :                         r = set_put(a->tokens, UINT_TO_PTR(token));
     909         [ #  # ]:          0 :                         if (r < 0)
     910         [ #  # ]:          0 :                                 log_unit_error_errno(u, r, "Failed to add token to set: %m");
     911                 :            :                 }
     912         [ #  # ]:          0 :         } else if (streq(key, "expire-token")) {
     913                 :            :                 unsigned token;
     914                 :            : 
     915         [ #  # ]:          0 :                 if (safe_atou(value, &token) < 0)
     916         [ #  # ]:          0 :                         log_unit_debug(u, "Failed to parse token value: %s", value);
     917                 :            :                 else {
     918                 :          0 :                         r = set_ensure_allocated(&a->expire_tokens, NULL);
     919         [ #  # ]:          0 :                         if (r < 0) {
     920                 :          0 :                                 log_oom();
     921                 :          0 :                                 return 0;
     922                 :            :                         }
     923                 :            : 
     924                 :          0 :                         r = set_put(a->expire_tokens, UINT_TO_PTR(token));
     925         [ #  # ]:          0 :                         if (r < 0)
     926         [ #  # ]:          0 :                                 log_unit_error_errno(u, r, "Failed to add expire token to set: %m");
     927                 :            :                 }
     928         [ #  # ]:          0 :         } else if (streq(key, "pipe-fd")) {
     929                 :            :                 int fd;
     930                 :            : 
     931   [ #  #  #  #  :          0 :                 if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
                   #  # ]
     932         [ #  # ]:          0 :                         log_unit_debug(u, "Failed to parse pipe-fd value: %s", value);
     933                 :            :                 else {
     934                 :          0 :                         safe_close(a->pipe_fd);
     935                 :          0 :                         a->pipe_fd = fdset_remove(fds, fd);
     936                 :            :                 }
     937                 :            :         } else
     938         [ #  # ]:          0 :                 log_unit_debug(u, "Unknown serialization key: %s", key);
     939                 :            : 
     940                 :          0 :         return 0;
     941                 :            : }
     942                 :            : 
     943                 :          0 : static UnitActiveState automount_active_state(Unit *u) {
     944         [ #  # ]:          0 :         assert(u);
     945                 :            : 
     946                 :          0 :         return state_translation_table[AUTOMOUNT(u)->state];
     947                 :            : }
     948                 :            : 
     949                 :          0 : static const char *automount_sub_state_to_string(Unit *u) {
     950         [ #  # ]:          0 :         assert(u);
     951                 :            : 
     952                 :          0 :         return automount_state_to_string(AUTOMOUNT(u)->state);
     953                 :            : }
     954                 :            : 
     955                 :          0 : static bool automount_may_gc(Unit *u) {
     956                 :            :         Unit *t;
     957                 :            : 
     958         [ #  # ]:          0 :         assert(u);
     959                 :            : 
     960                 :          0 :         t = UNIT_TRIGGER(u);
     961         [ #  # ]:          0 :         if (!t)
     962                 :          0 :                 return true;
     963                 :            : 
     964                 :          0 :         return UNIT_VTABLE(t)->may_gc(t);
     965                 :            : }
     966                 :            : 
     967                 :          0 : static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata) {
     968                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     969                 :            :         union autofs_v5_packet_union packet;
     970                 :          0 :         Automount *a = AUTOMOUNT(userdata);
     971                 :            :         Unit *trigger;
     972                 :            :         int r;
     973                 :            : 
     974         [ #  # ]:          0 :         assert(a);
     975         [ #  # ]:          0 :         assert(fd == a->pipe_fd);
     976                 :            : 
     977         [ #  # ]:          0 :         if (events != EPOLLIN) {
     978   [ #  #  #  # ]:          0 :                 log_unit_error(UNIT(a), "Got invalid poll event %"PRIu32" on pipe (fd=%d)", events, fd);
     979                 :          0 :                 goto fail;
     980                 :            :         }
     981                 :            : 
     982                 :          0 :         r = loop_read_exact(a->pipe_fd, &packet, sizeof(packet), true);
     983         [ #  # ]:          0 :         if (r < 0) {
     984   [ #  #  #  # ]:          0 :                 log_unit_error_errno(UNIT(a), r, "Invalid read from pipe: %m");
     985                 :          0 :                 goto fail;
     986                 :            :         }
     987                 :            : 
     988      [ #  #  # ]:          0 :         switch (packet.hdr.type) {
     989                 :            : 
     990                 :          0 :         case autofs_ptype_missing_direct:
     991                 :            : 
     992         [ #  # ]:          0 :                 if (packet.v5_packet.pid > 0) {
     993                 :          0 :                         _cleanup_free_ char *p = NULL;
     994                 :            : 
     995                 :          0 :                         get_process_comm(packet.v5_packet.pid, &p);
     996   [ #  #  #  # ]:          0 :                         log_unit_info(UNIT(a), "Got automount request for %s, triggered by %"PRIu32" (%s)", a->where, packet.v5_packet.pid, strna(p));
     997                 :            :                 } else
     998   [ #  #  #  # ]:          0 :                         log_unit_debug(UNIT(a), "Got direct mount request on %s", a->where);
     999                 :            : 
    1000                 :          0 :                 r = set_ensure_allocated(&a->tokens, NULL);
    1001         [ #  # ]:          0 :                 if (r < 0) {
    1002   [ #  #  #  # ]:          0 :                         log_unit_error(UNIT(a), "Failed to allocate token set.");
    1003                 :          0 :                         goto fail;
    1004                 :            :                 }
    1005                 :            : 
    1006                 :          0 :                 r = set_put(a->tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token));
    1007         [ #  # ]:          0 :                 if (r < 0) {
    1008   [ #  #  #  # ]:          0 :                         log_unit_error_errno(UNIT(a), r, "Failed to remember token: %m");
    1009                 :          0 :                         goto fail;
    1010                 :            :                 }
    1011                 :            : 
    1012                 :          0 :                 automount_enter_running(a);
    1013                 :          0 :                 break;
    1014                 :            : 
    1015                 :          0 :         case autofs_ptype_expire_direct:
    1016   [ #  #  #  # ]:          0 :                 log_unit_debug(UNIT(a), "Got direct umount request on %s", a->where);
    1017                 :            : 
    1018                 :          0 :                 automount_stop_expire(a);
    1019                 :            : 
    1020                 :          0 :                 r = set_ensure_allocated(&a->expire_tokens, NULL);
    1021         [ #  # ]:          0 :                 if (r < 0) {
    1022   [ #  #  #  # ]:          0 :                         log_unit_error(UNIT(a), "Failed to allocate token set.");
    1023                 :          0 :                         goto fail;
    1024                 :            :                 }
    1025                 :            : 
    1026                 :          0 :                 r = set_put(a->expire_tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token));
    1027         [ #  # ]:          0 :                 if (r < 0) {
    1028   [ #  #  #  # ]:          0 :                         log_unit_error_errno(UNIT(a), r, "Failed to remember token: %m");
    1029                 :          0 :                         goto fail;
    1030                 :            :                 }
    1031                 :            : 
    1032         [ #  # ]:          0 :                 trigger = UNIT_TRIGGER(UNIT(a));
    1033         [ #  # ]:          0 :                 if (!trigger) {
    1034   [ #  #  #  # ]:          0 :                         log_unit_error(UNIT(a), "Unit to trigger vanished.");
    1035                 :          0 :                         goto fail;
    1036                 :            :                 }
    1037                 :            : 
    1038         [ #  # ]:          0 :                 r = manager_add_job(UNIT(a)->manager, JOB_STOP, trigger, JOB_REPLACE, NULL, &error, NULL);
    1039         [ #  # ]:          0 :                 if (r < 0) {
    1040   [ #  #  #  # ]:          0 :                         log_unit_warning(UNIT(a), "Failed to queue umount startup job: %s", bus_error_message(&error, r));
    1041                 :          0 :                         goto fail;
    1042                 :            :                 }
    1043                 :          0 :                 break;
    1044                 :            : 
    1045                 :          0 :         default:
    1046   [ #  #  #  # ]:          0 :                 log_unit_error(UNIT(a), "Received unknown automount request %i", packet.hdr.type);
    1047                 :          0 :                 break;
    1048                 :            :         }
    1049                 :            : 
    1050                 :          0 :         return 0;
    1051                 :            : 
    1052                 :          0 : fail:
    1053                 :          0 :         automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
    1054                 :          0 :         return 0;
    1055                 :            : }
    1056                 :            : 
    1057                 :         56 : static void automount_shutdown(Manager *m) {
    1058         [ -  + ]:         56 :         assert(m);
    1059                 :            : 
    1060                 :         56 :         m->dev_autofs_fd = safe_close(m->dev_autofs_fd);
    1061                 :         56 : }
    1062                 :            : 
    1063                 :          0 : static void automount_reset_failed(Unit *u) {
    1064                 :          0 :         Automount *a = AUTOMOUNT(u);
    1065                 :            : 
    1066         [ #  # ]:          0 :         assert(a);
    1067                 :            : 
    1068         [ #  # ]:          0 :         if (a->state == AUTOMOUNT_FAILED)
    1069                 :          0 :                 automount_set_state(a, AUTOMOUNT_DEAD);
    1070                 :            : 
    1071                 :          0 :         a->result = AUTOMOUNT_SUCCESS;
    1072                 :          0 : }
    1073                 :            : 
    1074                 :         88 : static bool automount_supported(void) {
    1075                 :            :         static int supported = -1;
    1076                 :            : 
    1077         [ +  + ]:         88 :         if (supported < 0)
    1078                 :         20 :                 supported = access("/dev/autofs", F_OK) >= 0;
    1079                 :            : 
    1080                 :         88 :         return supported;
    1081                 :            : }
    1082                 :            : 
    1083                 :            : static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = {
    1084                 :            :         [AUTOMOUNT_SUCCESS] = "success",
    1085                 :            :         [AUTOMOUNT_FAILURE_RESOURCES] = "resources",
    1086                 :            :         [AUTOMOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
    1087                 :            :         [AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT] = "mount-start-limit-hit",
    1088                 :            : };
    1089                 :            : 
    1090   [ +  +  +  + ]:         48 : DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult);
    1091                 :            : 
    1092                 :            : const UnitVTable automount_vtable = {
    1093                 :            :         .object_size = sizeof(Automount),
    1094                 :            : 
    1095                 :            :         .sections =
    1096                 :            :                 "Unit\0"
    1097                 :            :                 "Automount\0"
    1098                 :            :                 "Install\0",
    1099                 :            : 
    1100                 :            :         .init = automount_init,
    1101                 :            :         .load = automount_load,
    1102                 :            :         .done = automount_done,
    1103                 :            : 
    1104                 :            :         .coldplug = automount_coldplug,
    1105                 :            : 
    1106                 :            :         .dump = automount_dump,
    1107                 :            : 
    1108                 :            :         .start = automount_start,
    1109                 :            :         .stop = automount_stop,
    1110                 :            : 
    1111                 :            :         .serialize = automount_serialize,
    1112                 :            :         .deserialize_item = automount_deserialize_item,
    1113                 :            : 
    1114                 :            :         .active_state = automount_active_state,
    1115                 :            :         .sub_state_to_string = automount_sub_state_to_string,
    1116                 :            : 
    1117                 :            :         .may_gc = automount_may_gc,
    1118                 :            : 
    1119                 :            :         .trigger_notify = automount_trigger_notify,
    1120                 :            : 
    1121                 :            :         .reset_failed = automount_reset_failed,
    1122                 :            : 
    1123                 :            :         .bus_vtable = bus_automount_vtable,
    1124                 :            :         .bus_set_property = bus_automount_set_property,
    1125                 :            : 
    1126                 :            :         .can_transient = true,
    1127                 :            : 
    1128                 :            :         .shutdown = automount_shutdown,
    1129                 :            :         .supported = automount_supported,
    1130                 :            : 
    1131                 :            :         .status_message_formats = {
    1132                 :            :                 .finished_start_job = {
    1133                 :            :                         [JOB_DONE]       = "Set up automount %s.",
    1134                 :            :                         [JOB_FAILED]     = "Failed to set up automount %s.",
    1135                 :            :                 },
    1136                 :            :                 .finished_stop_job = {
    1137                 :            :                         [JOB_DONE]       = "Unset automount %s.",
    1138                 :            :                         [JOB_FAILED]     = "Failed to unset automount %s.",
    1139                 :            :                 },
    1140                 :            :         },
    1141                 :            : };

Generated by: LCOV version 1.14