[systemd-devel] [PATCH] journald: collect process data from socket data
Piotr Wilczek
p.wilczek at samsung.com
Fri May 30 03:45:21 PDT 2014
This patch adds posibility for journal to get process data from
socket data (if available) instead of from procfs.
Additionally a new procinfo structure is added to store all process
data in single place. This data include creditentials and status.
To enable this functionality, SO_PASSPROC socket option must be set.
This option is introduced in:
http://lwn.net/Articles/600564/
With this patch journald cpu usage is decresed by about 20%
Signed-off-by: Piotr Wilczek <p.wilczek at samsung.com>
---
src/journal/journald-kmsg.c | 2 +-
src/journal/journald-native.c | 24 ++++----
src/journal/journald-native.h | 4 +-
src/journal/journald-server.c | 131 +++++++++++++++++++++++++++++++++---------
src/journal/journald-server.h | 17 +++++-
src/journal/journald-stream.c | 7 ++-
src/journal/journald-syslog.c | 15 +++--
src/journal/journald-syslog.h | 2 +-
8 files changed, 155 insertions(+), 47 deletions(-)
diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c
index 12992e7..0bac0df 100644
--- a/src/journal/journald-kmsg.c
+++ b/src/journal/journald-kmsg.c
@@ -304,7 +304,7 @@ static void dev_kmsg_record(Server *s, char *p, size_t l) {
if (message)
IOVEC_SET_STRING(iovec[n++], message);
- server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, NULL, 0, NULL, priority, 0);
+ server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, priority, 0);
finish:
for (j = 0; j < z; j++)
diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c
index c54f647..b2c44d6 100644
--- a/src/journal/journald-native.c
+++ b/src/journal/journald-native.c
@@ -75,9 +75,7 @@ static bool allow_object_pid(struct ucred *ucred) {
void server_process_native_message(
Server *s,
const void *buffer, size_t buffer_size,
- struct ucred *ucred,
- struct timeval *tv,
- const char *label, size_t label_len) {
+ struct procinfo *procinfo) {
struct iovec *iovec = NULL;
unsigned n = 0, j, tn = (unsigned) -1;
@@ -87,12 +85,20 @@ void server_process_native_message(
char *identifier = NULL, *message = NULL;
pid_t object_pid = 0;
+ struct ucred *ucred = NULL;
+ struct timeval *tv = NULL;
+
assert(s);
assert(buffer || buffer_size == 0);
p = buffer;
remaining = buffer_size;
+ if (procinfo) {
+ ucred = procinfo->ucred;
+ tv = procinfo->tv;
+ }
+
while (remaining > 0) {
const char *e, *q;
@@ -106,7 +112,7 @@ void server_process_native_message(
if (e == p) {
/* Entry separator */
- server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
+ server_dispatch_message(s, iovec, n, m, procinfo, NULL, priority, object_pid);
n = 0;
priority = LOG_INFO;
@@ -266,7 +272,7 @@ void server_process_native_message(
server_forward_wall(s, priority, identifier, message, ucred);
}
- server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
+ server_dispatch_message(s, iovec, n, m, procinfo, NULL, priority, object_pid);
finish:
for (j = 0; j < n; j++) {
@@ -286,9 +292,7 @@ finish:
void server_process_native_file(
Server *s,
int fd,
- struct ucred *ucred,
- struct timeval *tv,
- const char *label, size_t label_len) {
+ struct procinfo *procinfo) {
struct stat st;
_cleanup_free_ void *p = NULL;
@@ -298,7 +302,7 @@ void server_process_native_file(
assert(s);
assert(fd >= 0);
- if (!ucred || ucred->uid != 0) {
+ if (!procinfo || !procinfo->ucred || procinfo->ucred->uid != 0) {
_cleanup_free_ char *sl = NULL, *k = NULL;
const char *e;
@@ -362,7 +366,7 @@ void server_process_native_file(
if (n < 0)
log_error("Failed to read file, ignoring: %s", strerror(-n));
else if (n > 0)
- server_process_native_message(s, p, n, ucred, tv, label, label_len);
+ server_process_native_message(s, p, n, procinfo);
}
int server_open_native_socket(Server*s) {
diff --git a/src/journal/journald-native.h b/src/journal/journald-native.h
index bf02fee..858a3d8 100644
--- a/src/journal/journald-native.h
+++ b/src/journal/journald-native.h
@@ -30,8 +30,8 @@
bool valid_user_field(const char *p, size_t l, bool allow_protected);
-void server_process_native_message(Server *s, const void *buffer, size_t buffer_size, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len);
+void server_process_native_message(Server *s, const void *buffer, size_t buffer_size, struct procinfo *procinfo);
-void server_process_native_file(Server *s, int fd, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len);
+void server_process_native_file(Server *s, int fd, struct procinfo *procinfo);
int server_open_native_socket(Server*s);
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 381d80a..6c029b3 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -533,12 +533,34 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned
server_schedule_sync(s, priority);
}
+static int get_cap(const char *status, const char *cap_name, char **cap_val)
+{
+ char *k, *l, *p;
+
+ if (!status || !cap_name)
+ return -1;
+
+ k = strstr(status, cap_name);
+ if (!k)
+ return -1;
+ k += strlen(cap_name);
+
+ p = strchr(k, '\n');
+ if (!p)
+ return -1;
+ l = strndup(k, p - k);
+ if (!l)
+ return -1;
+
+ *cap_val = l;
+
+ return 0;
+}
+
static void dispatch_message_real(
Server *s,
struct iovec *iovec, unsigned n, unsigned m,
- struct ucred *ucred,
- struct timeval *tv,
- const char *label, size_t label_len,
+ struct procinfo *procinfo,
const char *unit_id,
int priority,
pid_t object_pid) {
@@ -567,13 +589,19 @@ static void dispatch_message_real(
uint32_t audit;
uid_t loginuid;
#endif
+ struct ucred *ucred = NULL;
+ struct timeval *tv = NULL;
+#ifdef HAVE_SELINUX
+ const char *label = NULL;
+ size_t label_len = 0;
+#endif
assert(s);
assert(iovec);
assert(n > 0);
assert(n + N_IOVEC_META_FIELDS + (object_pid ? N_IOVEC_OBJECT_FIELDS : 0) <= m);
- if (ucred) {
+ if (procinfo && procinfo->ucred) {
realuid = ucred->uid;
sprintf(pid, "_PID="PID_FMT, ucred->pid);
@@ -585,28 +613,47 @@ static void dispatch_message_real(
sprintf(gid, "_GID="GID_FMT, ucred->gid);
IOVEC_SET_STRING(iovec[n++], gid);
- r = get_process_comm(ucred->pid, &t);
- if (r >= 0) {
- x = strappenda("_COMM=", t);
- free(t);
+ if (procinfo->comm) {
+ x = strappenda("_COMM=", procinfo->comm);
IOVEC_SET_STRING(iovec[n++], x);
+ } else {
+ r = get_process_comm(ucred->pid, &t);
+ if (r >= 0) {
+ x = strappenda("_COMM=", t);
+ free(t);
+ IOVEC_SET_STRING(iovec[n++], x);
+ }
}
- r = get_process_exe(ucred->pid, &t);
- if (r >= 0) {
- x = strappenda("_EXE=", t);
- free(t);
+ if (procinfo->exe) {
+ x = strappenda("_EXE=", procinfo->exe);
IOVEC_SET_STRING(iovec[n++], x);
+ } else {
+ r = get_process_exe(ucred->pid, &t);
+ if (r >= 0) {
+ x = strappenda("_EXE=", t);
+ free(t);
+ IOVEC_SET_STRING(iovec[n++], x);
+ }
}
- r = get_process_cmdline(ucred->pid, 0, false, &t);
- if (r >= 0) {
- x = strappenda("_CMDLINE=", t);
- free(t);
+ if (procinfo->cmdline) {
+ x = strappenda("_CMDLINE=", procinfo->cmdline);
IOVEC_SET_STRING(iovec[n++], x);
+ } else {
+ r = get_process_cmdline(ucred->pid, 0, false, &t);
+ if (r >= 0) {
+ x = strappenda("_CMDLINE=", t);
+ free(t);
+ IOVEC_SET_STRING(iovec[n++], x);
+ }
}
- r = get_process_capeff(ucred->pid, &t);
+ r = -1;
+ if (procinfo->status)
+ r = get_cap(procinfo->status, "CapEff:\t", &t);
+ if (r < 0)
+ r = get_process_capeff(ucred->pid, &t);
if (r >= 0) {
x = strappenda("_CAP_EFFECTIVE=", t);
free(t);
@@ -825,6 +872,7 @@ void server_driver_message(Server *s, sd_id128_t message_id, const char *format,
int n = 0;
va_list ap;
struct ucred ucred = {};
+ struct procinfo procinfo = {};
assert(s);
assert(format);
@@ -849,15 +897,15 @@ void server_driver_message(Server *s, sd_id128_t message_id, const char *format,
ucred.uid = getuid();
ucred.gid = getgid();
- dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &ucred, NULL, NULL, 0, NULL, LOG_INFO, 0);
+ procinfo.ucred = &ucred;
+
+ dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &procinfo, NULL, LOG_INFO, 0);
}
void server_dispatch_message(
Server *s,
struct iovec *iovec, unsigned n, unsigned m,
- struct ucred *ucred,
- struct timeval *tv,
- const char *label, size_t label_len,
+ struct procinfo *procinfo,
const char *unit_id,
int priority,
pid_t object_pid) {
@@ -865,10 +913,14 @@ void server_dispatch_message(
int rl, r;
_cleanup_free_ char *path = NULL;
char *c;
+ struct ucred *ucred = NULL;
assert(s);
assert(iovec || n == 0);
+ if (procinfo)
+ ucred = procinfo->ucred;
+
if (n == 0)
return;
@@ -915,7 +967,7 @@ void server_dispatch_message(
"Suppressed %u messages from %s", rl - 1, path);
finish:
- dispatch_message_real(s, iovec, n, m, ucred, tv, label, label_len, unit_id, priority, object_pid);
+ dispatch_message_real(s, iovec, n, m, procinfo, unit_id, priority, object_pid);
}
@@ -1122,6 +1174,9 @@ int process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userda
char *label = NULL;
size_t label_len = 0;
struct iovec iovec;
+ struct procinfo procinfo;
+
+ memset(&procinfo, 0x00, sizeof(struct procinfo));
union {
struct cmsghdr cmsghdr;
@@ -1136,7 +1191,7 @@ int process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userda
uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
CMSG_SPACE(sizeof(struct timeval)) +
CMSG_SPACE(sizeof(int)) + /* fd */
- CMSG_SPACE(NAME_MAX)]; /* selinux label */
+ CMSG_SPACE(PATH_MAX)]; /* selinux label */
} control = {};
struct msghdr msghdr = {
.msg_iov = &iovec,
@@ -1189,20 +1244,44 @@ int process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userda
fds = (int*) CMSG_DATA(cmsg);
n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
}
+ else if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_PROCINFO) {
+
+ unsigned int i;
+ char *ptr = CMSG_DATA(cmsg);
+
+ procinfo.ucred = ucred;
+ procinfo.label = label;
+ procinfo.label_len = label_len;
+ procinfo.tv = tv;
+
+ for (i = 0; i < cmsg->cmsg_len; i+=strlen(ptr+i)+1) {
+ if (strlen(ptr+i) == 0)
+ continue;
+ if (strncmp(ptr+i, "COMM=", strlen("COMM=")) == 0)
+ procinfo.comm = ptr+i+strlen("COMM=");
+ if (strncmp(ptr+i, "EXE=", strlen("EXE=")) == 0)
+ procinfo.exe = ptr+i+strlen("EXE=");
+ if (strncmp(ptr+i, "CMDLINE=", strlen("CMDLINE=")) == 0)
+ procinfo.cmdline = ptr+i+strlen("CMDLINE=");
+ if (strncmp(ptr+i, "STATUS=", strlen("STATUS=")) == 0)
+ procinfo.status = ptr+i+strlen("STATUS=");
+ }
+ }
}
if (fd == s->syslog_fd) {
if (n > 0 && n_fds == 0) {
s->buffer[n] = 0;
- server_process_syslog_message(s, strstrip(s->buffer), ucred, tv, label, label_len);
+ server_process_syslog_message(s, strstrip(s->buffer), &procinfo);
} else if (n_fds > 0)
log_warning("Got file descriptors via syslog socket. Ignoring.");
} else {
if (n > 0 && n_fds == 0)
- server_process_native_message(s, s->buffer, n, ucred, tv, label, label_len);
+ server_process_native_message(s, s->buffer, n, &procinfo);
else if (n == 0 && n_fds == 1)
- server_process_native_file(s, fds[0], ucred, tv, label, label_len);
+ server_process_native_file(s, fds[0], &procinfo);
else if (n_fds > 0)
log_warning("Got too many file descriptors via native socket. Ignoring.");
}
diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h
index e468b82..3f9b43f 100644
--- a/src/journal/journald-server.h
+++ b/src/journal/journald-server.h
@@ -143,12 +143,27 @@ typedef struct Server {
char *cgroup_root;
} Server;
+#ifndef SCM_PROCINFO
+#define SCM_PROCINFO 0x05
+#endif
+
+struct procinfo {
+ struct ucred *ucred;
+ struct timeval *tv;
+ char *label;
+ size_t label_len;
+ char *comm;
+ char *exe;
+ char *cmdline;
+ char *status;
+};
+
#define N_IOVEC_META_FIELDS 20
#define N_IOVEC_KERNEL_FIELDS 64
#define N_IOVEC_UDEV_FIELDS 32
#define N_IOVEC_OBJECT_FIELDS 11
-void server_dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigned m, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len, const char *unit_id, int priority, pid_t object_pid);
+void server_dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigned m, struct procinfo *procinfo, const char *unit_id, int priority, pid_t object_pid);
void server_driver_message(Server *s, sd_id128_t message_id, const char *format, ...) _printf_(3,4);
/* gperf lookup function */
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index 89da150..1a62462 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -86,6 +86,7 @@ static int stdout_stream_log(StdoutStream *s, const char *p) {
unsigned n = 0;
char *label = NULL;
size_t label_len = 0;
+ struct procinfo procinfo = { 0 };
assert(s);
assert(p);
@@ -137,7 +138,11 @@ static int stdout_stream_log(StdoutStream *s, const char *p) {
}
#endif
- server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, s->unit_id, priority, 0);
+ procinfo.ucred = &s->ucred;
+ procinfo.label = label;
+ procinfo.label_len = label_len;
+
+ server_dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &procinfo, s->unit_id, priority, 0);
return 0;
}
diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c
index 434eac4..4bbc389 100644
--- a/src/journal/journald-syslog.c
+++ b/src/journal/journald-syslog.c
@@ -351,10 +351,7 @@ static void syslog_skip_date(char **buf) {
void server_process_syslog_message(
Server *s,
const char *buf,
- struct ucred *ucred,
- struct timeval *tv,
- const char *label,
- size_t label_len) {
+ struct procinfo *procinfo) {
char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *syslog_pid = NULL;
struct iovec iovec[N_IOVEC_META_FIELDS + 6];
@@ -363,9 +360,17 @@ void server_process_syslog_message(
char *identifier = NULL, *pid = NULL;
const char *orig;
+ struct ucred *ucred = NULL;
+ struct timeval *tv = NULL;
+
assert(s);
assert(buf);
+ if (procinfo) {
+ ucred = procinfo->ucred;
+ tv = procinfo->tv;
+ }
+
orig = buf;
syslog_parse_priority(&buf, &priority, true);
@@ -409,7 +414,7 @@ void server_process_syslog_message(
if (message)
IOVEC_SET_STRING(iovec[n++], message);
- server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, label, label_len, NULL, priority, 0);
+ server_dispatch_message(s, iovec, n, ELEMENTSOF(iovec), procinfo, NULL, priority, 0);
free(message);
free(identifier);
diff --git a/src/journal/journald-syslog.h b/src/journal/journald-syslog.h
index 057ea79..79f6949 100644
--- a/src/journal/journald-syslog.h
+++ b/src/journal/journald-syslog.h
@@ -30,7 +30,7 @@ size_t syslog_parse_identifier(const char **buf, char **identifier, char **pid);
void server_forward_syslog(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred, struct timeval *tv);
-void server_process_syslog_message(Server *s, const char *buf, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len);
+void server_process_syslog_message(Server *s, const char *buf, struct procinfo *procinfo);
int server_open_syslog_socket(Server *s);
void server_maybe_warn_forward_syslog_missed(Server *s);
--
1.9.1
More information about the systemd-devel
mailing list