lslogins: print systemd journal logs

Co-Author: Ondrej Oprala <ooprala@redhat.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2014-05-27 17:34:15 +02:00
parent 1ad36b5264
commit f37b357b47
2 changed files with 81 additions and 7 deletions

View File

@ -177,6 +177,10 @@ lslogins_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir)
if HAVE_SELINUX
lslogins_LDADD += -lselinux
endif
if HAVE_SYSTEMD
lslogins_LDADD += $(SYSTEMD_LIBS) $(SYSTEMD_JOURNAL_LIBS)
lslogins_CFLAGS += $(SYSTEMD_CFLAGS) $(SYSTEMD_JOURNAL_CFLAGS)
endif
endif # BUILD_LSLOGINS
if BUILD_VIPW

View File

@ -43,6 +43,10 @@
# include <selinux/selinux.h>
#endif
#ifdef HAVE_LIBSYSTEMD
# include <systemd/sd-journal.h>
#endif
#include "c.h"
#include "nls.h"
#include "closestream.h"
@ -246,6 +250,7 @@ struct lslogins_control {
void *usertree;
uid_t uid;
uid_t UID_MIN;
uid_t UID_MAX;
@ -260,7 +265,9 @@ struct lslogins_control {
int sel_enabled;
unsigned int time_mode;
const char *journal_path;
};
/* these have to remain global since there's no other
* reasonable way to pass them for each call of fill_table()
* via twalk() */
@ -340,6 +347,9 @@ static char *build_sgroups_string(gid_t *sgroups, size_t nsgroups, int want_name
size_t n = 0, maxlen, len;
char *res, *p;
if (!nsgroups)
return NULL;
len = maxlen = nsgroups * 10;
res = p = xmalloc(maxlen);
@ -461,7 +471,8 @@ static int get_sgroups(gid_t **list, size_t *len, struct passwd *pwd)
++n;
}
(*list)[n] = (*list)[--(*len)];
if (*len)
(*list)[n] = (*list)[--(*len)];
return 0;
}
@ -500,7 +511,8 @@ static struct lslogins_user *get_user_info(struct lslogins_control *ctl, const c
if (!pwd)
return NULL;
uid = pwd->pw_uid;
ctl->uid = uid = pwd->pw_uid;
/* nfsnobody is an exception to the UID_MAX limit.
* This is "nobody" on some systems; the decisive
* point is the UID - 65534 */
@ -970,11 +982,11 @@ static void fill_table(const void *u, const VISIT which, const int depth __attri
case COL_PWD_CTIME_MAX:
rc = scols_line_set_data(ln, n, user->pwd_ctime_max);
break;
#ifdef HAVE_LIBSELINUX
case COL_SELINUX:
#ifdef HAVE_LIBSELINUX
rc = scols_line_set_data(ln, n, user->context);
break;
#endif
break;
case COL_NPROCS:
rc = scols_line_set_data(ln, n, user->nprocs);
break;
@ -989,6 +1001,60 @@ static void fill_table(const void *u, const VISIT which, const int depth __attri
}
return;
}
#ifdef HAVE_LIBSYSTEMD
static void print_journal_tail(const char *journal_path, uid_t uid, size_t len)
{
sd_journal *j;
char *match, *buf;
uint64_t x;
time_t t;
const char *identifier, *pid, *message;
size_t identifier_len, pid_len, message_len;
if (journal_path)
sd_journal_open_directory(&j, journal_path, 0);
else
sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
buf = xmalloc(sizeof(char) * 16);
xasprintf(&match, "_UID=%d", uid);
sd_journal_add_match(j, match, 0);
sd_journal_seek_tail(j);
sd_journal_previous_skip(j, len);
do {
if (0 > sd_journal_get_data(j, "SYSLOG_IDENTIFIER",
(const void **) &identifier, &identifier_len))
return;
if (0 > sd_journal_get_data(j, "_PID",
(const void **) &pid, &pid_len))
return;
if (0 > sd_journal_get_data(j, "MESSAGE",
(const void **) &message, &message_len))
return;
sd_journal_get_realtime_usec(j, &x);
t = x / 1000000;
strftime(buf, 16, "%b %d %H:%M:%S", localtime(&t));
fprintf(stdout, "%s", buf);
identifier = strchr(identifier, '=') + 1;
pid = strchr(pid, '=') + 1 ;
message = strchr(message, '=') + 1;
fprintf(stdout, " %s", identifier);
fprintf(stdout, "[%s]:", pid);
fprintf(stdout, "%s\n", message);
} while (sd_journal_next(j));
free(buf);
free(match);
sd_journal_flush_matches(j);
sd_journal_close(j);
}
#endif
static int print_pretty(struct libscols_table *tb)
{
@ -1024,9 +1090,14 @@ static int print_user_table(struct lslogins_control *ctl)
return -1;
twalk(ctl->usertree, fill_table);
if (outmode == OUT_PRETTY)
if (outmode == OUT_PRETTY) {
print_pretty(tb);
else
#ifdef HAVE_LIBSYSTEMD
fprintf(stdout, _("\nLast logs:\n"));
print_journal_tail(ctl->journal_path, ctl->uid, 3);
fputc('\n', stdout);
#endif
} else
scols_print_table(tb);
return 0;
}
@ -1383,6 +1454,5 @@ int main(int argc, char *argv[])
tdestroy(ctl->usertree, free_user);
free_ctl(ctl);
return EXIT_SUCCESS;
}