2011-10-07 21:06:39 +02:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd .
Copyright 2011 Lennart Poettering
systemd is free software ; you can redistribute it and / or modify it
2012-04-12 00:20:58 +02:00
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation ; either version 2.1 of the License , or
2011-10-07 21:06:39 +02:00
( at your option ) any later version .
systemd is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
2012-04-12 00:20:58 +02:00
Lesser General Public License for more details .
2011-10-07 21:06:39 +02:00
2012-04-12 00:20:58 +02:00
You should have received a copy of the GNU Lesser General Public License
2011-10-07 21:06:39 +02:00
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
2012-11-12 20:16:07 +01:00
# include <locale.h>
2011-10-07 21:06:39 +02:00
# include <fcntl.h>
# include <errno.h>
# include <stddef.h>
2011-10-14 04:44:50 +02:00
# include <string.h>
# include <stdio.h>
# include <unistd.h>
# include <stdlib.h>
2011-12-19 22:35:46 +01:00
# include <sys/poll.h>
2011-12-21 18:17:22 +01:00
# include <time.h>
2011-12-21 18:59:56 +01:00
# include <getopt.h>
2012-09-22 18:50:27 +02:00
# include <signal.h>
2012-05-30 18:43:23 +02:00
# include <sys/stat.h>
2012-08-17 22:10:11 +02:00
# include <sys/ioctl.h>
# include <linux/fs.h>
2011-10-07 21:06:39 +02:00
2012-01-05 16:01:58 +01:00
# include <systemd/sd-journal.h>
2011-10-14 04:44:50 +02:00
# include "log.h"
2013-03-14 00:30:05 +01:00
# include "logs-show.h"
2011-12-21 18:17:22 +01:00
# include "util.h"
2012-05-30 22:45:47 +02:00
# include "path-util.h"
2011-12-21 18:59:56 +01:00
# include "build.h"
# include "pager.h"
2012-01-03 21:08:28 +01:00
# include "logs-show.h"
2012-07-11 01:08:38 +02:00
# include "strv.h"
2012-07-16 22:24:02 +02:00
# include "journal-internal.h"
2012-08-13 20:31:10 +02:00
# include "journal-def.h"
2012-08-16 01:51:54 +02:00
# include "journal-verify.h"
2012-08-16 02:14:34 +02:00
# include "journal-authenticate.h"
2012-08-20 22:02:19 +02:00
# include "journal-qrcode.h"
2012-08-16 02:14:34 +02:00
# include "fsprg.h"
2012-10-16 02:59:27 +02:00
# include "unit-name.h"
2012-11-15 23:03:31 +01:00
# include "catalog.h"
2012-08-13 20:31:10 +02:00
2012-08-17 00:45:18 +02:00
# define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
2011-10-12 05:29:08 +02:00
2012-01-04 18:33:36 +01:00
static OutputMode arg_output = OUTPUT_SHORT ;
2013-03-07 20:44:35 +01:00
static bool arg_pager_end = false ;
2011-12-21 18:17:22 +01:00
static bool arg_follow = false ;
2012-11-17 15:27:59 +01:00
static bool arg_full = false ;
2012-10-18 23:22:56 +02:00
static bool arg_all = false ;
2011-12-21 18:59:56 +01:00
static bool arg_no_pager = false ;
2013-01-28 05:53:52 +01:00
static int arg_lines = - 1 ;
2012-01-04 15:27:31 +01:00
static bool arg_no_tail = false ;
2012-03-14 19:54:22 +01:00
static bool arg_quiet = false ;
2012-09-06 01:49:00 +02:00
static bool arg_merge = false ;
2012-07-01 18:47:40 +02:00
static bool arg_this_boot = false ;
2012-09-27 23:25:23 +02:00
static const char * arg_cursor = NULL ;
2012-07-11 01:08:38 +02:00
static const char * arg_directory = NULL ;
2012-07-27 10:31:33 +02:00
static int arg_priorities = 0xFF ;
2012-08-17 00:45:18 +02:00
static const char * arg_verify_key = NULL ;
2012-08-20 16:51:46 +02:00
# ifdef HAVE_GCRYPT
2012-08-17 00:45:18 +02:00
static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC ;
2012-08-20 16:51:46 +02:00
# endif
2012-10-11 16:42:46 +02:00
static usec_t arg_since , arg_until ;
static bool arg_since_set = false , arg_until_set = false ;
2012-10-16 02:59:27 +02:00
static const char * arg_unit = NULL ;
2013-03-14 00:30:05 +01:00
static bool arg_unit_system ;
2012-10-18 03:29:19 +02:00
static const char * arg_field = NULL ;
2012-11-15 23:03:31 +01:00
static bool arg_catalog = false ;
2013-03-01 10:27:10 +01:00
static bool arg_reverse = false ;
2011-12-19 22:35:46 +01:00
2012-08-13 20:31:10 +02:00
static enum {
ACTION_SHOW ,
ACTION_NEW_ID128 ,
ACTION_PRINT_HEADER ,
2012-08-15 01:54:09 +02:00
ACTION_SETUP_KEYS ,
2012-09-07 23:20:28 +02:00
ACTION_VERIFY ,
ACTION_DISK_USAGE ,
2012-11-15 23:03:31 +01:00
ACTION_LIST_CATALOG ,
ACTION_UPDATE_CATALOG
2012-08-13 20:31:10 +02:00
} arg_action = ACTION_SHOW ;
2011-12-21 18:59:56 +01:00
static int help ( void ) {
2012-10-18 23:22:56 +02:00
printf ( " %s [OPTIONS...] [MATCHES...] \n \n "
2012-10-18 03:33:44 +02:00
" Query the journal. \n \n "
" Flags: \n "
2012-10-11 16:42:46 +02:00
" --since=DATE Start showing entries newer or of the specified date \n "
" --until=DATE Stop showing entries older or of the specified date \n "
2012-10-18 23:22:56 +02:00
" -c --cursor=CURSOR Start showing entries from specified cursor \n "
2012-10-16 02:59:27 +02:00
" -b --this-boot Show data only from current boot \n "
" -u --unit=UNIT Show data only from the specified unit \n "
2013-03-01 14:39:04 +01:00
" --user-unit=UNIT Show data only from the specified user session unit \n "
2012-10-18 23:22:56 +02:00
" -p --priority=RANGE Show only messages within the specified priority range \n "
2013-03-07 20:44:35 +01:00
" -e --pager-end Immediately jump to end of the journal in the pager \n "
2012-08-17 00:45:18 +02:00
" -f --follow Follow journal \n "
2012-09-21 22:33:02 +02:00
" -n --lines[=INTEGER] Number of journal entries to show \n "
2012-08-17 00:45:18 +02:00
" --no-tail Show all lines, even in follow mode \n "
2013-03-01 10:27:10 +01:00
" -r --reverse Show the newest entries first \n "
2012-08-17 00:45:18 +02:00
" -o --output=STRING Change journal output mode (short, short-monotonic, \n "
2012-10-11 02:37:10 +02:00
" verbose, export, json, json-pretty, json-sse, cat) \n "
2012-11-15 23:03:31 +01:00
" -x --catalog Add message explanations where available \n "
2012-11-17 15:27:59 +01:00
" --full Do not ellipsize fields \n "
2012-10-16 02:59:27 +02:00
" -a --all Show all fields, including long and unprintable \n "
2012-08-17 00:45:18 +02:00
" -q --quiet Don't show privilege warning \n "
2012-10-16 02:59:27 +02:00
" --no-pager Do not pipe output into a pager \n "
2012-09-06 01:49:00 +02:00
" -m --merge Show entries from all available journals \n "
2012-08-17 00:45:18 +02:00
" -D --directory=PATH Show journal files from directory \n "
2012-10-18 03:33:44 +02:00
# ifdef HAVE_GCRYPT
" --interval=TIME Time interval for changing the FSS sealing key \n "
" --verify-key=KEY Specify FSS verification key \n "
# endif
" \n Commands: \n "
" -h --help Show this help \n "
" --version Show package version \n "
2012-08-17 00:45:18 +02:00
" --new-id128 Generate a new 128 Bit ID \n "
" --header Show journal header information \n "
2012-09-07 23:20:28 +02:00
" --disk-usage Show total disk usage \n "
2012-10-18 03:33:44 +02:00
" -F --field=FIELD List all values a certain field takes \n "
2012-11-15 23:03:31 +01:00
" --list-catalog Show message IDs of all entries in the message catalog \n "
" --update-catalog Update the message catalog database \n "
2012-08-20 16:51:46 +02:00
# ifdef HAVE_GCRYPT
2012-08-17 00:45:18 +02:00
" --setup-keys Generate new FSS key pair \n "
" --verify Verify journal file consistency \n "
2012-08-20 16:51:46 +02:00
# endif
, program_invocation_short_name ) ;
2011-12-21 18:59:56 +01:00
return 0 ;
}
static int parse_argv ( int argc , char * argv [ ] ) {
enum {
ARG_VERSION = 0x100 ,
2012-01-04 15:27:31 +01:00
ARG_NO_PAGER ,
2012-01-05 16:28:17 +01:00
ARG_NO_TAIL ,
2012-07-16 22:24:02 +02:00
ARG_NEW_ID128 ,
2012-08-13 20:31:10 +02:00
ARG_HEADER ,
2012-11-17 15:27:59 +01:00
ARG_FULL ,
2012-08-15 01:54:09 +02:00
ARG_SETUP_KEYS ,
2012-08-17 00:45:18 +02:00
ARG_INTERVAL ,
2012-08-16 02:14:34 +02:00
ARG_VERIFY ,
2012-09-07 23:20:28 +02:00
ARG_VERIFY_KEY ,
2012-10-11 16:42:46 +02:00
ARG_DISK_USAGE ,
ARG_SINCE ,
2012-11-15 23:03:31 +01:00
ARG_UNTIL ,
2013-03-01 14:39:04 +01:00
ARG_USER_UNIT ,
2012-11-15 23:03:31 +01:00
ARG_LIST_CATALOG ,
ARG_UPDATE_CATALOG
2011-12-21 18:59:56 +01:00
} ;
static const struct option options [ ] = {
2012-08-17 00:45:18 +02:00
{ " help " , no_argument , NULL , ' h ' } ,
{ " version " , no_argument , NULL , ARG_VERSION } ,
{ " no-pager " , no_argument , NULL , ARG_NO_PAGER } ,
2013-03-07 20:44:35 +01:00
{ " pager-end " , no_argument , NULL , ' e ' } ,
2012-08-17 00:45:18 +02:00
{ " follow " , no_argument , NULL , ' f ' } ,
{ " output " , required_argument , NULL , ' o ' } ,
{ " all " , no_argument , NULL , ' a ' } ,
2012-11-17 15:27:59 +01:00
{ " full " , no_argument , NULL , ARG_FULL } ,
2012-09-21 22:33:02 +02:00
{ " lines " , optional_argument , NULL , ' n ' } ,
2012-08-17 00:45:18 +02:00
{ " no-tail " , no_argument , NULL , ARG_NO_TAIL } ,
{ " new-id128 " , no_argument , NULL , ARG_NEW_ID128 } ,
{ " quiet " , no_argument , NULL , ' q ' } ,
2012-09-06 01:49:00 +02:00
{ " merge " , no_argument , NULL , ' m ' } ,
2012-08-17 00:45:18 +02:00
{ " this-boot " , no_argument , NULL , ' b ' } ,
{ " directory " , required_argument , NULL , ' D ' } ,
{ " header " , no_argument , NULL , ARG_HEADER } ,
2012-11-15 12:17:03 +01:00
{ " priority " , required_argument , NULL , ' p ' } ,
2012-08-17 00:45:18 +02:00
{ " setup-keys " , no_argument , NULL , ARG_SETUP_KEYS } ,
{ " interval " , required_argument , NULL , ARG_INTERVAL } ,
{ " verify " , no_argument , NULL , ARG_VERIFY } ,
{ " verify-key " , required_argument , NULL , ARG_VERIFY_KEY } ,
2012-09-07 23:20:28 +02:00
{ " disk-usage " , no_argument , NULL , ARG_DISK_USAGE } ,
2012-10-10 01:35:24 +02:00
{ " cursor " , required_argument , NULL , ' c ' } ,
2012-10-11 16:42:46 +02:00
{ " since " , required_argument , NULL , ARG_SINCE } ,
{ " until " , required_argument , NULL , ARG_UNTIL } ,
2012-10-16 02:59:27 +02:00
{ " unit " , required_argument , NULL , ' u ' } ,
2013-03-14 00:30:05 +01:00
{ " user-unit " , required_argument , NULL , ARG_USER_UNIT } ,
2012-10-18 03:33:44 +02:00
{ " field " , required_argument , NULL , ' F ' } ,
2012-11-15 23:03:31 +01:00
{ " catalog " , no_argument , NULL , ' x ' } ,
{ " list-catalog " , no_argument , NULL , ARG_LIST_CATALOG } ,
{ " update-catalog " , no_argument , NULL , ARG_UPDATE_CATALOG } ,
2013-03-01 10:27:10 +01:00
{ " reverse " , no_argument , NULL , ' r ' } ,
2012-08-17 00:45:18 +02:00
{ NULL , 0 , NULL , 0 }
2011-12-21 18:59:56 +01:00
} ;
2012-01-04 02:14:42 +01:00
int c , r ;
2011-12-21 18:59:56 +01:00
assert ( argc > = 0 ) ;
assert ( argv ) ;
2013-03-07 20:44:35 +01:00
while ( ( c = getopt_long ( argc , argv , " hefo:an::qmbD:p:c:u:F:xr " , options , NULL ) ) > = 0 ) {
2011-12-21 18:59:56 +01:00
switch ( c ) {
case ' h ' :
help ( ) ;
return 0 ;
case ARG_VERSION :
puts ( PACKAGE_STRING ) ;
puts ( SYSTEMD_FEATURES ) ;
return 0 ;
case ARG_NO_PAGER :
arg_no_pager = true ;
break ;
2013-03-07 20:44:35 +01:00
case ' e ' :
arg_pager_end = true ;
2013-03-07 21:49:12 +01:00
if ( arg_lines < 0 )
arg_lines = 1000 ;
2013-03-07 20:44:35 +01:00
break ;
2011-12-21 18:59:56 +01:00
case ' f ' :
arg_follow = true ;
break ;
case ' o ' :
2012-09-21 22:33:02 +02:00
arg_output = output_mode_from_string ( optarg ) ;
2012-01-04 18:33:36 +01:00
if ( arg_output < 0 ) {
2012-10-15 18:14:09 +02:00
log_error ( " Unknown output format '%s'. " , optarg ) ;
2011-12-21 18:59:56 +01:00
return - EINVAL ;
}
2012-01-04 18:33:36 +01:00
2012-10-15 18:14:09 +02:00
if ( arg_output = = OUTPUT_EXPORT | |
arg_output = = OUTPUT_JSON | |
arg_output = = OUTPUT_JSON_PRETTY | |
arg_output = = OUTPUT_JSON_SSE | |
arg_output = = OUTPUT_CAT )
arg_quiet = true ;
2011-12-21 18:59:56 +01:00
break ;
2012-11-17 15:27:59 +01:00
case ARG_FULL :
arg_full = true ;
break ;
2011-12-21 18:59:56 +01:00
case ' a ' :
2012-10-18 23:22:56 +02:00
arg_all = true ;
2011-12-21 18:59:56 +01:00
break ;
2012-01-04 02:14:42 +01:00
case ' n ' :
2012-09-21 22:33:02 +02:00
if ( optarg ) {
2013-01-28 05:53:52 +01:00
r = safe_atoi ( optarg , & arg_lines ) ;
if ( r < 0 | | arg_lines < 0 ) {
2012-09-21 22:33:02 +02:00
log_error ( " Failed to parse lines '%s' " , optarg ) ;
return - EINVAL ;
}
2013-02-12 00:31:13 +01:00
} else {
int n ;
/* Hmm, no argument? Maybe the next
* word on the command line is
* supposed to be the argument ? Let ' s
* see if there is one , and is
* parsable as a positive
* integer . . . */
if ( optind < argc & &
safe_atoi ( argv [ optind ] , & n ) > = 0 & &
n > = 0 ) {
arg_lines = n ;
optind + + ;
} else
arg_lines = 10 ;
}
2012-09-21 22:33:02 +02:00
2012-01-04 02:14:42 +01:00
break ;
2012-01-04 15:27:31 +01:00
case ARG_NO_TAIL :
arg_no_tail = true ;
break ;
2012-01-07 01:37:15 +01:00
case ARG_NEW_ID128 :
2012-08-13 20:31:10 +02:00
arg_action = ACTION_NEW_ID128 ;
2012-01-05 16:28:17 +01:00
break ;
2012-03-14 19:54:22 +01:00
case ' q ' :
arg_quiet = true ;
2012-03-15 07:26:55 +01:00
break ;
2012-03-14 19:54:22 +01:00
2012-09-06 01:49:00 +02:00
case ' m ' :
arg_merge = true ;
2012-03-27 00:14:29 +02:00
break ;
2012-07-01 18:47:40 +02:00
case ' b ' :
arg_this_boot = true ;
break ;
2012-07-11 01:08:38 +02:00
case ' D ' :
arg_directory = optarg ;
break ;
2012-09-27 23:25:23 +02:00
case ' c ' :
arg_cursor = optarg ;
break ;
2012-07-16 22:24:02 +02:00
case ARG_HEADER :
2012-08-13 20:31:10 +02:00
arg_action = ACTION_PRINT_HEADER ;
break ;
2012-08-20 16:51:46 +02:00
case ARG_VERIFY :
arg_action = ACTION_VERIFY ;
break ;
2012-09-07 23:20:28 +02:00
case ARG_DISK_USAGE :
arg_action = ACTION_DISK_USAGE ;
break ;
2012-08-20 16:51:46 +02:00
# ifdef HAVE_GCRYPT
2012-08-13 20:31:10 +02:00
case ARG_SETUP_KEYS :
arg_action = ACTION_SETUP_KEYS ;
2012-07-16 22:24:02 +02:00
break ;
2012-08-15 01:54:09 +02:00
2012-08-17 00:45:18 +02:00
case ARG_VERIFY_KEY :
2012-08-16 02:14:34 +02:00
arg_action = ACTION_VERIFY ;
2012-08-17 00:45:18 +02:00
arg_verify_key = optarg ;
2012-09-06 01:49:00 +02:00
arg_merge = false ;
2012-08-16 02:14:34 +02:00
break ;
2012-08-17 00:45:18 +02:00
case ARG_INTERVAL :
r = parse_usec ( optarg , & arg_interval ) ;
if ( r < 0 | | arg_interval < = 0 ) {
log_error ( " Failed to parse sealing key change interval: %s " , optarg ) ;
2012-08-16 23:58:14 +02:00
return - EINVAL ;
}
break ;
2012-08-20 16:51:46 +02:00
# else
case ARG_SETUP_KEYS :
case ARG_VERIFY_KEY :
case ARG_INTERVAL :
log_error ( " Forward-secure sealing not available. " ) ;
return - ENOTSUP ;
# endif
2012-08-16 23:58:14 +02:00
2012-07-27 10:31:33 +02:00
case ' p ' : {
const char * dots ;
dots = strstr ( optarg , " .. " ) ;
if ( dots ) {
char * a ;
int from , to , i ;
/* a range */
a = strndup ( optarg , dots - optarg ) ;
if ( ! a )
return log_oom ( ) ;
from = log_level_from_string ( a ) ;
to = log_level_from_string ( dots + 2 ) ;
free ( a ) ;
if ( from < 0 | | to < 0 ) {
log_error ( " Failed to parse log level range %s " , optarg ) ;
return - EINVAL ;
}
arg_priorities = 0 ;
if ( from < to ) {
for ( i = from ; i < = to ; i + + )
arg_priorities | = 1 < < i ;
} else {
for ( i = to ; i < = from ; i + + )
arg_priorities | = 1 < < i ;
}
} else {
int p , i ;
p = log_level_from_string ( optarg ) ;
if ( p < 0 ) {
log_error ( " Unknown log level %s " , optarg ) ;
return - EINVAL ;
}
arg_priorities = 0 ;
for ( i = 0 ; i < = p ; i + + )
arg_priorities | = 1 < < i ;
}
break ;
}
2012-10-11 16:42:46 +02:00
case ARG_SINCE :
r = parse_timestamp ( optarg , & arg_since ) ;
if ( r < 0 ) {
log_error ( " Failed to parse timestamp: %s " , optarg ) ;
return - EINVAL ;
}
arg_since_set = true ;
break ;
case ARG_UNTIL :
r = parse_timestamp ( optarg , & arg_until ) ;
if ( r < 0 ) {
log_error ( " Failed to parse timestamp: %s " , optarg ) ;
return - EINVAL ;
}
arg_until_set = true ;
break ;
2013-03-14 00:30:05 +01:00
case ' u ' :
2013-03-01 14:39:04 +01:00
arg_unit = optarg ;
2013-03-14 00:30:05 +01:00
arg_unit_system = true ;
2013-03-01 14:39:04 +01:00
break ;
2013-03-14 00:30:05 +01:00
case ARG_USER_UNIT :
2012-10-16 02:59:27 +02:00
arg_unit = optarg ;
2013-03-14 00:30:05 +01:00
arg_unit_system = false ;
2012-10-16 02:59:27 +02:00
break ;
2011-12-21 18:59:56 +01:00
case ' ? ' :
return - EINVAL ;
2012-10-18 03:33:44 +02:00
case ' F ' :
arg_field = optarg ;
break ;
2012-11-15 23:03:31 +01:00
case ' x ' :
arg_catalog = true ;
break ;
case ARG_LIST_CATALOG :
arg_action = ACTION_LIST_CATALOG ;
break ;
case ARG_UPDATE_CATALOG :
arg_action = ACTION_UPDATE_CATALOG ;
break ;
2013-03-01 10:27:10 +01:00
case ' r ' :
arg_reverse = true ;
break ;
2011-12-21 18:59:56 +01:00
default :
log_error ( " Unknown option code %c " , c ) ;
return - EINVAL ;
}
}
2013-01-28 05:53:52 +01:00
if ( arg_follow & & ! arg_no_tail & & arg_lines < 0 )
2012-01-04 15:27:31 +01:00
arg_lines = 10 ;
2013-02-24 15:27:51 +01:00
if ( arg_since_set & & arg_until_set & & arg_since > arg_until ) {
2012-10-11 16:42:46 +02:00
log_error ( " --since= must be before --until=. " ) ;
return - EINVAL ;
}
if ( arg_cursor & & arg_since_set ) {
log_error ( " Please specify either --since= or --cursor=, not both. " ) ;
return - EINVAL ;
}
2013-03-01 10:27:10 +01:00
if ( arg_follow & & arg_reverse ) {
log_error ( " Please specify either --reverse= or --follow=, not both. " ) ;
return - EINVAL ;
}
2011-12-21 18:59:56 +01:00
return 1 ;
}
2012-01-07 01:37:15 +01:00
static int generate_new_id128 ( void ) {
2012-01-05 16:28:17 +01:00
sd_id128_t id ;
int r ;
unsigned i ;
r = sd_id128_randomize ( & id ) ;
if ( r < 0 ) {
log_error ( " Failed to generate ID: %s " , strerror ( - r ) ) ;
return r ;
}
printf ( " As string: \n "
SD_ID128_FORMAT_STR " \n \n "
" As UUID: \n "
" %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x \n \n "
" As macro: \n "
2013-02-11 04:47:14 +01:00
" #define MESSAGE_XYZ SD_ID128_MAKE( " ,
2012-01-05 16:28:17 +01:00
SD_ID128_FORMAT_VAL ( id ) ,
SD_ID128_FORMAT_VAL ( id ) ) ;
for ( i = 0 ; i < 16 ; i + + )
printf ( " %02x%s " , id . bytes [ i ] , i ! = 15 ? " , " : " " ) ;
2013-02-11 04:47:14 +01:00
fputs ( " ) \n \n " , stdout ) ;
2012-01-05 16:28:17 +01:00
2013-02-11 04:47:14 +01:00
printf ( " As Python constant: \n "
" >>> import uuid \n "
" >>> MESSAGE_XYZ = uuid.UUID(' " SD_ID128_FORMAT_STR " ') \n " ,
SD_ID128_FORMAT_VAL ( id ) ) ;
2012-01-05 16:28:17 +01:00
return 0 ;
}
2012-07-11 01:08:38 +02:00
static int add_matches ( sd_journal * j , char * * args ) {
char * * i ;
2012-07-01 18:47:40 +02:00
2012-07-11 01:08:38 +02:00
assert ( j ) ;
2012-07-01 18:47:40 +02:00
2012-07-11 01:08:38 +02:00
STRV_FOREACH ( i , args ) {
2013-03-15 23:00:57 +01:00
int r ;
2012-07-01 18:47:40 +02:00
2012-07-13 00:29:26 +02:00
if ( streq ( * i , " + " ) )
r = sd_journal_add_disjunction ( j ) ;
else if ( path_is_absolute ( * i ) ) {
2013-03-15 23:00:57 +01:00
char _cleanup_free_ * p , * t = NULL ;
2012-05-30 22:45:47 +02:00
const char * path ;
2012-07-11 01:08:38 +02:00
struct stat st ;
2012-05-30 22:45:47 +02:00
2012-07-11 01:08:38 +02:00
p = canonicalize_file_name ( * i ) ;
path = p ? p : * i ;
2012-05-30 22:45:47 +02:00
if ( stat ( path , & st ) < 0 ) {
log_error ( " Couldn't stat file: %m " ) ;
2012-07-11 01:08:38 +02:00
return - errno ;
2012-05-30 22:45:47 +02:00
}
2012-08-09 17:05:29 +02:00
if ( S_ISREG ( st . st_mode ) & & ( 0111 & st . st_mode ) )
2012-05-30 22:45:47 +02:00
t = strappend ( " _EXE= " , path ) ;
2012-08-09 17:05:29 +02:00
else if ( S_ISCHR ( st . st_mode ) )
asprintf ( & t , " _KERNEL_DEVICE=c%u:%u " , major ( st . st_rdev ) , minor ( st . st_rdev ) ) ;
else if ( S_ISBLK ( st . st_mode ) )
asprintf ( & t , " _KERNEL_DEVICE=b%u:%u " , major ( st . st_rdev ) , minor ( st . st_rdev ) ) ;
else {
log_error ( " File is not a device node, regular file or is not executable: %s " , * i ) ;
2012-07-11 01:08:38 +02:00
return - EINVAL ;
2012-05-30 18:43:23 +02:00
}
2012-05-30 22:45:47 +02:00
2012-08-09 17:05:29 +02:00
if ( ! t )
return log_oom ( ) ;
r = sd_journal_add_match ( j , t , 0 ) ;
2012-05-30 22:45:47 +02:00
} else
2012-07-13 00:29:26 +02:00
r = sd_journal_add_match ( j , * i , 0 ) ;
2012-05-30 22:45:47 +02:00
2011-10-15 01:13:37 +02:00
if ( r < 0 ) {
2012-07-13 00:29:26 +02:00
log_error ( " Failed to add match '%s': %s " , * i , strerror ( - r ) ) ;
2012-07-11 01:08:38 +02:00
return r ;
2011-10-15 01:13:37 +02:00
}
}
2012-07-11 01:08:38 +02:00
return 0 ;
}
static int add_this_boot ( sd_journal * j ) {
char match [ 9 + 32 + 1 ] = " _BOOT_ID= " ;
sd_id128_t boot_id ;
int r ;
2012-07-27 10:31:33 +02:00
assert ( j ) ;
2012-07-11 01:08:38 +02:00
if ( ! arg_this_boot )
return 0 ;
r = sd_id128_get_boot ( & boot_id ) ;
if ( r < 0 ) {
log_error ( " Failed to get boot id: %s " , strerror ( - r ) ) ;
return r ;
}
sd_id128_to_string ( boot_id , match + 9 ) ;
r = sd_journal_add_match ( j , match , strlen ( match ) ) ;
if ( r < 0 ) {
log_error ( " Failed to add match: %s " , strerror ( - r ) ) ;
return r ;
}
return 0 ;
}
2012-10-16 02:59:27 +02:00
static int add_unit ( sd_journal * j ) {
_cleanup_free_ char * m = NULL , * u = NULL ;
int r ;
assert ( j ) ;
if ( isempty ( arg_unit ) )
return 0 ;
u = unit_name_mangle ( arg_unit ) ;
if ( ! u )
return log_oom ( ) ;
2013-03-14 00:30:05 +01:00
if ( arg_unit_system )
r = add_matches_for_unit ( j , u ) ;
else
r = add_matches_for_user_unit ( j , u , getuid ( ) ) ;
if ( r < 0 )
2012-10-16 02:59:27 +02:00
return r ;
return 0 ;
}
2012-07-27 10:31:33 +02:00
static int add_priorities ( sd_journal * j ) {
char match [ ] = " PRIORITY=0 " ;
int i , r ;
assert ( j ) ;
if ( arg_priorities = = 0xFF )
return 0 ;
for ( i = LOG_EMERG ; i < = LOG_DEBUG ; i + + )
if ( arg_priorities & ( 1 < < i ) ) {
match [ sizeof ( match ) - 2 ] = ' 0 ' + i ;
r = sd_journal_add_match ( j , match , strlen ( match ) ) ;
if ( r < 0 ) {
log_error ( " Failed to add match: %s " , strerror ( - r ) ) ;
return r ;
}
}
return 0 ;
}
2012-08-13 20:31:10 +02:00
static int setup_keys ( void ) {
# ifdef HAVE_GCRYPT
size_t mpk_size , seed_size , state_size , i ;
uint8_t * mpk , * seed , * state ;
ssize_t l ;
2012-08-17 22:10:11 +02:00
int fd = - 1 , r , attr = 0 ;
2012-08-13 20:31:10 +02:00
sd_id128_t machine , boot ;
char * p = NULL , * k = NULL ;
2012-08-17 00:45:18 +02:00
struct FSSHeader h ;
2012-08-16 23:58:14 +02:00
uint64_t n ;
2012-08-13 20:31:10 +02:00
r = sd_id128_get_machine ( & machine ) ;
if ( r < 0 ) {
log_error ( " Failed to get machine ID: %s " , strerror ( - r ) ) ;
return r ;
}
r = sd_id128_get_boot ( & boot ) ;
if ( r < 0 ) {
log_error ( " Failed to get boot ID: %s " , strerror ( - r ) ) ;
return r ;
}
2012-08-17 00:45:18 +02:00
if ( asprintf ( & p , " /var/log/journal/ " SD_ID128_FORMAT_STR " /fss " ,
2012-08-13 20:31:10 +02:00
SD_ID128_FORMAT_VAL ( machine ) ) < 0 )
return log_oom ( ) ;
if ( access ( p , F_OK ) > = 0 ) {
2012-08-20 15:59:33 +02:00
log_error ( " Sealing key file %s exists already. " , p ) ;
2012-08-13 20:31:10 +02:00
r = - EEXIST ;
goto finish ;
}
2012-08-17 00:45:18 +02:00
if ( asprintf ( & k , " /var/log/journal/ " SD_ID128_FORMAT_STR " /fss.tmp.XXXXXX " ,
2012-08-13 20:31:10 +02:00
SD_ID128_FORMAT_VAL ( machine ) ) < 0 ) {
r = log_oom ( ) ;
goto finish ;
}
mpk_size = FSPRG_mskinbytes ( FSPRG_RECOMMENDED_SECPAR ) ;
mpk = alloca ( mpk_size ) ;
seed_size = FSPRG_RECOMMENDED_SEEDLEN ;
seed = alloca ( seed_size ) ;
state_size = FSPRG_stateinbytes ( FSPRG_RECOMMENDED_SECPAR ) ;
state = alloca ( state_size ) ;
fd = open ( " /dev/random " , O_RDONLY | O_CLOEXEC | O_NOCTTY ) ;
if ( fd < 0 ) {
log_error ( " Failed to open /dev/random: %m " ) ;
r = - errno ;
goto finish ;
}
log_info ( " Generating seed... " ) ;
l = loop_read ( fd , seed , seed_size , true ) ;
if ( l < 0 | | ( size_t ) l ! = seed_size ) {
log_error ( " Failed to read random seed: %s " , strerror ( EIO ) ) ;
r = - EIO ;
goto finish ;
}
log_info ( " Generating key pair... " ) ;
FSPRG_GenMK ( NULL , mpk , seed , seed_size , FSPRG_RECOMMENDED_SECPAR ) ;
2012-08-17 00:45:18 +02:00
log_info ( " Generating sealing key... " ) ;
2012-08-13 20:31:10 +02:00
FSPRG_GenState0 ( state , mpk , seed , seed_size ) ;
2012-08-17 00:45:18 +02:00
assert ( arg_interval > 0 ) ;
2012-08-13 20:31:10 +02:00
n = now ( CLOCK_REALTIME ) ;
2012-08-17 00:45:18 +02:00
n / = arg_interval ;
2012-08-13 20:31:10 +02:00
close_nointr_nofail ( fd ) ;
fd = mkostemp ( k , O_WRONLY | O_CLOEXEC | O_NOCTTY ) ;
if ( fd < 0 ) {
log_error ( " Failed to open %s: %m " , k ) ;
r = - errno ;
goto finish ;
}
2012-08-17 22:10:11 +02:00
/* Enable secure remove, exclusion from dump, synchronous
* writing and in - place updating */
if ( ioctl ( fd , FS_IOC_GETFLAGS , & attr ) < 0 )
log_warning ( " FS_IOC_GETFLAGS failed: %m " ) ;
attr | = FS_SECRM_FL | FS_NODUMP_FL | FS_SYNC_FL | FS_NOCOW_FL ;
if ( ioctl ( fd , FS_IOC_SETFLAGS , & attr ) < 0 )
log_warning ( " FS_IOC_SETFLAGS failed: %m " ) ;
2012-08-13 20:31:10 +02:00
zero ( h ) ;
memcpy ( h . signature , " KSHHRHLP " , 8 ) ;
h . machine_id = machine ;
h . boot_id = boot ;
h . header_size = htole64 ( sizeof ( h ) ) ;
2012-08-17 00:45:18 +02:00
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 ) ;
2012-08-13 20:31:10 +02:00
l = loop_write ( fd , & h , sizeof ( h ) , false ) ;
if ( l < 0 | | ( size_t ) l ! = sizeof ( h ) ) {
log_error ( " Failed to write header: %s " , strerror ( EIO ) ) ;
r = - EIO ;
goto finish ;
}
l = loop_write ( fd , state , state_size , false ) ;
if ( l < 0 | | ( size_t ) l ! = state_size ) {
log_error ( " Failed to write state: %s " , strerror ( EIO ) ) ;
r = - EIO ;
goto finish ;
}
if ( link ( k , p ) < 0 ) {
log_error ( " Failed to link file: %m " ) ;
r = - errno ;
goto finish ;
}
2012-10-18 23:59:41 +02:00
if ( on_tty ( ) ) {
2012-08-13 20:31:10 +02:00
fprintf ( stderr ,
" \n "
2012-08-17 00:45:18 +02:00
" The new key pair has been generated. The " ANSI_HIGHLIGHT_ON " secret sealing key " ANSI_HIGHLIGHT_OFF " has been written to \n "
2012-08-21 01:02:08 +02:00
" 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 "
2012-08-13 20:31:10 +02:00
" \n "
" \t %s \n "
" \n "
2012-08-17 00:45:18 +02:00
" Please write down the following " ANSI_HIGHLIGHT_ON " secret verification key " ANSI_HIGHLIGHT_OFF " . It should be stored \n "
" at a safe location and should not be saved locally on disk. \n "
2012-08-13 20:31:10 +02:00
" \n \t " ANSI_HIGHLIGHT_RED_ON , p ) ;
fflush ( stderr ) ;
}
for ( i = 0 ; i < seed_size ; i + + ) {
if ( i > 0 & & i % 3 = = 0 )
putchar ( ' - ' ) ;
printf ( " %02x " , ( ( uint8_t * ) seed ) [ i ] ) ;
}
2012-08-17 00:45:18 +02:00
printf ( " /%llx-%llx \n " , ( unsigned long long ) n , ( unsigned long long ) arg_interval ) ;
2012-10-18 23:59:41 +02:00
if ( on_tty ( ) ) {
2012-08-20 22:02:19 +02:00
char tsb [ FORMAT_TIMESPAN_MAX ] , * hn ;
2012-08-13 20:31:10 +02:00
2012-08-17 00:45:18 +02:00
fprintf ( stderr ,
ANSI_HIGHLIGHT_OFF " \n "
" The sealing key is automatically changed every %s. \n " ,
format_timespan ( tsb , sizeof ( tsb ) , arg_interval ) ) ;
2012-08-20 22:02:19 +02:00
hn = gethostname_malloc ( ) ;
if ( hn ) {
hostname_cleanup ( hn ) ;
2012-08-20 22:22:05 +02:00
fprintf ( stderr , " \n The keys have been generated for host %s/ " SD_ID128_FORMAT_STR " . \n " , hn , SD_ID128_FORMAT_VAL ( machine ) ) ;
2012-08-20 22:02:19 +02:00
} else
2012-08-20 22:22:05 +02:00
fprintf ( stderr , " \n The keys have been generated for host " SD_ID128_FORMAT_STR " . \n " , SD_ID128_FORMAT_VAL ( machine ) ) ;
2012-08-20 22:02:19 +02:00
# ifdef HAVE_QRENCODE
2012-09-12 09:23:38 +02:00
/* If this is not an UTF-8 system don't print any QR codes */
2012-11-02 17:27:15 +01:00
if ( is_locale_utf8 ( ) ) {
2012-09-12 09:23:38 +02:00
fputs ( " \n To transfer the verification key to your phone please scan the QR code below: \n \n " , stderr ) ;
print_qr_code ( stderr , seed , seed_size , n , arg_interval , hn , machine ) ;
}
2012-08-20 22:02:19 +02:00
# endif
free ( hn ) ;
2012-08-17 00:45:18 +02:00
}
2012-08-13 20:31:10 +02:00
r = 0 ;
finish :
if ( fd > = 0 )
close_nointr_nofail ( fd ) ;
if ( k ) {
unlink ( k ) ;
free ( k ) ;
}
free ( p ) ;
return r ;
# else
2012-08-20 16:51:46 +02:00
log_error ( " Forward-secure sealing not available. " ) ;
return - ENOTSUP ;
2012-08-13 20:31:10 +02:00
# endif
}
2012-08-15 01:54:09 +02:00
static int verify ( sd_journal * j ) {
int r = 0 ;
Iterator i ;
JournalFile * f ;
assert ( j ) ;
2012-08-21 15:53:48 +02:00
log_show_color ( true ) ;
2012-08-15 01:54:09 +02:00
HASHMAP_FOREACH ( f , j - > files , i ) {
int k ;
2012-09-24 15:02:43 +02:00
usec_t first , validated , last ;
2012-08-15 01:54:09 +02:00
2012-08-16 21:00:34 +02:00
# ifdef HAVE_GCRYPT
2012-08-20 16:51:46 +02:00
if ( ! arg_verify_key & & JOURNAL_HEADER_SEALED ( f - > header ) )
2012-08-21 15:53:48 +02:00
log_notice ( " Journal file %s has sealing enabled but verification key has not been passed using --verify-key=. " , f - > path ) ;
2012-08-16 21:00:34 +02:00
# endif
2012-08-16 02:14:34 +02:00
2012-09-24 15:02:43 +02:00
k = journal_file_verify ( f , arg_verify_key , & first , & validated , & last , true ) ;
2012-08-16 21:00:34 +02:00
if ( k = = - EINVAL ) {
2012-08-17 00:45:18 +02:00
/* If the key was invalid give up right-away. */
2012-08-16 21:00:34 +02:00
return k ;
} else if ( k < 0 ) {
2012-08-15 01:54:09 +02:00
log_warning ( " FAIL: %s (%s) " , f - > path , strerror ( - k ) ) ;
2012-08-16 21:00:34 +02:00
r = k ;
2012-08-17 03:30:22 +02:00
} else {
char a [ FORMAT_TIMESTAMP_MAX ] , b [ FORMAT_TIMESTAMP_MAX ] , c [ FORMAT_TIMESPAN_MAX ] ;
2012-08-15 01:54:09 +02:00
log_info ( " PASS: %s " , f - > path ) ;
2012-08-17 03:30:22 +02:00
2012-08-21 23:03:20 +02:00
if ( arg_verify_key & & JOURNAL_HEADER_SEALED ( f - > header ) ) {
2012-09-24 15:02:43 +02:00
if ( validated > 0 ) {
2012-08-21 23:03:20 +02:00
log_info ( " => Validated from %s to %s, final %s entries not sealed. " ,
2012-09-24 15:02:43 +02:00
format_timestamp ( a , sizeof ( a ) , first ) ,
format_timestamp ( b , sizeof ( b ) , validated ) ,
format_timespan ( c , sizeof ( c ) , last > validated ? last - validated : 0 ) ) ;
} else if ( last > 0 )
2012-08-21 23:03:20 +02:00
log_info ( " => No sealing yet, %s of entries not sealed. " ,
2012-09-24 15:02:43 +02:00
format_timespan ( c , sizeof ( c ) , last - first ) ) ;
2012-08-21 23:03:20 +02:00
else
log_info ( " => No sealing yet, no entries in file. " ) ;
}
2012-08-17 03:30:22 +02:00
}
2012-08-15 01:54:09 +02:00
}
return r ;
}
2012-10-18 03:34:43 +02:00
static int access_check ( void ) {
# ifdef HAVE_ACL
2013-03-05 18:53:21 +01:00
if ( access ( " /var/log/journal " , F_OK ) < 0 & & geteuid ( ) ! = 0 & & in_group ( " systemd-journal " ) < = 0 ) {
log_error ( " Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'systemd-journal' can always see messages. " ) ;
2012-10-18 03:34:43 +02:00
return - EACCES ;
}
2013-03-05 18:53:21 +01:00
if ( ! arg_quiet & & geteuid ( ) ! = 0 & & in_group ( " systemd-journal " ) < = 0 )
log_warning ( " Showing user generated messages only. Users in the group 'systemd-journal' can see all messages. Pass -q to turn this notice off. " ) ;
2012-10-18 03:34:43 +02:00
# else
2013-03-05 18:53:21 +01:00
if ( geteuid ( ) ! = 0 & & in_group ( " systemd-journal " ) < = 0 ) {
log_error ( " No access to messages. Only users in the group 'systemd-journal' can see messages. " ) ;
2012-10-18 03:34:43 +02:00
return - EACCES ;
}
# endif
return 0 ;
}
2012-07-11 01:08:38 +02:00
int main ( int argc , char * argv [ ] ) {
int r ;
2013-03-18 04:36:25 +01:00
sd_journal _cleanup_journal_close_ * j = NULL ;
2012-07-11 01:08:38 +02:00
bool need_seek = false ;
2012-07-11 01:36:55 +02:00
sd_id128_t previous_boot_id ;
2013-01-28 05:53:52 +01:00
bool previous_boot_id_valid = false , first_line = true ;
int n_shown = 0 ;
2012-07-11 01:08:38 +02:00
2012-11-12 20:16:07 +01:00
setlocale ( LC_ALL , " " ) ;
2012-07-11 01:08:38 +02:00
log_parse_environment ( ) ;
log_open ( ) ;
r = parse_argv ( argc , argv ) ;
if ( r < = 0 )
goto finish ;
2012-10-19 00:06:47 +02:00
signal ( SIGWINCH , columns_lines_cache_reset ) ;
2012-08-13 20:31:10 +02:00
if ( arg_action = = ACTION_NEW_ID128 ) {
2012-07-11 01:08:38 +02:00
r = generate_new_id128 ( ) ;
goto finish ;
}
2012-08-13 20:31:10 +02:00
if ( arg_action = = ACTION_SETUP_KEYS ) {
r = setup_keys ( ) ;
goto finish ;
}
2012-11-15 23:03:31 +01:00
if ( arg_action = = ACTION_LIST_CATALOG ) {
r = catalog_list ( stdout ) ;
2012-11-16 01:34:53 +01:00
if ( r < 0 )
log_error ( " Failed to list catalog: %s " , strerror ( - r ) ) ;
2012-11-15 23:03:31 +01:00
goto finish ;
}
if ( arg_action = = ACTION_UPDATE_CATALOG ) {
r = catalog_update ( ) ;
goto finish ;
}
2012-10-18 03:34:43 +02:00
r = access_check ( ) ;
if ( r < 0 )
2013-03-18 04:36:25 +01:00
return EXIT_FAILURE ;
2012-10-18 03:34:43 +02:00
2012-07-11 01:08:38 +02:00
if ( arg_directory )
r = sd_journal_open_directory ( & j , arg_directory , 0 ) ;
else
2012-09-06 01:49:00 +02:00
r = sd_journal_open ( & j , arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY ) ;
2012-07-11 01:08:38 +02:00
if ( r < 0 ) {
log_error ( " Failed to open journal: %s " , strerror ( - r ) ) ;
2013-03-18 04:36:25 +01:00
return EXIT_FAILURE ;
2012-07-11 01:08:38 +02:00
}
2012-08-15 01:54:09 +02:00
if ( arg_action = = ACTION_VERIFY ) {
r = verify ( j ) ;
goto finish ;
}
2012-08-13 20:31:10 +02:00
if ( arg_action = = ACTION_PRINT_HEADER ) {
2012-07-16 22:24:02 +02:00
journal_print_header ( j ) ;
2013-03-18 04:36:25 +01:00
return EXIT_SUCCESS ;
2012-07-16 22:24:02 +02:00
}
2012-09-07 23:20:28 +02:00
if ( arg_action = = ACTION_DISK_USAGE ) {
uint64_t bytes ;
char sbytes [ FORMAT_BYTES_MAX ] ;
r = sd_journal_get_usage ( j , & bytes ) ;
if ( r < 0 )
2013-03-18 04:36:25 +01:00
return EXIT_FAILURE ;
2012-09-07 23:20:28 +02:00
2013-03-18 04:36:25 +01:00
printf ( " Journals take up %s on disk. \n " ,
format_bytes ( sbytes , sizeof ( sbytes ) , bytes ) ) ;
return EXIT_SUCCESS ;
2012-09-07 23:20:28 +02:00
}
2012-07-11 01:08:38 +02:00
r = add_this_boot ( j ) ;
if ( r < 0 )
2013-03-18 04:36:25 +01:00
return EXIT_FAILURE ;
2012-07-11 01:08:38 +02:00
2012-10-16 02:59:27 +02:00
r = add_unit ( j ) ;
if ( r < 0 )
2013-03-18 04:36:25 +01:00
return EXIT_FAILURE ;
2012-10-16 02:59:27 +02:00
2012-07-11 01:08:38 +02:00
r = add_matches ( j , argv + optind ) ;
if ( r < 0 )
2013-03-18 04:36:25 +01:00
return EXIT_FAILURE ;
2012-07-11 01:08:38 +02:00
2012-07-27 10:31:33 +02:00
r = add_priorities ( j ) ;
if ( r < 0 )
2013-03-18 04:36:25 +01:00
return EXIT_FAILURE ;
2012-07-27 10:31:33 +02:00
2013-01-28 05:53:52 +01:00
/* Opening the fd now means the first sd_journal_wait() will actually wait */
r = sd_journal_get_fd ( j ) ;
if ( r < 0 )
2013-03-18 04:36:25 +01:00
return EXIT_FAILURE ;
2013-01-28 05:53:52 +01:00
2012-10-18 03:33:44 +02:00
if ( arg_field ) {
const void * data ;
size_t size ;
r = sd_journal_query_unique ( j , arg_field ) ;
if ( r < 0 ) {
log_error ( " Failed to query unique data objects: %s " , strerror ( - r ) ) ;
2013-03-18 04:36:25 +01:00
return EXIT_FAILURE ;
2012-10-18 03:33:44 +02:00
}
SD_JOURNAL_FOREACH_UNIQUE ( j , data , size ) {
const void * eq ;
2013-01-28 05:53:52 +01:00
if ( arg_lines > = 0 & & n_shown > = arg_lines )
2012-10-18 22:55:12 +02:00
break ;
2012-10-18 03:33:44 +02:00
eq = memchr ( data , ' = ' , size ) ;
if ( eq )
printf ( " %.*s \n " , ( int ) ( size - ( ( const uint8_t * ) eq - ( const uint8_t * ) data + 1 ) ) , ( const char * ) eq + 1 ) ;
else
printf ( " %.*s \n " , ( int ) size , ( const char * ) data ) ;
2012-10-18 22:55:12 +02:00
n_shown + + ;
2012-10-18 03:33:44 +02:00
}
2013-03-18 04:36:25 +01:00
return EXIT_SUCCESS ;
2012-10-18 03:33:44 +02:00
}
2012-10-11 16:42:46 +02:00
if ( arg_cursor ) {
r = sd_journal_seek_cursor ( j , arg_cursor ) ;
2012-06-09 10:32:38 +02:00
if ( r < 0 ) {
2012-10-11 16:42:46 +02:00
log_error ( " Failed to seek to cursor: %s " , strerror ( - r ) ) ;
2013-03-18 04:36:25 +01:00
return EXIT_FAILURE ;
2012-06-09 10:32:38 +02:00
}
2013-03-01 10:27:10 +01:00
if ( ! arg_reverse )
r = sd_journal_next ( j ) ;
else
r = sd_journal_previous ( j ) ;
2012-06-09 10:32:38 +02:00
2013-03-01 10:27:10 +01:00
} else if ( arg_since_set & & ! arg_reverse ) {
2012-10-11 16:42:46 +02:00
r = sd_journal_seek_realtime_usec ( j , arg_since ) ;
2012-09-27 23:25:23 +02:00
if ( r < 0 ) {
2012-10-11 16:42:46 +02:00
log_error ( " Failed to seek to date: %s " , strerror ( - r ) ) ;
2013-03-18 04:36:25 +01:00
return EXIT_FAILURE ;
2012-09-27 23:25:23 +02:00
}
r = sd_journal_next ( j ) ;
2013-03-01 10:27:10 +01:00
} else if ( arg_until_set & & arg_reverse ) {
r = sd_journal_seek_realtime_usec ( j , arg_until ) ;
if ( r < 0 ) {
log_error ( " Failed to seek to date: %s " , strerror ( - r ) ) ;
2013-03-18 04:36:25 +01:00
return EXIT_FAILURE ;
2013-03-01 10:27:10 +01:00
}
r = sd_journal_previous ( j ) ;
2013-01-28 05:53:52 +01:00
} else if ( arg_lines > = 0 ) {
2012-01-04 02:14:42 +01:00
r = sd_journal_seek_tail ( j ) ;
if ( r < 0 ) {
log_error ( " Failed to seek to tail: %s " , strerror ( - r ) ) ;
2013-03-18 04:36:25 +01:00
return EXIT_FAILURE ;
2012-01-04 02:14:42 +01:00
}
r = sd_journal_previous_skip ( j , arg_lines ) ;
2012-09-27 23:25:23 +02:00
2013-03-01 10:27:10 +01:00
} else if ( arg_reverse ) {
r = sd_journal_seek_tail ( j ) ;
if ( r < 0 ) {
log_error ( " Failed to seek to tail: %s " , strerror ( - r ) ) ;
2013-03-18 04:36:25 +01:00
return EXIT_FAILURE ;
2013-03-01 10:27:10 +01:00
}
r = sd_journal_previous ( j ) ;
2012-01-04 02:14:42 +01:00
} else {
r = sd_journal_seek_head ( j ) ;
if ( r < 0 ) {
log_error ( " Failed to seek to head: %s " , strerror ( - r ) ) ;
2013-03-18 04:36:25 +01:00
return EXIT_FAILURE ;
2012-01-04 02:14:42 +01:00
}
2012-01-04 04:00:14 +01:00
r = sd_journal_next ( j ) ;
}
if ( r < 0 ) {
log_error ( " Failed to iterate through journal: %s " , strerror ( - r ) ) ;
2013-03-18 04:36:25 +01:00
return EXIT_FAILURE ;
2011-12-19 22:35:46 +01:00
}
2011-10-07 21:06:39 +02:00
2012-10-18 23:34:37 +02:00
if ( ! arg_no_pager & & ! arg_follow )
2013-03-07 20:44:35 +01:00
pager_open ( arg_pager_end ) ;
2011-12-21 18:59:56 +01:00
2012-10-11 16:42:46 +02:00
if ( ! arg_quiet ) {
usec_t start , end ;
char start_buf [ FORMAT_TIMESTAMP_MAX ] , end_buf [ FORMAT_TIMESTAMP_MAX ] ;
r = sd_journal_get_cutoff_realtime_usec ( j , & start , & end ) ;
if ( r < 0 ) {
log_error ( " Failed to get cutoff: %s " , strerror ( - r ) ) ;
goto finish ;
}
if ( r > 0 ) {
if ( arg_follow )
2012-10-16 01:09:09 +02:00
printf ( " -- Logs begin at %s. -- \n " ,
format_timestamp ( start_buf , sizeof ( start_buf ) , start ) ) ;
2012-10-11 16:42:46 +02:00
else
2012-10-16 01:09:09 +02:00
printf ( " -- Logs begin at %s, end at %s. -- \n " ,
2012-10-11 16:42:46 +02:00
format_timestamp ( start_buf , sizeof ( start_buf ) , start ) ,
format_timestamp ( end_buf , sizeof ( end_buf ) , end ) ) ;
}
}
2011-12-19 22:35:46 +01:00
for ( ; ; ) {
2013-01-28 05:53:52 +01:00
while ( arg_lines < 0 | | n_shown < arg_lines | | ( arg_follow & & ! first_line ) ) {
2012-10-11 16:42:46 +02:00
int flags ;
2012-01-04 04:00:14 +01:00
if ( need_seek ) {
2013-03-07 06:40:30 +01:00
if ( ! arg_reverse )
2013-03-01 10:27:10 +01:00
r = sd_journal_next ( j ) ;
else
r = sd_journal_previous ( j ) ;
2012-01-04 04:00:14 +01:00
if ( r < 0 ) {
log_error ( " Failed to iterate through journal: %s " , strerror ( - r ) ) ;
goto finish ;
}
2011-12-21 18:59:56 +01:00
}
if ( r = = 0 )
break ;
2013-03-01 10:27:10 +01:00
if ( arg_until_set & & ! arg_reverse ) {
2012-10-11 16:42:46 +02:00
usec_t usec ;
r = sd_journal_get_realtime_usec ( j , & usec ) ;
if ( r < 0 ) {
log_error ( " Failed to determine timestamp: %s " , strerror ( - r ) ) ;
goto finish ;
}
2013-02-24 15:27:51 +01:00
if ( usec > arg_until )
goto finish ;
2012-10-11 16:42:46 +02:00
}
2013-03-01 10:27:10 +01:00
if ( arg_since_set & & arg_reverse ) {
usec_t usec ;
r = sd_journal_get_realtime_usec ( j , & usec ) ;
if ( r < 0 ) {
log_error ( " Failed to determine timestamp: %s " , strerror ( - r ) ) ;
goto finish ;
}
if ( usec < arg_since )
goto finish ;
}
2012-09-06 01:52:46 +02:00
if ( ! arg_merge ) {
sd_id128_t boot_id ;
2012-07-11 01:36:55 +02:00
2012-09-06 01:52:46 +02:00
r = sd_journal_get_monotonic_usec ( j , NULL , & boot_id ) ;
if ( r > = 0 ) {
if ( previous_boot_id_valid & &
! sd_id128_equal ( boot_id , previous_boot_id ) )
2012-10-16 01:09:09 +02:00
printf ( ANSI_HIGHLIGHT_ON " -- Reboot -- " ANSI_HIGHLIGHT_OFF " \n " ) ;
2012-09-06 01:52:46 +02:00
previous_boot_id = boot_id ;
previous_boot_id_valid = true ;
}
2012-07-11 01:36:55 +02:00
}
2012-10-11 16:42:46 +02:00
flags =
2012-10-18 23:22:56 +02:00
arg_all * OUTPUT_SHOW_ALL |
2012-11-17 15:27:59 +01:00
( arg_full | | ! on_tty ( ) | | pager_have ( ) ) * OUTPUT_FULL_WIDTH |
2012-11-15 23:03:31 +01:00
on_tty ( ) * OUTPUT_COLOR |
arg_catalog * OUTPUT_CATALOG ;
2012-10-11 16:42:46 +02:00
2012-09-27 23:27:10 +02:00
r = output_journal ( stdout , j , arg_output , 0 , flags ) ;
2013-01-13 12:28:38 +01:00
if ( r < 0 | | ferror ( stdout ) )
2011-12-21 18:17:22 +01:00
goto finish ;
2012-01-04 04:00:14 +01:00
need_seek = true ;
2012-10-11 16:42:46 +02:00
n_shown + + ;
2011-10-07 21:06:39 +02:00
}
2011-12-19 22:35:46 +01:00
if ( ! arg_follow )
break ;
2012-07-10 21:46:11 +02:00
r = sd_journal_wait ( j , ( uint64_t ) - 1 ) ;
2011-12-19 22:35:46 +01:00
if ( r < 0 ) {
2012-10-09 01:31:27 +02:00
log_error ( " Couldn't wait for journal event: %s " , strerror ( - r ) ) ;
2011-12-19 22:35:46 +01:00
goto finish ;
}
2013-01-28 05:53:52 +01:00
first_line = false ;
2011-11-08 18:20:03 +01:00
}
2011-10-07 21:06:39 +02:00
finish :
2011-12-21 18:59:56 +01:00
pager_close ( ) ;
2011-10-14 04:44:50 +02:00
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS ;
2011-10-07 21:06:39 +02:00
}