[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