X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fshared%2Futil.c;h=5a326ec43512f7cd85927daaa2f105f0e8da7b9a;hb=0c0271841ab45595f71528c50bcf1904d4b841d5;hp=42a2e27308f9e42b46268a4b4de1dcf0d9fcffaf;hpb=8c7c140fcab0592735d22168657a143969a4c2bf;p=elogind.git diff --git a/src/shared/util.c b/src/shared/util.c index 42a2e2730..5a326ec43 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -57,6 +57,8 @@ #include #include #include +#include +#include #include "macro.h" #include "util.h" @@ -75,6 +77,10 @@ char **saved_argv = NULL; static volatile unsigned cached_columns = 0; static volatile unsigned cached_lines = 0; +bool is_efiboot(void) { + return access("/sys/firmware/efi", F_OK) >= 0; +} + size_t page_size(void) { static __thread size_t pgsz = 0; long r; @@ -148,6 +154,9 @@ usec_t timespec_load(const struct timespec *ts) { ts->tv_nsec == (long) -1) return (usec_t) -1; + if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC) + return (usec_t) -1; + return (usec_t) ts->tv_sec * USEC_PER_SEC + (usec_t) ts->tv_nsec / NSEC_PER_USEC; @@ -175,6 +184,9 @@ usec_t timeval_load(const struct timeval *tv) { tv->tv_usec == (suseconds_t) -1) return (usec_t) -1; + if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC) + return (usec_t) -1; + return (usec_t) tv->tv_sec * USEC_PER_SEC + (usec_t) tv->tv_usec; @@ -216,45 +228,38 @@ char* endswith(const char *s, const char *postfix) { return (char*) s + sl - pl; } -bool startswith(const char *s, const char *prefix) { - size_t sl, pl; +char* startswith(const char *s, const char *prefix) { + const char *a, *b; assert(s); assert(prefix); - sl = strlen(s); - pl = strlen(prefix); - - if (pl == 0) - return true; - - if (sl < pl) - return false; + a = s, b = prefix; + for (;;) { + if (*b == 0) + return (char*) a; + if (*a != *b) + return NULL; - return memcmp(s, prefix, pl) == 0; + a++, b++; + } } -bool startswith_no_case(const char *s, const char *prefix) { - size_t sl, pl; - unsigned i; +char* startswith_no_case(const char *s, const char *prefix) { + const char *a, *b; assert(s); assert(prefix); - sl = strlen(s); - pl = strlen(prefix); - - if (pl == 0) - return true; - - if (sl < pl) - return false; - - for(i = 0; i < pl; ++i) - if (tolower(s[i]) != tolower(prefix[i])) - return false; + a = s, b = prefix; + for (;;) { + if (*b == 0) + return (char*) a; + if (tolower(*a) != tolower(*b)) + return NULL; - return true; + a++, b++; + } } bool first_word(const char *s, const char *word) { @@ -378,7 +383,7 @@ int safe_atou(const char *s, unsigned *ret_u) { errno = 0; l = strtoul(s, &x, 0); - if (!x || *x || errno) + if (!x || x == s || *x || errno) return errno ? -errno : -EINVAL; if ((unsigned long) (unsigned) l != l) @@ -398,7 +403,7 @@ int safe_atoi(const char *s, int *ret_i) { errno = 0; l = strtol(s, &x, 0); - if (!x || *x || errno) + if (!x || x == s || *x || errno) return errno ? -errno : -EINVAL; if ((long) (int) l != l) @@ -418,7 +423,7 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) { errno = 0; l = strtoull(s, &x, 0); - if (!x || *x || errno) + if (!x || x == s || *x || errno) return errno ? -errno : -EINVAL; *ret_llu = l; @@ -435,7 +440,7 @@ int safe_atolli(const char *s, long long int *ret_lli) { errno = 0; l = strtoll(s, &x, 0); - if (!x || *x || errno) + if (!x || x == s || *x || errno) return errno ? -errno : -EINVAL; *ret_lli = l; @@ -5208,7 +5213,7 @@ static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_IDLE] = "idle" }; -DEFINE_STRING_TABLE_LOOKUP(ioprio_class, int); +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX); static const char *const sigchld_code_table[] = { [CLD_EXITED] = "exited", @@ -5244,7 +5249,7 @@ static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = { [LOG_FAC(LOG_LOCAL7)] = "local7" }; -DEFINE_STRING_TABLE_LOOKUP(log_facility_unshifted, int); +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0)); static const char *const log_level_table[] = { [LOG_EMERG] = "emerg", @@ -5257,7 +5262,7 @@ static const char *const log_level_table[] = { [LOG_DEBUG] = "debug" }; -DEFINE_STRING_TABLE_LOOKUP(log_level, int); +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG); static const char* const sched_policy_table[] = { [SCHED_OTHER] = "other", @@ -5267,7 +5272,7 @@ static const char* const sched_policy_table[] = { [SCHED_RR] = "rr" }; -DEFINE_STRING_TABLE_LOOKUP(sched_policy, int); +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX); static const char* const rlimit_table[] = { [RLIMIT_CPU] = "LimitCPU", @@ -5297,7 +5302,7 @@ static const char* const ip_tos_table[] = { [IPTOS_LOWCOST] = "low-cost", }; -DEFINE_STRING_TABLE_LOOKUP(ip_tos, int); +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff); static const char *const __signal_table[] = { [SIGHUP] = "HUP", @@ -5698,6 +5703,30 @@ int can_sleep(const char *type) { return false; } +int can_sleep_disk(const char *type) { + char *w, *state; + size_t l, k; + int r; + _cleanup_free_ char *p = NULL; + + assert(type); + + r = read_one_line_file("/sys/power/disk", &p); + if (r < 0) + return r == -ENOENT ? 0 : r; + + k = strlen(type); + FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state) { + if (l == k && memcmp(w, type, l) == 0) + return true; + + if (l == k + 2 && w[0] == '[' && memcmp(w + 1, type, l - 2) == 0 && w[l-1] == ']') + return true; + } + + return false; +} + bool is_valid_documentation_url(const char *url) { assert(url); @@ -6069,3 +6098,68 @@ finish: return 0; } + +/* hey glibc, APIs with callbacks without a user pointer are so useless */ +void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, + int (*compar) (const void *, const void *, void *), void *arg) { + size_t l, u, idx; + const void *p; + int comparison; + + l = 0; + u = nmemb; + while (l < u) { + idx = (l + u) / 2; + p = (void *)(((const char *) base) + (idx * size)); + comparison = compar(key, p, arg); + if (comparison < 0) + u = idx; + else if (comparison > 0) + l = idx + 1; + else + return (void *)p; + } + return NULL; +} + +bool is_locale_utf8(void) { + const char *set; + static int cached_answer = -1; + + if (cached_answer >= 0) + goto out; + + if (!setlocale(LC_ALL, "")) { + cached_answer = true; + goto out; + } + + set = nl_langinfo(CODESET); + if (!set) { + cached_answer = true; + goto out; + } + + cached_answer = streq(set, "UTF-8"); +out: + return (bool)cached_answer; +} + +const char *draw_special_char(DrawSpecialChar ch) { + static const char *draw_table[2][_DRAW_SPECIAL_CHAR_MAX] = { + /* UTF-8 */ { + [DRAW_TREE_VERT] = "\342\224\202 ", /* │ */ + [DRAW_TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */ + [DRAW_TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */ + [DRAW_TRIANGULAR_BULLET] = "\342\200\243 ", /* ‣ */ + }, + /* ASCII fallback */ { + [DRAW_TREE_VERT] = "| ", + [DRAW_TREE_BRANCH] = "|-", + [DRAW_TREE_RIGHT] = "`-", + [DRAW_TRIANGULAR_BULLET] = "> ", + } + }; + + return draw_table[!is_locale_utf8()][ch]; +}