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