return (char*) s + sl - pl;
}
-bool first_word(const char *s, const char *word) {
+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 false;
+ return NULL;
if (wl == 0)
- return true;
+ return (char*) s;
if (memcmp(s, word, wl) != 0)
- return false;
+ return NULL;
- return s[wl] == 0 ||
- strchr(WHITESPACE, s[wl]);
+ p = s + wl;
+ if (*p == 0)
+ return (char*) p;
+
+ if (!strchr(WHITESPACE, *p))
+ return NULL;
+
+ p += strspn(p, WHITESPACE);
+ return (char*) p;
}
int close_nointr(int fd) {
- int r;
-
assert(fd >= 0);
- r = close(fd);
- if (r >= 0)
- return r;
- else if (errno == EINTR)
- /*
- * Just ignore EINTR; a retry loop is the wrong
- * thing to do on Linux.
- *
- * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
- * https://bugzilla.gnome.org/show_bug.cgi?id=682819
- * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR
- * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain
- */
+
+ if (close(fd) >= 0)
return 0;
- else
- return -errno;
+
+ /*
+ * Just ignore EINTR; a retry loop is the wrong thing to do on
+ * Linux.
+ *
+ * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
+ * https://bugzilla.gnome.org/show_bug.cgi?id=682819
+ * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR
+ * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain
+ */
+ if (errno == EINTR)
+ return 0;
+
+ return -errno;
}
int safe_close(int fd) {
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
- return -1;
+ return -EINVAL;
}
char *hexmem(const void *p, size_t l) {
if (c >= '0' && c <= '7')
return c - '0';
- return -1;
+ return -EINVAL;
}
char decchar(int x) {
if (c >= '0' && c <= '9')
return c - '0';
- return -1;
+ return -EINVAL;
}
char *cescape(const char *s) {
endswith(filename, ".rpmorig") ||
endswith(filename, ".dpkg-old") ||
endswith(filename, ".dpkg-new") ||
+ endswith(filename, ".dpkg-tmp") ||
endswith(filename, ".swp");
}
}
int release_terminal(void) {
- int r = 0;
- struct sigaction sa_old, sa_new = {
+ static const struct sigaction sa_new = {
.sa_handler = SIG_IGN,
.sa_flags = SA_RESTART,
};
- _cleanup_close_ int fd;
+
+ _cleanup_close_ int fd = -1;
+ struct sigaction sa_old;
+ int r = 0;
fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY|O_CLOEXEC);
if (fd < 0)
if (emax < 3)
emax = 3;
- e = ellipsize(s, emax, 75);
+ e = ellipsize(s, emax, 50);
if (e) {
free(s);
s = e;
_exit(EXIT_FAILURE);
}
-
log_debug("Spawned %s as " PID_FMT ".", path, pid);
r = hashmap_put(pids, UINT_TO_PTR(pid), path);
if (signo > 0 && signo < _NSIG)
return signo;
}
- return -1;
+ return -EINVAL;
}
bool kexec_loaded(void) {
bool is_localhost(const char *hostname) {
assert(hostname);
- /* This tries to identify local hostnames described in RFC6761
- * plus the redhatism of .localdomain */
+ /* This tries to identify local host and domain names
+ * described in RFC6761 plus the redhatism of .localdomain */
return streq(hostname, "localhost") ||
streq(hostname, "localhost.") ||
+ streq(hostname, "localdomain.") ||
+ streq(hostname, "localdomain") ||
endswith(hostname, ".localhost") ||
endswith(hostname, ".localhost.") ||
endswith(hostname, ".localdomain") ||
return fd;
}
+
+int is_symlink(const char *path) {
+ struct stat info;
+
+ if (lstat(path, &info) < 0)
+ return -errno;
+
+ if (S_ISLNK(info.st_mode))
+ return 1;
+
+ return 0;
+}
+
+int unquote_first_word(const char **p, char **ret) {
+ _cleanup_free_ char *s = NULL;
+ size_t allocated = 0, sz = 0;
+
+ enum {
+ START,
+ VALUE,
+ VALUE_ESCAPE,
+ SINGLE_QUOTE,
+ SINGLE_QUOTE_ESCAPE,
+ DOUBLE_QUOTE,
+ DOUBLE_QUOTE_ESCAPE,
+ SPACE,
+ } state = START;
+
+ assert(p);
+ assert(*p);
+ assert(ret);
+
+ /* 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 (c == 0)
+ goto finish;
+ else if (strchr(WHITESPACE, c))
+ break;
+
+ state = VALUE;
+ /* fallthrough */
+
+ case VALUE:
+ if (c == 0)
+ goto finish;
+ else if (c == '\'')
+ state = SINGLE_QUOTE;
+ else if (c == '\\')
+ state = VALUE_ESCAPE;
+ else if (c == '\"')
+ state = DOUBLE_QUOTE;
+ else if (strchr(WHITESPACE, c))
+ state = SPACE;
+ else {
+ if (!GREEDY_REALLOC(s, allocated, sz+2))
+ return -ENOMEM;
+
+ s[sz++] = c;
+ }
+
+ break;
+
+ case VALUE_ESCAPE:
+ if (c == 0)
+ return -EINVAL;
+
+ if (!GREEDY_REALLOC(s, allocated, sz+2))
+ return -ENOMEM;
+
+ s[sz++] = c;
+ state = VALUE;
+
+ break;
+
+ case SINGLE_QUOTE:
+ if (c == 0)
+ 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 SINGLE_QUOTE_ESCAPE:
+ if (c == 0)
+ return -EINVAL;
+
+ if (!GREEDY_REALLOC(s, allocated, sz+2))
+ return -ENOMEM;
+
+ s[sz++] = c;
+ state = SINGLE_QUOTE;
+ 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 DOUBLE_QUOTE_ESCAPE:
+ if (c == 0)
+ return -EINVAL;
+
+ if (!GREEDY_REALLOC(s, allocated, sz+2))
+ return -ENOMEM;
+
+ s[sz++] = c;
+ state = DOUBLE_QUOTE;
+ break;
+
+ case SPACE:
+ if (c == 0)
+ goto finish;
+ if (!strchr(WHITESPACE, c))
+ goto finish;
+
+ break;
+ }
+
+ (*p) ++;
+ }
+
+finish:
+ if (!s) {
+ *ret = NULL;
+ return 0;
+ }
+
+ s[sz] = 0;
+ *ret = s;
+ s = NULL;
+
+ return 1;
+}
+
+int unquote_many_words(const char **p, ...) {
+ 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, p);
+ 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 = unquote_first_word(p, &l[c]);
+ 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, p);
+ for (i = 0; i < n; i++) {
+ char **v;
+
+ v = va_arg(ap, char **);
+ assert(v);
+
+ *v = l[i];
+ }
+ va_end(ap);
+
+ return c;
+}