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