]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/automount.c
util: split-out hwclock.[ch]
[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
LP
33#include "automount.h"
34#include "load-fragment.h"
5cb5a6ff 35#include "load-dropin.h"
8d567588 36#include "unit-name.h"
4139c1b2 37#include "dbus-automount.h"
398ef8ba 38#include "bus-errors.h"
4e67ddd6 39#include "special.h"
e51bc1a2 40#include "label.h"
49e942b2 41#include "mkdir.h"
5cb5a6ff 42
e537352b
LP
43static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = {
44 [AUTOMOUNT_DEAD] = UNIT_INACTIVE,
45 [AUTOMOUNT_WAITING] = UNIT_ACTIVE,
46 [AUTOMOUNT_RUNNING] = UNIT_ACTIVE,
74ac3cbd 47 [AUTOMOUNT_FAILED] = UNIT_FAILED
e537352b 48};
5cb5a6ff 49
a16e1123 50static int open_dev_autofs(Manager *m);
8d567588 51
e537352b
LP
52static void automount_init(Unit *u) {
53 Automount *a = AUTOMOUNT(u);
5cb5a6ff 54
8d567588 55 assert(u);
ac155bb8 56 assert(u->load_state == UNIT_STUB);
8d567588
LP
57
58 a->pipe_watch.fd = a->pipe_fd = -1;
a16e1123 59 a->pipe_watch.type = WATCH_INVALID;
1cf18f27
LP
60
61 a->directory_mode = 0755;
c8f4d764 62
1124fe6f 63 UNIT(a)->ignore_on_isolate = true;
8d567588
LP
64}
65
66static void repeat_unmout(const char *path) {
67 assert(path);
68
69 for (;;) {
1b560190
LP
70 /* If there are multiple mounts on a mount point, this
71 * removes them all */
8d567588
LP
72
73 if (umount2(path, MNT_DETACH) >= 0)
74 continue;
75
76 if (errno != EINVAL)
77 log_error("Failed to unmount: %m");
78
79 break;
80 }
81}
82
83static void unmount_autofs(Automount *a) {
84 assert(a);
85
86 if (a->pipe_fd < 0)
87 return;
88
89 automount_send_ready(a, -EHOSTDOWN);
90
91 unit_unwatch_fd(UNIT(a), &a->pipe_watch);
92 close_nointr_nofail(a->pipe_fd);
93 a->pipe_fd = -1;
94
a16e1123
LP
95 /* If we reload/reexecute things we keep the mount point
96 * around */
97 if (a->where &&
1124fe6f
MS
98 (UNIT(a)->manager->exit_code != MANAGER_RELOAD &&
99 UNIT(a)->manager->exit_code != MANAGER_REEXECUTE))
a16e1123 100 repeat_unmout(a->where);
8d567588
LP
101}
102
103static void automount_done(Unit *u) {
104 Automount *a = AUTOMOUNT(u);
105
106 assert(a);
107
108 unmount_autofs(a);
57020a3a 109 unit_ref_unset(&a->mount);
8d567588 110
a16e1123
LP
111 free(a->where);
112 a->where = NULL;
113
114 set_free(a->tokens);
115 a->tokens = NULL;
8d567588
LP
116}
117
6e2ef85b
LP
118int automount_add_one_mount_link(Automount *a, Mount *m) {
119 int r;
120
121 assert(a);
122 assert(m);
123
1124fe6f
MS
124 if (UNIT(a)->load_state != UNIT_LOADED ||
125 UNIT(m)->load_state != UNIT_LOADED)
6e2ef85b
LP
126 return 0;
127
128 if (!path_startswith(a->where, m->where))
129 return 0;
130
1b560190
LP
131 if (path_equal(a->where, m->where))
132 return 0;
133
2c966c03 134 if ((r = unit_add_two_dependencies(UNIT(a), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0)
6e2ef85b
LP
135 return r;
136
137 return 0;
138}
139
140static int automount_add_mount_links(Automount *a) {
ac155bb8 141 Unit *other;
6e2ef85b
LP
142 int r;
143
144 assert(a);
145
1124fe6f 146 LIST_FOREACH(units_by_type, other, UNIT(a)->manager->units_by_type[UNIT_MOUNT])
595ed347 147 if ((r = automount_add_one_mount_link(a, MOUNT(other))) < 0)
6e2ef85b
LP
148 return r;
149
150 return 0;
151}
152
2edd4434
LP
153static int automount_add_default_dependencies(Automount *a) {
154 int r;
155
156 assert(a);
157
1124fe6f 158 if (UNIT(a)->manager->running_as == MANAGER_SYSTEM) {
2edd4434 159
2a77d31d
LP
160 if ((r = unit_add_dependency_by_name(UNIT(a), UNIT_BEFORE, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
161 return r;
162
ead8e478 163 if ((r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true)) < 0)
2edd4434
LP
164 return r;
165 }
166
167 return 0;
168}
169
8d567588
LP
170static int automount_verify(Automount *a) {
171 bool b;
172 char *e;
173 assert(a);
174
1124fe6f 175 if (UNIT(a)->load_state != UNIT_LOADED)
8d567588
LP
176 return 0;
177
41e45059
LP
178 if (path_equal(a->where, "/")) {
179 log_error("Cannot have an automount unit for the root directory. Refusing.");
180 return -EINVAL;
181 }
182
a16e1123 183 if (!(e = unit_name_from_path(a->where, ".automount")))
8d567588
LP
184 return -ENOMEM;
185
186 b = unit_has_name(UNIT(a), e);
187 free(e);
188
189 if (!b) {
1124fe6f 190 log_error("%s's Where setting doesn't match unit name. Refusing.", UNIT(a)->id);
8d567588
LP
191 return -EINVAL;
192 }
193
194 return 0;
e537352b 195}
5cb5a6ff 196
e537352b
LP
197static int automount_load(Unit *u) {
198 int r;
199 Automount *a = AUTOMOUNT(u);
23a177ef 200
e537352b 201 assert(u);
ac155bb8 202 assert(u->load_state == UNIT_STUB);
5cb5a6ff 203
e537352b
LP
204 /* Load a .automount file */
205 if ((r = unit_load_fragment_and_dropin_optional(u)) < 0)
206 return r;
23a177ef 207
ac155bb8 208 if (u->load_state == UNIT_LOADED) {
57020a3a 209 Unit *x;
23a177ef 210
a16e1123 211 if (!a->where)
ac155bb8 212 if (!(a->where = unit_name_to_path(u->id)))
a16e1123
LP
213 return -ENOMEM;
214
215 path_kill_slashes(a->where);
216
6e2ef85b
LP
217 if ((r = automount_add_mount_links(a)) < 0)
218 return r;
219
57020a3a
LP
220 r = unit_load_related_unit(u, ".mount", &x);
221 if (r < 0)
23a177ef
LP
222 return r;
223
57020a3a
LP
224 unit_ref_set(&a->mount, x);
225
226 r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(a->mount), true);
227 if (r < 0)
23a177ef 228 return r;
4e67ddd6 229
1124fe6f 230 if (UNIT(a)->default_dependencies)
2edd4434 231 if ((r = automount_add_default_dependencies(a)) < 0)
4e67ddd6 232 return r;
23a177ef
LP
233 }
234
8d567588 235 return automount_verify(a);
5cb5a6ff
LP
236}
237
8d567588
LP
238static void automount_set_state(Automount *a, AutomountState state) {
239 AutomountState old_state;
e537352b 240 assert(a);
034c6ed7 241
8d567588
LP
242 old_state = a->state;
243 a->state = state;
244
245 if (state != AUTOMOUNT_WAITING &&
246 state != AUTOMOUNT_RUNNING)
247 unmount_autofs(a);
248
249 if (state != old_state)
40d50879 250 log_debug("%s changed %s -> %s",
1124fe6f 251 UNIT(a)->id,
a16e1123
LP
252 automount_state_to_string(old_state),
253 automount_state_to_string(state));
8d567588 254
e2f3b44c 255 unit_notify(UNIT(a), state_translation_table[old_state], state_translation_table[state], true);
034c6ed7
LP
256}
257
a16e1123
LP
258static int automount_coldplug(Unit *u) {
259 Automount *a = AUTOMOUNT(u);
260 int r;
261
262 assert(a);
263 assert(a->state == AUTOMOUNT_DEAD);
264
265 if (a->deserialized_state != a->state) {
266
ac155bb8 267 if ((r = open_dev_autofs(u->manager)) < 0)
a16e1123
LP
268 return r;
269
270 if (a->deserialized_state == AUTOMOUNT_WAITING ||
271 a->deserialized_state == AUTOMOUNT_RUNNING) {
272
273 assert(a->pipe_fd >= 0);
274
275 if ((r = unit_watch_fd(UNIT(a), a->pipe_fd, EPOLLIN, &a->pipe_watch)) < 0)
276 return r;
277 }
278
279 automount_set_state(a, a->deserialized_state);
280 }
281
282 return 0;
283}
284
87f0e418 285static void automount_dump(Unit *u, FILE *f, const char *prefix) {
a16e1123 286 Automount *a = AUTOMOUNT(u);
5cb5a6ff 287
a16e1123 288 assert(a);
5cb5a6ff
LP
289
290 fprintf(f,
a16e1123 291 "%sAutomount State: %s\n"
81a5c6d0 292 "%sResult: %s\n"
1cf18f27
LP
293 "%sWhere: %s\n"
294 "%sDirectoryMode: %04o\n",
a16e1123 295 prefix, automount_state_to_string(a->state),
81a5c6d0 296 prefix, automount_result_to_string(a->result),
1cf18f27
LP
297 prefix, a->where,
298 prefix, a->directory_mode);
5cb5a6ff
LP
299}
300
81a5c6d0 301static void automount_enter_dead(Automount *a, AutomountResult f) {
8d567588
LP
302 assert(a);
303
81a5c6d0
LP
304 if (f != AUTOMOUNT_SUCCESS)
305 a->result = f;
8d567588 306
81a5c6d0 307 automount_set_state(a, a->result != AUTOMOUNT_SUCCESS ? AUTOMOUNT_FAILED : AUTOMOUNT_DEAD);
8d567588
LP
308}
309
310static int open_dev_autofs(Manager *m) {
311 struct autofs_dev_ioctl param;
312
313 assert(m);
314
315 if (m->dev_autofs_fd >= 0)
316 return m->dev_autofs_fd;
317
c0f9c7da 318 label_fix("/dev/autofs", false);
56cf987f 319
a16e1123 320 if ((m->dev_autofs_fd = open("/dev/autofs", O_CLOEXEC|O_RDONLY)) < 0) {
11c3a4ee
LP
321 log_error("Failed to open /dev/autofs: %s", strerror(errno));
322 return -errno;
8d567588
LP
323 }
324
325 init_autofs_dev_ioctl(&param);
326 if (ioctl(m->dev_autofs_fd, AUTOFS_DEV_IOCTL_VERSION, &param) < 0) {
327 close_nointr_nofail(m->dev_autofs_fd);
328 m->dev_autofs_fd = -1;
329 return -errno;
330 }
331
332 log_debug("Autofs kernel version %i.%i", param.ver_major, param.ver_minor);
333
334 return m->dev_autofs_fd;
335}
336
337static int open_ioctl_fd(int dev_autofs_fd, const char *where, dev_t devid) {
338 struct autofs_dev_ioctl *param;
339 size_t l;
340 int r;
341
342 assert(dev_autofs_fd >= 0);
343 assert(where);
344
345 l = sizeof(struct autofs_dev_ioctl) + strlen(where) + 1;
346
347 if (!(param = malloc(l)))
348 return -ENOMEM;
349
350 init_autofs_dev_ioctl(param);
351 param->size = l;
352 param->ioctlfd = -1;
353 param->openmount.devid = devid;
354 strcpy(param->path, where);
355
356 if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_OPENMOUNT, param) < 0) {
357 r = -errno;
358 goto finish;
359 }
360
361 if (param->ioctlfd < 0) {
362 r = -EIO;
363 goto finish;
364 }
365
a16e1123 366 fd_cloexec(param->ioctlfd, true);
8d567588
LP
367 r = param->ioctlfd;
368
369finish:
370 free(param);
371 return r;
372}
373
374static int autofs_protocol(int dev_autofs_fd, int ioctl_fd) {
375 uint32_t major, minor;
376 struct autofs_dev_ioctl param;
377
378 assert(dev_autofs_fd >= 0);
379 assert(ioctl_fd >= 0);
380
381 init_autofs_dev_ioctl(&param);
382 param.ioctlfd = ioctl_fd;
383
384 if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_PROTOVER, &param) < 0)
385 return -errno;
386
387 major = param.protover.version;
388
389 init_autofs_dev_ioctl(&param);
390 param.ioctlfd = ioctl_fd;
391
392 if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_PROTOSUBVER, &param) < 0)
393 return -errno;
394
395 minor = param.protosubver.sub_version;
396
397 log_debug("Autofs protocol version %i.%i", major, minor);
398 return 0;
399}
400
401static int autofs_set_timeout(int dev_autofs_fd, int ioctl_fd, time_t sec) {
402 struct autofs_dev_ioctl param;
403
404 assert(dev_autofs_fd >= 0);
405 assert(ioctl_fd >= 0);
406
407 init_autofs_dev_ioctl(&param);
408 param.ioctlfd = ioctl_fd;
409 param.timeout.timeout = sec;
410
411 if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_TIMEOUT, &param) < 0)
412 return -errno;
413
414 return 0;
415}
416
417static int autofs_send_ready(int dev_autofs_fd, int ioctl_fd, uint32_t token, int status) {
418 struct autofs_dev_ioctl param;
419
420 assert(dev_autofs_fd >= 0);
421 assert(ioctl_fd >= 0);
422
423 init_autofs_dev_ioctl(&param);
424 param.ioctlfd = ioctl_fd;
425
426 if (status) {
427 param.fail.token = token;
428 param.fail.status = status;
429 } else
430 param.ready.token = token;
431
432 if (ioctl(dev_autofs_fd, status ? AUTOFS_DEV_IOCTL_FAIL : AUTOFS_DEV_IOCTL_READY, &param) < 0)
433 return -errno;
434
435 return 0;
436}
437
438int automount_send_ready(Automount *a, int status) {
439 int ioctl_fd, r;
440 unsigned token;
441
442 assert(a);
443 assert(status <= 0);
444
445 if (set_isempty(a->tokens))
446 return 0;
447
1124fe6f 448 if ((ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id)) < 0) {
8d567588
LP
449 r = ioctl_fd;
450 goto fail;
451 }
452
453 if (status)
454 log_debug("Sending failure: %s", strerror(-status));
455 else
456 log_debug("Sending success.");
457
e364ad06
LP
458 r = 0;
459
8d567588
LP
460 /* Autofs thankfully does not hand out 0 as a token */
461 while ((token = PTR_TO_UINT(set_steal_first(a->tokens)))) {
462 int k;
463
464 /* Autofs fun fact II:
465 *
466 * if you pass a positive status code here, the kernel will
467 * freeze! Yay! */
468
1124fe6f 469 if ((k = autofs_send_ready(UNIT(a)->manager->dev_autofs_fd,
8d567588
LP
470 ioctl_fd,
471 token,
472 status)) < 0)
473 r = k;
474 }
475
8d567588
LP
476fail:
477 if (ioctl_fd >= 0)
478 close_nointr_nofail(ioctl_fd);
479
480 return r;
481}
482
483static void automount_enter_waiting(Automount *a) {
484 int p[2] = { -1, -1 };
485 char name[32], options[128];
486 bool mounted = false;
487 int r, ioctl_fd = -1, dev_autofs_fd;
488 struct stat st;
489
490 assert(a);
491 assert(a->pipe_fd < 0);
492 assert(a->where);
493
494 if (a->tokens)
495 set_clear(a->tokens);
8d567588 496
1124fe6f 497 if ((dev_autofs_fd = open_dev_autofs(UNIT(a)->manager)) < 0) {
8d567588
LP
498 r = dev_autofs_fd;
499 goto fail;
500 }
501
502 /* We knowingly ignore the results of this call */
503 mkdir_p(a->where, 0555);
504
a16e1123 505 if (pipe2(p, O_NONBLOCK|O_CLOEXEC) < 0) {
8d567588
LP
506 r = -errno;
507 goto fail;
508 }
509
510 snprintf(options, sizeof(options), "fd=%i,pgrp=%u,minproto=5,maxproto=5,direct", p[1], (unsigned) getpgrp());
511 char_array_0(options);
512
513 snprintf(name, sizeof(name), "systemd-%u", (unsigned) getpid());
514 char_array_0(name);
515
516 if (mount(name, a->where, "autofs", 0, options) < 0) {
517 r = -errno;
518 goto fail;
519 }
520
521 mounted = true;
522
523 close_nointr_nofail(p[1]);
524 p[1] = -1;
525
526 if (stat(a->where, &st) < 0) {
527 r = -errno;
528 goto fail;
529 }
530
531 if ((ioctl_fd = open_ioctl_fd(dev_autofs_fd, a->where, st.st_dev)) < 0) {
532 r = ioctl_fd;
533 goto fail;
534 }
535
536 if ((r = autofs_protocol(dev_autofs_fd, ioctl_fd)) < 0)
537 goto fail;
538
539 if ((r = autofs_set_timeout(dev_autofs_fd, ioctl_fd, 300)) < 0)
540 goto fail;
541
542 /* Autofs fun fact:
543 *
544 * Unless we close the ioctl fd here, for some weird reason
545 * the direct mount will not receive events from the
546 * kernel. */
547
548 close_nointr_nofail(ioctl_fd);
549 ioctl_fd = -1;
550
551 if ((r = unit_watch_fd(UNIT(a), p[0], EPOLLIN, &a->pipe_watch)) < 0)
552 goto fail;
553
554 a->pipe_fd = p[0];
555 a->dev_id = st.st_dev;
556
557 automount_set_state(a, AUTOMOUNT_WAITING);
558
559 return;
560
561fail:
562 assert_se(close_pipe(p) == 0);
563
564 if (ioctl_fd >= 0)
565 close_nointr_nofail(ioctl_fd);
566
567 if (mounted)
568 repeat_unmout(a->where);
569
570 log_error("Failed to initialize automounter: %s", strerror(-r));
81a5c6d0 571 automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
8d567588
LP
572}
573
574static void automount_enter_runnning(Automount *a) {
575 int r;
576 struct stat st;
398ef8ba 577 DBusError error;
8d567588
LP
578
579 assert(a);
57020a3a 580 assert(UNIT_DEREF(a->mount));
8d567588 581
398ef8ba
LP
582 dbus_error_init(&error);
583
ba3e67a7
LP
584 /* We don't take mount requests anymore if we are supposed to
585 * shut down anyway */
5d909e3e 586 if (unit_pending_inactive(UNIT(a))) {
1124fe6f 587 log_debug("Suppressing automount request on %s since unit stop is scheduled.", UNIT(a)->id);
ba3e67a7
LP
588 automount_send_ready(a, -EHOSTDOWN);
589 return;
590 }
591
1cf18f27 592 mkdir_p(a->where, a->directory_mode);
8d567588 593
1cf18f27
LP
594 /* Before we do anything, let's see if somebody is playing games with us? */
595 if (lstat(a->where, &st) < 0) {
1124fe6f 596 log_warning("%s failed to stat automount point: %m", UNIT(a)->id);
8d567588
LP
597 goto fail;
598 }
599
600 if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id)
1124fe6f
MS
601 log_info("%s's automount point already active?", UNIT(a)->id);
602 else if ((r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_DEREF(a->mount), JOB_REPLACE, true, &error, NULL)) < 0) {
603 log_warning("%s failed to queue mount startup job: %s", UNIT(a)->id, bus_error(&error, r));
8d567588
LP
604 goto fail;
605 }
606
607 automount_set_state(a, AUTOMOUNT_RUNNING);
608 return;
609
610fail:
81a5c6d0 611 automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
398ef8ba 612 dbus_error_free(&error);
8d567588
LP
613}
614
615static int automount_start(Unit *u) {
616 Automount *a = AUTOMOUNT(u);
617
618 assert(a);
619
74ac3cbd 620 assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED);
01f78473 621
0c85a4f3 622 if (path_is_mount_point(a->where, false)) {
ac155bb8 623 log_error("Path %s is already a mount point, refusing start for %s", a->where, u->id);
8d567588
LP
624 return -EEXIST;
625 }
626
ac155bb8 627 if (UNIT_DEREF(a->mount)->load_state != UNIT_LOADED)
01f78473 628 return -ENOENT;
8d567588 629
81a5c6d0 630 a->result = AUTOMOUNT_SUCCESS;
8d567588
LP
631 automount_enter_waiting(a);
632 return 0;
633}
634
635static int automount_stop(Unit *u) {
636 Automount *a = AUTOMOUNT(u);
637
638 assert(a);
639
640 assert(a->state == AUTOMOUNT_WAITING || a->state == AUTOMOUNT_RUNNING);
641
81a5c6d0 642 automount_enter_dead(a, AUTOMOUNT_SUCCESS);
8d567588
LP
643 return 0;
644}
645
a16e1123
LP
646static int automount_serialize(Unit *u, FILE *f, FDSet *fds) {
647 Automount *a = AUTOMOUNT(u);
648 void *p;
649 Iterator i;
650
651 assert(a);
652 assert(f);
653 assert(fds);
654
655 unit_serialize_item(u, f, "state", automount_state_to_string(a->state));
81a5c6d0 656 unit_serialize_item(u, f, "result", automount_result_to_string(a->result));
a16e1123
LP
657 unit_serialize_item_format(u, f, "dev-id", "%u", (unsigned) a->dev_id);
658
659 SET_FOREACH(p, a->tokens, i)
660 unit_serialize_item_format(u, f, "token", "%u", PTR_TO_UINT(p));
661
662 if (a->pipe_fd >= 0) {
663 int copy;
664
665 if ((copy = fdset_put_dup(fds, a->pipe_fd)) < 0)
666 return copy;
667
668 unit_serialize_item_format(u, f, "pipe-fd", "%i", copy);
669 }
670
671 return 0;
672}
673
674static int automount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
675 Automount *a = AUTOMOUNT(u);
676 int r;
677
678 assert(a);
679 assert(fds);
680
681 if (streq(key, "state")) {
682 AutomountState state;
683
684 if ((state = automount_state_from_string(value)) < 0)
685 log_debug("Failed to parse state value %s", value);
686 else
687 a->deserialized_state = state;
81a5c6d0
LP
688 } else if (streq(key, "result")) {
689 AutomountResult f;
690
691 f = automount_result_from_string(value);
692 if (f < 0)
693 log_debug("Failed to parse result value %s", value);
694 else if (f != AUTOMOUNT_SUCCESS)
695 a->result = f;
a16e1123 696
a16e1123
LP
697 } else if (streq(key, "dev-id")) {
698 unsigned d;
699
700 if (safe_atou(value, &d) < 0)
701 log_debug("Failed to parse dev-id value %s", value);
702 else
703 a->dev_id = (unsigned) d;
704 } else if (streq(key, "token")) {
705 unsigned token;
706
707 if (safe_atou(value, &token) < 0)
708 log_debug("Failed to parse token value %s", value);
709 else {
710 if (!a->tokens)
711 if (!(a->tokens = set_new(trivial_hash_func, trivial_compare_func)))
712 return -ENOMEM;
713
714 if ((r = set_put(a->tokens, UINT_TO_PTR(token))) < 0)
715 return r;
716 }
717 } else if (streq(key, "pipe-fd")) {
718 int fd;
719
720 if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
721 log_debug("Failed to parse pipe-fd value %s", value);
722 else {
723 if (a->pipe_fd >= 0)
724 close_nointr_nofail(a->pipe_fd);
725
726 a->pipe_fd = fdset_remove(fds, fd);
727 }
728 } else
729 log_debug("Unknown serialization key '%s'", key);
730
731 return 0;
732}
733
87f0e418 734static UnitActiveState automount_active_state(Unit *u) {
a16e1123 735 assert(u);
87f0e418 736
e537352b 737 return state_translation_table[AUTOMOUNT(u)->state];
5cb5a6ff
LP
738}
739
10a94420
LP
740static const char *automount_sub_state_to_string(Unit *u) {
741 assert(u);
742
a16e1123 743 return automount_state_to_string(AUTOMOUNT(u)->state);
10a94420
LP
744}
745
701cc384
LP
746static bool automount_check_gc(Unit *u) {
747 Automount *a = AUTOMOUNT(u);
748
749 assert(a);
750
57020a3a 751 if (!UNIT_DEREF(a->mount))
7573916f
LP
752 return false;
753
57020a3a 754 return UNIT_VTABLE(UNIT_DEREF(a->mount))->check_gc(UNIT_DEREF(a->mount));
701cc384
LP
755}
756
8d567588 757static void automount_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
701cc384 758 Automount *a = AUTOMOUNT(u);
8d567588
LP
759 union autofs_v5_packet_union packet;
760 ssize_t l;
761 int r;
762
8d567588
LP
763 assert(a);
764 assert(fd == a->pipe_fd);
765
766 if (events != EPOLLIN) {
767 log_error("Got invalid poll event on pipe.");
768 goto fail;
769 }
770
eb22ac37 771 if ((l = loop_read(a->pipe_fd, &packet, sizeof(packet), true)) != sizeof(packet)) {
8d567588
LP
772 log_error("Invalid read from pipe: %s", l < 0 ? strerror(-l) : "short read");
773 goto fail;
774 }
775
776 switch (packet.hdr.type) {
777
778 case autofs_ptype_missing_direct:
941a4041
LP
779
780 if (packet.v5_packet.pid > 0) {
781 char *p = NULL;
782
87d2c1ff 783 get_process_comm(packet.v5_packet.pid, &p);
941a4041
LP
784 log_debug("Got direct mount request for %s, triggered by %lu (%s)", packet.v5_packet.name, (unsigned long) packet.v5_packet.pid, strna(p));
785 free(p);
786
787 } else
788 log_debug("Got direct mount request for %s", packet.v5_packet.name);
8d567588 789
a16e1123
LP
790 if (!a->tokens)
791 if (!(a->tokens = set_new(trivial_hash_func, trivial_compare_func))) {
792 log_error("Failed to allocate token set.");
793 goto fail;
794 }
795
8d567588
LP
796 if ((r = set_put(a->tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token))) < 0) {
797 log_error("Failed to remember token: %s", strerror(-r));
798 goto fail;
799 }
800
801 automount_enter_runnning(a);
802 break;
803
804 default:
805 log_error("Received unknown automount request %i", packet.hdr.type);
806 break;
807 }
808
809 return;
810
811fail:
81a5c6d0 812 automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
8d567588
LP
813}
814
815static void automount_shutdown(Manager *m) {
816 assert(m);
817
818 if (m->dev_autofs_fd >= 0)
819 close_nointr_nofail(m->dev_autofs_fd);
820}
821
74ac3cbd 822static void automount_reset_failed(Unit *u) {
5632e374
LP
823 Automount *a = AUTOMOUNT(u);
824
825 assert(a);
826
74ac3cbd 827 if (a->state == AUTOMOUNT_FAILED)
5632e374
LP
828 automount_set_state(a, AUTOMOUNT_DEAD);
829
81a5c6d0 830 a->result = AUTOMOUNT_SUCCESS;
5632e374
LP
831}
832
a16e1123
LP
833static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
834 [AUTOMOUNT_DEAD] = "dead",
835 [AUTOMOUNT_WAITING] = "waiting",
836 [AUTOMOUNT_RUNNING] = "running",
74ac3cbd 837 [AUTOMOUNT_FAILED] = "failed"
a16e1123
LP
838};
839
840DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState);
841
81a5c6d0
LP
842static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = {
843 [AUTOMOUNT_SUCCESS] = "success",
844 [AUTOMOUNT_FAILURE_RESOURCES] = "resources"
845};
846
847DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult);
848
87f0e418 849const UnitVTable automount_vtable = {
8d567588 850 .suffix = ".automount",
7d17cfbc 851 .object_size = sizeof(Automount),
f975e971
LP
852 .sections =
853 "Unit\0"
854 "Automount\0"
855 "Install\0",
5cb5a6ff 856
e537352b 857 .no_alias = true,
8d567588 858 .no_instances = true,
e537352b 859
034c6ed7 860 .init = automount_init,
e537352b 861 .load = automount_load,
034c6ed7 862 .done = automount_done,
5cb5a6ff 863
a16e1123
LP
864 .coldplug = automount_coldplug,
865
034c6ed7 866 .dump = automount_dump,
5cb5a6ff 867
8d567588
LP
868 .start = automount_start,
869 .stop = automount_stop,
870
a16e1123
LP
871 .serialize = automount_serialize,
872 .deserialize_item = automount_deserialize_item,
873
10a94420 874 .active_state = automount_active_state,
8d567588
LP
875 .sub_state_to_string = automount_sub_state_to_string,
876
701cc384
LP
877 .check_gc = automount_check_gc,
878
8d567588
LP
879 .fd_event = automount_fd_event,
880
74ac3cbd 881 .reset_failed = automount_reset_failed,
5632e374 882
c4e2ceae 883 .bus_interface = "org.freedesktop.systemd1.Automount",
4139c1b2 884 .bus_message_handler = bus_automount_message_handler,
067d72c9 885 .bus_invalidating_properties = bus_automount_invalidating_properties,
4139c1b2 886
8d567588 887 .shutdown = automount_shutdown
5cb5a6ff 888};