mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-22 13:33:56 +03:00
journal: add ability to browse journals of running OS containers
This adds the new library call sd_journal_open_container() and a new "-M" switch to journalctl. Particular care is taken that journalctl's "-b" switch resolves to the current boot ID of the container, not the host.
This commit is contained in:
parent
842129f587
commit
b6741478e7
2
TODO
2
TODO
@ -30,6 +30,8 @@ External:
|
||||
|
||||
Features:
|
||||
|
||||
* libsystemd-journal returns the object created as first param in sd_journal_new(), sd_bus_new() and suchlike as last...
|
||||
|
||||
* cgroups:
|
||||
- implement system-wide DefaultCPUAccounting=1 switch (and similar for blockio, memory?)
|
||||
- implement per-slice CPUFairScheduling=1 switch
|
||||
|
@ -647,6 +647,16 @@
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-M</option></term>
|
||||
<term><option>--machine=</option></term>
|
||||
|
||||
<listitem><para>Show messages from a
|
||||
running, local container. Specify a
|
||||
container name to connect
|
||||
to.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-D <replaceable>DIR</replaceable></option></term>
|
||||
<term><option>--directory=<replaceable>DIR</replaceable></option></term>
|
||||
|
@ -46,6 +46,7 @@
|
||||
<refname>sd_journal_open</refname>
|
||||
<refname>sd_journal_open_directory</refname>
|
||||
<refname>sd_journal_open_files</refname>
|
||||
<refname>sd_journal_open_container</refname>
|
||||
<refname>sd_journal_close</refname>
|
||||
<refname>sd_journal</refname>
|
||||
<refname>SD_JOURNAL_LOCAL_ONLY</refname>
|
||||
@ -79,6 +80,13 @@
|
||||
<paramdef>int <parameter>flags</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_journal_open_container</function></funcdef>
|
||||
<paramdef>sd_journal** <parameter>ret</parameter></paramdef>
|
||||
<paramdef>const char* <parameter>machine</parameter></paramdef>
|
||||
<paramdef>int <parameter>flags</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>void <function>sd_journal_close</function></funcdef>
|
||||
<paramdef>sd_journal* <parameter>j</parameter></paramdef>
|
||||
@ -131,6 +139,13 @@
|
||||
can be rotated at any moment, and the opening of
|
||||
specific files is inherently racy.</para>
|
||||
|
||||
<para><function>sd_journal_open_container()</function>
|
||||
is similar to <function>sd_journal_open()</function>
|
||||
but opens the journal files of a running
|
||||
OS container. The specified machine name refers to a
|
||||
container that is registered with
|
||||
<citerefentry><refentrytitle>systemd-machined</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||
|
||||
<para><varname>sd_journal</varname> objects cannot be
|
||||
used in the child after a fork. Functions which take a
|
||||
journal object as an argument
|
||||
@ -230,7 +245,8 @@
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd-journal</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_journal_next</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sd_journal_get_data</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
<citerefentry><refentrytitle>sd_journal_get_data</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-machined</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
@ -93,6 +93,7 @@ static bool arg_catalog = false;
|
||||
static bool arg_reverse = false;
|
||||
static int arg_journal_type = 0;
|
||||
static const char *arg_root = NULL;
|
||||
static const char *arg_machine = NULL;
|
||||
|
||||
static enum {
|
||||
ACTION_SHOW,
|
||||
@ -120,6 +121,7 @@ static int help(void) {
|
||||
"Flags:\n"
|
||||
" --system Show only the system journal\n"
|
||||
" --user Show only the user journal for current user\n"
|
||||
" -M --machine=CONTAINER Operate on local container\n"
|
||||
" --since=DATE Start showing entries newer or of the specified date\n"
|
||||
" --until=DATE Stop showing entries older or of the specified date\n"
|
||||
" -c --cursor=CURSOR Start showing entries from specified cursor\n"
|
||||
@ -247,6 +249,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG },
|
||||
{ "update-catalog", no_argument, NULL, ARG_UPDATE_CATALOG },
|
||||
{ "reverse", no_argument, NULL, 'r' },
|
||||
{ "machine", required_argument, NULL, 'M' },
|
||||
{}
|
||||
};
|
||||
|
||||
@ -255,7 +258,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:u:F:xr", options, NULL)) >= 0) {
|
||||
while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:u:F:xrM:", options, NULL)) >= 0) {
|
||||
|
||||
switch (c) {
|
||||
|
||||
@ -389,6 +392,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
arg_journal_type |= SD_JOURNAL_CURRENT_USER;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
arg_machine = optarg;
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
arg_directory = optarg;
|
||||
break;
|
||||
@ -576,8 +583,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (arg_follow && !arg_no_tail && arg_lines < 0)
|
||||
arg_lines = 10;
|
||||
|
||||
if (arg_directory && arg_file) {
|
||||
log_error("Please specify either -D/--directory= or --file=, not both.");
|
||||
if (!!arg_directory + !!arg_file + !!arg_machine > 1) {
|
||||
log_error("Please specify either -D/--directory= or --file= or -M/--machine=, not more than one.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -881,7 +888,7 @@ static int add_boot(sd_journal *j) {
|
||||
return 0;
|
||||
|
||||
if (!arg_boot_descriptor)
|
||||
return add_match_this_boot(j);
|
||||
return add_match_this_boot(j, arg_machine);
|
||||
|
||||
if (strlen(arg_boot_descriptor) >= 32) {
|
||||
char tmp = arg_boot_descriptor[32];
|
||||
@ -1460,6 +1467,8 @@ int main(int argc, char *argv[]) {
|
||||
r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
|
||||
else if (arg_file)
|
||||
r = sd_journal_open_files(&j, (const char**) arg_file, 0);
|
||||
else if (arg_machine)
|
||||
r = sd_journal_open_container(&j, arg_machine, 0);
|
||||
else
|
||||
r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
|
||||
if (r < 0) {
|
||||
|
@ -109,3 +109,8 @@ LIBSYSTEMD_JOURNAL_205 {
|
||||
global:
|
||||
sd_journal_open_files;
|
||||
} LIBSYSTEMD_JOURNAL_202;
|
||||
|
||||
LIBSYSTEMD_JOURNAL_209 {
|
||||
global:
|
||||
sd_journal_open_container;
|
||||
} LIBSYSTEMD_JOURNAL_205;
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "missing.h"
|
||||
#include "catalog.h"
|
||||
#include "replace-var.h"
|
||||
#include "fileio.h"
|
||||
|
||||
#define JOURNAL_FILES_MAX 1024
|
||||
|
||||
@ -1465,7 +1466,7 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_root_directory(sd_journal *j, const char *p) {
|
||||
static int add_root_directory(sd_journal *j, const char *p, const char *prefix) {
|
||||
_cleanup_closedir_ DIR *d = NULL;
|
||||
Directory *m;
|
||||
int r;
|
||||
@ -1477,6 +1478,9 @@ static int add_root_directory(sd_journal *j, const char *p) {
|
||||
!path_startswith(p, "/run"))
|
||||
return -EINVAL;
|
||||
|
||||
if (prefix)
|
||||
p = strappenda(prefix, p);
|
||||
|
||||
d = opendir(p);
|
||||
if (!d)
|
||||
return -errno;
|
||||
@ -1576,7 +1580,7 @@ static int remove_directory(sd_journal *j, Directory *d) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_search_paths(sd_journal *j) {
|
||||
static int add_search_paths(sd_journal *j, const char *prefix) {
|
||||
int r;
|
||||
const char search_paths[] =
|
||||
"/run/log/journal\0"
|
||||
@ -1589,7 +1593,7 @@ static int add_search_paths(sd_journal *j) {
|
||||
* what's actually accessible, and ignore the rest. */
|
||||
|
||||
NULSTR_FOREACH(p, search_paths) {
|
||||
r = add_root_directory(j, p);
|
||||
r = add_root_directory(j, p, prefix);
|
||||
if (r < 0 && r != -ENOENT) {
|
||||
r = set_put_error(j, r);
|
||||
if (r < 0)
|
||||
@ -1619,7 +1623,7 @@ static int add_current_paths(sd_journal *j) {
|
||||
if (!dir)
|
||||
return -ENOMEM;
|
||||
|
||||
r = add_root_directory(j, dir);
|
||||
r = add_root_directory(j, dir, NULL);
|
||||
if (r < 0) {
|
||||
set_put_error(j, r);
|
||||
return r;
|
||||
@ -1684,18 +1688,13 @@ _public_ int sd_journal_open(sd_journal **ret, int flags) {
|
||||
int r;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (flags & ~(SD_JOURNAL_LOCAL_ONLY|
|
||||
SD_JOURNAL_RUNTIME_ONLY|
|
||||
SD_JOURNAL_SYSTEM|
|
||||
SD_JOURNAL_CURRENT_USER))
|
||||
return -EINVAL;
|
||||
assert_return((flags & ~(SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_RUNTIME_ONLY|SD_JOURNAL_SYSTEM|SD_JOURNAL_CURRENT_USER)) == 0, -EINVAL);
|
||||
|
||||
j = journal_new(flags, NULL);
|
||||
if (!j)
|
||||
return -ENOMEM;
|
||||
|
||||
r = add_search_paths(j);
|
||||
r = add_search_paths(j, NULL);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
@ -1708,6 +1707,45 @@ fail:
|
||||
return r;
|
||||
}
|
||||
|
||||
_public_ int sd_journal_open_container(sd_journal **ret, const char *machine, int flags) {
|
||||
_cleanup_free_ char *root = NULL, *class = NULL;
|
||||
sd_journal *j;
|
||||
char *p;
|
||||
int r;
|
||||
|
||||
assert_return(machine, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
assert_return((flags & ~(SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM)) == 0, -EINVAL);
|
||||
assert_return(filename_is_safe(machine), -EINVAL);
|
||||
|
||||
p = strappenda("/run/systemd/machines/", machine);
|
||||
r = parse_env_file(p, NEWLINE, "ROOT", &root, "CLASS", &class, NULL);
|
||||
if (r == -ENOENT)
|
||||
return -EHOSTDOWN;
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!root)
|
||||
return -ENODATA;
|
||||
|
||||
if (!streq_ptr(class, "container"))
|
||||
return -EIO;
|
||||
|
||||
j = journal_new(flags, NULL);
|
||||
if (!j)
|
||||
return -ENOMEM;
|
||||
|
||||
r = add_search_paths(j, root);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
*ret = j;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
sd_journal_close(j);
|
||||
return r;
|
||||
}
|
||||
|
||||
_public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int flags) {
|
||||
sd_journal *j;
|
||||
int r;
|
||||
@ -1720,7 +1758,7 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f
|
||||
if (!j)
|
||||
return -ENOMEM;
|
||||
|
||||
r = add_root_directory(j, path);
|
||||
r = add_root_directory(j, path, NULL);
|
||||
if (r < 0) {
|
||||
set_put_error(j, r);
|
||||
goto fail;
|
||||
@ -2083,9 +2121,9 @@ _public_ int sd_journal_get_fd(sd_journal *j) {
|
||||
if (j->no_new_files)
|
||||
r = add_current_paths(j);
|
||||
else if (j->path)
|
||||
r = add_root_directory(j, j->path);
|
||||
r = add_root_directory(j, j->path, NULL);
|
||||
else
|
||||
r = add_search_paths(j);
|
||||
r = add_search_paths(j, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -29,8 +29,9 @@
|
||||
#include "bus-container.h"
|
||||
|
||||
int bus_container_connect(sd_bus *b) {
|
||||
_cleanup_free_ char *p = NULL, *s = NULL, *ns = NULL, *root = NULL, *class = NULL;
|
||||
_cleanup_free_ char *s = NULL, *ns = NULL, *root = NULL, *class = NULL;
|
||||
_cleanup_close_ int nsfd = -1, rootfd = -1;
|
||||
char *p;
|
||||
siginfo_t si;
|
||||
pid_t leader, child;
|
||||
int r;
|
||||
@ -39,10 +40,7 @@ int bus_container_connect(sd_bus *b) {
|
||||
assert(b->input_fd < 0);
|
||||
assert(b->output_fd < 0);
|
||||
|
||||
p = strappend("/run/systemd/machines/", b->machine);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
p = strappenda("/run/systemd/machines/", b->machine);
|
||||
r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
|
||||
if (r == -ENOENT)
|
||||
return -EHOSTDOWN;
|
||||
|
@ -764,6 +764,9 @@ static int parse_container_address(sd_bus *b, const char **p, char **guid) {
|
||||
if (!machine)
|
||||
return -EINVAL;
|
||||
|
||||
if (!filename_is_safe(machine))
|
||||
return -EINVAL;
|
||||
|
||||
free(b->machine);
|
||||
b->machine = machine;
|
||||
machine = NULL;
|
||||
|
@ -24,12 +24,14 @@
|
||||
#include <errno.h>
|
||||
#include <sys/poll.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "logs-show.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "utf8.h"
|
||||
#include "hashmap.h"
|
||||
#include "fileio.h"
|
||||
#include "journal-internal.h"
|
||||
|
||||
/* up to three lines (each up to 100 characters),
|
||||
@ -1112,17 +1114,113 @@ int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
|
||||
return r;
|
||||
}
|
||||
|
||||
int add_match_this_boot(sd_journal *j) {
|
||||
static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
|
||||
_cleanup_free_ char *leader = NULL, *class = NULL;
|
||||
_cleanup_close_pipe_ int sock[2] = { -1, -1 };
|
||||
_cleanup_close_ int nsfd = -1;
|
||||
const char *p, *ns;
|
||||
pid_t pid, child;
|
||||
siginfo_t si;
|
||||
char buf[37];
|
||||
ssize_t k;
|
||||
int r;
|
||||
|
||||
assert(machine);
|
||||
assert(boot_id);
|
||||
|
||||
if (!filename_is_safe(machine))
|
||||
return -EINVAL;
|
||||
|
||||
p = strappenda("/run/systemd/machines/", machine);
|
||||
|
||||
r = parse_env_file(p, NEWLINE, "LEADER", &leader, "CLASS", &class, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!leader)
|
||||
return -ENODATA;
|
||||
if (!streq_ptr(class, "container"))
|
||||
return -EIO;
|
||||
r = parse_pid(leader, &pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
ns = procfs_file_alloca(pid, "ns/mnt");
|
||||
|
||||
nsfd = open(ns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
|
||||
if (nsfd < 0)
|
||||
return -errno;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sock) < 0)
|
||||
return -errno;
|
||||
|
||||
child = fork();
|
||||
if (child < 0)
|
||||
return -errno;
|
||||
|
||||
if (child == 0) {
|
||||
int fd;
|
||||
|
||||
close_nointr_nofail(sock[0]);
|
||||
sock[0] = -1;
|
||||
|
||||
r = setns(nsfd, CLONE_NEWNS);
|
||||
if (r < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
k = loop_read(fd, buf, 36, false);
|
||||
close_nointr_nofail(fd);
|
||||
if (k != 36)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
k = send(sock[1], buf, 36, MSG_NOSIGNAL);
|
||||
if (k != 36)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
close_nointr_nofail(sock[1]);
|
||||
sock[1] = -1;
|
||||
|
||||
k = recv(sock[0], buf, 36, 0);
|
||||
if (k != 36)
|
||||
return -EIO;
|
||||
|
||||
r = wait_for_terminate(child, &si);
|
||||
if (r < 0 || si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
|
||||
return r < 0 ? r : -EIO;
|
||||
|
||||
buf[36] = 0;
|
||||
r = sd_id128_from_string(buf, boot_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int add_match_this_boot(sd_journal *j, const char *machine) {
|
||||
char match[9+32+1] = "_BOOT_ID=";
|
||||
sd_id128_t boot_id;
|
||||
int r;
|
||||
|
||||
assert(j);
|
||||
|
||||
r = sd_id128_get_boot(&boot_id);
|
||||
if (r < 0) {
|
||||
log_error("Failed to get boot id: %s", strerror(-r));
|
||||
return r;
|
||||
if (machine) {
|
||||
r = get_boot_id_for_machine(machine, &boot_id);
|
||||
if (r < 0) {
|
||||
log_error("Failed to get boot id of container %s: %s", machine, strerror(-r));
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
r = sd_id128_get_boot(&boot_id);
|
||||
if (r < 0) {
|
||||
log_error("Failed to get boot id: %s", strerror(-r));
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
sd_id128_to_string(boot_id, match + 9);
|
||||
@ -1166,7 +1264,7 @@ int show_journal_by_unit(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = add_match_this_boot(j);
|
||||
r = add_match_this_boot(j, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -38,7 +38,7 @@ int output_journal(
|
||||
OutputFlags flags,
|
||||
bool *ellipsized);
|
||||
|
||||
int add_match_this_boot(sd_journal *j);
|
||||
int add_match_this_boot(sd_journal *j, const char *machine);
|
||||
|
||||
int add_matches_for_unit(
|
||||
sd_journal *j,
|
||||
|
@ -86,6 +86,7 @@ enum {
|
||||
int sd_journal_open(sd_journal **ret, int flags);
|
||||
int sd_journal_open_directory(sd_journal **ret, const char *path, int flags);
|
||||
int sd_journal_open_files(sd_journal **ret, const char **paths, int flags);
|
||||
int sd_journal_open_container(sd_journal **ret, const char *machine, int flags);
|
||||
void sd_journal_close(sd_journal *j);
|
||||
|
||||
int sd_journal_previous(sd_journal *j);
|
||||
|
Loading…
Reference in New Issue
Block a user