2011-10-07 23:06:39 +04: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
under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( 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
General Public License for more details .
You should have received a copy of the GNU General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
# include <fcntl.h>
# include <errno.h>
# include <stddef.h>
2011-10-14 06:44:50 +04:00
# include <string.h>
# include <stdio.h>
# include <unistd.h>
# include <stdlib.h>
2011-12-20 01:35:46 +04:00
# include <sys/poll.h>
2011-12-21 21:17:22 +04:00
# include <time.h>
2011-12-21 21:59:56 +04:00
# include <getopt.h>
2011-10-07 23:06:39 +04:00
2012-01-05 19:01:58 +04:00
# include <systemd/sd-journal.h>
2011-10-14 06:44:50 +04:00
# include "log.h"
2011-12-21 21:17:22 +04:00
# include "util.h"
2011-12-21 21:59:56 +04:00
# include "build.h"
# include "pager.h"
2012-01-04 00:08:28 +04:00
# include "logs-show.h"
2011-10-12 07:29:08 +04:00
2012-01-04 21:33:36 +04:00
static OutputMode arg_output = OUTPUT_SHORT ;
2011-12-21 21:17:22 +04:00
static bool arg_follow = false ;
static bool arg_show_all = false ;
2011-12-21 21:59:56 +04:00
static bool arg_no_pager = false ;
2012-01-04 05:14:42 +04:00
static int arg_lines = - 1 ;
2012-01-04 18:27:31 +04:00
static bool arg_no_tail = false ;
2012-01-07 04:37:15 +04:00
static bool arg_new_id128 = false ;
2011-12-20 01:35:46 +04:00
2011-12-21 21:59:56 +04:00
static int help ( void ) {
printf ( " %s [OPTIONS...] {COMMAND} ... \n \n "
2012-01-04 21:33:36 +04:00
" Send control commands to or query the journal. \n \n "
2011-12-21 21:59:56 +04:00
" -h --help Show this help \n "
" --version Show package version \n "
" --no-pager Do not pipe output into a pager \n "
" -a --all Show all properties, including long and unprintable \n "
" -f --follow Follow journal \n "
2012-01-04 21:33:36 +04:00
" -n --lines=INTEGER Journal entries to show \n "
2012-01-04 18:27:31 +04:00
" --no-tail Show all lines, even in follow mode \n "
2012-01-13 05:58:45 +04:00
" -o --output=STRING Change journal output mode (short, short-monotonic, \n "
" verbose, export, json, cat) \n "
2012-01-07 04:37:15 +04:00
" --new-id128 Generate a new 128 Bit id \n " ,
2011-12-21 21:59:56 +04:00
program_invocation_short_name ) ;
return 0 ;
}
static int parse_argv ( int argc , char * argv [ ] ) {
enum {
ARG_VERSION = 0x100 ,
2012-01-04 18:27:31 +04:00
ARG_NO_PAGER ,
2012-01-05 19:28:17 +04:00
ARG_NO_TAIL ,
2012-01-07 04:37:15 +04:00
ARG_NEW_ID128
2011-12-21 21:59:56 +04:00
} ;
static const struct option options [ ] = {
{ " help " , no_argument , NULL , ' h ' } ,
{ " version " , no_argument , NULL , ARG_VERSION } ,
{ " no-pager " , no_argument , NULL , ARG_NO_PAGER } ,
{ " follow " , no_argument , NULL , ' f ' } ,
{ " output " , required_argument , NULL , ' o ' } ,
{ " all " , no_argument , NULL , ' a ' } ,
2012-01-04 05:14:42 +04:00
{ " lines " , required_argument , NULL , ' n ' } ,
2012-01-04 18:27:31 +04:00
{ " no-tail " , no_argument , NULL , ARG_NO_TAIL } ,
2012-01-07 04:37:15 +04:00
{ " new-id128 " , no_argument , NULL , ARG_NEW_ID128 } ,
2011-12-21 21:59:56 +04:00
{ NULL , 0 , NULL , 0 }
} ;
2012-01-04 05:14:42 +04:00
int c , r ;
2011-12-21 21:59:56 +04:00
assert ( argc > = 0 ) ;
assert ( argv ) ;
2012-01-04 05:14:42 +04:00
while ( ( c = getopt_long ( argc , argv , " hfo:an: " , options , NULL ) ) > = 0 ) {
2011-12-21 21:59:56 +04:00
switch ( c ) {
case ' h ' :
help ( ) ;
return 0 ;
case ARG_VERSION :
puts ( PACKAGE_STRING ) ;
puts ( DISTRIBUTION ) ;
puts ( SYSTEMD_FEATURES ) ;
return 0 ;
case ARG_NO_PAGER :
arg_no_pager = true ;
break ;
case ' f ' :
arg_follow = true ;
break ;
case ' o ' :
2012-01-04 21:33:36 +04:00
arg_output = output_mode_from_string ( optarg ) ;
if ( arg_output < 0 ) {
2011-12-21 21:59:56 +04:00
log_error ( " Unknown output '%s'. " , optarg ) ;
return - EINVAL ;
}
2012-01-04 21:33:36 +04:00
2011-12-21 21:59:56 +04:00
break ;
case ' a ' :
arg_show_all = true ;
break ;
2012-01-04 05:14:42 +04:00
case ' n ' :
r = safe_atoi ( optarg , & arg_lines ) ;
2012-01-04 18:27:31 +04:00
if ( r < 0 | | arg_lines < 0 ) {
2012-01-04 05:14:42 +04:00
log_error ( " Failed to parse lines '%s' " , optarg ) ;
return - EINVAL ;
}
break ;
2012-01-04 18:27:31 +04:00
case ARG_NO_TAIL :
arg_no_tail = true ;
break ;
2012-01-07 04:37:15 +04:00
case ARG_NEW_ID128 :
arg_new_id128 = true ;
2012-01-05 19:28:17 +04:00
break ;
2011-12-21 21:59:56 +04:00
case ' ? ' :
return - EINVAL ;
default :
log_error ( " Unknown option code %c " , c ) ;
return - EINVAL ;
}
}
2012-01-17 18:21:40 +04:00
if ( arg_follow & & ! arg_no_tail & & arg_lines < 0 )
2012-01-04 18:27:31 +04:00
arg_lines = 10 ;
2011-12-21 21:59:56 +04:00
return 1 ;
}
2012-01-07 04:37:15 +04:00
static int generate_new_id128 ( void ) {
2012-01-05 19:28:17 +04: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 "
" #define MESSAGE_XYZ SD_ID128_MAKE( " ,
SD_ID128_FORMAT_VAL ( id ) ,
SD_ID128_FORMAT_VAL ( id ) ) ;
for ( i = 0 ; i < 16 ; i + + )
printf ( " %02x%s " , id . bytes [ i ] , i ! = 15 ? " , " : " " ) ;
fputs ( " ) \n " , stdout ) ;
return 0 ;
}
2011-10-07 23:06:39 +04:00
int main ( int argc , char * argv [ ] ) {
2011-12-20 01:35:46 +04:00
int r , i , fd ;
2011-10-14 06:44:50 +04:00
sd_journal * j = NULL ;
2011-12-21 21:17:22 +04:00
unsigned line = 0 ;
2012-01-04 07:00:14 +04:00
bool need_seek = false ;
2011-10-14 06:44:50 +04:00
2011-10-07 23:06:39 +04:00
log_parse_environment ( ) ;
log_open ( ) ;
2011-12-21 21:59:56 +04:00
r = parse_argv ( argc , argv ) ;
if ( r < = 0 )
goto finish ;
2012-01-07 04:37:15 +04:00
if ( arg_new_id128 ) {
r = generate_new_id128 ( ) ;
2012-01-05 19:28:17 +04:00
goto finish ;
}
2011-12-29 18:00:57 +04:00
r = sd_journal_open ( & j , 0 ) ;
2011-10-07 23:06:39 +04:00
if ( r < 0 ) {
log_error ( " Failed to open journal: %s " , strerror ( - r ) ) ;
2011-10-14 06:44:50 +04:00
goto finish ;
2011-10-07 23:06:39 +04:00
}
2011-12-21 21:59:56 +04:00
for ( i = optind ; i < argc ; i + + ) {
2011-10-15 03:13:37 +04:00
r = sd_journal_add_match ( j , argv [ i ] , strlen ( argv [ i ] ) ) ;
if ( r < 0 ) {
log_error ( " Failed to add match: %s " , strerror ( - r ) ) ;
goto finish ;
}
}
2011-12-20 01:35:46 +04:00
fd = sd_journal_get_fd ( j ) ;
if ( fd < 0 ) {
log_error ( " Failed to get wakeup fd: %s " , strerror ( - fd ) ) ;
goto finish ;
}
2011-10-15 04:45:58 +04:00
2012-01-04 05:14:42 +04:00
if ( arg_lines > = 0 ) {
r = sd_journal_seek_tail ( j ) ;
if ( r < 0 ) {
log_error ( " Failed to seek to tail: %s " , strerror ( - r ) ) ;
goto finish ;
}
r = sd_journal_previous_skip ( j , arg_lines ) ;
} else {
r = sd_journal_seek_head ( j ) ;
if ( r < 0 ) {
log_error ( " Failed to seek to head: %s " , strerror ( - r ) ) ;
goto finish ;
}
2012-01-04 07:00:14 +04:00
r = sd_journal_next ( j ) ;
}
if ( r < 0 ) {
log_error ( " Failed to iterate through journal: %s " , strerror ( - r ) ) ;
goto finish ;
2011-12-20 01:35:46 +04:00
}
2011-10-07 23:06:39 +04:00
2011-12-21 21:59:56 +04:00
if ( ! arg_no_pager & & ! arg_follow ) {
columns ( ) ;
pager_open ( ) ;
}
if ( arg_output = = OUTPUT_JSON ) {
2011-12-21 21:17:22 +04:00
fputc ( ' [ ' , stdout ) ;
2011-12-21 21:59:56 +04:00
fflush ( stdout ) ;
}
2011-12-21 21:17:22 +04:00
2011-12-20 01:35:46 +04:00
for ( ; ; ) {
2011-12-21 21:59:56 +04:00
for ( ; ; ) {
2012-01-04 07:00:14 +04:00
if ( need_seek ) {
r = sd_journal_next ( j ) ;
if ( r < 0 ) {
log_error ( " Failed to iterate through journal: %s " , strerror ( - r ) ) ;
goto finish ;
}
2011-12-21 21:59:56 +04:00
}
if ( r = = 0 )
break ;
2011-12-21 21:17:22 +04:00
line + + ;
2011-12-20 01:35:46 +04:00
2012-01-04 00:08:28 +04:00
r = output_journal ( j , arg_output , line , arg_show_all ) ;
2011-12-21 21:17:22 +04:00
if ( r < 0 )
goto finish ;
2012-01-04 07:00:14 +04:00
need_seek = true ;
2011-10-07 23:06:39 +04:00
}
2011-12-20 01:35:46 +04:00
if ( ! arg_follow )
break ;
2012-01-22 21:21:15 +04:00
r = fd_wait_for_event ( fd , POLLIN , ( usec_t ) - 1 ) ;
2012-01-04 21:33:36 +04:00
if ( r < 0 ) {
log_error ( " Couldn't wait for event: %s " , strerror ( - r ) ) ;
2011-12-20 01:35:46 +04:00
goto finish ;
}
2011-10-15 04:45:58 +04:00
2011-12-20 01:35:46 +04:00
r = sd_journal_process ( j ) ;
if ( r < 0 ) {
log_error ( " Failed to process: %s " , strerror ( - r ) ) ;
goto finish ;
}
2011-11-08 21:20:03 +04:00
}
2011-10-07 23:06:39 +04:00
2011-12-21 21:17:22 +04:00
if ( arg_output = = OUTPUT_JSON )
fputs ( " \n ] \n " , stdout ) ;
2011-10-07 23:06:39 +04:00
finish :
2011-10-14 06:44:50 +04:00
if ( j )
sd_journal_close ( j ) ;
2011-10-07 23:06:39 +04:00
2011-12-21 21:59:56 +04:00
pager_close ( ) ;
2011-10-14 06:44:50 +04:00
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS ;
2011-10-07 23:06:39 +04:00
}