X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fbasic%2Futil.c;h=d5c758e6ff9aeb8edf64b2381dfc4304b60d4b31;hb=ba812e282b3406f478e8ede2b6eb885f61fae6fc;hp=f17a473d6c6c3c59186a9eff84275394a1a6d4ce;hpb=1532f28b7cf3e6e02e74691450b2b5379be6b805;p=elogind.git
diff --git a/src/basic/util.c b/src/basic/util.c
index f17a473d6..d5c758e6f 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -19,81 +19,81 @@
along with systemd; If not, see .
***/
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
+// #include
+// #include
+#include
+// #include
+// #include
+// #include
+// #include
+// #include
+// #include
+// #include
+// #include
+// #include
+// #include
+// #include
+// #include
+// #include
+// #include
+#include
+// #include
+#include
+// #include
+#include
+#include
+// #include
+// #include
+// #include
+#include
+// #include
+// #include
+// #include
+#include
+// #include
+#include
+// #include
+// #include
+#include
+// #include
+// #include
+#include
/* When we include libgen.h because we need dirname() we immediately
* undefine basename() since libgen.h defines it as a macro to the POSIX
* version which is really broken. We prefer GNU basename(). */
-#include
-#undef basename
+// #include
+// #undef basename
#ifdef HAVE_SYS_AUXV_H
#include
#endif
-#include "config.h"
-#include "macro.h"
-#include "util.h"
-#include "ioprio.h"
-#include "missing.h"
-#include "log.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "path-util.h"
-#include "exit-status.h"
-#include "hashmap.h"
-#include "env-util.h"
-#include "fileio.h"
-#include "device-nodes.h"
-#include "utf8.h"
-#include "gunicode.h"
-#include "virt.h"
-#include "def.h"
-#include "sparse-endian.h"
-#include "formats-util.h"
-#include "process-util.h"
-#include "random-util.h"
-#include "terminal-util.h"
-#include "hostname-util.h"
-#include "signal-util.h"
+#include "config.h"
+#include "macro.h"
+#include "util.h"
+#include "ioprio.h"
+// #include "missing.h"
+// #include "log.h"
+#include "strv.h"
+#include "mkdir.h"
+#include "path-util.h"
+// #include "exit-status.h"
+// #include "hashmap.h"
+// #include "env-util.h"
+#include "fileio.h"
+// #include "device-nodes.h"
+#include "utf8.h"
+#include "gunicode.h"
+#include "virt.h"
+// #include "def.h"
+#include "sparse-endian.h"
+// #include "formats-util.h"
+#include "process-util.h"
+#include "random-util.h"
+// #include "terminal-util.h"
+#include "hostname-util.h"
+#include "signal-util.h"
/* Put this test here for a lack of better place */
assert_cc(EAGAIN == EWOULDBLOCK);
@@ -115,17 +115,23 @@ size_t page_size(void) {
return pgsz;
}
-bool streq_ptr(const char *a, const char *b) {
-
- /* Like streq(), but tries to make sense of NULL pointers */
+int strcmp_ptr(const char *a, const char *b) {
+ /* Like strcmp(), but tries to make sense of NULL pointers */
if (a && b)
- return streq(a, b);
+ return strcmp(a, b);
- if (!a && !b)
- return true;
+ if (!a && b)
+ return -1;
- return false;
+ 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) {
@@ -707,6 +713,8 @@ int readlink_malloc(const char *p, char **ret) {
return readlinkat_malloc(AT_FDCWD, p, ret);
}
+/// UNNEEDED by elogind
+#if 0
int readlink_value(const char *p, char **ret) {
_cleanup_free_ char *link = NULL;
char *value;
@@ -728,6 +736,7 @@ int readlink_value(const char *p, char **ret) {
return 0;
}
+#endif // 0
int readlink_and_make_absolute(const char *p, char **r) {
_cleanup_free_ char *target = NULL;
@@ -749,6 +758,8 @@ int readlink_and_make_absolute(const char *p, char **r) {
return 0;
}
+/// UNNEEDED by elogind
+#if 0
int readlink_and_canonicalize(const char *p, char **r) {
char *t, *s;
int j;
@@ -771,6 +782,7 @@ int readlink_and_canonicalize(const char *p, char **r) {
return 0;
}
+#endif // 0
char *strstrip(char *s) {
char *e;
@@ -836,6 +848,8 @@ char *file_in_same_dir(const char *path, const char *filename) {
return ret;
}
+/// UNNEEDED by elogind
+#if 0
int rmdir_parents(const char *path, const char *stop) {
size_t l;
int r = 0;
@@ -881,6 +895,7 @@ int rmdir_parents(const char *path, const char *stop) {
return 0;
}
+#endif // 0
char hexchar(int x) {
static const char table[16] = "0123456789abcdef";
@@ -919,32 +934,573 @@ char *hexmem(const void *p, size_t l) {
return r;
}
-void *unhexmem(const char *p, size_t l) {
- uint8_t *r, *z;
+int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
+ _cleanup_free_ uint8_t *r = NULL;
+ uint8_t *z;
const char *x;
+ assert(mem);
+ assert(len);
assert(p);
z = r = malloc((l + 1) / 2 + 1);
if (!r)
- return NULL;
+ return -ENOMEM;
for (x = p; x < p + l; x += 2) {
int a, b;
a = unhexchar(x[0]);
- if (x+1 < p + l)
+ if (a < 0)
+ return a;
+ else if (x+1 < p + l) {
b = unhexchar(x[1]);
- else
+ if (b < 0)
+ return b;
+ } else
b = 0;
*(z++) = (uint8_t) a << 4 | (uint8_t) b;
}
+ *z = 0;
+
+ *mem = r;
+ r = NULL;
+ *len = (l + 1) / 2;
+
+ return 0;
+}
+
+/* https://tools.ietf.org/html/rfc4648#section-6
+ * Notice that base32hex differs from base32 in the alphabet it uses.
+ * The distinction is that the base32hex representation preserves the
+ * order of the underlying data when compared as bytestrings, this is
+ * useful when representing NSEC3 hashes, as one can then verify the
+ * order of hashes directly from their representation. */
+char base32hexchar(int x) {
+ static const char table[32] = "0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUV";
+
+ return table[x & 31];
+}
+
+int unbase32hexchar(char c) {
+ unsigned offset;
+
+ if (c >= '0' && c <= '9')
+ return c - '0';
+
+ offset = '9' - '0' + 1;
+
+ if (c >= 'A' && c <= 'V')
+ return c - 'A' + offset;
+
+ return -EINVAL;
+}
+
+char *base32hexmem(const void *p, size_t l, bool padding) {
+ char *r, *z;
+ const uint8_t *x;
+ size_t len;
+
+ if (padding)
+ /* five input bytes makes eight output bytes, padding is added so we must round up */
+ len = 8 * (l + 4) / 5;
+ else {
+ /* same, but round down as there is no padding */
+ len = 8 * l / 5;
+
+ switch (l % 5) {
+ case 4:
+ len += 7;
+ break;
+ case 3:
+ len += 5;
+ break;
+ case 2:
+ len += 4;
+ break;
+ case 1:
+ len += 2;
+ break;
+ }
+ }
+
+ z = r = malloc(len + 1);
+ if (!r)
+ return NULL;
+
+ for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) {
+ /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
+ x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
+ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
+ *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
+ *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
+ *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
+ *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
+ *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
+ *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */
+ *(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */
+ }
+
+ switch (l % 5) {
+ case 4:
+ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
+ *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
+ *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
+ *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
+ *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
+ *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
+ *(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */
+ if (padding)
+ *(z++) = '=';
+
+ break;
+
+ case 3:
+ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
+ *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
+ *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
+ *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
+ *(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */
+ if (padding) {
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ }
+
+ break;
+
+ case 2:
+ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
+ *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
+ *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
+ *(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */
+ if (padding) {
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ }
+
+ break;
+
+ case 1:
+ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
+ *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
+ if (padding) {
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ *(z++) = '=';
+ }
+
+ break;
+ }
+
*z = 0;
return r;
}
+int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) {
+ _cleanup_free_ uint8_t *r = NULL;
+ int a, b, c, d, e, f, g, h;
+ uint8_t *z;
+ const char *x;
+ size_t len;
+ unsigned pad = 0;
+
+ assert(p);
+
+ /* padding ensures any base32hex input has input divisible by 8 */
+ if (padding && l % 8 != 0)
+ return -EINVAL;
+
+ if (padding) {
+ /* strip the padding */
+ while (l > 0 && p[l - 1] == '=' && pad < 7) {
+ pad ++;
+ l --;
+ }
+ }
+
+ /* a group of eight input bytes needs five output bytes, in case of
+ padding we need to add some extra bytes */
+ len = (l / 8) * 5;
+
+ switch (l % 8) {
+ case 7:
+ len += 4;
+ break;
+ case 5:
+ len += 3;
+ break;
+ case 4:
+ len += 2;
+ break;
+ case 2:
+ len += 1;
+ break;
+ case 0:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ z = r = malloc(len + 1);
+ if (!r)
+ return -ENOMEM;
+
+ for (x = p; x < p + (l / 8) * 8; x += 8) {
+ /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
+ e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
+ a = unbase32hexchar(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase32hexchar(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase32hexchar(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ d = unbase32hexchar(x[3]);
+ if (d < 0)
+ return -EINVAL;
+
+ e = unbase32hexchar(x[4]);
+ if (e < 0)
+ return -EINVAL;
+
+ f = unbase32hexchar(x[5]);
+ if (f < 0)
+ return -EINVAL;
+
+ g = unbase32hexchar(x[6]);
+ if (g < 0)
+ return -EINVAL;
+
+ h = unbase32hexchar(x[7]);
+ if (h < 0)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
+ *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
+ *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
+ *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
+ *(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */
+ }
+
+ switch (l % 8) {
+ case 7:
+ a = unbase32hexchar(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase32hexchar(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase32hexchar(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ d = unbase32hexchar(x[3]);
+ if (d < 0)
+ return -EINVAL;
+
+ e = unbase32hexchar(x[4]);
+ if (e < 0)
+ return -EINVAL;
+
+ f = unbase32hexchar(x[5]);
+ if (f < 0)
+ return -EINVAL;
+
+ g = unbase32hexchar(x[6]);
+ if (g < 0)
+ return -EINVAL;
+
+ /* g == 000VV000 */
+ if (g & 7)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
+ *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
+ *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
+ *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
+
+ break;
+ case 5:
+ a = unbase32hexchar(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase32hexchar(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase32hexchar(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ d = unbase32hexchar(x[3]);
+ if (d < 0)
+ return -EINVAL;
+
+ e = unbase32hexchar(x[4]);
+ if (e < 0)
+ return -EINVAL;
+
+ /* e == 000SSSS0 */
+ if (e & 1)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
+ *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
+ *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
+
+ break;
+ case 4:
+ a = unbase32hexchar(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase32hexchar(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase32hexchar(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ d = unbase32hexchar(x[3]);
+ if (d < 0)
+ return -EINVAL;
+
+ /* d == 000W0000 */
+ if (d & 15)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
+ *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
+
+ break;
+ case 2:
+ a = unbase32hexchar(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase32hexchar(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ /* b == 000YYY00 */
+ if (b & 3)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
+
+ break;
+ case 0:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *z = 0;
+
+ *mem = r;
+ r = NULL;
+ *_len = len;
+
+ return 0;
+}
+
+/* https://tools.ietf.org/html/rfc4648#section-4 */
+char base64char(int x) {
+ static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
+ return table[x & 63];
+}
+
+int unbase64char(char c) {
+ unsigned offset;
+
+ if (c >= 'A' && c <= 'Z')
+ return c - 'A';
+
+ offset = 'Z' - 'A' + 1;
+
+ if (c >= 'a' && c <= 'z')
+ return c - 'a' + offset;
+
+ offset += 'z' - 'a' + 1;
+
+ if (c >= '0' && c <= '9')
+ return c - '0' + offset;
+
+ offset += '9' - '0' + 1;
+
+ if (c == '+')
+ return offset;
+
+ offset ++;
+
+ if (c == '/')
+ return offset;
+
+ return -EINVAL;
+}
+
+char *base64mem(const void *p, size_t l) {
+ char *r, *z;
+ const uint8_t *x;
+
+ /* three input bytes makes four output bytes, padding is added so we must round up */
+ z = r = malloc(4 * (l + 2) / 3 + 1);
+ if (!r)
+ return NULL;
+
+ for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
+ /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
+ *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
+ *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
+ *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
+ *(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */
+ }
+
+ switch (l % 3) {
+ case 2:
+ *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
+ *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
+ *(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */
+ *(z++) = '=';
+
+ break;
+ case 1:
+ *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
+ *(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */
+ *(z++) = '=';
+ *(z++) = '=';
+
+ break;
+ }
+
+ *z = 0;
+ return r;
+}
+
+int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
+ _cleanup_free_ uint8_t *r = NULL;
+ int a, b, c, d;
+ uint8_t *z;
+ const char *x;
+ size_t len;
+
+ assert(p);
+
+ /* padding ensures any base63 input has input divisible by 4 */
+ if (l % 4 != 0)
+ return -EINVAL;
+
+ /* strip the padding */
+ if (l > 0 && p[l - 1] == '=')
+ l --;
+ if (l > 0 && p[l - 1] == '=')
+ l --;
+
+ /* a group of four input bytes needs three output bytes, in case of
+ padding we need to add two or three extra bytes */
+ len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0);
+
+ z = r = malloc(len + 1);
+ if (!r)
+ return -ENOMEM;
+
+ for (x = p; x < p + (l / 4) * 4; x += 4) {
+ /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
+ a = unbase64char(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase64char(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase64char(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ d = unbase64char(x[3]);
+ if (d < 0)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
+ *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
+ *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */
+ }
+
+ switch (l % 4) {
+ case 3:
+ a = unbase64char(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase64char(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ c = unbase64char(x[2]);
+ if (c < 0)
+ return -EINVAL;
+
+ /* c == 00ZZZZ00 */
+ if (c & 3)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
+ *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
+
+ break;
+ case 2:
+ a = unbase64char(x[0]);
+ if (a < 0)
+ return -EINVAL;
+
+ b = unbase64char(x[1]);
+ if (b < 0)
+ return -EINVAL;
+
+ /* b == 00YY0000 */
+ if (b & 15)
+ return -EINVAL;
+
+ *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
+
+ break;
+ case 0:
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *z = 0;
+
+ *mem = r;
+ r = NULL;
+ *_len = len;
+
+ return 0;
+}
+
char octchar(int x) {
return '0' + (x & 7);
}
@@ -1301,6 +1857,8 @@ char *xescape(const char *s, const char *bad) {
return r;
}
+/// UNNEEDED by elogind
+#if 0
char *ascii_strlower(char *t) {
char *p;
@@ -1312,6 +1870,7 @@ char *ascii_strlower(char *t) {
return t;
}
+#endif // 0
_pure_ static bool hidden_file_allow_backup(const char *filename) {
assert(filename);
@@ -1471,6 +2030,8 @@ bool chars_intersect(const char *a, const char *b) {
return false;
}
+/// UNNEEDED by elogind
+#if 0
bool fstype_is_network(const char *fstype) {
static const char table[] =
"afs\0"
@@ -1493,6 +2054,7 @@ bool fstype_is_network(const char *fstype) {
return nulstr_contains(table, fstype);
}
+#endif // 0
int flush_fd(int fd) {
struct pollfd pollfd = {
@@ -1771,6 +2333,8 @@ bool is_device_path(const char *path) {
path_startswith(path, "/sys/");
}
+/// UNNEEDED by elogind
+#if 0
int dir_is_empty(const char *path) {
_cleanup_closedir_ DIR *d;
@@ -1842,6 +2406,7 @@ void rename_process(const char name[8]) {
}
}
}
+#endif // 0
char *lookup_uid(uid_t uid) {
long bufsize;
@@ -1870,6 +2435,8 @@ char *lookup_uid(uid_t uid) {
return name;
}
+/// UNNEEDED by elogind
+#if 0
char* getlogname_malloc(void) {
uid_t uid;
struct stat st;
@@ -1891,6 +2458,7 @@ char *getusername_malloc(void) {
return lookup_uid(getuid());
}
+#endif // 0
bool is_temporary_fs(const struct statfs *s) {
assert(s);
@@ -1945,7 +2513,6 @@ int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) {
return 0;
}
-#endif // 0
cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
cpu_set_t *r;
@@ -1974,6 +2541,7 @@ cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
n *= 2;
}
}
+#endif // 0
int files_same(const char *filea, const char *fileb) {
struct stat a, b;
@@ -1988,6 +2556,8 @@ int files_same(const char *filea, const char *fileb) {
a.st_ino == b.st_ino;
}
+/// UNNEEDED by elogind
+#if 0
int running_in_chroot(void) {
int ret;
@@ -1997,6 +2567,7 @@ int running_in_chroot(void) {
return ret == 0;
}
+#endif // 0
static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
size_t x;
@@ -2480,21 +3051,6 @@ char* strshorten(char *s, size_t l) {
return s;
}
-bool machine_name_is_valid(const char *s) {
-
- if (!hostname_is_valid(s))
- return false;
-
- /* Machine names should be useful hostnames, but also be
- * useful in unit names, hence we enforce a stricter length
- * limitation. */
-
- if (strlen(s) > 64)
- return false;
-
- return true;
-}
-
int pipe_eof(int fd) {
struct pollfd pollfd = {
.fd = fd,
@@ -2554,8 +3110,9 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
f = fdopen(fd, "we");
if (!f) {
- unlink(t);
+ unlink_noerrno(t);
free(t);
+ safe_close(fd);
return -errno;
}
@@ -2565,6 +3122,8 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
return 0;
}
+/// UNNEEDED by elogind
+#if 0
int symlink_atomic(const char *from, const char *to) {
_cleanup_free_ char *t = NULL;
int r;
@@ -2587,8 +3146,6 @@ int symlink_atomic(const char *from, const char *to) {
return 0;
}
-/// UNNEEDED by elogind
-#if 0
int symlink_idempotent(const char *from, const char *to) {
_cleanup_free_ char *p = NULL;
int r;
@@ -2865,7 +3422,6 @@ int in_group(const char *name) {
return in_gid(gid);
}
-#endif // 0
int glob_exists(const char *path) {
_cleanup_globfree_ glob_t g = {};
@@ -2886,8 +3442,6 @@ int glob_exists(const char *path) {
return errno ? -errno : -EIO;
}
-/// UNNEEDED by elogind
-#if 0
int glob_extend(char ***strv, const char *path) {
_cleanup_globfree_ glob_t g = {};
int k;
@@ -3056,6 +3610,8 @@ bool is_main_thread(void) {
return cached > 0;
}
+/// UNNEEDED by elogind
+#if 0
int block_get_whole_disk(dev_t d, dev_t *ret) {
char *p, *s;
int r;
@@ -3115,6 +3671,7 @@ int block_get_whole_disk(dev_t d, dev_t *ret) {
return -ENOENT;
}
+#endif // 0
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
@@ -3245,7 +3802,7 @@ int prot_from_flags(int flags) {
return -EINVAL;
}
}
-#endif // 0
+
char *format_bytes(char *buf, size_t l, off_t t) {
unsigned i;
@@ -3284,6 +3841,7 @@ finish:
return buf;
}
+#endif // 0
void* memdup(const void *p, size_t l) {
void *r;
@@ -3435,6 +3993,8 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa
_exit(EXIT_FAILURE);
}
+/// UNNEEDED by elogind
+#if 0
int setrlimit_closest(int resource, const struct rlimit *rlim) {
struct rlimit highest, fixed;
@@ -3459,8 +4019,6 @@ int setrlimit_closest(int resource, const struct rlimit *rlim) {
return 0;
}
-/// UNNEEDED by elogind
-#if 0
bool http_etag_is_valid(const char *etag) {
if (isempty(etag))
return false;
@@ -3585,6 +4143,8 @@ int get_home_dir(char **_h) {
return 0;
}
+/// UNNEEDED by elogind
+#if 0
int get_shell(char **_s) {
struct passwd *p;
const char *e;
@@ -3631,6 +4191,7 @@ int get_shell(char **_s) {
*_s = s;
return 0;
}
+#endif // 0
bool filename_is_valid(const char *p) {
@@ -3662,7 +4223,7 @@ bool string_is_safe(const char *p) {
if (*t > 0 && *t < ' ')
return false;
- if (strchr("\\\"\'\0x7f", *t))
+ if (strchr("\\\"\'\x7f", *t))
return false;
}
@@ -3816,6 +4377,8 @@ const char *draw_special_char(DrawSpecialChar ch) {
return draw_table[!is_locale_utf8()][ch];
}
+/// UNNEEDED by elogind
+#if 0
char *strreplace(const char *text, const char *old_string, const char *new_string) {
const char *f;
char *t, *r;
@@ -4024,6 +4587,7 @@ int on_ac_power(void) {
return found_online || !found_offline;
}
+#endif // 0
static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) {
char **i;
@@ -4339,7 +4903,7 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
_cleanup_free_ char *word = NULL;
char *value = NULL;
- r = unquote_first_word(&p, &word, UNQUOTE_RELAX);
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
if (r < 0)
return r;
if (r == 0)
@@ -4379,7 +4943,7 @@ int get_proc_cmdline_key(const char *key, char **value) {
_cleanup_free_ char *word = NULL;
const char *e;
- r = unquote_first_word(&p, &word, UNQUOTE_RELAX);
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
if (r < 0)
return r;
if (r == 0)
@@ -4415,6 +4979,8 @@ int get_proc_cmdline_key(const char *key, char **value) {
}
+/// UNNEEDED by elogind
+#if 0
int container_get_leader(const char *machine, pid_t *pid) {
_cleanup_free_ char *s = NULL, *class = NULL;
const char *p;
@@ -4424,6 +4990,9 @@ int container_get_leader(const char *machine, pid_t *pid) {
assert(machine);
assert(pid);
+ if (!machine_name_is_valid(machine))
+ return -EINVAL;
+
p = strjoina("/run/systemd/machines/", machine);
r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
if (r == -ENOENT)
@@ -4445,9 +5014,10 @@ int container_get_leader(const char *machine, pid_t *pid) {
*pid = leader;
return 0;
}
+#endif // 0
-int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *root_fd) {
- _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1;
+int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
+ _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
int rfd = -1;
assert(pid >= 0);
@@ -4479,6 +5049,15 @@ int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *
return -errno;
}
+ if (userns_fd) {
+ const char *userns;
+
+ userns = procfs_file_alloca(pid, "ns/user");
+ usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+ if (usernsfd < 0 && errno != ENOENT)
+ return -errno;
+ }
+
if (root_fd) {
const char *root;
@@ -4497,15 +5076,33 @@ int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *
if (netns_fd)
*netns_fd = netnsfd;
+ if (userns_fd)
+ *userns_fd = usernsfd;
+
if (root_fd)
*root_fd = rfd;
- pidnsfd = mntnsfd = netnsfd = -1;
+ pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
return 0;
}
-int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd) {
+int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
+ if (userns_fd >= 0) {
+ /* Can't setns to your own userns, since then you could
+ * escalate from non-root to root in your own namespace, so
+ * check if namespaces equal before attempting to enter. */
+ _cleanup_free_ char *userns_fd_path = NULL;
+ int r;
+ if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
+ return -ENOMEM;
+
+ r = files_same(userns_fd_path, "/proc/self/ns/user");
+ if (r < 0)
+ return r;
+ if (r)
+ userns_fd = -1;
+ }
if (pidns_fd >= 0)
if (setns(pidns_fd, CLONE_NEWPID) < 0)
@@ -4519,6 +5116,10 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd) {
if (setns(netns_fd, CLONE_NEWNET) < 0)
return -errno;
+ if (userns_fd >= 0)
+ if (setns(userns_fd, CLONE_NEWUSER) < 0)
+ return -errno;
+
if (root_fd >= 0) {
if (fchdir(root_fd) < 0)
return -errno;
@@ -4613,6 +5214,8 @@ int mkostemp_safe(char *pattern, int flags) {
return fd;
}
+/// UNNEEDED by elogind
+#if 0
int open_tmpfile(const char *path, int flags) {
char *p;
int fd;
@@ -4636,6 +5239,7 @@ int open_tmpfile(const char *path, int flags) {
unlink(p);
return fd;
}
+#endif // 0
int fd_warn_permissions(const char *path, int fd) {
struct stat st;
@@ -4682,7 +5286,6 @@ unsigned long personality_from_string(const char *p) {
return PERSONALITY_INVALID;
}
-#endif // 0
const char* personality_to_string(unsigned long p) {
@@ -4702,6 +5305,7 @@ const char* personality_to_string(unsigned long p) {
return NULL;
}
+#endif // 0
uint64_t physical_memory(void) {
long mem;
@@ -4759,7 +5363,6 @@ void hexdump(FILE *f, const void *p, size_t s) {
s -= 16;
}
}
-#endif // 0
int update_reboot_param_file(const char *param) {
int r = 0;
@@ -5006,6 +5609,7 @@ int bind_remount_recursive(const char *prefix, bool ro) {
}
}
}
+#endif // 0
int fflush_and_check(FILE *f) {
assert(f);
@@ -5169,7 +5773,6 @@ int take_password_lock(const char *root) {
return fd;
}
-#endif // 0
int is_symlink(const char *path) {
struct stat info;
@@ -5179,6 +5782,7 @@ int is_symlink(const char *path) {
return !!S_ISLNK(info.st_mode);
}
+#endif // 0
int is_dir(const char* path, bool follow) {
struct stat st;
@@ -5206,7 +5810,7 @@ int is_device_node(const char *path) {
}
#endif // 0
-int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
+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;
@@ -5219,13 +5823,19 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
SINGLE_QUOTE_ESCAPE,
DOUBLE_QUOTE,
DOUBLE_QUOTE_ESCAPE,
- SPACE,
+ SEPARATOR,
} state = START;
assert(p);
- 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
@@ -5237,26 +5847,46 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
switch (state) {
case START:
- if (c == 0)
- goto finish;
- else if (strchr(WHITESPACE, c))
+ if (c == 0) {
+ if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
+ if (!GREEDY_REALLOC(s, allocated, sz+1))
+ return -ENOMEM;
+ goto finish_force_terminate;
+ } else if (strchr(separators, c)) {
+ if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
+ if (!GREEDY_REALLOC(s, allocated, sz+1))
+ return -ENOMEM;
+ (*p) ++;
+ goto finish_force_next;
+ }
break;
+ }
state = VALUE;
/* fallthrough */
case VALUE:
if (c == 0)
- goto finish;
- else if (c == '\'')
+ goto finish_force_terminate;
+ else if (c == '\'' && (flags & EXTRACT_QUOTES)) {
+ if (!GREEDY_REALLOC(s, allocated, sz+1))
+ return -ENOMEM;
+
state = SINGLE_QUOTE;
- else if (c == '\\')
+ } else if (c == '\\')
state = VALUE_ESCAPE;
- else if (c == '\"')
+ else if (c == '\"' && (flags & EXTRACT_QUOTES)) {
+ if (!GREEDY_REALLOC(s, allocated, sz+1))
+ return -ENOMEM;
+
state = DOUBLE_QUOTE;
- else if (strchr(WHITESPACE, c))
- state = SPACE;
- else {
+ } 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;
@@ -5267,8 +5897,8 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
case SINGLE_QUOTE:
if (c == 0) {
- if (flags & UNQUOTE_RELAX)
- goto finish;
+ if (flags & EXTRACT_RELAX)
+ goto finish_force_terminate;
return -EINVAL;
} else if (c == '\'')
state = VALUE;
@@ -5306,29 +5936,29 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
return -ENOMEM;
if (c == 0) {
- if ((flags & UNQUOTE_CUNESCAPE_RELAX) &&
- (state == VALUE_ESCAPE || flags & UNQUOTE_RELAX)) {
+ if ((flags & EXTRACT_CUNESCAPE_RELAX) &&
+ (state == VALUE_ESCAPE || flags & EXTRACT_RELAX)) {
/* If we find an unquoted trailing backslash and we're in
- * UNQUOTE_CUNESCAPE_RELAX mode, keep it verbatim in the
+ * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the
* output.
*
- * Unbalanced quotes will only be allowed in UNQUOTE_RELAX
- * mode, UNQUOTE_CUNESCAP_RELAX mode does not allow them.
+ * Unbalanced quotes will only be allowed in EXTRACT_RELAX
+ * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them.
*/
s[sz++] = '\\';
- goto finish;
+ goto finish_force_terminate;
}
- if (flags & UNQUOTE_RELAX)
- goto finish;
+ if (flags & EXTRACT_RELAX)
+ goto finish_force_terminate;
return -EINVAL;
}
- if (flags & UNQUOTE_CUNESCAPE) {
+ if (flags & EXTRACT_CUNESCAPE) {
uint32_t u;
r = cunescape_one(*p, (size_t) -1, &c, &u);
if (r < 0) {
- if (flags & UNQUOTE_CUNESCAPE_RELAX) {
+ if (flags & EXTRACT_CUNESCAPE_RELAX) {
s[sz++] = '\\';
s[sz++] = c;
goto end_escape;
@@ -5351,24 +5981,29 @@ end_escape:
VALUE;
break;
- case SPACE:
+ case SEPARATOR:
if (c == 0)
+ goto finish_force_terminate;
+ if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
+ goto finish_force_next;
+ if (!strchr(separators, c))
goto finish;
- if (!strchr(WHITESPACE, 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;
@@ -5376,26 +6011,29 @@ finish:
return 1;
}
-int unquote_first_word_and_warn(
+/// UNNEEDED by elogind
+#if 0
+int extract_first_word_and_warn(
const char **p,
char **ret,
- UnquoteFlags flags,
+ 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 UNQUOTE_CUNESCAPE_RELAX to keep the backslashes verbatim
+ * time using EXTRACT_CUNESCAPE_RELAX to keep the backslashes verbatim
* in invalid escape sequences. */
const char *save;
int r;
save = *p;
- r = unquote_first_word(p, ret, flags);
- if (r < 0 && !(flags&UNQUOTE_CUNESCAPE_RELAX)) {
- /* Retry it with UNQUOTE_CUNESCAPE_RELAX. */
+ r = extract_first_word(p, ret, separators, flags);
+ if (r < 0 && !(flags&EXTRACT_CUNESCAPE_RELAX)) {
+ /* Retry it with EXTRACT_CUNESCAPE_RELAX. */
*p = save;
- r = unquote_first_word(p, ret, flags|UNQUOTE_CUNESCAPE_RELAX);
+ r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX);
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"Unbalanced quoting in command line, ignoring: \"%s\"", rvalue);
@@ -5406,9 +6044,7 @@ int unquote_first_word_and_warn(
return r;
}
-/// UNNEEDED by elogind
-#if 0
-int unquote_many_words(const char **p, UnquoteFlags flags, ...) {
+int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) {
va_list ap;
char **l;
int n = 0, i, c, r;
@@ -5434,7 +6070,7 @@ int unquote_many_words(const char **p, UnquoteFlags flags, ...) {
l = newa0(char*, n);
for (c = 0; c < n; c++) {
- r = unquote_first_word(p, &l[c], flags);
+ r = extract_first_word(p, &l[c], separators, flags);
if (r < 0) {
int j;
@@ -5489,6 +6125,8 @@ int free_and_strdup(char **p, const char *s) {
return 1;
}
+/// UNNEEDED by elogind
+#if 0
int ptsname_malloc(int fd, char **ret) {
size_t l = 100;
@@ -5516,10 +6154,8 @@ int ptsname_malloc(int fd, char **ret) {
}
}
-/// UNNEEDED by elogind
-#if 0
int openpt_in_namespace(pid_t pid, int flags) {
- _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
+ _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
_cleanup_close_pair_ int pair[2] = { -1, -1 };
union {
struct cmsghdr cmsghdr;
@@ -5536,7 +6172,7 @@ int openpt_in_namespace(pid_t pid, int flags) {
assert(pid > 0);
- r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd);
+ r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
if (r < 0)
return r;
@@ -5552,7 +6188,7 @@ int openpt_in_namespace(pid_t pid, int flags) {
pair[0] = safe_close(pair[0]);
- r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
+ r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
if (r < 0)
_exit(EXIT_FAILURE);
@@ -5654,6 +6290,8 @@ int fd_getcrtime(int fd, usec_t *usec) {
return parse_crtime(le, usec);
}
+/// UNNEEDED by elogind
+#if 0
int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags) {
le64_t le;
ssize_t n;
@@ -5667,8 +6305,6 @@ int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags) {
return parse_crtime(le, usec);
}
-/// UNNEEDED by elogind
-#if 0
int path_getcrtime(const char *p, usec_t *usec) {
le64_t le;
ssize_t n;
@@ -5684,7 +6320,6 @@ int path_getcrtime(const char *p, usec_t *usec) {
return parse_crtime(le, usec);
}
-#endif // 0
int fd_setcrtime(int fd, usec_t usec) {
le64_t le;
@@ -5765,6 +6400,7 @@ int same_fd(int a, int b) {
return fa == fb;
}
+#endif // 0
int chattr_fd(int fd, unsigned value, unsigned mask) {
unsigned old_attr, new_attr;
@@ -5800,6 +6436,8 @@ int chattr_fd(int fd, unsigned value, unsigned mask) {
return 1;
}
+/// UNNEEDED by elogind
+#if 0
int chattr_path(const char *p, unsigned value, unsigned mask) {
_cleanup_close_ int fd = -1;
@@ -5814,6 +6452,7 @@ int chattr_path(const char *p, unsigned value, unsigned mask) {
return chattr_fd(fd, value, mask);
}
+#endif // 0
int read_attr_fd(int fd, unsigned *ret) {
struct stat st;
@@ -5832,6 +6471,8 @@ int read_attr_fd(int fd, unsigned *ret) {
return 0;
}
+/// UNNEEDED by elogind
+#if 0
int read_attr_path(const char *p, unsigned *ret) {
_cleanup_close_ int fd = -1;
@@ -5845,8 +6486,6 @@ int read_attr_path(const char *p, unsigned *ret) {
return read_attr_fd(fd, ret);
}
-/// UNNEEDED by elogind
-#if 0
static size_t nul_length(const uint8_t *p, size_t sz) {
size_t n = 0;
@@ -5978,6 +6617,8 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
return -1;
}
+/// UNNEEDED by elogind
+#if 0
void cmsg_close_all(struct msghdr *mh) {
struct cmsghdr *cmsg;
@@ -5996,10 +6637,9 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
if (ret >= 0)
return 0;
- /* Even though renameat2() exists since Linux 3.15, btrfs added
- * support for it later. If it is not implemented, fallback to another
- * method. */
- if (errno != EINVAL)
+ /* renameat2() exists since Linux 3.15, btrfs added support for it later.
+ * If it is not implemented, fallback to another method. */
+ if (!IN_SET(errno, EINVAL, ENOSYS))
return -errno;
/* The link()/unlink() fallback does not work on directories. But
@@ -6028,6 +6668,33 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
return 0;
}
+#endif // 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;
@@ -6055,13 +6722,7 @@ char *shell_maybe_quote(const char *s) {
*(t++) = '"';
t = mempcpy(t, s, p - s);
- for (; *p; p++) {
-
- if (strchr(SHELL_NEED_ESCAPE, *p))
- *(t++) = '\\';
-
- *(t++) = *p;
- }
+ t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE);
*(t++)= '"';
*t = 0;
@@ -6090,6 +6751,8 @@ int parse_mode(const char *s, mode_t *ret) {
return 0;
}
+/// UNNEEDED by elogind
+#if 0
int mount_move_root(const char *path) {
assert(path);
@@ -6107,6 +6770,7 @@ int mount_move_root(const char *path) {
return 0;
}
+#endif // 0
int reset_uid_gid(void) {
@@ -6121,3 +6785,73 @@ int reset_uid_gid(void) {
return 0;
}
+
+int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink) {
+ char *v;
+ size_t l;
+ ssize_t n;
+
+ assert(path);
+ assert(name);
+ assert(value);
+
+ for (l = 100; ; l = (size_t) n + 1) {
+ v = new0(char, l);
+ if (!v)
+ return -ENOMEM;
+
+ if (allow_symlink)
+ n = lgetxattr(path, name, v, l);
+ else
+ n = getxattr(path, name, v, l);
+
+ if (n >= 0 && (size_t) n < l) {
+ *value = v;
+ return n;
+ }
+
+ free(v);
+
+ if (n < 0 && errno != ERANGE)
+ return -errno;
+
+ if (allow_symlink)
+ n = lgetxattr(path, name, NULL, 0);
+ else
+ n = getxattr(path, name, NULL, 0);
+ if (n < 0)
+ return -errno;
+ }
+}
+
+int fgetxattr_malloc(int fd, const char *name, char **value) {
+ char *v;
+ size_t l;
+ ssize_t n;
+
+ assert(fd >= 0);
+ assert(name);
+ assert(value);
+
+ for (l = 100; ; l = (size_t) n + 1) {
+ v = new0(char, l);
+ if (!v)
+ return -ENOMEM;
+
+ n = fgetxattr(fd, name, v, l);
+
+ if (n >= 0 && (size_t) n < l) {
+ *value = v;
+ return n;
+ }
+
+ free(v);
+
+ if (n < 0 && errno != ERANGE)
+ return -errno;
+
+ n = fgetxattr(fd, name, NULL, 0);
+ if (n < 0)
+ return -errno;
+ }
+}