]>
git.proxmox.com Git - proxmox-mini-journalreader.git/blob - src/mini-journalreader.c
2 Copyright (C) 2019 Proxmox Server Solutions GmbH
4 Copyright: mini-journal is under GNU GPL, the GNU General Public License.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; version 2 dated June, 1991.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 Author: Dominik Csapak <d.csapak@proxmox.com>
28 #include <systemd/sd-journal.h>
34 static char buf
[BUFSIZE
+ 1];
35 static size_t offset
= 0;
37 uint64_t get_timestamp(sd_journal
*j
) {
39 int r
= sd_journal_get_realtime_usec(j
, ×tamp
);
41 fprintf(stderr
, "Failed %s\n", strerror(-r
));
47 void print_to_buf(const char * string
, uint32_t length
) {
51 size_t string_offset
= 0;
52 size_t remaining
= length
;
53 while (offset
+ remaining
> BUFSIZE
) {
54 strncpy(buf
+offset
, string
+string_offset
, BUFSIZE
-offset
);
55 string_offset
+= BUFSIZE
-offset
;
56 remaining
= length
- string_offset
;
57 write (1, buf
, BUFSIZE
);
60 strncpy(buf
+offset
, string
+string_offset
, remaining
);
64 void print_cursor(sd_journal
*j
) {
67 r
= sd_journal_get_cursor(j
, &cursor
);
69 fprintf(stderr
, "Failed to get cursor: %s\n", strerror(-r
));
72 print_to_buf(cursor
, strlen(cursor
));
73 print_to_buf("\n", 1);
77 void print_first_cursor(sd_journal
*j
) {
78 static bool printed_first_cursor
= false;
79 if (!printed_first_cursor
) {
81 printed_first_cursor
= true;
85 void print_reboot(sd_journal
*j
) {
88 int r
= sd_journal_get_data(j
, "_BOOT_ID", (const void **)&d
, &l
);
90 fprintf(stderr
, "Failed %s\n", strerror(-r
));
98 static char bootid
[32];
99 if (bootid
[0] != '\0') { // we have some bootid
100 if (strncmp(bootid
, d
, l
)) { // a new bootid found
101 strncpy(bootid
, d
, l
);
102 print_to_buf("-- Reboot --\n", 13);
105 strncpy(bootid
, d
, l
);
109 void print_timestamp(sd_journal
*j
) {
111 int r
= sd_journal_get_realtime_usec(j
, ×tamp
);
113 fprintf(stderr
, "Failed %s\n", strerror(-r
));
117 static uint64_t last_timestamp
;
118 static char timestring
[16];
119 if (timestamp
>= (last_timestamp
+(1000*1000))) {
120 timestamp
= timestamp
/ (1000*1000); // usec to sec
122 localtime_r((time_t *)×tamp
, &time
);
123 strftime(timestring
, 16, "%b %d %T", &time
);
124 last_timestamp
= timestamp
;
127 print_to_buf(timestring
, 15);
130 void print_pid(sd_journal
*j
) {
133 int r
= sd_journal_get_data(j
, "_PID", (const void **)&d
, &l
);
135 // we sometimes have no pid
143 print_to_buf("[", 1);
145 print_to_buf("]", 1);
148 bool print_field(sd_journal
*j
, const char *field
) {
151 int r
= sd_journal_get_data(j
, field
, (const void **)&d
, &l
);
153 // some fields do not exists
157 int fieldlen
= strlen(field
)+1;
165 void print_line(sd_journal
*j
) {
168 print_to_buf(" ", 1);
169 print_field(j
, "_HOSTNAME");
170 print_to_buf(" ", 1);
171 if (!print_field(j
, "SYSLOG_IDENTIFIER") &&
172 !print_field(j
, "_COMM")) {
173 print_to_buf("unknown", strlen("unknown") - 1);
176 print_to_buf(": ", 2);
177 print_field(j
, "MESSAGE");
178 print_to_buf("\n", 1);
183 void usage(char *error
) {
185 fprintf(stderr
, "ERROR: %s\n", error
);
187 fprintf(stderr
, "usage: %s [OPTIONS]\n", progname
);
188 fprintf(stderr
, " -b begin\tbegin at this epoch\n");
189 fprintf(stderr
, " -e end\tend at this epoch\n");
190 fprintf(stderr
, " -d directory\tpath to journal directory\n");
191 fprintf(stderr
, " -n number\tprint the last number entries\n");
192 fprintf(stderr
, " -f from\tprint from this cursor\n");
193 fprintf(stderr
, " -t to\tprint to this cursor\n");
194 fprintf(stderr
, " -h \t\tthis help\n");
195 fprintf(stderr
, "\n");
196 fprintf(stderr
, "giving a range conflicts with -n\n");
197 fprintf(stderr
, "-b and -f conflict\n");
198 fprintf(stderr
, "-e and -t conflict\n");
202 static uint64_t arg_to_uint64(const char *argument
) {
205 uint64_t value
= strtoull(argument
, &end
, 10);
206 if (errno
!= 0 || *end
!= '\0') {
207 fprintf(stderr
, "%s is not a valid integer number\n", argument
);
215 int main(int argc
, char *argv
[]) {
217 const char *directory
= NULL
;
218 const char *startcursor
= NULL
;
219 const char *endcursor
= NULL
;
226 while ((c
= getopt (argc
, argv
, "b:e:d:n:f:t:h")) != -1) {
229 begin
= arg_to_uint64(optarg
);
230 begin
= begin
* 1000 * 1000; // µs
233 end
= arg_to_uint64(optarg
);
234 end
= end
* 1000 * 1000; // µs
240 number
= arg_to_uint64(optarg
);
243 startcursor
= optarg
;
253 usage("invalid option or missing argument");
257 if (number
&& (begin
|| startcursor
)) {
258 usage("-n conflicts with -b and/or -f");
261 if (begin
&& startcursor
) {
262 usage("-b and -f conflict");
265 if (end
&& endcursor
) {
266 usage("-e and -t conflict");
270 usage("unkown, or to many arguments");
273 // to prevent calling it everytime we generate a timestamp
278 if (directory
== NULL
) {
279 r
= sd_journal_open(&j
, SD_JOURNAL_LOCAL_ONLY
);
281 r
= sd_journal_open_directory(&j
, directory
, 0);
285 fprintf(stderr
, "Failed to open journal: %s\n", strerror(-r
));
289 // if we want to print the last x entries, seek to cursor or end,
290 // then x entries back, print the cursor and finally print the
291 // entries until end or cursor
294 r
= sd_journal_seek_realtime_usec(j
, end
);
295 } else if (endcursor
!= NULL
) {
296 r
= sd_journal_seek_cursor(j
, endcursor
);
299 r
= sd_journal_seek_tail(j
);
303 fprintf(stderr
, "Failed to seek to end/cursor: %s\n", strerror(-r
));
307 // seek back number entries and print cursor
308 r
= sd_journal_previous_skip(j
, number
+ 1);
310 fprintf(stderr
, "Failed to seek back: %s\n", strerror(-r
));
315 r
= sd_journal_seek_realtime_usec(j
, begin
);
316 } else if (startcursor
) {
317 r
= sd_journal_seek_cursor(j
, startcursor
);
319 r
= sd_journal_seek_head(j
);
323 fprintf(stderr
, "Failed to seek to begin/cursor: %s\n", strerror(-r
));
327 // if we have a start cursor, we want to skip the first entry
329 r
= sd_journal_next(j
);
331 fprintf(stderr
, "Failed to seek to begin/cursor: %s\n", strerror(-r
));
334 print_first_cursor(j
);
339 while ((r
= sd_journal_next(j
)) > 0 && (end
== 0 || get_timestamp(j
) < end
)) {
340 print_first_cursor(j
);
341 if (endcursor
!= NULL
&& sd_journal_test_cursor(j
, endcursor
)) {
347 // print optional reboot
350 // print final cursor
353 // print remaining buffer
354 write(1, buf
, offset
);