]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/automount.c
udev: check-keymaps.sh - fix source directory
[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
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
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
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
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};