From f499daf4b3fbd24071b9f301ef6401e258d1b1d6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 9 Nov 2015 23:47:29 +0100 Subject: virt: make sure that we detect unknown container managers as VIRTUALIZATION_CONTAINER_OTHER If we don't know a container manager, we should consider it as "other" rather than as no container manager at all, to provide a somwhat useful upgrade path. --- src/basic/virt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/basic/virt.c b/src/basic/virt.c index ff006e96c6..d088b7a804 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -400,7 +400,7 @@ int detect_container(void) { goto finish; } - r = VIRTUALIZATION_NONE; + r = VIRTUALIZATION_CONTAINER_OTHER; finish: cached_found = r; -- cgit v1.2.3-54-g00ecf From a6a4d3c46bd41e2f33e8eb61ac53b3c79049f167 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 10 Nov 2015 00:36:57 +0100 Subject: cgls: suppress output of controller name, if it's the systemd one --- src/cgls/cgls.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c index 4e9a76a100..a5a580438a 100644 --- a/src/cgls/cgls.c +++ b/src/cgls/cgls.c @@ -165,8 +165,10 @@ static int get_cgroup_root(char **ret) { } static void show_cg_info(const char *controller, const char *path) { - if (cg_unified() <= 0) + + if (cg_unified() <= 0 && controller && !streq(controller, SYSTEMD_CGROUP_CONTROLLER)) printf("Controller %s; ", controller); + printf("Control group %s:\n", isempty(path) ? "/" : path); fflush(stdout); } -- cgit v1.2.3-54-g00ecf From b1f044bbc45cc05049eed9c483a2d6bef73c0adc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 10 Nov 2015 00:37:19 +0100 Subject: cgls: when showing root slice, put -.slice at top of tree --- src/cgls/cgls.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c index a5a580438a..22efc58ac9 100644 --- a/src/cgls/cgls.c +++ b/src/cgls/cgls.c @@ -272,6 +272,7 @@ int main(int argc, char *argv[]) { show_cg_info(SYSTEMD_CGROUP_CONTROLLER, root); + printf("-.slice\n"); r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, arg_kernel_threads, output_flags); } } -- cgit v1.2.3-54-g00ecf From 75eb615480afd787fa412f0a529523f568f79b26 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 10 Nov 2015 15:57:21 +0100 Subject: defs: rework CONF_DIRS_NULSTR() macro The macro is generically useful for putting together search paths, hence let's make it truly generic, by dropping the implicit ".d" appending it does, and leave that to the caller. Also rename it from CONF_DIRS_NULSTR() to CONF_PATHS_NULSTR(), since it's not strictly about dirs that way, but any kind of file system path. Also, mark CONF_DIR_SPLIT_USR() as internal macro by renaming it to _CONF_PATHS_SPLIT_USR() so that the leading underscore indicates that it's internal. --- src/basic/def.h | 24 +++++++++++++----------- src/binfmt/binfmt.c | 2 +- src/bootchart/bootchart.c | 6 ++---- src/core/main.c | 10 ++++++++-- src/journal-remote/journal-remote.c | 2 +- src/journal-remote/journal-upload.c | 2 +- src/journal/coredump.c | 4 ++-- src/journal/journald-server.c | 4 ++-- src/login/logind.c | 4 ++-- src/modules-load/modules-load.c | 2 +- src/resolve/resolved-conf.c | 4 ++-- src/shared/sleep-config.c | 2 +- src/sysctl/sysctl.c | 2 +- src/sysusers/sysusers.c | 2 +- src/timesync/timesyncd-conf.c | 4 ++-- src/tmpfiles/tmpfiles.c | 2 +- 16 files changed, 41 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/basic/def.h b/src/basic/def.h index 950f693899..0657ac7367 100644 --- a/src/basic/def.h +++ b/src/basic/def.h @@ -76,17 +76,19 @@ #define NOTIFY_FD_MAX 768 #define NOTIFY_BUFFER_MAX PIPE_BUF -/* Return a nulstr for a standard cascade of configuration directories, - * suitable to pass to conf_files_list_nulstr or config_parse_many. */ -#define CONF_DIRS_NULSTR(n) \ - "/etc/" n ".d\0" \ - "/run/" n ".d\0" \ - "/usr/local/lib/" n ".d\0" \ - "/usr/lib/" n ".d\0" \ - CONF_DIR_SPLIT_USR(n) - #ifdef HAVE_SPLIT_USR -#define CONF_DIR_SPLIT_USR(n) "/lib/" n ".d\0" +#define _CONF_PATHS_SPLIT_USR(n) "/lib/" n "\0" #else -#define CONF_DIR_SPLIT_USR(n) +#define _CONF_PATHS_SPLIT_USR(n) #endif + +/* Return a nulstr for a standard cascade of configuration paths, + * suitable to pass to conf_files_list_nulstr() or config_parse_many() + * to implement drop-in directories for extending configuration + * files. */ +#define CONF_PATHS_NULSTR(n) \ + "/etc/" n "\0" \ + "/run/" n "\0" \ + "/usr/local/lib/" n "\0" \ + "/usr/lib/" n "\0" \ + _CONF_PATHS_SPLIT_USR(n) diff --git a/src/binfmt/binfmt.c b/src/binfmt/binfmt.c index 42ad0adb02..03fb413fe5 100644 --- a/src/binfmt/binfmt.c +++ b/src/binfmt/binfmt.c @@ -37,7 +37,7 @@ #include "strv.h" #include "util.h" -static const char conf_file_dirs[] = CONF_DIRS_NULSTR("binfmt"); +static const char conf_file_dirs[] = CONF_PATHS_NULSTR("binfmt.d"); static int delete_rule(const char *rule) { _cleanup_free_ char *x = NULL, *fn = NULL; diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c index 852febb225..6a0e1d6b14 100644 --- a/src/bootchart/bootchart.c +++ b/src/bootchart/bootchart.c @@ -95,8 +95,6 @@ static void signal_handler(int sig) { exiting = 1; } -#define BOOTCHART_CONF "/etc/systemd/bootchart.conf" - #define BOOTCHART_MAX (16*1024*1024) static void parse_conf(void) { @@ -117,8 +115,8 @@ static void parse_conf(void) { { NULL, NULL, NULL, 0, NULL } }; - config_parse_many(BOOTCHART_CONF, - CONF_DIRS_NULSTR("systemd/bootchart.conf"), + config_parse_many(PKGSYSCONFDIR "/bootchart.conf", + CONF_PATHS_NULSTR("systemd/bootchart.conf.d"), NULL, config_item_table_lookup, items, true, NULL); if (init != NULL) diff --git a/src/core/main.c b/src/core/main.c index 950315e857..a86080642d 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -682,8 +682,14 @@ static int parse_config_file(void) { const char *fn, *conf_dirs_nulstr; - fn = arg_running_as == MANAGER_SYSTEM ? PKGSYSCONFDIR "/system.conf" : PKGSYSCONFDIR "/user.conf"; - conf_dirs_nulstr = arg_running_as == MANAGER_SYSTEM ? CONF_DIRS_NULSTR("systemd/system.conf") : CONF_DIRS_NULSTR("systemd/user.conf"); + fn = arg_running_as == MANAGER_SYSTEM ? + PKGSYSCONFDIR "/system.conf" : + PKGSYSCONFDIR "/user.conf"; + + conf_dirs_nulstr = arg_running_as == MANAGER_SYSTEM ? + CONF_PATHS_NULSTR("systemd/system.conf.d") : + CONF_PATHS_NULSTR("systemd/user.conf.d"); + config_parse_many(fn, conf_dirs_nulstr, "Manager\0", config_item_table_lookup, items, false, NULL); diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c index 6eb0ee9d9e..b2f5fbf6b4 100644 --- a/src/journal-remote/journal-remote.c +++ b/src/journal-remote/journal-remote.c @@ -1188,7 +1188,7 @@ static int parse_config(void) { {}}; return config_parse_many(PKGSYSCONFDIR "/journal-remote.conf", - CONF_DIRS_NULSTR("systemd/journal-remote.conf"), + CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"), "Remote\0", config_item_table_lookup, items, false, NULL); } diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c index 42d14dc7c4..6302266ccb 100644 --- a/src/journal-remote/journal-upload.c +++ b/src/journal-remote/journal-upload.c @@ -542,7 +542,7 @@ static int parse_config(void) { {}}; return config_parse_many(PKGSYSCONFDIR "/journal-upload.conf", - CONF_DIRS_NULSTR("systemd/journal-upload.conf"), + CONF_PATHS_NULSTR("systemd/journal-upload.conf.d"), "Upload\0", config_item_table_lookup, items, false, NULL); } diff --git a/src/journal/coredump.c b/src/journal/coredump.c index 4c83e311db..f750ddfcbd 100644 --- a/src/journal/coredump.c +++ b/src/journal/coredump.c @@ -126,8 +126,8 @@ static int parse_config(void) { {} }; - return config_parse_many("/etc/systemd/coredump.conf", - CONF_DIRS_NULSTR("systemd/coredump.conf"), + return config_parse_many(PKGSYSCONFDIR "/coredump.conf", + CONF_PATHS_NULSTR("systemd/coredump.conf.d"), "Coredump\0", config_item_table_lookup, items, false, NULL); diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 7a70dcbc57..f0d3a26372 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -1360,8 +1360,8 @@ static int server_parse_proc_cmdline(Server *s) { static int server_parse_config_file(Server *s) { assert(s); - return config_parse_many("/etc/systemd/journald.conf", - CONF_DIRS_NULSTR("systemd/journald.conf"), + return config_parse_many(PKGSYSCONFDIR "/journald.conf", + CONF_PATHS_NULSTR("systemd/journald.conf.d"), "Journal\0", config_item_perf_lookup, journald_gperf_lookup, false, s); diff --git a/src/login/logind.c b/src/login/logind.c index 83896ea627..be6bbe5b5c 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -1102,8 +1102,8 @@ static int manager_run(Manager *m) { static int manager_parse_config_file(Manager *m) { assert(m); - return config_parse_many("/etc/systemd/logind.conf", - CONF_DIRS_NULSTR("systemd/logind.conf"), + return config_parse_many(PKGSYSCONFDIR "/logind.conf", + CONF_PATHS_NULSTR("systemd/logind.conf.d"), "Login\0", config_item_perf_lookup, logind_gperf_lookup, false, m); diff --git a/src/modules-load/modules-load.c b/src/modules-load/modules-load.c index 13784763f1..a7fdcb09cf 100644 --- a/src/modules-load/modules-load.c +++ b/src/modules-load/modules-load.c @@ -38,7 +38,7 @@ static char **arg_proc_cmdline_modules = NULL; -static const char conf_file_dirs[] = CONF_DIRS_NULSTR("modules-load"); +static const char conf_file_dirs[] = CONF_PATHS_NULSTR("modules-load.d"); static void systemd_kmod_log(void *data, int priority, const char *file, int line, const char *fn, const char *format, va_list args) { diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index de1bd26174..9207719551 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -150,8 +150,8 @@ int config_parse_support( int manager_parse_config_file(Manager *m) { assert(m); - return config_parse_many("/etc/systemd/resolved.conf", - CONF_DIRS_NULSTR("systemd/resolved.conf"), + return config_parse_many(PKGSYSCONFDIR "/resolved.conf", + CONF_PATHS_NULSTR("systemd/resolved.conf.d"), "Resolve\0", config_item_perf_lookup, resolved_gperf_lookup, false, m); diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c index 102c5cc992..39b836d053 100644 --- a/src/shared/sleep-config.c +++ b/src/shared/sleep-config.c @@ -54,7 +54,7 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states) { }; config_parse_many(PKGSYSCONFDIR "/sleep.conf", - CONF_DIRS_NULSTR("systemd/sleep.conf"), + CONF_PATHS_NULSTR("systemd/sleep.conf.d"), "Sleep\0", config_item_table_lookup, items, false, NULL); diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c index 152c98b348..25b5ff52ea 100644 --- a/src/sysctl/sysctl.c +++ b/src/sysctl/sysctl.c @@ -41,7 +41,7 @@ static char **arg_prefixes = NULL; -static const char conf_file_dirs[] = CONF_DIRS_NULSTR("sysctl"); +static const char conf_file_dirs[] = CONF_PATHS_NULSTR("sysctl.d"); static int apply_all(Hashmap *sysctl_options) { char *property, *value; diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 008b1bde24..675f94906b 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -72,7 +72,7 @@ typedef struct Item { static char *arg_root = NULL; -static const char conf_file_dirs[] = CONF_DIRS_NULSTR("sysusers"); +static const char conf_file_dirs[] = CONF_PATHS_NULSTR("sysusers.d"); static Hashmap *users = NULL, *groups = NULL; static Hashmap *todo_uids = NULL, *todo_gids = NULL; diff --git a/src/timesync/timesyncd-conf.c b/src/timesync/timesyncd-conf.c index 001a0f4d41..5881bc0c45 100644 --- a/src/timesync/timesyncd-conf.c +++ b/src/timesync/timesyncd-conf.c @@ -100,8 +100,8 @@ int config_parse_servers( int manager_parse_config_file(Manager *m) { assert(m); - return config_parse_many("/etc/systemd/timesyncd.conf", - CONF_DIRS_NULSTR("systemd/timesyncd.conf"), + return config_parse_many(PKGSYSCONFDIR "/timesyncd.conf", + CONF_PATHS_NULSTR("systemd/timesyncd.conf.d"), "Time\0", config_item_perf_lookup, timesyncd_gperf_lookup, false, m); diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index ffae91a3ca..64f0c9396c 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -159,7 +159,7 @@ static char **arg_include_prefixes = NULL; static char **arg_exclude_prefixes = NULL; static char *arg_root = NULL; -static const char conf_file_dirs[] = CONF_DIRS_NULSTR("tmpfiles"); +static const char conf_file_dirs[] = CONF_PATHS_NULSTR("tmpfiles.d"); #define MAX_DEPTH 256 -- cgit v1.2.3-54-g00ecf From 519cffec890510f817740d07355e911b10c203b7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 10 Nov 2015 16:04:37 +0100 Subject: time-util: add parse_time(), which is like parse_sec() but allows specification of default time unit if none is specified MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is useful if we want to parse RLIMIT_RTTIME values where the common UNIX syntax is without any units but refers to a non-second unit (µs in this case), but where we want to allow specification of units. --- src/basic/calendarspec.c | 4 ++-- src/basic/time-util.c | 33 +++++++++++++++++++++------------ src/basic/time-util.h | 1 + src/test/test-time.c | 23 +++++++++++++++++++++++ 4 files changed, 47 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c index a6a906f453..7151fc3d0c 100644 --- a/src/basic/calendarspec.c +++ b/src/basic/calendarspec.c @@ -562,7 +562,7 @@ static int parse_date(const char **p, CalendarSpec *c) { return -EINVAL; } -static int parse_time(const char **p, CalendarSpec *c) { +static int parse_calendar_time(const char **p, CalendarSpec *c) { CalendarComponent *h = NULL, *m = NULL, *s = NULL; const char *t; int r; @@ -802,7 +802,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { if (r < 0) goto fail; - r = parse_time(&p, c); + r = parse_calendar_time(&p, c); if (r < 0) goto fail; diff --git a/src/basic/time-util.c b/src/basic/time-util.c index e629d91cb2..b36fbe4f09 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -705,7 +705,8 @@ finish: return 0; } -int parse_sec(const char *t, usec_t *usec) { +int parse_time(const char *t, usec_t *usec, usec_t default_unit) { + static const struct { const char *suffix; usec_t usec; @@ -737,7 +738,6 @@ int parse_sec(const char *t, usec_t *usec) { { "y", USEC_PER_YEAR }, { "usec", 1ULL }, { "us", 1ULL }, - { "", USEC_PER_SEC }, /* default is sec */ }; const char *p, *s; @@ -746,6 +746,7 @@ int parse_sec(const char *t, usec_t *usec) { assert(t); assert(usec); + assert(default_unit > 0); p = t; @@ -764,6 +765,7 @@ int parse_sec(const char *t, usec_t *usec) { long long l, z = 0; char *e; unsigned i, n = 0; + usec_t multiplier, k; p += strspn(p, WHITESPACE); @@ -806,21 +808,24 @@ int parse_sec(const char *t, usec_t *usec) { for (i = 0; i < ELEMENTSOF(table); i++) if (startswith(e, table[i].suffix)) { - usec_t k = (usec_t) z * table[i].usec; - - for (; n > 0; n--) - k /= 10; - - r += (usec_t) l * table[i].usec + k; + multiplier = table[i].usec; p = e + strlen(table[i].suffix); - - something = true; break; } - if (i >= ELEMENTSOF(table)) - return -EINVAL; + if (i >= ELEMENTSOF(table)) { + multiplier = default_unit; + p = e; + } + + something = true; + + k = (usec_t) z * multiplier; + for (; n > 0; n--) + k /= 10; + + r += (usec_t) l * multiplier + k; } *usec = r; @@ -828,6 +833,10 @@ int parse_sec(const char *t, usec_t *usec) { return 0; } +int parse_sec(const char *t, usec_t *usec) { + return parse_time(t, usec, USEC_PER_SEC); +} + int parse_nsec(const char *t, nsec_t *nsec) { static const struct { const char *suffix; diff --git a/src/basic/time-util.h b/src/basic/time-util.h index 925bf18eb2..0417c29cdd 100644 --- a/src/basic/time-util.h +++ b/src/basic/time-util.h @@ -104,6 +104,7 @@ int dual_timestamp_deserialize(const char *value, dual_timestamp *t); int parse_timestamp(const char *t, usec_t *usec); int parse_sec(const char *t, usec_t *usec); +int parse_time(const char *t, usec_t *usec, usec_t default_unit); int parse_nsec(const char *t, nsec_t *nsec); bool ntp_synced(void); diff --git a/src/test/test-time.c b/src/test/test-time.c index 3840fff061..820e4aaee2 100644 --- a/src/test/test-time.c +++ b/src/test/test-time.c @@ -57,6 +57,28 @@ static void test_parse_sec(void) { assert_se(parse_sec(".3 infinity", &u) < 0); } +static void test_parse_time(void) { + usec_t u; + + assert_se(parse_time("5", &u, 1) >= 0); + assert_se(u == 5); + + assert_se(parse_time("5", &u, USEC_PER_MSEC) >= 0); + assert_se(u == 5 * USEC_PER_MSEC); + + assert_se(parse_time("5", &u, USEC_PER_SEC) >= 0); + assert_se(u == 5 * USEC_PER_SEC); + + assert_se(parse_time("5s", &u, 1) >= 0); + assert_se(u == 5 * USEC_PER_SEC); + + assert_se(parse_time("5s", &u, USEC_PER_SEC) >= 0); + assert_se(u == 5 * USEC_PER_SEC); + + assert_se(parse_time("5s", &u, USEC_PER_MSEC) >= 0); + assert_se(u == 5 * USEC_PER_SEC); +} + static void test_parse_nsec(void) { nsec_t u; @@ -161,6 +183,7 @@ static void test_get_timezones(void) { int main(int argc, char *argv[]) { test_parse_sec(); + test_parse_time(); test_parse_nsec(); test_format_timespan(1); test_format_timespan(USEC_PER_MSEC); -- cgit v1.2.3-54-g00ecf From 65dce26488030eff078c498673d5d93e3c87b6a1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 10 Nov 2015 16:08:03 +0100 Subject: core: simplify parsing of capability bounding set settings Let's generate a simple error, and that's it. Let's not try to be smart and record the last word that failed. Also, let's make sure we don't compare numeric values with 0 by relying on C's downgrade-to-bool feature, as suggested in CODING_STYLE. --- src/core/load-fragment.c | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 7f12f26b08..cb26761b29 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -970,23 +970,22 @@ int config_parse_exec_secure_bits(const char *unit, return 0; } -int config_parse_bounding_set(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_bounding_set( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { uint64_t *capability_bounding_set_drop = data; - uint64_t capability_bounding_set; + uint64_t capability_bounding_set, sum = 0; bool invert = false; - uint64_t sum = 0; - const char *prev; - const char *cur; + const char *p; assert(filename); assert(lvalue); @@ -1003,35 +1002,32 @@ int config_parse_bounding_set(const char *unit, * non-inverted everywhere to have a fully normalized * interface. */ - prev = cur = rvalue; + p = rvalue; for (;;) { _cleanup_free_ char *word = NULL; - int cap; - int r; + int cap, r; - r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES); + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); if (r == 0) break; if (r == -ENOMEM) return log_oom(); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in bounding set, ignoring: %s", prev); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse word, ignoring: %s", rvalue); break; } cap = capability_from_name(word); if (cap < 0) { log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", word); - prev = cur; continue; } - sum |= ((uint64_t) 1ULL) << (uint64_t) cap; - prev = cur; + sum |= ((uint64_t) UINT64_C(1)) << (uint64_t) cap; } capability_bounding_set = invert ? ~sum : sum; - if (*capability_bounding_set_drop && capability_bounding_set) + if (*capability_bounding_set_drop != 0 && capability_bounding_set != 0) *capability_bounding_set_drop = ~(~*capability_bounding_set_drop | capability_bounding_set); else *capability_bounding_set_drop = ~capability_bounding_set; -- cgit v1.2.3-54-g00ecf From d580265eb4bbbafabdb3b7f0b501c0b05b76b2b7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 10 Nov 2015 16:10:24 +0100 Subject: core: when parsing resource limits, be more careful with types and corner cases Let's not convert RLIM_INFINITY to "unsigned long long" and then back to rlim_t, but let's leave it in the right type right-away. Parse resource limits as 64 bit in all cases, as according to the man page that's what libc does anyway. Make sure setting a resource limit to (uint64_t) -1 results in a parsing error, and isn't implicitly converted to RLIM_INFINITY. --- src/core/load-fragment.c | 75 +++++++++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index cb26761b29..cdc2ad950d 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -1035,19 +1035,21 @@ int config_parse_bounding_set( return 0; } -int config_parse_limit(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_limit( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { struct rlimit **rl = data; - unsigned long long u; + rlim_t v; + int r; assert(filename); assert(lvalue); @@ -1057,15 +1059,22 @@ int config_parse_limit(const char *unit, rl += ltype; if (streq(rvalue, "infinity")) - u = (unsigned long long) RLIM_INFINITY; + v = RLIM_INFINITY; else { - int r; + uint64_t u; - r = safe_atollu(rvalue, &u); + /* setrlimit(2) suggests rlim_t is always 64bit on Linux. */ + assert_cc(sizeof(rlim_t) == sizeof(uint64_t)); + + r = safe_atou64(rvalue, &u); + if (r >= 0 && u >= (uint64_t) RLIM_INFINITY) + r = -ERANGE; if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); return 0; } + + v = (rlim_t) u; } if (!*rl) { @@ -1074,23 +1083,25 @@ int config_parse_limit(const char *unit, return log_oom(); } - (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u; + (*rl)->rlim_cur = (*rl)->rlim_max = v; return 0; } -int config_parse_bytes_limit(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_bytes_limit( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { struct rlimit **rl = data; - uint64_t bytes; + rlim_t bytes; + int r; assert(filename); assert(lvalue); @@ -1100,15 +1111,19 @@ int config_parse_bytes_limit(const char *unit, rl += ltype; if (streq(rvalue, "infinity")) - bytes = (uint64_t) RLIM_INFINITY; + bytes = RLIM_INFINITY; else { - int r; + uint64_t u; - r = parse_size(rvalue, 1024, &bytes); + r = parse_size(rvalue, 1024, &u); + if (r >= 0 && u >= (uint64_t) RLIM_INFINITY) + r = -ERANGE; if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); return 0; } + + bytes = (rlim_t) u; } if (!*rl) { @@ -1117,7 +1132,7 @@ int config_parse_bytes_limit(const char *unit, return log_oom(); } - (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) bytes; + (*rl)->rlim_cur = (*rl)->rlim_max = bytes; return 0; } -- cgit v1.2.3-54-g00ecf From a4c1800284e3546bbfab2dc19eb59bcb91c4a2ca Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 10 Nov 2015 16:52:52 +0100 Subject: core: accept time units for time-based resource limits Let's make sure "LimitCPU=30min" can be parsed properly, following the usual logic how we parse time values. Similar for LimitRTTIME=. While we are at it, extend a bit on the man page section about resource limits. Fixes: #1772 --- man/systemd.exec.xml | 86 ++++++++++++++++++++++------- src/core/load-fragment-gperf.gperf.m4 | 4 +- src/core/load-fragment.c | 101 ++++++++++++++++++++++++++++++++++ src/core/load-fragment.h | 2 + src/test/test-unit-file.c | 61 ++++++++++++++++++++ 5 files changed, 231 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 96298f11ed..2b090871ff 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -568,90 +568,133 @@ of various resources for executed processes. See setrlimit2 for details. Use the string infinity to - configure no limit on a specific resource. The multiplicative suffixes - K (=1024), M (=1024*1024) and so on for G, T, P and E may be used for - resource limits measured in bytes (e.g. LimitAS=16G). + configure no limit on a specific resource. The multiplicative + suffixes K (=1024), M (=1024*1024) and so on for G, T, P and E + may be used for resource limits measured in bytes + (e.g. LimitAS=16G). For the limits referring to time values, + the usual time units ms, s, min, h and so on may be used (see + systemd.time7 + for details). Note that if no time unit is specified for + LimitCPU= the default unit of seconds is + implied, while for LimitRTTIME= the default + unit of microseconds is implied. Also, note that the effective + granularity of the limits might influence their + enforcement. For example, time limits specified for + LimitCPU= will be rounded up implicitly to + multiples of 1s. + + Note that most process resource limits configured with + these options are per-process, and processes may fork in order + to acquire a new set of resources that are accounted + independently of the original process, and may thus escape + limits set. Also note that LimitRSS= is not + implemented on Linux, and setting it has no effect. Often it + is advisable to prefer the resource controls listed in + systemd.resource-control5 + over these per-process limits, as they apply to services as a + whole, may be altered dynamically at runtime, and are + generally more expressive. For example, + MemoryLimit= is a more powerful (and + working) replacement for LimitRSS=. Limit directives and their equivalent with ulimit - + + Directive ulimit equivalent + Unit - LimitCPU + LimitCPU= ulimit -t + Seconds - LimitFSIZE + LimitFSIZE= ulimit -f + Bytes - LimitDATA + LimitDATA= ulimit -d + Bytes - LimitSTACK + LimitSTACK= ulimit -s + Bytes - LimitCORE + LimitCORE= ulimit -c + Bytes - LimitRSS + LimitRSS= ulimit -m + Bytes - LimitNOFILE + LimitNOFILE= ulimit -n + Number of File Descriptors - LimitAS + LimitAS= ulimit -v + Bytes - LimitNPROC + LimitNPROC= ulimit -u + Number of Processes - LimitMEMLOCK + LimitMEMLOCK= ulimit -l + Bytes - LimitLOCKS + LimitLOCKS= ulimit -x + Number of Locks - LimitSIGPENDING + LimitSIGPENDING= ulimit -i + Number of Queued Signals - LimitMSGQUEUE + LimitMSGQUEUE= ulimit -q + Bytes - LimitNICE + LimitNICE= ulimit -e + Nice Level - LimitRTPRIO + LimitRTPRIO= ulimit -r + Realtime Priority - LimitRTTIME + LimitRTTIME= No equivalent + Microseconds -
+ @@ -1320,6 +1363,7 @@ systemd.mount5, systemd.kill5, systemd.resource-control5, + systemd.time7, systemd.directives7, tmpfiles.d5, exec3 diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 5b7954dbf9..75388659e3 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -58,7 +58,7 @@ $1.RestrictAddressFamilies, config_parse_address_families, 0, $1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 $1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 $1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0') -$1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) +$1.LimitCPU, config_parse_sec_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) $1.LimitFSIZE, config_parse_bytes_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) $1.LimitDATA, config_parse_bytes_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit) $1.LimitSTACK, config_parse_bytes_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit) @@ -73,7 +73,7 @@ $1.LimitSIGPENDING, config_parse_limit, RLIMIT_SIGP $1.LimitMSGQUEUE, config_parse_bytes_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit) $1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit) $1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit) -$1.LimitRTTIME, config_parse_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit) +$1.LimitRTTIME, config_parse_usec_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit) $1.ReadWriteDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_dirs) $1.ReadOnlyDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_dirs) $1.InaccessibleDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_dirs) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index cdc2ad950d..28b90eccc1 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -1136,6 +1136,107 @@ int config_parse_bytes_limit( return 0; } +int config_parse_sec_limit( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + struct rlimit **rl = data; + rlim_t seconds; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + rl += ltype; + + if (streq(rvalue, "infinity")) + seconds = RLIM_INFINITY; + else { + usec_t t; + + r = parse_sec(rvalue, &t); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); + return 0; + } + + if (t == USEC_INFINITY) + seconds = RLIM_INFINITY; + else + seconds = (rlim_t) (DIV_ROUND_UP(t, USEC_PER_SEC)); + } + + if (!*rl) { + *rl = new(struct rlimit, 1); + if (!*rl) + return log_oom(); + } + + (*rl)->rlim_cur = (*rl)->rlim_max = seconds; + return 0; +} + + +int config_parse_usec_limit( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + struct rlimit **rl = data; + rlim_t useconds; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + rl += ltype; + + if (streq(rvalue, "infinity")) + useconds = RLIM_INFINITY; + else { + usec_t t; + + r = parse_time(rvalue, &t, 1); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); + return 0; + } + + if (t == USEC_INFINITY) + useconds = RLIM_INFINITY; + else + useconds = (rlim_t) t; + } + + if (!*rl) { + *rl = new(struct rlimit, 1); + if (!*rl) + return log_oom(); + } + + (*rl)->rlim_cur = (*rl)->rlim_max = useconds; + return 0; +} + #ifdef HAVE_SYSV_COMPAT int config_parse_sysv_priority(const char *unit, const char *filename, diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 029775bb46..0cf821289c 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -57,6 +57,8 @@ int config_parse_exec_secure_bits(const char *unit, const char *filename, unsign int config_parse_bounding_set(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_bytes_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_sec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_usec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_sysv_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_kill_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_exec_mount_flags(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index f9107e0d0d..3648ec9c58 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -681,6 +681,66 @@ static void test_config_parse_bounding_set(void) { assert_se(capability_bounding_set_drop == ~(make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN))); } +static void test_config_parse_rlimit(void) { + struct rlimit * rl[_RLIMIT_MAX] = {}; + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + + rl[RLIMIT_NOFILE] = mfree(rl[RLIMIT_NOFILE]); + + assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == 56); + assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); + + assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "57s", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == 57); + assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); + + assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); + + assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "1234ms", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == 2); + assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); + + rl[RLIMIT_CPU] = mfree(rl[RLIMIT_CPU]); + + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + + rl[RLIMIT_RTTIME] = mfree(rl[RLIMIT_RTTIME]); +} + int main(int argc, char *argv[]) { int r; @@ -690,6 +750,7 @@ int main(int argc, char *argv[]) { r = test_unit_file_get_set(); test_config_parse_exec(); test_config_parse_bounding_set(); + test_config_parse_rlimit(); test_load_env_file_1(); test_load_env_file_2(); test_load_env_file_3(); -- cgit v1.2.3-54-g00ecf From b374689c02c681671a3c3c0b0fd3add32386b442 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 10 Nov 2015 16:53:00 +0100 Subject: journald: dispatch SIGTERM/SIGINT with a low priority Let's make sure to process all queued log data before exiting, so that we don't unnecessary lose messages when shutting down. https://github.com/systemd/systemd/pull/1812#issuecomment-155149871 --- src/journal/journald-server.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src') diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index f0d3a26372..36fe739073 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -1296,10 +1296,22 @@ static int setup_signals(Server *s) { if (r < 0) return r; + /* Let's process SIGTERM late, so that we flush all queued + * messages to disk before we exit */ + r = sd_event_source_set_priority(s->sigterm_event_source, SD_EVENT_PRIORITY_NORMAL+20); + if (r < 0) + return r; + + /* When journald is invoked on the terminal (when debugging), + * it's useful if C-c is handled equivalent to SIGTERM. */ r = sd_event_add_signal(s->event, &s->sigint_event_source, SIGINT, dispatch_sigterm, s); if (r < 0) return r; + r = sd_event_source_set_priority(s->sigint_event_source, SD_EVENT_PRIORITY_NORMAL+20); + if (r < 0) + return r; + return 0; } -- cgit v1.2.3-54-g00ecf From 2d49a208f8ad9d1c4e79fa4302451e35d06de707 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 10 Nov 2015 17:27:16 +0100 Subject: parse-util: really refuse parsing negative values as positive ones, even on x86-32 strtoull() doesn't make it particularly easy to detect passed-in negative numbers, as it silently converts them to positive ones without generating any error. Since we are not interested in negative values we should hence explicitly filter them out by looking at the string directly and returning ERANGE if we see a leading "-". Fixes: #1829 --- src/basic/parse-util.c | 100 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c index b6358c459a..151067e916 100644 --- a/src/basic/parse-util.c +++ b/src/basic/parse-util.c @@ -67,11 +67,14 @@ int parse_mode(const char *s, mode_t *ret) { assert(s); assert(ret); + s += strspn(s, WHITESPACE); + if (s[0] == '-') + return -ERANGE; + errno = 0; l = strtol(s, &x, 8); if (errno != 0) return -errno; - if (!x || x == s || *x) return -EINVAL; if (l < 0 || l > 07777) @@ -162,15 +165,15 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) { unsigned i; p += strspn(p, WHITESPACE); - if (*p == '-') - return -ERANGE; errno = 0; l = strtoull(p, &e, 10); - if (errno > 0) + if (errno != 0) return -errno; if (e == p) return -EINVAL; + if (*p == '-') + return -ERANGE; if (*e == '.') { e++; @@ -181,7 +184,7 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) { char *e2; l2 = strtoull(e, &e2, 10); - if (errno > 0) + if (errno != 0) return -errno; /* Ignore failure. E.g. 10.M is valid */ @@ -307,12 +310,24 @@ int safe_atou(const char *s, unsigned *ret_u) { assert(s); assert(ret_u); - errno = 0; - l = strtoul(s, &x, 0); + /* strtoul() is happy to parse negative values, and silently + * converts them to unsigned values without generating an + * error. We want a clean error, hence let's look for the "-" + * prefix on our own, and generate an error. But let's do so + * only after strtoul() validated that the string is clean + * otherwise, so that we return EINVAL preferably over + * ERANGE. */ - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; + s += strspn(s, WHITESPACE); + errno = 0; + l = strtoul(s, &x, 0); + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if (s[0] == '-') + return -ERANGE; if ((unsigned long) (unsigned) l != l) return -ERANGE; @@ -329,10 +344,10 @@ int safe_atoi(const char *s, int *ret_i) { errno = 0; l = strtol(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; if ((long) (int) l != l) return -ERANGE; @@ -347,11 +362,16 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) { assert(s); assert(ret_llu); + s += strspn(s, WHITESPACE); + errno = 0; l = strtoull(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno ? -errno : -EINVAL; + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if (*s == '-') + return -ERANGE; *ret_llu = l; return 0; @@ -366,9 +386,10 @@ int safe_atolli(const char *s, long long int *ret_lli) { errno = 0; l = strtoll(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno ? -errno : -EINVAL; + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; *ret_lli = l; return 0; @@ -381,12 +402,16 @@ int safe_atou8(const char *s, uint8_t *ret) { assert(s); assert(ret); + s += strspn(s, WHITESPACE); + errno = 0; l = strtoul(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if (s[0] == '-') + return -ERANGE; if ((unsigned long) (uint8_t) l != l) return -ERANGE; @@ -401,12 +426,16 @@ int safe_atou16(const char *s, uint16_t *ret) { assert(s); assert(ret); + s += strspn(s, WHITESPACE); + errno = 0; l = strtoul(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if (s[0] == '-') + return -ERANGE; if ((unsigned long) (uint16_t) l != l) return -ERANGE; @@ -423,10 +452,10 @@ int safe_atoi16(const char *s, int16_t *ret) { errno = 0; l = strtol(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; if ((long) (int16_t) l != l) return -ERANGE; @@ -448,10 +477,13 @@ int safe_atod(const char *s, double *ret_d) { errno = 0; d = strtod_l(s, &x, loc); - - if (!x || x == s || *x || errno) { + if (errno != 0) { freelocale(loc); - return errno ? -errno : -EINVAL; + return -errno; + } + if (!x || x == s || *x) { + freelocale(loc); + return -EINVAL; } freelocale(loc); -- cgit v1.2.3-54-g00ecf