]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/automount.c
util-lib: split out IO related calls to io-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 23#include <fcntl.h>
07630cea
LP
24#include <limits.h>
25#include <linux/auto_dev-ioctl.h>
26#include <linux/auto_fs4.h>
8d567588 27#include <sys/epoll.h>
07630cea 28#include <sys/mount.h>
8d567588 29#include <sys/stat.h>
07630cea 30#include <unistd.h>
5cb5a6ff 31
07630cea 32#include "async.h"
3ffd4af2 33#include "automount.h"
07630cea
LP
34#include "bus-error.h"
35#include "bus-util.h"
36#include "dbus-automount.h"
3ffd4af2 37#include "fd-util.h"
07630cea 38#include "formats-util.h"
c004493c 39#include "io-util.h"
e51bc1a2 40#include "label.h"
49e942b2 41#include "mkdir.h"
07630cea 42#include "mount.h"
9eb977db 43#include "path-util.h"
0b452006 44#include "process-util.h"
07630cea
LP
45#include "special.h"
46#include "string-util.h"
47#include "unit-name.h"
48#include "unit.h"
5cb5a6ff 49
e537352b
LP
50static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = {
51 [AUTOMOUNT_DEAD] = UNIT_INACTIVE,
52 [AUTOMOUNT_WAITING] = UNIT_ACTIVE,
53 [AUTOMOUNT_RUNNING] = UNIT_ACTIVE,
74ac3cbd 54 [AUTOMOUNT_FAILED] = UNIT_FAILED
e537352b 55};
5cb5a6ff 56
deb0a77c
MO
57struct expire_data {
58 int dev_autofs_fd;
59 int ioctl_fd;
60};
61
62static inline void expire_data_free(struct expire_data *data) {
63 if (!data)
64 return;
65
66 safe_close(data->dev_autofs_fd);
67 safe_close(data->ioctl_fd);
68 free(data);
69}
70
71DEFINE_TRIVIAL_CLEANUP_FUNC(struct expire_data*, expire_data_free);
72
a16e1123 73static int open_dev_autofs(Manager *m);
718db961 74static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata);
8d567588 75
e537352b
LP
76static void automount_init(Unit *u) {
77 Automount *a = AUTOMOUNT(u);
5cb5a6ff 78
8d567588 79 assert(u);
ac155bb8 80 assert(u->load_state == UNIT_STUB);
8d567588 81
718db961 82 a->pipe_fd = -1;
1cf18f27 83 a->directory_mode = 0755;
1124fe6f 84 UNIT(a)->ignore_on_isolate = true;
8d567588
LP
85}
86
a5e41bdb 87static void repeat_unmount(const char *path) {
8d567588
LP
88 assert(path);
89
90 for (;;) {
1b560190
LP
91 /* If there are multiple mounts on a mount point, this
92 * removes them all */
8d567588
LP
93
94 if (umount2(path, MNT_DETACH) >= 0)
95 continue;
96
97 if (errno != EINVAL)
56f64d95 98 log_error_errno(errno, "Failed to unmount: %m");
8d567588
LP
99
100 break;
101 }
102}
103
deb0a77c
MO
104static int automount_send_ready(Automount *a, Set *tokens, int status);
105
8d567588
LP
106static void unmount_autofs(Automount *a) {
107 assert(a);
108
109 if (a->pipe_fd < 0)
110 return;
111
deb0a77c
MO
112 automount_send_ready(a, a->tokens, -EHOSTDOWN);
113 automount_send_ready(a, a->expire_tokens, -EHOSTDOWN);
8d567588 114
718db961 115 a->pipe_event_source = sd_event_source_unref(a->pipe_event_source);
03e334a1 116 a->pipe_fd = safe_close(a->pipe_fd);
8d567588 117
a16e1123
LP
118 /* If we reload/reexecute things we keep the mount point
119 * around */
120 if (a->where &&
1124fe6f
MS
121 (UNIT(a)->manager->exit_code != MANAGER_RELOAD &&
122 UNIT(a)->manager->exit_code != MANAGER_REEXECUTE))
a5e41bdb 123 repeat_unmount(a->where);
8d567588
LP
124}
125
126static void automount_done(Unit *u) {
127 Automount *a = AUTOMOUNT(u);
128
129 assert(a);
130
131 unmount_autofs(a);
8d567588 132
a1e58e8e 133 a->where = mfree(a->where);
a16e1123 134
525d3cc7
LP
135 a->tokens = set_free(a->tokens);
136 a->expire_tokens = set_free(a->expire_tokens);
deb0a77c
MO
137
138 a->expire_event_source = sd_event_source_unref(a->expire_event_source);
8d567588
LP
139}
140
a57f7e2c
LP
141static int automount_add_mount_links(Automount *a) {
142 _cleanup_free_ char *parent = NULL;
6e2ef85b
LP
143 int r;
144
145 assert(a);
1b560190 146
a57f7e2c 147 r = path_get_parent(a->where, &parent);
0b2665c3 148 if (r < 0)
6e2ef85b
LP
149 return r;
150
a57f7e2c 151 return unit_require_mounts_for(UNIT(a), parent);
6e2ef85b
LP
152}
153
2edd4434
LP
154static int automount_add_default_dependencies(Automount *a) {
155 int r;
156
157 assert(a);
158
b2c23da8 159 if (UNIT(a)->manager->running_as != MANAGER_SYSTEM)
6b1dc2bd 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 169static int automount_verify(Automount *a) {
e1d75803 170 _cleanup_free_ char *e = NULL;
7410616c
LP
171 int r;
172
8d567588
LP
173 assert(a);
174
1124fe6f 175 if (UNIT(a)->load_state != UNIT_LOADED)
8d567588
LP
176 return 0;
177
41e45059 178 if (path_equal(a->where, "/")) {
f2341e0a 179 log_unit_error(UNIT(a), "Cannot have an automount unit for the root directory. Refusing.");
41e45059
LP
180 return -EINVAL;
181 }
182
7410616c
LP
183 r = unit_name_from_path(a->where, ".automount", &e);
184 if (r < 0)
f2341e0a 185 return log_unit_error(UNIT(a), "Failed to generate unit name from path: %m");
8d567588 186
7410616c 187 if (!unit_has_name(UNIT(a), e)) {
f2341e0a 188 log_unit_error(UNIT(a), "Where= setting doesn't match unit name. Refusing.");
8d567588
LP
189 return -EINVAL;
190 }
191
192 return 0;
e537352b 193}
5cb5a6ff 194
e537352b 195static int automount_load(Unit *u) {
e537352b 196 Automount *a = AUTOMOUNT(u);
3ecaa09b 197 int r;
23a177ef 198
e537352b 199 assert(u);
ac155bb8 200 assert(u->load_state == UNIT_STUB);
5cb5a6ff 201
e537352b 202 /* Load a .automount file */
0b2665c3
LP
203 r = unit_load_fragment_and_dropin_optional(u);
204 if (r < 0)
e537352b 205 return r;
23a177ef 206
ac155bb8 207 if (u->load_state == UNIT_LOADED) {
57020a3a 208 Unit *x;
23a177ef 209
0b2665c3 210 if (!a->where) {
7410616c
LP
211 r = unit_name_to_path(u->id, &a->where);
212 if (r < 0)
213 return r;
0b2665c3 214 }
a16e1123
LP
215
216 path_kill_slashes(a->where);
217
3ecaa09b 218 r = unit_load_related_unit(u, ".mount", &x);
0b2665c3 219 if (r < 0)
6e2ef85b
LP
220 return r;
221
3ecaa09b 222 r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
57020a3a 223 if (r < 0)
23a177ef
LP
224 return r;
225
3ecaa09b 226 r = automount_add_mount_links(a);
57020a3a 227 if (r < 0)
23a177ef 228 return r;
4e67ddd6 229
0b2665c3
LP
230 if (UNIT(a)->default_dependencies) {
231 r = automount_add_default_dependencies(a);
232 if (r < 0)
4e67ddd6 233 return r;
0b2665c3 234 }
23a177ef
LP
235 }
236
8d567588 237 return automount_verify(a);
5cb5a6ff
LP
238}
239
8d567588
LP
240static void automount_set_state(Automount *a, AutomountState state) {
241 AutomountState old_state;
e537352b 242 assert(a);
034c6ed7 243
8d567588
LP
244 old_state = a->state;
245 a->state = state;
246
247 if (state != AUTOMOUNT_WAITING &&
248 state != AUTOMOUNT_RUNNING)
249 unmount_autofs(a);
250
251 if (state != old_state)
f2341e0a 252 log_unit_debug(UNIT(a), "Changed %s -> %s", automount_state_to_string(old_state), 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
be847e82 257static int automount_coldplug(Unit *u) {
a16e1123
LP
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
0b2665c3
LP
266 r = open_dev_autofs(u->manager);
267 if (r < 0)
a16e1123
LP
268 return r;
269
270 if (a->deserialized_state == AUTOMOUNT_WAITING ||
271 a->deserialized_state == AUTOMOUNT_RUNNING) {
a16e1123
LP
272 assert(a->pipe_fd >= 0);
273
151b9b96 274 r = sd_event_add_io(u->manager->event, &a->pipe_event_source, a->pipe_fd, EPOLLIN, automount_dispatch_io, u);
0b2665c3 275 if (r < 0)
a16e1123 276 return r;
7dfbe2e3
TG
277
278 (void) sd_event_source_set_description(a->pipe_event_source, "automount-io");
a16e1123
LP
279 }
280
281 automount_set_state(a, a->deserialized_state);
282 }
283
284 return 0;
285}
286
87f0e418 287static void automount_dump(Unit *u, FILE *f, const char *prefix) {
deb0a77c 288 char time_string[FORMAT_TIMESPAN_MAX];
a16e1123 289 Automount *a = AUTOMOUNT(u);
5cb5a6ff 290
a16e1123 291 assert(a);
5cb5a6ff
LP
292
293 fprintf(f,
a16e1123 294 "%sAutomount State: %s\n"
81a5c6d0 295 "%sResult: %s\n"
1cf18f27 296 "%sWhere: %s\n"
deb0a77c
MO
297 "%sDirectoryMode: %04o\n"
298 "%sTimeoutIdleUSec: %s\n",
a16e1123 299 prefix, automount_state_to_string(a->state),
81a5c6d0 300 prefix, automount_result_to_string(a->result),
1cf18f27 301 prefix, a->where,
deb0a77c
MO
302 prefix, a->directory_mode,
303 prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, a->timeout_idle_usec, USEC_PER_SEC));
5cb5a6ff
LP
304}
305
81a5c6d0 306static void automount_enter_dead(Automount *a, AutomountResult f) {
8d567588
LP
307 assert(a);
308
81a5c6d0
LP
309 if (f != AUTOMOUNT_SUCCESS)
310 a->result = f;
8d567588 311
81a5c6d0 312 automount_set_state(a, a->result != AUTOMOUNT_SUCCESS ? AUTOMOUNT_FAILED : AUTOMOUNT_DEAD);
8d567588
LP
313}
314
315static int open_dev_autofs(Manager *m) {
316 struct autofs_dev_ioctl param;
317
318 assert(m);
319
320 if (m->dev_autofs_fd >= 0)
321 return m->dev_autofs_fd;
322
c9bc0764 323 label_fix("/dev/autofs", false, false);
56cf987f 324
0b2665c3 325 m->dev_autofs_fd = open("/dev/autofs", O_CLOEXEC|O_RDONLY);
4a62c710
MS
326 if (m->dev_autofs_fd < 0)
327 return log_error_errno(errno, "Failed to open /dev/autofs: %m");
8d567588
LP
328
329 init_autofs_dev_ioctl(&param);
330 if (ioctl(m->dev_autofs_fd, AUTOFS_DEV_IOCTL_VERSION, &param) < 0) {
03e334a1 331 m->dev_autofs_fd = safe_close(m->dev_autofs_fd);
8d567588
LP
332 return -errno;
333 }
334
335 log_debug("Autofs kernel version %i.%i", param.ver_major, param.ver_minor);
336
337 return m->dev_autofs_fd;
338}
339
340static int open_ioctl_fd(int dev_autofs_fd, const char *where, dev_t devid) {
341 struct autofs_dev_ioctl *param;
342 size_t l;
8d567588
LP
343
344 assert(dev_autofs_fd >= 0);
345 assert(where);
346
347 l = sizeof(struct autofs_dev_ioctl) + strlen(where) + 1;
0b2665c3 348 param = alloca(l);
8d567588
LP
349
350 init_autofs_dev_ioctl(param);
351 param->size = l;
352 param->ioctlfd = -1;
353 param->openmount.devid = devid;
354 strcpy(param->path, where);
355
0b2665c3
LP
356 if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_OPENMOUNT, param) < 0)
357 return -errno;
8d567588 358
0b2665c3
LP
359 if (param->ioctlfd < 0)
360 return -EIO;
8d567588 361
f34beace 362 (void) fd_cloexec(param->ioctlfd, true);
0b2665c3 363 return param->ioctlfd;
8d567588
LP
364}
365
366static int autofs_protocol(int dev_autofs_fd, int ioctl_fd) {
367 uint32_t major, minor;
368 struct autofs_dev_ioctl param;
369
370 assert(dev_autofs_fd >= 0);
371 assert(ioctl_fd >= 0);
372
373 init_autofs_dev_ioctl(&param);
374 param.ioctlfd = ioctl_fd;
375
376 if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_PROTOVER, &param) < 0)
377 return -errno;
378
379 major = param.protover.version;
380
381 init_autofs_dev_ioctl(&param);
382 param.ioctlfd = ioctl_fd;
383
384 if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_PROTOSUBVER, &param) < 0)
385 return -errno;
386
387 minor = param.protosubver.sub_version;
388
389 log_debug("Autofs protocol version %i.%i", major, minor);
390 return 0;
391}
392
deb0a77c 393static int autofs_set_timeout(int dev_autofs_fd, int ioctl_fd, usec_t usec) {
8d567588
LP
394 struct autofs_dev_ioctl param;
395
396 assert(dev_autofs_fd >= 0);
397 assert(ioctl_fd >= 0);
398
399 init_autofs_dev_ioctl(&param);
400 param.ioctlfd = ioctl_fd;
deb0a77c
MO
401
402 /* Convert to seconds, rounding up. */
403 param.timeout.timeout = (usec + USEC_PER_SEC - 1) / USEC_PER_SEC;
8d567588
LP
404
405 if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_TIMEOUT, &param) < 0)
406 return -errno;
407
408 return 0;
409}
410
411static int autofs_send_ready(int dev_autofs_fd, int ioctl_fd, uint32_t token, int status) {
412 struct autofs_dev_ioctl param;
413
414 assert(dev_autofs_fd >= 0);
415 assert(ioctl_fd >= 0);
416
417 init_autofs_dev_ioctl(&param);
418 param.ioctlfd = ioctl_fd;
419
420 if (status) {
421 param.fail.token = token;
422 param.fail.status = status;
423 } else
424 param.ready.token = token;
425
426 if (ioctl(dev_autofs_fd, status ? AUTOFS_DEV_IOCTL_FAIL : AUTOFS_DEV_IOCTL_READY, &param) < 0)
427 return -errno;
428
429 return 0;
430}
431
deb0a77c 432static int automount_send_ready(Automount *a, Set *tokens, int status) {
03e334a1 433 _cleanup_close_ int ioctl_fd = -1;
8d567588 434 unsigned token;
03e334a1 435 int r;
8d567588
LP
436
437 assert(a);
438 assert(status <= 0);
439
deb0a77c 440 if (set_isempty(tokens))
8d567588
LP
441 return 0;
442
0b2665c3 443 ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id);
03e334a1
LP
444 if (ioctl_fd < 0)
445 return ioctl_fd;
8d567588
LP
446
447 if (status)
f2341e0a 448 log_unit_debug_errno(UNIT(a), status, "Sending failure: %m");
8d567588 449 else
f2341e0a 450 log_unit_debug(UNIT(a), "Sending success.");
8d567588 451
e364ad06
LP
452 r = 0;
453
8d567588 454 /* Autofs thankfully does not hand out 0 as a token */
deb0a77c 455 while ((token = PTR_TO_UINT(set_steal_first(tokens)))) {
8d567588
LP
456 int k;
457
458 /* Autofs fun fact II:
459 *
460 * if you pass a positive status code here, the kernel will
461 * freeze! Yay! */
462
0b2665c3
LP
463 k = autofs_send_ready(UNIT(a)->manager->dev_autofs_fd,
464 ioctl_fd,
465 token,
466 status);
467 if (k < 0)
8d567588
LP
468 r = k;
469 }
470
8d567588
LP
471 return r;
472}
473
3dbadf9e
MO
474static int automount_start_expire(Automount *a);
475
deb0a77c 476int automount_update_mount(Automount *a, MountState old_state, MountState state) {
3dbadf9e
MO
477 int r;
478
deb0a77c
MO
479 assert(a);
480
481 switch (state) {
482 case MOUNT_MOUNTED:
483 case MOUNT_REMOUNTING:
484 automount_send_ready(a, a->tokens, 0);
3dbadf9e
MO
485 r = automount_start_expire(a);
486 if (r < 0)
487 log_unit_warning_errno(UNIT(a), r, "Failed to start expiration timer, ignoring: %m");
deb0a77c
MO
488 break;
489 case MOUNT_DEAD:
490 case MOUNT_UNMOUNTING:
491 case MOUNT_MOUNTING_SIGTERM:
492 case MOUNT_MOUNTING_SIGKILL:
493 case MOUNT_REMOUNTING_SIGTERM:
494 case MOUNT_REMOUNTING_SIGKILL:
495 case MOUNT_UNMOUNTING_SIGTERM:
496 case MOUNT_UNMOUNTING_SIGKILL:
497 case MOUNT_FAILED:
498 if (old_state != state)
499 automount_send_ready(a, a->tokens, -ENODEV);
3dbadf9e 500 (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF);
deb0a77c
MO
501 break;
502 default:
503 break;
504 }
505
506 switch (state) {
507 case MOUNT_DEAD:
508 automount_send_ready(a, a->expire_tokens, 0);
509 break;
510 case MOUNT_MOUNTING:
511 case MOUNT_MOUNTING_DONE:
512 case MOUNT_MOUNTING_SIGTERM:
513 case MOUNT_MOUNTING_SIGKILL:
514 case MOUNT_REMOUNTING_SIGTERM:
515 case MOUNT_REMOUNTING_SIGKILL:
516 case MOUNT_UNMOUNTING_SIGTERM:
517 case MOUNT_UNMOUNTING_SIGKILL:
518 case MOUNT_FAILED:
519 if (old_state != state)
520 automount_send_ready(a, a->expire_tokens, -ENODEV);
521 break;
522 default:
523 break;
524 }
525
526 return 0;
527}
528
8d567588 529static void automount_enter_waiting(Automount *a) {
03e334a1 530 _cleanup_close_ int ioctl_fd = -1;
8d567588 531 int p[2] = { -1, -1 };
5ffa8c81
ZJS
532 char name[sizeof("systemd-")-1 + DECIMAL_STR_MAX(pid_t) + 1];
533 char options[sizeof("fd=,pgrp=,minproto=5,maxproto=5,direct")-1
534 + DECIMAL_STR_MAX(int) + DECIMAL_STR_MAX(gid_t) + 1];
8d567588 535 bool mounted = false;
03e334a1 536 int r, dev_autofs_fd;
8d567588
LP
537 struct stat st;
538
539 assert(a);
540 assert(a->pipe_fd < 0);
541 assert(a->where);
542
f2341e0a
LP
543 set_clear(a->tokens);
544
545 r = unit_fail_if_symlink(UNIT(a), a->where);
546 if (r < 0)
547 goto fail;
548
549 (void) mkdir_p_label(a->where, 0555);
550
551 unit_warn_if_dir_nonempty(UNIT(a), a->where);
8d567588 552
0b2665c3
LP
553 dev_autofs_fd = open_dev_autofs(UNIT(a)->manager);
554 if (dev_autofs_fd < 0) {
8d567588
LP
555 r = dev_autofs_fd;
556 goto fail;
557 }
558
a16e1123 559 if (pipe2(p, O_NONBLOCK|O_CLOEXEC) < 0) {
8d567588
LP
560 r = -errno;
561 goto fail;
562 }
563
5ffa8c81
ZJS
564 xsprintf(options, "fd=%i,pgrp="PID_FMT",minproto=5,maxproto=5,direct", p[1], getpgrp());
565 xsprintf(name, "systemd-"PID_FMT, getpid());
8d567588
LP
566 if (mount(name, a->where, "autofs", 0, options) < 0) {
567 r = -errno;
568 goto fail;
569 }
570
571 mounted = true;
572
03e334a1 573 p[1] = safe_close(p[1]);
8d567588
LP
574
575 if (stat(a->where, &st) < 0) {
576 r = -errno;
577 goto fail;
578 }
579
0b2665c3
LP
580 ioctl_fd = open_ioctl_fd(dev_autofs_fd, a->where, st.st_dev);
581 if (ioctl_fd < 0) {
8d567588
LP
582 r = ioctl_fd;
583 goto fail;
584 }
585
0b2665c3
LP
586 r = autofs_protocol(dev_autofs_fd, ioctl_fd);
587 if (r < 0)
8d567588
LP
588 goto fail;
589
deb0a77c 590 r = autofs_set_timeout(dev_autofs_fd, ioctl_fd, a->timeout_idle_usec);
0b2665c3 591 if (r < 0)
8d567588
LP
592 goto fail;
593
594 /* Autofs fun fact:
595 *
596 * Unless we close the ioctl fd here, for some weird reason
597 * the direct mount will not receive events from the
598 * kernel. */
599
151b9b96 600 r = sd_event_add_io(UNIT(a)->manager->event, &a->pipe_event_source, p[0], EPOLLIN, automount_dispatch_io, a);
0b2665c3 601 if (r < 0)
8d567588
LP
602 goto fail;
603
7dfbe2e3
TG
604 (void) sd_event_source_set_description(a->pipe_event_source, "automount-io");
605
8d567588
LP
606 a->pipe_fd = p[0];
607 a->dev_id = st.st_dev;
608
609 automount_set_state(a, AUTOMOUNT_WAITING);
610
611 return;
612
613fail:
3d94f76c 614 safe_close_pair(p);
8d567588
LP
615
616 if (mounted)
a5e41bdb 617 repeat_unmount(a->where);
8d567588 618
f2341e0a 619 log_unit_error_errno(UNIT(a), r, "Failed to initialize automounter: %m");
81a5c6d0 620 automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
8d567588
LP
621}
622
deb0a77c
MO
623static void *expire_thread(void *p) {
624 struct autofs_dev_ioctl param;
625 _cleanup_(expire_data_freep) struct expire_data *data = (struct expire_data*)p;
626 int r;
627
628 assert(data->dev_autofs_fd >= 0);
629 assert(data->ioctl_fd >= 0);
630
631 init_autofs_dev_ioctl(&param);
632 param.ioctlfd = data->ioctl_fd;
633
634 do {
635 r = ioctl(data->dev_autofs_fd, AUTOFS_DEV_IOCTL_EXPIRE, &param);
636 } while (r >= 0);
637
638 if (errno != EAGAIN)
639 log_warning_errno(errno, "Failed to expire automount, ignoring: %m");
640
641 return NULL;
642}
643
deb0a77c
MO
644static int automount_dispatch_expire(sd_event_source *source, usec_t usec, void *userdata) {
645 Automount *a = AUTOMOUNT(userdata);
646 _cleanup_(expire_data_freep) struct expire_data *data = NULL;
647 int r;
648
649 assert(a);
650 assert(source == a->expire_event_source);
651
652 data = new0(struct expire_data, 1);
653 if (!data)
654 return log_oom();
655
656 data->ioctl_fd = -1;
657
658 data->dev_autofs_fd = fcntl(UNIT(a)->manager->dev_autofs_fd, F_DUPFD_CLOEXEC, 3);
659 if (data->dev_autofs_fd < 0)
f2341e0a 660 return log_unit_error_errno(UNIT(a), errno, "Failed to duplicate autofs fd: %m");
deb0a77c
MO
661
662 data->ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id);
663 if (data->ioctl_fd < 0)
f2341e0a 664 return log_unit_error_errno(UNIT(a), data->ioctl_fd, "Couldn't open autofs ioctl fd: %m");
deb0a77c
MO
665
666 r = asynchronous_job(expire_thread, data);
667 if (r < 0)
f2341e0a 668 return log_unit_error_errno(UNIT(a), r, "Failed to start expire job: %m");
deb0a77c
MO
669
670 data = NULL;
671
672 return automount_start_expire(a);
673}
674
675static int automount_start_expire(Automount *a) {
676 int r;
677 usec_t timeout;
678
679 assert(a);
680
93a3b53b
DM
681 if (a->timeout_idle_usec == 0)
682 return 0;
683
dbf5cc47 684 timeout = now(CLOCK_MONOTONIC) + MAX(a->timeout_idle_usec/3, USEC_PER_SEC);
deb0a77c
MO
685
686 if (a->expire_event_source) {
687 r = sd_event_source_set_time(a->expire_event_source, timeout);
688 if (r < 0)
689 return r;
690
691 return sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_ONESHOT);
692 }
693
7dfbe2e3 694 r = sd_event_add_time(
deb0a77c
MO
695 UNIT(a)->manager->event,
696 &a->expire_event_source,
697 CLOCK_MONOTONIC, timeout, 0,
698 automount_dispatch_expire, a);
7dfbe2e3
TG
699 if (r < 0)
700 return r;
701
702 (void) sd_event_source_set_description(a->expire_event_source, "automount-expire");
703
704 return 0;
deb0a77c
MO
705}
706
8d567588 707static void automount_enter_runnning(Automount *a) {
718db961 708 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
3ecaa09b
LP
709 struct stat st;
710 int r;
8d567588
LP
711
712 assert(a);
8d567588 713
ba3e67a7
LP
714 /* We don't take mount requests anymore if we are supposed to
715 * shut down anyway */
31afa0a4 716 if (unit_stop_pending(UNIT(a))) {
f2341e0a 717 log_unit_debug(UNIT(a), "Suppressing automount request since unit stop is scheduled.");
deb0a77c
MO
718 automount_send_ready(a, a->tokens, -EHOSTDOWN);
719 automount_send_ready(a, a->expire_tokens, -EHOSTDOWN);
ba3e67a7
LP
720 return;
721 }
722
d2e54fae 723 mkdir_p_label(a->where, a->directory_mode);
8d567588 724
1cf18f27
LP
725 /* Before we do anything, let's see if somebody is playing games with us? */
726 if (lstat(a->where, &st) < 0) {
f2341e0a 727 log_unit_warning_errno(UNIT(a), errno, "Failed to stat automount point: %m");
8d567588
LP
728 goto fail;
729 }
730
731 if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id)
f2341e0a 732 log_unit_info(UNIT(a), "Automount point already active?");
3ecaa09b
LP
733 else {
734 r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_TRIGGER(UNIT(a)),
735 JOB_REPLACE, true, &error, NULL);
736 if (r < 0) {
f2341e0a 737 log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r));
3ecaa09b
LP
738 goto fail;
739 }
8d567588
LP
740 }
741
742 automount_set_state(a, AUTOMOUNT_RUNNING);
743 return;
744
745fail:
81a5c6d0 746 automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
8d567588
LP
747}
748
749static int automount_start(Unit *u) {
750 Automount *a = AUTOMOUNT(u);
751
752 assert(a);
74ac3cbd 753 assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED);
01f78473 754
e26d6ce5 755 if (path_is_mount_point(a->where, 0) > 0) {
f2341e0a 756 log_unit_error(u, "Path %s is already a mount point, refusing start.", a->where);
8d567588
LP
757 return -EEXIST;
758 }
759
3ecaa09b 760 if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
01f78473 761 return -ENOENT;
8d567588 762
81a5c6d0 763 a->result = AUTOMOUNT_SUCCESS;
8d567588 764 automount_enter_waiting(a);
82a2b6bb 765 return 1;
8d567588
LP
766}
767
768static int automount_stop(Unit *u) {
769 Automount *a = AUTOMOUNT(u);
770
771 assert(a);
8d567588
LP
772 assert(a->state == AUTOMOUNT_WAITING || a->state == AUTOMOUNT_RUNNING);
773
81a5c6d0 774 automount_enter_dead(a, AUTOMOUNT_SUCCESS);
82a2b6bb 775 return 1;
8d567588
LP
776}
777
a16e1123
LP
778static int automount_serialize(Unit *u, FILE *f, FDSet *fds) {
779 Automount *a = AUTOMOUNT(u);
a16e1123 780 Iterator i;
a34ceba6
LP
781 void *p;
782 int r;
a16e1123
LP
783
784 assert(a);
785 assert(f);
786 assert(fds);
787
788 unit_serialize_item(u, f, "state", automount_state_to_string(a->state));
81a5c6d0 789 unit_serialize_item(u, f, "result", automount_result_to_string(a->result));
a16e1123
LP
790 unit_serialize_item_format(u, f, "dev-id", "%u", (unsigned) a->dev_id);
791
792 SET_FOREACH(p, a->tokens, i)
793 unit_serialize_item_format(u, f, "token", "%u", PTR_TO_UINT(p));
deb0a77c
MO
794 SET_FOREACH(p, a->expire_tokens, i)
795 unit_serialize_item_format(u, f, "expire-token", "%u", PTR_TO_UINT(p));
a16e1123 796
a34ceba6
LP
797 r = unit_serialize_item_fd(u, f, fds, "pipe-fd", a->pipe_fd);
798 if (r < 0)
799 return r;
a16e1123
LP
800
801 return 0;
802}
803
804static int automount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
805 Automount *a = AUTOMOUNT(u);
806 int r;
807
808 assert(a);
809 assert(fds);
810
811 if (streq(key, "state")) {
812 AutomountState state;
813
0b2665c3
LP
814 state = automount_state_from_string(value);
815 if (state < 0)
f2341e0a 816 log_unit_debug(u, "Failed to parse state value: %s", value);
a16e1123
LP
817 else
818 a->deserialized_state = state;
81a5c6d0
LP
819 } else if (streq(key, "result")) {
820 AutomountResult f;
821
822 f = automount_result_from_string(value);
823 if (f < 0)
f2341e0a 824 log_unit_debug(u, "Failed to parse result value: %s", value);
81a5c6d0
LP
825 else if (f != AUTOMOUNT_SUCCESS)
826 a->result = f;
a16e1123 827
a16e1123
LP
828 } else if (streq(key, "dev-id")) {
829 unsigned d;
830
831 if (safe_atou(value, &d) < 0)
f2341e0a 832 log_unit_debug(u, "Failed to parse dev-id value: %s", value);
a16e1123
LP
833 else
834 a->dev_id = (unsigned) d;
835 } else if (streq(key, "token")) {
836 unsigned token;
837
838 if (safe_atou(value, &token) < 0)
f2341e0a 839 log_unit_debug(u, "Failed to parse token value: %s", value);
a16e1123 840 else {
f34beace
LP
841 r = set_ensure_allocated(&a->tokens, NULL);
842 if (r < 0) {
843 log_oom();
844 return 0;
845 }
a16e1123 846
0b2665c3
LP
847 r = set_put(a->tokens, UINT_TO_PTR(token));
848 if (r < 0)
f2341e0a 849 log_unit_error_errno(u, r, "Failed to add token to set: %m");
a16e1123 850 }
deb0a77c
MO
851 } else if (streq(key, "expire-token")) {
852 unsigned token;
853
854 if (safe_atou(value, &token) < 0)
f2341e0a 855 log_unit_debug(u, "Failed to parse token value: %s", value);
deb0a77c
MO
856 else {
857 r = set_ensure_allocated(&a->expire_tokens, NULL);
858 if (r < 0) {
859 log_oom();
860 return 0;
861 }
862
863 r = set_put(a->expire_tokens, UINT_TO_PTR(token));
864 if (r < 0)
f2341e0a 865 log_unit_error_errno(u, r, "Failed to add expire token to set: %m");
deb0a77c 866 }
a16e1123
LP
867 } else if (streq(key, "pipe-fd")) {
868 int fd;
869
870 if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
f2341e0a 871 log_unit_debug(u, "Failed to parse pipe-fd value: %s", value);
a16e1123 872 else {
03e334a1 873 safe_close(a->pipe_fd);
a16e1123
LP
874 a->pipe_fd = fdset_remove(fds, fd);
875 }
876 } else
f2341e0a 877 log_unit_debug(u, "Unknown serialization key: %s", key);
a16e1123
LP
878
879 return 0;
880}
881
87f0e418 882static UnitActiveState automount_active_state(Unit *u) {
a16e1123 883 assert(u);
87f0e418 884
e537352b 885 return state_translation_table[AUTOMOUNT(u)->state];
5cb5a6ff
LP
886}
887
10a94420
LP
888static const char *automount_sub_state_to_string(Unit *u) {
889 assert(u);
890
a16e1123 891 return automount_state_to_string(AUTOMOUNT(u)->state);
10a94420
LP
892}
893
701cc384 894static bool automount_check_gc(Unit *u) {
3ecaa09b 895 assert(u);
701cc384 896
3ecaa09b 897 if (!UNIT_TRIGGER(u))
7573916f
LP
898 return false;
899
3ecaa09b 900 return UNIT_VTABLE(UNIT_TRIGGER(u))->check_gc(UNIT_TRIGGER(u));
701cc384
LP
901}
902
718db961 903static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata) {
deb0a77c 904 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
8d567588 905 union autofs_v5_packet_union packet;
718db961 906 Automount *a = AUTOMOUNT(userdata);
5f8ae398 907 struct stat st;
8d567588
LP
908 int r;
909
8d567588
LP
910 assert(a);
911 assert(fd == a->pipe_fd);
912
913 if (events != EPOLLIN) {
f2341e0a 914 log_unit_error(UNIT(a), "Got invalid poll event %"PRIu32" on pipe (fd=%d)", events, fd);
8d567588
LP
915 goto fail;
916 }
917
a6dcc7e5
ZJS
918 r = loop_read_exact(a->pipe_fd, &packet, sizeof(packet), true);
919 if (r < 0) {
f2341e0a 920 log_unit_error_errno(UNIT(a), r, "Invalid read from pipe: %m");
8d567588
LP
921 goto fail;
922 }
923
924 switch (packet.hdr.type) {
925
926 case autofs_ptype_missing_direct:
941a4041
LP
927
928 if (packet.v5_packet.pid > 0) {
e42e801b 929 _cleanup_free_ char *p = NULL;
941a4041 930
87d2c1ff 931 get_process_comm(packet.v5_packet.pid, &p);
f2341e0a 932 log_unit_info(UNIT(a), "Got automount request for %s, triggered by %"PRIu32" (%s)", a->where, packet.v5_packet.pid, strna(p));
941a4041 933 } else
f2341e0a 934 log_unit_debug(UNIT(a), "Got direct mount request on %s", a->where);
8d567588 935
d5099efc 936 r = set_ensure_allocated(&a->tokens, NULL);
0b2665c3 937 if (r < 0) {
f2341e0a 938 log_unit_error(UNIT(a), "Failed to allocate token set.");
0b2665c3
LP
939 goto fail;
940 }
a16e1123 941
0b2665c3
LP
942 r = set_put(a->tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token));
943 if (r < 0) {
f2341e0a 944 log_unit_error_errno(UNIT(a), r, "Failed to remember token: %m");
8d567588
LP
945 goto fail;
946 }
947
948 automount_enter_runnning(a);
949 break;
950
deb0a77c 951 case autofs_ptype_expire_direct:
f2341e0a 952 log_unit_debug(UNIT(a), "Got direct umount request on %s", a->where);
deb0a77c
MO
953
954 (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF);
955
956 r = set_ensure_allocated(&a->expire_tokens, NULL);
957 if (r < 0) {
f2341e0a 958 log_unit_error(UNIT(a), "Failed to allocate token set.");
deb0a77c
MO
959 goto fail;
960 }
961
962 r = set_put(a->expire_tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token));
963 if (r < 0) {
f2341e0a 964 log_unit_error_errno(UNIT(a), r, "Failed to remember token: %m");
deb0a77c
MO
965 goto fail;
966 }
5f8ae398
MO
967
968 /* Before we do anything, let's see if somebody is playing games with us? */
969 if (lstat(a->where, &st) < 0) {
970 log_unit_warning_errno(UNIT(a), errno, "Failed to stat automount point: %m");
971 goto fail;
972 }
973
974 if (!S_ISDIR(st.st_mode) || st.st_dev == a->dev_id) {
975 log_unit_info(UNIT(a), "Automount point already unmounted?");
976 automount_send_ready(a, a->expire_tokens, 0);
977 break;
978 }
979
deb0a77c
MO
980 r = manager_add_job(UNIT(a)->manager, JOB_STOP, UNIT_TRIGGER(UNIT(a)), JOB_REPLACE, true, &error, NULL);
981 if (r < 0) {
f2341e0a 982 log_unit_warning(UNIT(a), "Failed to queue umount startup job: %s", bus_error_message(&error, r));
deb0a77c
MO
983 goto fail;
984 }
985 break;
986
8d567588 987 default:
f2341e0a 988 log_unit_error(UNIT(a), "Received unknown automount request %i", packet.hdr.type);
8d567588
LP
989 break;
990 }
991
718db961 992 return 0;
8d567588
LP
993
994fail:
81a5c6d0 995 automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
718db961 996 return 0;
8d567588
LP
997}
998
999static void automount_shutdown(Manager *m) {
1000 assert(m);
1001
03e334a1 1002 m->dev_autofs_fd = safe_close(m->dev_autofs_fd);
8d567588
LP
1003}
1004
74ac3cbd 1005static void automount_reset_failed(Unit *u) {
5632e374
LP
1006 Automount *a = AUTOMOUNT(u);
1007
1008 assert(a);
1009
74ac3cbd 1010 if (a->state == AUTOMOUNT_FAILED)
5632e374
LP
1011 automount_set_state(a, AUTOMOUNT_DEAD);
1012
81a5c6d0 1013 a->result = AUTOMOUNT_SUCCESS;
5632e374
LP
1014}
1015
1c2e9646 1016static bool automount_supported(void) {
0faacd47
LP
1017 static int supported = -1;
1018
0faacd47
LP
1019 if (supported < 0)
1020 supported = access("/dev/autofs", F_OK) >= 0;
1021
1022 return supported;
1023}
1024
81a5c6d0
LP
1025static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = {
1026 [AUTOMOUNT_SUCCESS] = "success",
1027 [AUTOMOUNT_FAILURE_RESOURCES] = "resources"
1028};
1029
1030DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult);
1031
87f0e418 1032const UnitVTable automount_vtable = {
7d17cfbc 1033 .object_size = sizeof(Automount),
718db961 1034
f975e971
LP
1035 .sections =
1036 "Unit\0"
1037 "Automount\0"
1038 "Install\0",
5cb5a6ff 1039
e537352b 1040 .no_alias = true,
8d567588 1041 .no_instances = true,
e537352b 1042
034c6ed7 1043 .init = automount_init,
e537352b 1044 .load = automount_load,
034c6ed7 1045 .done = automount_done,
5cb5a6ff 1046
a16e1123
LP
1047 .coldplug = automount_coldplug,
1048
034c6ed7 1049 .dump = automount_dump,
5cb5a6ff 1050
8d567588
LP
1051 .start = automount_start,
1052 .stop = automount_stop,
1053
a16e1123
LP
1054 .serialize = automount_serialize,
1055 .deserialize_item = automount_deserialize_item,
1056
10a94420 1057 .active_state = automount_active_state,
8d567588
LP
1058 .sub_state_to_string = automount_sub_state_to_string,
1059
701cc384
LP
1060 .check_gc = automount_check_gc,
1061
74ac3cbd 1062 .reset_failed = automount_reset_failed,
5632e374 1063
718db961 1064 .bus_vtable = bus_automount_vtable,
4139c1b2 1065
c6918296 1066 .shutdown = automount_shutdown,
0faacd47 1067 .supported = automount_supported,
c6918296
MS
1068
1069 .status_message_formats = {
1070 .finished_start_job = {
1071 [JOB_DONE] = "Set up automount %s.",
1072 [JOB_FAILED] = "Failed to set up automount %s.",
c6918296
MS
1073 },
1074 .finished_stop_job = {
1075 [JOB_DONE] = "Unset automount %s.",
1076 [JOB_FAILED] = "Failed to unset automount %s.",
1077 },
1078 },
5cb5a6ff 1079};