#include <libintl.h>
#include <limits.h>
#include <linux/magic.h>
+#include <linux/oom.h>
#include <linux/sched.h>
#include <locale.h>
#include <netinet/ip.h>
#include "def.h"
#include "device-nodes.h"
#include "env-util.h"
+#include "escape.h"
#include "exit-status.h"
#include "fileio.h"
#include "formats-util.h"
#include "random-util.h"
#include "signal-util.h"
#include "sparse-endian.h"
+#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "utf8.h"
-#include "util.h"
#include "virt.h"
+#include "util.h"
/* Put this test here for a lack of better place */
assert_cc(EAGAIN == EWOULDBLOCK);
return pgsz;
}
-int strcmp_ptr(const char *a, const char *b) {
-
- /* Like strcmp(), but tries to make sense of NULL pointers */
- if (a && b)
- return strcmp(a, b);
-
- if (!a && b)
- return -1;
-
- if (a && !b)
- return 1;
-
- return 0;
-}
-
-bool streq_ptr(const char *a, const char *b) {
- return strcmp_ptr(a, b) == 0;
-}
-
-char* endswith(const char *s, const char *postfix) {
- size_t sl, pl;
-
- assert(s);
- assert(postfix);
-
- sl = strlen(s);
- pl = strlen(postfix);
-
- if (pl == 0)
- return (char*) s + sl;
-
- if (sl < pl)
- return NULL;
-
- if (memcmp(s + sl - pl, postfix, pl) != 0)
- return NULL;
-
- return (char*) s + sl - pl;
-}
-
-char* endswith_no_case(const char *s, const char *postfix) {
- size_t sl, pl;
-
- assert(s);
- assert(postfix);
-
- sl = strlen(s);
- pl = strlen(postfix);
-
- if (pl == 0)
- return (char*) s + sl;
-
- if (sl < pl)
- return NULL;
-
- if (strcasecmp(s + sl - pl, postfix) != 0)
- return NULL;
-
- return (char*) s + sl - pl;
-}
-
-char* first_word(const char *s, const char *word) {
- size_t sl, wl;
- const char *p;
-
- assert(s);
- assert(word);
-
- /* Checks if the string starts with the specified word, either
- * followed by NUL or by whitespace. Returns a pointer to the
- * NUL or the first character after the whitespace. */
-
- sl = strlen(s);
- wl = strlen(word);
-
- if (sl < wl)
- return NULL;
-
- if (wl == 0)
- return (char*) s;
-
- if (memcmp(s, word, wl) != 0)
- return NULL;
-
- p = s + wl;
- if (*p == 0)
- return (char*) p;
-
- if (!strchr(WHITESPACE, *p))
- return NULL;
-
- p += strspn(p, WHITESPACE);
- return (char*) p;
-}
-
-size_t cescape_char(char c, char *buf) {
- char * buf_old = buf;
-
- switch (c) {
-
- case '\a':
- *(buf++) = '\\';
- *(buf++) = 'a';
- break;
- case '\b':
- *(buf++) = '\\';
- *(buf++) = 'b';
- break;
- case '\f':
- *(buf++) = '\\';
- *(buf++) = 'f';
- break;
- case '\n':
- *(buf++) = '\\';
- *(buf++) = 'n';
- break;
- case '\r':
- *(buf++) = '\\';
- *(buf++) = 'r';
- break;
- case '\t':
- *(buf++) = '\\';
- *(buf++) = 't';
- break;
- case '\v':
- *(buf++) = '\\';
- *(buf++) = 'v';
- break;
- case '\\':
- *(buf++) = '\\';
- *(buf++) = '\\';
- break;
- case '"':
- *(buf++) = '\\';
- *(buf++) = '"';
- break;
- case '\'':
- *(buf++) = '\\';
- *(buf++) = '\'';
- break;
-
- default:
- /* For special chars we prefer octal over
- * hexadecimal encoding, simply because glib's
- * g_strescape() does the same */
- if ((c < ' ') || (c >= 127)) {
- *(buf++) = '\\';
- *(buf++) = octchar((unsigned char) c >> 6);
- *(buf++) = octchar((unsigned char) c >> 3);
- *(buf++) = octchar((unsigned char) c);
- } else
- *(buf++) = c;
- break;
- }
-
- return buf - buf_old;
-}
-
int close_nointr(int fd) {
assert(fd >= 0);
return 0;
}
-static size_t strcspn_escaped(const char *s, const char *reject) {
- bool escaped = false;
- int n;
-
- for (n=0; s[n]; n++) {
- if (escaped)
- escaped = false;
- else if (s[n] == '\\')
- escaped = true;
- else if (strchr(reject, s[n]))
- break;
- }
-
- /* if s ends in \, return index of previous char */
- return n - escaped;
-}
-
-/* Split a string into words. */
-const char* split(const char **state, size_t *l, const char *separator, bool quoted) {
- const char *current;
-
- current = *state;
-
- if (!*current) {
- assert(**state == '\0');
- return NULL;
- }
-
- current += strspn(current, separator);
- if (!*current) {
- *state = current;
- return NULL;
- }
-
- if (quoted && strchr("\'\"", *current)) {
- char quotechars[2] = {*current, '\0'};
-
- *l = strcspn_escaped(current + 1, quotechars);
- if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
- (current[*l + 2] && !strchr(separator, current[*l + 2]))) {
- /* right quote missing or garbage at the end */
- *state = current;
- return NULL;
- }
- *state = current++ + *l + 2;
- } else if (quoted) {
- *l = strcspn_escaped(current, separator);
- if (current[*l] && !strchr(separator, current[*l])) {
- /* unfinished escape */
- *state = current;
- return NULL;
- }
- *state = current + *l;
- } else {
- *l = strcspn(current, separator);
- *state = current + *l;
- }
-
- return current;
-}
int fchmod_umask(int fd, mode_t m) {
mode_t u;
return r;
}
-char *truncate_nl(char *s) {
- assert(s);
-
- s[strcspn(s, NEWLINE)] = 0;
- return s;
-}
-
-char *strnappend(const char *s, const char *suffix, size_t b) {
- size_t a;
- char *r;
-
- if (!s && !suffix)
- return strdup("");
-
- if (!s)
- return strndup(suffix, b);
-
- if (!suffix)
- return strdup(s);
-
- assert(s);
- assert(suffix);
-
- a = strlen(s);
- if (b > ((size_t) -1) - a)
- return NULL;
-
- r = new(char, a+b+1);
- if (!r)
- return NULL;
-
- memcpy(r, s, a);
- memcpy(r+a, suffix, b);
- r[a+b] = 0;
-
- return r;
-}
-
-char *strappend(const char *s, const char *suffix) {
- return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
-}
-
int readlinkat_malloc(int fd, const char *p, char **ret) {
size_t l = 100;
int r;
return 0;
}
-char *strstrip(char *s) {
- char *e;
-
- /* Drops trailing whitespace. Modifies the string in
- * place. Returns pointer to first non-space character */
-
- s += strspn(s, WHITESPACE);
-
- for (e = strchr(s, 0); e > s; e --)
- if (!strchr(WHITESPACE, e[-1]))
- break;
-
- *e = 0;
-
- return s;
-}
-
-char *delete_chars(char *s, const char *bad) {
- char *f, *t;
-
- /* Drops all whitespace, regardless where in the string */
-
- for (f = s, t = s; *f; f++) {
- if (strchr(bad, *f))
- continue;
-
- *(t++) = *f;
- }
-
- *t = 0;
-
- return s;
-}
-
char *file_in_same_dir(const char *path, const char *filename) {
char *e, *ret;
size_t k;
int undecchar(char c) {
if (c >= '0' && c <= '9')
- return c - '0';
-
- return -EINVAL;
-}
-
-char *cescape(const char *s) {
- char *r, *t;
- const char *f;
-
- assert(s);
-
- /* Does C style string escaping. May be reversed with
- * cunescape(). */
-
- r = new(char, strlen(s)*4 + 1);
- if (!r)
- return NULL;
-
- for (f = s, t = r; *f; f++)
- t += cescape_char(*f, t);
-
- *t = 0;
-
- return r;
-}
-
-static int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) {
- int r = 1;
-
- assert(p);
- assert(*p);
- assert(ret);
-
- /* Unescapes C style. Returns the unescaped character in ret,
- * unless we encountered a \u sequence in which case the full
- * unicode character is returned in ret_unicode, instead. */
-
- if (length != (size_t) -1 && length < 1)
- return -EINVAL;
-
- switch (p[0]) {
-
- case 'a':
- *ret = '\a';
- break;
- case 'b':
- *ret = '\b';
- break;
- case 'f':
- *ret = '\f';
- break;
- case 'n':
- *ret = '\n';
- break;
- case 'r':
- *ret = '\r';
- break;
- case 't':
- *ret = '\t';
- break;
- case 'v':
- *ret = '\v';
- break;
- case '\\':
- *ret = '\\';
- break;
- case '"':
- *ret = '"';
- break;
- case '\'':
- *ret = '\'';
- break;
-
- case 's':
- /* This is an extension of the XDG syntax files */
- *ret = ' ';
- break;
-
- case 'x': {
- /* hexadecimal encoding */
- int a, b;
-
- if (length != (size_t) -1 && length < 3)
- return -EINVAL;
-
- a = unhexchar(p[1]);
- if (a < 0)
- return -EINVAL;
-
- b = unhexchar(p[2]);
- if (b < 0)
- return -EINVAL;
-
- /* Don't allow NUL bytes */
- if (a == 0 && b == 0)
- return -EINVAL;
-
- *ret = (char) ((a << 4U) | b);
- r = 3;
- break;
- }
-
- case 'u': {
- /* C++11 style 16bit unicode */
-
- int a[4];
- unsigned i;
- uint32_t c;
-
- if (length != (size_t) -1 && length < 5)
- return -EINVAL;
-
- for (i = 0; i < 4; i++) {
- a[i] = unhexchar(p[1 + i]);
- if (a[i] < 0)
- return a[i];
- }
-
- c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3];
-
- /* Don't allow 0 chars */
- if (c == 0)
- return -EINVAL;
-
- if (c < 128)
- *ret = c;
- else {
- if (!ret_unicode)
- return -EINVAL;
-
- *ret = 0;
- *ret_unicode = c;
- }
-
- r = 5;
- break;
- }
-
- case 'U': {
- /* C++11 style 32bit unicode */
-
- int a[8];
- unsigned i;
- uint32_t c;
-
- if (length != (size_t) -1 && length < 9)
- return -EINVAL;
-
- for (i = 0; i < 8; i++) {
- a[i] = unhexchar(p[1 + i]);
- if (a[i] < 0)
- return a[i];
- }
-
- c = ((uint32_t) a[0] << 28U) | ((uint32_t) a[1] << 24U) | ((uint32_t) a[2] << 20U) | ((uint32_t) a[3] << 16U) |
- ((uint32_t) a[4] << 12U) | ((uint32_t) a[5] << 8U) | ((uint32_t) a[6] << 4U) | (uint32_t) a[7];
-
- /* Don't allow 0 chars */
- if (c == 0)
- return -EINVAL;
-
- /* Don't allow invalid code points */
- if (!unichar_is_valid(c))
- return -EINVAL;
-
- if (c < 128)
- *ret = c;
- else {
- if (!ret_unicode)
- return -EINVAL;
-
- *ret = 0;
- *ret_unicode = c;
- }
-
- r = 9;
- break;
- }
-
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7': {
- /* octal encoding */
- int a, b, c;
- uint32_t m;
-
- if (length != (size_t) -1 && length < 3)
- return -EINVAL;
-
- a = unoctchar(p[0]);
- if (a < 0)
- return -EINVAL;
-
- b = unoctchar(p[1]);
- if (b < 0)
- return -EINVAL;
-
- c = unoctchar(p[2]);
- if (c < 0)
- return -EINVAL;
-
- /* don't allow NUL bytes */
- if (a == 0 && b == 0 && c == 0)
- return -EINVAL;
-
- /* Don't allow bytes above 255 */
- m = ((uint32_t) a << 6U) | ((uint32_t) b << 3U) | (uint32_t) c;
- if (m > 255)
- return -EINVAL;
-
- *ret = m;
- r = 3;
- break;
- }
-
- default:
- return -EINVAL;
- }
-
- return r;
-}
-
-int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret) {
- char *r, *t;
- const char *f;
- size_t pl;
-
- assert(s);
- assert(ret);
-
- /* Undoes C style string escaping, and optionally prefixes it. */
-
- pl = prefix ? strlen(prefix) : 0;
-
- r = new(char, pl+length+1);
- if (!r)
- return -ENOMEM;
-
- if (prefix)
- memcpy(r, prefix, pl);
-
- for (f = s, t = r + pl; f < s + length; f++) {
- size_t remaining;
- uint32_t u;
- char c;
- int k;
-
- remaining = s + length - f;
- assert(remaining > 0);
-
- if (*f != '\\') {
- /* A literal literal, copy verbatim */
- *(t++) = *f;
- continue;
- }
-
- if (remaining == 1) {
- if (flags & UNESCAPE_RELAX) {
- /* A trailing backslash, copy verbatim */
- *(t++) = *f;
- continue;
- }
-
- free(r);
- return -EINVAL;
- }
-
- k = cunescape_one(f + 1, remaining - 1, &c, &u);
- if (k < 0) {
- if (flags & UNESCAPE_RELAX) {
- /* Invalid escape code, let's take it literal then */
- *(t++) = '\\';
- continue;
- }
-
- free(r);
- return k;
- }
-
- if (c != 0)
- /* Non-Unicode? Let's encode this directly */
- *(t++) = c;
- else
- /* Unicode? Then let's encode this in UTF-8 */
- t += utf8_encode_unichar(t, u);
-
- f += k;
- }
-
- *t = 0;
-
- *ret = r;
- return t - r;
-}
-
-int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) {
- return cunescape_length_with_prefix(s, length, NULL, flags, ret);
-}
-
-int cunescape(const char *s, UnescapeFlags flags, char **ret) {
- return cunescape_length(s, strlen(s), flags, ret);
-}
-
-char *xescape(const char *s, const char *bad) {
- char *r, *t;
- const char *f;
-
- /* Escapes all chars in bad, in addition to \ and all special
- * chars, in \xFF style escaping. May be reversed with
- * cunescape(). */
-
- r = new(char, strlen(s) * 4 + 1);
- if (!r)
- return NULL;
-
- for (f = s, t = r; *f; f++) {
-
- if ((*f < ' ') || (*f >= 127) ||
- (*f == '\\') || strchr(bad, *f)) {
- *(t++) = '\\';
- *(t++) = 'x';
- *(t++) = hexchar(*f >> 4);
- *(t++) = hexchar(*f);
- } else
- *(t++) = *f;
- }
-
- *t = 0;
-
- return r;
-}
-
-char *ascii_strlower(char *t) {
- char *p;
-
- assert(t);
-
- for (p = t; *p; p++)
- if (*p >= 'A' && *p <= 'Z')
- *p = *p - 'A' + 'a';
+ return c - '0';
- return t;
+ return -EINVAL;
}
_pure_ static bool hidden_file_allow_backup(const char *filename) {
return r;
}
-bool chars_intersect(const char *a, const char *b) {
- const char *p;
-
- /* Returns true if any of the chars in a are in b. */
- for (p = a; *p; p++)
- if (strchr(b, *p))
- return true;
-
- return false;
-}
-
bool fstype_is_network(const char *fstype) {
static const char table[] =
"afs\0"
int dir_is_empty(const char *path) {
_cleanup_closedir_ DIR *d;
+ struct dirent *de;
d = opendir(path);
if (!d)
return -errno;
- for (;;) {
- struct dirent *de;
-
- errno = 0;
- de = readdir(d);
- if (!de && errno != 0)
- return -errno;
-
- if (!de)
- return 1;
+ FOREACH_DIRENT(de, d, return -errno)
+ return 0;
- if (!hidden_file(de->d_name))
- return 0;
- }
+ return 1;
}
char* dirname_malloc(const char *path) {
return lookup_uid(getuid());
}
-bool is_temporary_fs(const struct statfs *s) {
+bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
assert(s);
+ assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
+
+ return F_TYPE_EQUAL(s->f_type, magic_value);
+}
+
+int fd_check_fstype(int fd, statfs_f_type_t magic_value) {
+ struct statfs s;
+
+ if (fstatfs(fd, &s) < 0)
+ return -errno;
- return F_TYPE_EQUAL(s->f_type, TMPFS_MAGIC) ||
- F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC);
+ return is_fs_type(&s, magic_value);
+}
+
+int path_check_fstype(const char *path, statfs_f_type_t magic_value) {
+ _cleanup_close_ int fd = -1;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ return -errno;
+
+ return fd_check_fstype(fd, magic_value);
+}
+
+bool is_temporary_fs(const struct statfs *s) {
+ return is_fs_type(s, TMPFS_MAGIC) ||
+ is_fs_type(s, RAMFS_MAGIC);
}
int fd_is_temporary_fs(int fd) {
return ret == 0;
}
-static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
- size_t x;
- char *r;
-
- assert(s);
- assert(percent <= 100);
- assert(new_length >= 3);
-
- if (old_length <= 3 || old_length <= new_length)
- return strndup(s, old_length);
-
- r = new0(char, new_length+1);
- if (!r)
- return NULL;
-
- x = (new_length * percent) / 100;
-
- if (x > new_length - 3)
- x = new_length - 3;
-
- memcpy(r, s, x);
- r[x] = '.';
- r[x+1] = '.';
- r[x+2] = '.';
- memcpy(r + x + 3,
- s + old_length - (new_length - x - 3),
- new_length - x - 3);
-
- return r;
-}
-
-char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
- size_t x;
- char *e;
- const char *i, *j;
- unsigned k, len, len2;
-
- assert(s);
- assert(percent <= 100);
- assert(new_length >= 3);
-
- /* if no multibyte characters use ascii_ellipsize_mem for speed */
- if (ascii_is_valid(s))
- return ascii_ellipsize_mem(s, old_length, new_length, percent);
-
- if (old_length <= 3 || old_length <= new_length)
- return strndup(s, old_length);
-
- x = (new_length * percent) / 100;
-
- if (x > new_length - 3)
- x = new_length - 3;
-
- k = 0;
- for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) {
- int c;
-
- c = utf8_encoded_to_unichar(i);
- if (c < 0)
- return NULL;
- k += unichar_iswide(c) ? 2 : 1;
- }
-
- if (k > x) /* last character was wide and went over quota */
- x ++;
-
- for (j = s + old_length; k < new_length && j > i; ) {
- int c;
-
- j = utf8_prev_char(j);
- c = utf8_encoded_to_unichar(j);
- if (c < 0)
- return NULL;
- k += unichar_iswide(c) ? 2 : 1;
- }
- assert(i <= j);
-
- /* we don't actually need to ellipsize */
- if (i == j)
- return memdup(s, old_length + 1);
-
- /* make space for ellipsis */
- j = utf8_next_char(j);
-
- len = i - s;
- len2 = s + old_length - j;
- e = new(char, len + 3 + len2 + 1);
- if (!e)
- return NULL;
-
- /*
- printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n",
- old_length, new_length, x, len, len2, k);
- */
-
- memcpy(e, s, len);
- e[len] = 0xe2; /* tri-dot ellipsis: … */
- e[len + 1] = 0x80;
- e[len + 2] = 0xa6;
-
- memcpy(e + len + 3, j, len2 + 1);
-
- return e;
-}
-
-char *ellipsize(const char *s, size_t length, unsigned percent) {
- return ellipsize_mem(s, strlen(s), length, percent);
-}
-
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
_cleanup_close_ int fd;
int r;
wait_for_terminate_and_warn(name, executor_pid, true);
}
-bool nulstr_contains(const char*nulstr, const char *needle) {
- const char *i;
-
- if (!nulstr)
- return false;
-
- NULSTR_FOREACH(i, nulstr)
- if (streq(i, needle))
- return true;
-
- return false;
-}
-
bool plymouth_running(void) {
return access("/run/plymouth/pid", F_OK) >= 0;
}
-char* strshorten(char *s, size_t l) {
- assert(s);
-
- if (l < strlen(s))
- s[l] = 0;
-
- return s;
-}
-
int pipe_eof(int fd) {
struct pollfd pollfd = {
.fd = fd,
return n;
}
-char *strjoin(const char *x, ...) {
- va_list ap;
- size_t l;
- char *r, *p;
-
- va_start(ap, x);
-
- if (x) {
- l = strlen(x);
-
- for (;;) {
- const char *t;
- size_t n;
-
- t = va_arg(ap, const char *);
- if (!t)
- break;
-
- n = strlen(t);
- if (n > ((size_t) -1) - l) {
- va_end(ap);
- return NULL;
- }
-
- l += n;
- }
- } else
- l = 0;
-
- va_end(ap);
-
- r = new(char, l+1);
- if (!r)
- return NULL;
-
- if (x) {
- p = stpcpy(r, x);
-
- va_start(ap, x);
-
- for (;;) {
- const char *t;
-
- t = va_arg(ap, const char *);
- if (!t)
- break;
-
- p = stpcpy(p, t);
- }
-
- va_end(ap);
- } else
- r[0] = 0;
-
- return r;
-}
-
bool is_main_thread(void) {
static thread_local int cached = 0;
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0));
+bool log_facility_unshifted_is_valid(int facility) {
+ return facility >= 0 && facility <= LOG_FAC(~0);
+}
+
static const char *const log_level_table[] = {
[LOG_EMERG] = "emerg",
[LOG_ALERT] = "alert",
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG);
+bool log_level_is_valid(int level) {
+ return level >= 0 && level <= LOG_DEBUG;
+}
+
static const char* const sched_policy_table[] = {
[SCHED_OTHER] = "other",
[SCHED_BATCH] = "batch",
return true;
}
-/**
- * Check if a string contains control characters. If 'ok' is non-NULL
- * it may be a string containing additional CCs to be considered OK.
- */
-bool string_has_cc(const char *p, const char *ok) {
- const char *t;
-
- assert(p);
-
- for (t = p; *t; t++) {
- if (ok && strchr(ok, *t))
- continue;
-
- if (*t > 0 && *t < ' ')
- return true;
-
- if (*t == 127)
- return true;
- }
-
- return false;
-}
-
bool path_is_safe(const char *p) {
if (isempty(p))
return draw_table[!is_locale_utf8()][ch];
}
-char *strreplace(const char *text, const char *old_string, const char *new_string) {
- const char *f;
- char *t, *r;
- size_t l, old_len, new_len;
-
- assert(text);
- assert(old_string);
- assert(new_string);
-
- old_len = strlen(old_string);
- new_len = strlen(new_string);
-
- l = strlen(text);
- r = new(char, l+1);
- if (!r)
- return NULL;
-
- f = text;
- t = r;
- while (*f) {
- char *a;
- size_t d, nl;
-
- if (!startswith(f, old_string)) {
- *(t++) = *(f++);
- continue;
- }
-
- d = t - r;
- nl = l - old_len + new_len;
- a = realloc(r, nl + 1);
- if (!a)
- goto oom;
-
- l = nl;
- r = a;
- t = r + d;
-
- t = stpcpy(t, new_string);
- f += old_len;
- }
-
- *t = 0;
- return r;
-
-oom:
- free(r);
- return NULL;
-}
-
-char *strip_tab_ansi(char **ibuf, size_t *_isz) {
- const char *i, *begin = NULL;
- enum {
- STATE_OTHER,
- STATE_ESCAPE,
- STATE_BRACKET
- } state = STATE_OTHER;
- char *obuf = NULL;
- size_t osz = 0, isz;
- FILE *f;
-
- assert(ibuf);
- assert(*ibuf);
-
- /* Strips ANSI color and replaces TABs by 8 spaces */
-
- isz = _isz ? *_isz : strlen(*ibuf);
-
- f = open_memstream(&obuf, &osz);
- if (!f)
- return NULL;
-
- for (i = *ibuf; i < *ibuf + isz + 1; i++) {
-
- switch (state) {
-
- case STATE_OTHER:
- if (i >= *ibuf + isz) /* EOT */
- break;
- else if (*i == '\x1B')
- state = STATE_ESCAPE;
- else if (*i == '\t')
- fputs(" ", f);
- else
- fputc(*i, f);
- break;
-
- case STATE_ESCAPE:
- if (i >= *ibuf + isz) { /* EOT */
- fputc('\x1B', f);
- break;
- } else if (*i == '[') {
- state = STATE_BRACKET;
- begin = i + 1;
- } else {
- fputc('\x1B', f);
- fputc(*i, f);
- state = STATE_OTHER;
- }
-
- break;
-
- case STATE_BRACKET:
-
- if (i >= *ibuf + isz || /* EOT */
- (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) {
- fputc('\x1B', f);
- fputc('[', f);
- state = STATE_OTHER;
- i = begin-1;
- } else if (*i == 'm')
- state = STATE_OTHER;
- break;
- }
- }
-
- if (ferror(f)) {
- fclose(f);
- free(obuf);
- return NULL;
- }
-
- fclose(f);
-
- free(*ibuf);
- *ibuf = obuf;
-
- if (_isz)
- *_isz = osz;
-
- return obuf;
-}
-
int on_ac_power(void) {
bool found_offline = false, found_online = false;
_cleanup_closedir_ DIR *d = NULL;
return 0;
}
- return -errno;
- }
-
- copy = strv_copy((char**) search);
- if (!copy)
- return -ENOMEM;
-
- return search_and_fopen_internal(path, mode, root, copy, _f);
-}
-
-int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) {
- _cleanup_strv_free_ char **s = NULL;
-
- if (path_is_absolute(path)) {
- FILE *f;
-
- f = fopen(path, mode);
- if (f) {
- *_f = f;
- return 0;
- }
-
- return -errno;
- }
-
- s = strv_split_nulstr(search);
- if (!s)
- return -ENOMEM;
-
- return search_and_fopen_internal(path, mode, root, s, _f);
-}
-
-char *strextend(char **x, ...) {
- va_list ap;
- size_t f, l;
- char *r, *p;
-
- assert(x);
-
- l = f = *x ? strlen(*x) : 0;
-
- va_start(ap, x);
- for (;;) {
- const char *t;
- size_t n;
-
- t = va_arg(ap, const char *);
- if (!t)
- break;
-
- n = strlen(t);
- if (n > ((size_t) -1) - l) {
- va_end(ap);
- return NULL;
- }
-
- l += n;
- }
- va_end(ap);
-
- r = realloc(*x, l+1);
- if (!r)
- return NULL;
-
- p = r + f;
-
- va_start(ap, x);
- for (;;) {
- const char *t;
-
- t = va_arg(ap, const char *);
- if (!t)
- break;
-
- p = stpcpy(p, t);
+ return -errno;
}
- va_end(ap);
- *p = 0;
- *x = r;
+ copy = strv_copy((char**) search);
+ if (!copy)
+ return -ENOMEM;
- return r + l;
+ return search_and_fopen_internal(path, mode, root, copy, _f);
}
-char *strrep(const char *s, unsigned n) {
- size_t l;
- char *r, *p;
- unsigned i;
+int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) {
+ _cleanup_strv_free_ char **s = NULL;
- assert(s);
+ if (path_is_absolute(path)) {
+ FILE *f;
- l = strlen(s);
- p = r = malloc(l * n + 1);
- if (!r)
- return NULL;
+ f = fopen(path, mode);
+ if (f) {
+ *_f = f;
+ return 0;
+ }
- for (i = 0; i < n; i++)
- p = stpcpy(p, s);
+ return -errno;
+ }
- *p = 0;
- return r;
+ s = strv_split_nulstr(search);
+ if (!s)
+ return -ENOMEM;
+
+ return search_and_fopen_internal(path, mode, root, s, _f);
}
void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
return true;
}
-int split_pair(const char *s, const char *sep, char **l, char **r) {
- char *x, *a, *b;
-
- assert(s);
- assert(sep);
- assert(l);
- assert(r);
-
- if (isempty(sep))
- return -EINVAL;
-
- x = strstr(s, sep);
- if (!x)
- return -EINVAL;
-
- a = strndup(s, x - s);
- if (!a)
- return -ENOMEM;
-
- b = strdup(x + strlen(sep));
- if (!b) {
- free(a);
- return -ENOMEM;
- }
-
- *l = a;
- *r = b;
-
- return 0;
-}
-
int shall_restore_state(void) {
_cleanup_free_ char *value = NULL;
int r;
return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
}
-int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) {
- _cleanup_free_ char *s = NULL;
- size_t allocated = 0, sz = 0;
- int r;
-
- enum {
- START,
- VALUE,
- VALUE_ESCAPE,
- SINGLE_QUOTE,
- SINGLE_QUOTE_ESCAPE,
- DOUBLE_QUOTE,
- DOUBLE_QUOTE_ESCAPE,
- SEPARATOR,
- } state = START;
-
- assert(p);
- assert(ret);
-
- if (!separators)
- separators = WHITESPACE;
-
- /* Bail early if called after last value or with no input */
- if (!*p)
- goto finish_force_terminate;
-
- /* Parses the first word of a string, and returns it in
- * *ret. Removes all quotes in the process. When parsing fails
- * (because of an uneven number of quotes or similar), leaves
- * the pointer *p at the first invalid character. */
-
- for (;;) {
- char c = **p;
-
- switch (state) {
-
- case START:
- if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
- if (!GREEDY_REALLOC(s, allocated, sz+1))
- return -ENOMEM;
-
- if (c == 0)
- goto finish_force_terminate;
- else if (strchr(separators, c)) {
- if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
- (*p) ++;
- goto finish_force_next;
- }
- break;
- }
-
- /* We found a non-blank character, so we will always
- * want to return a string (even if it is empty),
- * allocate it here. */
- if (!GREEDY_REALLOC(s, allocated, sz+1))
- return -ENOMEM;
-
- state = VALUE;
- /* fallthrough */
-
- case VALUE:
- if (c == 0)
- goto finish_force_terminate;
- else if (c == '\'' && (flags & EXTRACT_QUOTES))
- state = SINGLE_QUOTE;
- else if (c == '\\')
- state = VALUE_ESCAPE;
- else if (c == '\"' && (flags & EXTRACT_QUOTES))
- state = DOUBLE_QUOTE;
- else if (strchr(separators, c)) {
- if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
- (*p) ++;
- goto finish_force_next;
- }
- state = SEPARATOR;
- } else {
- if (!GREEDY_REALLOC(s, allocated, sz+2))
- return -ENOMEM;
-
- s[sz++] = c;
- }
-
- break;
-
- case SINGLE_QUOTE:
- if (c == 0) {
- if (flags & EXTRACT_RELAX)
- goto finish_force_terminate;
- return -EINVAL;
- } else if (c == '\'')
- state = VALUE;
- else if (c == '\\')
- state = SINGLE_QUOTE_ESCAPE;
- else {
- if (!GREEDY_REALLOC(s, allocated, sz+2))
- return -ENOMEM;
-
- s[sz++] = c;
- }
-
- break;
-
- case DOUBLE_QUOTE:
- if (c == 0)
- return -EINVAL;
- else if (c == '\"')
- state = VALUE;
- else if (c == '\\')
- state = DOUBLE_QUOTE_ESCAPE;
- else {
- if (!GREEDY_REALLOC(s, allocated, sz+2))
- return -ENOMEM;
-
- s[sz++] = c;
- }
-
- break;
-
- case SINGLE_QUOTE_ESCAPE:
- case DOUBLE_QUOTE_ESCAPE:
- case VALUE_ESCAPE:
- if (!GREEDY_REALLOC(s, allocated, sz+7))
- return -ENOMEM;
-
- if (c == 0) {
- if ((flags & EXTRACT_CUNESCAPE_RELAX) &&
- (state == VALUE_ESCAPE || flags & EXTRACT_RELAX)) {
- /* If we find an unquoted trailing backslash and we're in
- * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the
- * output.
- *
- * Unbalanced quotes will only be allowed in EXTRACT_RELAX
- * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them.
- */
- s[sz++] = '\\';
- goto finish_force_terminate;
- }
- if (flags & EXTRACT_RELAX)
- goto finish_force_terminate;
- return -EINVAL;
- }
-
- if (flags & EXTRACT_CUNESCAPE) {
- uint32_t u;
-
- r = cunescape_one(*p, (size_t) -1, &c, &u);
- if (r < 0) {
- if (flags & EXTRACT_CUNESCAPE_RELAX) {
- s[sz++] = '\\';
- s[sz++] = c;
- goto end_escape;
- }
- return -EINVAL;
- }
-
- (*p) += r - 1;
-
- if (c != 0)
- s[sz++] = c; /* normal explicit char */
- else
- sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */
- } else
- s[sz++] = c;
-
-end_escape:
- state = (state == SINGLE_QUOTE_ESCAPE) ? SINGLE_QUOTE :
- (state == DOUBLE_QUOTE_ESCAPE) ? DOUBLE_QUOTE :
- VALUE;
- break;
-
- case SEPARATOR:
- if (c == 0)
- goto finish_force_terminate;
- if (!strchr(separators, c))
- goto finish;
- break;
- }
-
- (*p) ++;
- }
-
-finish_force_terminate:
- *p = NULL;
-finish:
- if (!s) {
- *p = NULL;
- *ret = NULL;
- return 0;
- }
-
-finish_force_next:
- s[sz] = 0;
- *ret = s;
- s = NULL;
-
- return 1;
-}
-
-int extract_first_word_and_warn(
- const char **p,
- char **ret,
- const char *separators,
- ExtractFlags flags,
- const char *unit,
- const char *filename,
- unsigned line,
- const char *rvalue) {
-
- /* Try to unquote it, if it fails, warn about it and try again but this
- * time using EXTRACT_CUNESCAPE_RELAX to keep the backslashes verbatim
- * in invalid escape sequences. */
- const char *save;
- int r;
-
- save = *p;
- r = extract_first_word(p, ret, separators, flags);
- if (r < 0 && !(flags & EXTRACT_CUNESCAPE_RELAX)) {
-
- /* Retry it with EXTRACT_CUNESCAPE_RELAX. */
- *p = save;
- r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, r, "Unbalanced quoting in command line, ignoring: \"%s\"", rvalue);
- else
- log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid escape sequences in command line: \"%s\"", rvalue);
- }
-
- return r;
-}
-
-int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) {
- va_list ap;
- char **l;
- int n = 0, i, c, r;
-
- /* Parses a number of words from a string, stripping any
- * quotes if necessary. */
-
- assert(p);
-
- /* Count how many words are expected */
- va_start(ap, flags);
- for (;;) {
- if (!va_arg(ap, char **))
- break;
- n++;
- }
- va_end(ap);
-
- if (n <= 0)
- return 0;
-
- /* Read all words into a temporary array */
- l = newa0(char*, n);
- for (c = 0; c < n; c++) {
-
- r = extract_first_word(p, &l[c], separators, flags);
- if (r < 0) {
- int j;
-
- for (j = 0; j < c; j++)
- free(l[j]);
-
- return r;
- }
-
- if (r == 0)
- break;
- }
-
- /* If we managed to parse all words, return them in the passed
- * in parameters */
- va_start(ap, flags);
- for (i = 0; i < n; i++) {
- char **v;
-
- v = va_arg(ap, char **);
- assert(v);
-
- *v = l[i];
- }
- va_end(ap);
-
- return c;
-}
-
-int free_and_strdup(char **p, const char *s) {
- char *t;
-
- assert(p);
-
- /* Replaces a string pointer with an strdup()ed new string,
- * possibly freeing the old one. */
-
- if (streq_ptr(*p, s))
- return 0;
-
- if (s) {
- t = strdup(s);
- if (!t)
- return -ENOMEM;
- } else
- t = NULL;
-
- free(*p);
- *p = t;
-
- return 1;
-}
-
-int ptsname_malloc(int fd, char **ret) {
- size_t l = 100;
-
- assert(fd >= 0);
- assert(ret);
-
- for (;;) {
- char *c;
-
- c = new(char, l);
- if (!c)
- return -ENOMEM;
-
- if (ptsname_r(fd, c, l) == 0) {
- *ret = c;
- return 0;
- }
- if (errno != ERANGE) {
- free(c);
- return -errno;
- }
-
- free(c);
- l *= 2;
- }
-}
-
-int openpt_in_namespace(pid_t pid, int flags) {
- _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
- _cleanup_close_pair_ int pair[2] = { -1, -1 };
- siginfo_t si;
- pid_t child;
- int r;
-
- assert(pid > 0);
-
- r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
- if (r < 0)
- return r;
-
- if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
- return -errno;
-
- child = fork();
- if (child < 0)
- return -errno;
-
- if (child == 0) {
- int master;
-
- pair[0] = safe_close(pair[0]);
-
- r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
- if (r < 0)
- _exit(EXIT_FAILURE);
-
- master = posix_openpt(flags);
- if (master < 0)
- _exit(EXIT_FAILURE);
-
- if (unlockpt(master) < 0)
- _exit(EXIT_FAILURE);
-
- if (send_one_fd(pair[1], master, 0) < 0)
- _exit(EXIT_FAILURE);
-
- _exit(EXIT_SUCCESS);
- }
-
- pair[1] = safe_close(pair[1]);
-
- r = wait_for_terminate(child, &si);
- if (r < 0)
- return r;
- if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
- return -EIO;
-
- return receive_one_fd(pair[0], 0);
-}
-
ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) {
+ char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
_cleanup_close_ int fd = -1;
ssize_t l;
/* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */
- fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOATIME|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
+ fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
if (fd < 0)
return -errno;
- l = fgetxattr(fd, attribute, value, size);
+ xsprintf(fn, "/proc/self/fd/%i", fd);
+
+ l = getxattr(fn, attribute, value, size);
if (l < 0)
return -errno;
return 0;
}
-static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) {
- assert(bad);
-
- for (; *s; s++) {
- if (*s == '\\' || strchr(bad, *s))
- *(t++) = '\\';
-
- *(t++) = *s;
- }
-
- return t;
-}
-
-char *shell_escape(const char *s, const char *bad) {
- char *r, *t;
-
- r = new(char, strlen(s)*2+1);
- if (!r)
- return NULL;
-
- t = strcpy_backslash_escaped(r, s, bad);
- *t = 0;
-
- return r;
-}
-
-char *shell_maybe_quote(const char *s) {
- const char *p;
- char *r, *t;
-
- assert(s);
-
- /* Encloses a string in double quotes if necessary to make it
- * OK as shell string. */
-
- for (p = s; *p; p++)
- if (*p <= ' ' ||
- *p >= 127 ||
- strchr(SHELL_NEED_QUOTES, *p))
- break;
-
- if (!*p)
- return strdup(s);
-
- r = new(char, 1+strlen(s)*2+1+1);
- if (!r)
- return NULL;
-
- t = r;
- *(t++) = '"';
- t = mempcpy(t, s, p - s);
-
- t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE);
-
- *(t++)= '"';
- *t = 0;
-
- return r;
-}
-
int parse_mode(const char *s, mode_t *ret) {
char *x;
long l;
SYSTEMD_FEATURES);
return 0;
}
+
+bool fdname_is_valid(const char *s) {
+ const char *p;
+
+ /* Validates a name for $LISTEN_FDNAMES. We basically allow
+ * everything ASCII that's not a control character. Also, as
+ * special exception the ":" character is not allowed, as we
+ * use that as field separator in $LISTEN_FDNAMES.
+ *
+ * Note that the empty string is explicitly allowed
+ * here. However, we limit the length of the names to 255
+ * characters. */
+
+ if (!s)
+ return false;
+
+ for (p = s; *p; p++) {
+ if (*p < ' ')
+ return false;
+ if (*p >= 127)
+ return false;
+ if (*p == ':')
+ return false;
+ }
+
+ return p - s < 256;
+}
+
+bool oom_score_adjust_is_valid(int oa) {
+ return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX;
+}