From b08d03ffe58332f590aae5c78a85e4fc0b8588ce Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Jan 2010 02:07:41 +0100 Subject: [PATCH] add mount enumerator --- device.c | 14 ++- load-fragment.c | 6 +- mount.c | 326 +++++++++++++++++++++++++++++++++++++++++++++++- mount.h | 3 +- unit.c | 39 +++--- unit.h | 2 +- 6 files changed, 361 insertions(+), 29 deletions(-) diff --git a/device.c b/device.c index 22b0f608..6d7e2c6f 100644 --- a/device.c +++ b/device.c @@ -33,7 +33,7 @@ static void device_dump(Unit *u, FILE *f, const char *prefix) { prefix, d->sysfs); } -static int device_add_escaped_name(Unit *u, const char *dn) { +static int device_add_escaped_name(Unit *u, const char *prefix, const char *dn, bool make_id) { char *e; int r; @@ -41,10 +41,14 @@ static int device_add_escaped_name(Unit *u, const char *dn) { assert(dn); assert(dn[0] == '/'); - if (!(e = unit_name_escape_path(dn+1, ".device"))) + if (!(e = unit_name_escape_path(prefix, dn+1, ".device"))) return -ENOMEM; r = unit_add_name(u, e); + + if (r >= 0 && make_id) + unit_choose_id(u, e); + free(e); if (r < 0 && r != -EEXIST) @@ -79,7 +83,7 @@ static int device_process_device(Manager *m, struct udev_device *dev) { return -ENOMEM; assert(sysfs[0] == '/'); - if (!(e = unit_name_escape_path(sysfs+1, ".device"))) + if (!(e = unit_name_escape_path("sysfs-", sysfs+1, ".device"))) return -ENOMEM; if (!(u = manager_get_unit(m, e))) { @@ -116,12 +120,12 @@ static int device_process_device(Manager *m, struct udev_device *dev) { } if (dn) - if ((r = device_add_escaped_name(u, dn)) < 0) + if ((r = device_add_escaped_name(u, "node-", dn, true)) < 0) goto fail; first = udev_device_get_devlinks_list_entry(dev); udev_list_entry_foreach(item, first) - if ((r = device_add_escaped_name(u, udev_list_entry_get_name(item))) < 0) + if ((r = device_add_escaped_name(u, "node-", udev_list_entry_get_name(item), false)) < 0) goto fail; if (names) { diff --git a/load-fragment.c b/load-fragment.c index 1a334bbc..94bdf171 100644 --- a/load-fragment.c +++ b/load-fragment.c @@ -647,6 +647,8 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_id) { if (c++ >= FOLLOW_MAX) return -ELOOP; + path_kill_slashes(*filename); + /* Add the file name we are currently looking at to * the names of this unit */ name = file_name_from_path(*filename); @@ -804,12 +806,12 @@ static int load_from_path(Unit *u, const char *path) { if ((r = unit_add_name(u, k)) < 0) goto finish; - if (id == k) - assert_se(u->meta.id = set_get(u->meta.names, k)); free(k); } + unit_choose_id(u, id); + free(u->meta.load_path); u->meta.load_path = filename; filename = NULL; diff --git a/mount.c b/mount.c index 7a1ec087..ddf0520e 100644 --- a/mount.c +++ b/mount.c @@ -1,12 +1,15 @@ /*-*- Mode: C; c-basic-offset: 8 -*-*/ #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; @@ -33,7 +36,8 @@ static void mount_done(Unit *u) { Mount *d = MOUNT(u); assert(d); - free(d->path); + free(d->what); + free(d->where); } static void mount_dump(Unit *u, FILE *f, const char *prefix) { @@ -52,9 +56,319 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) { fprintf(f, "%sMount State: %s\n" - "%sPath: %s\n", + "%sWhere: %s\n" + "%sWhat: %s\n", prefix, state_table[s->state], - prefix, s->path); + prefix, s->where, + prefix, s->what); +} + +static void mount_shutdown(Manager *m) { +} + +static int mount_add_node_links(Mount *m) { + Unit *device; + char *e; + int r; + + assert(m); + + /* Adds in links to the device that this node is based on */ + + if (!path_startswith(m->what, "/dev/")) + return 0; + + if (!(e = unit_name_escape_path("node-", m->what+1, ".device"))) + return -ENOMEM; + + r = manager_load_unit(UNIT(m)->meta.manager, e, &device); + free(e); + + if (r < 0) + return r; + + if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, device)) < 0) + return r; + + if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, device)) < 0) + return r; + + if ((r = unit_add_dependency(device, UNIT_WANTS, UNIT(m))) < 0) + return r; + + return 0; +} + +static int mount_add_path_links(Mount *m) { + Iterator i; + Unit *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) { + Mount *n; + + if (other->meta.type != UNIT_MOUNT) + continue; + + n = MOUNT(other); + + if (path_startswith(m->where, n->where)) { + + if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, other)) < 0) + return r; + + if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, other)) < 0) + return r; + + } else if (startswith(n->where, m->where)) { + + if ((r = unit_add_dependency(UNIT(m), UNIT_BEFORE, other)) < 0) + return r; + + if ((r = unit_add_dependency(other, UNIT_REQUIRES, UNIT(m))) < 0) + return r; + } + } + + return 0; +} + +static int mount_add_one(Manager *m, const char *what, const char *where) { + char *e; + int r; + Unit *u; + bool delete; + + assert(what); + assert(where); + + /* probably some kind of swap, which we don't cover for now */ + if (where[0] != '/') + return 0; + + if (streq(where, "/")) + e = strdup("rootfs.mount"); + else + e = unit_name_escape_path("fs-", where+1, ".mount"); + + if (!e) + return -ENOMEM; + + if (!(u = manager_get_unit(m, e))) { + delete = true; + + if (!(u = unit_new(m))) { + free(e); + return -ENOMEM; + } + + r = unit_add_name(u, e); + free(e); + + if (r < 0) + goto fail; + + if (!(MOUNT(u)->what = strdup(what)) || + !(MOUNT(u)->where = strdup(where)) || + !(u->meta.description = strdup(where))) { + r = -ENOMEM; + goto fail; + } + } else { + delete = false; + free(e); + } + + 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: + if (delete && u) + unit_free(u); + + return 0; +} + +static char *fstab_node_to_udev_node(char *p) { + char *dn, *t; + int r; + + /* FIXME: to follow udev's logic 100% we need to leave valid + * UTF8 chars unescaped */ + + if (startswith(p, "LABEL=")) { + + if (!(t = strdup(p+6))) + return NULL; + + r = asprintf(&dn, "/dev/disk/by-label/%s", xescape(t, "/ ")); + free(t); + + if (r < 0) + return NULL; + + return dn; + } + + if (startswith(p, "UUID=")) { + + if (!(t = strdup(p+5))) + return NULL; + + r = asprintf(&dn, "/dev/disk/by-uuid/%s", ascii_strlower(xescape(t, "/ "))); + free(t); + + if (r < 0) + return NULL; + + return dn; + } + + return strdup(p); +} + +static int mount_load_etc_fstab(Manager *m) { + FILE *f; + int r; + struct mntent* me; + + assert(m); + + errno = 0; + if (!(f = setmntent("/etc/fstab", "r"))) + return -errno; + + while ((me = getmntent(f))) { + char *where, *what; + + if (!(what = fstab_node_to_udev_node(me->mnt_fsname))) { + r = -ENOMEM; + goto finish; + } + + if (!(where = strdup(me->mnt_dir))) { + free(what); + r = -ENOMEM; + goto finish; + } + + if (what[0] == '/') + path_kill_slashes(what); + + if (where[0] == '/') + path_kill_slashes(where); + + r = mount_add_one(m, what, where); + free(what); + free(where); + + if (r < 0) + goto finish; + } + + r = 0; +finish: + + endmntent(f); + return r; +} + +static int mount_load_proc_mounts(Manager *m) { + FILE *f; + int r; + + assert(m); + + if (!(f = fopen("/proc/self/mountinfo", "r"))) + return -errno; + + for (;;) { + int k; + char *device, *path, *d, *p; + + if ((k = fscanf(f, + "%*s " /* (1) mount id */ + "%*s " /* (2) parent id */ + "%*s " /* (3) major:minor */ + "%*s " /* (4) root */ + "%ms " /* (5) mount point */ + "%*s" /* (6) mount options */ + "%*[^-]" /* (7) optional fields */ + "- " /* (8) seperator */ + "%*s " /* (9) file system type */ + "%ms" /* (10) mount source */ + "%*[^\n]", /* some rubbish at the end */ + &path, + &device)) != 2) { + + if (k == EOF) { + if (feof(f)) + break; + + r = -errno; + goto finish; + } + + r = -EBADMSG; + goto finish; + } + + if (!(d = cunescape(device))) { + free(device); + free(path); + r = -ENOMEM; + goto finish; + } + free(device); + + if (!(p = cunescape(path))) { + free(d); + free(path); + r = -ENOMEM; + goto finish; + } + free(path); + + r = mount_add_one(m, d, p); + free(d); + free(p); + + if (r < 0) + goto finish; + } + + r = 0; + +finish: + fclose(f); + + return r; +} + +static int mount_enumerate(Manager *m) { + int r; + assert(m); + + if ((r = mount_load_etc_fstab(m)) < 0) + goto fail; + + if ((r = mount_load_proc_mounts(m)) < 0) + goto fail; + + return 0; + +fail: + mount_shutdown(m); + return r; } static UnitActiveState mount_active_state(Unit *u) { @@ -75,8 +389,10 @@ const UnitVTable mount_vtable = { .init = mount_init, .done = mount_done, - .dump = mount_dump, - .active_state = mount_active_state, + .enumerate = mount_enumerate, + .shutdown = mount_shutdown, + + .active_state = mount_active_state }; diff --git a/mount.h b/mount.h index 734e96cb..5b5d5a38 100644 --- a/mount.h +++ b/mount.h @@ -20,7 +20,8 @@ struct Mount { Meta meta; MountState state; - char *path; + + char *what, *where; }; extern const UnitVTable mount_vtable; diff --git a/unit.c b/unit.c index dbdd7e66..7723393d 100644 --- a/unit.c +++ b/unit.c @@ -903,32 +903,41 @@ int set_unit_path(const char *p) { return 0; } -char *unit_name_escape_path(const char *path, const char *suffix) { +char *unit_name_escape_path(const char *prefix, const char *path, const char *suffix) { char *r, *t; const char *f; - size_t a, b; + size_t a, b, c; assert(path); - assert(suffix); - /* Takes a path and a util suffix and makes a nice unit name - * of it, escaping all weird chars on the way. + /* Takes a path and a suffix and prefix and makes a nice + * string suitable as unit name of it, escaping all weird + * chars on the way. * - * / becomes _, and all chars not alloweed in a unit name get - * escaped as \xFF, including the _ and the \ itself, of - * course. This escaping is hence reversible. + * / becomes ., and all chars not alloweed in a unit name get + * escaped as \xFF, including \ and ., of course. This + * escaping is hence reversible. */ - a = strlen(path); - b = strlen(suffix); + if (!prefix) + prefix = ""; + + if (!suffix) + suffix = ""; - if (!(r = new(char, a*4+b+1))) + a = strlen(prefix); + b = strlen(path); + c = strlen(suffix); + + if (!(r = new(char, a+b*4+c+1))) return NULL; - for (f = path, t = r; *f; f++) { + memcpy(r, prefix, a); + + for (f = path, t = r+a; *f; f++) { if (*f == '/') - *(t++) = '_'; - else if (*f == '_' || *f == '\\' || !strchr(VALID_CHARS, *f)) { + *(t++) = '.'; + else if (*f == '.' || *f == '\\' || !strchr(VALID_CHARS, *f)) { *(t++) = '\\'; *(t++) = 'x'; *(t++) = hexchar(*f > 4); @@ -937,7 +946,7 @@ char *unit_name_escape_path(const char *path, const char *suffix) { *(t++) = *f; } - memcpy(t, suffix, b+1); + memcpy(t, suffix, c+1); return r; } diff --git a/unit.h b/unit.h index 8505d275..0cd09fe5 100644 --- a/unit.h +++ b/unit.h @@ -240,6 +240,6 @@ bool unit_job_is_applicable(Unit *u, JobType j); const char *unit_path(void); int set_unit_path(const char *p); -char *unit_name_escape_path(const char *path, const char *suffix); +char *unit_name_escape_path(const char *prefix, const char *path, const char *suffix); #endif -- 2.39.5