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