+
+void* greedy_realloc(void **p, size_t *allocated, size_t need) {
+ size_t a;
+ void *q;
+
+ assert(p);
+ assert(allocated);
+
+ if (*allocated >= need)
+ return *p;
+
+ a = MAX(64u, need * 2);
+
+ /* check for overflows */
+ if (a < need)
+ return NULL;
+
+ q = realloc(*p, a);
+ if (!q)
+ return NULL;
+
+ *p = q;
+ *allocated = a;
+ return q;
+}
+
+void* greedy_realloc0(void **p, size_t *allocated, size_t need) {
+ size_t prev;
+ uint8_t *q;
+
+ assert(p);
+ assert(allocated);
+
+ prev = *allocated;
+
+ q = greedy_realloc(p, allocated, need);
+ if (!q)
+ return NULL;
+
+ if (*allocated > prev)
+ memset(&q[prev], 0, *allocated - prev);
+
+ return q;
+}
+
+bool id128_is_valid(const char *s) {
+ size_t i, l;
+
+ l = strlen(s);
+ if (l == 32) {
+
+ /* Simple formatted 128bit hex string */
+
+ for (i = 0; i < l; i++) {
+ char c = s[i];
+
+ if (!(c >= '0' && c <= '9') &&
+ !(c >= 'a' && c <= 'z') &&
+ !(c >= 'A' && c <= 'Z'))
+ return false;
+ }
+
+ } else if (l == 36) {
+
+ /* Formatted UUID */
+
+ for (i = 0; i < l; i++) {
+ char c = s[i];
+
+ if ((i == 8 || i == 13 || i == 18 || i == 23)) {
+ if (c != '-')
+ return false;
+ } else {
+ if (!(c >= '0' && c <= '9') &&
+ !(c >= 'a' && c <= 'z') &&
+ !(c >= 'A' && c <= 'Z'))
+ return false;
+ }
+ }
+
+ } else
+ return false;
+
+ return true;
+}
+
+void parse_user_at_host(char *arg, char **user, char **host) {
+ assert(arg);
+ assert(user);
+ assert(host);
+
+ *host = strchr(arg, '@');
+ if (*host == NULL)
+ *host = arg;
+ else {
+ *host[0]++ = '\0';
+ *user = arg;
+ }
+}
+
+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 *line;
+ char *w, *state;
+ size_t l;
+ int r;
+
+ r = proc_cmdline(&line);
+ if (r < 0)
+ return r;
+ if (r == 0) /* Container ... */
+ return 1;
+
+ FOREACH_WORD_QUOTED(w, l, line, state)
+ if (l == 23 && strneq(w, "systemd.restore_state=0", 23))
+ return 0;
+
+ return 1;
+}
+
+int proc_cmdline(char **ret) {
+ int r;
+
+ if (detect_container(NULL) > 0) {
+ *ret = NULL;
+ return 0;
+ }
+
+ r = read_one_line_file("/proc/cmdline", ret);
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
+int container_get_leader(const char *machine, pid_t *pid) {
+ _cleanup_free_ char *s = NULL, *class = NULL;
+ const char *p;
+ pid_t leader;
+ int r;
+
+ assert(machine);
+ assert(pid);
+
+ p = strappenda("/run/systemd/machines/", machine);
+ r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
+ if (r == -ENOENT)
+ return -EHOSTDOWN;
+ if (r < 0)
+ return r;
+ if (!s)
+ return -EIO;
+
+ if (!streq_ptr(class, "container"))
+ return -EIO;
+
+ r = parse_pid(s, &leader);
+ if (r < 0)
+ return r;
+ if (leader <= 1)
+ return -EIO;
+
+ *pid = leader;
+ return 0;
+}
+
+int namespace_open(pid_t pid, int *namespace_fd, int *root_fd) {
+ _cleanup_close_ int nsfd = -1;
+ const char *ns, *root;
+ int rfd;
+
+ assert(pid >= 0);
+ assert(namespace_fd);
+ assert(root_fd);
+
+ ns = procfs_file_alloca(pid, "ns/mnt");
+ nsfd = open(ns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+ if (nsfd < 0)
+ return -errno;
+
+ root = procfs_file_alloca(pid, "root");
+ rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+ if (rfd < 0)
+ return -errno;
+
+ *namespace_fd = nsfd;
+ *root_fd = rfd;
+ nsfd = -1;
+
+ return 0;
+}
+
+int namespace_enter(int namespace_fd, int root_fd) {
+ assert(namespace_fd >= 0);
+ assert(root_fd >= 0);
+
+ if (setns(namespace_fd, CLONE_NEWNS) < 0)
+ return -errno;
+
+ if (fchdir(root_fd) < 0)
+ return -errno;
+
+ if (chroot(".") < 0)
+ return -errno;
+
+ return 0;
+}