2010-07-28 16:20:38 +04:00
/*
2013-06-09 00:23:39 +04:00
* Copyright ( C ) 2010 - 2013 Red Hat , Inc . All rights reserved .
2010-07-28 16:20:38 +04:00
*
* This file is part of LVM2 .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU General Public License v .2 .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
2016-01-21 13:49:46 +03:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2010-07-28 16:20:38 +04:00
*/
2014-03-04 18:10:58 +04:00
# include <errno.h>
2009-02-12 22:54:45 +03:00
# include <fcntl.h>
2013-06-09 00:23:39 +04:00
# include <limits.h>
2009-02-12 22:54:45 +03:00
# include <stdio.h>
2013-06-09 00:23:39 +04:00
# include <stdlib.h>
# include <string.h>
2014-03-04 18:10:58 +04:00
# include <sys/klog.h>
2013-06-09 00:23:39 +04:00
# include <sys/resource.h> /* rusage */
# include <sys/select.h>
2009-02-12 22:54:45 +03:00
# include <sys/socket.h>
2013-12-04 20:01:59 +04:00
# include <sys/stat.h>
2013-06-09 00:23:39 +04:00
# include <sys/time.h>
# include <sys/types.h>
2009-02-12 22:54:45 +03:00
# include <sys/wait.h>
2011-01-28 19:05:38 +03:00
# include <time.h>
2013-06-09 00:23:39 +04:00
# include <unistd.h>
2013-12-05 14:12:56 +04:00
# include <stdint.h>
2009-02-12 22:54:45 +03:00
2011-01-05 18:03:43 +03:00
static pid_t pid ;
static int fds [ 2 ] ;
2010-04-07 13:41:33 +04:00
# define MAX 1024
2013-06-09 00:23:39 +04:00
# define MAX_LOG_SIZE (32*1024*1024) /* Default max size of test log */
2014-04-25 01:44:22 +04:00
# define WRITE_TIMEOUT (180 * 2) /* 3 minutes */
2010-04-07 13:41:33 +04:00
struct stats {
int nfailed ;
int nskipped ;
int npassed ;
2012-05-16 14:43:41 +04:00
int nknownfail ;
2010-04-30 18:33:39 +04:00
int nwarned ;
2013-06-09 00:23:39 +04:00
int ninterrupted ;
2010-04-07 13:41:33 +04:00
int status [ MAX ] ;
} ;
2011-01-05 18:03:43 +03:00
static struct stats s ;
2009-02-12 22:54:45 +03:00
2011-01-05 18:03:43 +03:00
static char * readbuf = NULL ;
2013-06-03 14:09:21 +04:00
static size_t readbuf_sz = 0 , readbuf_used = 0 ;
2009-02-12 22:54:45 +03:00
2011-01-05 18:03:43 +03:00
static int die = 0 ;
2012-03-12 18:24:15 +04:00
static int verbose = 0 ; /* >1 with timestamps */
2012-10-08 22:15:55 +04:00
static int interactive = 0 ; /* disable all redirections */
2013-12-15 19:36:24 +04:00
static int quiet = 0 ;
2013-06-03 14:07:31 +04:00
static const char * results ;
2013-06-09 00:23:39 +04:00
static unsigned fullbuffer = 0 ;
2013-12-05 14:12:56 +04:00
static int unlimited = 0 ;
2014-04-25 01:44:22 +04:00
static int write_timeout = WRITE_TIMEOUT ;
2011-01-05 03:16:18 +03:00
2013-12-16 14:47:09 +04:00
static time_t harness_start ;
2013-05-27 06:26:33 +04:00
static FILE * outfile = NULL ;
2013-12-04 20:01:59 +04:00
char testdirdebug [ PATH_MAX ] ;
2013-05-27 06:26:33 +04:00
2011-01-05 03:16:18 +03:00
struct subst {
2011-03-10 17:47:22 +03:00
const char * key ;
char * value ;
2011-01-05 03:16:18 +03:00
} ;
2011-01-05 18:03:43 +03:00
static struct subst subst [ 2 ] ;
2009-02-12 22:54:45 +03:00
2013-06-03 14:09:21 +04:00
enum {
UNKNOWN ,
FAILED ,
2013-06-09 00:23:39 +04:00
INTERRUPTED ,
2013-11-21 13:41:08 +04:00
KNOWNFAIL ,
PASSED ,
SKIPPED ,
2013-07-23 13:42:34 +04:00
TIMEOUT ,
2013-11-21 13:41:08 +04:00
WARNED ,
2013-06-03 14:09:21 +04:00
} ;
2009-02-12 22:54:45 +03:00
2011-01-13 14:02:55 +03:00
static void handler ( int sig ) {
signal ( sig , SIG_DFL ) ;
2013-07-23 13:42:34 +04:00
kill ( - pid , sig ) ;
2011-01-13 14:02:55 +03:00
die = sig ;
2009-02-12 22:54:45 +03:00
}
2013-05-27 06:26:33 +04:00
static int outline ( FILE * out , char * buf , int start , int force ) {
2011-03-10 17:47:22 +03:00
char * from = buf + start ;
char * next = strchr ( buf + start , ' \n ' ) ;
if ( ! next & & ! force ) /* not a complete line yet... */
return start ;
if ( ! next )
next = from + strlen ( from ) ;
else
+ + next ;
if ( ! strncmp ( from , " @TESTDIR= " , 9 ) ) {
subst [ 0 ] . key = " @TESTDIR@ " ;
2013-06-12 16:16:25 +04:00
free ( subst [ 0 ] . value ) ;
2011-03-10 17:47:22 +03:00
subst [ 0 ] . value = strndup ( from + 9 , next - from - 9 - 1 ) ;
2013-12-05 00:37:33 +04:00
snprintf ( testdirdebug , sizeof ( testdirdebug ) , " %s/debug.log " , subst [ 0 ] . value ) ;
2011-03-10 17:47:22 +03:00
} else if ( ! strncmp ( from , " @PREFIX= " , 8 ) ) {
subst [ 1 ] . key = " @PREFIX@ " ;
2013-06-12 16:16:25 +04:00
free ( subst [ 1 ] . value ) ;
2011-03-10 17:47:22 +03:00
subst [ 1 ] . value = strndup ( from + 8 , next - from - 8 - 1 ) ;
} else {
char * line = strndup ( from , next - from ) ;
char * a = line , * b ;
do {
int idx = - 1 ;
int i ;
b = line + strlen ( line ) ;
for ( i = 0 ; i < 2 ; + + i ) {
if ( subst [ i ] . key ) {
// printf("trying: %s -> %s\n", subst[i].value, subst[i].key);
char * stop = strstr ( a , subst [ i ] . value ) ;
if ( stop & & stop < b ) {
idx = i ;
b = stop ;
}
}
}
2013-05-27 06:26:33 +04:00
fwrite ( a , 1 , b - a , out ) ;
2011-03-10 17:47:22 +03:00
a = b ;
if ( idx > = 0 ) {
2013-05-27 06:26:33 +04:00
fprintf ( out , " %s " , subst [ idx ] . key ) ;
2011-03-10 17:47:22 +03:00
a + = strlen ( subst [ idx ] . value ) ;
}
} while ( b < line + strlen ( line ) ) ;
free ( line ) ;
}
return next - buf + ( force ? 0 : 1 ) ;
2011-01-05 03:16:18 +03:00
}
2011-01-05 18:03:43 +03:00
static void dump ( void ) {
2011-01-13 18:03:28 +03:00
int counter_last = - 1 , counter = 0 ;
2011-01-05 03:16:18 +03:00
2013-06-03 14:09:21 +04:00
while ( ( counter < ( int ) readbuf_used ) & & ( counter ! = counter_last ) ) {
2011-01-13 14:02:55 +03:00
counter_last = counter ;
2013-05-27 06:26:33 +04:00
counter = outline ( stdout , readbuf , counter , 1 ) ;
2011-01-13 14:02:55 +03:00
}
2009-02-12 22:54:45 +03:00
}
2013-05-27 06:26:33 +04:00
static void trickle ( FILE * out , int * last , int * counter ) {
2013-06-03 14:09:21 +04:00
if ( * last > ( int ) readbuf_used ) {
2013-05-27 06:26:33 +04:00
* last = - 1 ;
* counter = 0 ;
2012-03-12 18:24:15 +04:00
}
2013-06-03 14:09:21 +04:00
while ( ( * counter < ( int ) readbuf_used ) & & ( * counter ! = * last ) ) {
2013-05-27 06:26:33 +04:00
* last = * counter ;
* counter = outline ( out , readbuf , * counter , 1 ) ;
2012-02-15 05:31:10 +04:00
}
}
2011-01-05 18:03:43 +03:00
static void clear ( void ) {
2009-02-12 22:54:45 +03:00
readbuf_used = 0 ;
2013-06-12 16:16:25 +04:00
fullbuffer = 0 ;
2009-02-12 22:54:45 +03:00
}
2012-03-12 18:24:15 +04:00
static int64_t _get_time_us ( void )
{
struct timeval tv ;
( void ) gettimeofday ( & tv , 0 ) ;
return ( int64_t ) tv . tv_sec * 1000000 + ( int64_t ) tv . tv_usec ;
}
static void _append_buf ( const char * buf , size_t len )
{
if ( ( readbuf_used + len ) > = readbuf_sz ) {
2013-12-05 14:12:56 +04:00
if ( ( readbuf_sz > = MAX_LOG_SIZE ) & & ! unlimited ) {
2013-06-09 00:23:39 +04:00
if ( fullbuffer + + = = 0 )
2013-07-23 13:42:34 +04:00
kill ( - pid , SIGINT ) ;
2013-06-09 00:23:39 +04:00
return ;
}
2014-03-03 22:08:22 +04:00
readbuf_sz = 2 * ( readbuf_used + len + readbuf_sz ) ;
2012-03-12 18:24:15 +04:00
readbuf = realloc ( readbuf , readbuf_sz ) ;
}
if ( ! readbuf )
exit ( 205 ) ;
memcpy ( readbuf + readbuf_used , buf , len ) ;
readbuf_used + = len ;
}
static const char * _append_with_stamp ( const char * buf , int stamp )
{
static const char spaces [ ] = " " ;
static int64_t t_last ;
static int64_t t_start = 0 ;
int64_t t_now ;
char stamp_buf [ 32 ] ; /* Bigger to always fit both numbers */
const char * be ;
const char * bb = buf ;
size_t len ;
while ( ( be = strchr ( bb , ' \n ' ) ) ) {
if ( stamp + + = = 0 ) {
t_now = _get_time_us ( ) ;
if ( ! t_start )
t_start = t_last = t_now ;
len = snprintf ( stamp_buf , sizeof ( stamp_buf ) ,
" %8.3f%8.4f " ,
( t_now - t_start ) / 1000000.f ,
( t_now - t_last ) / 1000000.f ) ;
_append_buf ( stamp_buf , ( len < ( sizeof ( spaces ) - 1 ) ) ?
len : ( sizeof ( spaces ) - 1 ) ) ;
t_last = t_now ;
}
_append_buf ( bb , be + 1 - bb ) ;
bb = be + 1 ;
if ( stamp > 0 & & bb [ 0 ] )
_append_buf ( spaces , sizeof ( spaces ) - 1 ) ;
}
return bb ;
}
2014-03-03 22:08:22 +04:00
static int drain ( int fd )
2013-09-12 15:30:12 +04:00
{
2014-03-03 22:08:22 +04:00
char buf [ 2 * 1024 * 1024 + 1 ] ; /* try to capture large sysrq trace */
2012-03-12 18:24:15 +04:00
const char * bp ;
int stamp = 0 ;
2014-03-03 22:08:22 +04:00
int sz ;
2012-03-12 18:24:15 +04:00
2013-05-27 06:26:33 +04:00
static int stdout_last = - 1 , stdout_counter = 0 ;
static int outfile_last = - 1 , outfile_counter = 0 ;
2014-03-03 22:08:22 +04:00
if ( ( sz = read ( fd , buf , sizeof ( buf ) - 1 ) ) > 0 ) {
2012-03-12 18:24:15 +04:00
buf [ sz ] = ' \0 ' ;
bp = ( verbose < 2 ) ? buf : _append_with_stamp ( buf , stamp ) ;
if ( sz > ( bp - buf ) ) {
_append_buf ( bp , sz - ( bp - buf ) ) ;
stamp = - 1 ; /* unfinished line */
} else
stamp = 0 ;
readbuf [ readbuf_used ] = 0 ;
2012-02-15 05:31:10 +04:00
if ( verbose )
2013-05-27 06:26:33 +04:00
trickle ( stdout , & stdout_last , & stdout_counter ) ;
if ( outfile )
trickle ( outfile , & outfile_last , & outfile_counter ) ;
2009-02-12 22:54:45 +03:00
}
2014-03-03 22:08:22 +04:00
return sz ;
}
static int drain_fds ( int fd1 , int fd2 , long timeout )
{
return - 1 ;
2009-02-12 22:54:45 +03:00
}
2014-03-04 18:10:58 +04:00
# define SYSLOG_ACTION_READ_CLEAR 4
# define SYSLOG_ACTION_CLEAR 5
static void clear_dmesg ( void )
{
klogctl ( SYSLOG_ACTION_CLEAR , 0 , 0 ) ;
}
static void drain_dmesg ( void )
{
char buf [ 1024 * 1024 + 1 ] ;
2014-03-04 19:22:11 +04:00
int sz = klogctl ( SYSLOG_ACTION_READ_CLEAR , buf , sizeof ( buf ) - 1 ) ;
if ( sz > 0 ) {
buf [ sz ] = 0 ;
_append_buf ( buf , sz ) ;
}
2014-03-04 18:10:58 +04:00
}
2013-06-09 00:23:39 +04:00
static const char * duration ( time_t start , const struct rusage * usage )
2011-01-28 19:05:38 +03:00
{
2013-06-09 00:23:39 +04:00
static char buf [ 100 ] ;
2011-01-28 19:05:38 +03:00
int t = ( int ) ( time ( NULL ) - start ) ;
2013-06-09 00:23:39 +04:00
int p = sprintf ( buf , " %2d:%02d " , t / 60 , t % 60 ) ;
if ( usage )
sprintf ( buf + p , " %2ld:%02ld.%03ld/%ld:%02ld.%03ld%5ld%8ld/%ld " ,
usage - > ru_utime . tv_sec / 60 , usage - > ru_utime . tv_sec % 60 ,
usage - > ru_utime . tv_usec / 1000 ,
usage - > ru_stime . tv_sec / 60 , usage - > ru_stime . tv_sec % 60 ,
usage - > ru_stime . tv_usec / 1000 ,
usage - > ru_maxrss / 1024 ,
usage - > ru_inblock , usage - > ru_oublock ) ;
2011-01-28 19:05:38 +03:00
return buf ;
}
2013-06-09 00:23:39 +04:00
static void passed ( int i , char * f , time_t t , const struct rusage * usage ) {
2012-05-16 14:43:41 +04:00
if ( readbuf & & strstr ( readbuf , " TEST EXPECT FAIL " ) ) {
+ + s . npassed ;
s . status [ i ] = PASSED ;
2013-06-09 00:23:39 +04:00
printf ( " passed (UNEXPECTED). %s \n " , duration ( t , usage ) ) ;
2012-05-16 14:43:41 +04:00
} else if ( readbuf & & strstr ( readbuf , " TEST WARNING " ) ) {
2010-04-30 18:33:39 +04:00
+ + s . nwarned ;
s . status [ i ] = WARNED ;
2013-06-09 00:23:39 +04:00
printf ( " warnings %s \n " , duration ( t , usage ) ) ;
2010-04-30 18:33:39 +04:00
} else {
+ + s . npassed ;
s . status [ i ] = PASSED ;
2013-06-09 00:23:39 +04:00
printf ( " passed. %s \n " , duration ( t , usage ) ) ;
}
}
static void interrupted ( int i , char * f ) {
+ + s . ninterrupted ;
s . status [ i ] = INTERRUPTED ;
printf ( " \n interrupted. \n " ) ;
2013-12-15 19:36:24 +04:00
if ( ! quiet & & ! verbose & & fullbuffer ) {
2013-06-09 00:23:39 +04:00
printf ( " -- Interrupted %s ------------------------------------ \n " , f ) ;
dump ( ) ;
printf ( " \n -- Interrupted %s (end) ------------------------------ \n " , f ) ;
2010-04-30 18:33:39 +04:00
}
2009-02-12 22:54:45 +03:00
}
2013-07-23 13:42:34 +04:00
static void timeout ( int i , char * f ) {
+ + s . ninterrupted ;
s . status [ i ] = TIMEOUT ;
printf ( " timeout. \n " ) ;
2013-12-15 19:36:24 +04:00
if ( ! quiet & & ! verbose & & readbuf ) {
2013-07-23 13:42:34 +04:00
printf ( " -- Timed out %s ------------------------------------ \n " , f ) ;
dump ( ) ;
printf ( " \n -- Timed out %s (end) ------------------------------ \n " , f ) ;
}
}
2011-01-05 18:03:43 +03:00
static void skipped ( int i , char * f ) {
2010-04-07 13:41:33 +04:00
+ + s . nskipped ;
s . status [ i ] = SKIPPED ;
2009-02-12 22:54:45 +03:00
printf ( " skipped. \n " ) ;
}
2011-01-05 18:03:43 +03:00
static void failed ( int i , char * f , int st ) {
2012-05-16 14:43:41 +04:00
if ( readbuf & & strstr ( readbuf , " TEST EXPECT FAIL " ) ) {
printf ( " FAILED (expected). \n " ) ;
s . status [ i ] = KNOWNFAIL ;
+ + s . nknownfail ;
return ;
}
2010-04-07 13:41:33 +04:00
+ + s . nfailed ;
s . status [ i ] = FAILED ;
2013-10-12 00:31:57 +04:00
printf ( " FAILED (status %d). \n " , WEXITSTATUS ( st ) ) ;
2013-12-15 19:36:24 +04:00
if ( ! quiet & & ! verbose & & readbuf ) {
2011-11-07 21:02:56 +04:00
printf ( " -- FAILED %s ------------------------------------ \n " , f ) ;
dump ( ) ;
printf ( " -- FAILED %s (end) ------------------------------ \n " , f ) ;
}
2009-02-12 22:54:45 +03:00
}
2011-01-05 18:03:43 +03:00
static void run ( int i , char * f ) {
2013-06-09 00:23:39 +04:00
struct rusage usage ;
2013-06-03 14:09:21 +04:00
char flavour [ 512 ] , script [ 512 ] ;
2009-02-12 22:54:45 +03:00
pid = fork ( ) ;
if ( pid < 0 ) {
perror ( " Fork failed. " ) ;
exit ( 201 ) ;
} else if ( pid = = 0 ) {
2012-10-08 22:15:55 +04:00
if ( ! interactive ) {
2013-10-12 00:31:57 +04:00
close ( STDIN_FILENO ) ;
dup2 ( fds [ 1 ] , STDOUT_FILENO ) ;
dup2 ( fds [ 1 ] , STDERR_FILENO ) ;
2012-10-08 22:15:55 +04:00
close ( fds [ 1 ] ) ;
}
2013-10-12 00:31:57 +04:00
close ( fds [ 0 ] ) ;
2013-05-27 05:12:03 +04:00
if ( strchr ( f , ' : ' ) ) {
strcpy ( flavour , f ) ;
* strchr ( flavour , ' : ' ) = 0 ;
setenv ( " LVM_TEST_FLAVOUR " , flavour , 1 ) ;
strcpy ( script , strchr ( f , ' : ' ) + 1 ) ;
} else {
strcpy ( script , f ) ;
}
2013-07-23 13:42:34 +04:00
setpgid ( 0 , 0 ) ;
2013-06-09 00:23:39 +04:00
execlp ( " bash " , " bash " , " -noprofile " , " -norc " , script , NULL ) ;
2009-02-12 22:54:45 +03:00
perror ( " execlp " ) ;
2009-07-14 01:26:41 +04:00
fflush ( stderr ) ;
_exit ( 202 ) ;
2009-02-12 22:54:45 +03:00
} else {
2013-06-09 00:23:39 +04:00
int st = - 1 , w ;
2011-01-28 19:05:38 +03:00
time_t start = time ( NULL ) ;
2009-02-12 22:54:45 +03:00
char buf [ 128 ] ;
2013-06-03 14:07:31 +04:00
char outpath [ PATH_MAX ] ;
char * c = outpath + strlen ( results ) + 1 ;
2013-12-04 20:01:59 +04:00
struct stat statbuf ;
2013-07-23 13:42:34 +04:00
int runaway = 0 ;
2013-09-09 14:14:00 +04:00
int no_write = 0 ;
2014-03-04 18:10:58 +04:00
int clobber_dmesg = 0 ;
2013-12-05 14:12:56 +04:00
int collect_debug = 0 ;
2013-12-16 00:10:57 +04:00
int fd_debuglog = - 1 ;
2014-03-03 22:08:22 +04:00
int fd_kmsg ;
2014-03-04 20:50:17 +04:00
fd_set set ;
2014-03-03 22:08:22 +04:00
int ret ;
2013-06-09 00:23:39 +04:00
2013-10-12 00:31:57 +04:00
//close(fds[1]);
2013-12-04 20:01:59 +04:00
testdirdebug [ 0 ] = ' \0 ' ; /* Capture RUNTESTDIR */
2013-06-03 14:07:31 +04:00
snprintf ( buf , sizeof ( buf ) , " %s ... " , f ) ;
2014-03-03 00:30:26 +04:00
printf ( " Running %-60s%c " , buf , verbose ? ' \n ' : ' ' ) ;
2009-02-12 22:54:45 +03:00
fflush ( stdout ) ;
2013-06-03 14:07:31 +04:00
snprintf ( outpath , sizeof ( outpath ) , " %s/%s.txt " , results , f ) ;
while ( ( c = strchr ( c , ' / ' ) ) )
* c = ' _ ' ;
2013-06-09 00:23:39 +04:00
if ( ! ( outfile = fopen ( outpath , " w " ) ) )
perror ( " fopen " ) ;
2014-03-03 00:30:26 +04:00
/* Mix-in kernel log message */
2014-03-04 18:10:58 +04:00
if ( ( fd_kmsg = open ( " /dev/kmsg " , O_RDONLY | O_NONBLOCK ) ) < 0 ) {
if ( errno ! = ENOENT ) /* Older kernels (<3.5) do not support /dev/kmsg */
perror ( " open /dev/kmsg " ) ;
} else if ( lseek ( fd_kmsg , 0L , SEEK_END ) = = ( off_t ) - 1 )
perror ( " lseek /dev/kmsg " ) ;
2014-03-03 00:30:26 +04:00
2014-03-04 19:22:11 +04:00
if ( ( fd_kmsg < 0 ) & &
( clobber_dmesg = strcmp ( getenv ( " LVM_TEST_CAN_CLOBBER_DMESG " ) ? : " 0 " , " 0 " ) ) )
clear_dmesg ( ) ;
2013-06-09 00:23:39 +04:00
while ( ( w = wait4 ( pid , & st , WNOHANG , & usage ) ) = = 0 ) {
2014-03-04 20:50:17 +04:00
struct timeval selectwait = { . tv_usec = 500000 } ; /* 0.5s */
2013-07-23 13:42:34 +04:00
if ( ( fullbuffer & & fullbuffer + + = = 8000 ) | |
2014-04-25 01:44:22 +04:00
( write_timeout > 0 & & no_write > write_timeout ) )
2013-07-23 13:42:34 +04:00
{
2013-12-04 22:48:29 +04:00
timeout :
2013-08-05 23:11:49 +04:00
kill ( pid , SIGINT ) ;
2013-07-23 13:42:34 +04:00
sleep ( 5 ) ; /* wait a bit for a reaction */
if ( ( w = waitpid ( pid , & st , WNOHANG ) ) = = 0 ) {
2014-04-25 01:44:22 +04:00
if ( write_timeout > 0 & & no_write > write_timeout )
2013-12-05 15:32:27 +04:00
/*
* Kernel traces needed , when stuck for
* too long in userspace without producing
* any output , in other case it should be
* user space problem
*/
system ( " echo t > /proc/sysrq-trigger " ) ;
2013-12-05 14:12:56 +04:00
collect_debug = 1 ;
2013-07-23 13:42:34 +04:00
kill ( - pid , SIGKILL ) ;
2013-08-05 23:11:49 +04:00
w = pid ; // waitpid(pid, &st, NULL);
2013-07-23 13:42:34 +04:00
}
runaway = 1 ;
break ;
}
2014-03-04 20:50:17 +04:00
if ( clobber_dmesg )
drain_dmesg ( ) ;
FD_ZERO ( & set ) ;
FD_SET ( fds [ 0 ] , & set ) ;
if ( fd_kmsg > = 0 )
FD_SET ( fd_kmsg , & set ) ;
if ( ( ret = select ( fd_kmsg > fds [ 0 ] ? fd_kmsg + 1 : fds [ 0 ] + 1 , & set , NULL , NULL , & selectwait ) ) < = 0 ) {
2013-12-04 20:01:59 +04:00
/* Still checking debug log size if it's not growing too much */
2013-12-05 14:12:56 +04:00
if ( ! unlimited & & testdirdebug [ 0 ] & &
( stat ( testdirdebug , & statbuf ) = = 0 ) & &
2013-12-04 22:48:29 +04:00
statbuf . st_size > 32 * 1024 * 1024 ) { /* 32MB command log size */
printf ( " Killing test since debug.log has gone wild (size %ld) \n " ,
statbuf . st_size ) ;
goto timeout ;
2013-12-04 20:01:59 +04:00
}
2013-09-09 14:14:00 +04:00
no_write + + ;
2013-06-09 00:23:39 +04:00
continue ;
2014-03-04 20:50:17 +04:00
}
if ( FD_ISSET ( fds [ 0 ] , & set ) & & drain ( fds [ 0 ] ) > 0 )
2014-03-03 22:08:22 +04:00
no_write = 0 ;
2014-03-04 20:50:17 +04:00
else if ( fd_kmsg > = 0 & & FD_ISSET ( fd_kmsg , & set ) & & ( drain ( fd_kmsg ) < 0 ) ) {
close ( fd_kmsg ) ;
fd_kmsg = - 1 ; /* Likely /dev/kmsg is not readable */
if ( ( clobber_dmesg = strcmp ( getenv ( " LVM_TEST_CAN_CLOBBER_DMESG " ) ? : " 0 " , " 0 " ) ) )
clear_dmesg ( ) ;
}
2013-06-09 00:23:39 +04:00
}
if ( w ! = pid ) {
perror ( " waitpid " ) ;
exit ( 206 ) ;
}
2014-03-03 22:08:22 +04:00
while ( ! fullbuffer & & ( drain_fds ( fds [ 0 ] , fd_kmsg , 0 ) > 0 ) )
/* read out what was left */ ;
2013-07-23 13:42:34 +04:00
if ( die = = 2 )
2013-06-09 00:23:39 +04:00
interrupted ( i , f ) ;
2013-07-23 13:42:34 +04:00
else if ( runaway ) {
2013-12-05 14:12:56 +04:00
if ( collect_debug & &
2013-12-16 00:10:57 +04:00
( fd_debuglog = open ( testdirdebug , O_RDONLY ) ) ! = - 1 ) {
2014-03-03 22:08:22 +04:00
runaway = unlimited ? INT32_MAX : 4 * 1024 * 1024 ;
while ( ! fullbuffer & & runaway > 0 & & ( ret = drain ( fd_debuglog ) ) > 0 )
runaway - = ret ;
2013-12-16 00:10:57 +04:00
close ( fd_debuglog ) ;
2013-12-05 14:12:56 +04:00
}
2013-07-23 13:42:34 +04:00
timeout ( i , f ) ;
} else if ( WIFEXITED ( st ) ) {
2013-06-09 00:23:39 +04:00
if ( WEXITSTATUS ( st ) = = 0 )
passed ( i , f , start , & usage ) ;
else if ( WEXITSTATUS ( st ) = = 200 )
skipped ( i , f ) ;
else
2009-02-12 22:54:45 +03:00
failed ( i , f , st ) ;
2013-06-09 00:23:39 +04:00
} else
failed ( i , f , st ) ;
2013-06-12 16:16:25 +04:00
2014-03-03 22:08:22 +04:00
if ( fd_kmsg > = 0 )
close ( fd_kmsg ) ;
2014-03-04 18:10:58 +04:00
else if ( clobber_dmesg )
drain_dmesg ( ) ;
2013-06-09 00:23:39 +04:00
if ( outfile )
2013-06-03 14:07:31 +04:00
fclose ( outfile ) ;
2013-06-09 00:23:39 +04:00
if ( fullbuffer )
printf ( " \n Test was interrupted, output has got too large (>%u) (loop:%u) \n "
" Set LVM_TEST_UNLIMITED=1 for unlimited log. \n " ,
( unsigned ) readbuf_sz , fullbuffer ) ;
2013-06-12 16:16:25 +04:00
clear ( ) ;
2009-02-12 22:54:45 +03:00
}
}
int main ( int argc , char * * argv ) {
2013-06-03 14:07:31 +04:00
char results_list [ PATH_MAX ] ;
const char * result ;
2012-10-08 22:15:55 +04:00
const char * be_verbose = getenv ( " VERBOSE " ) ,
2013-12-15 19:36:24 +04:00
* be_interactive = getenv ( " INTERACTIVE " ) ,
2014-04-25 01:44:22 +04:00
* be_quiet = getenv ( " QUIET " ) ,
* be_write_timeout = getenv ( " WRITE_TIMEOUT " ) ;
2011-01-28 19:05:38 +03:00
time_t start = time ( NULL ) ;
2009-02-12 22:54:45 +03:00
int i ;
2013-06-03 14:07:31 +04:00
FILE * list ;
2010-04-07 13:41:33 +04:00
if ( argc > = MAX ) {
fprintf ( stderr , " Sorry, my head exploded. Please increase MAX. \n " ) ;
exit ( 1 ) ;
}
2012-03-12 18:24:15 +04:00
if ( be_verbose )
verbose = atoi ( be_verbose ) ;
2009-02-12 22:54:45 +03:00
2012-10-08 22:15:55 +04:00
if ( be_interactive )
interactive = atoi ( be_interactive ) ;
2013-12-15 19:36:24 +04:00
if ( be_quiet )
quiet = atoi ( be_quiet ) ;
2014-04-25 01:44:22 +04:00
if ( be_write_timeout )
write_timeout = atoi ( be_write_timeout ) * 2 ;
2013-06-09 00:23:39 +04:00
results = getenv ( " LVM_TEST_RESULTS " ) ? : " results " ;
2013-12-05 14:12:56 +04:00
unlimited = getenv ( " LVM_TEST_UNLIMITED " ) ? 1 : 0 ;
2013-06-09 00:23:39 +04:00
( void ) snprintf ( results_list , sizeof ( results_list ) , " %s/list " , results ) ;
2013-06-03 14:07:31 +04:00
2013-10-12 00:31:57 +04:00
//if (pipe(fds)) {
2009-02-12 22:54:45 +03:00
if ( socketpair ( PF_UNIX , SOCK_STREAM , 0 , fds ) ) {
perror ( " socketpair " ) ;
return 201 ;
}
2013-10-12 00:31:57 +04:00
if ( fcntl ( fds [ 0 ] , F_SETFL , O_NONBLOCK ) = = - 1 ) {
2009-02-12 22:54:45 +03:00
perror ( " fcntl on socket " ) ;
return 202 ;
}
/* set up signal handlers */
2013-06-12 16:16:25 +04:00
for ( i = 0 ; i < = 32 ; + + i )
switch ( i ) {
case SIGCHLD : case SIGWINCH : case SIGURG :
case SIGKILL : case SIGSTOP : break ;
default : signal ( i , handler ) ;
}
2009-02-12 22:54:45 +03:00
2013-12-16 14:47:09 +04:00
harness_start = time ( NULL ) ;
2009-02-12 22:54:45 +03:00
/* run the tests */
2013-12-16 14:47:09 +04:00
for ( i = 1 ; ! die & & i < argc ; + + i ) {
2009-02-12 22:54:45 +03:00
run ( i , argv [ i ] ) ;
2014-06-06 19:36:38 +04:00
if ( time ( NULL ) - harness_start > 48 * 360 ) { /* 04:48 */
printf ( " Nearly 5 hours passed, giving up... \n " ) ;
2013-12-16 20:35:33 +04:00
die = 1 ;
2013-12-16 14:47:09 +04:00
}
}
2009-02-12 22:54:45 +03:00
2013-06-12 16:16:25 +04:00
free ( subst [ 0 ] . value ) ;
free ( subst [ 1 ] . value ) ;
free ( readbuf ) ;
2013-12-10 14:21:40 +04:00
printf ( " \n ## %d tests %s : %d OK, %d warnings, %d failures (%d interrupted), %d known failures; "
" %d skipped \n " ,
2013-06-09 00:23:39 +04:00
s . nwarned + s . npassed + s . nfailed + s . nskipped + s . ninterrupted ,
duration ( start , NULL ) ,
2013-12-10 14:21:40 +04:00
s . npassed , s . nwarned , s . nfailed + s . ninterrupted , s . ninterrupted ,
s . nknownfail , s . nskipped ) ;
2009-02-12 22:54:45 +03:00
2013-05-27 06:26:33 +04:00
/* dump a list to results */
2013-06-03 14:07:31 +04:00
if ( ( list = fopen ( results_list , " w " ) ) ) {
for ( i = 1 ; i < argc ; + + i ) {
switch ( s . status [ i ] ) {
case FAILED : result = " failed " ; break ;
2013-11-21 13:41:08 +04:00
case INTERRUPTED : result = " interrupted " ; break ;
case PASSED : result = " passed " ; break ;
2013-06-03 14:07:31 +04:00
case SKIPPED : result = " skipped " ; break ;
2013-07-23 13:42:34 +04:00
case TIMEOUT : result = " timeout " ; break ;
2013-11-21 13:41:08 +04:00
case WARNED : result = " warnings " ; break ;
2013-06-03 14:07:31 +04:00
default : result = " unknown " ; break ;
}
fprintf ( list , " %s %s \n " , argv [ i ] , result ) ;
2013-05-27 06:26:33 +04:00
}
2013-06-03 14:07:31 +04:00
fclose ( list ) ;
} else
perror ( " fopen result " ) ;
2013-05-27 06:26:33 +04:00
2009-02-12 22:54:45 +03:00
/* print out a summary */
2013-11-21 13:41:08 +04:00
if ( s . nfailed | | s . nskipped | | s . nknownfail | | s . ninterrupted | | s . nwarned ) {
2009-02-12 22:54:45 +03:00
for ( i = 1 ; i < argc ; + + i ) {
2010-04-07 13:41:33 +04:00
switch ( s . status [ i ] ) {
2009-02-12 22:54:45 +03:00
case FAILED :
printf ( " FAILED: %s \n " , argv [ i ] ) ;
break ;
2013-11-21 13:41:08 +04:00
case INTERRUPTED :
printf ( " INTERRUPTED: %s \n " , argv [ i ] ) ;
break ;
2012-05-16 14:43:41 +04:00
case KNOWNFAIL :
printf ( " FAILED (expected): %s \n " , argv [ i ] ) ;
break ;
2009-02-12 22:54:45 +03:00
case SKIPPED :
printf ( " skipped: %s \n " , argv [ i ] ) ;
break ;
2013-09-04 18:20:35 +04:00
case TIMEOUT :
2013-10-12 00:31:57 +04:00
printf ( " TIMEOUT: %s \n " , argv [ i ] ) ;
2013-09-04 18:20:35 +04:00
break ;
2013-11-21 13:41:08 +04:00
case WARNED :
printf ( " WARNED: %s \n " , argv [ i ] ) ;
break ;
2013-06-03 14:09:21 +04:00
default : /* do nothing */ ;
2009-02-12 22:54:45 +03:00
}
}
printf ( " \n " ) ;
2013-06-09 00:23:39 +04:00
return ( s . nfailed > 0 ) | | ( s . ninterrupted > 0 ) | | die ;
2009-02-12 22:54:45 +03:00
}
2011-01-28 19:05:38 +03:00
2010-04-13 11:34:19 +04:00
return die ;
2009-02-12 22:54:45 +03:00
}