X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Futil.c;h=99836953bfafd8853ba3d217476b5cd42139b9f2;hp=1c97a8a94ae65386b7731c672e4e1248d7f65826;hb=c1e5704657315b436c0409e8172c1fcb76adccad;hpb=01539d6ef9689ffdc7c0743e12740a78bb938b97 diff --git a/src/shared/util.c b/src/shared/util.c index 1c97a8a94..99836953b 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" @@ -72,7 +74,12 @@ int saved_argc = 0; char **saved_argv = NULL; -static int parsed_columns = 0; +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; @@ -147,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; @@ -174,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; @@ -194,7 +207,7 @@ struct timeval *timeval_store(struct timeval *tv, usec_t u) { return tv; } -bool endswith(const char *s, const char *postfix) { +char* endswith(const char *s, const char *postfix) { size_t sl, pl; assert(s); @@ -204,53 +217,49 @@ bool endswith(const char *s, const char *postfix) { pl = strlen(postfix); if (pl == 0) - return true; + return (char*) s + sl; if (sl < pl) - return false; + return NULL; + + if (memcmp(s + sl - pl, postfix, pl) != 0) + return NULL; - return memcmp(s + sl - pl, postfix, pl) == 0; + 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) { @@ -374,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) @@ -394,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) @@ -414,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; @@ -431,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; @@ -2175,28 +2184,25 @@ int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) { } int ask(char *ret, const char *replies, const char *text, ...) { - bool on_tty; assert(ret); assert(replies); assert(text); - on_tty = isatty(STDOUT_FILENO); - for (;;) { va_list ap; char c; int r; bool need_nl = true; - if (on_tty) + if (on_tty()) fputs(ANSI_HIGHLIGHT_ON, stdout); va_start(ap, text); vprintf(text, ap); va_end(ap); - if (on_tty) + if (on_tty()) fputs(ANSI_HIGHLIGHT_OFF, stdout); fflush(stdout); @@ -3793,46 +3799,26 @@ int fd_columns(int fd) { return ws.ws_col; } -static unsigned columns_cached(bool cached) { - static __thread int env_columns = -1; +unsigned columns(void) { const char *e; + unsigned c; - if (_likely_(parsed_columns > 0 && cached)) - return parsed_columns; - - if (_unlikely_(env_columns == -1)) { - e = getenv("COLUMNS"); - if (e) - env_columns = atoi(e); - else - env_columns = 0; - } - - if (env_columns > 0) { - parsed_columns = env_columns; - return parsed_columns; - } - - if (parsed_columns <= 0 || !cached) - parsed_columns = fd_columns(STDOUT_FILENO); - - if (parsed_columns <= 0) - parsed_columns = 80; + if (_likely_(cached_columns > 0)) + return cached_columns; - return parsed_columns; -} + c = 0; + e = getenv("COLUMNS"); + if (e) + safe_atou(e, &c); -unsigned columns(void) { - return columns_cached(true); -} + if (c <= 0) + c = fd_columns(STDOUT_FILENO); -unsigned columns_uncached(void) { - return columns_cached(false); -} + if (c <= 0) + c = 80; -/* intended to be used as a SIGWINCH sighandler */ -void columns_cache_reset(int signum) { - parsed_columns = 0; + cached_columns = c; + return c; } int fd_lines(int fd) { @@ -3849,23 +3835,40 @@ int fd_lines(int fd) { } unsigned lines(void) { - static __thread int parsed_lines = 0; const char *e; + unsigned l; - if (_likely_(parsed_lines > 0)) - return parsed_lines; + if (_likely_(cached_lines > 0)) + return cached_lines; + l = 0; e = getenv("LINES"); if (e) - parsed_lines = atoi(e); + safe_atou(e, &l); - if (parsed_lines <= 0) - parsed_lines = fd_lines(STDOUT_FILENO); + if (l <= 0) + l = fd_lines(STDOUT_FILENO); - if (parsed_lines <= 0) - parsed_lines = 25; + if (l <= 0) + l = 24; - return parsed_lines; + cached_lines = l; + return cached_lines; +} + +/* intended to be used as a SIGWINCH sighandler */ +void columns_lines_cache_reset(int signum) { + cached_columns = 0; + cached_lines = 0; +} + +bool on_tty(void) { + static int cached_on_tty = -1; + + if (_unlikely_(cached_on_tty < 0)) + cached_on_tty = isatty(STDOUT_FILENO) > 0; + + return cached_on_tty; } int running_in_chroot(void) { @@ -5210,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", @@ -5246,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", @@ -5259,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", @@ -5269,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", @@ -5299,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", @@ -5700,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); @@ -6071,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_BOX_VERT] = "\342\224\202", /* │ */ + [DRAW_BOX_VERT_AND_RIGHT] = "\342\224\234", /* ├ */ + [DRAW_BOX_UP_AND_RIGHT] = "\342\224\224", /* └ */ + [DRAW_TRIANGULAR_BULLET] = "\342\200\243", /* ‣ */ + }, + /* ASCII fallback */ { + [DRAW_BOX_VERT] = "|", + [DRAW_BOX_VERT_AND_RIGHT] = "+", + [DRAW_BOX_UP_AND_RIGHT] = "\\", + [DRAW_TRIANGULAR_BULLET] = ">", + } + }; + + return draw_table[!is_locale_utf8()][ch]; +}