]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/journal/journalctl.c
util-lib: split string parsing related calls from util.[ch] into parse-util.[ch]
[thirdparty/systemd.git] / src / journal / journalctl.c
index 073cc77711335db420a900b958243346c09ca5af..c13b674e15dcf0009c094e81da3c061014277873 100644 (file)
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-#include <locale.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <fnmatch.h>
-#include <errno.h>
+#include <getopt.h>
+#include <linux/fs.h>
+#include <locale.h>
+#include <poll.h>
+#include <signal.h>
 #include <stddef.h>
-#include <string.h>
 #include <stdio.h>
-#include <unistd.h>
 #include <stdlib.h>
-#include <getopt.h>
-#include <signal.h>
-#include <poll.h>
-#include <sys/stat.h>
+#include <string.h>
 #include <sys/inotify.h>
-#include <linux/fs.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
-#include "sd-journal.h"
 #include "sd-bus.h"
-#include "log.h"
-#include "logs-show.h"
-#include "util.h"
+#include "sd-journal.h"
+
 #include "acl-util.h"
-#include "path-util.h"
+#include "bus-error.h"
+#include "bus-util.h"
+#include "catalog.h"
+#include "fd-util.h"
 #include "fileio.h"
-#include "build.h"
-#include "pager.h"
-#include "strv.h"
-#include "set.h"
-#include "sigbus.h"
-#include "journal-internal.h"
+#include "fsprg.h"
+#include "hostname-util.h"
+#include "io-util.h"
 #include "journal-def.h"
-#include "journal-verify.h"
+#include "journal-internal.h"
 #include "journal-qrcode.h"
 #include "journal-vacuum.h"
-#include "fsprg.h"
-#include "unit-name.h"
-#include "catalog.h"
+#include "journal-verify.h"
+#include "log.h"
+#include "logs-show.h"
 #include "mkdir.h"
-#include "bus-util.h"
-#include "bus-error.h"
+#include "pager.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "set.h"
+#include "sigbus.h"
+#include "strv.h"
 #include "terminal-util.h"
-#include "hostname-util.h"
+#include "unit-name.h"
+#include "user-util.h"
 
 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
 
@@ -105,10 +108,11 @@ static const char *arg_field = NULL;
 static bool arg_catalog = false;
 static bool arg_reverse = false;
 static int arg_journal_type = 0;
-static const char *arg_root = NULL;
+static char *arg_root = NULL;
 static const char *arg_machine = NULL;
-static off_t arg_vacuum_size = (off_t) -1;
-static usec_t arg_vacuum_time = USEC_INFINITY;
+static uint64_t arg_vacuum_size = 0;
+static uint64_t arg_vacuum_n_files = 0;
+static usec_t arg_vacuum_time = 0;
 
 static enum {
         ACTION_SHOW,
@@ -122,6 +126,7 @@ static enum {
         ACTION_UPDATE_CATALOG,
         ACTION_LIST_BOOTS,
         ACTION_FLUSH,
+        ACTION_ROTATE,
         ACTION_VACUUM,
 } arg_action = ACTION_SHOW;
 
@@ -193,8 +198,8 @@ static void help(void) {
                "     --system              Show the system journal\n"
                "     --user                Show the user journal for the current user\n"
                "  -M --machine=CONTAINER   Operate on local container\n"
-               "     --since=DATE          Show entries not older than the specified date\n"
-               "     --until=DATE          Show entries not newer than the specified date\n"
+               "  -S --since=DATE          Show entries not older than the specified date\n"
+               "  -U --until=DATE          Show entries not newer than the specified date\n"
                "  -c --cursor=CURSOR       Show entries starting at the specified cursor\n"
                "     --after-cursor=CURSOR Show entries after the specified cursor\n"
                "     --show-cursor         Print the cursor after all the entries\n"
@@ -217,7 +222,7 @@ static void help(void) {
                "  -x --catalog             Add message explanations where available\n"
                "     --no-full             Ellipsize fields\n"
                "  -a --all                 Show all fields, including long and unprintable\n"
-               "  -q --quiet               Do not show privilege warning\n"
+               "  -q --quiet               Do not show info messages and privilege warning\n"
                "     --no-pager            Do not pipe output into a pager\n"
                "  -m --merge               Show entries from all available journals\n"
                "  -D --directory=PATH      Show journal files from directory\n"
@@ -235,8 +240,10 @@ static void help(void) {
                "     --new-id128           Generate a new 128-bit ID\n"
                "     --disk-usage          Show total disk usage of all journal files\n"
                "     --vacuum-size=BYTES   Reduce disk usage below specified size\n"
-               "     --vacuum-time=TIME    Remove journal files older than specified date\n"
+               "     --vacuum-files=INT    Leave only the specified number of journal files\n"
+               "     --vacuum-time=TIME    Remove journal files older than specified time\n"
                "     --flush               Flush all journal data from /run into /var\n"
+               "     --rotate              Request immediate rotation of the journal files\n"
                "     --header              Show journal header information\n"
                "     --list-catalog        Show all message IDs in the catalog\n"
                "     --dump-catalog        Show entries in the message catalog\n"
@@ -267,8 +274,6 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_VERIFY,
                 ARG_VERIFY_KEY,
                 ARG_DISK_USAGE,
-                ARG_SINCE,
-                ARG_UNTIL,
                 ARG_AFTER_CURSOR,
                 ARG_SHOW_CURSOR,
                 ARG_USER_UNIT,
@@ -278,7 +283,9 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_FORCE,
                 ARG_UTC,
                 ARG_FLUSH,
+                ARG_ROTATE,
                 ARG_VACUUM_SIZE,
+                ARG_VACUUM_FILES,
                 ARG_VACUUM_TIME,
         };
 
@@ -318,8 +325,8 @@ static int parse_argv(int argc, char *argv[]) {
                 { "cursor",         required_argument, NULL, 'c'                },
                 { "after-cursor",   required_argument, NULL, ARG_AFTER_CURSOR   },
                 { "show-cursor",    no_argument,       NULL, ARG_SHOW_CURSOR    },
-                { "since",          required_argument, NULL, ARG_SINCE          },
-                { "until",          required_argument, NULL, ARG_UNTIL          },
+                { "since",          required_argument, NULL, 'S'                },
+                { "until",          required_argument, NULL, 'U'                },
                 { "unit",           required_argument, NULL, 'u'                },
                 { "user-unit",      required_argument, NULL, ARG_USER_UNIT      },
                 { "field",          required_argument, NULL, 'F'                },
@@ -331,7 +338,9 @@ static int parse_argv(int argc, char *argv[]) {
                 { "machine",        required_argument, NULL, 'M'                },
                 { "utc",            no_argument,       NULL, ARG_UTC            },
                 { "flush",          no_argument,       NULL, ARG_FLUSH          },
+                { "rotate",         no_argument,       NULL, ARG_ROTATE         },
                 { "vacuum-size",    required_argument, NULL, ARG_VACUUM_SIZE    },
+                { "vacuum-files",   required_argument, NULL, ARG_VACUUM_FILES   },
                 { "vacuum-time",    required_argument, NULL, ARG_VACUUM_TIME    },
                 {}
         };
@@ -341,7 +350,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:t:u:F:xrM:", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:S:U:t:u:F:xrM:", options, NULL)) >= 0)
 
                 switch (c) {
 
@@ -350,9 +359,7 @@ static int parse_argv(int argc, char *argv[]) {
                         return 0;
 
                 case ARG_VERSION:
-                        puts(PACKAGE_STRING);
-                        puts(SYSTEMD_FEATURES);
-                        return 0;
+                        return version();
 
                 case ARG_NO_PAGER:
                         arg_no_pager = true;
@@ -502,7 +509,9 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case ARG_ROOT:
-                        arg_root = optarg;
+                        r = parse_path_argument_and_warn(optarg, true, &arg_root);
+                        if (r < 0)
+                                return r;
                         break;
 
                 case 'c':
@@ -539,6 +548,16 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_action = ACTION_VACUUM;
                         break;
 
+                case ARG_VACUUM_FILES:
+                        r = safe_atou64(optarg, &arg_vacuum_n_files);
+                        if (r < 0) {
+                                log_error("Failed to parse vacuum files: %s", optarg);
+                                return r;
+                        }
+
+                        arg_action = ACTION_VACUUM;
+                        break;
+
                 case ARG_VACUUM_TIME:
                         r = parse_sec(optarg, &arg_vacuum_time);
                         if (r < 0) {
@@ -631,7 +650,7 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
                 }
 
-                case ARG_SINCE:
+                case 'S':
                         r = parse_timestamp(optarg, &arg_since);
                         if (r < 0) {
                                 log_error("Failed to parse timestamp: %s", optarg);
@@ -640,7 +659,7 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_since_set = true;
                         break;
 
-                case ARG_UNTIL:
+                case 'U':
                         r = parse_timestamp(optarg, &arg_until);
                         if (r < 0) {
                                 log_error("Failed to parse timestamp: %s", optarg);
@@ -699,6 +718,10 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_action = ACTION_FLUSH;
                         break;
 
+                case ARG_ROTATE:
+                        arg_action = ACTION_ROTATE;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -729,7 +752,7 @@ static int parse_argv(int argc, char *argv[]) {
                 return -EINVAL;
         }
 
-        if (arg_action != ACTION_SHOW && optind < argc) {
+        if (!IN_SET(arg_action, ACTION_SHOW, ACTION_DUMP_CATALOG, ACTION_LIST_CATALOG) && optind < argc) {
                 log_error("Extraneous arguments starting with '%s'", argv[optind]);
                 return -EINVAL;
         }
@@ -1259,8 +1282,7 @@ static int add_units(sd_journal *j) {
                 }
         }
 
-        strv_free(patterns);
-        patterns = NULL;
+        patterns = strv_free(patterns);
 
         STRV_FOREACH(i, arg_user_units) {
                 _cleanup_free_ char *u = NULL;
@@ -1429,8 +1451,7 @@ static int setup_keys(void) {
 
         fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
         if (fd < 0) {
-                log_error_errno(errno, "Failed to open /dev/random: %m");
-                r = -errno;
+                r = log_error_errno(errno, "Failed to open /dev/random: %m");
                 goto finish;
         }
 
@@ -1455,8 +1476,7 @@ static int setup_keys(void) {
         safe_close(fd);
         fd = mkostemp_safe(k, O_WRONLY|O_CLOEXEC);
         if (fd < 0) {
-                log_error_errno(errno, "Failed to open %s: %m", k);
-                r = -errno;
+                r = log_error_errno(errno, "Failed to open %s: %m", k);
                 goto finish;
         }
 
@@ -1489,23 +1509,22 @@ static int setup_keys(void) {
         }
 
         if (link(k, p) < 0) {
-                log_error_errno(errno, "Failed to link file: %m");
-                r = -errno;
+                r = log_error_errno(errno, "Failed to link file: %m");
                 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 new key pair has been generated. The " ANSI_HIGHLIGHT "secret sealing key" ANSI_NORMAL " 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"
+                        "Please write down the following " ANSI_HIGHLIGHT "secret verification key" ANSI_NORMAL ". 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);
+                        "\n\t" ANSI_HIGHLIGHT_RED, p);
                 fflush(stderr);
         }
         for (i = 0; i < seed_size; i++) {
@@ -1520,14 +1539,14 @@ static int setup_keys(void) {
                 char tsb[FORMAT_TIMESPAN_MAX], *hn;
 
                 fprintf(stderr,
-                        ANSI_HIGHLIGHT_OFF "\n"
+                        ANSI_NORMAL "\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);
+                        hostname_cleanup(hn);
                         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));
@@ -1584,7 +1603,7 @@ static int verify(sd_journal *j) {
                         /* If the key was invalid give up right-away. */
                         return k;
                 } else if (k < 0) {
-                        log_warning("FAIL: %s (%s)", f->path, strerror(-k));
+                        log_warning_errno(k, "FAIL: %s (%m)", f->path);
                         r = k;
                 } else {
                         char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
@@ -1729,7 +1748,7 @@ static int flush_to_var(void) {
 
         /* OK, let's actually do the full logic, send SIGUSR1 to the
          * daemon and set up inotify to wait for the flushed file to appear */
-        r = bus_open_system_systemd(&bus);
+        r = bus_connect_system_systemd(&bus);
         if (r < 0)
                 return log_error_errno(r, "Failed to get D-Bus connection: %m");
 
@@ -1776,6 +1795,30 @@ static int flush_to_var(void) {
         return 0;
 }
 
+static int rotate(void) {
+        _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
+        int r;
+
+        r = bus_connect_system_systemd(&bus);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get D-Bus connection: %m");
+
+        r = sd_bus_call_method(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "KillUnit",
+                        &error,
+                        NULL,
+                        "ssi", "systemd-journald.service", "main", SIGUSR2);
+        if (r < 0)
+                return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r));
+
+        return 0;
+}
+
 int main(int argc, char *argv[]) {
         int r;
         _cleanup_journal_close_ sd_journal *j = NULL;
@@ -1811,6 +1854,11 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
+        if (arg_action == ACTION_ROTATE) {
+                r = rotate();
+                goto finish;
+        }
+
         if (arg_action == ACTION_SETUP_KEYS) {
                 r = setup_keys();
                 goto finish;
@@ -1835,6 +1883,7 @@ int main(int argc, char *argv[]) {
                 } else {
                         bool oneline = arg_action == ACTION_LIST_CATALOG;
 
+                        pager_open_if_enabled();
                         if (optind < argc)
                                 r = catalog_list_items(stdout, database,
                                                        oneline, argv + optind);
@@ -1899,9 +1948,9 @@ int main(int argc, char *argv[]) {
                         if (d->is_root)
                                 continue;
 
-                        q = journal_directory_vacuum(d->path, arg_vacuum_size, arg_vacuum_time, NULL, true);
+                        q = journal_directory_vacuum(d->path, arg_vacuum_size, arg_vacuum_n_files, arg_vacuum_time, NULL, true);
                         if (q < 0) {
-                                log_error_errno(q, "Failed to vacuum: %m");
+                                log_error_errno(q, "Failed to vacuum %s: %m", d->path);
                                 r = q;
                         }
                 }
@@ -2067,8 +2116,12 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
         if (r == 0) {
-                printf("-- No entries --\n");
-                goto finish;
+                if (arg_follow)
+                        need_seek = true;
+                else {
+                        printf("-- No entries --\n");
+                        goto finish;
+                }
         }
 
         if (!arg_follow)
@@ -2144,7 +2197,7 @@ int main(int argc, char *argv[]) {
                                         if (previous_boot_id_valid &&
                                             !sd_id128_equal(boot_id, previous_boot_id))
                                                 printf("%s-- Reboot --%s\n",
-                                                       ansi_highlight(), ansi_highlight_off());
+                                                       ansi_highlight(), ansi_normal());
 
                                         previous_boot_id = boot_id;
                                         previous_boot_id_valid = true;
@@ -2200,5 +2253,7 @@ finish:
         strv_free(arg_system_units);
         strv_free(arg_user_units);
 
+        free(arg_root);
+
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }