X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=mount.c;h=728f3a25e4d49dcc40e79a7346338d6af0801b21;hp=ddf0520ed4996d93899e044813f031f6ae07a931;hb=cc13a98b680087b24c1a319d10db98cd755a94d2;hpb=b08d03ffe58332f590aae5c78a85e4fc0b8588ce diff --git a/mount.c b/mount.c index ddf0520ed..728f3a25e 100644 --- a/mount.c +++ b/mount.c @@ -3,53 +3,67 @@ #include #include #include +#include +#include #include "unit.h" #include "mount.h" #include "load-fragment.h" -#include "load-fstab.h" #include "load-dropin.h" #include "log.h" -static int mount_init(Unit *u) { - int r; +static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = { + [MOUNT_DEAD] = UNIT_INACTIVE, + [MOUNT_MOUNTING] = UNIT_ACTIVATING, + [MOUNT_MOUNTED] = UNIT_ACTIVE, + [MOUNT_UNMOUNTING] = UNIT_DEACTIVATING, + [MOUNT_MAINTAINANCE] = UNIT_INACTIVE, +}; + +static const char* const state_string_table[_MOUNT_STATE_MAX] = { + [MOUNT_DEAD] = "dead", + [MOUNT_MOUNTING] = "mounting", + [MOUNT_MOUNTED] = "mounted", + [MOUNT_UNMOUNTING] = "unmounting", + [MOUNT_MAINTAINANCE] = "maintainance" +}; + +static void mount_done(Unit *u) { Mount *m = MOUNT(u); assert(m); + free(m->what); + free(m->where); +} - /* Load a .mount file */ - if ((r = unit_load_fragment(u)) < 0) - return r; +static void mount_set_state(Mount *m, MountState state) { + MountState old_state; + assert(m); - /* Load entry from /etc/fstab */ - if ((r = unit_load_fstab(u)) < 0) - return r; + if (state == m->state) + return; - /* Load drop-in directory data */ - if ((r = unit_load_dropin(u)) < 0) - return r; + old_state = m->state; + m->state = state; - return r; + log_debug("%s changed %s → %s", unit_id(UNIT(m)), state_string_table[old_state], state_string_table[state]); + + unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state]); } -static void mount_done(Unit *u) { - Mount *d = MOUNT(u); +static int mount_coldplug(Unit *u) { + Mount *m = MOUNT(u); - assert(d); - free(d->what); - free(d->where); -} + assert(m); + assert(m->state == MOUNT_DEAD); -static void mount_dump(Unit *u, FILE *f, const char *prefix) { + if (m->from_proc_self_mountinfo) + mount_set_state(m, MOUNT_MOUNTED); - static const char* const state_table[_MOUNT_STATE_MAX] = { - [MOUNT_DEAD] = "dead", - [MOUNT_MOUNTING] = "mounting", - [MOUNT_MOUNTED] = "mounted", - [MOUNT_UNMOUNTING] = "unmounting", - [MOUNT_MAINTAINANCE] = "maintainance" - }; + return 0; +} +static void mount_dump(Unit *u, FILE *f, const char *prefix) { Mount *s = MOUNT(u); assert(s); @@ -57,13 +71,27 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) { fprintf(f, "%sMount State: %s\n" "%sWhere: %s\n" - "%sWhat: %s\n", - prefix, state_table[s->state], + "%sWhat: %s\n" + "%sFrom /etc/fstab: %s\n" + "%sFrom /proc/self/mountinfo: %s\n", + prefix, state_string_table[s->state], prefix, s->where, - prefix, s->what); + prefix, s->what, + prefix, yes_no(s->from_etc_fstab), + prefix, yes_no(s->from_proc_self_mountinfo)); +} + +static UnitActiveState mount_active_state(Unit *u) { + assert(u); + + return state_translation_table[MOUNT(u)->state]; } static void mount_shutdown(Manager *m) { + assert(m); + + if (m->proc_self_mountinfo) + fclose(m->proc_self_mountinfo); } static int mount_add_node_links(Mount *m) { @@ -100,35 +128,34 @@ static int mount_add_node_links(Mount *m) { } static int mount_add_path_links(Mount *m) { - Iterator i; - Unit *other; + Meta *other; int r; /* Adds in link to other mount points, that might lie below or * above us in the hierarchy */ - HASHMAP_FOREACH(other, UNIT(m)->meta.manager->units, i) { + LIST_FOREACH(units_per_type, other, UNIT(m)->meta.manager->units_per_type[UNIT_MOUNT]) { Mount *n; - if (other->meta.type != UNIT_MOUNT) - continue; + n = (Mount*) other; - n = MOUNT(other); + if (n == m) + return 0; if (path_startswith(m->where, n->where)) { - if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, other)) < 0) + if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, (Unit*) other)) < 0) return r; - if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, other)) < 0) + if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, (Unit*) other)) < 0) return r; } else if (startswith(n->where, m->where)) { - if ((r = unit_add_dependency(UNIT(m), UNIT_BEFORE, other)) < 0) + if ((r = unit_add_dependency(UNIT(m), UNIT_BEFORE, (Unit*) other)) < 0) return r; - if ((r = unit_add_dependency(other, UNIT_REQUIRES, UNIT(m))) < 0) + if ((r = unit_add_dependency((Unit*) other, UNIT_REQUIRES, UNIT(m))) < 0) return r; } } @@ -136,12 +163,13 @@ static int mount_add_path_links(Mount *m) { return 0; } -static int mount_add_one(Manager *m, const char *what, const char *where) { +static int mount_add_one(Manager *m, const char *what, const char *where, bool live, bool set_flags) { char *e; int r; Unit *u; bool delete; + assert(m); assert(what); assert(where); @@ -172,23 +200,39 @@ static int mount_add_one(Manager *m, const char *what, const char *where) { goto fail; if (!(MOUNT(u)->what = strdup(what)) || - !(MOUNT(u)->where = strdup(where)) || - !(u->meta.description = strdup(where))) { - r = -ENOMEM; + !(MOUNT(u)->where = strdup(where))) { + r = -ENOMEM; + goto fail; + } + + if ((r = unit_set_description(u, where)) < 0) goto fail; - } + + unit_add_to_load_queue(u); } else { delete = false; free(e); } + if (set_flags) + MOUNT(u)->still_exists = true; + + if (live) { + if (set_flags) + MOUNT(u)->just_created = !MOUNT(u)->from_proc_self_mountinfo; + MOUNT(u)->from_proc_self_mountinfo = true; + } else { + if (set_flags) + MOUNT(u)->just_created = !MOUNT(u)->from_etc_fstab; + MOUNT(u)->from_etc_fstab = true; + } + if ((r = mount_add_node_links(MOUNT(u))) < 0) goto fail; if ((r = mount_add_path_links(MOUNT(u))) < 0) goto fail; - unit_add_to_load_queue(u); return 0; fail: @@ -207,10 +251,10 @@ static char *fstab_node_to_udev_node(char *p) { if (startswith(p, "LABEL=")) { - if (!(t = strdup(p+6))) + if (!(t = xescape(p+6, "/ "))) return NULL; - r = asprintf(&dn, "/dev/disk/by-label/%s", xescape(t, "/ ")); + r = asprintf(&dn, "/dev/disk/by-label/%s", t); free(t); if (r < 0) @@ -221,10 +265,10 @@ static char *fstab_node_to_udev_node(char *p) { if (startswith(p, "UUID=")) { - if (!(t = strdup(p+5))) + if (!(t = xescape(p+5, "/ "))) return NULL; - r = asprintf(&dn, "/dev/disk/by-uuid/%s", ascii_strlower(xescape(t, "/ "))); + r = asprintf(&dn, "/dev/disk/by-uuid/%s", ascii_strlower(t)); free(t); if (r < 0) @@ -236,7 +280,7 @@ static char *fstab_node_to_udev_node(char *p) { return strdup(p); } -static int mount_load_etc_fstab(Manager *m) { +static int mount_load_etc_fstab(Manager *m, bool set_flags) { FILE *f; int r; struct mntent* me; @@ -267,7 +311,7 @@ static int mount_load_etc_fstab(Manager *m) { if (where[0] == '/') path_kill_slashes(where); - r = mount_add_one(m, what, where); + r = mount_add_one(m, what, where, false, set_flags); free(what); free(where); @@ -282,20 +326,18 @@ finish: return r; } -static int mount_load_proc_mounts(Manager *m) { - FILE *f; +static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) { int r; assert(m); - if (!(f = fopen("/proc/self/mountinfo", "r"))) - return -errno; + rewind(m->proc_self_mountinfo); for (;;) { int k; char *device, *path, *d, *p; - if ((k = fscanf(f, + if ((k = fscanf(m->proc_self_mountinfo, "%*s " /* (1) mount id */ "%*s " /* (2) parent id */ "%*s " /* (3) major:minor */ @@ -305,63 +347,64 @@ static int mount_load_proc_mounts(Manager *m) { "%*[^-]" /* (7) optional fields */ "- " /* (8) seperator */ "%*s " /* (9) file system type */ - "%ms" /* (10) mount source */ - "%*[^\n]", /* some rubbish at the end */ + "%ms" /* (10) mount source */ + "%*[^\n]", /* some rubbish at the end */ &path, &device)) != 2) { - if (k == EOF) { - if (feof(f)) - break; - - r = -errno; - goto finish; - } + if (k == EOF) + break; - r = -EBADMSG; - goto finish; + return -EBADMSG; } if (!(d = cunescape(device))) { free(device); free(path); - r = -ENOMEM; - goto finish; + return -ENOMEM; } free(device); if (!(p = cunescape(path))) { free(d); free(path); - r = -ENOMEM; - goto finish; + return -ENOMEM; } free(path); - r = mount_add_one(m, d, p); + r = mount_add_one(m, d, p, true, set_flags); free(d); free(p); if (r < 0) - goto finish; + return r; } - r = 0; - -finish: - fclose(f); - - return r; + return 0; } static int mount_enumerate(Manager *m) { int r; + struct epoll_event ev; assert(m); - if ((r = mount_load_etc_fstab(m)) < 0) + if (!(m->proc_self_mountinfo = fopen("/proc/self/mountinfo", "r"))) + return -errno; + + m->mount_watch.type = WATCH_MOUNT; + m->mount_watch.fd = fileno(m->proc_self_mountinfo); + + zero(ev); + ev.events = EPOLLERR; + ev.data.ptr = &m->mount_watch; + + if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->mount_watch.fd, &ev) < 0) + return -errno; + + if ((r = mount_load_etc_fstab(m, false)) < 0) goto fail; - if ((r = mount_load_proc_mounts(m)) < 0) + if ((r = mount_load_proc_self_mountinfo(m, false)) < 0) goto fail; return 0; @@ -371,28 +414,51 @@ fail: return r; } -static UnitActiveState mount_active_state(Unit *u) { +void mount_fd_event(Manager *m, int events) { + Meta *meta; + int r; + + assert(m); + assert(events == EPOLLERR); + + /* The manager calls this for every fd event happening on the + * /proc/self/mountinfo file, which informs us about mounting + * table changes */ - static const UnitActiveState table[_MOUNT_STATE_MAX] = { - [MOUNT_DEAD] = UNIT_INACTIVE, - [MOUNT_MOUNTING] = UNIT_ACTIVATING, - [MOUNT_MOUNTED] = UNIT_ACTIVE, - [MOUNT_UNMOUNTING] = UNIT_DEACTIVATING, - [MOUNT_MAINTAINANCE] = UNIT_INACTIVE, - }; + if ((r = mount_load_proc_self_mountinfo(m, true)) < 0) { + log_error("Failed to reread /proc/self/mountinfo: %s", strerror(-errno)); + return; + } + + manager_dispatch_load_queue(m); + + LIST_FOREACH(units_per_type, meta, m->units_per_type[UNIT_MOUNT]) { + Mount *mount = (Mount*) meta; + + if (mount->just_created && mount->state == MOUNT_DEAD) + mount_set_state(mount, MOUNT_MOUNTED); + else if (!mount->still_exists && mount->state == MOUNT_MOUNTED) { + mount_set_state(mount, MOUNT_DEAD); + mount->from_proc_self_mountinfo = false; + } - return table[MOUNT(u)->state]; + /* Clear the flags for later calls */ + mount->just_created = false; + mount->still_exists = false; + } } const UnitVTable mount_vtable = { .suffix = ".mount", - .init = mount_init, + .init = unit_load_fragment_and_dropin, .done = mount_done, + .coldplug = mount_coldplug, + .dump = mount_dump, - .enumerate = mount_enumerate, - .shutdown = mount_shutdown, + .active_state = mount_active_state, - .active_state = mount_active_state + .enumerate = mount_enumerate, + .shutdown = mount_shutdown };