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