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