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