summaryrefslogtreecommitdiff
path: root/src/shared
diff options
context:
space:
mode:
authorRonny Chevalier <chevalier.ronny@gmail.com>2015-04-10 20:43:52 +0200
committerSven Eden <yamakuzure@gmx.net>2017-03-14 08:02:36 +0100
commit01c94c5d0aff09b4c0e429d483c8eeba40017071 (patch)
treea538badab62aa338c24809ebeb75ecf47d476a4f /src/shared
parentd6a6c7157af1ce285962f98f006a3f05bb7c11ef (diff)
shared: add formats-util.h
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/ask-password-api.c1
-rw-r--r--src/shared/cgroup-show.c1
-rw-r--r--src/shared/cgroup-util.c1
-rw-r--r--src/shared/clean-ipc.c1
-rw-r--r--src/shared/formats-util.h63
-rw-r--r--src/shared/install-printf.c1
-rw-r--r--src/shared/log.c1
-rw-r--r--src/shared/logs-show.c1
-rw-r--r--src/shared/mkdir-label.c35
-rw-r--r--src/shared/socket-util.c1
-rw-r--r--src/shared/util.c507
-rw-r--r--src/shared/util.h42
12 files changed, 596 insertions, 59 deletions
diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c
index 44ebc5849..dfc89d23f 100644
--- a/src/shared/ask-password-api.c
+++ b/src/shared/ask-password-api.c
@@ -32,6 +32,7 @@
#include <sys/signalfd.h>
#include "util.h"
+#include "formats-util.h"
#include "mkdir.h"
#include "strv.h"
diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c
index 0f263e958..fed72ac17 100644
--- a/src/shared/cgroup-show.c
+++ b/src/shared/cgroup-show.c
@@ -26,7 +26,6 @@
#include "util.h"
#include "formats-util.h"
-#include "process-util.h"
#include "macro.h"
#include "path-util.h"
#include "cgroup-util.h"
diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c
index 63166a3a9..c746d606d 100644
--- a/src/shared/cgroup-util.c
+++ b/src/shared/cgroup-util.c
@@ -34,7 +34,6 @@
#include "macro.h"
#include "util.h"
#include "formats-util.h"
-#include "process-util.h"
#include "path-util.h"
#include "fileio.h"
#include "special.h"
diff --git a/src/shared/clean-ipc.c b/src/shared/clean-ipc.c
index ea781f5de..48b10865d 100644
--- a/src/shared/clean-ipc.c
+++ b/src/shared/clean-ipc.c
@@ -29,6 +29,7 @@
#include <mqueue.h>
#include "util.h"
+#include "formats-util.h"
#include "strv.h"
#include "clean-ipc.h"
diff --git a/src/shared/formats-util.h b/src/shared/formats-util.h
new file mode 100644
index 000000000..ce516b117
--- /dev/null
+++ b/src/shared/formats-util.h
@@ -0,0 +1,63 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Ronny Chevalier
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <inttypes.h>
+
+#if SIZEOF_PID_T == 4
+# define PID_PRI PRIi32
+#elif SIZEOF_PID_T == 2
+# define PID_PRI PRIi16
+#else
+# error Unknown pid_t size
+#endif
+#define PID_FMT "%" PID_PRI
+
+#if SIZEOF_UID_T == 4
+# define UID_FMT "%" PRIu32
+#elif SIZEOF_UID_T == 2
+# define UID_FMT "%" PRIu16
+#else
+# error Unknown uid_t size
+#endif
+
+#if SIZEOF_GID_T == 4
+# define GID_FMT "%" PRIu32
+#elif SIZEOF_GID_T == 2
+# define GID_FMT "%" PRIu16
+#else
+# error Unknown gid_t size
+#endif
+
+#if SIZEOF_TIME_T == 8
+# define PRI_TIME PRIi64
+#elif SIZEOF_TIME_T == 4
+# define PRI_TIME PRIu32
+#else
+# error Unknown time_t size
+#endif
+
+#if SIZEOF_RLIM_T == 8
+# define RLIM_FMT "%" PRIu64
+#elif SIZEOF_RLIM_T == 4
+# define RLIM_FMT "%" PRIu32
+#else
+# error Unknown rlim_t size
+#endif
diff --git a/src/shared/install-printf.c b/src/shared/install-printf.c
index f62a0321e..999664942 100644
--- a/src/shared/install-printf.c
+++ b/src/shared/install-printf.c
@@ -25,6 +25,7 @@
#include "unit-name.h"
#include "util.h"
#include "install-printf.h"
+#include "formats-util.h"
static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) {
InstallInfo *i = userdata;
diff --git a/src/shared/log.c b/src/shared/log.c
index 7edcf1f18..32ec581d8 100644
--- a/src/shared/log.c
+++ b/src/shared/log.c
@@ -35,7 +35,6 @@
#include "macro.h"
#include "socket-util.h"
#include "formats-util.h"
-#include "process-util.h"
#define SNDBUF_SIZE (8*1024*1024)
diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c
index 7a7a1e934..e179b8a7b 100644
--- a/src/shared/logs-show.c
+++ b/src/shared/logs-show.c
@@ -32,7 +32,6 @@
#include "hashmap.h"
#include "journal-internal.h"
#include "formats-util.h"
-#include "process-util.h"
/* up to three lines (each up to 100 characters),
or 300 characters, whichever is less */
diff --git a/src/shared/mkdir-label.c b/src/shared/mkdir-label.c
index 76bbc1edd..221dd67eb 100644
--- a/src/shared/mkdir-label.c
+++ b/src/shared/mkdir-label.c
@@ -3,8 +3,7 @@
/***
This file is part of systemd.
- Copyright 2010 Lennart Poettering
- Copyright 2013 Kay Sievers
+ Copyright 2014 Zbigniew Jędrzejewski-Szmek
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -20,20 +19,32 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <fcntl.h>
#include <unistd.h>
+#include <stdlib.h>
#include <stdio.h>
-#include "label.h"
-#include "mkdir.h"
+#include "util.h"
+#include "formats-util.h"
-int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid) {
- return mkdir_safe_internal(path, mode, uid, gid, mkdir_label);
-}
+int main(int argc, char** argv) {
+ const char *p = argv[1] ?: "/tmp";
+ char *pattern = strjoina(p, "/systemd-test-XXXXXX");
+ _cleanup_close_ int fd, fd2;
+ _cleanup_free_ char *cmd, *cmd2;
-int mkdir_parents_label(const char *path, mode_t mode) {
- return mkdir_parents_internal(NULL, path, mode, mkdir_label);
-}
+ fd = open_tmpfile(p, O_RDWR|O_CLOEXEC);
+ assert_se(fd >= 0);
+
+ assert_se(asprintf(&cmd, "ls -l /proc/"PID_FMT"/fd/%d", getpid(), fd) > 0);
+ system(cmd);
+
+ fd2 = mkostemp_safe(pattern, O_RDWR|O_CLOEXEC);
+ assert_se(fd >= 0);
+ assert_se(unlink(pattern) == 0);
+
+ assert_se(asprintf(&cmd2, "ls -l /proc/"PID_FMT"/fd/%d", getpid(), fd2) > 0);
+ system(cmd2);
-int mkdir_p_label(const char *path, mode_t mode) {
- return mkdir_p_internal(NULL, path, mode, mkdir_label);
+ return 0;
}
diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c
index 4a6bf50b1..94a066334 100644
--- a/src/shared/socket-util.c
+++ b/src/shared/socket-util.c
@@ -35,6 +35,7 @@
#include "socket-util.h"
#include "missing.h"
#include "fileio.h"
+#include "formats-util.h"
int socket_address_parse(SocketAddress *a, const char *s) {
char *e, *n;
diff --git a/src/shared/util.c b/src/shared/util.c
index 863371c0d..b1f4e309d 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -93,7 +93,6 @@
#include "def.h"
#include "sparse-endian.h"
#include "formats-util.h"
-#include "process-util.h"
/* Put this test here for a lack of better place */
assert_cc(EAGAIN == EWOULDBLOCK);
@@ -186,7 +185,7 @@ char* first_word(const char *s, const char *word) {
return (char*) p;
}
-size_t cescape_char(char c, char *buf) {
+static size_t cescape_char(char c, char *buf) {
char * buf_old = buf;
switch (c) {
@@ -599,6 +598,49 @@ const char* split(const char **state, size_t *l, const char *separator, bool quo
return current;
}
+int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
+ int r;
+ _cleanup_free_ char *line = NULL;
+ long unsigned ppid;
+ const char *p;
+
+ assert(pid >= 0);
+ assert(_ppid);
+
+ if (pid == 0) {
+ *_ppid = getppid();
+ return 0;
+ }
+
+ p = procfs_file_alloca(pid, "stat");
+ r = read_one_line_file(p, &line);
+ if (r < 0)
+ return r;
+
+ /* Let's skip the pid and comm fields. The latter is enclosed
+ * in () but does not escape any () in its value, so let's
+ * skip over it manually */
+
+ p = strrchr(line, ')');
+ if (!p)
+ return -EIO;
+
+ p++;
+
+ if (sscanf(p, " "
+ "%*c " /* state */
+ "%lu ", /* ppid */
+ &ppid) != 1)
+ return -EIO;
+
+ if ((long unsigned) (pid_t) ppid != ppid)
+ return -ERANGE;
+
+ *_ppid = (pid_t) ppid;
+
+ return 0;
+}
+
int fchmod_umask(int fd, mode_t m) {
mode_t u;
int r;
@@ -617,6 +659,308 @@ char *truncate_nl(char *s) {
return s;
}
+int get_process_state(pid_t pid) {
+ const char *p;
+ char state;
+ int r;
+ _cleanup_free_ char *line = NULL;
+
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "stat");
+ r = read_one_line_file(p, &line);
+ if (r < 0)
+ return r;
+
+ p = strrchr(line, ')');
+ if (!p)
+ return -EIO;
+
+ p++;
+
+ if (sscanf(p, " %c", &state) != 1)
+ return -EIO;
+
+ return (unsigned char) state;
+}
+
+int get_process_comm(pid_t pid, char **name) {
+ const char *p;
+ int r;
+
+ assert(name);
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "comm");
+
+ 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) {
+ _cleanup_fclose_ FILE *f = NULL;
+ char *r = NULL, *k;
+ const char *p;
+ int c;
+
+ assert(line);
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "cmdline");
+
+ f = fopen(p, "re");
+ if (!f)
+ return -errno;
+
+ if (max_length == 0) {
+ size_t len = 0, allocated = 0;
+
+ while ((c = getc(f)) != EOF) {
+
+ if (!GREEDY_REALLOC(r, allocated, len+2)) {
+ free(r);
+ return -ENOMEM;
+ }
+
+ r[len++] = isprint(c) ? c : ' ';
+ }
+
+ if (len > 0)
+ r[len-1] = 0;
+
+ } else {
+ bool space = false;
+ size_t left;
+
+ r = new(char, max_length);
+ if (!r)
+ return -ENOMEM;
+
+ k = r;
+ left = max_length;
+ while ((c = getc(f)) != EOF) {
+
+ if (isprint(c)) {
+ if (space) {
+ if (left <= 4)
+ break;
+
+ *(k++) = ' ';
+ left--;
+ space = false;
+ }
+
+ if (left <= 4)
+ break;
+
+ *(k++) = (char) c;
+ left--;
+ } else
+ space = true;
+ }
+
+ if (left <= 4) {
+ size_t n = MIN(left-1, 3U);
+ memcpy(k, "...", n);
+ k[n] = 0;
+ } else
+ *k = 0;
+ }
+
+ /* Kernel threads have no argv[] */
+ if (isempty(r)) {
+ _cleanup_free_ char *t = NULL;
+ int h;
+
+ free(r);
+
+ if (!comm_fallback)
+ return -ENOENT;
+
+ h = get_process_comm(pid, &t);
+ if (h < 0)
+ return h;
+
+ r = strjoin("[", t, "]", NULL);
+ if (!r)
+ return -ENOMEM;
+ }
+
+ *line = r;
+ return 0;
+}
+
+int is_kernel_thread(pid_t pid) {
+ const char *p;
+ size_t count;
+ char c;
+ bool eof;
+ FILE *f;
+
+ if (pid == 0)
+ return 0;
+
+ assert(pid > 0);
+
+ p = procfs_file_alloca(pid, "cmdline");
+ f = fopen(p, "re");
+ if (!f)
+ return -errno;
+
+ count = fread(&c, 1, 1, f);
+ eof = feof(f);
+ fclose(f);
+
+ /* Kernel threads have an empty cmdline */
+
+ if (count <= 0)
+ return eof ? 1 : -errno;
+
+ return 0;
+}
+
+int get_process_capeff(pid_t pid, char **capeff) {
+ const char *p;
+
+ assert(capeff);
+ assert(pid >= 0);
+
+ p = procfs_file_alloca(pid, "status");
+
+ 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);
+
+ p = procfs_file_alloca(pid, "exe");
+ r = get_process_link_contents(p, name);
+ if (r < 0)
+ return r;
+
+ d = endswith(*name, " (deleted)");
+ if (d)
+ *d = '\0';
+
+ return 0;
+}
+
+static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
+ _cleanup_fclose_ FILE *f = NULL;
+ char line[LINE_MAX];
+ const char *p;
+
+ assert(field);
+ assert(uid);
+
+ if (pid == 0)
+ return getuid();
+
+ p = procfs_file_alloca(pid, "status");
+ f = fopen(p, "re");
+ if (!f)
+ return -errno;
+
+ FOREACH_LINE(line, f, return -errno) {
+ char *l;
+
+ l = strstrip(line);
+
+ if (startswith(l, field)) {
+ l += strlen(field);
+ l += strspn(l, WHITESPACE);
+
+ l[strcspn(l, WHITESPACE)] = 0;
+
+ return parse_uid(l, uid);
+ }
+ }
+
+ return -EIO;
+}
+
+int get_process_uid(pid_t pid, uid_t *uid) {
+ return get_process_id(pid, "Uid:", uid);
+}
+
+int get_process_gid(pid_t pid, gid_t *gid) {
+ assert_cc(sizeof(uid_t) == sizeof(gid_t));
+ 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 **env) {
+ _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(env);
+
+ 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';
+ *env = outcome;
+ outcome = NULL;
+
+ return 0;
+}
+
char *strnappend(const char *s, const char *suffix, size_t b) {
size_t a;
char *r;
@@ -3332,6 +3676,73 @@ static char *unquote(const char *s, const char* quotes) {
return strdup(s);
}
+int wait_for_terminate(pid_t pid, siginfo_t *status) {
+ siginfo_t dummy;
+
+ assert(pid >= 1);
+
+ if (!status)
+ status = &dummy;
+
+ for (;;) {
+ zero(*status);
+
+ if (waitid(P_PID, pid, status, WEXITED) < 0) {
+
+ if (errno == EINTR)
+ continue;
+
+ return -errno;
+ }
+
+ return 0;
+ }
+}
+
+/*
+ * Return values:
+ * < 0 : wait_for_terminate() failed to get the state of the
+ * process, the process was terminated by a signal, or
+ * failed for an unknown reason.
+ * >=0 : The process terminated normally, and its exit code is
+ * returned.
+ *
+ * That is, success is indicated by a return value of zero, and an
+ * error is indicated by a non-zero value.
+ *
+ * A warning is emitted if the process terminates abnormally,
+ * and also if it returns non-zero unless check_exit_code is true.
+ */
+int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code) {
+ int r;
+ siginfo_t status;
+
+ assert(name);
+ assert(pid > 1);
+
+ r = wait_for_terminate(pid, &status);
+ 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)
+ log_full(check_exit_code ? LOG_WARNING : LOG_DEBUG,
+ "%s failed with error code %i.", name, status.si_status);
+ else
+ log_debug("%s succeeded.", name);
+
+ return status.si_status;
+ } else if (status.si_code == CLD_KILLED ||
+ status.si_code == CLD_DUMPED) {
+
+ log_warning("%s terminated by signal %s.", name, signal_to_string(status.si_status));
+ return -EPROTO;
+ }
+
+ log_warning("%s failed due to unknown reason.", name);
+ return -EPROTO;
+}
+
noreturn void freeze(void) {
/* Make sure nobody waits for us on a socket anymore */
@@ -3708,6 +4119,17 @@ void execute_directories(const char* const* directories, usec_t timeout, char *a
wait_for_terminate_and_warn(name, executor_pid, true);
}
+int kill_and_sigcont(pid_t pid, int sig) {
+ int r;
+
+ r = kill(pid, sig) < 0 ? -errno : 0;
+
+ if (r >= 0)
+ kill(pid, SIGCONT);
+
+ return r;
+}
+
bool nulstr_contains(const char*nulstr, const char *needle) {
const char *i;
@@ -4916,6 +5338,60 @@ int setrlimit_closest(int resource, const struct rlimit *rlim) {
return 0;
}
+int getenv_for_pid(pid_t pid, const char *field, char **_value) {
+ _cleanup_fclose_ FILE *f = NULL;
+ char *value = NULL;
+ int r;
+ bool done = false;
+ size_t l;
+ const char *path;
+
+ assert(pid >= 0);
+ assert(field);
+ assert(_value);
+
+ path = procfs_file_alloca(pid, "environ");
+
+ f = fopen(path, "re");
+ if (!f)
+ return -errno;
+
+ l = strlen(field);
+ r = 0;
+
+ do {
+ char line[LINE_MAX];
+ unsigned i;
+
+ for (i = 0; i < sizeof(line)-1; i++) {
+ int c;
+
+ c = getc(f);
+ if (_unlikely_(c == EOF)) {
+ done = true;
+ break;
+ } else if (c == 0)
+ break;
+
+ line[i] = c;
+ }
+ line[i] = 0;
+
+ if (memcmp(line, field, l) == 0 && line[l] == '=') {
+ value = strdup(line + l + 1);
+ if (!value)
+ return -ENOMEM;
+
+ r = 1;
+ break;
+ }
+
+ } while (!done);
+
+ *_value = value;
+ return r;
+}
+
bool http_etag_is_valid(const char *etag) {
if (isempty(etag))
return false;
@@ -6021,6 +6497,33 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd) {
return 0;
}
+bool pid_is_unwaited(pid_t pid) {
+ /* Checks whether a PID is still valid at all, including a zombie */
+
+ if (pid <= 0)
+ return false;
+
+ if (kill(pid, 0) >= 0)
+ return true;
+
+ return errno != ESRCH;
+}
+
+bool pid_is_alive(pid_t pid) {
+ int r;
+
+ /* Checks whether a PID is still valid and not a zombie */
+
+ if (pid <= 0)
+ return false;
+
+ r = get_process_state(pid);
+ if (r == -ENOENT || r == 'Z')
+ return false;
+
+ return true;
+}
+
int getpeercred(int fd, struct ucred *ucred) {
socklen_t n = sizeof(struct ucred);
struct ucred u;
diff --git a/src/shared/util.h b/src/shared/util.h
index 9271578d5..f9f96ce8a 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -43,50 +43,10 @@
#include <sys/inotify.h>
#include <sys/statfs.h>
-#if SIZEOF_PID_T == 4
-# define PID_PRI PRIi32
-#elif SIZEOF_PID_T == 2
-# define PID_PRI PRIi16
-#else
-# error Unknown pid_t size
-#endif
-#define PID_FMT "%" PID_PRI
-
-#if SIZEOF_UID_T == 4
-# define UID_FMT "%" PRIu32
-#elif SIZEOF_UID_T == 2
-# define UID_FMT "%" PRIu16
-#else
-# error Unknown uid_t size
-#endif
-
-#if SIZEOF_GID_T == 4
-# define GID_FMT "%" PRIu32
-#elif SIZEOF_GID_T == 2
-# define GID_FMT "%" PRIu16
-#else
-# error Unknown gid_t size
-#endif
-
-#if SIZEOF_TIME_T == 8
-# define PRI_TIME PRIi64
-#elif SIZEOF_TIME_T == 4
-# define PRI_TIME PRIu32
-#else
-# error Unknown time_t size
-#endif
-
-#if SIZEOF_RLIM_T == 8
-# define RLIM_FMT "%" PRIu64
-#elif SIZEOF_RLIM_T == 4
-# define RLIM_FMT "%" PRIu32
-#else
-# error Unknown rlim_t size
-#endif
-
#include "macro.h"
#include "missing.h"
#include "time-util.h"
+#include "formats-util.h"
/* What is interpreted as whitespace? */
#define WHITESPACE " \t\n\r"