X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fload-fragment.c;h=0961d945aa3a2d042fc29389019d2bf032dd2ccf;hp=e448d04783919eff3729a4058d0fe7ecab66f4cd;hb=1124fe6f01b1d59d016c238026f20380f38d98dc;hpb=f975e971accc4d50c73ae53167db3df7a7099cf2 diff --git a/src/load-fragment.c b/src/load-fragment.c index e448d0478..0961d945a 100644 --- a/src/load-fragment.c +++ b/src/load-fragment.c @@ -84,7 +84,8 @@ int config_parse_unit_deps( char *t, *k; int r; - if (!(t = strndup(w, l))) + t = strndup(w, l); + if (!t) return -ENOMEM; k = unit_name_printf(u, t); @@ -94,12 +95,8 @@ int config_parse_unit_deps( return -ENOMEM; r = unit_add_dependency_by_name(u, d, k, NULL, true); - - if (r < 0) { - log_error("Failed to add dependency on %s, ignoring: %s", k, strerror(-r)); - free(k); - return 0; - } + if (r < 0) + log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r)); free(k); } @@ -554,6 +551,7 @@ int config_parse_exec( if (!n[0]) { log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue); strv_free(n); + free(path); return 0; } @@ -1264,6 +1262,7 @@ int config_parse_timer_unit( Timer *t = data; int r; DBusError error; + Unit *u; assert(filename); assert(lvalue); @@ -1277,12 +1276,15 @@ int config_parse_timer_unit( return 0; } - if ((r = manager_load_unit(t->meta.manager, rvalue, NULL, NULL, &t->unit)) < 0) { + r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, NULL, &u); + if (r < 0) { log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r)); dbus_error_free(&error); return 0; } + unit_ref_set(&t->unit, u); + return 0; } @@ -1346,6 +1348,7 @@ int config_parse_path_unit( Path *t = data; int r; DBusError error; + Unit *u; assert(filename); assert(lvalue); @@ -1359,12 +1362,14 @@ int config_parse_path_unit( return 0; } - if ((r = manager_load_unit(t->meta.manager, rvalue, NULL, &error, &t->unit)) < 0) { + if ((r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, &error, &u)) < 0) { log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r)); dbus_error_free(&error); return 0; } + unit_ref_set(&t->unit, u); + return 0; } @@ -1381,6 +1386,7 @@ int config_parse_socket_service( Socket *s = data; int r; DBusError error; + Unit *x; assert(filename); assert(lvalue); @@ -1394,12 +1400,15 @@ int config_parse_socket_service( return 0; } - if ((r = manager_load_unit(s->meta.manager, rvalue, NULL, &error, (Unit**) &s->service)) < 0) { + r = manager_load_unit(UNIT(s)->manager, rvalue, NULL, &error, &x); + if (r < 0) { log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r)); dbus_error_free(&error); return 0; } + unit_ref_set(&s->service, x); + return 0; } @@ -1415,7 +1424,6 @@ int config_parse_service_sockets( Service *s = data; int r; - DBusError error; char *state, *w; size_t l; @@ -1424,35 +1432,34 @@ int config_parse_service_sockets( assert(rvalue); assert(data); - dbus_error_init(&error); - FOREACH_WORD_QUOTED(w, l, rvalue, state) { - char *t; - Unit *sock; + char *t, *k; - if (!(t = strndup(w, l))) + t = strndup(w, l); + if (!t) return -ENOMEM; - if (!endswith(t, ".socket")) { - log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue); - free(t); - continue; - } - - r = manager_load_unit(s->meta.manager, t, NULL, &error, &sock); + k = unit_name_printf(UNIT(s), t); free(t); - if (r < 0) { - log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r)); - dbus_error_free(&error); + if (!k) + return -ENOMEM; + + if (!endswith(k, ".socket")) { + log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue); + free(k); continue; } - if ((r = set_ensure_allocated(&s->configured_sockets, trivial_hash_func, trivial_compare_func)) < 0) - return r; + r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true); + if (r < 0) + log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r)); - if ((r = set_put(s->configured_sockets, sock)) < 0) + r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true); + if (r < 0) return r; + + free(k); } return 0; @@ -1545,10 +1552,12 @@ int config_parse_unit_condition_path( assert(rvalue); assert(data); - if ((trigger = rvalue[0] == '|')) + trigger = rvalue[0] == '|'; + if (trigger) rvalue++; - if ((negate = rvalue[0] == '!')) + negate = rvalue[0] == '!'; + if (negate) rvalue++; if (!path_is_absolute(rvalue)) { @@ -1556,10 +1565,11 @@ int config_parse_unit_condition_path( return 0; } - if (!(c = condition_new(cond, rvalue, trigger, negate))) + c = condition_new(cond, rvalue, trigger, negate); + if (!c) return -ENOMEM; - LIST_PREPEND(Condition, conditions, u->meta.conditions, c); + LIST_PREPEND(Condition, conditions, u->conditions, c); return 0; } @@ -1592,7 +1602,7 @@ int config_parse_unit_condition_string( if (!(c = condition_new(cond, rvalue, trigger, negate))) return -ENOMEM; - LIST_PREPEND(Condition, conditions, u->meta.conditions, c); + LIST_PREPEND(Condition, conditions, u->conditions, c); return 0; } @@ -1633,12 +1643,381 @@ int config_parse_unit_condition_null( if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate))) return -ENOMEM; - LIST_PREPEND(Condition, conditions, u->meta.conditions, c); + LIST_PREPEND(Condition, conditions, u->conditions, c); return 0; } DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier"); +int config_parse_unit_cgroup_attr( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Unit *u = data; + char **l; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + l = strv_split_quoted(rvalue); + if (!l) + return -ENOMEM; + + if (strv_length(l) != 2) { + log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue); + strv_free(l); + return 0; + } + + r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL); + strv_free(l); + + if (r < 0) { + log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue); + return 0; + } + + return 0; +} + +int config_parse_unit_cpu_shares(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) { + Unit *u = data; + int r; + unsigned long ul; + char *t; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (safe_atolu(rvalue, &ul) < 0 || ul < 1) { + log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue); + return 0; + } + + if (asprintf(&t, "%lu", ul) < 0) + return -ENOMEM; + + r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL); + free(t); + + if (r < 0) { + log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue); + return 0; + } + + return 0; +} + +int config_parse_unit_memory_limit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) { + Unit *u = data; + int r; + off_t sz; + char *t; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) { + log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue); + return 0; + } + + if (asprintf(&t, "%llu", (unsigned long long) sz) < 0) + return -ENOMEM; + + r = unit_add_cgroup_attribute(u, + "memory", + streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes", + t, NULL); + free(t); + + if (r < 0) { + log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue); + return 0; + } + + return 0; +} + +static int device_map(const char *controller, const char *name, const char *value, char **ret) { + char **l; + + assert(controller); + assert(name); + assert(value); + assert(ret); + + l = strv_split_quoted(value); + if (!l) + return -ENOMEM; + + assert(strv_length(l) >= 1); + + if (streq(l[0], "*")) { + + if (asprintf(ret, "a *:*%s%s", + isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) { + strv_free(l); + return -ENOMEM; + } + + } else { + struct stat st; + + if (stat(l[0], &st) < 0) { + log_warning("Couldn't stat device %s", l[0]); + strv_free(l); + return -errno; + } + + if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) { + log_warning("%s is not a device.", l[0]); + strv_free(l); + return -ENODEV; + } + + if (asprintf(ret, "%c %u:%u%s%s", + S_ISCHR(st.st_mode) ? 'c' : 'b', + major(st.st_rdev), minor(st.st_rdev), + isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) { + + strv_free(l); + return -ENOMEM; + } + } + + strv_free(l); + return 0; +} + +int config_parse_unit_device_allow(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) { + Unit *u = data; + char **l; + int r; + unsigned k; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + l = strv_split_quoted(rvalue); + if (!l) + return -ENOMEM; + + k = strv_length(l); + if (k < 1 || k > 2) { + log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue); + strv_free(l); + return 0; + } + + if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) { + log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue); + strv_free(l); + return 0; + } + + if (!isempty(l[1]) && !in_charset(l[1], "rwm")) { + log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue); + strv_free(l); + return 0; + } + strv_free(l); + + r = unit_add_cgroup_attribute(u, "devices", + streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny", + rvalue, device_map); + + if (r < 0) { + log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue); + return 0; + } + + return 0; +} + +static int blkio_map(const char *controller, const char *name, const char *value, char **ret) { + struct stat st; + char **l; + dev_t d; + + assert(controller); + assert(name); + assert(value); + assert(ret); + + l = strv_split_quoted(value); + if (!l) + return -ENOMEM; + + assert(strv_length(l) == 2); + + if (stat(l[0], &st) < 0) { + log_warning("Couldn't stat device %s", l[0]); + strv_free(l); + return -errno; + } + + if (S_ISBLK(st.st_mode)) + d = st.st_rdev; + else if (major(st.st_dev) != 0) { + /* If this is not a device node then find the block + * device this file is stored on */ + d = st.st_dev; + + /* If this is a partition, try to get the originating + * block device */ + block_get_whole_disk(d, &d); + } else { + log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]); + strv_free(l); + return -ENODEV; + } + + if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) { + strv_free(l); + return -ENOMEM; + } + + strv_free(l); + return 0; +} + +int config_parse_unit_blkio_weight(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) { + Unit *u = data; + int r; + unsigned long ul; + const char *device = NULL, *weight; + unsigned k; + char *t, **l; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + l = strv_split_quoted(rvalue); + if (!l) + return -ENOMEM; + + k = strv_length(l); + if (k < 1 || k > 2) { + log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue); + strv_free(l); + return 0; + } + + if (k == 1) + weight = l[0]; + else { + device = l[0]; + weight = l[1]; + } + + if (device && !path_is_absolute(device)) { + log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue); + strv_free(l); + return 0; + } + + if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) { + log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue); + strv_free(l); + return 0; + } + + if (device) + r = asprintf(&t, "%s %lu", device, ul); + else + r = asprintf(&t, "%lu", ul); + strv_free(l); + + if (r < 0) + return -ENOMEM; + + if (device) + r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map); + else + r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL); + free(t); + + if (r < 0) { + log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue); + return 0; + } + + return 0; +} + +int config_parse_unit_blkio_bandwidth(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) { + Unit *u = data; + int r; + off_t bytes; + unsigned k; + char *t, **l; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + l = strv_split_quoted(rvalue); + if (!l) + return -ENOMEM; + + k = strv_length(l); + if (k != 2) { + log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue); + strv_free(l); + return 0; + } + + if (!path_is_absolute(l[0])) { + log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue); + strv_free(l); + return 0; + } + + if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) { + log_error("[%s:%u] Failed to parse block IO bandwith value, ignoring: %s", filename, line, rvalue); + strv_free(l); + return 0; + } + + r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes); + strv_free(l); + + if (r < 0) + return -ENOMEM; + + r = unit_add_cgroup_attribute(u, "blkio", + streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device", + t, blkio_map); + free(t); + + if (r < 0) { + log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue); + return 0; + } + + return 0; +} + + #define FOLLOW_MAX 8 static int open_follow(char **filename, FILE **_f, Set *names, char **_final) { @@ -1730,7 +2109,7 @@ static int merge_by_names(Unit **u, Set *names, const char *id) { * ours? Then let's try it the other way * round */ - other = manager_get_unit((*u)->meta.manager, k); + other = manager_get_unit((*u)->manager, k); free(k); if (other) @@ -1784,7 +2163,7 @@ static int load_from_path(Unit *u, const char *path) { } else { char **p; - STRV_FOREACH(p, u->meta.manager->lookup_paths.unit_path) { + STRV_FOREACH(p, u->manager->lookup_paths.unit_path) { /* Instead of opening the path right away, we manually * follow all symlinks and add their name to our unit @@ -1794,8 +2173,8 @@ static int load_from_path(Unit *u, const char *path) { goto finish; } - if (u->meta.manager->unit_path_cache && - !set_get(u->meta.manager->unit_path_cache, filename)) + if (u->manager->unit_path_cache && + !set_get(u->manager->unit_path_cache, filename)) r = -ENOENT; else r = open_follow(&filename, &f, symlink_names, &id); @@ -1831,7 +2210,7 @@ static int load_from_path(Unit *u, const char *path) { goto finish; if (merged != u) { - u->meta.load_state = UNIT_MERGED; + u->load_state = UNIT_MERGED; r = 0; goto finish; } @@ -1843,21 +2222,21 @@ static int load_from_path(Unit *u, const char *path) { } if (null_or_empty(&st)) - u->meta.load_state = UNIT_MASKED; + u->load_state = UNIT_MASKED; else { /* Now, parse the file contents */ r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u); if (r < 0) goto finish; - u->meta.load_state = UNIT_LOADED; + u->load_state = UNIT_LOADED; } - free(u->meta.fragment_path); - u->meta.fragment_path = filename; + free(u->fragment_path); + u->fragment_path = filename; filename = NULL; - u->meta.fragment_mtime = timespec_load(&st.st_mtim); + u->fragment_mtime = timespec_load(&st.st_mtim); r = 0; @@ -1877,49 +2256,49 @@ int unit_load_fragment(Unit *u) { const char *t; assert(u); - assert(u->meta.load_state == UNIT_STUB); - assert(u->meta.id); + assert(u->load_state == UNIT_STUB); + assert(u->id); /* First, try to find the unit under its id. We always look * for unit files in the default directories, to make it easy * to override things by placing things in /etc/systemd/system */ - if ((r = load_from_path(u, u->meta.id)) < 0) + if ((r = load_from_path(u, u->id)) < 0) return r; /* Try to find an alias we can load this with */ - if (u->meta.load_state == UNIT_STUB) - SET_FOREACH(t, u->meta.names, i) { + if (u->load_state == UNIT_STUB) + SET_FOREACH(t, u->names, i) { - if (t == u->meta.id) + if (t == u->id) continue; if ((r = load_from_path(u, t)) < 0) return r; - if (u->meta.load_state != UNIT_STUB) + if (u->load_state != UNIT_STUB) break; } /* And now, try looking for it under the suggested (originally linked) path */ - if (u->meta.load_state == UNIT_STUB && u->meta.fragment_path) { + if (u->load_state == UNIT_STUB && u->fragment_path) { - if ((r = load_from_path(u, u->meta.fragment_path)) < 0) + if ((r = load_from_path(u, u->fragment_path)) < 0) return r; - if (u->meta.load_state == UNIT_STUB) { + if (u->load_state == UNIT_STUB) { /* Hmm, this didn't work? Then let's get rid * of the fragment path stored for us, so that * we don't point to an invalid location. */ - free(u->meta.fragment_path); - u->meta.fragment_path = NULL; + free(u->fragment_path); + u->fragment_path = NULL; } } /* Look for a template */ - if (u->meta.load_state == UNIT_STUB && u->meta.instance) { + if (u->load_state == UNIT_STUB && u->instance) { char *k; - if (!(k = unit_name_template(u->meta.id))) + if (!(k = unit_name_template(u->id))) return -ENOMEM; r = load_from_path(u, k); @@ -1928,10 +2307,10 @@ int unit_load_fragment(Unit *u) { if (r < 0) return r; - if (u->meta.load_state == UNIT_STUB) - SET_FOREACH(t, u->meta.names, i) { + if (u->load_state == UNIT_STUB) + SET_FOREACH(t, u->names, i) { - if (t == u->meta.id) + if (t == u->id) continue; if (!(k = unit_name_template(t))) @@ -1943,7 +2322,7 @@ int unit_load_fragment(Unit *u) { if (r < 0) return r; - if (u->meta.load_state != UNIT_STUB) + if (u->load_state != UNIT_STUB) break; } }