]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/journal-util.c
vmspawn: Run auxiliary daemons inside scope instead of separate service (#38047)
[thirdparty/systemd.git] / src / shared / journal-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <unistd.h>
4
5 #include "sd-bus.h"
6 #include "sd-journal.h"
7
8 #include "acl-util.h"
9 #include "alloc-util.h"
10 #include "bus-error.h"
11 #include "bus-locator.h"
12 #include "bus-util.h"
13 #include "fd-util.h"
14 #include "fs-util.h"
15 #include "hashmap.h"
16 #include "journal-internal.h"
17 #include "journal-util.h"
18 #include "log.h"
19 #include "strv.h"
20 #include "user-util.h"
21
22 static int access_check_var_log_journal(sd_journal *j, bool want_other_users) {
23 int r;
24
25 assert(j);
26
27 /* If we are root, we should have access, don't warn. */
28 if (getuid() == 0)
29 return 0;
30
31 /* If we are in the 'systemd-journal' group, we should have
32 * access too. */
33 r = in_group("systemd-journal");
34 if (r < 0)
35 return log_error_errno(r, "Failed to check if we are in the 'systemd-journal' group: %m");
36 if (r > 0)
37 return 0;
38
39 #if HAVE_ACL
40 _cleanup_strv_free_ char **g = NULL;
41 const char* dir;
42
43 if (access_nofollow("/run/log/journal", F_OK) >= 0)
44 dir = "/run/log/journal";
45 else
46 dir = "/var/log/journal";
47
48 /* If we are in any of the groups listed in the journal ACLs,
49 * then all is good, too. Let's enumerate all groups from the
50 * default ACL of the directory, which generally should allow
51 * access to most journal files too. */
52 r = acl_search_groups(dir, &g);
53 if (r < 0)
54 return log_error_errno(r, "Failed to search journal ACL: %m");
55 if (r > 0)
56 return 0;
57
58 /* Print a pretty list, if there were ACLs set. */
59 if (!strv_isempty(g)) {
60 _cleanup_free_ char *s = NULL;
61
62 /* There are groups in the ACL, let's list them */
63 r = strv_extend(&g, "systemd-journal");
64 if (r < 0)
65 return log_oom();
66
67 strv_sort_uniq(g);
68
69 s = strv_join(g, "', '");
70 if (!s)
71 return log_oom();
72
73 log_notice("Hint: You are currently not seeing messages from %s.\n"
74 " Users in groups '%s' can see all messages.\n"
75 " Pass -q to turn off this notice.",
76 want_other_users ? "other users and the system" : "the system",
77 s);
78 return 1;
79 }
80 #endif
81
82 /* If no ACLs were found, print a short version of the message. */
83 log_notice("Hint: You are currently not seeing messages from %s.\n"
84 " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
85 " turn off this notice.",
86 want_other_users ? "other users and the system" : "the system");
87
88 return 1;
89 }
90
91 int journal_access_blocked(sd_journal *j) {
92 return hashmap_contains(j->errors, INT_TO_PTR(-EACCES));
93 }
94
95 int journal_access_check_and_warn(sd_journal *j, bool quiet, bool want_other_users) {
96 void *code;
97 char *path;
98 int r = 0;
99
100 assert(j);
101
102 if (hashmap_isempty(j->errors)) {
103 if (ordered_hashmap_isempty(j->files) && !quiet)
104 log_notice("No journal files were found.");
105
106 return 0;
107 }
108
109 if (journal_access_blocked(j)) {
110 if (!quiet)
111 (void) access_check_var_log_journal(j, want_other_users);
112
113 if (ordered_hashmap_isempty(j->files))
114 r = log_error_errno(EACCES, "No journal files were opened due to insufficient permissions.");
115 }
116
117 HASHMAP_FOREACH_KEY(path, code, j->errors) {
118 int err;
119
120 err = ABS(PTR_TO_INT(code));
121
122 switch (err) {
123 case EACCES:
124 continue;
125
126 case ENODATA:
127 log_warning_errno(err, "Journal file %s is truncated, ignoring file.", path);
128 break;
129
130 case EPROTONOSUPPORT:
131 log_warning_errno(err, "Journal file %1$s uses an unsupported feature, ignoring file.\n"
132 "Use SYSTEMD_LOG_LEVEL=debug journalctl --file=%1$s to see the details.",
133 path);
134 break;
135
136 case EBADMSG:
137 log_warning_errno(err, "Journal file %s corrupted, ignoring file.", path);
138 break;
139
140 case ETOOMANYREFS:
141 log_warning_errno(err, "Too many journal files (limit is at %u) in scope, ignoring file '%s'.", JOURNAL_FILES_MAX, path);
142 break;
143
144 default:
145 log_warning_errno(err, "An error was encountered while opening journal file or directory %s, ignoring file: %m", path);
146 }
147 }
148
149 return r;
150 }
151
152 int journal_open_machine(sd_journal **ret, const char *machine, int flags) {
153 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
154 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
155 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
156 _cleanup_(sd_journal_closep) sd_journal *j = NULL;
157 _cleanup_close_ int machine_fd = -EBADF;
158 int fd, r;
159
160 assert(ret);
161 assert(machine);
162
163 if (geteuid() != 0)
164 /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
165 * the container, thus we need root privileges to override them. */
166 return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Using the --machine= switch requires root privileges.");
167
168 r = sd_bus_open_system(&bus);
169 if (r < 0)
170 return log_error_errno(r, "Failed to open system bus: %m");
171
172 r = bus_call_method(bus, bus_machine_mgr, "OpenMachineRootDirectory", &error, &reply, "s", machine);
173 if (r < 0)
174 return log_error_errno(r, "Failed to open root directory of machine '%s': %s",
175 machine, bus_error_message(&error, r));
176
177 r = sd_bus_message_read(reply, "h", &fd);
178 if (r < 0)
179 return bus_log_parse_error(r);
180
181 machine_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
182 if (machine_fd < 0)
183 return log_error_errno(errno, "Failed to duplicate file descriptor: %m");
184
185 r = sd_journal_open_directory_fd(&j, machine_fd, SD_JOURNAL_OS_ROOT | SD_JOURNAL_TAKE_DIRECTORY_FD | flags);
186 if (r < 0)
187 return log_error_errno(r, "Failed to open journal in machine '%s': %m", machine);
188
189 TAKE_FD(machine_fd);
190 *ret = TAKE_PTR(j);
191 return 0;
192 }