#include <langinfo.h>
#include <locale.h>
#include <libgen.h>
+#undef basename
#include "macro.h"
#include "util.h"
static volatile unsigned cached_lines = 0;
size_t page_size(void) {
- static __thread size_t pgsz = 0;
+ static thread_local size_t pgsz = 0;
long r;
if (_likely_(pgsz > 0))
/* Split a string into words, but consider strings enclosed in '' and
* "" as words even if they include spaces. */
char *split_quoted(const char *c, size_t *l, char **state) {
- char *current, *e;
+ const char *current, *e;
bool escaped = false;
- current = *state ? *state : (char*) c;
+ assert(c);
+ assert(l);
+ assert(state);
- if (!*current || *c == 0)
- return NULL;
+ current = *state ? *state : c;
current += strspn(current, WHITESPACE);
- if (*current == '\'') {
+ if (*current == 0)
+ return NULL;
+
+ else if (*current == '\'') {
current ++;
for (e = current; *e; e++) {
}
*l = e-current;
- *state = *e == 0 ? e : e+1;
+ *state = (char*) (*e == 0 ? e : e+1);
+
} else if (*current == '\"') {
current ++;
}
*l = e-current;
- *state = *e == 0 ? e : e+1;
+ *state = (char*) (*e == 0 ? e : e+1);
+
} else {
for (e = current; *e; e++) {
if (escaped)
break;
}
*l = e-current;
- *state = e;
+ *state = (char*) e;
}
return (char*) current;
f = fopen(p, "re");
if (!f)
- return -errno;
+ return errno == ENOENT ? -ESRCH : -errno;
if (!fgets(line, sizeof(line), f)) {
if (ferror(f))
int get_process_comm(pid_t pid, char **name) {
const char *p;
+ int r;
assert(name);
assert(pid >= 0);
else
p = procfs_file_alloca(pid, "comm");
- return read_one_line_file(p, name);
+ r = read_one_line_file(p, name);
+ if (r == -ENOENT)
+ return -ESRCH;
+
+ return r;
}
int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) {
r = readlink_malloc(p, name);
if (r < 0)
- return r;
+ return r == -ENOENT ? -ESRCH : r;
d = endswith(*name, " (deleted)");
if (d)
int dir_is_empty(const char *path) {
_cleanup_closedir_ DIR *d;
- int r;
d = opendir(path);
if (!d)
for (;;) {
struct dirent *de;
- union dirent_storage buf;
- r = readdir_r(d, &buf.de, &de);
- if (r > 0)
- return -r;
+ errno = 0;
+ de = readdir(d);
+ if (!de && errno != 0)
+ return -errno;
if (!de)
return 1;
assert(r);
k = ttyname_r(fd, path, sizeof(path));
- if (k != 0)
+ if (k > 0)
return -k;
char_array_0(path);
for (;;) {
struct dirent *de;
- union dirent_storage buf;
bool is_dir, keep_around;
struct stat st;
int r;
- r = readdir_r(d, &buf.de, &de);
- if (r != 0 && ret == 0) {
- ret = -r;
+ errno = 0;
+ de = readdir(d);
+ if (!de && errno != 0) {
+ if (ret == 0)
+ ret = -errno;
break;
}
_pure_ static int is_temporary_fs(struct statfs *s) {
assert(s);
- return
- F_TYPE_EQUAL(s->f_type, TMPFS_MAGIC) ||
- F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC);
+
+ return F_TYPE_EQUAL(s->f_type, TMPFS_MAGIC) ||
+ F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC);
}
int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) {
return -EPROTO;
}
-_noreturn_ void freeze(void) {
+noreturn void freeze(void) {
/* Make sure nobody waits for us on a socket anymore */
close_all_fds(NULL, 0);
if (!t)
return -ENOMEM;
- fn = path_get_file_name(path);
- k = fn-path;
+ fn = basename(path);
+ k = fn - path;
memcpy(t, path, k);
t[k] = '.';
stpcpy(stpcpy(t+k+1, fn), "XXXXXX");
if (!t)
return -ENOMEM;
- fn = path_get_file_name(to);
+ fn = basename(to);
k = fn-to;
memcpy(t, to, k);
t[k] = '.';
for (;;) {
struct dirent *de;
- union dirent_storage buf;
- int k;
- k = readdir_r(d, &buf.de, &de);
- assert(k >= 0);
- if (k > 0)
- return -k;
+ errno = 0;
+ de = readdir(d);
+ if (!de && errno != 0)
+ return -errno;
if (!de)
break;
}
bool is_main_thread(void) {
- static __thread int cached = 0;
+ static thread_local int cached = 0;
if (_unlikely_(cached == 0))
cached = getpid() == gettid() ? 1 : -1;
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int);
const char *signal_to_string(int signo) {
- static __thread char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1];
+ static thread_local char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1];
const char *name;
name = __signal_to_string(signo);
socklen_t l = sizeof(value);
r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
- if (r >= 0 &&
- l == sizeof(value) &&
- (size_t) value >= n*2)
+ if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
return 0;
+ /* If we have the privileges we will ignore the kernel limit. */
+
value = (int) n;
- r = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value));
- if (r < 0)
- return -errno;
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
+ return -errno;
return 1;
}
socklen_t l = sizeof(value);
r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l);
- if (r >= 0 &&
- l == sizeof(value) &&
- (size_t) value >= n*2)
+ if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
return 0;
- value = (int) n;
- r = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value));
- if (r < 0)
- return -errno;
+ /* If we have the privileges we will ignore the kernel limit. */
+ value = (int) n;
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0)
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0)
+ return -errno;
return 1;
}
}
bool in_initrd(void) {
- static __thread int saved = -1;
+ static int saved = -1;
struct statfs s;
if (saved >= 0)
}
int get_home_dir(char **_h) {
- char *h;
+ struct passwd *p;
const char *e;
+ char *h;
uid_t u;
- struct passwd *p;
assert(_h);
return 0;
}
+int get_shell(char **_s) {
+ struct passwd *p;
+ const char *e;
+ char *s;
+ uid_t u;
+
+ assert(_s);
+
+ /* Take the user specified one */
+ e = getenv("SHELL");
+ if (e) {
+ s = strdup(e);
+ if (!s)
+ return -ENOMEM;
+
+ *_s = s;
+ return 0;
+ }
+
+ /* Hardcode home directory for root to avoid NSS */
+ u = getuid();
+ if (u == 0) {
+ s = strdup("/bin/sh");
+ if (!s)
+ return -ENOMEM;
+
+ *_s = s;
+ return 0;
+ }
+
+ /* Check the database... */
+ errno = 0;
+ p = getpwuid(u);
+ if (!p)
+ return errno > 0 ? -errno : -ESRCH;
+
+ if (!path_is_absolute(p->pw_shell))
+ return -EINVAL;
+
+ s = strdup(p->pw_shell);
+ if (!s)
+ return -ENOMEM;
+
+ *_s = s;
+ return 0;
+}
+
bool filename_is_safe(const char *p) {
if (isempty(p))
goto out;
}
- if(streq(set, "UTF-8")) {
+ if (streq(set, "UTF-8")) {
cached_answer = true;
goto out;
}
for (;;) {
struct dirent *de;
- union dirent_storage buf;
_cleanup_close_ int fd = -1, device = -1;
char contents[6];
ssize_t n;
- int k;
- k = readdir_r(d, &buf.de, &de);
- if (k != 0)
- return -k;
+ errno = 0;
+ de = readdir(d);
+ if (!de && errno != 0)
+ return -errno;
if (!de)
break;
return search_and_fopen_internal(path, mode, s, _f);
}
-int create_tmp_dir(char template[], char** dir_name) {
- int r = 0;
- char *d = NULL, *dt;
-
- assert(dir_name);
-
- RUN_WITH_UMASK(0077) {
- d = mkdtemp(template);
- }
- if (!d) {
- log_error("Can't create directory %s: %m", template);
- return -errno;
- }
-
- dt = strjoin(d, "/tmp", NULL);
- if (!dt) {
- r = log_oom();
- goto fail3;
- }
-
- RUN_WITH_UMASK(0000) {
- r = mkdir(dt, 0777);
- }
- if (r < 0) {
- log_error("Can't create directory %s: %m", dt);
- r = -errno;
- goto fail2;
- }
- log_debug("Created temporary directory %s", dt);
-
- r = chmod(dt, 0777 | S_ISVTX);
- if (r < 0) {
- log_error("Failed to chmod %s: %m", dt);
- r = -errno;
- goto fail1;
- }
- log_debug("Set sticky bit on %s", dt);
-
- *dir_name = dt;
-
- return 0;
-fail1:
- rmdir(dt);
-fail2:
- free(dt);
-fail3:
- rmdir(template);
- return r;
-}
-
char *strextend(char **x, ...) {
va_list ap;
size_t f, l;
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;
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;
return 1;
FOREACH_WORD_QUOTED(w, l, line, state)
- if (l == 23 && memcmp(w, "systemd.restore_state=0", 23))
+ if (l == 23 && strneq(w, "systemd.restore_state=0", 23))
return 0;
return 1;
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 *pidns_fd, int *mntns_fd, int *root_fd) {
+ _cleanup_close_ int pidnsfd = -1, mntnsfd = -1;
+ const char *pidns, *mntns, *root;
+ int rfd;
+
+ assert(pid >= 0);
+ assert(pidns_fd);
+ assert(mntns_fd);
+ assert(root_fd);
+
+ mntns = procfs_file_alloca(pid, "ns/mnt");
+ mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+ if (mntnsfd < 0)
+ return -errno;
+
+ pidns = procfs_file_alloca(pid, "ns/pid");
+ pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+ if (pidnsfd < 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;
+
+ *pidns_fd = pidnsfd;
+ *mntns_fd = mntnsfd;
+ *root_fd = rfd;
+ pidnsfd = -1;
+ mntnsfd = -1;
+
+ return 0;
+}
+
+int namespace_enter(int pidns_fd, int mntns_fd, int root_fd) {
+ assert(pidns_fd >= 0);
+ assert(mntns_fd >= 0);
+ assert(root_fd >= 0);
+
+ if (setns(pidns_fd, CLONE_NEWPID) < 0)
+ return -errno;
+
+ if (setns(mntns_fd, CLONE_NEWNS) < 0)
+ return -errno;
+
+ if (fchdir(root_fd) < 0)
+ return -errno;
+
+ if (chroot(".") < 0)
+ return -errno;
+
+ if (setresgid(0, 0, 0) < 0)
+ return -errno;
+
+ if (setresuid(0, 0, 0) < 0)
+ return -errno;
+
+ return 0;
+}
+
+bool pid_valid(pid_t pid) {
+ if (pid <= 0)
+ return false;
+
+ if (kill(pid, 0) >= 0)
+ return true;
+
+ return errno != ESRCH;
+}