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