chiark / gitweb /
journald: fix _SYSTEMD_CGROUP= values
[elogind.git] / src / logs-show.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2012 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <time.h>
23 #include <assert.h>
24 #include <errno.h>
25
26 #include "logs-show.h"
27 #include "log.h"
28 #include "util.h"
29
30 #define PRINT_THRESHOLD 128
31
32 static bool contains_unprintable(const void *p, size_t l) {
33         const char *j;
34
35         for (j = p; j < (const char *) p + l; j++)
36                 if (*j < ' ' || *j >= 127)
37                         return true;
38
39         return false;
40 }
41
42 static int output_short(sd_journal *j, unsigned line, bool show_all) {
43         int r;
44         uint64_t realtime;
45         time_t t;
46         struct tm tm;
47         char buf[64];
48         const void *data;
49         size_t length;
50         size_t n = 0;
51
52         assert(j);
53
54         r = sd_journal_get_realtime_usec(j, &realtime);
55         if (r < 0) {
56                 log_error("Failed to get realtime: %s", strerror(-r));
57                 return r;
58         }
59
60         t = (time_t) (realtime / USEC_PER_SEC);
61         if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
62                 log_error("Failed to format time.");
63                 return -EINVAL;
64         }
65
66         fputs(buf, stdout);
67         n += strlen(buf);
68
69         if (sd_journal_get_data(j, "_HOSTNAME", &data, &length) >= 0 &&
70             (show_all || (!contains_unprintable(data, length) &&
71                           length < PRINT_THRESHOLD))) {
72                 printf(" %.*s", (int) length - 10, ((const char*) data) + 10);
73                 n += length - 10 + 1;
74         }
75
76         if (sd_journal_get_data(j, "MESSAGE", &data, &length) >= 0) {
77                 if (show_all)
78                         printf(" %.*s", (int) length - 8, ((const char*) data) + 8);
79                 else if (contains_unprintable(data, length))
80                         fputs(" [blob data]", stdout);
81                 else if (length - 8 + n < columns())
82                         printf(" %.*s", (int) length - 8, ((const char*) data) + 8);
83                 else if (n < columns()) {
84                         char *e;
85
86                         e = ellipsize_mem((const char *) data + 8, length - 8, columns() - n - 2, 90);
87
88                         if (!e)
89                                 printf(" %.*s", (int) length - 8, ((const char*) data) + 8);
90                         else
91                                 printf(" %s", e);
92
93                         free(e);
94                 }
95         }
96
97         fputc('\n', stdout);
98
99         return 0;
100 }
101
102 static int output_verbose(sd_journal *j, unsigned line, bool show_all) {
103         const void *data;
104         size_t length;
105         char *cursor;
106         uint64_t realtime;
107         char ts[FORMAT_TIMESTAMP_MAX];
108         int r;
109
110         assert(j);
111
112         r = sd_journal_get_realtime_usec(j, &realtime);
113         if (r < 0) {
114                 log_error("Failed to get realtime timestamp: %s", strerror(-r));
115                 return r;
116         }
117
118         r = sd_journal_get_cursor(j, &cursor);
119         if (r < 0) {
120                 log_error("Failed to get cursor: %s", strerror(-r));
121                 return r;
122         }
123
124         printf("%s [%s]\n",
125                format_timestamp(ts, sizeof(ts), realtime),
126                cursor);
127
128         free(cursor);
129
130         SD_JOURNAL_FOREACH_DATA(j, data, length) {
131                 if (!show_all && (length > PRINT_THRESHOLD ||
132                                   contains_unprintable(data, length))) {
133                         const char *c;
134
135                         c = memchr(data, '=', length);
136                         if (!c) {
137                                 log_error("Invalid field.");
138                                 return -EINVAL;
139                         }
140
141                         printf("\t%.*s=[blob data]\n",
142                                (int) (c - (const char*) data),
143                                (const char*) data);
144                 } else
145                         printf("\t%.*s\n", (int) length, (const char*) data);
146         }
147
148         return 0;
149 }
150
151 static int output_export(sd_journal *j, unsigned line, bool show_all) {
152         sd_id128_t boot_id;
153         char sid[33];
154         int r;
155         usec_t realtime, monotonic;
156         char *cursor;
157         const void *data;
158         size_t length;
159
160         assert(j);
161
162         r = sd_journal_get_realtime_usec(j, &realtime);
163         if (r < 0) {
164                 log_error("Failed to get realtime timestamp: %s", strerror(-r));
165                 return r;
166         }
167
168         r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
169         if (r < 0) {
170                 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
171                 return r;
172         }
173
174         r = sd_journal_get_cursor(j, &cursor);
175         if (r < 0) {
176                 log_error("Failed to get cursor: %s", strerror(-r));
177                 return r;
178         }
179
180         printf(".cursor=%s\n"
181                ".realtime=%llu\n"
182                ".monotonic=%llu\n"
183                ".boot_id=%s\n",
184                cursor,
185                (unsigned long long) realtime,
186                (unsigned long long) monotonic,
187                sd_id128_to_string(boot_id, sid));
188
189         free(cursor);
190
191         SD_JOURNAL_FOREACH_DATA(j, data, length) {
192
193                 if (contains_unprintable(data, length)) {
194                         const char *c;
195                         uint64_t le64;
196
197                         c = memchr(data, '=', length);
198                         if (!c) {
199                                 log_error("Invalid field.");
200                                 return -EINVAL;
201                         }
202
203                         fwrite(data, c - (const char*) data, 1, stdout);
204                         fputc('\n', stdout);
205                         le64 = htole64(length - (c - (const char*) data) - 1);
206                         fwrite(&le64, sizeof(le64), 1, stdout);
207                         fwrite(c + 1, length - (c - (const char*) data) - 1, 1, stdout);
208                 } else
209                         fwrite(data, length, 1, stdout);
210
211                 fputc('\n', stdout);
212         }
213
214         fputc('\n', stdout);
215
216         return 0;
217 }
218
219 static void json_escape(const char* p, size_t l) {
220
221         if (contains_unprintable(p, l)) {
222                 bool not_first = false;
223
224                 fputs("[ ", stdout);
225
226                 while (l > 0) {
227                         if (not_first)
228                                 printf(", %u", (uint8_t) *p);
229                         else {
230                                 not_first = true;
231                                 printf("%u", (uint8_t) *p);
232                         }
233
234                         p++;
235                         l--;
236                 }
237
238                 fputs(" ]", stdout);
239         } else {
240                 fputc('\"', stdout);
241
242                 while (l > 0) {
243                         if (*p == '"' || *p == '\\') {
244                                 fputc('\\', stdout);
245                                 fputc(*p, stdout);
246                         } else
247                                 fputc(*p, stdout);
248
249                         p++;
250                         l--;
251                 }
252
253                 fputc('\"', stdout);
254         }
255 }
256
257 static int output_json(sd_journal *j, unsigned line, bool show_all) {
258         uint64_t realtime, monotonic;
259         char *cursor;
260         const void *data;
261         size_t length;
262         sd_id128_t boot_id;
263         char sid[33];
264         int r;
265
266         assert(j);
267
268         r = sd_journal_get_realtime_usec(j, &realtime);
269         if (r < 0) {
270                 log_error("Failed to get realtime timestamp: %s", strerror(-r));
271                 return r;
272         }
273
274         r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
275         if (r < 0) {
276                 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
277                 return r;
278         }
279
280         r = sd_journal_get_cursor(j, &cursor);
281         if (r < 0) {
282                 log_error("Failed to get cursor: %s", strerror(-r));
283                 return r;
284         }
285
286         if (line == 1)
287                 fputc('\n', stdout);
288         else
289                 fputs(",\n", stdout);
290
291         printf("{\n"
292                "\t\".cursor\" : \"%s\",\n"
293                "\t\".realtime\" : %llu,\n"
294                "\t\".monotonic\" : %llu,\n"
295                "\t\".boot_id\" : \"%s\"",
296                cursor,
297                (unsigned long long) realtime,
298                (unsigned long long) monotonic,
299                sd_id128_to_string(boot_id, sid));
300
301         free(cursor);
302
303         SD_JOURNAL_FOREACH_DATA(j, data, length) {
304                 const char *c;
305
306                 c = memchr(data, '=', length);
307                 if (!c) {
308                         log_error("Invalid field.");
309                         return -EINVAL;
310                 }
311
312                 fputs(",\n\t", stdout);
313                 json_escape(data, c - (const char*) data);
314                 fputs(" : ", stdout);
315                 json_escape(c + 1, length - (c - (const char*) data) - 1);
316         }
317
318         fputs("\n}", stdout);
319         fflush(stdout);
320
321         return 0;
322 }
323
324 static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line, bool show_all) = {
325         [OUTPUT_SHORT] = output_short,
326         [OUTPUT_VERBOSE] = output_verbose,
327         [OUTPUT_EXPORT] = output_export,
328         [OUTPUT_JSON] = output_json
329 };
330
331 int output_journal(sd_journal *j, output_mode mode, unsigned line, bool show_all) {
332         assert(mode < _OUTPUT_MODE_MAX);
333
334         return output_funcs[mode](j, line, show_all);
335 }
336
337 int show_journal_by_service(
338                 const char *service,
339                 output_mode mode,
340                 const char *prefix,
341                 unsigned n_columns,
342                 usec_t not_before,
343                 unsigned how_many,
344                 bool show_all) {
345
346         char *m = NULL;
347         sd_journal *j;
348         int r;
349         unsigned i;
350
351         assert(service);
352
353         if (n_columns <= 0)
354                 n_columns = columns();
355
356         if (how_many <= 0)
357                 how_many = 10;
358
359         if (!prefix)
360                 prefix = "";
361
362         if (asprintf(&m, "_SYSTEMD_SERVICE=%s", service) < 0) {
363                 r = -ENOMEM;
364                 goto finish;
365         }
366
367         r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
368         if (r < 0)
369                 goto finish;
370
371         r = sd_journal_add_match(j, m, strlen(m));
372         if (r < 0)
373                 goto finish;
374
375         r = sd_journal_seek_tail(j);
376         if (r < 0)
377                 goto finish;
378
379         for (i = 0; i < how_many; i++)
380                 sd_journal_previous(j);
381
382         for (i = 0; i < how_many; i++) {
383
384                 r = sd_journal_next(j);
385                 if (r < 0)
386                         goto finish;
387
388                 if (r == 0)
389                         break;
390
391                 r = output_journal(j, mode, i+1, show_all);
392                 if (r < 0)
393                         goto finish;
394         }
395
396 finish:
397         if (m)
398                 free(m);
399
400         if (j)
401                 sd_journal_close(j);
402
403         return r;
404 }