journalctl.c revision 730836403aee5f5bb998e6e3622ea7068fce0699
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen/***
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen This file is part of systemd.
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen Copyright 2011 Lennart Poettering
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen systemd is free software; you can redistribute it and/or modify it
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen under the terms of the GNU Lesser General Public License as published by
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen the Free Software Foundation; either version 2.1 of the License, or
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen (at your option) any later version.
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen systemd is distributed in the hope that it will be useful, but
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen Lesser General Public License for more details.
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen You should have received a copy of the GNU Lesser General Public License
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen***/
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include <locale.h>
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include <fcntl.h>
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include <fnmatch.h>
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include <errno.h>
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include <stddef.h>
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include <string.h>
1346b1f0388f4100bb3c2a2bb23bc881769c020cTom Gundersen#include <stdio.h>
f5be560181d092c5f52a2b819aedcd48220f36abTom Gundersen#include <unistd.h>
dd43110f781a9245ec00531456fee68ed763a179Tom Gundersen#include <stdlib.h>
5c1d3fc93d91384bbac29adf01074fa4375317eaUmut Tezduyar Lindskog#include <time.h>
4138fb2c7936758da709eaed3f6b4f3df1d04effPatrik Flykt#include <getopt.h>
4138fb2c7936758da709eaed3f6b4f3df1d04effPatrik Flykt#include <signal.h>
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include <sys/stat.h>
ce43e484465050c619ea9a1991d49b3d6215028bSusant Sahani#include <sys/ioctl.h>
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include <linux/fs.h>
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#ifdef HAVE_ACL
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include <sys/acl.h>
06f021a8048583d66202e3ac5cd0a12386d33ac2Tom Gundersen#include "acl-util.h"
134e56dcc53970a20a858283650bb92cd5da1d17Lennart Poettering#endif
3b653205cf7bd3851befd0a9f6a3ded6e267c173Lennart Poettering
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include "systemd/sd-journal.h"
aba496a58acf9d9c61314de71353550e579f85eeUmut Tezduyar Lindskog
4faefc7ff884eae65a80e82313fd9f4bb859d6dbLennart Poettering#include "log.h"
4faefc7ff884eae65a80e82313fd9f4bb859d6dbLennart Poettering#include "logs-show.h"
aba496a58acf9d9c61314de71353550e579f85eeUmut Tezduyar Lindskog#include "util.h"
1a436809498faf6486815baa0338fb6b8e5def07Tom Gundersen#include "path-util.h"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include "fileio.h"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include "build.h"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include "pager.h"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include "strv.h"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include "set.h"
11bf3cced13c885ca215c108cb0bdb7a148520d6Lennart Poettering#include "journal-internal.h"
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta#include "journal-def.h"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include "journal-verify.h"
cb9fc36a1211967e8c58b0502a26c42552ac8060Lennart Poettering#include "journal-authenticate.h"
769d324c99aab129148bd25f5f663ef441287d86Lennart Poettering#include "journal-qrcode.h"
769d324c99aab129148bd25f5f663ef441287d86Lennart Poettering#include "fsprg.h"
769d324c99aab129148bd25f5f663ef441287d86Lennart Poettering#include "unit-name.h"
769d324c99aab129148bd25f5f663ef441287d86Lennart Poettering#include "catalog.h"
769d324c99aab129148bd25f5f663ef441287d86Lennart Poettering
cb9fc36a1211967e8c58b0502a26c42552ac8060Lennart Poettering#define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
cb9fc36a1211967e8c58b0502a26c42552ac8060Lennart Poettering
cb9fc36a1211967e8c58b0502a26c42552ac8060Lennart Poetteringstatic OutputMode arg_output = OUTPUT_SHORT;
ed942a9eb22d50f667909ad6184b45015d28d054Tom Gundersenstatic bool arg_pager_end = false;
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersenstatic bool arg_follow = false;
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersenstatic bool arg_full = true;
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersenstatic bool arg_all = false;
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersenstatic bool arg_no_pager = false;
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersenstatic int arg_lines = -1;
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersenstatic bool arg_no_tail = false;
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersenstatic bool arg_quiet = false;
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersenstatic bool arg_merge = false;
b98b483bac585af754e8a22ea890db8486905d8aAlin Rautastatic bool arg_boot = false;
b98b483bac585af754e8a22ea890db8486905d8aAlin Rautastatic sd_id128_t arg_boot_id = {};
b98b483bac585af754e8a22ea890db8486905d8aAlin Rautastatic int arg_boot_offset = 0;
b98b483bac585af754e8a22ea890db8486905d8aAlin Rautastatic bool arg_dmesg = false;
b98b483bac585af754e8a22ea890db8486905d8aAlin Rautastatic const char *arg_cursor = NULL;
b98b483bac585af754e8a22ea890db8486905d8aAlin Rautastatic const char *arg_after_cursor = NULL;
b98b483bac585af754e8a22ea890db8486905d8aAlin Rautastatic bool arg_show_cursor = false;
b98b483bac585af754e8a22ea890db8486905d8aAlin Rautastatic const char *arg_directory = NULL;
b98b483bac585af754e8a22ea890db8486905d8aAlin Rautastatic char **arg_file = NULL;
b98b483bac585af754e8a22ea890db8486905d8aAlin Rautastatic int arg_priorities = 0xFF;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic const char *arg_verify_key = NULL;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#ifdef HAVE_GCRYPT
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic bool arg_force = false;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#endif
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic usec_t arg_since, arg_until;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic bool arg_since_set = false, arg_until_set = false;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic char **arg_syslog_identifier = NULL;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic char **arg_system_units = NULL;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic char **arg_user_units = NULL;
edb85f0d8d0a84f27308a3728f3fde3c52b9dce2Susant Sahanistatic const char *arg_field = NULL;
edb85f0d8d0a84f27308a3728f3fde3c52b9dce2Susant Sahanistatic bool arg_catalog = false;
2cc412b59353576cece2d5b30c6a39c70552f0a0Tom Gundersenstatic bool arg_reverse = false;
2cc412b59353576cece2d5b30c6a39c70552f0a0Tom Gundersenstatic int arg_journal_type = 0;
2cc412b59353576cece2d5b30c6a39c70552f0a0Tom Gundersenstatic const char *arg_root = NULL;
edbb03e95a3c31bf719d5c6c46eec14d0bcb9c8fTom Gundersenstatic const char *arg_machine = NULL;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic enum {
1a436809498faf6486815baa0338fb6b8e5def07Tom Gundersen ACTION_SHOW,
1a436809498faf6486815baa0338fb6b8e5def07Tom Gundersen ACTION_NEW_ID128,
6a0a2f860f1ca4a10932da3b41dbc3c0139757ccTom Gundersen ACTION_PRINT_HEADER,
cb9fc36a1211967e8c58b0502a26c42552ac8060Lennart Poettering ACTION_SETUP_KEYS,
5be4d38e31281727b6f45ae869136bb01a1f7790Tom Gundersen ACTION_VERIFY,
bcb7a07e0a785bda1eed658e984ff6b4a11cba9aTom Gundersen ACTION_DISK_USAGE,
4f882b2a5007e51032459e29d15a86df6b5ea9f4Tom Gundersen ACTION_LIST_CATALOG,
1346b1f0388f4100bb3c2a2bb23bc881769c020cTom Gundersen ACTION_DUMP_CATALOG,
ad0734e890b25751ef8229e47210ff11ae8fa3f3Tom Gundersen ACTION_UPDATE_CATALOG,
4cc7a82c9490a3c5ae03b1d6d168ce40ba499e23Eugene Yakubovich ACTION_LIST_BOOTS,
f5de5b00204f041aaec828d336c8afd9e860a5c3Tom Gundersen} arg_action = ACTION_SHOW;
eb27aeca247a4cf8816fffc4c0dbcab55ead3864Tom Gundersen
e1ea665edac17d75fce01b72dadfa3211b60df2cEugene Yakubovichtypedef struct boot_id_t {
84b5b79a8f7b423c5b7cad4170eb68d57fe5e26cAngus Gibson sd_id128_t id;
5c1d3fc93d91384bbac29adf01074fa4375317eaUmut Tezduyar Lindskog uint64_t first;
bfa695b5cc37aeb78737c57c84e9e69ea08152c0Tom Gundersen uint64_t last;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen} boot_id_t;
dd43110f781a9245ec00531456fee68ed763a179Tom Gundersen
dd43110f781a9245ec00531456fee68ed763a179Tom Gundersenstatic void pager_open_if_enabled(void) {
e1853b00ef7cb56cafd908327dd44b3ab48b402cSusant Sahani
e1853b00ef7cb56cafd908327dd44b3ab48b402cSusant Sahani if (arg_no_pager)
769d324c99aab129148bd25f5f663ef441287d86Lennart Poettering return;
5a8bcb674f71a20e95df55319b34c556638378ceLennart Poettering
5a8bcb674f71a20e95df55319b34c556638378ceLennart Poettering pager_open(arg_pager_end);
c106cc36b9b8e8998eb95299b02f1db9c1209122Tom Gundersen}
c106cc36b9b8e8998eb95299b02f1db9c1209122Tom Gundersen
c106cc36b9b8e8998eb95299b02f1db9c1209122Tom Gundersenstatic int parse_boot_descriptor(const char *x, sd_id128_t *boot_id, int *offset) {
ce43e484465050c619ea9a1991d49b3d6215028bSusant Sahani sd_id128_t id = SD_ID128_NULL;
ce43e484465050c619ea9a1991d49b3d6215028bSusant Sahani int off = 0, r;
f048a16b464295a4e0a4f4c1210f06343ad31231Tom Gundersen
f048a16b464295a4e0a4f4c1210f06343ad31231Tom Gundersen if (strlen(x) >= 32) {
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta char *t;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
6ae115c1fe95611b39d2f20cfcea3d385429f59eTom Gundersen t = strndupa(x, 32);
6ae115c1fe95611b39d2f20cfcea3d385429f59eTom Gundersen r = sd_id128_from_string(t, &id);
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta if (r >= 0)
6ae115c1fe95611b39d2f20cfcea3d385429f59eTom Gundersen x += 32;
67272d157a35e5cda4e5c904eafdcc23d20541d1Tom Gundersen
6192b846ca0d15602e94ddb5da4420b7c60d64a5Tom Gundersen if (*x != '-' && *x != '+' && *x != 0)
06f021a8048583d66202e3ac5cd0a12386d33ac2Tom Gundersen return -EINVAL;
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersen
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersen if (*x != 0) {
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen r = safe_atoi(x, &off);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen if (r < 0)
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen return r;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen }
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen } else {
16aa63a00b5b1db23a9c0b8de350ebf482d90cd0Tom Gundersen r = safe_atoi(x, &off);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen if (r < 0)
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering return r;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen }
5c1d3fc93d91384bbac29adf01074fa4375317eaUmut Tezduyar Lindskog
81163121e649523b4071f67ddc03c2db649036c5Tom Gundersen if (boot_id)
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen *boot_id = id;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
eb0ea358b688a6f83ff305c6b825c61f12b6dcb8Tom Gundersen if (offset)
aba496a58acf9d9c61314de71353550e579f85eeUmut Tezduyar Lindskog *offset = off;
8cd11a0f0f4ca05199e1166f6a07472b296f7455Tom Gundersen
5d3de3fe9cc452f1bfe3c2dcafecbd7f904da4dcLennart Poettering return 0;
c081882f07617e56bcbce54105068137e4e0bb52Susant Sahani}
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
fd6d906cf46ecef45ebbb5a361e1dc436f031d7aLennart Poetteringstatic void help(void) {
5a8bcb674f71a20e95df55319b34c556638378ceLennart Poettering
3d3d425547a3f38473fcf8737b85dfebb630479dTom Gundersen pager_open_if_enabled();
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen printf("%s [OPTIONS...] [MATCHES...]\n\n"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen "Query the journal.\n\n"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen "Flags:\n"
16aa63a00b5b1db23a9c0b8de350ebf482d90cd0Tom Gundersen " --system Show the system journal\n"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen " --user Show the user journal for the current user\n"
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering " -M --machine=CONTAINER Operate on local container\n"
6ae115c1fe95611b39d2f20cfcea3d385429f59eTom Gundersen " --since=DATE Start showing entries on or newer than the specified date\n"
9e7e440835c43d81ffdbc299d2c07daaa641ed50Tom Gundersen " --until=DATE Stop showing entries on or older than the specified date\n"
5c1d3fc93d91384bbac29adf01074fa4375317eaUmut Tezduyar Lindskog " -c --cursor=CURSOR Start showing entries from the specified cursor\n"
5c1d3fc93d91384bbac29adf01074fa4375317eaUmut Tezduyar Lindskog " --after-cursor=CURSOR Start showing entries from after the specified cursor\n"
28cc555d8504c9429776aedbbe1fee7101258578Dan Williams " --show-cursor Print the cursor after all the entries\n"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen " -b --boot[=ID] Show data only from ID or, if unspecified, the current boot\n"
5d3de3fe9cc452f1bfe3c2dcafecbd7f904da4dcLennart Poettering " --list-boots Show terse information about recorded boots\n"
5d3de3fe9cc452f1bfe3c2dcafecbd7f904da4dcLennart Poettering " -k --dmesg Show kernel message log from the current boot\n"
9e7e440835c43d81ffdbc299d2c07daaa641ed50Tom Gundersen " -u --unit=UNIT Show data only from the specified unit\n"
46b0c76e2c355c0d0cc4792abb98cde07b28bc53Emil Renner Berthing " --user-unit=UNIT Show data only from the specified user session unit\n"
6ae115c1fe95611b39d2f20cfcea3d385429f59eTom Gundersen " -t --identifier=STRING Show only messages with the specified syslog identifier\n"
3d3d425547a3f38473fcf8737b85dfebb630479dTom Gundersen " -p --priority=RANGE Show only messages within the specified priority range\n"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen " -e --pager-end Immediately jump to end of the journal in the pager\n"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen " -f --follow Follow the journal\n"
11bf3cced13c885ca215c108cb0bdb7a148520d6Lennart Poettering " -n --lines[=INTEGER] Number of journal entries to show\n"
11bf3cced13c885ca215c108cb0bdb7a148520d6Lennart Poettering " --no-tail Show all lines, even in follow mode\n"
11bf3cced13c885ca215c108cb0bdb7a148520d6Lennart Poettering " -r --reverse Show the newest entries first\n"
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering " -o --output=STRING Change journal output mode (short, short-iso,\n"
11bf3cced13c885ca215c108cb0bdb7a148520d6Lennart Poettering " short-precise, short-monotonic, verbose,\n"
11bf3cced13c885ca215c108cb0bdb7a148520d6Lennart Poettering " export, json, json-pretty, json-sse, cat)\n"
11bf3cced13c885ca215c108cb0bdb7a148520d6Lennart Poettering " -x --catalog Add message explanations where available\n"
11bf3cced13c885ca215c108cb0bdb7a148520d6Lennart Poettering " --no-full Ellipsize fields\n"
11bf3cced13c885ca215c108cb0bdb7a148520d6Lennart Poettering " -a --all Show all fields, including long and unprintable\n"
11bf3cced13c885ca215c108cb0bdb7a148520d6Lennart Poettering " -q --quiet Do not show privilege warning\n"
11bf3cced13c885ca215c108cb0bdb7a148520d6Lennart Poettering " --no-pager Do not pipe output into a pager\n"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen " -m --merge Show entries from all available journals\n"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen " -D --directory=PATH Show journal files from directory\n"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen " --file=PATH Show journal file\n"
9c0a72f961e00b0447767973e7117e131bea5b5dTom Gundersen " --root=ROOT Operate on catalog files underneath the root ROOT\n"
1346b1f0388f4100bb3c2a2bb23bc881769c020cTom Gundersen#ifdef HAVE_GCRYPT
9c0a72f961e00b0447767973e7117e131bea5b5dTom Gundersen " --interval=TIME Time interval for changing the FSS sealing key\n"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen " --verify-key=KEY Specify FSS verification key\n"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen " --force Force overriding of the FSS key pair with --setup-keys\n"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#endif
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen "\nCommands:\n"
6a24f1484fcc1f59f89617afbe4282667a358eabTom Gundersen " -h --help Show this help text\n"
6a24f1484fcc1f59f89617afbe4282667a358eabTom Gundersen " --version Show package version\n"
bbf7c04821a71fec67eaf0e7a34d17afc5913c13Tom Gundersen " --new-id128 Generate a new 128-bit ID\n"
bbf7c04821a71fec67eaf0e7a34d17afc5913c13Tom Gundersen " --header Show journal header information\n"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen " --disk-usage Show total disk usage of all journal files\n"
52433f6b65eccd1c54606dde999610640f3458acTom Gundersen " -F --field=FIELD List all values that a specified field takes\n"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen " --list-catalog Show message IDs of all entries in the message catalog\n"
11bf3cced13c885ca215c108cb0bdb7a148520d6Lennart Poettering " --dump-catalog Show entries in the message catalog\n"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen " --update-catalog Update the message catalog database\n"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#ifdef HAVE_GCRYPT
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen " --setup-keys Generate a new FSS key pair\n"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen " --verify Verify journal file consistency\n"
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek#endif
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek , program_invocation_short_name);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen}
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersenstatic int parse_argv(int argc, char *argv[]) {
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen enum {
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen ARG_VERSION = 0x100,
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen ARG_NO_PAGER,
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen ARG_NO_FULL,
505f8da7325591defe5f751f328bd26915267602Tom Gundersen ARG_NO_TAIL,
45af44d47da6933b260c734ad9ff721f63f80a4dTom Gundersen ARG_NEW_ID128,
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen ARG_LIST_BOOTS,
bbf7c04821a71fec67eaf0e7a34d17afc5913c13Tom Gundersen ARG_USER,
3bef724f7e7f7eaca69881548b06e221b77d7031Tom Gundersen ARG_SYSTEM,
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering ARG_ROOT,
11bf3cced13c885ca215c108cb0bdb7a148520d6Lennart Poettering ARG_HEADER,
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen ARG_SETUP_KEYS,
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen ARG_FILE,
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen ARG_INTERVAL,
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen ARG_VERIFY,
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen ARG_VERIFY_KEY,
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen ARG_DISK_USAGE,
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen ARG_SINCE,
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen ARG_UNTIL,
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen ARG_AFTER_CURSOR,
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen ARG_SHOW_CURSOR,
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen ARG_USER_UNIT,
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen ARG_LIST_CATALOG,
505f8da7325591defe5f751f328bd26915267602Tom Gundersen ARG_DUMP_CATALOG,
505f8da7325591defe5f751f328bd26915267602Tom Gundersen ARG_UPDATE_CATALOG,
505f8da7325591defe5f751f328bd26915267602Tom Gundersen ARG_FORCE,
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen };
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
69a93e7db47addc4495a6ec9dc0fc74092a6ebeeTom Gundersen static const struct option options[] = {
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen { "help", no_argument, NULL, 'h' },
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen { "version" , no_argument, NULL, ARG_VERSION },
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen { "no-pager", no_argument, NULL, ARG_NO_PAGER },
6192b846ca0d15602e94ddb5da4420b7c60d64a5Tom Gundersen { "pager-end", no_argument, NULL, 'e' },
6192b846ca0d15602e94ddb5da4420b7c60d64a5Tom Gundersen { "follow", no_argument, NULL, 'f' },
6192b846ca0d15602e94ddb5da4420b7c60d64a5Tom Gundersen { "force", no_argument, NULL, ARG_FORCE },
6192b846ca0d15602e94ddb5da4420b7c60d64a5Tom Gundersen { "output", required_argument, NULL, 'o' },
6192b846ca0d15602e94ddb5da4420b7c60d64a5Tom Gundersen { "all", no_argument, NULL, 'a' },
6192b846ca0d15602e94ddb5da4420b7c60d64a5Tom Gundersen { "full", no_argument, NULL, 'l' },
6192b846ca0d15602e94ddb5da4420b7c60d64a5Tom Gundersen { "no-full", no_argument, NULL, ARG_NO_FULL },
6192b846ca0d15602e94ddb5da4420b7c60d64a5Tom Gundersen { "lines", optional_argument, NULL, 'n' },
6192b846ca0d15602e94ddb5da4420b7c60d64a5Tom Gundersen { "no-tail", no_argument, NULL, ARG_NO_TAIL },
6192b846ca0d15602e94ddb5da4420b7c60d64a5Tom Gundersen { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
6192b846ca0d15602e94ddb5da4420b7c60d64a5Tom Gundersen { "quiet", no_argument, NULL, 'q' },
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "merge", no_argument, NULL, 'm' },
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "boot", optional_argument, NULL, 'b' },
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "list-boots", no_argument, NULL, ARG_LIST_BOOTS },
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "this-boot", optional_argument, NULL, 'b' }, /* deprecated */
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "dmesg", no_argument, NULL, 'k' },
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "system", no_argument, NULL, ARG_SYSTEM },
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "user", no_argument, NULL, ARG_USER },
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "directory", required_argument, NULL, 'D' },
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "file", required_argument, NULL, ARG_FILE },
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "root", required_argument, NULL, ARG_ROOT },
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "header", no_argument, NULL, ARG_HEADER },
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "identifier", required_argument, NULL, 't' },
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "priority", required_argument, NULL, 'p' },
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "interval", required_argument, NULL, ARG_INTERVAL },
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "verify", no_argument, NULL, ARG_VERIFY },
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "cursor", required_argument, NULL, 'c' },
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR },
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR },
7951dea20911969287878e6897b3eca348721adeSusant Sahani { "since", required_argument, NULL, ARG_SINCE },
85a8eeee36b57c1ab382b0225fa9a87525bbeee9Susant Sahani { "until", required_argument, NULL, ARG_UNTIL },
85a8eeee36b57c1ab382b0225fa9a87525bbeee9Susant Sahani { "unit", required_argument, NULL, 'u' },
85a8eeee36b57c1ab382b0225fa9a87525bbeee9Susant Sahani { "user-unit", required_argument, NULL, ARG_USER_UNIT },
85a8eeee36b57c1ab382b0225fa9a87525bbeee9Susant Sahani { "field", required_argument, NULL, 'F' },
85a8eeee36b57c1ab382b0225fa9a87525bbeee9Susant Sahani { "catalog", no_argument, NULL, 'x' },
85a8eeee36b57c1ab382b0225fa9a87525bbeee9Susant Sahani { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
85a8eeee36b57c1ab382b0225fa9a87525bbeee9Susant Sahani { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG },
85a8eeee36b57c1ab382b0225fa9a87525bbeee9Susant Sahani { "update-catalog", no_argument, NULL, ARG_UPDATE_CATALOG },
85a8eeee36b57c1ab382b0225fa9a87525bbeee9Susant Sahani { "reverse", no_argument, NULL, 'r' },
85a8eeee36b57c1ab382b0225fa9a87525bbeee9Susant Sahani { "machine", required_argument, NULL, 'M' },
85a8eeee36b57c1ab382b0225fa9a87525bbeee9Susant Sahani {}
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen };
c0dda18697e0994272c0c9616d36f6777b60e2c7Tom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen int c, r;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f048a16b464295a4e0a4f4c1210f06343ad31231Tom Gundersen assert(argc >= 0);
28cc555d8504c9429776aedbbe1fee7101258578Dan Williams assert(argv);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f882c247ad59776c3a7753bb963c1f8e2386cb79Tom Gundersen while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:t:u:F:xrM:", options, NULL)) >= 0)
5c1d3fc93d91384bbac29adf01074fa4375317eaUmut Tezduyar Lindskog
5c1d3fc93d91384bbac29adf01074fa4375317eaUmut Tezduyar Lindskog switch (c) {
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen case 'h':
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen help();
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen return 0;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
71a6151083d842b2f5bf04e50239f0bf85d34d2eTom Gundersen case ARG_VERSION:
71a6151083d842b2f5bf04e50239f0bf85d34d2eTom Gundersen puts(PACKAGE_STRING);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen puts(SYSTEMD_FEATURES);
6ae115c1fe95611b39d2f20cfcea3d385429f59eTom Gundersen return 0;
6ae115c1fe95611b39d2f20cfcea3d385429f59eTom Gundersen
6ae115c1fe95611b39d2f20cfcea3d385429f59eTom Gundersen case ARG_NO_PAGER:
6ae115c1fe95611b39d2f20cfcea3d385429f59eTom Gundersen arg_no_pager = true;
5d8e593dce074bff966fc0a46579c61b4f3bc33aSusant Sahani break;
5d8e593dce074bff966fc0a46579c61b4f3bc33aSusant Sahani
5d8e593dce074bff966fc0a46579c61b4f3bc33aSusant Sahani case 'e':
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen arg_pager_end = true;
f048a16b464295a4e0a4f4c1210f06343ad31231Tom Gundersen
f048a16b464295a4e0a4f4c1210f06343ad31231Tom Gundersen if (arg_lines < 0)
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen arg_lines = 1000;
f882c247ad59776c3a7753bb963c1f8e2386cb79Tom Gundersen
aba496a58acf9d9c61314de71353550e579f85eeUmut Tezduyar Lindskog break;
407fe036a24834203aca6c1eec7d74d9ad3e9ee0Tom Gundersen
5a8bcb674f71a20e95df55319b34c556638378ceLennart Poettering case 'f':
5a8bcb674f71a20e95df55319b34c556638378ceLennart Poettering arg_follow = true;
9505d3c6deda0452c22ab2ed47bca74b98d87a17Tom Gundersen break;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen case 'o':
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen arg_output = output_mode_from_string(optarg);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen if (arg_output < 0) {
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen log_error("Unknown output format '%s'.", optarg);
71a6151083d842b2f5bf04e50239f0bf85d34d2eTom Gundersen return -EINVAL;
71a6151083d842b2f5bf04e50239f0bf85d34d2eTom Gundersen }
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
eb0ea358b688a6f83ff305c6b825c61f12b6dcb8Tom Gundersen if (arg_output == OUTPUT_EXPORT ||
eb0ea358b688a6f83ff305c6b825c61f12b6dcb8Tom Gundersen arg_output == OUTPUT_JSON ||
eb0ea358b688a6f83ff305c6b825c61f12b6dcb8Tom Gundersen arg_output == OUTPUT_JSON_PRETTY ||
eb0ea358b688a6f83ff305c6b825c61f12b6dcb8Tom Gundersen arg_output == OUTPUT_JSON_SSE ||
6ae115c1fe95611b39d2f20cfcea3d385429f59eTom Gundersen arg_output == OUTPUT_CAT)
6ae115c1fe95611b39d2f20cfcea3d385429f59eTom Gundersen arg_quiet = true;
6ae115c1fe95611b39d2f20cfcea3d385429f59eTom Gundersen
6ae115c1fe95611b39d2f20cfcea3d385429f59eTom Gundersen break;
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta case 'l':
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta arg_full = true;
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta break;
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta case ARG_NO_FULL:
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta arg_full = false;
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta break;
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta case 'a':
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta arg_all = true;
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta break;
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta case 'n':
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta if (optarg) {
b98b483bac585af754e8a22ea890db8486905d8aAlin Rauta r = safe_atoi(optarg, &arg_lines);
ed942a9eb22d50f667909ad6184b45015d28d054Tom Gundersen if (r < 0 || arg_lines < 0) {
ed942a9eb22d50f667909ad6184b45015d28d054Tom Gundersen log_error("Failed to parse lines '%s'", optarg);
ed942a9eb22d50f667909ad6184b45015d28d054Tom Gundersen return -EINVAL;
ed942a9eb22d50f667909ad6184b45015d28d054Tom Gundersen }
ed942a9eb22d50f667909ad6184b45015d28d054Tom Gundersen } else {
ed942a9eb22d50f667909ad6184b45015d28d054Tom Gundersen int n;
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersen
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersen /* Hmm, no argument? Maybe the next
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersen * word on the command line is
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersen * supposed to be the argument? Let's
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersen * see if there is one, and is
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersen * parsable as a positive
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersen * integer... */
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersen
bd8f65387673e29f46136a4ed172097035002c23Tom Gundersen if (optind < argc &&
11bf3cced13c885ca215c108cb0bdb7a148520d6Lennart Poettering safe_atoi(argv[optind], &n) >= 0 &&
11bf3cced13c885ca215c108cb0bdb7a148520d6Lennart Poettering n >= 0) {
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering arg_lines = n;
11bf3cced13c885ca215c108cb0bdb7a148520d6Lennart Poettering optind++;
11bf3cced13c885ca215c108cb0bdb7a148520d6Lennart Poettering } else
11bf3cced13c885ca215c108cb0bdb7a148520d6Lennart Poettering arg_lines = 10;
cb9fc36a1211967e8c58b0502a26c42552ac8060Lennart Poettering }
cb9fc36a1211967e8c58b0502a26c42552ac8060Lennart Poettering
cb9fc36a1211967e8c58b0502a26c42552ac8060Lennart Poettering break;
769d324c99aab129148bd25f5f663ef441287d86Lennart Poettering
769d324c99aab129148bd25f5f663ef441287d86Lennart Poettering case ARG_NO_TAIL:
arg_no_tail = true;
break;
case ARG_NEW_ID128:
arg_action = ACTION_NEW_ID128;
break;
case 'q':
arg_quiet = true;
break;
case 'm':
arg_merge = true;
break;
case 'b':
arg_boot = true;
if (optarg) {
r = parse_boot_descriptor(optarg, &arg_boot_id, &arg_boot_offset);
if (r < 0) {
log_error("Failed to parse boot descriptor '%s'", optarg);
return -EINVAL;
}
} else {
/* Hmm, no argument? Maybe the next
* word on the command line is
* supposed to be the argument? Let's
* see if there is one and is parsable
* as a boot descriptor... */
if (optind < argc &&
parse_boot_descriptor(argv[optind], &arg_boot_id, &arg_boot_offset) >= 0)
optind++;
}
break;
case ARG_LIST_BOOTS:
arg_action = ACTION_LIST_BOOTS;
break;
case 'k':
arg_boot = arg_dmesg = true;
break;
case ARG_SYSTEM:
arg_journal_type |= SD_JOURNAL_SYSTEM;
break;
case ARG_USER:
arg_journal_type |= SD_JOURNAL_CURRENT_USER;
break;
case 'M':
arg_machine = optarg;
break;
case 'D':
arg_directory = optarg;
break;
case ARG_FILE:
r = glob_extend(&arg_file, optarg);
if (r < 0) {
log_error("Failed to add paths: %s", strerror(-r));
return r;
};
break;
case ARG_ROOT:
arg_root = optarg;
break;
case 'c':
arg_cursor = optarg;
break;
case ARG_AFTER_CURSOR:
arg_after_cursor = optarg;
break;
case ARG_SHOW_CURSOR:
arg_show_cursor = true;
break;
case ARG_HEADER:
arg_action = ACTION_PRINT_HEADER;
break;
case ARG_VERIFY:
arg_action = ACTION_VERIFY;
break;
case ARG_DISK_USAGE:
arg_action = ACTION_DISK_USAGE;
break;
#ifdef HAVE_GCRYPT
case ARG_FORCE:
arg_force = true;
break;
case ARG_SETUP_KEYS:
arg_action = ACTION_SETUP_KEYS;
break;
case ARG_VERIFY_KEY:
arg_action = ACTION_VERIFY;
arg_verify_key = optarg;
arg_merge = false;
break;
case ARG_INTERVAL:
r = parse_sec(optarg, &arg_interval);
if (r < 0 || arg_interval <= 0) {
log_error("Failed to parse sealing key change interval: %s", optarg);
return -EINVAL;
}
break;
#else
case ARG_SETUP_KEYS:
case ARG_VERIFY_KEY:
case ARG_INTERVAL:
case ARG_FORCE:
log_error("Forward-secure sealing not available.");
return -ENOTSUP;
#endif
case 'p': {
const char *dots;
dots = strstr(optarg, "..");
if (dots) {
char *a;
int from, to, i;
/* a range */
a = strndup(optarg, dots - optarg);
if (!a)
return log_oom();
from = log_level_from_string(a);
to = log_level_from_string(dots + 2);
free(a);
if (from < 0 || to < 0) {
log_error("Failed to parse log level range %s", optarg);
return -EINVAL;
}
arg_priorities = 0;
if (from < to) {
for (i = from; i <= to; i++)
arg_priorities |= 1 << i;
} else {
for (i = to; i <= from; i++)
arg_priorities |= 1 << i;
}
} else {
int p, i;
p = log_level_from_string(optarg);
if (p < 0) {
log_error("Unknown log level %s", optarg);
return -EINVAL;
}
arg_priorities = 0;
for (i = 0; i <= p; i++)
arg_priorities |= 1 << i;
}
break;
}
case ARG_SINCE:
r = parse_timestamp(optarg, &arg_since);
if (r < 0) {
log_error("Failed to parse timestamp: %s", optarg);
return -EINVAL;
}
arg_since_set = true;
break;
case ARG_UNTIL:
r = parse_timestamp(optarg, &arg_until);
if (r < 0) {
log_error("Failed to parse timestamp: %s", optarg);
return -EINVAL;
}
arg_until_set = true;
break;
case 't':
r = strv_extend(&arg_syslog_identifier, optarg);
if (r < 0)
return log_oom();
break;
case 'u':
r = strv_extend(&arg_system_units, optarg);
if (r < 0)
return log_oom();
break;
case ARG_USER_UNIT:
r = strv_extend(&arg_user_units, optarg);
if (r < 0)
return log_oom();
break;
case 'F':
arg_field = optarg;
break;
case 'x':
arg_catalog = true;
break;
case ARG_LIST_CATALOG:
arg_action = ACTION_LIST_CATALOG;
break;
case ARG_DUMP_CATALOG:
arg_action = ACTION_DUMP_CATALOG;
break;
case ARG_UPDATE_CATALOG:
arg_action = ACTION_UPDATE_CATALOG;
break;
case 'r':
arg_reverse = true;
break;
case '?':
return -EINVAL;
default:
assert_not_reached("Unhandled option");
}
if (arg_follow && !arg_no_tail && arg_lines < 0)
arg_lines = 10;
if (!!arg_directory + !!arg_file + !!arg_machine > 1) {
log_error("Please specify either -D/--directory= or --file= or -M/--machine=, not more than one.");
return -EINVAL;
}
if (arg_since_set && arg_until_set && arg_since > arg_until) {
log_error("--since= must be before --until=.");
return -EINVAL;
}
if (!!arg_cursor + !!arg_after_cursor + !!arg_since_set > 1) {
log_error("Please specify only one of --since=, --cursor=, and --after-cursor.");
return -EINVAL;
}
if (arg_follow && arg_reverse) {
log_error("Please specify either --reverse= or --follow=, not both.");
return -EINVAL;
}
if (arg_action != ACTION_SHOW && optind < argc) {
log_error("Extraneous arguments starting with '%s'", argv[optind]);
return -EINVAL;
}
return 1;
}
static int generate_new_id128(void) {
sd_id128_t id;
int r;
unsigned i;
r = sd_id128_randomize(&id);
if (r < 0) {
log_error("Failed to generate ID: %s", strerror(-r));
return r;
}
printf("As string:\n"
SD_ID128_FORMAT_STR "\n\n"
"As UUID:\n"
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
"As macro:\n"
"#define MESSAGE_XYZ SD_ID128_MAKE(",
SD_ID128_FORMAT_VAL(id),
SD_ID128_FORMAT_VAL(id));
for (i = 0; i < 16; i++)
printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
fputs(")\n\n", stdout);
printf("As Python constant:\n"
">>> import uuid\n"
">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
SD_ID128_FORMAT_VAL(id));
return 0;
}
static int add_matches(sd_journal *j, char **args) {
char **i;
bool have_term = false;
assert(j);
STRV_FOREACH(i, args) {
int r;
if (streq(*i, "+")) {
if (!have_term)
break;
r = sd_journal_add_disjunction(j);
have_term = false;
} else if (path_is_absolute(*i)) {
_cleanup_free_ char *p, *t = NULL, *t2 = NULL;
const char *path;
_cleanup_free_ char *interpreter = NULL;
struct stat st;
p = canonicalize_file_name(*i);
path = p ? p : *i;
if (stat(path, &st) < 0) {
log_error("Couldn't stat file: %m");
return -errno;
}
if (S_ISREG(st.st_mode) && (0111 & st.st_mode)) {
if (executable_is_script(path, &interpreter) > 0) {
_cleanup_free_ char *comm;
comm = strndup(basename(path), 15);
if (!comm)
return log_oom();
t = strappend("_COMM=", comm);
/* Append _EXE only if the interpreter is not a link.
Otherwise, it might be outdated often. */
if (lstat(interpreter, &st) == 0 &&
!S_ISLNK(st.st_mode)) {
t2 = strappend("_EXE=", interpreter);
if (!t2)
return log_oom();
}
} else
t = strappend("_EXE=", path);
} else if (S_ISCHR(st.st_mode)) {
if (asprintf(&t, "_KERNEL_DEVICE=c%u:%u",
major(st.st_rdev),
minor(st.st_rdev)) < 0)
return -ENOMEM;
} else if (S_ISBLK(st.st_mode)) {
if (asprintf(&t, "_KERNEL_DEVICE=b%u:%u",
major(st.st_rdev),
minor(st.st_rdev)) < 0)
return -ENOMEM;
} else {
log_error("File is neither a device node, nor regular file, nor executable: %s", *i);
return -EINVAL;
}
if (!t)
return log_oom();
r = sd_journal_add_match(j, t, 0);
if (t2)
r = sd_journal_add_match(j, t2, 0);
have_term = true;
} else {
r = sd_journal_add_match(j, *i, 0);
have_term = true;
}
if (r < 0) {
log_error("Failed to add match '%s': %s", *i, strerror(-r));
return r;
}
}
if (!strv_isempty(args) && !have_term) {
log_error("\"+\" can only be used between terms");
return -EINVAL;
}
return 0;
}
static int boot_id_cmp(const void *a, const void *b) {
uint64_t _a, _b;
_a = ((const boot_id_t *)a)->first;
_b = ((const boot_id_t *)b)->first;
return _a < _b ? -1 : (_a > _b ? 1 : 0);
}
static int list_boots(sd_journal *j) {
int r;
const void *data;
unsigned int count = 0;
int w, i;
size_t length, allocated = 0;
boot_id_t *id;
_cleanup_free_ boot_id_t *all_ids = NULL;
r = sd_journal_query_unique(j, "_BOOT_ID");
if (r < 0)
return r;
SD_JOURNAL_FOREACH_UNIQUE(j, data, length) {
if (length < strlen("_BOOT_ID="))
continue;
if (!GREEDY_REALLOC(all_ids, allocated, count + 1))
return log_oom();
id = &all_ids[count];
r = sd_id128_from_string(((const char *)data) + strlen("_BOOT_ID="), &id->id);
if (r < 0)
continue;
r = sd_journal_add_match(j, data, length);
if (r < 0)
return r;
r = sd_journal_seek_head(j);
if (r < 0)
return r;
r = sd_journal_next(j);
if (r < 0)
return r;
else if (r == 0)
goto flush;
r = sd_journal_get_realtime_usec(j, &id->first);
if (r < 0)
return r;
r = sd_journal_seek_tail(j);
if (r < 0)
return r;
r = sd_journal_previous(j);
if (r < 0)
return r;
else if (r == 0)
goto flush;
r = sd_journal_get_realtime_usec(j, &id->last);
if (r < 0)
return r;
count++;
flush:
sd_journal_flush_matches(j);
}
qsort_safe(all_ids, count, sizeof(boot_id_t), boot_id_cmp);
/* numbers are one less, but we need an extra char for the sign */
w = DECIMAL_STR_WIDTH(count - 1) + 1;
for (id = all_ids, i = 0; id < all_ids + count; id++, i++) {
char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX];
printf("% *i " SD_ID128_FORMAT_STR " %s—%s\n",
w, i - count + 1,
SD_ID128_FORMAT_VAL(id->id),
format_timestamp(a, sizeof(a), id->first),
format_timestamp(b, sizeof(b), id->last));
}
return 0;
}
static int get_relative_boot_id(sd_journal *j, sd_id128_t *boot_id, int relative) {
int r;
const void *data;
unsigned int count = 0;
size_t length, allocated = 0;
boot_id_t ref_boot_id = {SD_ID128_NULL}, *id;
_cleanup_free_ boot_id_t *all_ids = NULL;
assert(j);
assert(boot_id);
r = sd_journal_query_unique(j, "_BOOT_ID");
if (r < 0)
return r;
SD_JOURNAL_FOREACH_UNIQUE(j, data, length) {
if (length < strlen("_BOOT_ID="))
continue;
if (!GREEDY_REALLOC(all_ids, allocated, count + 1))
return log_oom();
id = &all_ids[count];
r = sd_id128_from_string(((const char *)data) + strlen("_BOOT_ID="), &id->id);
if (r < 0)
continue;
r = sd_journal_add_match(j, data, length);
if (r < 0)
return r;
r = sd_journal_seek_head(j);
if (r < 0)
return r;
r = sd_journal_next(j);
if (r < 0)
return r;
else if (r == 0)
goto flush;
r = sd_journal_get_realtime_usec(j, &id->first);
if (r < 0)
return r;
if (sd_id128_equal(id->id, *boot_id))
ref_boot_id = *id;
count++;
flush:
sd_journal_flush_matches(j);
}
qsort_safe(all_ids, count, sizeof(boot_id_t), boot_id_cmp);
if (sd_id128_equal(*boot_id, SD_ID128_NULL)) {
if (relative > (int) count || relative <= -(int)count)
return -EADDRNOTAVAIL;
*boot_id = all_ids[(relative <= 0)*count + relative - 1].id;
} else {
id = bsearch(&ref_boot_id, all_ids, count, sizeof(boot_id_t), boot_id_cmp);
if (!id ||
relative <= 0 ? (id - all_ids) + relative < 0 :
(id - all_ids) + relative >= (int) count)
return -EADDRNOTAVAIL;
*boot_id = (id + relative)->id;
}
return 0;
}
static int add_boot(sd_journal *j) {
char match[9+32+1] = "_BOOT_ID=";
int r;
assert(j);
if (!arg_boot)
return 0;
if (arg_boot_offset == 0 && sd_id128_equal(arg_boot_id, SD_ID128_NULL))
return add_match_this_boot(j, arg_machine);
r = get_relative_boot_id(j, &arg_boot_id, arg_boot_offset);
if (r < 0) {
if (sd_id128_equal(arg_boot_id, SD_ID128_NULL))
log_error("Failed to look up boot %+i: %s", arg_boot_offset, strerror(-r));
else
log_error("Failed to look up boot ID "SD_ID128_FORMAT_STR"%+i: %s",
SD_ID128_FORMAT_VAL(arg_boot_id), arg_boot_offset, strerror(-r));
return r;
}
sd_id128_to_string(arg_boot_id, match + 9);
r = sd_journal_add_match(j, match, sizeof(match) - 1);
if (r < 0) {
log_error("Failed to add match: %s", strerror(-r));
return r;
}
r = sd_journal_add_conjunction(j);
if (r < 0)
return r;
return 0;
}
static int add_dmesg(sd_journal *j) {
int r;
assert(j);
if (!arg_dmesg)
return 0;
r = sd_journal_add_match(j, "_TRANSPORT=kernel", strlen("_TRANSPORT=kernel"));
if (r < 0) {
log_error("Failed to add match: %s", strerror(-r));
return r;
}
r = sd_journal_add_conjunction(j);
if (r < 0)
return r;
return 0;
}
static int get_possible_units(sd_journal *j,
const char *fields,
char **patterns,
Set **units) {
_cleanup_set_free_free_ Set *found;
const char *field;
int r;
found = set_new(string_hash_func, string_compare_func);
if (!found)
return log_oom();
NULSTR_FOREACH(field, fields) {
const void *data;
size_t size;
r = sd_journal_query_unique(j, field);
if (r < 0)
return r;
SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
char **pattern, *eq;
size_t prefix;
_cleanup_free_ char *u = NULL;
eq = memchr(data, '=', size);
if (eq)
prefix = eq - (char*) data + 1;
else
prefix = 0;
u = strndup((char*) data + prefix, size - prefix);
if (!u)
return log_oom();
STRV_FOREACH(pattern, patterns)
if (fnmatch(*pattern, u, FNM_NOESCAPE) == 0) {
log_debug("Matched %s with pattern %s=%s", u, field, *pattern);
r = set_consume(found, u);
u = NULL;
if (r < 0 && r != -EEXIST)
return r;
break;
}
}
}
*units = found;
found = NULL;
return 0;
}
/* This list is supposed to return the superset of unit names
* possibly matched by rules added with add_matches_for_unit... */
#define SYSTEM_UNITS \
"_SYSTEMD_UNIT\0" \
"COREDUMP_UNIT\0" \
"UNIT\0" \
"OBJECT_SYSTEMD_UNIT\0" \
"_SYSTEMD_SLICE\0"
/* ... and add_matches_for_user_unit */
#define USER_UNITS \
"_SYSTEMD_USER_UNIT\0" \
"USER_UNIT\0" \
"COREDUMP_USER_UNIT\0" \
"OBJECT_SYSTEMD_USER_UNIT\0"
static int add_units(sd_journal *j) {
_cleanup_strv_free_ char **patterns = NULL;
int r, count = 0;
char **i;
assert(j);
STRV_FOREACH(i, arg_system_units) {
_cleanup_free_ char *u = NULL;
u = unit_name_mangle(*i, MANGLE_GLOB);
if (!u)
return log_oom();
if (string_is_glob(u)) {
r = strv_push(&patterns, u);
if (r < 0)
return r;
u = NULL;
} else {
r = add_matches_for_unit(j, u);
if (r < 0)
return r;
r = sd_journal_add_disjunction(j);
if (r < 0)
return r;
count ++;
}
}
if (!strv_isempty(patterns)) {
_cleanup_set_free_free_ Set *units = NULL;
Iterator it;
char *u;
r = get_possible_units(j, SYSTEM_UNITS, patterns, &units);
if (r < 0)
return r;
SET_FOREACH(u, units, it) {
r = add_matches_for_unit(j, u);
if (r < 0)
return r;
r = sd_journal_add_disjunction(j);
if (r < 0)
return r;
count ++;
}
}
strv_free(patterns);
patterns = NULL;
STRV_FOREACH(i, arg_user_units) {
_cleanup_free_ char *u = NULL;
u = unit_name_mangle(*i, MANGLE_GLOB);
if (!u)
return log_oom();
if (string_is_glob(u)) {
r = strv_push(&patterns, u);
if (r < 0)
return r;
u = NULL;
} else {
r = add_matches_for_user_unit(j, u, getuid());
if (r < 0)
return r;
r = sd_journal_add_disjunction(j);
if (r < 0)
return r;
count ++;
}
}
if (!strv_isempty(patterns)) {
_cleanup_set_free_free_ Set *units = NULL;
Iterator it;
char *u;
r = get_possible_units(j, USER_UNITS, patterns, &units);
if (r < 0)
return r;
SET_FOREACH(u, units, it) {
r = add_matches_for_user_unit(j, u, getuid());
if (r < 0)
return r;
r = sd_journal_add_disjunction(j);
if (r < 0)
return r;
count ++;
}
}
/* Complain if the user request matches but nothing whatsoever was
* found, since otherwise everything would be matched. */
if (!(strv_isempty(arg_system_units) && strv_isempty(arg_user_units)) && count == 0)
return -ENODATA;
r = sd_journal_add_conjunction(j);
if (r < 0)
return r;
return 0;
}
static int add_priorities(sd_journal *j) {
char match[] = "PRIORITY=0";
int i, r;
assert(j);
if (arg_priorities == 0xFF)
return 0;
for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
if (arg_priorities & (1 << i)) {
match[sizeof(match)-2] = '0' + i;
r = sd_journal_add_match(j, match, strlen(match));
if (r < 0) {
log_error("Failed to add match: %s", strerror(-r));
return r;
}
}
r = sd_journal_add_conjunction(j);
if (r < 0)
return r;
return 0;
}
static int add_syslog_identifier(sd_journal *j) {
int r;
char **i;
assert(j);
STRV_FOREACH(i, arg_syslog_identifier) {
char *u;
u = strappenda("SYSLOG_IDENTIFIER=", *i);
r = sd_journal_add_match(j, u, 0);
if (r < 0)
return r;
r = sd_journal_add_disjunction(j);
if (r < 0)
return r;
}
r = sd_journal_add_conjunction(j);
if (r < 0)
return r;
return 0;
}
static int setup_keys(void) {
#ifdef HAVE_GCRYPT
size_t mpk_size, seed_size, state_size, i;
uint8_t *mpk, *seed, *state;
ssize_t l;
int fd = -1, r, attr = 0;
sd_id128_t machine, boot;
char *p = NULL, *k = NULL;
struct FSSHeader h;
uint64_t n;
struct stat st;
r = stat("/var/log/journal", &st);
if (r < 0 && errno != ENOENT && errno != ENOTDIR) {
log_error("stat(\"%s\") failed: %m", "/var/log/journal");
return -errno;
}
if (r < 0 || !S_ISDIR(st.st_mode)) {
log_error("%s is not a directory, must be using persistent logging for FSS.",
"/var/log/journal");
return r < 0 ? -errno : -ENOTDIR;
}
r = sd_id128_get_machine(&machine);
if (r < 0) {
log_error("Failed to get machine ID: %s", strerror(-r));
return r;
}
r = sd_id128_get_boot(&boot);
if (r < 0) {
log_error("Failed to get boot ID: %s", strerror(-r));
return r;
}
if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
SD_ID128_FORMAT_VAL(machine)) < 0)
return log_oom();
if (access(p, F_OK) >= 0) {
if (arg_force) {
r = unlink(p);
if (r < 0) {
log_error("unlink(\"%s\") failed: %m", p);
r = -errno;
goto finish;
}
} else {
log_error("Sealing key file %s exists already. (--force to recreate)", p);
r = -EEXIST;
goto finish;
}
}
if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
SD_ID128_FORMAT_VAL(machine)) < 0) {
r = log_oom();
goto finish;
}
mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
mpk = alloca(mpk_size);
seed_size = FSPRG_RECOMMENDED_SEEDLEN;
seed = alloca(seed_size);
state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
state = alloca(state_size);
fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0) {
log_error("Failed to open /dev/random: %m");
r = -errno;
goto finish;
}
log_info("Generating seed...");
l = loop_read(fd, seed, seed_size, true);
if (l < 0 || (size_t) l != seed_size) {
log_error("Failed to read random seed: %s", strerror(EIO));
r = -EIO;
goto finish;
}
log_info("Generating key pair...");
FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
log_info("Generating sealing key...");
FSPRG_GenState0(state, mpk, seed, seed_size);
assert(arg_interval > 0);
n = now(CLOCK_REALTIME);
n /= arg_interval;
safe_close(fd);
fd = mkostemp_safe(k, O_WRONLY|O_CLOEXEC);
if (fd < 0) {
log_error("Failed to open %s: %m", k);
r = -errno;
goto finish;
}
/* Enable secure remove, exclusion from dump, synchronous
* writing and in-place updating */
if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
log_warning("FS_IOC_GETFLAGS failed: %m");
attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
log_warning("FS_IOC_SETFLAGS failed: %m");
zero(h);
memcpy(h.signature, "KSHHRHLP", 8);
h.machine_id = machine;
h.boot_id = boot;
h.header_size = htole64(sizeof(h));
h.start_usec = htole64(n * arg_interval);
h.interval_usec = htole64(arg_interval);
h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
h.fsprg_state_size = htole64(state_size);
l = loop_write(fd, &h, sizeof(h), false);
if (l < 0 || (size_t) l != sizeof(h)) {
log_error("Failed to write header: %s", strerror(EIO));
r = -EIO;
goto finish;
}
l = loop_write(fd, state, state_size, false);
if (l < 0 || (size_t) l != state_size) {
log_error("Failed to write state: %s", strerror(EIO));
r = -EIO;
goto finish;
}
if (link(k, p) < 0) {
log_error("Failed to link file: %m");
r = -errno;
goto finish;
}
if (on_tty()) {
fprintf(stderr,
"\n"
"The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
"the following local file. This key file is automatically updated when the\n"
"sealing key is advanced. It should not be used on multiple hosts.\n"
"\n"
"\t%s\n"
"\n"
"Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
"at a safe location and should not be saved locally on disk.\n"
"\n\t" ANSI_HIGHLIGHT_RED_ON, p);
fflush(stderr);
}
for (i = 0; i < seed_size; i++) {
if (i > 0 && i % 3 == 0)
putchar('-');
printf("%02x", ((uint8_t*) seed)[i]);
}
printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
if (on_tty()) {
char tsb[FORMAT_TIMESPAN_MAX], *hn;
fprintf(stderr,
ANSI_HIGHLIGHT_OFF "\n"
"The sealing key is automatically changed every %s.\n",
format_timespan(tsb, sizeof(tsb), arg_interval, 0));
hn = gethostname_malloc();
if (hn) {
hostname_cleanup(hn, false);
fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
} else
fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
#ifdef HAVE_QRENCODE
/* If this is not an UTF-8 system don't print any QR codes */
if (is_locale_utf8()) {
fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
}
#endif
free(hn);
}
r = 0;
finish:
safe_close(fd);
if (k) {
unlink(k);
free(k);
}
free(p);
return r;
#else
log_error("Forward-secure sealing not available.");
return -ENOTSUP;
#endif
}
static int verify(sd_journal *j) {
int r = 0;
Iterator i;
JournalFile *f;
assert(j);
log_show_color(true);
HASHMAP_FOREACH(f, j->files, i) {
int k;
usec_t first, validated, last;
#ifdef HAVE_GCRYPT
if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
#endif
k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
if (k == -EINVAL) {
/* If the key was invalid give up right-away. */
return k;
} else if (k < 0) {
log_warning("FAIL: %s (%s)", f->path, strerror(-k));
r = k;
} else {
char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
log_info("PASS: %s", f->path);
if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
if (validated > 0) {
log_info("=> Validated from %s to %s, final %s entries not sealed.",
format_timestamp(a, sizeof(a), first),
format_timestamp(b, sizeof(b), validated),
format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0));
} else if (last > 0)
log_info("=> No sealing yet, %s of entries not sealed.",
format_timespan(c, sizeof(c), last - first, 0));
else
log_info("=> No sealing yet, no entries in file.");
}
}
}
return r;
}
#ifdef HAVE_ACL
static int access_check_var_log_journal(sd_journal *j) {
_cleanup_strv_free_ char **g = NULL;
bool have_access;
int r;
assert(j);
have_access = in_group("systemd-journal") > 0;
if (!have_access) {
/* Let's enumerate all groups from the default ACL of
* the directory, which generally should allow access
* to most journal files too */
r = search_acl_groups(&g, "/var/log/journal/", &have_access);
if (r < 0)
return r;
}
if (!have_access) {
if (strv_isempty(g))
log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
" Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
" turn off this notice.");
else {
_cleanup_free_ char *s = NULL;
r = strv_extend(&g, "systemd-journal");
if (r < 0)
return log_oom();
strv_sort(g);
strv_uniq(g);
s = strv_join(g, "', '");
if (!s)
return log_oom();
log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
" Users in the groups '%s' can see all messages.\n"
" Pass -q to turn off this notice.", s);
}
}
return 0;
}
#endif
static int access_check(sd_journal *j) {
Iterator it;
void *code;
int r = 0;
assert(j);
if (set_isempty(j->errors)) {
if (hashmap_isempty(j->files))
log_notice("No journal files were found.");
return 0;
}
if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
#ifdef HAVE_ACL
/* If /var/log/journal doesn't even exist,
* unprivileged users have no access at all */
if (access("/var/log/journal", F_OK) < 0 &&
geteuid() != 0 &&
in_group("systemd-journal") <= 0) {
log_error("Unprivileged users cannot access messages, unless persistent log storage is\n"
"enabled. Users in the 'systemd-journal' group may always access messages.");
return -EACCES;
}
/* If /var/log/journal exists, try to pring a nice
notice if the user lacks access to it */
if (!arg_quiet && geteuid() != 0) {
r = access_check_var_log_journal(j);
if (r < 0)
return r;
}
#else
if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n"
"group may access messages.");
return -EACCES;
}
#endif
if (hashmap_isempty(j->files)) {
log_error("No journal files were opened due to insufficient permissions.");
r = -EACCES;
}
}
SET_FOREACH(code, j->errors, it) {
int err;
err = -PTR_TO_INT(code);
assert(err > 0);
if (err != EACCES)
log_warning("Error was encountered while opening journal files: %s",
strerror(err));
}
return r;
}
int main(int argc, char *argv[]) {
int r;
_cleanup_journal_close_ sd_journal *j = NULL;
bool need_seek = false;
sd_id128_t previous_boot_id;
bool previous_boot_id_valid = false, first_line = true;
int n_shown = 0;
bool ellipsized = false;
setlocale(LC_ALL, "");
log_parse_environment();
log_open();
r = parse_argv(argc, argv);
if (r <= 0)
goto finish;
signal(SIGWINCH, columns_lines_cache_reset);
if (arg_action == ACTION_NEW_ID128) {
r = generate_new_id128();
goto finish;
}
if (arg_action == ACTION_SETUP_KEYS) {
r = setup_keys();
goto finish;
}
if (arg_action == ACTION_UPDATE_CATALOG ||
arg_action == ACTION_LIST_CATALOG ||
arg_action == ACTION_DUMP_CATALOG) {
_cleanup_free_ char *database;
database = path_join(arg_root, CATALOG_DATABASE, NULL);
if (!database) {
r = log_oom();
goto finish;
}
if (arg_action == ACTION_UPDATE_CATALOG) {
r = catalog_update(database, arg_root, catalog_file_dirs);
if (r < 0)
log_error("Failed to list catalog: %s", strerror(-r));
} else {
bool oneline = arg_action == ACTION_LIST_CATALOG;
if (optind < argc)
r = catalog_list_items(stdout, database,
oneline, argv + optind);
else
r = catalog_list(stdout, database, oneline);
if (r < 0)
log_error("Failed to list catalog: %s", strerror(-r));
}
goto finish;
}
if (arg_directory)
r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
else if (arg_file)
r = sd_journal_open_files(&j, (const char**) arg_file, 0);
else if (arg_machine)
r = sd_journal_open_container(&j, arg_machine, 0);
else
r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
if (r < 0) {
log_error("Failed to open %s: %s",
arg_directory ? arg_directory : arg_file ? "files" : "journal",
strerror(-r));
return EXIT_FAILURE;
}
r = access_check(j);
if (r < 0)
return EXIT_FAILURE;
if (arg_action == ACTION_VERIFY) {
r = verify(j);
goto finish;
}
if (arg_action == ACTION_PRINT_HEADER) {
journal_print_header(j);
return EXIT_SUCCESS;
}
if (arg_action == ACTION_DISK_USAGE) {
uint64_t bytes = 0;
char sbytes[FORMAT_BYTES_MAX];
r = sd_journal_get_usage(j, &bytes);
if (r < 0)
return EXIT_FAILURE;
printf("Journals take up %s on disk.\n",
format_bytes(sbytes, sizeof(sbytes), bytes));
return EXIT_SUCCESS;
}
if (arg_action == ACTION_LIST_BOOTS) {
r = list_boots(j);
goto finish;
}
/* add_boot() must be called first!
* It may need to seek the journal to find parent boot IDs. */
r = add_boot(j);
if (r < 0)
return EXIT_FAILURE;
r = add_dmesg(j);
if (r < 0)
return EXIT_FAILURE;
r = add_units(j);
strv_free(arg_system_units);
strv_free(arg_user_units);
if (r < 0) {
log_error("Failed to add filter for units: %s", strerror(-r));
return EXIT_FAILURE;
}
r = add_syslog_identifier(j);
if (r < 0) {
log_error("Failed to add filter for syslog identifiers: %s", strerror(-r));
return EXIT_FAILURE;
}
r = add_priorities(j);
if (r < 0) {
log_error("Failed to add filter for priorities: %s", strerror(-r));
return EXIT_FAILURE;
}
r = add_matches(j, argv + optind);
if (r < 0) {
log_error("Failed to add filters: %s", strerror(-r));
return EXIT_FAILURE;
}
if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) {
_cleanup_free_ char *filter;
filter = journal_make_match_string(j);
log_debug("Journal filter: %s", filter);
}
if (arg_field) {
const void *data;
size_t size;
r = sd_journal_set_data_threshold(j, 0);
if (r < 0) {
log_error("Failed to unset data size threshold");
return EXIT_FAILURE;
}
r = sd_journal_query_unique(j, arg_field);
if (r < 0) {
log_error("Failed to query unique data objects: %s", strerror(-r));
return EXIT_FAILURE;
}
SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
const void *eq;
if (arg_lines >= 0 && n_shown >= arg_lines)
break;
eq = memchr(data, '=', size);
if (eq)
printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
else
printf("%.*s\n", (int) size, (const char*) data);
n_shown ++;
}
return EXIT_SUCCESS;
}
/* Opening the fd now means the first sd_journal_wait() will actually wait */
if (arg_follow) {
r = sd_journal_get_fd(j);
if (r < 0)
return EXIT_FAILURE;
}
if (arg_cursor || arg_after_cursor) {
r = sd_journal_seek_cursor(j, arg_cursor ?: arg_after_cursor);
if (r < 0) {
log_error("Failed to seek to cursor: %s", strerror(-r));
return EXIT_FAILURE;
}
if (!arg_reverse)
r = sd_journal_next_skip(j, 1 + !!arg_after_cursor);
else
r = sd_journal_previous_skip(j, 1 + !!arg_after_cursor);
if (arg_after_cursor && r < 2 && !arg_follow)
/* We couldn't find the next entry after the cursor. */
arg_lines = 0;
} else if (arg_since_set && !arg_reverse) {
r = sd_journal_seek_realtime_usec(j, arg_since);
if (r < 0) {
log_error("Failed to seek to date: %s", strerror(-r));
return EXIT_FAILURE;
}
r = sd_journal_next(j);
} else if (arg_until_set && arg_reverse) {
r = sd_journal_seek_realtime_usec(j, arg_until);
if (r < 0) {
log_error("Failed to seek to date: %s", strerror(-r));
return EXIT_FAILURE;
}
r = sd_journal_previous(j);
} else if (arg_lines >= 0) {
r = sd_journal_seek_tail(j);
if (r < 0) {
log_error("Failed to seek to tail: %s", strerror(-r));
return EXIT_FAILURE;
}
r = sd_journal_previous_skip(j, arg_lines);
} else if (arg_reverse) {
r = sd_journal_seek_tail(j);
if (r < 0) {
log_error("Failed to seek to tail: %s", strerror(-r));
return EXIT_FAILURE;
}
r = sd_journal_previous(j);
} else {
r = sd_journal_seek_head(j);
if (r < 0) {
log_error("Failed to seek to head: %s", strerror(-r));
return EXIT_FAILURE;
}
r = sd_journal_next(j);
}
if (r < 0) {
log_error("Failed to iterate through journal: %s", strerror(-r));
return EXIT_FAILURE;
}
if (!arg_follow)
pager_open_if_enabled();
if (!arg_quiet) {
usec_t start, end;
char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
if (r < 0) {
log_error("Failed to get cutoff: %s", strerror(-r));
goto finish;
}
if (r > 0) {
if (arg_follow)
printf("-- Logs begin at %s. --\n",
format_timestamp(start_buf, sizeof(start_buf), start));
else
printf("-- Logs begin at %s, end at %s. --\n",
format_timestamp(start_buf, sizeof(start_buf), start),
format_timestamp(end_buf, sizeof(end_buf), end));
}
}
for (;;) {
while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
int flags;
if (need_seek) {
if (!arg_reverse)
r = sd_journal_next(j);
else
r = sd_journal_previous(j);
if (r < 0) {
log_error("Failed to iterate through journal: %s", strerror(-r));
goto finish;
}
if (r == 0)
break;
}
if (arg_until_set && !arg_reverse) {
usec_t usec;
r = sd_journal_get_realtime_usec(j, &usec);
if (r < 0) {
log_error("Failed to determine timestamp: %s", strerror(-r));
goto finish;
}
if (usec > arg_until)
goto finish;
}
if (arg_since_set && arg_reverse) {
usec_t usec;
r = sd_journal_get_realtime_usec(j, &usec);
if (r < 0) {
log_error("Failed to determine timestamp: %s", strerror(-r));
goto finish;
}
if (usec < arg_since)
goto finish;
}
if (!arg_merge) {
sd_id128_t boot_id;
r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
if (r >= 0) {
if (previous_boot_id_valid &&
!sd_id128_equal(boot_id, previous_boot_id))
printf("%s-- Reboot --%s\n",
ansi_highlight(), ansi_highlight_off());
previous_boot_id = boot_id;
previous_boot_id_valid = true;
}
}
flags =
arg_all * OUTPUT_SHOW_ALL |
arg_full * OUTPUT_FULL_WIDTH |
on_tty() * OUTPUT_COLOR |
arg_catalog * OUTPUT_CATALOG;
r = output_journal(stdout, j, arg_output, 0, flags, &ellipsized);
need_seek = true;
if (r == -EADDRNOTAVAIL)
break;
else if (r < 0 || ferror(stdout))
goto finish;
n_shown++;
}
if (!arg_follow) {
if (arg_show_cursor) {
_cleanup_free_ char *cursor = NULL;
r = sd_journal_get_cursor(j, &cursor);
if (r < 0 && r != -EADDRNOTAVAIL)
log_error("Failed to get cursor: %s", strerror(-r));
else if (r >= 0)
printf("-- cursor: %s\n", cursor);
}
break;
}
r = sd_journal_wait(j, (uint64_t) -1);
if (r < 0) {
log_error("Couldn't wait for journal event: %s", strerror(-r));
goto finish;
}
first_line = false;
}
finish:
pager_close();
strv_free(arg_file);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}