2000-05-03 17:54:28 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2000-06-05 17:54:26 +04:00
randomised byte range lock tester
2000-05-03 17:54:28 +04:00
Copyright ( C ) Andrew Tridgell 1999
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2000-05-03 17:54:28 +04:00
( at your option ) any later version .
This program 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
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2000-05-03 17:54:28 +04:00
*/
# include "includes.h"
2011-05-06 13:47:43 +04:00
# include "libsmb/libsmb.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2011-03-23 14:43:17 +03:00
# include "locking/proto.h"
2011-03-23 16:18:59 +03:00
# include "libsmb/nmblib.h"
2000-05-03 17:54:28 +04:00
2002-03-11 02:17:47 +03:00
static fstring password [ 2 ] ;
static fstring username [ 2 ] ;
2003-02-24 06:06:45 +03:00
static int got_user ;
2000-05-03 17:54:28 +04:00
static int got_pass ;
2007-10-19 04:40:25 +04:00
static bool use_kerberos ;
2000-05-03 17:54:28 +04:00
static int numops = 1000 ;
2007-10-19 04:40:25 +04:00
static bool showall ;
static bool analyze ;
static bool hide_unlock_fails ;
static bool use_oplocks ;
2002-03-04 03:35:28 +03:00
static unsigned lock_range = 100 ;
static unsigned lock_base = 0 ;
2002-03-05 22:51:37 +03:00
static unsigned min_length = 0 ;
2007-10-19 04:40:25 +04:00
static bool exact_error_codes ;
static bool zero_zero ;
2000-05-03 17:54:28 +04:00
2006-12-18 23:37:26 +03:00
extern char * optarg ;
extern int optind ;
2000-05-24 09:47:08 +04:00
# define FILENAME "\\locktest.dat"
2000-05-06 05:36:59 +04:00
2000-05-03 18:49:15 +04:00
# define READ_PCT 50
2001-08-27 12:19:43 +04:00
# define LOCK_PCT 45
# define UNLOCK_PCT 70
2000-05-06 05:36:59 +04:00
# define RANGE_MULTIPLE 1
2000-06-13 19:47:23 +04:00
# define NSERVERS 2
2000-06-29 12:22:00 +04:00
# define NCONNECTIONS 2
# define NFILES 2
2000-05-04 13:32:21 +04:00
# define LOCK_TIMEOUT 0
2000-05-03 17:54:28 +04:00
2000-06-05 17:54:26 +04:00
# define NASTY_POSIX_LOCK_HACK 0
2000-05-05 05:11:23 +04:00
2001-08-27 12:19:43 +04:00
enum lock_op { OP_LOCK , OP_UNLOCK , OP_REOPEN } ;
2000-05-05 05:11:23 +04:00
2006-12-19 23:16:52 +03:00
static const char * lock_op_type ( int op )
2006-03-03 02:23:05 +03:00
{
if ( op = = WRITE_LOCK ) return " write " ;
else if ( op = = READ_LOCK ) return " read " ;
else return " other " ;
}
2006-12-19 23:16:52 +03:00
static const char * lock_op_name ( enum lock_op op )
2006-03-03 02:23:05 +03:00
{
if ( op = = OP_LOCK ) return " lock " ;
else if ( op = = OP_UNLOCK ) return " unlock " ;
else return " reopen " ;
}
2000-05-04 08:14:23 +04:00
struct record {
2001-08-27 12:19:43 +04:00
enum lock_op lock_op ;
2001-09-16 12:24:44 +04:00
enum brl_type lock_type ;
2000-05-04 10:30:17 +04:00
char conn , f ;
2008-10-14 03:59:36 +04:00
uint64_t start , len ;
2000-05-04 10:30:17 +04:00
char needed ;
2000-05-04 08:14:23 +04:00
} ;
2000-05-03 18:49:15 +04:00
2001-07-03 08:29:50 +04:00
# define PRESETS 0
# if PRESETS
2000-05-04 08:14:23 +04:00
static struct record preset [ ] = {
2001-08-27 12:19:43 +04:00
{ OP_LOCK , WRITE_LOCK , 0 , 0 , 2 , 0 , 1 } ,
{ OP_LOCK , WRITE_LOCK , 0 , 0 , 0 , 0 , 1 } ,
{ OP_LOCK , WRITE_LOCK , 0 , 0 , 3 , 0 , 1 } ,
{ OP_UNLOCK , 0 , 0 , 0 , 2 , 0 , 1 } ,
{ OP_REOPEN , 0 , 0 , 0 , 0 , 0 , 1 } ,
{ OP_LOCK , READ_LOCK , 0 , 0 , 2 , 0 , 1 } ,
{ OP_LOCK , READ_LOCK , 0 , 0 , 1 , 1 , 1 } ,
{ OP_LOCK , WRITE_LOCK , 0 , 0 , 0 , 0 , 1 } ,
{ OP_REOPEN , 0 , 0 , 0 , 0 , 0 , 1 } ,
{ OP_LOCK , READ_LOCK , 0 , 0 , 2 , 0 , 1 } ,
{ OP_LOCK , WRITE_LOCK , 0 , 0 , 3 , 1 , 1 } ,
{ OP_LOCK , WRITE_LOCK , 0 , 0 , 0 , 0 , 1 } ,
{ OP_REOPEN , 0 , 0 , 0 , 0 , 0 , 1 } ,
{ OP_LOCK , READ_LOCK , 0 , 0 , 2 , 0 , 1 } ,
{ OP_LOCK , WRITE_LOCK , 0 , 0 , 1 , 1 , 1 } ,
{ OP_LOCK , WRITE_LOCK , 0 , 0 , 0 , 0 , 1 } ,
{ OP_REOPEN , 0 , 0 , 0 , 0 , 0 , 1 } ,
{ OP_LOCK , WRITE_LOCK , 0 , 0 , 2 , 0 , 1 } ,
{ OP_LOCK , READ_LOCK , 0 , 0 , 1 , 1 , 1 } ,
{ OP_LOCK , WRITE_LOCK , 0 , 0 , 0 , 0 , 1 } ,
{ OP_REOPEN , 0 , 0 , 0 , 0 , 0 , 1 } ,
{ OP_LOCK , WRITE_LOCK , 0 , 0 , 2 , 0 , 1 } ,
{ OP_LOCK , READ_LOCK , 0 , 0 , 3 , 1 , 1 } ,
{ OP_LOCK , WRITE_LOCK , 0 , 0 , 0 , 0 , 1 } ,
{ OP_REOPEN , 0 , 0 , 0 , 0 , 0 , 1 } ,
2000-05-04 10:57:26 +04:00
} ;
2001-07-03 08:29:50 +04:00
# endif
2000-05-03 17:54:28 +04:00
2000-05-04 08:14:23 +04:00
static struct record * recorded ;
2000-05-03 17:54:28 +04:00
2007-05-29 13:30:34 +04:00
static void print_brl ( struct file_id id ,
2007-05-07 13:35:35 +04:00
struct server_id pid ,
2006-07-11 22:01:26 +04:00
enum brl_type lock_type ,
enum brl_flavour lock_flav ,
br_off start ,
2007-05-29 17:26:44 +04:00
br_off size ,
void * private_data )
2000-05-04 10:30:17 +04:00
{
2000-05-05 05:11:23 +04:00
# if NASTY_POSIX_LOCK_HACK
{
static SMB_INO_T lastino ;
if ( lastino ! = ino ) {
2007-12-05 03:56:18 +03:00
char * cmd ;
if ( asprintf ( & cmd ,
" egrep POSIX.*%u /proc/locks " , ( int ) ino ) > 0 ) {
system ( cmd ) ;
SAFE_FREE ( cmd ) ;
}
2000-05-05 05:11:23 +04:00
}
lastino = ino ;
}
# endif
2000-05-05 05:20:25 +04:00
2007-05-29 13:30:34 +04:00
printf ( " %s %s %s %.0f:%.0f(%.0f) \n " ,
2007-09-10 14:56:07 +04:00
procid_str_static ( & pid ) , file_id_string_tos ( & id ) ,
2000-05-05 05:20:25 +04:00
lock_type = = READ_LOCK ? " R " : " W " ,
2000-05-05 05:26:52 +04:00
( double ) start , ( double ) start + size - 1 , ( double ) size ) ;
2000-05-05 05:20:25 +04:00
2000-05-04 10:30:17 +04:00
}
2000-06-13 19:47:23 +04:00
static void show_locks ( void )
{
2007-05-29 17:26:44 +04:00
brl_forall ( print_brl , NULL ) ;
2000-06-29 12:22:00 +04:00
/* system("cat /proc/locks"); */
2000-06-13 19:47:23 +04:00
}
2000-05-03 17:54:28 +04:00
/*****************************************************
return a connection to a server
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-08-17 19:04:57 +04:00
static struct cli_state * connect_one ( char * share , int snum )
2000-05-03 17:54:28 +04:00
{
struct cli_state * c ;
char * server_n ;
fstring server ;
2000-05-04 10:30:17 +04:00
fstring myname ;
static int count ;
2007-06-20 21:38:42 +04:00
NTSTATUS status ;
2011-09-07 22:35:51 +04:00
int flags = 0 ;
2000-05-03 17:54:28 +04:00
fstrcpy ( server , share + 2 ) ;
2001-07-04 11:36:09 +04:00
share = strchr_m ( server , ' \\ ' ) ;
2000-05-03 17:54:28 +04:00
if ( ! share ) return NULL ;
* share = 0 ;
share + + ;
server_n = server ;
2007-10-25 01:16:54 +04:00
2003-07-22 08:31:20 +04:00
slprintf ( myname , sizeof ( myname ) , " lock-%lu-%u " , ( unsigned long ) getpid ( ) , count + + ) ;
2000-05-04 10:30:17 +04:00
2000-05-03 17:54:28 +04:00
/* have to open a new connection */
2011-09-07 22:35:51 +04:00
if ( use_kerberos ) {
flags | = CLI_FULL_CONNECTION_USE_KERBEROS ;
}
if ( use_oplocks ) {
flags | = CLI_FULL_CONNECTION_OPLOCKS ;
}
status = cli_connect_nb ( server_n , NULL , 0 , 0x20 , myname ,
Undefined , flags , & c ) ;
2007-06-20 21:38:42 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-05-28 20:57:03 +04:00
DEBUG ( 0 , ( " Connection to %s failed. Error %s \n " , server_n ,
nt_errstr ( status ) ) ) ;
2007-06-20 21:38:42 +04:00
return NULL ;
}
2011-09-13 16:33:31 +04:00
status = cli_negprot ( c , PROTOCOL_NT1 ) ;
2008-09-11 20:57:49 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " protocol negotiation failed: %s \n " ,
nt_errstr ( status ) ) ) ;
2000-05-03 17:54:28 +04:00
cli_shutdown ( c ) ;
return NULL ;
}
if ( ! got_pass ) {
char * pass = getpass ( " Password: " ) ;
if ( pass ) {
2003-01-14 11:53:59 +03:00
fstrcpy ( password [ 0 ] , pass ) ;
fstrcpy ( password [ 1 ] , pass ) ;
2000-05-03 17:54:28 +04:00
}
}
2002-03-11 02:17:47 +03:00
if ( got_pass = = 1 ) {
2011-05-04 22:38:26 +04:00
strlcpy ( password [ 1 ] , password [ 0 ] , sizeof ( password [ 1 ] ) ) ;
strlcpy ( username [ 1 ] , username [ 0 ] , sizeof ( username [ 1 ] ) ) ;
2002-03-11 02:17:47 +03:00
}
2011-01-17 15:03:05 +03:00
status = cli_session_setup ( c , username [ snum ] ,
password [ snum ] , strlen ( password [ snum ] ) ,
password [ snum ] , strlen ( password [ snum ] ) ,
lp_workgroup ( ) ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " session setup failed: %s \n " , nt_errstr ( status ) ) ) ;
2000-05-03 17:54:28 +04:00
return NULL ;
}
/*
* These next two lines are needed to emulate
* old client behaviour for people who have
* scripts based on client output .
* QUESTION ? Do we want to have a ' client compatibility
* mode to turn these on / off ? JRA .
*/
if ( * c - > server_domain | | * c - > server_os | | * c - > server_type )
DEBUG ( 1 , ( " Domain=[%s] OS=[%s] Server=[%s] \n " ,
c - > server_domain , c - > server_os , c - > server_type ) ) ;
DEBUG ( 4 , ( " session setup ok \n " ) ) ;
2009-01-26 10:37:13 +03:00
status = cli_tcon_andx ( c , share , " ????? " , password [ snum ] ,
strlen ( password [ snum ] ) + 1 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " tree connect failed: %s \n " , nt_errstr ( status ) ) ) ;
2000-05-03 17:54:28 +04:00
cli_shutdown ( c ) ;
return NULL ;
}
DEBUG ( 4 , ( " tconx ok \n " ) ) ;
return c ;
}
2009-05-01 02:26:43 +04:00
static void reconnect ( struct cli_state * cli [ NSERVERS ] [ NCONNECTIONS ] , uint16_t fnum [ NSERVERS ] [ NCONNECTIONS ] [ NFILES ] ,
2000-06-13 19:47:23 +04:00
char * share [ NSERVERS ] )
2000-05-04 08:14:23 +04:00
{
2000-05-04 10:30:17 +04:00
int server , conn , f ;
2000-05-04 08:14:23 +04:00
2000-06-13 19:47:23 +04:00
for ( server = 0 ; server < NSERVERS ; server + + )
2000-05-04 12:58:07 +04:00
for ( conn = 0 ; conn < NCONNECTIONS ; conn + + ) {
2000-05-04 08:14:23 +04:00
if ( cli [ server ] [ conn ] ) {
2000-05-04 12:58:07 +04:00
for ( f = 0 ; f < NFILES ; f + + ) {
2009-05-01 02:26:43 +04:00
if ( fnum [ server ] [ conn ] [ f ] ! = ( uint16_t ) - 1 ) {
2002-03-11 02:17:47 +03:00
cli_close ( cli [ server ] [ conn ] , fnum [ server ] [ conn ] [ f ] ) ;
2009-05-01 02:26:43 +04:00
fnum [ server ] [ conn ] [ f ] = ( uint16_t ) - 1 ;
2002-03-11 02:17:47 +03:00
}
2000-05-04 10:30:17 +04:00
}
cli_ulogoff ( cli [ server ] [ conn ] ) ;
2000-05-04 08:14:23 +04:00
cli_shutdown ( cli [ server ] [ conn ] ) ;
}
2002-03-11 02:17:47 +03:00
cli [ server ] [ conn ] = connect_one ( share [ server ] , server ) ;
2000-05-04 08:14:23 +04:00
if ( ! cli [ server ] [ conn ] ) {
DEBUG ( 0 , ( " Failed to connect to %s \n " , share [ server ] ) ) ;
exit ( 1 ) ;
}
}
}
2007-10-19 04:40:25 +04:00
static bool test_one ( struct cli_state * cli [ NSERVERS ] [ NCONNECTIONS ] ,
2009-05-01 02:26:43 +04:00
uint16_t fnum [ NSERVERS ] [ NCONNECTIONS ] [ NFILES ] ,
2000-05-04 08:14:23 +04:00
struct record * rec )
{
2000-05-06 05:36:59 +04:00
unsigned conn = rec - > conn ;
unsigned f = rec - > f ;
2008-10-14 03:59:36 +04:00
uint64_t start = rec - > start ;
uint64_t len = rec - > len ;
2001-09-16 12:24:44 +04:00
enum brl_type op = rec - > lock_type ;
2000-06-13 19:47:23 +04:00
int server ;
2002-03-11 02:17:47 +03:00
NTSTATUS status [ NSERVERS ] ;
2000-05-04 08:14:23 +04:00
2001-08-27 12:19:43 +04:00
switch ( rec - > lock_op ) {
case OP_LOCK :
2000-05-04 08:14:23 +04:00
/* set a lock */
2000-06-13 19:47:23 +04:00
for ( server = 0 ; server < NSERVERS ; server + + ) {
2011-07-11 13:19:21 +04:00
status [ server ] = cli_lock64 ( cli [ server ] [ conn ] ,
fnum [ server ] [ conn ] [ f ] ,
start , len , LOCK_TIMEOUT ,
op ) ;
2002-03-11 02:17:47 +03:00
if ( ! exact_error_codes & &
NT_STATUS_EQUAL ( status [ server ] ,
NT_STATUS_FILE_LOCK_CONFLICT ) ) {
status [ server ] = NT_STATUS_LOCK_NOT_GRANTED ;
}
2000-06-13 19:47:23 +04:00
}
2002-03-11 02:17:47 +03:00
if ( showall | | ! NT_STATUS_EQUAL ( status [ 0 ] , status [ 1 ] ) ) {
printf ( " lock conn=%u f=%u range=%.0f(%.0f) op=%s -> %s:%s \n " ,
2000-05-05 05:26:52 +04:00
conn , f ,
2001-08-24 23:34:11 +04:00
( double ) start , ( double ) len ,
2000-05-05 05:26:52 +04:00
op = = READ_LOCK ? " READ_LOCK " : " WRITE_LOCK " ,
2002-03-17 07:36:35 +03:00
nt_errstr ( status [ 0 ] ) , nt_errstr ( status [ 1 ] ) ) ;
2000-05-04 08:14:23 +04:00
}
2002-03-11 02:17:47 +03:00
if ( showall | | ! NT_STATUS_EQUAL ( status [ 0 ] , status [ 1 ] ) ) show_locks ( ) ;
if ( ! NT_STATUS_EQUAL ( status [ 0 ] , status [ 1 ] ) ) return False ;
2001-08-27 12:19:43 +04:00
break ;
case OP_UNLOCK :
2000-05-04 08:14:23 +04:00
/* unset a lock */
2000-06-13 19:47:23 +04:00
for ( server = 0 ; server < NSERVERS ; server + + ) {
2011-07-11 13:19:21 +04:00
status [ server ] = cli_unlock64 ( cli [ server ] [ conn ] ,
fnum [ server ] [ conn ] [ f ] ,
start , len ) ;
2000-06-13 19:47:23 +04:00
}
2002-03-11 02:17:47 +03:00
if ( showall | |
( ! hide_unlock_fails & & ! NT_STATUS_EQUAL ( status [ 0 ] , status [ 1 ] ) ) ) {
printf ( " unlock conn=%u f=%u range=%.0f(%.0f) -> %s:%s \n " ,
2000-05-05 05:26:52 +04:00
conn , f ,
2001-08-24 23:34:11 +04:00
( double ) start , ( double ) len ,
2002-03-17 07:36:35 +03:00
nt_errstr ( status [ 0 ] ) , nt_errstr ( status [ 1 ] ) ) ;
2000-05-04 08:14:23 +04:00
}
2002-03-11 02:17:47 +03:00
if ( showall | | ! NT_STATUS_EQUAL ( status [ 0 ] , status [ 1 ] ) ) show_locks ( ) ;
if ( ! hide_unlock_fails & & ! NT_STATUS_EQUAL ( status [ 0 ] , status [ 1 ] ) )
return False ;
2001-08-27 12:19:43 +04:00
break ;
case OP_REOPEN :
2000-05-04 08:14:23 +04:00
/* reopen the file */
2000-06-13 19:47:23 +04:00
for ( server = 0 ; server < NSERVERS ; server + + ) {
cli_close ( cli [ server ] [ conn ] , fnum [ server ] [ conn ] [ f ] ) ;
2009-05-01 02:26:43 +04:00
fnum [ server ] [ conn ] [ f ] = ( uint16_t ) - 1 ;
2000-05-04 08:14:23 +04:00
}
2000-06-13 19:47:23 +04:00
for ( server = 0 ; server < NSERVERS ; server + + ) {
2009-05-01 02:26:43 +04:00
fnum [ server ] [ conn ] [ f ] = ( uint16_t ) - 1 ;
if ( ! NT_STATUS_IS_OK ( cli_open ( cli [ server ] [ conn ] , FILENAME ,
2000-06-13 19:47:23 +04:00
O_RDWR | O_CREAT ,
2009-05-01 02:26:43 +04:00
DENY_NONE , & fnum [ server ] [ conn ] [ f ] ) ) ) {
2000-06-13 19:47:23 +04:00
printf ( " failed to reopen on share%d \n " , server ) ;
return False ;
}
2000-05-04 08:14:23 +04:00
}
if ( showall ) {
2000-05-06 05:36:59 +04:00
printf ( " reopen conn=%u f=%u \n " ,
2000-05-04 08:14:23 +04:00
conn , f ) ;
2000-06-13 19:47:23 +04:00
show_locks ( ) ;
2000-05-04 08:14:23 +04:00
}
2001-08-27 12:19:43 +04:00
break ;
2000-05-04 08:14:23 +04:00
}
2001-08-27 12:19:43 +04:00
2000-05-04 08:14:23 +04:00
return True ;
}
2000-06-13 19:47:23 +04:00
static void close_files ( struct cli_state * cli [ NSERVERS ] [ NCONNECTIONS ] ,
2009-05-01 02:26:43 +04:00
uint16_t fnum [ NSERVERS ] [ NCONNECTIONS ] [ NFILES ] )
2000-05-04 08:14:23 +04:00
{
int server , conn , f ;
2000-06-13 19:47:23 +04:00
for ( server = 0 ; server < NSERVERS ; server + + )
2000-05-04 12:58:07 +04:00
for ( conn = 0 ; conn < NCONNECTIONS ; conn + + )
for ( f = 0 ; f < NFILES ; f + + ) {
2009-05-01 02:26:43 +04:00
if ( fnum [ server ] [ conn ] [ f ] ! = ( uint16_t ) - 1 ) {
2000-05-04 08:14:23 +04:00
cli_close ( cli [ server ] [ conn ] , fnum [ server ] [ conn ] [ f ] ) ;
2009-05-01 02:26:43 +04:00
fnum [ server ] [ conn ] [ f ] = ( uint16_t ) - 1 ;
2000-05-04 08:14:23 +04:00
}
2000-05-04 10:30:17 +04:00
}
2000-06-13 19:47:23 +04:00
for ( server = 0 ; server < NSERVERS ; server + + ) {
2011-04-29 07:23:14 +04:00
cli_unlink ( cli [ server ] [ 0 ] , FILENAME , FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN ) ;
2000-06-13 19:47:23 +04:00
}
2000-05-04 10:30:17 +04:00
}
2000-06-13 19:47:23 +04:00
static void open_files ( struct cli_state * cli [ NSERVERS ] [ NCONNECTIONS ] ,
2009-05-01 02:26:43 +04:00
uint16_t fnum [ NSERVERS ] [ NCONNECTIONS ] [ NFILES ] )
2000-05-04 10:30:17 +04:00
{
int server , conn , f ;
2000-06-13 19:47:23 +04:00
for ( server = 0 ; server < NSERVERS ; server + + )
2000-05-04 12:58:07 +04:00
for ( conn = 0 ; conn < NCONNECTIONS ; conn + + )
for ( f = 0 ; f < NFILES ; f + + ) {
2009-05-01 02:26:43 +04:00
fnum [ server ] [ conn ] [ f ] = ( uint16_t ) - 1 ;
if ( ! NT_STATUS_IS_OK ( cli_open ( cli [ server ] [ conn ] , FILENAME ,
2000-05-04 08:14:23 +04:00
O_RDWR | O_CREAT ,
2009-05-01 02:26:43 +04:00
DENY_NONE ,
& fnum [ server ] [ conn ] [ f ] ) ) ) {
2000-05-06 05:36:59 +04:00
fprintf ( stderr , " Failed to open fnum[%u][%u][%u] \n " ,
2000-05-04 08:14:23 +04:00
server , conn , f ) ;
exit ( 1 ) ;
}
}
}
2000-06-13 19:47:23 +04:00
static int retest ( struct cli_state * cli [ NSERVERS ] [ NCONNECTIONS ] ,
2009-05-01 02:26:43 +04:00
uint16_t fnum [ NSERVERS ] [ NCONNECTIONS ] [ NFILES ] ,
2000-05-04 08:14:23 +04:00
int n )
{
int i ;
2000-05-06 05:36:59 +04:00
printf ( " testing %u ... \n " , n ) ;
2000-05-04 08:14:23 +04:00
for ( i = 0 ; i < n ; i + + ) {
2000-05-04 10:30:17 +04:00
if ( i & & i % 100 = = 0 ) {
2000-05-06 05:36:59 +04:00
printf ( " %u \n " , i ) ;
2000-05-04 08:14:23 +04:00
}
2000-05-04 10:30:17 +04:00
if ( recorded [ i ] . needed & &
! test_one ( cli , fnum , & recorded [ i ] ) ) return i ;
2000-05-04 08:14:23 +04:00
}
return n ;
}
/* each server has two connections open to it. Each connection has two file
descriptors open on the file - 8 file descriptors in total
we then do random locking ops in tamdem on the 4 fnums from each
server and ensure that the results match
*/
2000-06-13 19:47:23 +04:00
static void test_locks ( char * share [ NSERVERS ] )
2000-05-04 08:14:23 +04:00
{
2000-06-13 19:47:23 +04:00
struct cli_state * cli [ NSERVERS ] [ NCONNECTIONS ] ;
2009-05-01 02:26:43 +04:00
uint16_t fnum [ NSERVERS ] [ NCONNECTIONS ] [ NFILES ] ;
2001-08-27 12:19:43 +04:00
int n , i , n1 , skip , r1 , r2 ;
2000-05-04 08:14:23 +04:00
ZERO_STRUCT ( fnum ) ;
ZERO_STRUCT ( cli ) ;
2005-05-07 10:59:00 +04:00
recorded = SMB_MALLOC_ARRAY ( struct record , numops ) ;
2000-05-04 08:14:23 +04:00
for ( n = 0 ; n < numops ; n + + ) {
2001-07-03 08:29:50 +04:00
# if PRESETS
2000-05-04 08:14:23 +04:00
if ( n < sizeof ( preset ) / sizeof ( preset [ 0 ] ) ) {
recorded [ n ] = preset [ n ] ;
} else {
2001-07-03 08:29:50 +04:00
# endif
2000-05-04 12:58:07 +04:00
recorded [ n ] . conn = random ( ) % NCONNECTIONS ;
recorded [ n ] . f = random ( ) % NFILES ;
2002-03-04 03:35:28 +03:00
recorded [ n ] . start = lock_base + ( ( unsigned ) random ( ) % ( lock_range - 1 ) ) ;
2002-03-05 22:51:37 +03:00
recorded [ n ] . len = min_length +
2002-03-04 03:35:28 +03:00
random ( ) % ( lock_range - ( recorded [ n ] . start - lock_base ) ) ;
2000-05-04 10:30:17 +04:00
recorded [ n ] . start * = RANGE_MULTIPLE ;
recorded [ n ] . len * = RANGE_MULTIPLE ;
2001-08-27 12:19:43 +04:00
r1 = random ( ) % 100 ;
r2 = random ( ) % 100 ;
if ( r1 < READ_PCT ) {
recorded [ n ] . lock_type = READ_LOCK ;
} else {
recorded [ n ] . lock_type = WRITE_LOCK ;
}
if ( r2 < LOCK_PCT ) {
recorded [ n ] . lock_op = OP_LOCK ;
} else if ( r2 < UNLOCK_PCT ) {
recorded [ n ] . lock_op = OP_UNLOCK ;
} else {
recorded [ n ] . lock_op = OP_REOPEN ;
}
2000-05-04 08:14:23 +04:00
recorded [ n ] . needed = True ;
2002-03-11 02:17:47 +03:00
if ( ! zero_zero & & recorded [ n ] . start = = 0 & & recorded [ n ] . len = = 0 ) {
2001-08-27 12:19:43 +04:00
recorded [ n ] . len = 1 ;
}
2001-07-03 08:29:50 +04:00
# if PRESETS
2000-05-04 08:14:23 +04:00
}
2001-07-03 08:29:50 +04:00
# endif
2000-05-04 08:14:23 +04:00
}
2000-06-13 19:47:23 +04:00
reconnect ( cli , fnum , share ) ;
2000-05-04 10:30:17 +04:00
open_files ( cli , fnum ) ;
n = retest ( cli , fnum , numops ) ;
2000-05-04 08:14:23 +04:00
2000-05-04 10:30:17 +04:00
if ( n = = numops | | ! analyze ) return ;
2000-05-04 08:14:23 +04:00
n + + ;
2001-08-24 23:34:11 +04:00
skip = n / 2 ;
2000-05-04 08:14:23 +04:00
while ( 1 ) {
n1 = n ;
2000-05-04 10:30:17 +04:00
close_files ( cli , fnum ) ;
2000-06-13 19:47:23 +04:00
reconnect ( cli , fnum , share ) ;
2000-05-04 08:14:23 +04:00
open_files ( cli , fnum ) ;
2001-08-27 12:19:43 +04:00
for ( i = 0 ; i < n - skip ; i + = skip ) {
2001-08-24 23:34:11 +04:00
int m , j ;
2001-08-27 12:19:43 +04:00
printf ( " excluding %d-%d \n " , i , i + skip - 1 ) ;
2001-08-24 23:34:11 +04:00
for ( j = i ; j < i + skip ; j + + ) {
recorded [ j ] . needed = False ;
}
2000-05-04 10:30:17 +04:00
close_files ( cli , fnum ) ;
open_files ( cli , fnum ) ;
2000-05-04 08:14:23 +04:00
m = retest ( cli , fnum , n ) ;
if ( m = = n ) {
2001-08-24 23:34:11 +04:00
for ( j = i ; j < i + skip ; j + + ) {
recorded [ j ] . needed = True ;
}
2000-05-04 08:14:23 +04:00
} else {
2001-08-24 23:34:11 +04:00
if ( i + ( skip - 1 ) < m ) {
memmove ( & recorded [ i ] , & recorded [ i + skip ] ,
( m - ( i + skip - 1 ) ) * sizeof ( recorded [ 0 ] ) ) ;
2000-05-04 08:14:23 +04:00
}
2001-08-24 23:34:11 +04:00
n = m - ( skip - 1 ) ;
2000-05-04 08:14:23 +04:00
i - - ;
}
}
2001-08-24 23:34:11 +04:00
if ( skip > 1 ) {
skip = skip / 2 ;
printf ( " skip=%d \n " , skip ) ;
continue ;
}
2000-05-04 08:14:23 +04:00
if ( n1 = = n ) break ;
}
2000-05-04 10:30:17 +04:00
close_files ( cli , fnum ) ;
2000-06-13 19:47:23 +04:00
reconnect ( cli , fnum , share ) ;
2000-05-04 10:30:17 +04:00
open_files ( cli , fnum ) ;
showall = True ;
n1 = retest ( cli , fnum , n ) ;
if ( n1 ! = n - 1 ) {
2000-05-06 05:36:59 +04:00
printf ( " ERROR - inconsistent result (%u %u) \n " , n1 , n ) ;
2000-05-04 10:30:17 +04:00
}
close_files ( cli , fnum ) ;
2000-05-04 08:14:23 +04:00
for ( i = 0 ; i < n ; i + + ) {
2006-03-03 02:23:05 +03:00
printf ( " {%s, %s, conn = %u, file = %u, start = %.0f, len = %.0f, %u}, \n " ,
lock_op_name ( recorded [ i ] . lock_op ) ,
lock_op_type ( recorded [ i ] . lock_type ) ,
2000-05-04 08:14:23 +04:00
recorded [ i ] . conn ,
recorded [ i ] . f ,
2000-09-29 08:43:07 +04:00
( double ) recorded [ i ] . start ,
( double ) recorded [ i ] . len ,
2000-05-04 08:14:23 +04:00
recorded [ i ] . needed ) ;
}
}
2000-05-03 17:54:28 +04:00
static void usage ( void )
{
printf (
" Usage: \n \
locktest / / server1 / share1 / / server2 / share2 [ options . . ] \ n \
options : \ n \
2002-03-11 02:17:47 +03:00
- U user % % pass ( may be specified twice ) \ n \
2002-03-04 03:24:24 +03:00
- k use kerberos \ n \
2000-05-03 17:54:28 +04:00
- s seed \ n \
2000-05-03 18:49:15 +04:00
- o numops \ n \
2000-05-24 11:15:54 +04:00
- u hide unlock fails \ n \
2000-05-03 18:49:15 +04:00
- a ( show all ops ) \ n \
2001-11-20 11:48:46 +03:00
- A analyse for minimal ops \ n \
2000-06-05 13:40:58 +04:00
- O use oplocks \ n \
2002-03-11 02:17:47 +03:00
- E enable exact error code checking \ n \
- Z enable the zero / zero lock \ n \
2002-03-04 03:35:28 +03:00
- R range set lock range \ n \
- B base set lock base \ n \
2002-03-05 22:51:37 +03:00
- M min set min lock length \ n \
2000-05-03 17:54:28 +04:00
" );
}
/****************************************************************************
main program
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int main ( int argc , char * argv [ ] )
{
2000-06-13 19:47:23 +04:00
char * share [ NSERVERS ] ;
2000-05-03 17:54:28 +04:00
int opt ;
char * p ;
2000-06-13 19:47:23 +04:00
int seed , server ;
2000-05-03 17:54:28 +04:00
setlinebuf ( stdout ) ;
2006-03-03 00:42:39 +03:00
load_case_tables ( ) ;
2000-09-29 08:43:07 +04:00
if ( argc < 3 | | argv [ 1 ] [ 0 ] = = ' - ' ) {
2000-05-03 17:54:28 +04:00
usage ( ) ;
exit ( 1 ) ;
}
2010-10-29 07:19:32 +04:00
setup_logging ( argv [ 0 ] , DEBUG_STDOUT ) ;
2000-05-03 17:54:28 +04:00
2000-06-13 19:47:23 +04:00
for ( server = 0 ; server < NSERVERS ; server + + ) {
share [ server ] = argv [ 1 + server ] ;
all_string_sub ( share [ server ] , " / " , " \\ " , 0 ) ;
}
argc - = NSERVERS ;
argv + = NSERVERS ;
2000-05-03 17:54:28 +04:00
2011-07-27 18:55:25 +04:00
lp_load_global ( get_dyn_CONFIGFILE ( ) ) ;
2000-05-03 17:54:28 +04:00
load_interfaces ( ) ;
if ( getenv ( " USER " ) ) {
2003-01-14 11:53:59 +03:00
fstrcpy ( username [ 0 ] , getenv ( " USER " ) ) ;
fstrcpy ( username [ 1 ] , getenv ( " USER " ) ) ;
2000-05-03 17:54:28 +04:00
}
seed = time ( NULL ) ;
2002-03-11 02:17:47 +03:00
while ( ( opt = getopt ( argc , argv , " U:s:ho:aAW:OkR:B:M:EZ " ) ) ! = EOF ) {
2000-05-03 17:54:28 +04:00
switch ( opt ) {
2002-03-04 03:24:24 +03:00
case ' k ' :
# ifdef HAVE_KRB5
use_kerberos = True ;
# else
d_printf ( " No kerberos support compiled in \n " ) ;
exit ( 1 ) ;
# endif
break ;
2000-05-03 17:54:28 +04:00
case ' U ' :
2003-02-24 06:06:45 +03:00
got_user = 1 ;
2002-03-11 02:17:47 +03:00
if ( got_pass = = 2 ) {
d_printf ( " Max of 2 usernames \n " ) ;
exit ( 1 ) ;
}
2003-01-14 11:53:59 +03:00
fstrcpy ( username [ got_pass ] , optarg ) ;
2002-03-11 02:17:47 +03:00
p = strchr_m ( username [ got_pass ] , ' % ' ) ;
2000-05-03 17:54:28 +04:00
if ( p ) {
* p = 0 ;
2003-01-14 11:53:59 +03:00
fstrcpy ( password [ got_pass ] , p + 1 ) ;
2002-03-11 02:17:47 +03:00
got_pass + + ;
2000-05-03 17:54:28 +04:00
}
break ;
2002-03-04 03:35:28 +03:00
case ' R ' :
lock_range = strtol ( optarg , NULL , 0 ) ;
break ;
case ' B ' :
lock_base = strtol ( optarg , NULL , 0 ) ;
break ;
2002-03-05 22:51:37 +03:00
case ' M ' :
min_length = strtol ( optarg , NULL , 0 ) ;
break ;
2000-05-03 17:54:28 +04:00
case ' s ' :
seed = atoi ( optarg ) ;
break ;
2000-05-24 11:15:54 +04:00
case ' u ' :
hide_unlock_fails = True ;
break ;
2000-05-03 17:54:28 +04:00
case ' o ' :
numops = atoi ( optarg ) ;
break ;
2000-06-05 13:40:58 +04:00
case ' O ' :
use_oplocks = True ;
break ;
2000-05-03 18:49:15 +04:00
case ' a ' :
showall = True ;
break ;
2000-05-04 08:14:23 +04:00
case ' A ' :
analyze = True ;
break ;
2002-03-11 02:17:47 +03:00
case ' Z ' :
zero_zero = True ;
break ;
case ' E ' :
exact_error_codes = True ;
break ;
2000-05-03 17:54:28 +04:00
case ' h ' :
usage ( ) ;
exit ( 1 ) ;
default :
printf ( " Unknown option %c (%d) \n " , ( char ) opt , opt ) ;
exit ( 1 ) ;
}
}
2003-02-24 06:06:45 +03:00
if ( use_kerberos & & ! got_user ) got_pass = True ;
2000-05-03 17:54:28 +04:00
argc - = optind ;
argv + = optind ;
2000-05-06 05:36:59 +04:00
DEBUG ( 0 , ( " seed=%u \n " , seed ) ) ;
2000-05-03 17:54:28 +04:00
srandom ( seed ) ;
2000-06-13 19:47:23 +04:00
test_locks ( share ) ;
2000-05-03 17:54:28 +04:00
return ( 0 ) ;
}