]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/journal/journalctl.c
journalctl: make pcre2 a dlopen() dependency
[thirdparty/systemd.git] / src / journal / journalctl.c
index 4e2a8f6d1184ebac1499ec129412c8aed8fd9521..a957ac1237700ebb0e9d56de247987f29024bda9 100644 (file)
 #include "pager.h"
 #include "parse-util.h"
 #include "path-util.h"
+#include "pcre2-dlopen.h"
 #include "pretty-print.h"
 #include "rlimit-util.h"
 #include "set.h"
 #include "sigbus.h"
 #include "string-table.h"
 #include "strv.h"
+#include "stdio-util.h"
 #include "syslog-util.h"
 #include "terminal-util.h"
 #include "tmpfile-util.h"
@@ -101,6 +103,7 @@ static const char *arg_directory = NULL;
 static char **arg_file = NULL;
 static bool arg_file_stdin = false;
 static int arg_priorities = 0xFF;
+static Set *arg_facilities = NULL;
 static char *arg_verify_key = NULL;
 #if HAVE_GCRYPT
 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
@@ -158,20 +161,20 @@ typedef struct BootId {
 } BootId;
 
 #if HAVE_PCRE2
-DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_match_data*, pcre2_match_data_free);
-DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_code*, pcre2_code_free);
+DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_match_data*, sym_pcre2_match_data_free);
+DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_code*, sym_pcre2_code_free);
 
 static int pattern_compile(const char *pattern, unsigned flags, pcre2_code **out) {
         int errorcode, r;
         PCRE2_SIZE erroroffset;
         pcre2_code *p;
 
-        p = pcre2_compile((PCRE2_SPTR8) pattern,
-                          PCRE2_ZERO_TERMINATED, flags, &errorcode, &erroroffset, NULL);
+        p = sym_pcre2_compile((PCRE2_SPTR8) pattern,
+                              PCRE2_ZERO_TERMINATED, flags, &errorcode, &erroroffset, NULL);
         if (!p) {
                 unsigned char buf[LINE_MAX];
 
-                r = pcre2_get_error_message(errorcode, buf, sizeof buf);
+                r = sym_pcre2_get_error_message(errorcode, buf, sizeof buf);
 
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                        "Bad pattern \"%s\": %s", pattern,
@@ -181,7 +184,6 @@ static int pattern_compile(const char *pattern, unsigned flags, pcre2_code **out
         *out = p;
         return 0;
 }
-
 #endif
 
 static int add_matches_for_device(sd_journal *j, const char *devpath) {
@@ -303,6 +305,21 @@ static int parse_boot_descriptor(const char *x, sd_id128_t *boot_id, int *offset
         return 1;
 }
 
+static int help_facilities(void) {
+        if (!arg_quiet)
+                puts("Available facilities:");
+
+        for (int i = 0; i < LOG_NFACILITIES; i++) {
+                _cleanup_free_ char *t = NULL;
+
+                if (log_facility_unshifted_to_string_alloc(i, &t))
+                        return log_oom();
+                puts(t);
+        }
+
+        return 0;
+}
+
 static int help(void) {
         _cleanup_free_ char *link = NULL;
         int r;
@@ -332,8 +349,9 @@ static int help(void) {
                "     --user-unit=UNIT        Show logs from the specified user unit\n"
                "  -t --identifier=STRING     Show entries with the specified syslog identifier\n"
                "  -p --priority=RANGE        Show entries with the specified priority\n"
+               "     --facility=FACILITY...  Show entries with the specified facilities\n"
                "  -g --grep=PATTERN          Show entries with MESSAGE matching PATTERN\n"
-               "     --case-sensitive[=BOOL] Force case sensitive or insenstive matching\n"
+               "     --case-sensitive[=BOOL] Force case sensitive or insensitive matching\n"
                "  -e --pager-end             Immediately jump to the end in the pager\n"
                "  -f --follow                Follow the journal\n"
                "  -n --lines[=INTEGER]       Number of journal entries to show\n"
@@ -404,6 +422,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_SYSTEM,
                 ARG_ROOT,
                 ARG_HEADER,
+                ARG_FACILITY,
                 ARG_SETUP_KEYS,
                 ARG_FILE,
                 ARG_INTERVAL,
@@ -461,6 +480,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "header",               no_argument,       NULL, ARG_HEADER               },
                 { "identifier",           required_argument, NULL, 't'                      },
                 { "priority",             required_argument, NULL, 'p'                      },
+                { "facility",             required_argument, NULL, ARG_FACILITY             },
                 { "grep",                 required_argument, NULL, 'g'                      },
                 { "case-sensitive",       optional_argument, NULL, ARG_CASE_SENSITIVE       },
                 { "setup-keys",           no_argument,       NULL, ARG_SETUP_KEYS           },
@@ -685,7 +705,7 @@ static int parse_argv(int argc, char *argv[]) {
                                  * STDIN. To avoid confusion we hence don't document this feature. */
                                 arg_file_stdin = true;
                         else {
-                                r = glob_extend(&arg_file, optarg);
+                                r = glob_extend(&arg_file, optarg, GLOB_NOCHECK);
                                 if (r < 0)
                                         return log_error_errno(r, "Failed to add paths: %m");
                         }
@@ -832,6 +852,36 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
                 }
 
+                case ARG_FACILITY: {
+                        const char *p;
+
+                        for (p = optarg;;) {
+                                _cleanup_free_ char *fac = NULL;
+                                int num;
+
+                                r = extract_first_word(&p, &fac, ",", 0);
+                                if (r < 0)
+                                        return log_error_errno(r, "Failed to parse facilities: %s", optarg);
+                                if (r == 0)
+                                        break;
+
+                                if (streq(fac, "help")) {
+                                        help_facilities();
+                                        return 0;
+                                }
+
+                                num = log_facility_unshifted_from_string(fac);
+                                if (num < 0)
+                                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                               "Bad --facility= argument \"%s\".", fac);
+
+                                if (set_ensure_put(&arg_facilities, NULL, INT_TO_PTR(num)) < 0)
+                                        return log_oom();
+                        }
+
+                        break;
+                }
+
 #if HAVE_PCRE2
                 case 'g':
                         arg_pattern = optarg;
@@ -1037,14 +1087,18 @@ static int parse_argv(int argc, char *argv[]) {
         if (arg_pattern) {
                 unsigned flags;
 
+                r = dlopen_pcre2();
+                if (r < 0)
+                        return r;
+
                 if (arg_case_sensitive >= 0)
                         flags = !arg_case_sensitive * PCRE2_CASELESS;
                 else {
-                        _cleanup_(pcre2_match_data_freep) pcre2_match_data *md = NULL;
+                        _cleanup_(sym_pcre2_match_data_freep) pcre2_match_data *md = NULL;
                         bool has_case;
-                        _cleanup_(pcre2_code_freep) pcre2_code *cs = NULL;
+                        _cleanup_(sym_pcre2_code_freep) pcre2_code *cs = NULL;
 
-                        md = pcre2_match_data_create(1, NULL);
+                        md = sym_pcre2_match_data_create(1, NULL);
                         if (!md)
                                 return log_oom();
 
@@ -1052,7 +1106,7 @@ static int parse_argv(int argc, char *argv[]) {
                         if (r < 0)
                                 return r;
 
-                        r = pcre2_match(cs, (PCRE2_SPTR8) arg_pattern, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL);
+                        r = sym_pcre2_match(cs, (PCRE2_SPTR8) arg_pattern, PCRE2_ZERO_TERMINATED, 0, 0, md, NULL);
                         has_case = r >= 0;
 
                         flags = !has_case * PCRE2_CASELESS;
@@ -1676,6 +1730,24 @@ static int add_priorities(sd_journal *j) {
         return 0;
 }
 
+static int add_facilities(sd_journal *j) {
+        void *p;
+        Iterator it;
+        int r;
+
+        SET_FOREACH(p, arg_facilities, it) {
+                char match[STRLEN("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(int)];
+
+                xsprintf(match, "SYSLOG_FACILITY=%d", PTR_TO_INT(p));
+
+                r = sd_journal_add_match(j, match, strlen(match));
+                if (r < 0)
+                        return log_error_errno(r, "Failed to add match: %m");
+        }
+
+        return 0;
+}
+
 static int add_syslog_identifier(sd_journal *j) {
         int r;
         char **i;
@@ -1710,7 +1782,6 @@ static int setup_keys(void) {
         int fd = -1, r;
         sd_id128_t machine, boot;
         char *p = NULL, *k = NULL;
-        struct FSSHeader h;
         uint64_t n;
         struct stat st;
 
@@ -1800,15 +1871,17 @@ static int setup_keys(void) {
         if (r < 0)
                 log_warning_errno(r, "Failed to set file attributes: %m");
 
-        zero(h);
+        struct FSSHeader h = {
+                .machine_id = machine,
+                .boot_id = boot,
+                .header_size = htole64(sizeof(h)),
+                .start_usec = htole64(n * arg_interval),
+                .interval_usec = htole64(arg_interval),
+                .fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR),
+                .fsprg_state_size = htole64(state_size),
+        };
+
         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);
 
         r = loop_write(fd, &h, sizeof(h), false);
         if (r < 0) {
@@ -2019,10 +2092,13 @@ static int wait_for_change(sd_journal *j, int poll_fd) {
                 return log_error_errno(errno, "Couldn't wait for journal event: %m");
         }
 
-        if (pollfds[1].revents & (POLLHUP|POLLERR)) /* STDOUT has been closed? */
+        if (pollfds[1].revents & (POLLHUP|POLLERR|POLLNVAL)) /* STDOUT has been closed? */
                 return log_debug_errno(SYNTHETIC_ERRNO(ECANCELED),
                                        "Standard output has been closed.");
 
+        if (pollfds[0].revents & POLLNVAL)
+                return log_debug_errno(SYNTHETIC_ERRNO(EBADF), "Change fd closed?");
+
         r = sd_journal_process(j);
         if (r < 0)
                 return log_error_errno(r, "Failed to process journal events: %m");
@@ -2038,9 +2114,7 @@ int main(int argc, char *argv[]) {
         int n_shown = 0, r, poll_fd = -1;
 
         setlocale(LC_ALL, "");
-        log_show_color(true);
-        log_parse_environment();
-        log_open();
+        log_setup_cli();
 
         /* Increase max number of open files if we can, we might needs this when browsing journal files, which might be
          * split up into many files. */
@@ -2314,6 +2388,10 @@ int main(int argc, char *argv[]) {
         if (r < 0)
                 goto finish;
 
+        r = add_facilities(j);
+        if (r < 0)
+                goto finish;
+
         r = add_matches(j, argv + optind);
         if (r < 0)
                 goto finish;
@@ -2556,12 +2634,12 @@ int main(int argc, char *argv[]) {
 
 #if HAVE_PCRE2
                         if (arg_compiled_pattern) {
-                                _cleanup_(pcre2_match_data_freep) pcre2_match_data *md = NULL;
+                                _cleanup_(sym_pcre2_match_data_freep) pcre2_match_data *md = NULL;
                                 const void *message;
                                 size_t len;
                                 PCRE2_SIZE *ovec;
 
-                                md = pcre2_match_data_create(1, NULL);
+                                md = sym_pcre2_match_data_create(1, NULL);
                                 if (!md)
                                         return log_oom();
 
@@ -2578,13 +2656,13 @@ int main(int argc, char *argv[]) {
 
                                 assert_se(message = startswith(message, "MESSAGE="));
 
-                                r = pcre2_match(arg_compiled_pattern,
-                                                message,
-                                                len - strlen("MESSAGE="),
-                                                0,      /* start at offset 0 in the subject */
-                                                0,      /* default options */
-                                                md,
-                                                NULL);
+                                r = sym_pcre2_match(arg_compiled_pattern,
+                                                    message,
+                                                    len - strlen("MESSAGE="),
+                                                    0,      /* start at offset 0 in the subject */
+                                                    0,      /* default options */
+                                                    md,
+                                                    NULL);
                                 if (r == PCRE2_ERROR_NOMATCH) {
                                         need_seek = true;
                                         continue;
@@ -2593,14 +2671,14 @@ int main(int argc, char *argv[]) {
                                         unsigned char buf[LINE_MAX];
                                         int r2;
 
-                                        r2 = pcre2_get_error_message(r, buf, sizeof buf);
+                                        r2 = sym_pcre2_get_error_message(r, buf, sizeof buf);
                                         log_error("Pattern matching failed: %s",
                                                   r2 < 0 ? "unknown error" : (char*) buf);
                                         r = -EINVAL;
                                         goto finish;
                                 }
 
-                                ovec = pcre2_get_ovector_pointer(md);
+                                ovec = sym_pcre2_get_ovector_pointer(md);
                                 highlight[0] = ovec[0];
                                 highlight[1] = ovec[1];
                         }
@@ -2681,6 +2759,7 @@ finish:
 
         strv_free(arg_file);
 
+        set_free(arg_facilities);
         strv_free(arg_syslog_identifier);
         strv_free(arg_system_units);
         strv_free(arg_user_units);
@@ -2691,7 +2770,7 @@ finish:
 
 #if HAVE_PCRE2
         if (arg_compiled_pattern) {
-                pcre2_code_free(arg_compiled_pattern);
+                sym_pcre2_code_free(arg_compiled_pattern);
 
                 /* --grep was used, no error was thrown, but the pattern didn't
                  * match anything. Let's mimic grep's behavior here and return