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