1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
11 #include "load-fragment.h"
12 #include "load-dropin.h"
15 static const UnitActiveState state_translation_table
[_MOUNT_STATE_MAX
] = {
16 [MOUNT_DEAD
] = UNIT_INACTIVE
,
17 [MOUNT_MOUNTING
] = UNIT_ACTIVATING
,
18 [MOUNT_MOUNTED
] = UNIT_ACTIVE
,
19 [MOUNT_UNMOUNTING
] = UNIT_DEACTIVATING
,
20 [MOUNT_MAINTAINANCE
] = UNIT_INACTIVE
,
23 static const char* const state_string_table
[_MOUNT_STATE_MAX
] = {
24 [MOUNT_DEAD
] = "dead",
25 [MOUNT_MOUNTING
] = "mounting",
26 [MOUNT_MOUNTED
] = "mounted",
27 [MOUNT_UNMOUNTING
] = "unmounting",
28 [MOUNT_MAINTAINANCE
] = "maintainance"
31 static void mount_done(Unit
*u
) {
39 static void mount_set_state(Mount
*m
, MountState state
) {
43 if (state
== m
->state
)
49 log_debug("%s changed %s → %s", unit_id(UNIT(m
)), state_string_table
[old_state
], state_string_table
[state
]);
51 unit_notify(UNIT(m
), state_translation_table
[old_state
], state_translation_table
[state
]);
54 static int mount_coldplug(Unit
*u
) {
58 assert(m
->state
== MOUNT_DEAD
);
60 if (m
->from_proc_self_mountinfo
)
61 mount_set_state(m
, MOUNT_MOUNTED
);
66 static void mount_dump(Unit
*u
, FILE *f
, const char *prefix
) {
75 "%sFrom /etc/fstab: %s\n"
76 "%sFrom /proc/self/mountinfo: %s\n",
77 prefix
, state_string_table
[s
->state
],
80 prefix
, yes_no(s
->from_etc_fstab
),
81 prefix
, yes_no(s
->from_proc_self_mountinfo
));
84 static UnitActiveState
mount_active_state(Unit
*u
) {
87 return state_translation_table
[MOUNT(u
)->state
];
90 static void mount_shutdown(Manager
*m
) {
93 if (m
->proc_self_mountinfo
)
94 fclose(m
->proc_self_mountinfo
);
97 static int mount_add_node_links(Mount
*m
) {
104 /* Adds in links to the device that this node is based on */
106 if (!path_startswith(m
->what
, "/dev/"))
109 if (!(e
= unit_name_escape_path("node-", m
->what
+1, ".device")))
112 r
= manager_load_unit(UNIT(m
)->meta
.manager
, e
, &device
);
118 if ((r
= unit_add_dependency(UNIT(m
), UNIT_AFTER
, device
)) < 0)
121 if ((r
= unit_add_dependency(UNIT(m
), UNIT_REQUIRES
, device
)) < 0)
124 if ((r
= unit_add_dependency(device
, UNIT_WANTS
, UNIT(m
))) < 0)
130 static int mount_add_path_links(Mount
*m
) {
134 /* Adds in link to other mount points, that might lie below or
135 * above us in the hierarchy */
137 LIST_FOREACH(units_per_type
, other
, UNIT(m
)->meta
.manager
->units_per_type
[UNIT_MOUNT
]) {
145 if (path_startswith(m
->where
, n
->where
)) {
147 if ((r
= unit_add_dependency(UNIT(m
), UNIT_AFTER
, (Unit
*) other
)) < 0)
150 if ((r
= unit_add_dependency(UNIT(m
), UNIT_REQUIRES
, (Unit
*) other
)) < 0)
153 } else if (startswith(n
->where
, m
->where
)) {
155 if ((r
= unit_add_dependency(UNIT(m
), UNIT_BEFORE
, (Unit
*) other
)) < 0)
158 if ((r
= unit_add_dependency((Unit
*) other
, UNIT_REQUIRES
, UNIT(m
))) < 0)
166 static int mount_add_one(Manager
*m
, const char *what
, const char *where
, bool live
, bool set_flags
) {
176 /* probably some kind of swap, which we don't cover for now */
180 if (streq(where
, "/"))
181 e
= strdup("rootfs.mount");
183 e
= unit_name_escape_path("fs-", where
+1, ".mount");
188 if (!(u
= manager_get_unit(m
, e
))) {
191 if (!(u
= unit_new(m
))) {
196 r
= unit_add_name(u
, e
);
202 if (!(MOUNT(u
)->what
= strdup(what
)) ||
203 !(MOUNT(u
)->where
= strdup(where
))) {
208 if ((r
= unit_set_description(u
, where
)) < 0)
217 MOUNT(u
)->still_exists
= true;
221 MOUNT(u
)->just_created
= !MOUNT(u
)->from_proc_self_mountinfo
;
222 MOUNT(u
)->from_proc_self_mountinfo
= true;
225 MOUNT(u
)->just_created
= !MOUNT(u
)->from_etc_fstab
;
226 MOUNT(u
)->from_etc_fstab
= true;
229 if ((r
= mount_add_node_links(MOUNT(u
))) < 0)
232 if ((r
= mount_add_path_links(MOUNT(u
))) < 0)
235 unit_add_to_load_queue(u
);
246 static char *fstab_node_to_udev_node(char *p
) {
250 /* FIXME: to follow udev's logic 100% we need to leave valid
251 * UTF8 chars unescaped */
253 if (startswith(p
, "LABEL=")) {
255 if (!(t
= xescape(p
+6, "/ ")))
258 r
= asprintf(&dn
, "/dev/disk/by-label/%s", t
);
267 if (startswith(p
, "UUID=")) {
269 if (!(t
= xescape(p
+5, "/ ")))
272 r
= asprintf(&dn
, "/dev/disk/by-uuid/%s", ascii_strlower(t
));
284 static int mount_load_etc_fstab(Manager
*m
, bool set_flags
) {
292 if (!(f
= setmntent("/etc/fstab", "r")))
295 while ((me
= getmntent(f
))) {
298 if (!(what
= fstab_node_to_udev_node(me
->mnt_fsname
))) {
303 if (!(where
= strdup(me
->mnt_dir
))) {
310 path_kill_slashes(what
);
313 path_kill_slashes(where
);
315 r
= mount_add_one(m
, what
, where
, false, set_flags
);
330 static int mount_load_proc_self_mountinfo(Manager
*m
, bool set_flags
) {
335 rewind(m
->proc_self_mountinfo
);
339 char *device
, *path
, *d
, *p
;
341 if ((k
= fscanf(m
->proc_self_mountinfo
,
342 "%*s " /* (1) mount id */
343 "%*s " /* (2) parent id */
344 "%*s " /* (3) major:minor */
345 "%*s " /* (4) root */
346 "%ms " /* (5) mount point */
347 "%*s" /* (6) mount options */
348 "%*[^-]" /* (7) optional fields */
349 "- " /* (8) seperator */
350 "%*s " /* (9) file system type */
351 "%ms" /* (10) mount source */
352 "%*[^\n]", /* some rubbish at the end */
362 if (!(d
= cunescape(device
))) {
369 if (!(p
= cunescape(path
))) {
376 r
= mount_add_one(m
, d
, p
, true, set_flags
);
387 static int mount_enumerate(Manager
*m
) {
389 struct epoll_event ev
;
392 if (!(m
->proc_self_mountinfo
= fopen("/proc/self/mountinfo", "r")))
395 m
->mount_watch
.type
= WATCH_MOUNT
;
396 m
->mount_watch
.fd
= fileno(m
->proc_self_mountinfo
);
399 ev
.events
= EPOLLERR
;
400 ev
.data
.ptr
= &m
->mount_watch
;
402 if (epoll_ctl(m
->epoll_fd
, EPOLL_CTL_ADD
, m
->mount_watch
.fd
, &ev
) < 0)
405 if ((r
= mount_load_etc_fstab(m
, false)) < 0)
408 if ((r
= mount_load_proc_self_mountinfo(m
, false)) < 0)
418 void mount_fd_event(Manager
*m
, int events
) {
423 assert(events
== POLLERR
);
425 /* The manager calls this for every fd event happening on the
426 * /proc/self/mountinfo file, which informs us about mounting
429 if ((r
= mount_load_proc_self_mountinfo(m
, true)) < 0) {
430 log_error("Failed to reread /proc/self/mountinfo: %s", strerror(-errno
));
434 manager_dispatch_load_queue(m
);
436 LIST_FOREACH(units_per_type
, meta
, m
->units_per_type
[UNIT_MOUNT
]) {
437 Mount
*mount
= (Mount
*) meta
;
439 if (mount
->just_created
&& mount
->state
== MOUNT_DEAD
)
440 mount_set_state(mount
, MOUNT_MOUNTED
);
441 else if (!mount
->still_exists
&& mount
->state
== MOUNT_MOUNTED
) {
442 mount_set_state(mount
, MOUNT_DEAD
);
443 mount
->from_proc_self_mountinfo
= false;
446 /* Clear the flags for later calls */
447 mount
->just_created
= false;
448 mount
->still_exists
= false;
452 const UnitVTable mount_vtable
= {
455 .init
= unit_load_fragment_and_dropin
,
457 .coldplug
= mount_coldplug
,
461 .active_state
= mount_active_state
,
463 .enumerate
= mount_enumerate
,
464 .shutdown
= mount_shutdown