return (char*) p;
}
+static 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 get_status_field(p, "\nCapEff:", capeff);
}
+static int get_process_link_contents(const char *proc_file, char **name) {
+ int r;
+
+ assert(proc_file);
+ assert(name);
+
+ r = readlink_malloc(proc_file, name);
+ if (r < 0)
+ return r == -ENOENT ? -ESRCH : r;
+
+ return 0;
+}
+
int get_process_exe(pid_t pid, char **name) {
const char *p;
char *d;
int r;
assert(pid >= 0);
- assert(name);
p = procfs_file_alloca(pid, "exe");
-
- r = readlink_malloc(p, name);
+ r = get_process_link_contents(p, name);
if (r < 0)
- return r == -ENOENT ? -ESRCH : r;
+ return r;
d = endswith(*name, " (deleted)");
if (d)
return get_process_id(pid, "Gid:", gid);
}
+int get_process_cwd(pid_t pid, char **cwd) {
+ const char *p;
+
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "cwd");
+
+ return get_process_link_contents(p, cwd);
+}
+
+int get_process_root(pid_t pid, char **root) {
+ const char *p;
+
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "root");
+
+ return get_process_link_contents(p, root);
+}
+
+int get_process_environ(pid_t pid, char **environ) {
+ _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_free_ char *outcome = NULL;
+ int c;
+ const char *p;
+ size_t allocated = 0, sz = 0;
+
+ assert(pid >= 0);
+ assert(environ);
+
+ p = procfs_file_alloca(pid, "environ");
+
+ f = fopen(p, "re");
+ if (!f)
+ return -errno;
+
+ while ((c = fgetc(f)) != EOF) {
+ if (!GREEDY_REALLOC(outcome, allocated, sz + 5))
+ return -ENOMEM;
+
+ if (c == '\0')
+ outcome[sz++] = '\n';
+ else
+ sz += cescape_char(c, outcome + sz);
+ }
+
+ outcome[sz] = '\0';
+ *environ = outcome;
+ outcome = NULL;
+
+ return 0;
+}
+
char *strnappend(const char *s, const char *suffix, size_t b) {
size_t a;
char *r;
return NULL;
for (f = s, t = r; *f; f++)
-
- switch (*f) {
-
- case '\a':
- *(t++) = '\\';
- *(t++) = 'a';
- break;
- case '\b':
- *(t++) = '\\';
- *(t++) = 'b';
- break;
- case '\f':
- *(t++) = '\\';
- *(t++) = 'f';
- break;
- case '\n':
- *(t++) = '\\';
- *(t++) = 'n';
- break;
- case '\r':
- *(t++) = '\\';
- *(t++) = 'r';
- break;
- case '\t':
- *(t++) = '\\';
- *(t++) = 't';
- break;
- case '\v':
- *(t++) = '\\';
- *(t++) = 'v';
- break;
- case '\\':
- *(t++) = '\\';
- *(t++) = '\\';
- break;
- case '"':
- *(t++) = '\\';
- *(t++) = '"';
- break;
- case '\'':
- *(t++) = '\\';
- *(t++) = '\'';
- break;
-
- default:
- /* For special chars we prefer octal over
- * hexadecimal encoding, simply because glib's
- * g_strescape() does the same */
- if ((*f < ' ') || (*f >= 127)) {
- *(t++) = '\\';
- *(t++) = octchar((unsigned char) *f >> 6);
- *(t++) = octchar((unsigned char) *f >> 3);
- *(t++) = octchar((unsigned char) *f);
- } else
- *(t++) = *f;
- break;
- }
+ t += cescape_char(*f, t);
*t = 0;
r = reset_terminal_fd(fd, true);
if (r < 0)
- log_warning("Failed to reset terminal: %s", strerror(-r));
+ log_warning_errno(r, "Failed to reset terminal: %m");
return fd;
assert(pid > 1);
r = wait_for_terminate(pid, &status);
- if (r < 0) {
- log_warning("Failed to wait for %s: %s", name, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_warning_errno(r, "Failed to wait for %s: %m", name);
if (status.si_code == CLD_EXITED) {
if (status.si_status != 0) {
executor_pid = fork();
if (executor_pid < 0) {
- log_error("Failed to fork: %m");
+ log_error_errno(errno, "Failed to fork: %m");
return;
} else if (executor_pid == 0) {
if (errno == ENOENT)
_exit(EXIT_SUCCESS);
- log_error("Failed to enumerate directory %s: %m", directory);
+ log_error_errno(errno, "Failed to enumerate directory %s: %m", directory);
_exit(EXIT_FAILURE);
}
}
pid = fork();
if (pid < 0) {
- log_error("Failed to fork: %m");
+ log_error_errno(errno, "Failed to fork: %m");
continue;
} else if (pid == 0) {
char *_argv[2];
argv[0] = path;
execv(path, argv);
- log_error("Failed to execute %s: %m", path);
+ log_error_errno(errno, "Failed to execute %s: %m", path);
_exit(EXIT_FAILURE);
}
* keep an unused copy of stdin around. */
fd = open("/dev/tty", O_WRONLY);
if (fd < 0) {
- log_error("Failed to open /dev/tty: %m");
+ log_error_errno(errno, "Failed to open /dev/tty: %m");
_exit(EXIT_FAILURE);
}
/* Make /dev/console the controlling terminal and stdin/stdout/stderr */
fd = acquire_terminal("/dev/console", false, true, true, USEC_INFINITY);
- if (fd < 0) {
- log_error("Failed to acquire terminal: %s", strerror(-fd));
- return fd;
- }
+ if (fd < 0)
+ return log_error_errno(fd, "Failed to acquire terminal: %m");
r = make_stdio(fd);
- if (r < 0) {
- log_error("Failed to duplicate terminal fd: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to duplicate terminal fd: %m");
return 0;
}
}
int shall_restore_state(void) {
- _cleanup_free_ char *line = NULL;
- const char *p;
+ _cleanup_free_ char *value = NULL;
int r;
- r = proc_cmdline(&line);
+ r = get_proc_cmdline_key("systemd.restore_state=", &value);
if (r < 0)
return r;
+ if (r == 0)
+ return true;
- r = 1;
- p = line;
-
- for (;;) {
- _cleanup_free_ char *word = NULL;
- const char *e;
- int k;
-
- k = unquote_first_word(&p, &word, true);
- if (k < 0)
- return k;
- if (k == 0)
- break;
-
- e = startswith(word, "systemd.restore_state=");
- if (!e)
- continue;
-
- k = parse_boolean(e);
- if (k >= 0)
- r = k;
- }
-
- return r;
+ return parse_boolean(value) != 0;
}
int proc_cmdline(char **ret) {
return 0;
}
+int get_proc_cmdline_key(const char *key, char **value) {
+ _cleanup_free_ char *line = NULL, *ret = NULL;
+ bool found = false;
+ const char *p;
+ int r;
+
+ assert(key);
+
+ r = proc_cmdline(&line);
+ if (r < 0)
+ return r;
+
+ p = line;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+ const char *e;
+
+ r = unquote_first_word(&p, &word, true);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ /* Filter out arguments that are intended only for the
+ * initrd */
+ if (!in_initrd() && startswith(word, "rd."))
+ continue;
+
+ if (value) {
+ e = startswith(word, key);
+ if (!e)
+ continue;
+
+ r = free_and_strdup(&ret, e);
+ if (r < 0)
+ return r;
+
+ found = true;
+ } else {
+ if (streq(word, key))
+ found = true;
+ }
+ }
+
+ if (value) {
+ *value = ret;
+ ret = NULL;
+ }
+
+ return found;
+
+}
+
int container_get_leader(const char *machine, pid_t *pid) {
_cleanup_free_ char *s = NULL, *class = NULL;
const char *p;
* to namespacing issues */
if (u.pid <= 0)
return -ENODATA;
+ if (u.uid == (uid_t) -1)
+ return -ENODATA;
+ if (u.gid == (gid_t) -1)
+ return -ENODATA;
*ucred = u;
return 0;