journald.c revision 5430f7f2bc7330f3088b894166bf3524a067e3d8
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers This file is part of systemd.
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers Copyright 2011 Lennart Poettering
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers systemd is free software; you can redistribute it and/or modify it
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers under the terms of the GNU Lesser General Public License as published by
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering (at your option) any later version.
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers systemd is distributed in the hope that it will be useful, but
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers WITHOUT ANY WARRANTY; without even the implied warranty of
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers Lesser General Public License for more details.
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers You should have received a copy of the GNU Lesser General Public License
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers#define DEFAULT_RATE_LIMIT_INTERVAL (10*USEC_PER_SEC)
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers#define RECHECK_AVAILABLE_SPACE_USEC (30*USEC_PER_SEC)
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers#define RECHECK_VAR_AVAILABLE_USEC (30*USEC_PER_SEC)
81fd105a5f9762fa2f2e42bc949876e32b3a126fZbigniew Jędrzejewski-Szmek LIST_FIELDS(StdoutStream, stdout_stream);
81fd105a5f9762fa2f2e42bc949876e32b3a126fZbigniew Jędrzejewski-Szmekstatic int server_flush_to_var(Server *s);
87699fe313cf8919917f2ea422b8d10b3ae3b244Daniel Mack const char *f;
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers if (s->cached_available_space_timestamp + RECHECK_AVAILABLE_SPACE_USEC > ts)
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers p = strappend(f, sd_id128_to_string(machine, ids));
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek sum += (uint64_t) st.st_blocks * 512UL;
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers avail = sum >= m->max_use ? 0 : m->max_use - sum;
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers ss_avail = ss_avail < m->keep_free ? 0 : ss_avail - m->keep_free;
28efac0d37ceb5093a804da6a00c620034c5484fZbigniew Jędrzejewski-Szmek r = get_group_creds(&adm, &s->file_gid);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers log_warning("Failed to resolve 'adm' group: %s", strerror(-r));
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers /* if we couldn't read the gid, then it will be 0, but that's
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers * fine and we shouldn't try to resolve the group again, so
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers * let's just pretend it worked right-away. */
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversstatic void server_fix_perms(Server *s, JournalFile *f, uid_t uid) {
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers r = fchmod_and_fchown(f->fd, 0640, 0, s->file_gid);
28efac0d37ceb5093a804da6a00c620034c5484fZbigniew Jędrzejewski-Szmek log_warning("Failed to fix access mode/rights on %s, ignoring: %s", f->path, strerror(-r));
87699fe313cf8919917f2ea422b8d10b3ae3b244Daniel Mack log_warning("Failed to read ACL on %s, ignoring: %m", f->path);
87699fe313cf8919917f2ea422b8d10b3ae3b244Daniel Mack if (r <= 0) {
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers log_warning("Failed to patch ACL on %s, ignoring: %m", f->path);
28efac0d37ceb5093a804da6a00c620034c5484fZbigniew Jędrzejewski-Szmek if (acl_get_permset(entry, &permset) < 0 ||
28efac0d37ceb5093a804da6a00c620034c5484fZbigniew Jędrzejewski-Szmek log_warning("Failed to patch ACL on %s, ignoring: %m", f->path);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers log_warning("Failed to set ACL on %s, ignoring: %m", f->path);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversstatic JournalFile* find_journal(Server *s, uid_t uid) {
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers /* We split up user logs only on /var, not on /run. If the
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers * runtime file is open, we write to it exclusively, in order
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek * to guarantee proper order as soon as we flush /run to
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers * /var and close the runtime file. */
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers f = hashmap_get(s->user_journals, UINT32_TO_PTR(uid));
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (asprintf(&p, "/var/log/journal/%s/user-%lu.journal", sd_id128_to_string(machine, ids), (unsigned long) uid) < 0)
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers while (hashmap_size(s->user_journals) >= USER_JOURNALS_MAX) {
28efac0d37ceb5093a804da6a00c620034c5484fZbigniew Jędrzejewski-Szmek /* Too many open? Then let's close one */
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers r = journal_file_open_reliably(p, O_RDWR|O_CREAT, 0640, s->system_journal, &f);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers r = hashmap_put(s->user_journals, UINT32_TO_PTR(uid), f);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (r < 0) {
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmekstatic void server_rotate(Server *s) {
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers log_error("Failed to rotate %s: %s", s->runtime_journal->path, strerror(-r));
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers log_error("Failed to rotate %s: %s", s->system_journal->path, strerror(-r));
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) {
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers log_error("Failed to rotate %s: %s", f->path, strerror(-r));
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers server_fix_perms(s, s->system_journal, PTR_TO_UINT32(k));
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers if (r < 0) {
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers log_error("Failed to get machine ID: %s", strerror(-r));
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers if (asprintf(&p, "/var/log/journal/%s", ids) < 0) {
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers r = journal_directory_vacuum(p, s->system_metrics.max_use, s->system_metrics.keep_free);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers if (r < 0 && r != -ENOENT)
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers log_error("Failed to vacuum %s: %s", p, strerror(-r));
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (asprintf(&p, "/run/log/journal/%s", ids) < 0) {
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers r = journal_directory_vacuum(p, s->runtime_metrics.max_use, s->runtime_metrics.keep_free);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (r < 0 && r != -ENOENT)
28efac0d37ceb5093a804da6a00c620034c5484fZbigniew Jędrzejewski-Szmek log_error("Failed to vacuum %s: %s", p, strerror(-r));
98fce79dea6f653dead88638fc17a27280b1f250Zbigniew Jędrzejewski-Szmek s->cached_available_space_timestamp = 0;
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &process_path);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &init_path);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers *source_time = NULL, *boot_id = NULL, *machine_id = NULL,
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers *comm = NULL, *cmdline = NULL, *hostname = NULL,
9a9bb3ca1eddc8caa2d7aa3e6e27d270e296923fMichał Bartoszkiewicz *audit_session = NULL, *audit_loginuid = NULL,
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers *owner_uid = NULL, *unit = NULL, *selinux_context = NULL;
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers bool vacuumed = false;
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers if (asprintf(&pid, "_PID=%lu", (unsigned long) ucred->pid) >= 0)
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (asprintf(&uid, "_UID=%lu", (unsigned long) ucred->uid) >= 0)
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering if (asprintf(&gid, "_GID=%lu", (unsigned long) ucred->gid) >= 0)
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (r >= 0) {
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers r = get_process_cmdline(ucred->pid, LINE_MAX, false, &t);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (r >= 0) {
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers if (asprintf(&audit_session, "_AUDIT_SESSION=%lu", (unsigned long) audit) >= 0)
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers r = audit_loginuid_from_pid(ucred->pid, &loginuid);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (asprintf(&audit_loginuid, "_AUDIT_LOGINUID=%lu", (unsigned long) loginuid) >= 0)
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek t = shortened_cgroup_path(ucred->pid);
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek IOVEC_SET_STRING(iovec[n++], session);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (sd_pid_get_owner_uid(ucred->uid, &owner) >= 0)
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (asprintf(&owner_uid, "_SYSTEMD_OWNER_UID=%lu", (unsigned long) owner) >= 0)
8adaf7bd23baa6e2cd99e9e88e55d0f5f5db29a2Richard Maw selinux_context = malloc(sizeof("_SELINUX_CONTEXT=") + label_len);
b2fadec6048adb3596f2633cb7fe7a49f5937a18Zbigniew Jędrzejewski-Szmek memcpy(selinux_context, "_SELINUX_CONTEXT=", sizeof("_SELINUX_CONTEXT=")-1);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers memcpy(selinux_context+sizeof("_SELINUX_CONTEXT=")-1, label, label_len);
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek selinux_context[sizeof("_SELINUX_CONTEXT=")-1+label_len] = 0;
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek IOVEC_SET_STRING(iovec[n++], selinux_context);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers selinux_context = strappend("_SELINUX_CONTEXT=", con);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers if (asprintf(&source_time, "_SOURCE_REALTIME_TIMESTAMP=%llu",
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers /* Note that strictly speaking storing the boot id here is
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers * redundant since the entry includes this in-line
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers * anyway. However, we need this indexed, too. */
98fce79dea6f653dead88638fc17a27280b1f250Zbigniew Jędrzejewski-Szmek if (asprintf(&boot_id, "_BOOT_ID=%s", sd_id128_to_string(id, idbuf)) >= 0)
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (asprintf(&machine_id, "_MACHINE_ID=%s", sd_id128_to_string(id, idbuf)) >= 0)
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers f = find_journal(s, realuid == 0 ? 0 : loginuid);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers log_warning("Dropping message, as we can't find a place to store the data.");
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek r = journal_file_append_entry(f, NULL, iovec, n, &s->seqnum, NULL, NULL);
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek if ((r == -E2BIG || /* hit limit */
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek r == -EFBIG || /* hit fs limit */
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers r == -EPROTONOSUPPORT) && /* unsupported feature */
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers log_info("Allocation limit reached, rotating.");
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers log_warning("Journal file corrupted, rotating.");
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers log_error("Failed to write entry, ignoring: %s", strerror(-r));
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmekstatic void driver_message(Server *s, sd_id128_t message_id, const char *format, ...) {
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek char buffer[16 + LINE_MAX + 1];
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek struct iovec iovec[N_IOVEC_META_FIELDS + 4];
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek IOVEC_SET_STRING(iovec[n++], "PRIORITY=5");
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=driver");
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek vsnprintf(buffer + 8, sizeof(buffer) - 8, format, ap);
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek IOVEC_SET_STRING(iovec[n++], buffer);
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek snprintf(mid, sizeof(mid), "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(message_id));
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek IOVEC_SET_STRING(iovec[n++], mid);
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &ucred, NULL, NULL, 0);
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmekstatic void dispatch_message(Server *s,
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek struct iovec *iovec, unsigned n, unsigned m,
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek const char *label, size_t label_len,
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek path = shortened_cgroup_path(ucred->pid);
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek /* example: /user/lennart/3/foobar
81fd105a5f9762fa2f2e42bc949876e32b3a126fZbigniew Jędrzejewski-Szmek * So let's cut of everything past the third /, since that is
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek * wher user directories start */
387066c2e5bda159201896b194711965b52f34a9Michal Sekletar rl = journal_rate_limit_test(s->rate_limit, path, priority & LOG_PRIMASK, available_space(s));
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek /* Write a suppression message if we suppressed something */
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmek driver_message(s, SD_MESSAGE_JOURNAL_DROPPED, "Suppressed %u messages from %s", rl - 1, path);
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek dispatch_message_real(s, iovec, n, m, ucred, tv, label, label_len);
0732ef7acf37473847992888bcb6446726d9d877Zbigniew Jędrzejewski-Szmekstatic void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned n_iovec, struct ucred *ucred, struct timeval *tv) {
78bd12a05a9252cf573da28394b23e2b891cbba8Zbigniew Jędrzejewski-Szmek uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
78bd12a05a9252cf573da28394b23e2b891cbba8Zbigniew Jędrzejewski-Szmek msghdr.msg_iov = (struct iovec*) iovec;
87699fe313cf8919917f2ea422b8d10b3ae3b244Daniel Mack strncpy(sa.un.sun_path, "/run/systemd/journal/syslog", sizeof(sa.un.sun_path));
78bd12a05a9252cf573da28394b23e2b891cbba8Zbigniew Jędrzejewski-Szmek msghdr.msg_namelen = offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path);
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek msghdr.msg_controllen = sizeof(control);
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek cmsg->cmsg_type = SCM_CREDENTIALS;
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek memcpy(CMSG_DATA(cmsg), ucred, sizeof(struct ucred));
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek msghdr.msg_controllen = cmsg->cmsg_len;
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek /* Forward the syslog message we received via /dev/log to
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek * /run/systemd/syslog. Unfortunately we currently can't set
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek * the SO_TIMESTAMP auxiliary data, and hence we don't. */
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0)
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek /* The socket is full? I guess the syslog implementation is
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek * too slow, and we shouldn't wait for that... */
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek /* Hmm, presumably the sender process vanished
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek * by now, so let's fix it as good as we
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek * can, and retry */
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers memcpy(CMSG_DATA(cmsg), &u, sizeof(struct ucred));
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0)
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers log_debug("Failed to forward syslog message: %m");
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversstatic void forward_syslog_raw(Server *s, const char *buffer, struct ucred *ucred, struct timeval *tv) {
b47d419c25ecc735615a1088060c1ec8bef1e41fZbigniew Jędrzejewski-Szmek IOVEC_SET_STRING(iovec, buffer);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversstatic void forward_syslog(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred, struct timeval *tv) {
87699fe313cf8919917f2ea422b8d10b3ae3b244Daniel Mack char header_priority[6], header_time[64], header_pid[16];
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers /* First: priority field */
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek snprintf(header_priority, sizeof(header_priority), "<%i>", priority);
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek IOVEC_SET_STRING(iovec[n++], header_priority);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers /* Second: timestamp */
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers t = tv ? tv->tv_sec : ((time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC));
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers /* Third: identifier and PID */
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering get_process_comm(ucred->pid, &ident_buf);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers /* Fourth: message */
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversstatic void forward_kmsg(Server *s, int priority, const char *identifier, const char *message, struct ucred *ucred) {
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering /* Never allow messages with kernel facility to be written to
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers * kmsg, regardless where the data comes from. */
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers /* First: priority field */
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers snprintf(header_priority, sizeof(header_priority), "<%i>", priority);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering IOVEC_SET_STRING(iovec[n++], header_priority);
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek /* Second: identifier and PID */
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid);
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek IOVEC_SET_STRING(iovec[n++], header_pid);
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek IOVEC_SET_STRING(iovec[n++], identifier);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers /* Fourth: message */
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC);
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering log_debug("Failed to open /dev/kmsg for logging: %s", strerror(errno));
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek log_debug("Failed to write to /dev/kmsg for logging: %s", strerror(errno));
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmekstatic void forward_console(Server *s, const char *identifier, const char *message, struct ucred *ucred) {
4e829d218cb2ba7e50616945007081f4c7fe0e29Zbigniew Jędrzejewski-Szmek /* First: identifier and PID */
28efac0d37ceb5093a804da6a00c620034c5484fZbigniew Jędrzejewski-Szmek get_process_comm(ucred->pid, &ident_buf);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) ucred->pid);
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek IOVEC_SET_STRING(iovec[n++], identifier);
c529695e7a30b300fdaa61ace4a8a4ed0e94ad1cLennart Poettering IOVEC_SET_STRING(iovec[n++], header_pid);
c529695e7a30b300fdaa61ace4a8a4ed0e94ad1cLennart Poettering IOVEC_SET_STRING(iovec[n++], identifier);
c529695e7a30b300fdaa61ace4a8a4ed0e94ad1cLennart Poettering /* Third: message */
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers log_debug("Failed to open /dev/console for logging: %s", strerror(errno));
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers log_debug("Failed to write to /dev/console for logging: %s", strerror(errno));
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversstatic void read_identifier(const char **buf, char **identifier, char **pid) {
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers const char *p;
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (p[k] == '[') {
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poetteringstatic void process_syslog_message(Server *s, const char *buf, struct ucred *ucred, struct timeval *tv, const char *label, size_t label_len) {
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers char *message = NULL, *syslog_priority = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *syslog_pid = NULL;
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers unsigned n = 0;
d14ab08b29d5b0b3ead6e63ac8be472f273011f9Lennart Poettering parse_syslog_priority((char**) &buf, &priority);
c529695e7a30b300fdaa61ace4a8a4ed0e94ad1cLennart Poettering read_identifier(&buf, &identifier, &pid);
c529695e7a30b300fdaa61ace4a8a4ed0e94ad1cLennart Poettering forward_kmsg(s, priority, identifier, buf, ucred);
c529695e7a30b300fdaa61ace4a8a4ed0e94ad1cLennart Poettering forward_console(s, identifier, buf, ucred);
c529695e7a30b300fdaa61ace4a8a4ed0e94ad1cLennart Poettering IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=syslog");
ebcf1f97de4f6b1580ae55eb56b1a3939fe6b602Lennart Poettering if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0)
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0)
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek IOVEC_SET_STRING(iovec[n++], syslog_facility);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers syslog_identifier = strappend("SYSLOG_IDENTIFIER=", identifier);
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt IOVEC_SET_STRING(iovec[n++], syslog_identifier);
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek syslog_pid = strappend("SYSLOG_PID=", pid);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers dispatch_message(s, iovec, n, ELEMENTSOF(iovec), ucred, tv, label, label_len, priority);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversstatic bool valid_user_field(const char *p, size_t l) {
df2d202e6ed4001a21c6512c244acad5d4706c87Lennart Poettering const char *a;
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers /* We kinda enforce POSIX syntax recommendations for
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmann environment variables here, but make a couple of additional
8433e33955f797510a3f323da9ffa08d12c374f4Jan Synacek http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering /* No empty field names */
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmann return false;
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmann /* Don't allow names longer than 64 chars */
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmann return false;
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmann /* Variables starting with an underscore are protected */
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmann if (p[0] == '_')
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmann return false;
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmann /* Don't allow digits as first character */
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmann return false;
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmann /* Only allow A-Z0-9 and '_' */
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmann for (a = p; a < p + l; a++)
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmann return false;
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmann unsigned n = 0, m = 0, j, tn = (unsigned) -1;
d4f5a1f47dbd04f26f2ddf951c97c4cb0ebbbe62David Herrmann const char *p;
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers while (remaining > 0) {
102d8f8169427cb68cdebf5ee0f0e07788e9c2b2Kay Sievers const char *e, *q;
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering /* Trailing noise, let's ignore it, and flush what we collected */
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers log_debug("Received message with trailing noise, ignoring.");
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers if (e == p) {
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers /* Entry separator */
0b507b17a760b21e33fc52ff377db6aa5086c680Lennart Poettering dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, priority);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers /* Ignore control commands for now, and
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers * comments too. */
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers /* A property follows */
c529695e7a30b300fdaa61ace4a8a4ed0e94ad1cLennart Poettering u = MAX((n+N_IOVEC_META_FIELDS+1) * 2U, 4U);
c529695e7a30b300fdaa61ace4a8a4ed0e94ad1cLennart Poettering c = realloc(iovec, u * sizeof(struct iovec));
8433e33955f797510a3f323da9ffa08d12c374f4Jan Synacek if (valid_user_field(p, q - p)) {
8623d3a3b2e3463fa6e4ded734323483540c3ed4David Herrmann /* If the field name starts with an
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek * underscore, skip the variable,
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmek * since that indidates a trusted
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers /* We need to determine the priority
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt * of this entry for the rate limiting
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (l == 10 &&
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek priority = (priority & LOG_FACMASK) | (p[9] - '0');
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek else if (l == 17 &&
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek memcmp(p, "SYSLOG_FACILITY=", 16) == 0 &&
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering priority = (priority & LOG_PRIMASK) | ((p[16] - '0') << 3);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers else if (l == 18 &&
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers priority = (priority & LOG_PRIMASK) | (((p[16] - '0')*10 + (p[17] - '0')) << 3);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers else if (l >= 12 &&
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers } else if (l >= 8 &&
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (remaining < e - p + 1 + sizeof(uint64_t) + 1) {
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers log_debug("Failed to parse message, ignoring.");
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt if (remaining < e - p + 1 + sizeof(uint64_t) + l + 1 ||
5bb658a1784a0fd4f0f32adb4b1fb636ff503f7dKay Sievers log_debug("Failed to parse message, ignoring.");
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers memcpy(k, p, e - p);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers k[e - p] = '=';
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers if (valid_user_field(p, e - p)) {
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers remaining -= (e - p) + 1 + sizeof(uint64_t) + l + 1;
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers IOVEC_SET_STRING(iovec[tn], "_TRANSPORT=journal");
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers forward_syslog(s, priority, identifier, message, ucred, tv);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers forward_kmsg(s, priority, identifier, message, ucred);
cde93897cdefdd7c7f66c400a61e42ceee5f6a46Lennart Poettering forward_console(s, identifier, message, ucred);
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, priority);
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers for (j = 0; j < n; j++) {
37224a5ff522a366b353e8a01e2c2eee1e5416e5Lennart Poettering (const uint8_t*) iovec[j].iov_base >= (const uint8_t*) buffer + buffer_size)
static void process_native_file(
Server *s,
int fd,
ssize_t n;
assert(s);
free(p);
int priority;
assert(s);
assert(p);
if (isempty(p))
if (s->level_prefix)
if (s->identifier) {
if (syslog_identifier)
if (message)
#ifdef HAVE_SELINUX
if (s->security_context) {
dispatch_message(s->server, iovec, n, ELEMENTSOF(iovec), &s->ucred, NULL, label, label_len, priority);
assert(s);
assert(p);
p = strstrip(p);
switch (s->state) {
case STDOUT_STREAM_IDENTIFIER:
if (isempty(p))
if (!s->identifier) {
return -ENOMEM;
case STDOUT_STREAM_PRIORITY:
return -EINVAL;
r = parse_boolean(p);
return -EINVAL;
s->level_prefix = !!r;
r = parse_boolean(p);
return -EINVAL;
s->forward_to_syslog = !!r;
r = parse_boolean(p);
return -EINVAL;
s->forward_to_kmsg = !!r;
r = parse_boolean(p);
return -EINVAL;
s->forward_to_console = !!r;
case STDOUT_STREAM_RUNNING:
return stdout_stream_log(s, p);
assert(s);
p = s->buffer;
char *end;
if (end)
*end = 0;
r = stdout_stream_line(s, p);
p += skip;
p[remaining] = 0;
r = stdout_stream_line(s, p);
p += remaining;
remaining = 0;
if (p > s->buffer) {
ssize_t l;
assert(s);
return -errno;
r = stdout_stream_scan(s, true);
s->length += l;
r = stdout_stream_scan(s, false);
assert(s);
if (s->server) {
if (s->fd >= 0) {
if (s->server)
#ifdef HAVE_SELINUX
if (s->security_context)
free(s);
int fd, r;
assert(s);
if (fd < 0) {
return -errno;
if (!stream) {
return -ENOMEM;
r = -errno;
goto fail;
#ifdef HAVE_SELINUX
r = -errno;
goto fail;
r = -errno;
goto fail;
s->n_stdout_streams ++;
fail:
usec_t r;
assert(t);
p = *_p;
k = undecchar(p[i]);
k = undecchar(p[i]);
char *message = NULL, *syslog_priority = NULL, *syslog_pid = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *source_time = NULL;
assert(s);
assert(p);
if (isempty(p))
(unsigned long long) usec) >= 0)
if (s->forward_to_syslog)
if (s->forward_to_syslog)
if (identifier) {
if (syslog_identifier)
if (pid) {
if (syslog_pid)
if (message)
assert(s);
p = s->proc_kmsg_buffer;
char *end;
if (end)
*end = 0;
proc_kmsg_line(s, p);
p += skip;
if (p > s->proc_kmsg_buffer) {
char *fn;
if (!s->system_journal) {
if (!fn)
return -ENOMEM;
if (!fn)
return -ENOMEM;
if (!s->runtime_journal) {
if (!fn)
return -ENOMEM;
if (s->system_journal) {
if (r != -ENOENT)
if (s->runtime_journal) {
sd_journal *j;
assert(s);
if (!s->runtime_journal)
if (!s->system_journal)
SD_JOURNAL_FOREACH(j) {
JournalFile *f;
f = j->current_file;
goto finish;
if (r == -E2BIG) {
server_rotate(s);
server_vacuum(s);
goto finish;
ssize_t l;
assert(s);
l = read(s->proc_kmsg_fd, s->proc_kmsg_buffer + s->proc_kmsg_length, sizeof(s->proc_kmsg_buffer) - 1 - s->proc_kmsg_length);
return -errno;
s->proc_kmsg_length += l;
proc_kmsg_scan(s);
assert(s);
if (s->proc_kmsg_fd < 0)
r = server_read_proc_kmsg(s);
assert(s);
ssize_t n;
return -EIO;
if (n != sizeof(sfsi)) {
return -EIO;
return -errno;
return -EIO;
r = server_read_proc_kmsg(s);
return -EIO;
} control;
ssize_t n;
unsigned n_fds = 0;
return -errno;
size_t l;
return -ENOMEM;
s->buffer_size = l;
s->buffer = b;
return -errno;
if (n > 0 && n_fds == 0) {
s->buffer[n] = 0;
} else if (n_fds > 0)
if (n > 0 && n_fds == 0)
else if (n_fds > 0)
return -EIO;
return -EIO;
int one, r;
assert(s);
if (s->syslog_fd < 0) {
if (s->syslog_fd < 0) {
return -errno;
r = bind(s->syslog_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
return -errno;
return -errno;
#ifdef HAVE_SELINUX
return -errno;
return -errno;
int one, r;
assert(s);
if (s->native_fd < 0) {
if (s->native_fd < 0) {
return -errno;
r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
return -errno;
return -errno;
#ifdef HAVE_SELINUX
return -errno;
return -errno;
assert(s);
if (s->stdout_fd < 0) {
if (s->stdout_fd < 0) {
return -errno;
r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
return -errno;
return -errno;
return -errno;
assert(s);
if (!s->import_proc_kmsg)
if (s->proc_kmsg_fd < 0) {
return -errno;
assert(s);
if (s->signal_fd < 0) {
return -errno;
return -errno;
size_t l;
char *word;
if (!word) {
r = -ENOMEM;
goto finish;
s->forward_to_syslog = r;
s->forward_to_kmsg = r;
s->forward_to_console = r;
FILE *f;
const char *fn;
assert(s);
return -errno;
r = config_parse(fn, f, "Journal\0", config_item_perf_lookup, (void*) journald_gperf_lookup, false, s);
fclose(f);
int n, r, fd;
assert(s);
zero(*s);
s->compress = true;
s->forward_to_syslog = true;
s->import_proc_kmsg = true;
if (!s->user_journals) {
return -ENOMEM;
if (s->epoll_fd < 0) {
return -errno;
n = sd_listen_fds(true);
if (s->native_fd >= 0) {
return -EINVAL;
if (s->stdout_fd >= 0) {
return -EINVAL;
if (s->syslog_fd >= 0) {
return -EINVAL;
return -EINVAL;
r = open_syslog_socket(s);
r = open_native_socket(s);
r = open_stdout_socket(s);
r = open_proc_kmsg(s);
r = open_signalfd(s);
if (!s->rate_limit)
return -ENOMEM;
r = system_journal_open(s);
JournalFile *f;
assert(s);
while (s->stdout_streams)
if (s->system_journal)
if (s->runtime_journal)
if (s->epoll_fd >= 0)
if (s->signal_fd >= 0)
if (s->syslog_fd >= 0)
if (s->native_fd >= 0)
if (s->stdout_fd >= 0)
if (s->proc_kmsg_fd >= 0)
if (s->rate_limit)
return EXIT_FAILURE;
log_open();
goto finish;
sd_notify(false,
r = -errno;
goto finish;
goto finish;
sd_notify(false,