Branch data 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 : 56 : static void automount_shutdown(Manager *m) {
1058 [ - + ]: 56 : assert(m);
1059 : :
1060 : 56 : m->dev_autofs_fd = safe_close(m->dev_autofs_fd);
1061 : 56 : }
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 : 88 : static bool automount_supported(void) {
1075 : : static int supported = -1;
1076 : :
1077 [ + + ]: 88 : if (supported < 0)
1078 : 20 : supported = access("/dev/autofs", F_OK) >= 0;
1079 : :
1080 : 88 : 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 [ + + + + ]: 48 : 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 : : };
|