chiark / gitweb /
journalctl,systemctl: fix tiny memleak
[elogind.git] / src / shared / logs-show.c
index b88547eb83a47c6968cd92efd9e8204042242fc4..ea4746879bf3d43b925a4832b115d91e4508c91b 100644 (file)
@@ -101,7 +101,7 @@ static bool shall_print(const char *p, size_t l, OutputFlags flags) {
         return true;
 }
 
-static void print_multiline(FILE *f, unsigned prefix, unsigned n_columns, int flags, int priority, const char* message, size_t message_len) {
+static void print_multiline(FILE *f, unsigned prefix, unsigned n_columns, OutputMode flags, int priority, const char* message, size_t message_len) {
         const char *color_on = "", *color_off = "";
         const char *pos, *end;
         bool continuation = false;
@@ -123,7 +123,7 @@ static void print_multiline(FILE *f, unsigned prefix, unsigned n_columns, int fl
                 len = end - pos;
                 assert(len >= 0);
 
-                if ((flags & OUTPUT_FULL_WIDTH) || (prefix + len + 1 < n_columns))
+                if (flags & (OUTPUT_FULL_WIDTH | OUTPUT_SHOW_ALL) || prefix + len + 1 < n_columns)
                         fprintf(f, "%*s%s%.*s%s\n",
                                 continuation * prefix, "",
                                 color_on, len, pos, color_off);
@@ -163,7 +163,7 @@ static int output_short(
 
         sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : PRINT_THRESHOLD);
 
-        SD_JOURNAL_FOREACH_DATA(j, data, length) {
+        JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
 
                 r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
                 if (r < 0)
@@ -218,6 +218,9 @@ static int output_short(
                         return r;
         }
 
+        if (r < 0)
+                return r;
+
         if (!message)
                 return 0;
 
@@ -240,7 +243,7 @@ static int output_short(
                         r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
 
                 if (r < 0) {
-                        log_error("Failed to get monotonic: %s", strerror(-r));
+                        log_error("Failed to get monotonic timestamp: %s", strerror(-r));
                         return r;
                 }
 
@@ -265,7 +268,7 @@ static int output_short(
                         r = sd_journal_get_realtime_usec(j, &x);
 
                 if (r < 0) {
-                        log_error("Failed to get realtime: %s", strerror(-r));
+                        log_error("Failed to get realtime timestamp: %s", strerror(-r));
                         return r;
                 }
 
@@ -336,7 +339,8 @@ static int output_verbose(
 
         r = sd_journal_get_realtime_usec(j, &realtime);
         if (r < 0) {
-                log_error("Failed to get realtime timestamp: %s", strerror(-r));
+                log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
+                         "Failed to get realtime timestamp: %s", strerror(-r));
                 return r;
         }
 
@@ -350,9 +354,11 @@ static int output_verbose(
                 format_timestamp(ts, sizeof(ts), realtime),
                 cursor);
 
-        SD_JOURNAL_FOREACH_DATA(j, data, length) {
+        JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
                 const char *c;
                 int fieldlen;
+                const char *on = "", *off = "";
+
                 c = memchr(data, '=', length);
                 if (!c) {
                         log_error("Invalid field.");
@@ -360,19 +366,31 @@ static int output_verbose(
                 }
                 fieldlen = c - (const char*) data;
 
-                if ((flags & OUTPUT_SHOW_ALL) || (length < PRINT_THRESHOLD && utf8_is_printable(data, length))) {
-                        fprintf(f, "    %.*s=", fieldlen, (const char*)data);
+                if (flags & OUTPUT_COLOR && startswith(data, "MESSAGE=")) {
+                        on = ANSI_HIGHLIGHT_ON;
+                        off = ANSI_HIGHLIGHT_OFF;
+                }
+
+                if (flags & OUTPUT_SHOW_ALL ||
+                    (((length < PRINT_THRESHOLD) || flags & OUTPUT_FULL_WIDTH) && utf8_is_printable(data, length))) {
+                        fprintf(f, "    %s%.*s=", on, fieldlen, (const char*)data);
                         print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1);
+                        fputs(off, f);
                 } else {
                         char bytes[FORMAT_BYTES_MAX];
 
-                        fprintf(f, "    %.*s=[%s blob data]\n",
+                        fprintf(f, "    %s%.*s=[%s blob data]%s\n",
+                                on,
                                 (int) (c - (const char*) data),
                                 (const char*) data,
-                                format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1));
+                                format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1),
+                                off);
                 }
         }
 
+        if (r < 0)
+                return r;
+
         if (flags & OUTPUT_CATALOG)
                 print_catalog(f, j);
 
@@ -426,12 +444,12 @@ static int output_export(
                 (unsigned long long) monotonic,
                 sd_id128_to_string(boot_id, sid));
 
-        SD_JOURNAL_FOREACH_DATA(j, data, length) {
+        JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
 
                 /* We already printed the boot id, from the data in
                  * the header, hence let's suppress it here */
                 if (length >= 9 &&
-                    memcmp(data, "_BOOT_ID=", 9) == 0)
+                    hasprefix(data, "_BOOT_ID="))
                         continue;
 
                 if (!utf8_is_printable(data, length)) {
@@ -455,6 +473,9 @@ static int output_export(
                 fputc('\n', f);
         }
 
+        if (r < 0)
+                return r;
+
         fputc('\n', f);
 
         return 0;
@@ -583,7 +604,7 @@ static int output_json(
                 return -ENOMEM;
 
         /* First round, iterate through the entry and count how often each field appears */
-        SD_JOURNAL_FOREACH_DATA(j, data, length) {
+        JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
                 const char *eq;
                 char *n;
                 unsigned u;
@@ -617,6 +638,9 @@ static int output_json(
                 }
         }
 
+        if (r < 0)
+                return r;
+
         separator = true;
         do {
                 done = true;
@@ -898,15 +922,15 @@ finish:
 
 int add_matches_for_unit(sd_journal *j, const char *unit) {
         int r;
-        _cleanup_free_ char *m1 = NULL, *m2 = NULL, *m3 = NULL;
+        char *m1, *m2, *m3, *m4;
 
         assert(j);
         assert(unit);
 
-        if (asprintf(&m1, "_SYSTEMD_UNIT=%s", unit) < 0 ||
-            asprintf(&m2, "COREDUMP_UNIT=%s", unit) < 0 ||
-            asprintf(&m3, "UNIT=%s", unit) < 0)
-                return -ENOMEM;
+        m1 = strappenda("_SYSTEMD_UNIT=", unit);
+        m2 = strappenda("COREDUMP_UNIT=", unit);
+        m3 = strappenda("UNIT=", unit);
+        m4 = strappenda("OBJECT_SYSTEMD_UNIT=", unit);
 
         (void)(
             /* Look for messages from the service itself */
@@ -914,45 +938,59 @@ int add_matches_for_unit(sd_journal *j, const char *unit) {
 
             /* Look for coredumps of the service */
             (r = sd_journal_add_disjunction(j)) ||
-            (r = sd_journal_add_match(j,
-                        "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
+            (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
+            (r = sd_journal_add_match(j, "_UID=0", 0)) ||
             (r = sd_journal_add_match(j, m2, 0)) ||
 
              /* Look for messages from PID 1 about this service */
             (r = sd_journal_add_disjunction(j)) ||
             (r = sd_journal_add_match(j, "_PID=1", 0)) ||
-            (r = sd_journal_add_match(j, m3, 0))
+            (r = sd_journal_add_match(j, m3, 0)) ||
+
+            /* Look for messages from authorized daemons about this service */
+            (r = sd_journal_add_disjunction(j)) ||
+            (r = sd_journal_add_match(j, "_UID=0", 0)) ||
+            (r = sd_journal_add_match(j, m4, 0))
         );
+
         return r;
 }
 
 int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
         int r;
-        _cleanup_free_ char *m1 = NULL, *m2 = NULL, *m3 = NULL, *m4 = NULL;
+        char *m1, *m2, *m3, *m4;
+        char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)];
 
         assert(j);
         assert(unit);
 
-        if (asprintf(&m1, "_SYSTEMD_USER_UNIT=%s", unit) < 0 ||
-            asprintf(&m2, "USER_UNIT=%s", unit) < 0 ||
-            asprintf(&m3, "COREDUMP_USER_UNIT=%s", unit) < 0 ||
-            asprintf(&m4, "_UID=%d", uid) < 0)
-                return -ENOMEM;
+        m1 = strappenda("_SYSTEMD_USER_UNIT=", unit);
+        m2 = strappenda("USER_UNIT=", unit);
+        m3 = strappenda("COREDUMP_USER_UNIT=", unit);
+        m4 = strappenda("OBJECT_SYSTEMD_USER_UNIT=", unit);
+        sprintf(muid, "_UID=%lu", (unsigned long) uid);
 
         (void) (
                 /* Look for messages from the user service itself */
                 (r = sd_journal_add_match(j, m1, 0)) ||
-                (r = sd_journal_add_match(j, m4, 0)) ||
+                (r = sd_journal_add_match(j, muid, 0)) ||
 
                 /* Look for messages from systemd about this service */
                 (r = sd_journal_add_disjunction(j)) ||
                 (r = sd_journal_add_match(j, m2, 0)) ||
-                (r = sd_journal_add_match(j, m4, 0)) ||
+                (r = sd_journal_add_match(j, muid, 0)) ||
 
                 /* Look for coredumps of the service */
                 (r = sd_journal_add_disjunction(j)) ||
                 (r = sd_journal_add_match(j, m3, 0)) ||
-                (r = sd_journal_add_match(j, m4, 0))
+                (r = sd_journal_add_match(j, muid, 0)) ||
+                (r = sd_journal_add_match(j, "_UID=0", 0)) ||
+
+                /* Look for messages from authorized daemons about this service */
+                (r = sd_journal_add_disjunction(j)) ||
+                (r = sd_journal_add_match(j, m4, 0)) ||
+                (r = sd_journal_add_match(j, muid, 0)) ||
+                (r = sd_journal_add_match(j, "_UID=0", 0))
         );
         return r;
 }
@@ -997,7 +1035,7 @@ int show_journal_by_unit(
 
         _cleanup_journal_close_ sd_journal*j = NULL;
         int r;
-        int jflags = SD_JOURNAL_LOCAL_ONLY | system * SD_JOURNAL_SYSTEM_ONLY;
+        int jflags = SD_JOURNAL_LOCAL_ONLY | system * SD_JOURNAL_SYSTEM;
 
         assert(mode >= 0);
         assert(mode < _OUTPUT_MODE_MAX);
@@ -1021,7 +1059,12 @@ int show_journal_by_unit(
         if (r < 0)
                 return r;
 
-        log_debug("Journal filter: %s", journal_make_match_string(j));
+        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);
+        }
 
         r = show_journal(f, j, mode, n_columns, not_before, how_many, flags);
         if (r < 0)