]>
Commit | Line | Data |
---|---|---|
87d2c1ff LP |
1 | /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ |
2 | ||
3 | /*** | |
4 | This file is part of systemd. | |
5 | ||
6 | Copyright 2011 Lennart Poettering | |
7 | ||
8 | systemd is free software; you can redistribute it and/or modify it | |
9 | under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation; either version 2 of the License, or | |
11 | (at your option) any later version. | |
12 | ||
13 | systemd is distributed in the hope that it will be useful, but | |
14 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | |
20 | ***/ | |
21 | ||
22 | #include <sys/epoll.h> | |
23 | #include <sys/socket.h> | |
24 | #include <errno.h> | |
25 | #include <sys/signalfd.h> | |
26 | #include <unistd.h> | |
27 | #include <fcntl.h> | |
f4b47811 LP |
28 | #include <sys/acl.h> |
29 | #include <acl/libacl.h> | |
7f3e6257 LP |
30 | #include <stddef.h> |
31 | #include <sys/ioctl.h> | |
32 | #include <linux/sockios.h> | |
6e409ce1 | 33 | #include <sys/statvfs.h> |
87d2c1ff | 34 | |
81527be1 LP |
35 | #include <systemd/sd-journal.h> |
36 | #include <systemd/sd-login.h> | |
37 | #include <systemd/sd-messages.h> | |
38 | #include <systemd/sd-daemon.h> | |
39 | ||
87d2c1ff | 40 | #include "hashmap.h" |
cec736d2 | 41 | #include "journal-file.h" |
87d2c1ff | 42 | #include "socket-util.h" |
f4b47811 | 43 | #include "acl-util.h" |
69e5d42d | 44 | #include "cgroup-util.h" |
fe652127 | 45 | #include "list.h" |
6e409ce1 | 46 | #include "journal-rate-limit.h" |
cf244689 | 47 | #include "journal-internal.h" |
e6960940 LP |
48 | #include "conf-parser.h" |
49 | #include "journald.h" | |
87d2c1ff | 50 | |
cab8ac60 | 51 | #define USER_JOURNALS_MAX 1024 |
fe652127 LP |
52 | #define STDOUT_STREAMS_MAX 4096 |
53 | ||
de97b26a LP |
54 | #define DEFAULT_RATE_LIMIT_INTERVAL (10*USEC_PER_SEC) |
55 | #define DEFAULT_RATE_LIMIT_BURST 200 | |
56 | ||
9cfb57c9 LP |
57 | #define RECHECK_AVAILABLE_SPACE_USEC (30*USEC_PER_SEC) |
58 | ||
54a7b863 LP |
59 | #define RECHECK_VAR_AVAILABLE_USEC (30*USEC_PER_SEC) |
60 | ||
8b18eb67 LP |
61 | #define SYSLOG_TIMEOUT_USEC (5*USEC_PER_SEC) |
62 | ||
224f2ee2 LP |
63 | #define N_IOVEC_META_FIELDS 16 |
64 | ||
fe652127 LP |
65 | typedef enum StdoutStreamState { |
66 | STDOUT_STREAM_TAG, | |
67 | STDOUT_STREAM_PRIORITY, | |
68 | STDOUT_STREAM_PRIORITY_PREFIX, | |
224f2ee2 LP |
69 | STDOUT_STREAM_FORWARD_TO_SYSLOG, |
70 | STDOUT_STREAM_FORWARD_TO_KMSG, | |
71 | STDOUT_STREAM_FORWARD_TO_CONSOLE, | |
fe652127 LP |
72 | STDOUT_STREAM_RUNNING |
73 | } StdoutStreamState; | |
74 | ||
75 | struct StdoutStream { | |
76 | Server *server; | |
77 | StdoutStreamState state; | |
78 | ||
79 | int fd; | |
80 | ||
81 | struct ucred ucred; | |
82 | ||
83 | char *tag; | |
84 | int priority; | |
85 | bool priority_prefix:1; | |
224f2ee2 LP |
86 | bool forward_to_syslog:1; |
87 | bool forward_to_kmsg:1; | |
88 | bool forward_to_console:1; | |
fe652127 LP |
89 | |
90 | char buffer[LINE_MAX+1]; | |
91 | size_t length; | |
92 | ||
93 | LIST_FIELDS(StdoutStream, stdout_stream); | |
94 | }; | |
95 | ||
cf244689 LP |
96 | static int server_flush_to_var(Server *s); |
97 | ||
6e409ce1 | 98 | static uint64_t available_space(Server *s) { |
babfc091 | 99 | char ids[33], *p; |
6e409ce1 | 100 | const char *f; |
babfc091 | 101 | sd_id128_t machine; |
6e409ce1 LP |
102 | struct statvfs ss; |
103 | uint64_t sum = 0, avail = 0, ss_avail = 0; | |
104 | int r; | |
105 | DIR *d; | |
babfc091 LP |
106 | usec_t ts; |
107 | JournalMetrics *m; | |
108 | ||
109 | ts = now(CLOCK_MONOTONIC); | |
9cfb57c9 LP |
110 | |
111 | if (s->cached_available_space_timestamp + RECHECK_AVAILABLE_SPACE_USEC > ts) | |
112 | return s->cached_available_space; | |
6e409ce1 LP |
113 | |
114 | r = sd_id128_get_machine(&machine); | |
115 | if (r < 0) | |
116 | return 0; | |
117 | ||
babfc091 | 118 | if (s->system_journal) { |
6e409ce1 | 119 | f = "/var/log/journal/"; |
babfc091 LP |
120 | m = &s->system_metrics; |
121 | } else { | |
6e409ce1 | 122 | f = "/run/log/journal/"; |
babfc091 LP |
123 | m = &s->runtime_metrics; |
124 | } | |
125 | ||
126 | assert(m); | |
6e409ce1 LP |
127 | |
128 | p = strappend(f, sd_id128_to_string(machine, ids)); | |
129 | if (!p) | |
130 | return 0; | |
131 | ||
132 | d = opendir(p); | |
133 | free(p); | |
134 | ||
135 | if (!d) | |
136 | return 0; | |
137 | ||
138 | if (fstatvfs(dirfd(d), &ss) < 0) | |
139 | goto finish; | |
140 | ||
141 | for (;;) { | |
142 | struct stat st; | |
143 | struct dirent buf, *de; | |
144 | int k; | |
145 | ||
146 | k = readdir_r(d, &buf, &de); | |
147 | if (k != 0) { | |
148 | r = -k; | |
149 | goto finish; | |
150 | } | |
151 | ||
152 | if (!de) | |
153 | break; | |
154 | ||
155 | if (!dirent_is_file_with_suffix(de, ".journal")) | |
156 | continue; | |
157 | ||
158 | if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) | |
159 | continue; | |
160 | ||
161 | sum += (uint64_t) st.st_blocks * (uint64_t) st.st_blksize; | |
162 | } | |
163 | ||
babfc091 | 164 | avail = sum >= m->max_use ? 0 : m->max_use - sum; |
6e409ce1 LP |
165 | |
166 | ss_avail = ss.f_bsize * ss.f_bavail; | |
167 | ||
babfc091 | 168 | ss_avail = ss_avail < m->keep_free ? 0 : ss_avail - m->keep_free; |
6e409ce1 LP |
169 | |
170 | if (ss_avail < avail) | |
171 | avail = ss_avail; | |
172 | ||
9cfb57c9 LP |
173 | s->cached_available_space = avail; |
174 | s->cached_available_space_timestamp = ts; | |
175 | ||
6e409ce1 LP |
176 | finish: |
177 | closedir(d); | |
178 | ||
179 | return avail; | |
180 | } | |
181 | ||
f4b47811 LP |
182 | static void fix_perms(JournalFile *f, uid_t uid) { |
183 | acl_t acl; | |
184 | acl_entry_t entry; | |
185 | acl_permset_t permset; | |
186 | int r; | |
187 | ||
188 | assert(f); | |
189 | ||
190 | r = fchmod_and_fchown(f->fd, 0640, 0, 0); | |
191 | if (r < 0) | |
192 | log_warning("Failed to fix access mode/rights on %s, ignoring: %s", f->path, strerror(-r)); | |
193 | ||
194 | if (uid <= 0) | |
195 | return; | |
196 | ||
197 | acl = acl_get_fd(f->fd); | |
198 | if (!acl) { | |
199 | log_warning("Failed to read ACL on %s, ignoring: %m", f->path); | |
200 | return; | |
201 | } | |
202 | ||
203 | r = acl_find_uid(acl, uid, &entry); | |
204 | if (r <= 0) { | |
205 | ||
206 | if (acl_create_entry(&acl, &entry) < 0 || | |
207 | acl_set_tag_type(entry, ACL_USER) < 0 || | |
208 | acl_set_qualifier(entry, &uid) < 0) { | |
209 | log_warning("Failed to patch ACL on %s, ignoring: %m", f->path); | |
210 | goto finish; | |
211 | } | |
212 | } | |
213 | ||
214 | if (acl_get_permset(entry, &permset) < 0 || | |
215 | acl_add_perm(permset, ACL_READ) < 0 || | |
216 | acl_calc_mask(&acl) < 0) { | |
217 | log_warning("Failed to patch ACL on %s, ignoring: %m", f->path); | |
218 | goto finish; | |
219 | } | |
220 | ||
221 | if (acl_set_fd(f->fd, acl) < 0) | |
222 | log_warning("Failed to set ACL on %s, ignoring: %m", f->path); | |
223 | ||
224 | finish: | |
225 | acl_free(acl); | |
226 | } | |
227 | ||
228 | static JournalFile* find_journal(Server *s, uid_t uid) { | |
229 | char *p; | |
230 | int r; | |
231 | JournalFile *f; | |
3fbf9cbb LP |
232 | char ids[33]; |
233 | sd_id128_t machine; | |
f4b47811 LP |
234 | |
235 | assert(s); | |
236 | ||
cf244689 LP |
237 | /* We split up user logs only on /var, not on /run. If the |
238 | * runtime file is open, we write to it exclusively, in order | |
239 | * to guarantee proper order as soon as we flush /run to | |
240 | * /var and close the runtime file. */ | |
241 | ||
242 | if (s->runtime_journal) | |
f4b47811 LP |
243 | return s->runtime_journal; |
244 | ||
245 | if (uid <= 0) | |
246 | return s->system_journal; | |
247 | ||
3fbf9cbb LP |
248 | r = sd_id128_get_machine(&machine); |
249 | if (r < 0) | |
250 | return s->system_journal; | |
251 | ||
f4b47811 LP |
252 | f = hashmap_get(s->user_journals, UINT32_TO_PTR(uid)); |
253 | if (f) | |
254 | return f; | |
255 | ||
3fbf9cbb | 256 | if (asprintf(&p, "/var/log/journal/%s/user-%lu.journal", sd_id128_to_string(machine, ids), (unsigned long) uid) < 0) |
f4b47811 LP |
257 | return s->system_journal; |
258 | ||
cab8ac60 LP |
259 | while (hashmap_size(s->user_journals) >= USER_JOURNALS_MAX) { |
260 | /* Too many open? Then let's close one */ | |
261 | f = hashmap_steal_first(s->user_journals); | |
262 | assert(f); | |
263 | journal_file_close(f); | |
264 | } | |
265 | ||
c2373f84 | 266 | r = journal_file_open(p, O_RDWR|O_CREAT, 0640, s->system_journal, &f); |
f4b47811 LP |
267 | free(p); |
268 | ||
269 | if (r < 0) | |
270 | return s->system_journal; | |
271 | ||
272 | fix_perms(f, uid); | |
babfc091 | 273 | f->metrics = s->system_metrics; |
807e17f0 | 274 | f->compress = s->compress; |
f4b47811 LP |
275 | |
276 | r = hashmap_put(s->user_journals, UINT32_TO_PTR(uid), f); | |
277 | if (r < 0) { | |
278 | journal_file_close(f); | |
279 | return s->system_journal; | |
280 | } | |
281 | ||
282 | return f; | |
283 | } | |
284 | ||
b1a0ab71 LP |
285 | static void server_rotate(Server *s) { |
286 | JournalFile *f; | |
bc85bfee | 287 | void *k; |
b1a0ab71 | 288 | Iterator i; |
bc85bfee | 289 | int r; |
bc85bfee LP |
290 | |
291 | log_info("Rotating..."); | |
292 | ||
293 | if (s->runtime_journal) { | |
294 | r = journal_file_rotate(&s->runtime_journal); | |
295 | if (r < 0) | |
296 | log_error("Failed to rotate %s: %s", s->runtime_journal->path, strerror(-r)); | |
297 | } | |
298 | ||
299 | if (s->system_journal) { | |
300 | r = journal_file_rotate(&s->system_journal); | |
301 | if (r < 0) | |
302 | log_error("Failed to rotate %s: %s", s->system_journal->path, strerror(-r)); | |
303 | } | |
304 | ||
305 | HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) { | |
306 | r = journal_file_rotate(&f); | |
307 | if (r < 0) | |
308 | log_error("Failed to rotate %s: %s", f->path, strerror(-r)); | |
309 | else | |
310 | hashmap_replace(s->user_journals, k, f); | |
311 | } | |
b1a0ab71 LP |
312 | } |
313 | ||
314 | static void server_vacuum(Server *s) { | |
315 | char *p; | |
316 | char ids[33]; | |
317 | sd_id128_t machine; | |
318 | int r; | |
bc85bfee LP |
319 | |
320 | log_info("Vacuuming..."); | |
321 | ||
322 | r = sd_id128_get_machine(&machine); | |
323 | if (r < 0) { | |
324 | log_error("Failed to get machine ID: %s", strerror(-r)); | |
325 | return; | |
326 | } | |
327 | ||
babfc091 | 328 | sd_id128_to_string(machine, ids); |
bc85bfee | 329 | |
babfc091 LP |
330 | if (s->system_journal) { |
331 | if (asprintf(&p, "/var/log/journal/%s", ids) < 0) { | |
332 | log_error("Out of memory."); | |
333 | return; | |
334 | } | |
bc85bfee | 335 | |
babfc091 LP |
336 | r = journal_directory_vacuum(p, s->system_metrics.max_use, s->system_metrics.keep_free); |
337 | if (r < 0 && r != -ENOENT) | |
338 | log_error("Failed to vacuum %s: %s", p, strerror(-r)); | |
339 | free(p); | |
bc85bfee LP |
340 | } |
341 | ||
babfc091 LP |
342 | |
343 | if (s->runtime_journal) { | |
344 | if (asprintf(&p, "/run/log/journal/%s", ids) < 0) { | |
345 | log_error("Out of memory."); | |
346 | return; | |
347 | } | |
348 | ||
349 | r = journal_directory_vacuum(p, s->runtime_metrics.max_use, s->runtime_metrics.keep_free); | |
350 | if (r < 0 && r != -ENOENT) | |
351 | log_error("Failed to vacuum %s: %s", p, strerror(-r)); | |
352 | free(p); | |
353 | } | |
9cfb57c9 LP |
354 | |
355 | s->cached_available_space_timestamp = 0; | |
bc85bfee LP |
356 | } |
357 | ||
6e409ce1 LP |
358 | static char *shortened_cgroup_path(pid_t pid) { |
359 | int r; | |
360 | char *process_path, *init_path, *path; | |
361 | ||
362 | assert(pid > 0); | |
363 | ||
364 | r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &process_path); | |
365 | if (r < 0) | |
366 | return NULL; | |
367 | ||
368 | r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &init_path); | |
369 | if (r < 0) { | |
370 | free(process_path); | |
371 | return NULL; | |
372 | } | |
373 | ||
bad75c27 LP |
374 | if (endswith(init_path, "/system")) |
375 | init_path[strlen(init_path) - 7] = 0; | |
376 | else if (streq(init_path, "/")) | |
6e409ce1 LP |
377 | init_path[0] = 0; |
378 | ||
783d2675 LP |
379 | if (startswith(process_path, init_path)) { |
380 | char *p; | |
381 | ||
382 | p = strdup(process_path + strlen(init_path)); | |
383 | if (!p) { | |
384 | free(process_path); | |
385 | free(init_path); | |
386 | return NULL; | |
387 | } | |
388 | path = p; | |
389 | } else { | |
6e409ce1 | 390 | path = process_path; |
783d2675 LP |
391 | process_path = NULL; |
392 | } | |
6e409ce1 | 393 | |
783d2675 | 394 | free(process_path); |
6e409ce1 LP |
395 | free(init_path); |
396 | ||
397 | return path; | |
398 | } | |
399 | ||
400 | static void dispatch_message_real(Server *s, | |
401 | struct iovec *iovec, unsigned n, unsigned m, | |
402 | struct ucred *ucred, | |
403 | struct timeval *tv) { | |
404 | ||
7f3e6257 | 405 | char *pid = NULL, *uid = NULL, *gid = NULL, |
87d2c1ff LP |
406 | *source_time = NULL, *boot_id = NULL, *machine_id = NULL, |
407 | *comm = NULL, *cmdline = NULL, *hostname = NULL, | |
408 | *audit_session = NULL, *audit_loginuid = NULL, | |
85d83bf4 | 409 | *exe = NULL, *cgroup = NULL, *session = NULL, |
94fb446e | 410 | *owner_uid = NULL, *unit = NULL; |
7f3e6257 | 411 | |
87d2c1ff LP |
412 | char idbuf[33]; |
413 | sd_id128_t id; | |
414 | int r; | |
415 | char *t; | |
de190aef | 416 | uid_t loginuid = 0, realuid = 0; |
f4b47811 | 417 | JournalFile *f; |
bc85bfee | 418 | bool vacuumed = false; |
87d2c1ff | 419 | |
7f3e6257 | 420 | assert(s); |
6e409ce1 LP |
421 | assert(iovec); |
422 | assert(n > 0); | |
224f2ee2 | 423 | assert(n + N_IOVEC_META_FIELDS <= m); |
87d2c1ff LP |
424 | |
425 | if (ucred) { | |
85d83bf4 LP |
426 | uint32_t audit; |
427 | uid_t owner; | |
87d2c1ff | 428 | |
de190aef LP |
429 | realuid = ucred->uid; |
430 | ||
431 | if (asprintf(&pid, "_PID=%lu", (unsigned long) ucred->pid) >= 0) | |
87d2c1ff LP |
432 | IOVEC_SET_STRING(iovec[n++], pid); |
433 | ||
de190aef | 434 | if (asprintf(&uid, "_UID=%lu", (unsigned long) ucred->uid) >= 0) |
87d2c1ff LP |
435 | IOVEC_SET_STRING(iovec[n++], uid); |
436 | ||
de190aef | 437 | if (asprintf(&gid, "_GID=%lu", (unsigned long) ucred->gid) >= 0) |
87d2c1ff LP |
438 | IOVEC_SET_STRING(iovec[n++], gid); |
439 | ||
440 | r = get_process_comm(ucred->pid, &t); | |
441 | if (r >= 0) { | |
de190aef | 442 | comm = strappend("_COMM=", t); |
85d83bf4 LP |
443 | free(t); |
444 | ||
87d2c1ff LP |
445 | if (comm) |
446 | IOVEC_SET_STRING(iovec[n++], comm); | |
87d2c1ff LP |
447 | } |
448 | ||
449 | r = get_process_exe(ucred->pid, &t); | |
450 | if (r >= 0) { | |
de190aef | 451 | exe = strappend("_EXE=", t); |
85d83bf4 LP |
452 | free(t); |
453 | ||
87d2c1ff LP |
454 | if (comm) |
455 | IOVEC_SET_STRING(iovec[n++], exe); | |
87d2c1ff LP |
456 | } |
457 | ||
458 | r = get_process_cmdline(ucred->pid, LINE_MAX, false, &t); | |
459 | if (r >= 0) { | |
de190aef | 460 | cmdline = strappend("_CMDLINE=", t); |
85d83bf4 LP |
461 | free(t); |
462 | ||
87d2c1ff LP |
463 | if (cmdline) |
464 | IOVEC_SET_STRING(iovec[n++], cmdline); | |
87d2c1ff LP |
465 | } |
466 | ||
85d83bf4 | 467 | r = audit_session_from_pid(ucred->pid, &audit); |
87d2c1ff | 468 | if (r >= 0) |
85d83bf4 | 469 | if (asprintf(&audit_session, "_AUDIT_SESSION=%lu", (unsigned long) audit) >= 0) |
87d2c1ff LP |
470 | IOVEC_SET_STRING(iovec[n++], audit_session); |
471 | ||
472 | r = audit_loginuid_from_pid(ucred->pid, &loginuid); | |
473 | if (r >= 0) | |
de190aef | 474 | if (asprintf(&audit_loginuid, "_AUDIT_LOGINUID=%lu", (unsigned long) loginuid) >= 0) |
87d2c1ff | 475 | IOVEC_SET_STRING(iovec[n++], audit_loginuid); |
69e5d42d | 476 | |
85d83bf4 LP |
477 | t = shortened_cgroup_path(ucred->pid); |
478 | if (t) { | |
479 | cgroup = strappend("_SYSTEMD_CGROUP=", t); | |
480 | free(t); | |
481 | ||
69e5d42d LP |
482 | if (cgroup) |
483 | IOVEC_SET_STRING(iovec[n++], cgroup); | |
85d83bf4 LP |
484 | } |
485 | ||
486 | if (sd_pid_get_session(ucred->pid, &t) >= 0) { | |
487 | session = strappend("_SYSTEMD_SESSION=", t); | |
488 | free(t); | |
489 | ||
490 | if (session) | |
491 | IOVEC_SET_STRING(iovec[n++], session); | |
492 | } | |
6e409ce1 | 493 | |
94fb446e LP |
494 | if (sd_pid_get_unit(ucred->pid, &t) >= 0) { |
495 | unit = strappend("_SYSTEMD_UNIT=", t); | |
85d83bf4 LP |
496 | free(t); |
497 | ||
94fb446e LP |
498 | if (unit) |
499 | IOVEC_SET_STRING(iovec[n++], unit); | |
69e5d42d | 500 | } |
85d83bf4 LP |
501 | |
502 | if (sd_pid_get_owner_uid(ucred->uid, &owner) >= 0) | |
503 | if (asprintf(&owner_uid, "_SYSTEMD_OWNER_UID=%lu", (unsigned long) owner) >= 0) | |
504 | IOVEC_SET_STRING(iovec[n++], owner_uid); | |
87d2c1ff LP |
505 | } |
506 | ||
507 | if (tv) { | |
de190aef | 508 | if (asprintf(&source_time, "_SOURCE_REALTIME_TIMESTAMP=%llu", |
87d2c1ff LP |
509 | (unsigned long long) timeval_load(tv)) >= 0) |
510 | IOVEC_SET_STRING(iovec[n++], source_time); | |
511 | } | |
512 | ||
ed49ef3f LP |
513 | /* Note that strictly speaking storing the boot id here is |
514 | * redundant since the entry includes this in-line | |
515 | * anyway. However, we need this indexed, too. */ | |
87d2c1ff LP |
516 | r = sd_id128_get_boot(&id); |
517 | if (r >= 0) | |
de190aef | 518 | if (asprintf(&boot_id, "_BOOT_ID=%s", sd_id128_to_string(id, idbuf)) >= 0) |
87d2c1ff LP |
519 | IOVEC_SET_STRING(iovec[n++], boot_id); |
520 | ||
521 | r = sd_id128_get_machine(&id); | |
522 | if (r >= 0) | |
de190aef | 523 | if (asprintf(&machine_id, "_MACHINE_ID=%s", sd_id128_to_string(id, idbuf)) >= 0) |
87d2c1ff LP |
524 | IOVEC_SET_STRING(iovec[n++], machine_id); |
525 | ||
526 | t = gethostname_malloc(); | |
527 | if (t) { | |
de190aef | 528 | hostname = strappend("_HOSTNAME=", t); |
85d83bf4 | 529 | free(t); |
87d2c1ff LP |
530 | if (hostname) |
531 | IOVEC_SET_STRING(iovec[n++], hostname); | |
87d2c1ff LP |
532 | } |
533 | ||
7f3e6257 LP |
534 | assert(n <= m); |
535 | ||
cf244689 LP |
536 | server_flush_to_var(s); |
537 | ||
bc85bfee | 538 | retry: |
de190aef | 539 | f = find_journal(s, realuid == 0 ? 0 : loginuid); |
f4b47811 LP |
540 | if (!f) |
541 | log_warning("Dropping message, as we can't find a place to store the data."); | |
542 | else { | |
c2373f84 | 543 | r = journal_file_append_entry(f, NULL, iovec, n, &s->seqnum, NULL, NULL); |
87d2c1ff | 544 | |
bc85bfee LP |
545 | if (r == -E2BIG && !vacuumed) { |
546 | log_info("Allocation limit reached."); | |
547 | ||
b1a0ab71 | 548 | server_rotate(s); |
bc85bfee LP |
549 | server_vacuum(s); |
550 | vacuumed = true; | |
551 | ||
552 | log_info("Retrying write."); | |
553 | goto retry; | |
554 | } | |
555 | ||
f4b47811 LP |
556 | if (r < 0) |
557 | log_error("Failed to write entry, ignoring: %s", strerror(-r)); | |
558 | } | |
87d2c1ff | 559 | |
87d2c1ff LP |
560 | free(pid); |
561 | free(uid); | |
562 | free(gid); | |
563 | free(comm); | |
69e5d42d | 564 | free(exe); |
87d2c1ff LP |
565 | free(cmdline); |
566 | free(source_time); | |
567 | free(boot_id); | |
568 | free(machine_id); | |
569 | free(hostname); | |
570 | free(audit_session); | |
571 | free(audit_loginuid); | |
7f3e6257 | 572 | free(cgroup); |
85d83bf4 LP |
573 | free(session); |
574 | free(owner_uid); | |
94fb446e | 575 | free(unit); |
7f3e6257 LP |
576 | } |
577 | ||
224f2ee2 LP |
578 | static void driver_message(Server *s, sd_id128_t message_id, const char *format, ...) { |
579 | char mid[11 + 32 + 1]; | |
580 | char buffer[16 + LINE_MAX + 1]; | |
581 | struct iovec iovec[N_IOVEC_META_FIELDS + 3]; | |
582 | int n = 0; | |
583 | va_list ap; | |
584 | struct ucred ucred; | |
585 | ||
586 | assert(s); | |
587 | assert(format); | |
588 | ||
589 | IOVEC_SET_STRING(iovec[n++], "PRIORITY=5"); | |
590 | ||
591 | memcpy(buffer, "MESSAGE=", 8); | |
592 | va_start(ap, format); | |
593 | vsnprintf(buffer + 8, sizeof(buffer) - 8, format, ap); | |
594 | va_end(ap); | |
595 | char_array_0(buffer); | |
596 | IOVEC_SET_STRING(iovec[n++], buffer); | |
597 | ||
598 | snprintf(mid, sizeof(mid), "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(message_id)); | |
599 | char_array_0(mid); | |
600 | IOVEC_SET_STRING(iovec[n++], mid); | |
601 | ||
602 | zero(ucred); | |
603 | ucred.pid = getpid(); | |
604 | ucred.uid = getuid(); | |
605 | ucred.gid = getgid(); | |
606 | ||
607 | dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &ucred, NULL); | |
608 | } | |
609 | ||
6e409ce1 LP |
610 | static void dispatch_message(Server *s, |
611 | struct iovec *iovec, unsigned n, unsigned m, | |
612 | struct ucred *ucred, | |
613 | struct timeval *tv, | |
614 | int priority) { | |
615 | int rl; | |
783d2675 | 616 | char *path = NULL, *c; |
6e409ce1 LP |
617 | |
618 | assert(s); | |
619 | assert(iovec || n == 0); | |
620 | ||
621 | if (n == 0) | |
622 | return; | |
623 | ||
624 | if (!ucred) | |
625 | goto finish; | |
626 | ||
627 | path = shortened_cgroup_path(ucred->pid); | |
628 | if (!path) | |
629 | goto finish; | |
630 | ||
631 | /* example: /user/lennart/3/foobar | |
632 | * /system/dbus.service/foobar | |
633 | * | |
634 | * So let's cut of everything past the third /, since that is | |
635 | * wher user directories start */ | |
636 | ||
637 | c = strchr(path, '/'); | |
638 | if (c) { | |
639 | c = strchr(c+1, '/'); | |
640 | if (c) { | |
641 | c = strchr(c+1, '/'); | |
642 | if (c) | |
643 | *c = 0; | |
644 | } | |
645 | } | |
646 | ||
224f2ee2 | 647 | rl = journal_rate_limit_test(s->rate_limit, path, priority & LOG_PRIMASK, available_space(s)); |
6e409ce1 LP |
648 | |
649 | if (rl == 0) { | |
650 | free(path); | |
651 | return; | |
652 | } | |
653 | ||
224f2ee2 LP |
654 | /* Write a suppression message if we suppressed something */ |
655 | if (rl > 1) | |
656 | driver_message(s, SD_MESSAGE_JOURNAL_DROPPED, "Suppressed %u messages from %s", rl - 1, path); | |
657 | ||
658 | free(path); | |
659 | ||
660 | finish: | |
661 | dispatch_message_real(s, iovec, n, m, ucred, tv); | |
662 | } | |
663 | ||
664 | static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, struct ucred *ucred, struct timeval *tv) { | |
665 | struct msghdr msghdr; | |
666 | struct cmsghdr *cmsg; | |
667 | union { | |
668 | struct cmsghdr cmsghdr; | |
669 | uint8_t buf[CMSG_SPACE(sizeof(struct ucred))]; | |
670 | } control; | |
671 | union sockaddr_union sa; | |
672 | ||
673 | assert(s); | |
674 | assert(iovec); | |
675 | assert(n_iovec > 0); | |
676 | ||
677 | zero(msghdr); | |
678 | msghdr.msg_iov = (struct iovec*) iovec; | |
679 | msghdr.msg_iovlen = n_iovec; | |
680 | ||
681 | zero(sa); | |
682 | sa.un.sun_family = AF_UNIX; | |
259d2e76 | 683 | strncpy(sa.un.sun_path, "/run/systemd/journal/syslog", sizeof(sa.un.sun_path)); |
224f2ee2 LP |
684 | msghdr.msg_name = &sa; |
685 | msghdr.msg_namelen = offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path); | |
686 | ||
687 | if (ucred) { | |
688 | zero(control); | |
689 | msghdr.msg_control = &control; | |
690 | msghdr.msg_controllen = sizeof(control); | |
691 | ||
692 | cmsg = CMSG_FIRSTHDR(&msghdr); | |
693 | cmsg->cmsg_level = SOL_SOCKET; | |
694 | cmsg->cmsg_type = SCM_CREDENTIALS; | |
695 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred)); | |
696 | memcpy(CMSG_DATA(cmsg), ucred, sizeof(struct ucred)); | |
697 | msghdr.msg_controllen = cmsg->cmsg_len; | |
698 | } | |
699 | ||
700 | /* Forward the syslog message we received via /dev/log to | |
701 | * /run/systemd/syslog. Unfortunately we currently can't set | |
702 | * the SO_TIMESTAMP auxiliary data, and hence we don't. */ | |
6e409ce1 | 703 | |
224f2ee2 LP |
704 | if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0) |
705 | return; | |
6e409ce1 | 706 | |
224f2ee2 LP |
707 | if (ucred && errno == ESRCH) { |
708 | struct ucred u; | |
6e409ce1 | 709 | |
224f2ee2 LP |
710 | /* Hmm, presumably the sender process vanished |
711 | * by now, so let's fix it as good as we | |
712 | * can, and retry */ | |
6e409ce1 | 713 | |
224f2ee2 LP |
714 | u = *ucred; |
715 | u.pid = getpid(); | |
716 | memcpy(CMSG_DATA(cmsg), &u, sizeof(struct ucred)); | |
717 | ||
718 | if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0) | |
719 | return; | |
6e409ce1 LP |
720 | } |
721 | ||
224f2ee2 LP |
722 | log_debug("Failed to forward syslog message: %m"); |
723 | } | |
724 | ||
725 | static void forward_syslog_raw(Server *s, const char *buffer, struct ucred *ucred, struct timeval *tv) { | |
726 | struct iovec iovec; | |
727 | ||
728 | assert(s); | |
729 | assert(buffer); | |
730 | ||
731 | IOVEC_SET_STRING(iovec, buffer); | |
732 | forward_syslog_iovec(s, &iovec, 1, ucred, tv); | |
733 | } | |
734 | ||
735 | static void forward_syslog(Server *s, int priority, const char *tag, const char *message, struct ucred *ucred, struct timeval *tv) { | |
736 | struct iovec iovec[5]; | |
737 | char header_priority[6], header_time[64], header_pid[16]; | |
738 | int n = 0; | |
739 | time_t t; | |
740 | struct tm *tm; | |
741 | char *tag_buf = NULL; | |
742 | ||
743 | assert(s); | |
744 | assert(priority >= 0); | |
745 | assert(priority <= 999); | |
746 | assert(message); | |
747 | ||
748 | /* First: priority field */ | |
749 | snprintf(header_priority, sizeof(header_priority), "<%i>", priority); | |
750 | char_array_0(header_priority); | |
751 | IOVEC_SET_STRING(iovec[n++], header_priority); | |
752 | ||
753 | /* Second: timestamp */ | |
754 | t = tv ? tv->tv_sec : ((time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC)); | |
755 | tm = localtime(&t); | |
756 | if (!tm) | |
757 | return; | |
758 | if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0) | |
759 | return; | |
760 | IOVEC_SET_STRING(iovec[n++], header_time); | |
761 | ||
762 | /* Third: tag and PID */ | |
763 | if (ucred) { | |
764 | if (!tag) { | |
765 | get_process_comm(ucred->pid, &tag_buf); | |
766 | tag = tag_buf; | |
767 | } | |
768 | ||
769 | snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid); | |
770 | char_array_0(header_pid); | |
771 | ||
772 | if (tag) | |
773 | IOVEC_SET_STRING(iovec[n++], tag); | |
774 | ||
775 | IOVEC_SET_STRING(iovec[n++], header_pid); | |
776 | } else if (tag) { | |
777 | IOVEC_SET_STRING(iovec[n++], tag); | |
778 | IOVEC_SET_STRING(iovec[n++], ": "); | |
779 | } | |
780 | ||
781 | /* Fourth: message */ | |
782 | IOVEC_SET_STRING(iovec[n++], message); | |
783 | ||
784 | forward_syslog_iovec(s, iovec, n, ucred, tv); | |
785 | ||
786 | free(tag_buf); | |
787 | } | |
788 | ||
789 | static int fixup_priority(int priority) { | |
790 | ||
791 | if ((priority & LOG_FACMASK) == 0) | |
792 | return (priority & LOG_PRIMASK) | LOG_USER; | |
793 | ||
794 | return priority; | |
795 | } | |
796 | ||
797 | static void forward_kmsg(Server *s, int priority, const char *tag, const char *message, struct ucred *ucred) { | |
798 | struct iovec iovec[5]; | |
799 | char header_priority[6], header_pid[16]; | |
800 | int n = 0; | |
801 | char *tag_buf = NULL; | |
802 | int fd; | |
803 | ||
804 | assert(s); | |
805 | assert(priority >= 0); | |
806 | assert(priority <= 999); | |
807 | assert(message); | |
808 | ||
809 | /* Never allow messages with kernel facility to be written to | |
810 | * kmsg, regardless where the data comes from. */ | |
811 | priority = fixup_priority(priority); | |
812 | ||
813 | /* First: priority field */ | |
814 | snprintf(header_priority, sizeof(header_priority), "<%i>", priority); | |
815 | char_array_0(header_priority); | |
816 | IOVEC_SET_STRING(iovec[n++], header_priority); | |
817 | ||
818 | /* Second: tag and PID */ | |
819 | if (ucred) { | |
820 | if (!tag) { | |
821 | get_process_comm(ucred->pid, &tag_buf); | |
822 | tag = tag_buf; | |
823 | } | |
824 | ||
825 | snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid); | |
826 | char_array_0(header_pid); | |
827 | ||
828 | if (tag) | |
829 | IOVEC_SET_STRING(iovec[n++], tag); | |
830 | ||
831 | IOVEC_SET_STRING(iovec[n++], header_pid); | |
832 | } else if (tag) { | |
833 | IOVEC_SET_STRING(iovec[n++], tag); | |
834 | IOVEC_SET_STRING(iovec[n++], ": "); | |
835 | } | |
836 | ||
837 | /* Fourth: message */ | |
838 | IOVEC_SET_STRING(iovec[n++], message); | |
839 | IOVEC_SET_STRING(iovec[n++], "\n"); | |
840 | ||
841 | fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC); | |
842 | if (fd < 0) { | |
843 | log_debug("Failed to open /dev/kmsg for logging: %s", strerror(errno)); | |
844 | goto finish; | |
845 | } | |
846 | ||
847 | if (writev(fd, iovec, n) < 0) | |
848 | log_debug("Failed to write to /dev/kmsg for logging: %s", strerror(errno)); | |
849 | ||
850 | close_nointr_nofail(fd); | |
6e409ce1 LP |
851 | |
852 | finish: | |
224f2ee2 LP |
853 | free(tag_buf); |
854 | } | |
855 | ||
856 | static void forward_console(Server *s, const char *tag, const char *message, struct ucred *ucred) { | |
857 | struct iovec iovec[4]; | |
858 | char header_pid[16]; | |
859 | int n = 0, fd; | |
860 | char *tag_buf = NULL; | |
861 | ||
862 | assert(s); | |
863 | assert(message); | |
864 | ||
865 | /* First: tag and PID */ | |
866 | if (ucred) { | |
867 | if (!tag) { | |
868 | get_process_comm(ucred->pid, &tag_buf); | |
869 | tag = tag_buf; | |
870 | } | |
871 | ||
872 | snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid); | |
873 | char_array_0(header_pid); | |
874 | ||
875 | if (tag) | |
876 | IOVEC_SET_STRING(iovec[n++], tag); | |
877 | ||
878 | IOVEC_SET_STRING(iovec[n++], header_pid); | |
879 | } else if (tag) { | |
880 | IOVEC_SET_STRING(iovec[n++], tag); | |
881 | IOVEC_SET_STRING(iovec[n++], ": "); | |
882 | } | |
883 | ||
884 | /* Third: message */ | |
885 | IOVEC_SET_STRING(iovec[n++], message); | |
886 | IOVEC_SET_STRING(iovec[n++], "\n"); | |
887 | ||
888 | fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); | |
889 | if (fd < 0) { | |
890 | log_debug("Failed to open /dev/console for logging: %s", strerror(errno)); | |
891 | goto finish; | |
892 | } | |
893 | ||
894 | if (writev(fd, iovec, n) < 0) | |
895 | log_debug("Failed to write to /dev/console for logging: %s", strerror(errno)); | |
896 | ||
897 | close_nointr_nofail(fd); | |
898 | ||
899 | finish: | |
900 | free(tag_buf); | |
901 | } | |
902 | ||
903 | static void read_tag(const char **buf, char **tag) { | |
904 | const char *p; | |
905 | char *t; | |
906 | size_t l, e; | |
907 | ||
908 | assert(buf); | |
909 | assert(tag); | |
910 | ||
911 | p = *buf; | |
912 | ||
913 | p += strspn(p, WHITESPACE); | |
914 | l = strcspn(p, WHITESPACE); | |
915 | ||
916 | if (l <= 0 || | |
917 | p[l-1] != ':') | |
918 | return; | |
919 | ||
920 | e = l; | |
921 | l--; | |
922 | ||
923 | if (p[l-1] == ']') { | |
924 | size_t k = l-1; | |
925 | ||
926 | for (;;) { | |
927 | ||
928 | if (p[k] == '[') { | |
929 | l = k; | |
930 | break; | |
931 | } | |
932 | ||
933 | if (k == 0) | |
934 | break; | |
935 | ||
936 | k--; | |
937 | } | |
938 | } | |
939 | ||
940 | t = strndup(p, l); | |
941 | if (t) | |
942 | *tag = t; | |
943 | ||
944 | *buf = p + e; | |
945 | *buf += strspn(*buf, WHITESPACE); | |
6e409ce1 LP |
946 | } |
947 | ||
7f3e6257 | 948 | static void process_syslog_message(Server *s, const char *buf, struct ucred *ucred, struct timeval *tv) { |
224f2ee2 LP |
949 | char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_tag = NULL; |
950 | struct iovec iovec[N_IOVEC_META_FIELDS + 4]; | |
7f3e6257 LP |
951 | unsigned n = 0; |
952 | int priority = LOG_USER | LOG_INFO; | |
224f2ee2 | 953 | char *tag = NULL; |
7f3e6257 LP |
954 | |
955 | assert(s); | |
956 | assert(buf); | |
957 | ||
224f2ee2 LP |
958 | if (s->forward_to_syslog) |
959 | forward_syslog_raw(s, buf, ucred, tv); | |
960 | ||
7f3e6257 LP |
961 | parse_syslog_priority((char**) &buf, &priority); |
962 | skip_syslog_date((char**) &buf); | |
224f2ee2 LP |
963 | read_tag(&buf, &tag); |
964 | ||
965 | if (s->forward_to_kmsg) | |
966 | forward_kmsg(s, priority, tag, buf, ucred); | |
967 | ||
968 | if (s->forward_to_console) | |
969 | forward_console(s, tag, buf, ucred); | |
7f3e6257 LP |
970 | |
971 | if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0) | |
972 | IOVEC_SET_STRING(iovec[n++], syslog_priority); | |
973 | ||
224f2ee2 LP |
974 | if (priority & LOG_FACMASK) |
975 | if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0) | |
976 | IOVEC_SET_STRING(iovec[n++], syslog_facility); | |
977 | ||
978 | if (tag) { | |
979 | syslog_tag = strappend("SYSLOG_TAG=", tag); | |
980 | if (syslog_tag) | |
981 | IOVEC_SET_STRING(iovec[n++], syslog_tag); | |
982 | } | |
7f3e6257 LP |
983 | |
984 | message = strappend("MESSAGE=", buf); | |
985 | if (message) | |
986 | IOVEC_SET_STRING(iovec[n++], message); | |
987 | ||
224f2ee2 | 988 | dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, priority); |
7f3e6257 LP |
989 | |
990 | free(message); | |
224f2ee2 | 991 | free(tag); |
87d2c1ff | 992 | free(syslog_priority); |
224f2ee2 LP |
993 | free(syslog_facility); |
994 | free(syslog_tag); | |
7f3e6257 LP |
995 | } |
996 | ||
6ad1d1c3 LP |
997 | static bool valid_user_field(const char *p, size_t l) { |
998 | const char *a; | |
999 | ||
1000 | /* We kinda enforce POSIX syntax recommendations for | |
1001 | environment variables here, but make a couple of additional | |
1002 | requirements. | |
1003 | ||
1004 | http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */ | |
1005 | ||
1006 | /* No empty field names */ | |
1007 | if (l <= 0) | |
1008 | return false; | |
1009 | ||
1010 | /* Don't allow names longer than 64 chars */ | |
1011 | if (l > 64) | |
1012 | return false; | |
1013 | ||
1014 | /* Variables starting with an underscore are protected */ | |
1015 | if (p[0] == '_') | |
1016 | return false; | |
1017 | ||
1018 | /* Don't allow digits as first character */ | |
1019 | if (p[0] >= '0' && p[0] <= '9') | |
1020 | return false; | |
1021 | ||
1022 | /* Only allow A-Z0-9 and '_' */ | |
1023 | for (a = p; a < p + l; a++) | |
1024 | if (!((*a >= 'A' && *a <= 'Z') || | |
1025 | (*a >= '0' && *a <= '9') || | |
1026 | *a == '_')) | |
1027 | return false; | |
1028 | ||
1029 | return true; | |
1030 | } | |
1031 | ||
7f3e6257 LP |
1032 | static void process_native_message(Server *s, const void *buffer, size_t buffer_size, struct ucred *ucred, struct timeval *tv) { |
1033 | struct iovec *iovec = NULL; | |
1034 | unsigned n = 0, m = 0, j; | |
1035 | const char *p; | |
1036 | size_t remaining; | |
6e409ce1 | 1037 | int priority = LOG_INFO; |
224f2ee2 | 1038 | char *tag = NULL, *message = NULL; |
7f3e6257 LP |
1039 | |
1040 | assert(s); | |
1041 | assert(buffer || n == 0); | |
1042 | ||
1043 | p = buffer; | |
1044 | remaining = buffer_size; | |
1045 | ||
1046 | while (remaining > 0) { | |
1047 | const char *e, *q; | |
1048 | ||
1049 | e = memchr(p, '\n', remaining); | |
1050 | ||
1051 | if (!e) { | |
1052 | /* Trailing noise, let's ignore it, and flush what we collected */ | |
1053 | log_debug("Received message with trailing noise, ignoring."); | |
1054 | break; | |
1055 | } | |
1056 | ||
1057 | if (e == p) { | |
1058 | /* Entry separator */ | |
6e409ce1 | 1059 | dispatch_message(s, iovec, n, m, ucred, tv, priority); |
7f3e6257 | 1060 | n = 0; |
6e409ce1 | 1061 | priority = LOG_INFO; |
7f3e6257 LP |
1062 | |
1063 | p++; | |
1064 | remaining--; | |
1065 | continue; | |
1066 | } | |
1067 | ||
6ad1d1c3 LP |
1068 | if (*p == '.' || *p == '#') { |
1069 | /* Ignore control commands for now, and | |
1070 | * comments too. */ | |
7f3e6257 LP |
1071 | remaining -= (e - p) + 1; |
1072 | p = e + 1; | |
1073 | continue; | |
1074 | } | |
1075 | ||
1076 | /* A property follows */ | |
1077 | ||
224f2ee2 | 1078 | if (n+N_IOVEC_META_FIELDS >= m) { |
7f3e6257 LP |
1079 | struct iovec *c; |
1080 | unsigned u; | |
1081 | ||
224f2ee2 | 1082 | u = MAX((n+N_IOVEC_META_FIELDS) * 2U, 4U); |
7f3e6257 LP |
1083 | c = realloc(iovec, u * sizeof(struct iovec)); |
1084 | if (!c) { | |
1085 | log_error("Out of memory"); | |
1086 | break; | |
1087 | } | |
1088 | ||
1089 | iovec = c; | |
1090 | m = u; | |
1091 | } | |
1092 | ||
1093 | q = memchr(p, '=', e - p); | |
1094 | if (q) { | |
6ad1d1c3 | 1095 | if (valid_user_field(p, q - p)) { |
224f2ee2 LP |
1096 | size_t l; |
1097 | ||
1098 | l = e - p; | |
1099 | ||
2b0ba69b LP |
1100 | /* If the field name starts with an |
1101 | * underscore, skip the variable, | |
1102 | * since that indidates a trusted | |
1103 | * field */ | |
1104 | iovec[n].iov_base = (char*) p; | |
224f2ee2 | 1105 | iovec[n].iov_len = l; |
2b0ba69b | 1106 | n++; |
6e409ce1 LP |
1107 | |
1108 | /* We need to determine the priority | |
1109 | * of this entry for the rate limiting | |
1110 | * logic */ | |
224f2ee2 LP |
1111 | if (l == 10 && |
1112 | memcmp(p, "PRIORITY=", 9) == 0 && | |
1113 | p[9] >= '0' && p[9] <= '9') | |
1114 | priority = (priority & LOG_FACMASK) | (p[9] - '0'); | |
1115 | ||
1116 | else if (l == 17 && | |
1117 | memcmp(p, "SYSLOG_FACILITY=", 16) == 0 && | |
1118 | p[16] >= '0' && p[16] <= '9') | |
1119 | priority = (priority & LOG_PRIMASK) | ((p[16] - '0') << 3); | |
1120 | ||
1121 | else if (l == 18 && | |
1122 | memcmp(p, "SYSLOG_FACILITY=", 16) == 0 && | |
1123 | p[16] >= '0' && p[16] <= '9' && | |
1124 | p[17] >= '0' && p[17] <= '9') | |
1125 | priority = (priority & LOG_PRIMASK) | (((p[16] - '0')*10 + (p[17] - '0')) << 3); | |
1126 | ||
1127 | else if (l >= 12 && | |
1128 | memcmp(p, "SYSLOG_TAG=", 11) == 0) { | |
1129 | char *t; | |
1130 | ||
1131 | t = strndup(p + 11, l - 11); | |
1132 | if (t) { | |
1133 | free(tag); | |
1134 | tag = t; | |
1135 | } | |
1136 | } else if (l >= 8 && | |
1137 | memcmp(p, "MESSAGE=", 8) == 0) { | |
1138 | char *t; | |
1139 | ||
1140 | t = strndup(p + 8, l - 8); | |
1141 | if (t) { | |
1142 | free(message); | |
1143 | message = t; | |
1144 | } | |
1145 | } | |
2b0ba69b | 1146 | } |
7f3e6257 LP |
1147 | |
1148 | remaining -= (e - p) + 1; | |
1149 | p = e + 1; | |
1150 | continue; | |
1151 | } else { | |
1152 | uint64_t l; | |
1153 | char *k; | |
1154 | ||
1155 | if (remaining < e - p + 1 + sizeof(uint64_t) + 1) { | |
1156 | log_debug("Failed to parse message, ignoring."); | |
1157 | break; | |
1158 | } | |
1159 | ||
1160 | memcpy(&l, e + 1, sizeof(uint64_t)); | |
1161 | l = le64toh(l); | |
1162 | ||
1163 | if (remaining < e - p + 1 + sizeof(uint64_t) + l + 1 || | |
1164 | e[1+sizeof(uint64_t)+l] != '\n') { | |
1165 | log_debug("Failed to parse message, ignoring."); | |
1166 | break; | |
1167 | } | |
1168 | ||
1169 | k = malloc((e - p) + 1 + l); | |
1170 | if (!k) { | |
1171 | log_error("Out of memory"); | |
1172 | break; | |
1173 | } | |
1174 | ||
1175 | memcpy(k, p, e - p); | |
1176 | k[e - p] = '='; | |
1177 | memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l); | |
1178 | ||
6ad1d1c3 | 1179 | if (valid_user_field(p, e - p)) { |
2b0ba69b LP |
1180 | iovec[n].iov_base = k; |
1181 | iovec[n].iov_len = (e - p) + 1 + l; | |
1182 | n++; | |
1183 | } else | |
1184 | free(k); | |
7f3e6257 LP |
1185 | |
1186 | remaining -= (e - p) + 1 + sizeof(uint64_t) + l + 1; | |
1187 | p = e + 1 + sizeof(uint64_t) + l + 1; | |
1188 | } | |
1189 | } | |
1190 | ||
224f2ee2 LP |
1191 | if (message) { |
1192 | if (s->forward_to_syslog) | |
1193 | forward_syslog(s, priority, tag, message, ucred, tv); | |
1194 | ||
1195 | if (s->forward_to_kmsg) | |
1196 | forward_kmsg(s, priority, tag, message, ucred); | |
1197 | ||
1198 | if (s->forward_to_console) | |
1199 | forward_console(s, tag, message, ucred); | |
1200 | } | |
1201 | ||
6e409ce1 | 1202 | dispatch_message(s, iovec, n, m, ucred, tv, priority); |
7f3e6257 LP |
1203 | |
1204 | for (j = 0; j < n; j++) | |
1205 | if (iovec[j].iov_base < buffer || | |
1206 | (const uint8_t*) iovec[j].iov_base >= (const uint8_t*) buffer + buffer_size) | |
1207 | free(iovec[j].iov_base); | |
224f2ee2 LP |
1208 | |
1209 | free(tag); | |
1210 | free(message); | |
87d2c1ff LP |
1211 | } |
1212 | ||
224f2ee2 LP |
1213 | static int stdout_stream_log(StdoutStream *s, const char *p) { |
1214 | struct iovec iovec[N_IOVEC_META_FIELDS + 4]; | |
1215 | char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_tag = NULL; | |
fe652127 | 1216 | unsigned n = 0; |
fe652127 LP |
1217 | int priority; |
1218 | ||
87d2c1ff | 1219 | assert(s); |
fe652127 LP |
1220 | assert(p); |
1221 | ||
1222 | priority = s->priority; | |
1223 | ||
224f2ee2 LP |
1224 | if (s->priority_prefix) |
1225 | parse_syslog_priority((char**) &p, &priority); | |
fe652127 | 1226 | |
224f2ee2 LP |
1227 | if (s->forward_to_syslog || s->server->forward_to_syslog) |
1228 | forward_syslog(s->server, fixup_priority(priority), s->tag, p, &s->ucred, NULL); | |
fe652127 | 1229 | |
224f2ee2 LP |
1230 | if (s->forward_to_kmsg || s->server->forward_to_kmsg) |
1231 | forward_kmsg(s->server, priority, s->tag, p, &s->ucred); | |
fe652127 | 1232 | |
224f2ee2 LP |
1233 | if (s->forward_to_console || s->server->forward_to_console) |
1234 | forward_console(s->server, s->tag, p, &s->ucred); | |
1235 | ||
1236 | if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0) | |
fe652127 LP |
1237 | IOVEC_SET_STRING(iovec[n++], syslog_priority); |
1238 | ||
224f2ee2 LP |
1239 | if (priority & LOG_FACMASK) |
1240 | if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0) | |
1241 | IOVEC_SET_STRING(iovec[n++], syslog_facility); | |
fe652127 | 1242 | |
224f2ee2 LP |
1243 | if (s->tag) { |
1244 | syslog_tag = strappend("SYSLOG_TAG=", s->tag); | |
1245 | if (syslog_tag) | |
1246 | IOVEC_SET_STRING(iovec[n++], syslog_tag); | |
87d2c1ff LP |
1247 | } |
1248 | ||
224f2ee2 LP |
1249 | message = strappend("MESSAGE=", p); |
1250 | if (message) | |
1251 | IOVEC_SET_STRING(iovec[n++], message); | |
fe652127 | 1252 | |
224f2ee2 | 1253 | dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, priority); |
fe652127 LP |
1254 | |
1255 | free(message); | |
1256 | free(syslog_priority); | |
224f2ee2 LP |
1257 | free(syslog_facility); |
1258 | free(syslog_tag); | |
fe652127 LP |
1259 | |
1260 | return 0; | |
1261 | } | |
1262 | ||
224f2ee2 LP |
1263 | static int stdout_stream_line(StdoutStream *s, char *p) { |
1264 | int r; | |
1265 | ||
fe652127 LP |
1266 | assert(s); |
1267 | assert(p); | |
1268 | ||
224f2ee2 | 1269 | p = strstrip(p); |
fe652127 LP |
1270 | |
1271 | switch (s->state) { | |
1272 | ||
1273 | case STDOUT_STREAM_TAG: | |
224f2ee2 LP |
1274 | s->tag = strdup(p); |
1275 | if (!s->tag) { | |
1276 | log_error("Out of memory"); | |
1277 | return -ENOMEM; | |
fe652127 LP |
1278 | } |
1279 | ||
1280 | s->state = STDOUT_STREAM_PRIORITY; | |
1281 | return 0; | |
1282 | ||
1283 | case STDOUT_STREAM_PRIORITY: | |
224f2ee2 LP |
1284 | r = safe_atoi(p, &s->priority); |
1285 | if (r < 0 || s->priority <= 0 || s->priority >= 999) { | |
fe652127 LP |
1286 | log_warning("Failed to parse log priority line."); |
1287 | return -EINVAL; | |
1288 | } | |
1289 | ||
fe652127 LP |
1290 | s->state = STDOUT_STREAM_PRIORITY_PREFIX; |
1291 | return 0; | |
1292 | ||
1293 | case STDOUT_STREAM_PRIORITY_PREFIX: | |
224f2ee2 LP |
1294 | r = parse_boolean(p); |
1295 | if (r < 0) { | |
fe652127 LP |
1296 | log_warning("Failed to parse priority prefix line."); |
1297 | return -EINVAL; | |
1298 | } | |
1299 | ||
224f2ee2 LP |
1300 | s->priority_prefix = !!r; |
1301 | s->state = STDOUT_STREAM_FORWARD_TO_SYSLOG; | |
fe652127 LP |
1302 | return 0; |
1303 | ||
224f2ee2 LP |
1304 | case STDOUT_STREAM_FORWARD_TO_SYSLOG: |
1305 | r = parse_boolean(p); | |
1306 | if (r < 0) { | |
1307 | log_warning("Failed to parse forward to syslog line."); | |
fe652127 LP |
1308 | return -EINVAL; |
1309 | } | |
1310 | ||
224f2ee2 LP |
1311 | s->forward_to_syslog = !!r; |
1312 | s->state = STDOUT_STREAM_FORWARD_TO_KMSG; | |
1313 | return 0; | |
1314 | ||
1315 | case STDOUT_STREAM_FORWARD_TO_KMSG: | |
1316 | r = parse_boolean(p); | |
1317 | if (r < 0) { | |
1318 | log_warning("Failed to parse copy to kmsg line."); | |
1319 | return -EINVAL; | |
1320 | } | |
1321 | ||
1322 | s->forward_to_kmsg = !!r; | |
1323 | s->state = STDOUT_STREAM_FORWARD_TO_CONSOLE; | |
1324 | return 0; | |
1325 | ||
1326 | case STDOUT_STREAM_FORWARD_TO_CONSOLE: | |
1327 | r = parse_boolean(p); | |
1328 | if (r < 0) { | |
1329 | log_warning("Failed to parse copy to console line."); | |
1330 | return -EINVAL; | |
1331 | } | |
1332 | ||
1333 | s->forward_to_console = !!r; | |
fe652127 LP |
1334 | s->state = STDOUT_STREAM_RUNNING; |
1335 | return 0; | |
1336 | ||
1337 | case STDOUT_STREAM_RUNNING: | |
224f2ee2 | 1338 | return stdout_stream_log(s, p); |
fe652127 LP |
1339 | } |
1340 | ||
1341 | assert_not_reached("Unknown stream state"); | |
1342 | } | |
1343 | ||
1344 | static int stdout_stream_scan(StdoutStream *s, bool force_flush) { | |
1345 | char *p; | |
1346 | size_t remaining; | |
1347 | int r; | |
1348 | ||
1349 | assert(s); | |
1350 | ||
1351 | p = s->buffer; | |
1352 | remaining = s->length; | |
1353 | for (;;) { | |
1354 | char *end; | |
1355 | size_t skip; | |
1356 | ||
1357 | end = memchr(p, '\n', remaining); | |
224f2ee2 | 1358 | if (end) |
fe652127 | 1359 | skip = end - p + 1; |
224f2ee2 LP |
1360 | else if (remaining >= sizeof(s->buffer) - 1) { |
1361 | end = p + sizeof(s->buffer) - 1; | |
1362 | skip = sizeof(s->buffer) - 1; | |
1363 | } else | |
1364 | break; | |
1365 | ||
1366 | *end = 0; | |
fe652127 | 1367 | |
224f2ee2 | 1368 | r = stdout_stream_line(s, p); |
fe652127 LP |
1369 | if (r < 0) |
1370 | return r; | |
1371 | ||
1372 | remaining -= skip; | |
1373 | p += skip; | |
1374 | } | |
1375 | ||
1376 | if (force_flush && remaining > 0) { | |
224f2ee2 LP |
1377 | p[remaining] = 0; |
1378 | r = stdout_stream_line(s, p); | |
fe652127 LP |
1379 | if (r < 0) |
1380 | return r; | |
1381 | ||
1382 | p += remaining; | |
1383 | remaining = 0; | |
1384 | } | |
1385 | ||
1386 | if (p > s->buffer) { | |
1387 | memmove(s->buffer, p, remaining); | |
1388 | s->length = remaining; | |
1389 | } | |
1390 | ||
1391 | return 0; | |
1392 | } | |
1393 | ||
1394 | static int stdout_stream_process(StdoutStream *s) { | |
1395 | ssize_t l; | |
1396 | int r; | |
1397 | ||
1398 | assert(s); | |
1399 | ||
1400 | l = read(s->fd, s->buffer+s->length, sizeof(s->buffer)-1-s->length); | |
1401 | if (l < 0) { | |
1402 | ||
1403 | if (errno == EAGAIN) | |
1404 | return 0; | |
1405 | ||
1406 | log_warning("Failed to read from stream: %m"); | |
1407 | return -errno; | |
1408 | } | |
1409 | ||
1410 | if (l == 0) { | |
1411 | r = stdout_stream_scan(s, true); | |
1412 | if (r < 0) | |
1413 | return r; | |
1414 | ||
1415 | return 0; | |
1416 | } | |
1417 | ||
1418 | s->length += l; | |
1419 | r = stdout_stream_scan(s, false); | |
1420 | if (r < 0) | |
1421 | return r; | |
1422 | ||
1423 | return 1; | |
1424 | ||
1425 | } | |
1426 | ||
1427 | static void stdout_stream_free(StdoutStream *s) { | |
1428 | assert(s); | |
1429 | ||
1430 | if (s->server) { | |
1431 | assert(s->server->n_stdout_streams > 0); | |
1432 | s->server->n_stdout_streams --; | |
1433 | LIST_REMOVE(StdoutStream, stdout_stream, s->server->stdout_streams, s); | |
1434 | } | |
1435 | ||
1436 | if (s->fd >= 0) { | |
1437 | if (s->server) | |
1438 | epoll_ctl(s->server->epoll_fd, EPOLL_CTL_DEL, s->fd, NULL); | |
1439 | ||
1440 | close_nointr_nofail(s->fd); | |
1441 | } | |
1442 | ||
1443 | free(s->tag); | |
1444 | free(s); | |
1445 | } | |
1446 | ||
1447 | static int stdout_stream_new(Server *s) { | |
1448 | StdoutStream *stream; | |
1449 | int fd, r; | |
1450 | socklen_t len; | |
1451 | struct epoll_event ev; | |
1452 | ||
1453 | assert(s); | |
1454 | ||
1455 | fd = accept4(s->stdout_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC); | |
1456 | if (fd < 0) { | |
1457 | if (errno == EAGAIN) | |
1458 | return 0; | |
1459 | ||
1460 | log_error("Failed to accept stdout connection: %m"); | |
1461 | return -errno; | |
1462 | } | |
1463 | ||
1464 | if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) { | |
1465 | log_warning("Too many stdout streams, refusing connection."); | |
1466 | close_nointr_nofail(fd); | |
1467 | return 0; | |
1468 | } | |
1469 | ||
1470 | stream = new0(StdoutStream, 1); | |
1471 | if (!stream) { | |
1472 | log_error("Out of memory."); | |
1473 | close_nointr_nofail(fd); | |
1474 | return -ENOMEM; | |
1475 | } | |
1476 | ||
1477 | stream->fd = fd; | |
1478 | ||
1479 | len = sizeof(stream->ucred); | |
1480 | if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &stream->ucred, &len) < 0) { | |
1481 | log_error("Failed to determine peer credentials: %m"); | |
1482 | r = -errno; | |
1483 | goto fail; | |
1484 | } | |
1485 | ||
1486 | if (shutdown(fd, SHUT_WR) < 0) { | |
1487 | log_error("Failed to shutdown writing side of socket: %m"); | |
1488 | r = -errno; | |
1489 | goto fail; | |
1490 | } | |
1491 | ||
1492 | zero(ev); | |
1493 | ev.data.ptr = stream; | |
1494 | ev.events = EPOLLIN; | |
1495 | if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) { | |
1496 | log_error("Failed to add stream to event loop: %m"); | |
1497 | r = -errno; | |
1498 | goto fail; | |
1499 | } | |
1500 | ||
1501 | stream->server = s; | |
1502 | LIST_PREPEND(StdoutStream, stdout_stream, s->stdout_streams, stream); | |
1503 | s->n_stdout_streams ++; | |
1504 | ||
1505 | return 0; | |
1506 | ||
1507 | fail: | |
1508 | stdout_stream_free(stream); | |
1509 | return r; | |
1510 | } | |
1511 | ||
cf244689 LP |
1512 | static int system_journal_open(Server *s) { |
1513 | int r; | |
1514 | char *fn; | |
1515 | sd_id128_t machine; | |
1516 | char ids[33]; | |
1517 | ||
1518 | r = sd_id128_get_machine(&machine); | |
1519 | if (r < 0) | |
1520 | return r; | |
1521 | ||
1522 | sd_id128_to_string(machine, ids); | |
1523 | ||
1524 | if (!s->system_journal) { | |
1525 | ||
1526 | /* First try to create the machine path, but not the prefix */ | |
1527 | fn = strappend("/var/log/journal/", ids); | |
1528 | if (!fn) | |
1529 | return -ENOMEM; | |
1530 | (void) mkdir(fn, 0755); | |
1531 | free(fn); | |
1532 | ||
1533 | /* The create the system journal file */ | |
1534 | fn = join("/var/log/journal/", ids, "/system.journal", NULL); | |
1535 | if (!fn) | |
1536 | return -ENOMEM; | |
1537 | ||
1538 | r = journal_file_open(fn, O_RDWR|O_CREAT, 0640, NULL, &s->system_journal); | |
1539 | free(fn); | |
1540 | ||
1541 | if (r >= 0) { | |
babfc091 LP |
1542 | journal_default_metrics(&s->system_metrics, s->system_journal->fd); |
1543 | ||
1544 | s->system_journal->metrics = s->system_metrics; | |
cf244689 LP |
1545 | s->system_journal->compress = s->compress; |
1546 | ||
1547 | fix_perms(s->system_journal, 0); | |
1548 | } else if (r < 0) { | |
1549 | ||
adf7d506 LP |
1550 | if (r != -ENOENT && r != -EROFS) |
1551 | log_warning("Failed to open system journal: %s", strerror(-r)); | |
1552 | ||
1553 | r = 0; | |
cf244689 LP |
1554 | } |
1555 | } | |
1556 | ||
1557 | if (!s->runtime_journal) { | |
1558 | ||
1559 | fn = join("/run/log/journal/", ids, "/system.journal", NULL); | |
1560 | if (!fn) | |
1561 | return -ENOMEM; | |
1562 | ||
1563 | if (s->system_journal) { | |
1564 | ||
1565 | /* Try to open the runtime journal, but only | |
1566 | * if it already exists, so that we can flush | |
1567 | * it into the system journal */ | |
1568 | ||
1569 | r = journal_file_open(fn, O_RDWR, 0640, NULL, &s->runtime_journal); | |
1570 | free(fn); | |
1571 | ||
1572 | if (r < 0) { | |
adf7d506 LP |
1573 | if (r != -ENOENT) |
1574 | log_warning("Failed to open runtime journal: %s", strerror(-r)); | |
cf244689 | 1575 | |
adf7d506 | 1576 | r = 0; |
cf244689 LP |
1577 | } |
1578 | ||
1579 | } else { | |
1580 | ||
1581 | /* OK, we really need the runtime journal, so create | |
1582 | * it if necessary. */ | |
1583 | ||
1584 | (void) mkdir_parents(fn, 0755); | |
1585 | r = journal_file_open(fn, O_RDWR|O_CREAT, 0640, NULL, &s->runtime_journal); | |
1586 | free(fn); | |
1587 | ||
1588 | if (r < 0) { | |
1589 | log_error("Failed to open runtime journal: %s", strerror(-r)); | |
1590 | return r; | |
1591 | } | |
1592 | } | |
1593 | ||
1594 | if (s->runtime_journal) { | |
babfc091 LP |
1595 | journal_default_metrics(&s->runtime_metrics, s->runtime_journal->fd); |
1596 | ||
1597 | s->runtime_journal->metrics = s->runtime_metrics; | |
cf244689 LP |
1598 | s->runtime_journal->compress = s->compress; |
1599 | ||
1600 | fix_perms(s->runtime_journal, 0); | |
1601 | } | |
1602 | } | |
1603 | ||
1604 | return r; | |
1605 | } | |
1606 | ||
1607 | static int server_flush_to_var(Server *s) { | |
1608 | char path[] = "/run/log/journal/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; | |
1609 | Object *o = NULL; | |
1610 | int r; | |
1611 | sd_id128_t machine; | |
1612 | sd_journal *j; | |
54a7b863 | 1613 | usec_t ts; |
cf244689 LP |
1614 | |
1615 | assert(s); | |
1616 | ||
54a7b863 LP |
1617 | if (!s->runtime_journal) |
1618 | return 0; | |
1619 | ||
1620 | ts = now(CLOCK_MONOTONIC); | |
1621 | if (s->var_available_timestamp + RECHECK_VAR_AVAILABLE_USEC > ts) | |
1622 | return 0; | |
1623 | ||
1624 | s->var_available_timestamp = ts; | |
1625 | ||
cf244689 LP |
1626 | system_journal_open(s); |
1627 | ||
54a7b863 | 1628 | if (!s->system_journal) |
cf244689 LP |
1629 | return 0; |
1630 | ||
1631 | r = sd_id128_get_machine(&machine); | |
1632 | if (r < 0) { | |
1633 | log_error("Failed to get machine id: %s", strerror(-r)); | |
1634 | return r; | |
1635 | } | |
1636 | ||
1637 | r = sd_journal_open(&j, SD_JOURNAL_RUNTIME_ONLY); | |
1638 | if (r < 0) { | |
1639 | log_error("Failed to read runtime journal: %s", strerror(-r)); | |
1640 | return r; | |
1641 | } | |
1642 | ||
1643 | SD_JOURNAL_FOREACH(j) { | |
1644 | JournalFile *f; | |
1645 | ||
1646 | f = j->current_file; | |
1647 | assert(f && f->current_offset > 0); | |
1648 | ||
1649 | r = journal_file_move_to_object(f, OBJECT_ENTRY, f->current_offset, &o); | |
1650 | if (r < 0) { | |
1651 | log_error("Can't read entry: %s", strerror(-r)); | |
1652 | goto finish; | |
1653 | } | |
1654 | ||
1655 | r = journal_file_copy_entry(f, s->system_journal, o, f->current_offset, NULL, NULL, NULL); | |
1656 | if (r == -E2BIG) { | |
1657 | log_info("Allocation limit reached."); | |
1658 | ||
1659 | journal_file_post_change(s->system_journal); | |
b1a0ab71 | 1660 | server_rotate(s); |
cf244689 LP |
1661 | server_vacuum(s); |
1662 | ||
1663 | r = journal_file_copy_entry(f, s->system_journal, o, f->current_offset, NULL, NULL, NULL); | |
1664 | } | |
1665 | ||
1666 | if (r < 0) { | |
1667 | log_error("Can't write entry: %s", strerror(-r)); | |
1668 | goto finish; | |
1669 | } | |
1670 | } | |
1671 | ||
1672 | finish: | |
1673 | journal_file_post_change(s->system_journal); | |
1674 | ||
1675 | journal_file_close(s->runtime_journal); | |
1676 | s->runtime_journal = NULL; | |
1677 | ||
1678 | if (r >= 0) { | |
1679 | sd_id128_to_string(machine, path + 17); | |
1680 | rm_rf(path, false, true, false); | |
1681 | } | |
1682 | ||
1683 | return r; | |
1684 | } | |
1685 | ||
fe652127 LP |
1686 | static int process_event(Server *s, struct epoll_event *ev) { |
1687 | assert(s); | |
1688 | ||
87d2c1ff LP |
1689 | if (ev->data.fd == s->signal_fd) { |
1690 | struct signalfd_siginfo sfsi; | |
1691 | ssize_t n; | |
1692 | ||
fe652127 LP |
1693 | if (ev->events != EPOLLIN) { |
1694 | log_info("Got invalid event from epoll."); | |
1695 | return -EIO; | |
1696 | } | |
1697 | ||
87d2c1ff LP |
1698 | n = read(s->signal_fd, &sfsi, sizeof(sfsi)); |
1699 | if (n != sizeof(sfsi)) { | |
1700 | ||
1701 | if (n >= 0) | |
1702 | return -EIO; | |
1703 | ||
1704 | if (errno == EINTR || errno == EAGAIN) | |
1705 | return 0; | |
1706 | ||
1707 | return -errno; | |
1708 | } | |
1709 | ||
cf244689 LP |
1710 | if (sfsi.ssi_signo == SIGUSR1) { |
1711 | server_flush_to_var(s); | |
1712 | return 0; | |
1713 | } | |
1714 | ||
87d2c1ff LP |
1715 | log_debug("Received SIG%s", signal_to_string(sfsi.ssi_signo)); |
1716 | return 0; | |
1717 | ||
fe652127 LP |
1718 | } else if (ev->data.fd == s->native_fd || |
1719 | ev->data.fd == s->syslog_fd) { | |
1720 | ||
1721 | if (ev->events != EPOLLIN) { | |
1722 | log_info("Got invalid event from epoll."); | |
1723 | return -EIO; | |
1724 | } | |
cec736d2 | 1725 | |
87d2c1ff | 1726 | for (;;) { |
87d2c1ff LP |
1727 | struct msghdr msghdr; |
1728 | struct iovec iovec; | |
1729 | struct ucred *ucred = NULL; | |
1730 | struct timeval *tv = NULL; | |
1731 | struct cmsghdr *cmsg; | |
1732 | union { | |
1733 | struct cmsghdr cmsghdr; | |
1734 | uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) + | |
1735 | CMSG_SPACE(sizeof(struct timeval))]; | |
1736 | } control; | |
1737 | ssize_t n; | |
7f3e6257 LP |
1738 | int v; |
1739 | ||
1740 | if (ioctl(ev->data.fd, SIOCINQ, &v) < 0) { | |
1741 | log_error("SIOCINQ failed: %m"); | |
1742 | return -errno; | |
1743 | } | |
1744 | ||
1745 | if (v <= 0) | |
1746 | return 1; | |
1747 | ||
1748 | if (s->buffer_size < (size_t) v) { | |
1749 | void *b; | |
1750 | size_t l; | |
1751 | ||
1752 | l = MAX(LINE_MAX + (size_t) v, s->buffer_size * 2); | |
1753 | b = realloc(s->buffer, l+1); | |
1754 | ||
1755 | if (!b) { | |
1756 | log_error("Couldn't increase buffer."); | |
1757 | return -ENOMEM; | |
1758 | } | |
1759 | ||
1760 | s->buffer_size = l; | |
1761 | s->buffer = b; | |
1762 | } | |
87d2c1ff LP |
1763 | |
1764 | zero(iovec); | |
7f3e6257 LP |
1765 | iovec.iov_base = s->buffer; |
1766 | iovec.iov_len = s->buffer_size; | |
87d2c1ff LP |
1767 | |
1768 | zero(control); | |
1769 | zero(msghdr); | |
1770 | msghdr.msg_iov = &iovec; | |
1771 | msghdr.msg_iovlen = 1; | |
1772 | msghdr.msg_control = &control; | |
1773 | msghdr.msg_controllen = sizeof(control); | |
1774 | ||
1775 | n = recvmsg(ev->data.fd, &msghdr, MSG_DONTWAIT); | |
1776 | if (n < 0) { | |
1777 | ||
1778 | if (errno == EINTR || errno == EAGAIN) | |
1779 | return 1; | |
1780 | ||
1781 | log_error("recvmsg() failed: %m"); | |
1782 | return -errno; | |
1783 | } | |
1784 | ||
1785 | for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { | |
1786 | ||
1787 | if (cmsg->cmsg_level == SOL_SOCKET && | |
1788 | cmsg->cmsg_type == SCM_CREDENTIALS && | |
1789 | cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) | |
1790 | ucred = (struct ucred*) CMSG_DATA(cmsg); | |
1791 | else if (cmsg->cmsg_level == SOL_SOCKET && | |
1792 | cmsg->cmsg_type == SO_TIMESTAMP && | |
1793 | cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) | |
1794 | tv = (struct timeval*) CMSG_DATA(cmsg); | |
1795 | } | |
1796 | ||
7f3e6257 LP |
1797 | if (ev->data.fd == s->syslog_fd) { |
1798 | char *e; | |
1799 | ||
1800 | e = memchr(s->buffer, '\n', n); | |
1801 | if (e) | |
1802 | *e = 0; | |
1803 | else | |
1804 | s->buffer[n] = 0; | |
87d2c1ff | 1805 | |
7f3e6257 LP |
1806 | process_syslog_message(s, strstrip(s->buffer), ucred, tv); |
1807 | } else | |
1808 | process_native_message(s, s->buffer, n, ucred, tv); | |
87d2c1ff | 1809 | } |
cec736d2 LP |
1810 | |
1811 | return 1; | |
fe652127 LP |
1812 | |
1813 | } else if (ev->data.fd == s->stdout_fd) { | |
1814 | ||
1815 | if (ev->events != EPOLLIN) { | |
1816 | log_info("Got invalid event from epoll."); | |
1817 | return -EIO; | |
1818 | } | |
1819 | ||
1820 | stdout_stream_new(s); | |
1821 | return 1; | |
1822 | ||
1823 | } else { | |
1824 | StdoutStream *stream; | |
1825 | ||
1826 | if ((ev->events|EPOLLIN|EPOLLHUP) != (EPOLLIN|EPOLLHUP)) { | |
1827 | log_info("Got invalid event from epoll."); | |
1828 | return -EIO; | |
1829 | } | |
1830 | ||
1831 | /* If it is none of the well-known fds, it must be an | |
1832 | * stdout stream fd. Note that this is a bit ugly here | |
1833 | * (since we rely that none of the well-known fds | |
1834 | * could be interpreted as pointer), but nonetheless | |
1835 | * safe, since the well-known fds would never get an | |
1836 | * fd > 4096, i.e. beyond the first memory page */ | |
1837 | ||
1838 | stream = ev->data.ptr; | |
1839 | ||
1840 | if (stdout_stream_process(stream) <= 0) | |
1841 | stdout_stream_free(stream); | |
1842 | ||
1843 | return 1; | |
87d2c1ff LP |
1844 | } |
1845 | ||
cec736d2 LP |
1846 | log_error("Unknown event."); |
1847 | return 0; | |
87d2c1ff LP |
1848 | } |
1849 | ||
7f3e6257 LP |
1850 | static int open_syslog_socket(Server *s) { |
1851 | union sockaddr_union sa; | |
1852 | int one, r; | |
fe652127 | 1853 | struct epoll_event ev; |
8b18eb67 | 1854 | struct timeval tv; |
87d2c1ff LP |
1855 | |
1856 | assert(s); | |
1857 | ||
7f3e6257 | 1858 | if (s->syslog_fd < 0) { |
87d2c1ff | 1859 | |
7f3e6257 LP |
1860 | s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); |
1861 | if (s->syslog_fd < 0) { | |
1862 | log_error("socket() failed: %m"); | |
1863 | return -errno; | |
1864 | } | |
1865 | ||
1866 | zero(sa); | |
1867 | sa.un.sun_family = AF_UNIX; | |
8b18eb67 | 1868 | strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path)); |
7f3e6257 LP |
1869 | |
1870 | unlink(sa.un.sun_path); | |
1871 | ||
1872 | r = bind(s->syslog_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)); | |
1873 | if (r < 0) { | |
1874 | log_error("bind() failed: %m"); | |
1875 | return -errno; | |
1876 | } | |
1877 | ||
1878 | chmod(sa.un.sun_path, 0666); | |
87d2c1ff LP |
1879 | } |
1880 | ||
7f3e6257 LP |
1881 | one = 1; |
1882 | r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); | |
1883 | if (r < 0) { | |
1884 | log_error("SO_PASSCRED failed: %m"); | |
1885 | return -errno; | |
87d2c1ff LP |
1886 | } |
1887 | ||
7f3e6257 LP |
1888 | one = 1; |
1889 | r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one)); | |
1890 | if (r < 0) { | |
1891 | log_error("SO_TIMESTAMP failed: %m"); | |
1892 | return -errno; | |
87d2c1ff LP |
1893 | } |
1894 | ||
8b18eb67 LP |
1895 | /* Since we use the same socket for forwarding this to some |
1896 | * other syslog implementation, make sure we don't hang | |
1897 | * forever */ | |
1898 | timeval_store(&tv, SYSLOG_TIMEOUT_USEC); | |
1899 | if (setsockopt(s->syslog_fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) { | |
1900 | log_error("SO_SNDTIMEO failed: %m"); | |
1901 | return -errno; | |
1902 | } | |
1903 | ||
fe652127 LP |
1904 | zero(ev); |
1905 | ev.events = EPOLLIN; | |
1906 | ev.data.fd = s->syslog_fd; | |
1907 | if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->syslog_fd, &ev) < 0) { | |
1908 | log_error("Failed to add syslog server fd to epoll object: %m"); | |
1909 | return -errno; | |
1910 | } | |
1911 | ||
7f3e6257 LP |
1912 | return 0; |
1913 | } | |
87d2c1ff | 1914 | |
7f3e6257 LP |
1915 | static int open_native_socket(Server*s) { |
1916 | union sockaddr_union sa; | |
1917 | int one, r; | |
fe652127 | 1918 | struct epoll_event ev; |
7f3e6257 LP |
1919 | |
1920 | assert(s); | |
1921 | ||
1922 | if (s->native_fd < 0) { | |
1923 | ||
1924 | s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); | |
1925 | if (s->native_fd < 0) { | |
87d2c1ff LP |
1926 | log_error("socket() failed: %m"); |
1927 | return -errno; | |
1928 | } | |
1929 | ||
1930 | zero(sa); | |
1931 | sa.un.sun_family = AF_UNIX; | |
259d2e76 | 1932 | strncpy(sa.un.sun_path, "/run/systemd/journal/socket", sizeof(sa.un.sun_path)); |
87d2c1ff LP |
1933 | |
1934 | unlink(sa.un.sun_path); | |
1935 | ||
7f3e6257 | 1936 | r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)); |
87d2c1ff LP |
1937 | if (r < 0) { |
1938 | log_error("bind() failed: %m"); | |
1939 | return -errno; | |
1940 | } | |
1941 | ||
1942 | chmod(sa.un.sun_path, 0666); | |
1943 | } | |
1944 | ||
1945 | one = 1; | |
7f3e6257 | 1946 | r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); |
87d2c1ff LP |
1947 | if (r < 0) { |
1948 | log_error("SO_PASSCRED failed: %m"); | |
1949 | return -errno; | |
1950 | } | |
1951 | ||
1952 | one = 1; | |
7f3e6257 | 1953 | r = setsockopt(s->native_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one)); |
87d2c1ff LP |
1954 | if (r < 0) { |
1955 | log_error("SO_TIMESTAMP failed: %m"); | |
1956 | return -errno; | |
1957 | } | |
1958 | ||
fe652127 LP |
1959 | zero(ev); |
1960 | ev.events = EPOLLIN; | |
1961 | ev.data.fd = s->native_fd; | |
1962 | if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->native_fd, &ev) < 0) { | |
1963 | log_error("Failed to add native server fd to epoll object: %m"); | |
1964 | return -errno; | |
1965 | } | |
1966 | ||
7f3e6257 LP |
1967 | return 0; |
1968 | } | |
1969 | ||
fe652127 LP |
1970 | static int open_stdout_socket(Server *s) { |
1971 | union sockaddr_union sa; | |
1972 | int r; | |
7f3e6257 | 1973 | struct epoll_event ev; |
fe652127 LP |
1974 | |
1975 | assert(s); | |
1976 | ||
1977 | if (s->stdout_fd < 0) { | |
1978 | ||
1979 | s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); | |
1980 | if (s->stdout_fd < 0) { | |
1981 | log_error("socket() failed: %m"); | |
1982 | return -errno; | |
1983 | } | |
1984 | ||
1985 | zero(sa); | |
1986 | sa.un.sun_family = AF_UNIX; | |
259d2e76 | 1987 | strncpy(sa.un.sun_path, "/run/systemd/journal/stdout", sizeof(sa.un.sun_path)); |
fe652127 LP |
1988 | |
1989 | unlink(sa.un.sun_path); | |
1990 | ||
1991 | r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)); | |
1992 | if (r < 0) { | |
1993 | log_error("bind() failed: %m"); | |
1994 | return -errno; | |
1995 | } | |
1996 | ||
1997 | chmod(sa.un.sun_path, 0666); | |
1998 | ||
1999 | if (listen(s->stdout_fd, SOMAXCONN) < 0) { | |
2000 | log_error("liste() failed: %m"); | |
2001 | return -errno; | |
2002 | } | |
2003 | } | |
2004 | ||
2005 | zero(ev); | |
2006 | ev.events = EPOLLIN; | |
2007 | ev.data.fd = s->stdout_fd; | |
2008 | if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->stdout_fd, &ev) < 0) { | |
2009 | log_error("Failed to add stdout server fd to epoll object: %m"); | |
2010 | return -errno; | |
2011 | } | |
2012 | ||
2013 | return 0; | |
2014 | } | |
2015 | ||
2016 | static int open_signalfd(Server *s) { | |
7f3e6257 | 2017 | sigset_t mask; |
fe652127 LP |
2018 | struct epoll_event ev; |
2019 | ||
2020 | assert(s); | |
2021 | ||
2022 | assert_se(sigemptyset(&mask) == 0); | |
cf244689 | 2023 | sigset_add_many(&mask, SIGINT, SIGTERM, SIGUSR1, -1); |
fe652127 LP |
2024 | assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); |
2025 | ||
2026 | s->signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC); | |
2027 | if (s->signal_fd < 0) { | |
2028 | log_error("signalfd(): %m"); | |
2029 | return -errno; | |
2030 | } | |
2031 | ||
2032 | zero(ev); | |
2033 | ev.events = EPOLLIN; | |
2034 | ev.data.fd = s->signal_fd; | |
2035 | ||
2036 | if (epoll_ctl(s->epoll_fd, EPOLL_CTL_ADD, s->signal_fd, &ev) < 0) { | |
2037 | log_error("epoll_ctl(): %m"); | |
2038 | return -errno; | |
2039 | } | |
2040 | ||
2041 | return 0; | |
2042 | } | |
2043 | ||
e6960940 LP |
2044 | static int server_parse_config_file(Server *s) { |
2045 | FILE *f; | |
2046 | const char *fn; | |
2047 | int r; | |
2048 | ||
2049 | assert(s); | |
2050 | ||
2051 | fn = "/etc/systemd/systemd-journald.conf"; | |
2052 | f = fopen(fn, "re"); | |
2053 | if (!f) { | |
2054 | if (errno == ENOENT) | |
2055 | return 0; | |
2056 | ||
2057 | log_warning("Failed to open configuration file %s: %m", fn); | |
2058 | return -errno; | |
2059 | } | |
2060 | ||
2061 | r = config_parse(fn, f, "Journal\0", config_item_perf_lookup, (void*) journald_gperf_lookup, false, s); | |
2062 | if (r < 0) | |
2063 | log_warning("Failed to parse configuration file: %s", strerror(-r)); | |
2064 | ||
2065 | fclose(f); | |
2066 | ||
2067 | return r; | |
2068 | } | |
2069 | ||
fe652127 LP |
2070 | static int server_init(Server *s) { |
2071 | int n, r, fd; | |
7f3e6257 LP |
2072 | |
2073 | assert(s); | |
2074 | ||
2075 | zero(*s); | |
fe652127 | 2076 | s->syslog_fd = s->native_fd = s->stdout_fd = s->signal_fd = s->epoll_fd = -1; |
807e17f0 | 2077 | s->compress = true; |
7f3e6257 | 2078 | |
e6960940 LP |
2079 | s->rate_limit_interval = DEFAULT_RATE_LIMIT_INTERVAL; |
2080 | s->rate_limit_burst = DEFAULT_RATE_LIMIT_BURST; | |
2081 | ||
224f2ee2 LP |
2082 | s->forward_to_syslog = true; |
2083 | ||
babfc091 LP |
2084 | memset(&s->system_metrics, 0xFF, sizeof(s->system_metrics)); |
2085 | memset(&s->runtime_metrics, 0xFF, sizeof(s->runtime_metrics)); | |
2086 | ||
e6960940 LP |
2087 | server_parse_config_file(s); |
2088 | ||
fe652127 LP |
2089 | s->user_journals = hashmap_new(trivial_hash_func, trivial_compare_func); |
2090 | if (!s->user_journals) { | |
2091 | log_error("Out of memory."); | |
2092 | return -ENOMEM; | |
2093 | } | |
2094 | ||
7f3e6257 LP |
2095 | s->epoll_fd = epoll_create1(EPOLL_CLOEXEC); |
2096 | if (s->epoll_fd < 0) { | |
2097 | log_error("Failed to create epoll object: %m"); | |
2098 | return -errno; | |
2099 | } | |
2100 | ||
2101 | n = sd_listen_fds(true); | |
2102 | if (n < 0) { | |
2103 | log_error("Failed to read listening file descriptors from environment: %s", strerror(-n)); | |
2104 | return n; | |
2105 | } | |
2106 | ||
2107 | for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) { | |
2108 | ||
259d2e76 | 2109 | if (sd_is_socket_unix(fd, SOCK_DGRAM, -1, "/run/systemd/journal/socket", 0) > 0) { |
7f3e6257 | 2110 | |
fe652127 LP |
2111 | if (s->native_fd >= 0) { |
2112 | log_error("Too many native sockets passed."); | |
7f3e6257 LP |
2113 | return -EINVAL; |
2114 | } | |
2115 | ||
fe652127 | 2116 | s->native_fd = fd; |
7f3e6257 | 2117 | |
259d2e76 | 2118 | } else if (sd_is_socket_unix(fd, SOCK_STREAM, 1, "/run/systemd/journal/stdout", 0) > 0) { |
7f3e6257 | 2119 | |
fe652127 LP |
2120 | if (s->stdout_fd >= 0) { |
2121 | log_error("Too many stdout sockets passed."); | |
7f3e6257 LP |
2122 | return -EINVAL; |
2123 | } | |
2124 | ||
fe652127 LP |
2125 | s->stdout_fd = fd; |
2126 | ||
2127 | } else if (sd_is_socket_unix(fd, SOCK_DGRAM, -1, "/dev/log", 0) > 0) { | |
2128 | ||
2129 | if (s->syslog_fd >= 0) { | |
2130 | log_error("Too many /dev/log sockets passed."); | |
2131 | return -EINVAL; | |
2132 | } | |
2133 | ||
2134 | s->syslog_fd = fd; | |
2135 | ||
7f3e6257 LP |
2136 | } else { |
2137 | log_error("Unknown socket passed."); | |
2138 | return -EINVAL; | |
2139 | } | |
2140 | } | |
2141 | ||
2142 | r = open_syslog_socket(s); | |
2143 | if (r < 0) | |
2144 | return r; | |
2145 | ||
7f3e6257 LP |
2146 | r = open_native_socket(s); |
2147 | if (r < 0) | |
2148 | return r; | |
2149 | ||
fe652127 LP |
2150 | r = open_stdout_socket(s); |
2151 | if (r < 0) | |
2152 | return r; | |
87d2c1ff | 2153 | |
ed49ef3f LP |
2154 | r = system_journal_open(s); |
2155 | if (r < 0) | |
87d2c1ff | 2156 | return r; |
87d2c1ff | 2157 | |
fe652127 LP |
2158 | r = open_signalfd(s); |
2159 | if (r < 0) | |
2160 | return r; | |
87d2c1ff | 2161 | |
e6960940 | 2162 | s->rate_limit = journal_rate_limit_new(s->rate_limit_interval, s->rate_limit_burst); |
6e409ce1 LP |
2163 | if (!s->rate_limit) |
2164 | return -ENOMEM; | |
2165 | ||
87d2c1ff LP |
2166 | return 0; |
2167 | } | |
2168 | ||
2169 | static void server_done(Server *s) { | |
2170 | JournalFile *f; | |
2171 | assert(s); | |
2172 | ||
fe652127 LP |
2173 | while (s->stdout_streams) |
2174 | stdout_stream_free(s->stdout_streams); | |
2175 | ||
87d2c1ff LP |
2176 | if (s->system_journal) |
2177 | journal_file_close(s->system_journal); | |
2178 | ||
f4b47811 LP |
2179 | if (s->runtime_journal) |
2180 | journal_file_close(s->runtime_journal); | |
2181 | ||
87d2c1ff LP |
2182 | while ((f = hashmap_steal_first(s->user_journals))) |
2183 | journal_file_close(f); | |
2184 | ||
2185 | hashmap_free(s->user_journals); | |
2186 | ||
2187 | if (s->epoll_fd >= 0) | |
2188 | close_nointr_nofail(s->epoll_fd); | |
2189 | ||
2190 | if (s->signal_fd >= 0) | |
2191 | close_nointr_nofail(s->signal_fd); | |
2192 | ||
2193 | if (s->syslog_fd >= 0) | |
2194 | close_nointr_nofail(s->syslog_fd); | |
7f3e6257 LP |
2195 | |
2196 | if (s->native_fd >= 0) | |
2197 | close_nointr_nofail(s->native_fd); | |
fe652127 LP |
2198 | |
2199 | if (s->stdout_fd >= 0) | |
2200 | close_nointr_nofail(s->stdout_fd); | |
6e409ce1 LP |
2201 | |
2202 | if (s->rate_limit) | |
2203 | journal_rate_limit_free(s->rate_limit); | |
783d2675 LP |
2204 | |
2205 | free(s->buffer); | |
87d2c1ff LP |
2206 | } |
2207 | ||
2208 | int main(int argc, char *argv[]) { | |
2209 | Server server; | |
2210 | int r; | |
2211 | ||
2212 | /* if (getppid() != 1) { */ | |
2213 | /* log_error("This program should be invoked by init only."); */ | |
2214 | /* return EXIT_FAILURE; */ | |
2215 | /* } */ | |
2216 | ||
2217 | if (argc > 1) { | |
2218 | log_error("This program does not take arguments."); | |
2219 | return EXIT_FAILURE; | |
2220 | } | |
2221 | ||
f4b47811 | 2222 | log_set_target(LOG_TARGET_CONSOLE); |
87d2c1ff LP |
2223 | log_parse_environment(); |
2224 | log_open(); | |
2225 | ||
2226 | umask(0022); | |
2227 | ||
2228 | r = server_init(&server); | |
2229 | if (r < 0) | |
2230 | goto finish; | |
2231 | ||
e6960940 LP |
2232 | server_vacuum(&server); |
2233 | server_flush_to_var(&server); | |
2234 | ||
87d2c1ff | 2235 | log_debug("systemd-journald running as pid %lu", (unsigned long) getpid()); |
224f2ee2 | 2236 | driver_message(&server, SD_MESSAGE_JOURNAL_START, "Journal started"); |
87d2c1ff LP |
2237 | |
2238 | sd_notify(false, | |
2239 | "READY=1\n" | |
fe652127 | 2240 | "STATUS=Processing requests..."); |
50f20cfd | 2241 | |
87d2c1ff LP |
2242 | for (;;) { |
2243 | struct epoll_event event; | |
2244 | ||
2245 | r = epoll_wait(server.epoll_fd, &event, 1, -1); | |
2246 | if (r < 0) { | |
2247 | ||
2248 | if (errno == EINTR) | |
2249 | continue; | |
2250 | ||
2251 | log_error("epoll_wait() failed: %m"); | |
2252 | r = -errno; | |
2253 | goto finish; | |
2254 | } else if (r == 0) | |
2255 | break; | |
2256 | ||
2257 | r = process_event(&server, &event); | |
2258 | if (r < 0) | |
2259 | goto finish; | |
2260 | else if (r == 0) | |
2261 | break; | |
2262 | } | |
2263 | ||
fe652127 | 2264 | log_debug("systemd-journald stopped as pid %lu", (unsigned long) getpid()); |
224f2ee2 | 2265 | driver_message(&server, SD_MESSAGE_JOURNAL_STOP, "Journal stopped"); |
fe652127 | 2266 | |
87d2c1ff LP |
2267 | finish: |
2268 | sd_notify(false, | |
2269 | "STATUS=Shutting down..."); | |
2270 | ||
2271 | server_done(&server); | |
2272 | ||
2273 | return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; | |
2274 | } |