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