[systemd-devel] [PATCH] journald: collect process data from socket data
Michal Sekletar
msekleta at redhat.com
Fri May 30 05:13:26 PDT 2014
On Fri, May 30, 2014 at 12:45:21PM +0200, Piotr Wilczek wrote:
> 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>
> ---
Thanks for moving this forward! I hope your attempt will go through David's
review.
I know that flag was suggested by Kay, but isn't there a nicer way how to expose
this to userspace given that in "man 7 unix" is written following:
"For historical reasons these socket options are specified with a
SOL_SOCKET type even though they are AF_UNIX specific."
AFAIK we had only SO_PASSCRED and your patchset adds one more.
Michal
> 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
>
> _______________________________________________
> systemd-devel mailing list
> systemd-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel
More information about the systemd-devel
mailing list