2000-09-13 11:07:17 +04:00
/*
Unix SMB / Netbios implementation .
Version 3.0
program to send control messages to Samba processes
Copyright ( C ) Andrew Tridgell 1994 - 1998
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
the Free Software Foundation ; either version 2 of the License , or
( 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
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
static struct {
char * name ;
int value ;
} msg_types [ ] = {
{ " debug " , MSG_DEBUG } ,
{ " force-election " , MSG_FORCE_ELECTION } ,
{ " ping " , MSG_PING } ,
2000-10-07 03:01:47 +04:00
{ " profile " , MSG_PROFILE } ,
2000-11-11 03:33:33 +03:00
{ " profilelevel " , MSG_REQ_PROFILELEVEL } ,
2000-10-07 03:01:47 +04:00
{ " debuglevel " , MSG_REQ_DEBUGLEVEL } ,
2000-11-11 01:07:57 +03:00
{ " printer-notify " , MSG_PRINTER_NOTIFY } ,
2000-09-13 11:07:17 +04:00
{ NULL , - 1 }
} ;
2000-10-12 04:29:01 +04:00
time_t timeout_start ;
# define MAX_WAIT 10
2000-09-30 00:08:00 +04:00
static void usage ( BOOL doexit )
2000-09-13 11:07:17 +04:00
{
int i ;
2000-09-30 00:08:00 +04:00
if ( doexit ) {
printf ( " Usage: smbcontrol -i \n " ) ;
printf ( " smbcontrol <destination> <message-type> <parameters> \n \n " ) ;
} else {
printf ( " <destination> <message-type> <parameters> \n \n " ) ;
}
2000-09-13 11:07:17 +04:00
printf ( " \t <destination> is one of \" nmbd \" , \" smbd \" or a process ID \n " ) ;
printf ( " \t <message-type> is one of: " ) ;
2000-10-07 03:01:47 +04:00
for ( i = 0 ; msg_types [ i ] . name ; i + + )
printf ( " %s%s " , i ? " , " : " " , msg_types [ i ] . name ) ;
2000-09-13 11:07:17 +04:00
printf ( " \n " ) ;
2000-09-30 00:08:00 +04:00
if ( doexit ) exit ( 1 ) ;
2000-09-13 11:07:17 +04:00
}
static int pong_count ;
2000-10-07 03:01:47 +04:00
static BOOL got_level ;
static BOOL pong_registered = False ;
static BOOL debuglevel_registered = False ;
2000-11-11 03:33:33 +03:00
static BOOL profilelevel_registered = False ;
2000-10-07 03:01:47 +04:00
2000-09-13 11:07:17 +04:00
/****************************************************************************
a useful function for testing the message system
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void pong_function ( int msg_type , pid_t src , void * buf , size_t len )
{
pong_count + + ;
2001-04-28 02:42:10 +04:00
printf ( " PONG from PID %u \n " , ( unsigned int ) src ) ;
2000-10-07 03:01:47 +04:00
}
/****************************************************************************
Prints out the current Debug level returned by MSG_DEBUGLEVEL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void debuglevel_function ( int msg_type , pid_t src , void * buf , size_t len )
{
2001-02-12 19:18:02 +03:00
int i ;
int debuglevel_class [ DBGC_LAST ] ;
memcpy ( debuglevel_class , buf , len ) ;
2001-04-28 02:42:10 +04:00
printf ( " Current debug level of PID %u is %d " , ( unsigned int ) src , debuglevel_class [ 0 ] ) ;
2001-02-12 19:18:02 +03:00
for ( i = 1 ; i < DBGC_LAST ; i + + )
if ( debuglevel_class [ i ] )
printf ( " %s:%d " , debug_classname_from_index ( i ) , debuglevel_class [ i ] ) ;
printf ( " \n " ) ;
2000-10-07 03:01:47 +04:00
got_level = True ;
2000-09-13 11:07:17 +04:00
}
2000-11-11 03:33:33 +03:00
/****************************************************************************
Prints out the current Profile level returned by MSG_PROFILELEVEL
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void profilelevel_function ( int msg_type , pid_t src , void * buf , size_t len )
{
int level ;
2001-04-13 23:12:06 +04:00
char * s = NULL ;
2000-11-11 03:33:33 +03:00
memcpy ( & level , buf , sizeof ( int ) ) ;
if ( level ) {
switch ( level ) {
case 1 :
s = " off " ;
break ;
case 3 :
s = " count only " ;
break ;
case 7 :
s = " count and time " ;
break ;
}
2001-04-28 02:42:10 +04:00
printf ( " Profiling %s on PID %u \n " , s , ( unsigned int ) src ) ;
2000-11-11 03:33:33 +03:00
} else {
2001-04-28 02:42:10 +04:00
printf ( " Profiling not available on PID %u \n " , ( unsigned int ) src ) ;
2000-11-11 03:33:33 +03:00
}
got_level = True ;
}
2000-09-13 11:07:17 +04:00
/****************************************************************************
send a message to a named destination
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-11-17 00:38:24 +03:00
static BOOL send_message ( char * dest , int msg_type , void * buf , int len , BOOL duplicates )
2000-09-13 11:07:17 +04:00
{
pid_t pid ;
2000-12-15 04:02:11 +03:00
TDB_CONTEXT * the_tdb ;
the_tdb = tdb_open ( lock_path ( " connections.tdb " ) , 0 , 0 , O_RDONLY , 0 ) ;
if ( ! the_tdb ) {
fprintf ( stderr , " Failed to open connections database in send_message. \n " ) ;
return False ;
}
2000-09-13 11:07:17 +04:00
/* "smbd" is the only broadcast operation */
if ( strequal ( dest , " smbd " ) ) {
2000-12-15 04:02:11 +03:00
return message_send_all ( the_tdb , msg_type , buf , len , duplicates ) ;
2000-09-13 11:07:17 +04:00
} else if ( strequal ( dest , " nmbd " ) ) {
pid = pidfile_pid ( dest ) ;
if ( pid = = 0 ) {
fprintf ( stderr , " Can't find pid for nmbd \n " ) ;
return False ;
}
2000-11-17 04:20:03 +03:00
} else if ( strequal ( dest , " self " ) ) {
pid = getpid ( ) ;
2000-09-13 11:07:17 +04:00
} else {
pid = atoi ( dest ) ;
if ( pid = = 0 ) {
fprintf ( stderr , " Not a valid pid \n " ) ;
return False ;
}
}
2000-11-17 00:38:24 +03:00
return message_send_pid ( pid , msg_type , buf , len , duplicates ) ;
2000-09-13 11:07:17 +04:00
}
/****************************************************************************
evaluate a message type string
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int parse_type ( char * mtype )
{
int i ;
for ( i = 0 ; msg_types [ i ] . name ; i + + ) {
if ( strequal ( mtype , msg_types [ i ] . name ) ) return msg_types [ i ] . value ;
}
return - 1 ;
}
2000-09-30 00:08:00 +04:00
/****************************************************************************
do command
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-05-15 02:37:01 +04:00
static BOOL do_command ( char * dest , char * msg_name , char * * params )
2000-09-13 11:07:17 +04:00
{
int i , n , v ;
int mtype ;
2001-04-13 23:12:06 +04:00
BOOL retval = False ;
2001-02-12 19:18:02 +03:00
int debuglevel_class [ DBGC_LAST ] ;
2000-09-13 11:07:17 +04:00
2000-09-30 00:08:00 +04:00
mtype = parse_type ( msg_name ) ;
2000-09-13 11:07:17 +04:00
if ( mtype = = - 1 ) {
2000-09-30 00:08:00 +04:00
fprintf ( stderr , " Couldn't resolve message type: %s \n " , msg_name ) ;
return ( False ) ;
2000-09-13 11:07:17 +04:00
}
switch ( mtype ) {
case MSG_DEBUG :
2001-05-15 02:37:01 +04:00
if ( ! params | | ! params [ 0 ] ) {
2000-09-13 11:07:17 +04:00
fprintf ( stderr , " MSG_DEBUG needs a parameter \n " ) ;
2000-09-30 00:08:00 +04:00
return ( False ) ;
2000-09-13 11:07:17 +04:00
}
2001-02-12 19:18:02 +03:00
ZERO_ARRAY ( debuglevel_class ) ;
if ( ! debug_parse_params ( params , debuglevel_class ) ) {
fprintf ( stderr , " MSG_DEBUG error. Expected <class name>:level \n " ) ;
return ( False ) ;
} else
send_message ( dest , MSG_DEBUG , debuglevel_class , sizeof ( debuglevel_class ) , False ) ;
2000-09-13 11:07:17 +04:00
break ;
2000-10-07 03:01:47 +04:00
case MSG_PROFILE :
2001-02-12 19:18:02 +03:00
if ( ! params [ 0 ] ) {
2000-10-07 03:01:47 +04:00
fprintf ( stderr , " MSG_PROFILE needs a parameter \n " ) ;
return ( False ) ;
}
2001-02-12 19:18:02 +03:00
if ( strequal ( params [ 0 ] , " off " ) ) {
2000-10-07 03:01:47 +04:00
v = 0 ;
2001-02-12 19:18:02 +03:00
} else if ( strequal ( params [ 0 ] , " count " ) ) {
2000-10-07 03:01:47 +04:00
v = 1 ;
2001-02-12 19:18:02 +03:00
} else if ( strequal ( params [ 0 ] , " on " ) ) {
2000-10-11 09:31:39 +04:00
v = 2 ;
2001-02-12 19:18:02 +03:00
} else if ( strequal ( params [ 0 ] , " flush " ) ) {
2000-10-11 09:31:39 +04:00
v = 3 ;
2000-10-07 03:01:47 +04:00
} else {
fprintf ( stderr ,
2000-10-11 09:31:39 +04:00
" MSG_PROFILE parameter must be off, count, on, or flush \n " ) ;
2000-10-07 03:01:47 +04:00
return ( False ) ;
}
2000-11-17 00:38:24 +03:00
send_message ( dest , MSG_PROFILE , & v , sizeof ( int ) , False ) ;
2000-10-07 03:01:47 +04:00
break ;
2000-09-13 11:07:17 +04:00
case MSG_FORCE_ELECTION :
if ( ! strequal ( dest , " nmbd " ) ) {
fprintf ( stderr , " force-election can only be sent to nmbd \n " ) ;
2000-09-30 00:08:00 +04:00
return ( False ) ;
2000-09-13 11:07:17 +04:00
}
2000-11-17 00:38:24 +03:00
send_message ( dest , MSG_FORCE_ELECTION , NULL , 0 , False ) ;
2000-09-13 11:07:17 +04:00
break ;
2000-11-11 03:33:33 +03:00
case MSG_REQ_PROFILELEVEL :
if ( ! profilelevel_registered ) {
message_register ( MSG_PROFILELEVEL , profilelevel_function ) ;
profilelevel_registered = True ;
}
got_level = False ;
2000-11-17 00:38:24 +03:00
retval = send_message ( dest , MSG_REQ_PROFILELEVEL , NULL , 0 , True ) ;
2000-11-11 03:33:33 +03:00
if ( retval ) {
timeout_start = time ( NULL ) ;
while ( ! got_level ) {
message_dispatch ( ) ;
if ( ( time ( NULL ) - timeout_start ) > MAX_WAIT ) {
fprintf ( stderr , " profilelevel timeout \n " ) ;
break ;
}
}
}
break ;
2000-10-07 03:01:47 +04:00
case MSG_REQ_DEBUGLEVEL :
if ( ! debuglevel_registered ) {
message_register ( MSG_DEBUGLEVEL , debuglevel_function ) ;
debuglevel_registered = True ;
}
got_level = False ;
2000-11-17 00:38:24 +03:00
retval = send_message ( dest , MSG_REQ_DEBUGLEVEL , NULL , 0 , True ) ;
2000-10-12 04:29:01 +04:00
if ( retval ) {
timeout_start = time ( NULL ) ;
while ( ! got_level ) {
message_dispatch ( ) ;
if ( ( time ( NULL ) - timeout_start ) > MAX_WAIT ) {
fprintf ( stderr , " debuglevel timeout \n " ) ;
break ;
}
}
}
2000-10-07 03:01:47 +04:00
break ;
2000-11-11 01:07:57 +03:00
case MSG_PRINTER_NOTIFY :
if ( ! strequal ( dest , " smbd " ) ) {
fprintf ( stderr , " printer-notify can only be sent to smbd \n " ) ;
return ( False ) ;
}
2001-02-12 19:18:02 +03:00
if ( ! params [ 0 ] ) {
2000-11-11 01:07:57 +03:00
fprintf ( stderr , " printer-notify needs a printer name \n " ) ;
return ( False ) ;
}
2001-02-12 19:18:02 +03:00
retval = send_message ( dest , MSG_PRINTER_NOTIFY , params [ 0 ] ,
strlen ( params [ 0 ] ) + 1 , False ) ;
2000-11-11 01:07:57 +03:00
break ;
2000-09-13 11:07:17 +04:00
case MSG_PING :
2000-10-07 03:01:47 +04:00
if ( ! pong_registered ) {
message_register ( MSG_PONG , pong_function ) ;
pong_registered = True ;
}
2001-02-12 19:18:02 +03:00
if ( ! params [ 0 ] ) {
2000-09-30 00:08:00 +04:00
fprintf ( stderr , " MSG_PING needs a parameter \n " ) ;
return ( False ) ;
}
2001-02-12 19:18:02 +03:00
n = atoi ( params [ 0 ] ) ;
2000-10-07 03:01:47 +04:00
pong_count = 0 ;
2000-09-13 11:07:17 +04:00
for ( i = 0 ; i < n ; i + + ) {
2000-11-17 00:38:24 +03:00
retval = send_message ( dest , MSG_PING , NULL , 0 , True ) ;
2000-10-12 04:29:01 +04:00
if ( retval = = False ) break ;
}
if ( retval ) {
timeout_start = time ( NULL ) ;
while ( pong_count < n ) {
message_dispatch ( ) ;
if ( ( time ( NULL ) - timeout_start ) > MAX_WAIT ) {
fprintf ( stderr , " PING timeout \n " ) ;
break ;
}
}
2000-09-13 11:07:17 +04:00
}
break ;
}
2000-09-30 00:08:00 +04:00
return ( True ) ;
}
int main ( int argc , char * argv [ ] )
{
int opt ;
char temp [ 255 ] ;
extern int optind ;
pstring servicesf = CONFIGFILE ;
BOOL interactive = False ;
TimeInit ( ) ;
setup_logging ( argv [ 0 ] , True ) ;
charset_initialise ( ) ;
lp_load ( servicesf , False , False , False ) ;
2000-10-12 21:58:40 +04:00
if ( ! message_init ( ) ) exit ( 1 ) ;
2000-09-30 00:08:00 +04:00
if ( argc < 2 ) usage ( True ) ;
while ( ( opt = getopt ( argc , argv , " i " ) ) ! = EOF ) {
switch ( opt ) {
case ' i ' :
interactive = True ;
break ;
default :
printf ( " Unknown option %c (%d) \n " , ( char ) opt , opt ) ;
usage ( True ) ;
}
}
argc - = optind ;
argv = & argv [ optind ] ;
if ( ! interactive ) {
if ( argc < 2 ) usage ( True ) ;
2001-02-12 19:18:02 +03:00
return ( do_command ( argv [ 0 ] , argv [ 1 ] , argc > 2 ? & argv [ 2 ] : 0 ) ) ;
2000-09-30 00:08:00 +04:00
}
while ( True ) {
char * myargv [ 3 ] ;
int myargc ;
printf ( " smbcontrol> " ) ;
2000-10-10 09:05:35 +04:00
if ( ! fgets ( temp , sizeof ( temp ) - 1 , stdin ) ) break ;
2000-09-30 00:08:00 +04:00
myargc = 0 ;
while ( ( myargc < 3 ) & &
2000-10-10 09:05:35 +04:00
( myargv [ myargc ] = strtok ( myargc ? NULL : temp , " \t \n " ) ) ) {
2000-09-30 00:08:00 +04:00
myargc + + ;
}
if ( ! myargc ) break ;
2000-10-12 21:58:40 +04:00
if ( strequal ( myargv [ 0 ] , " q " ) ) break ;
2000-09-30 00:08:00 +04:00
if ( myargc < 2 )
usage ( False ) ;
2001-02-12 19:18:02 +03:00
else if ( ! do_command ( myargv [ 0 ] , myargv [ 1 ] , myargc > 2 ? & myargv [ 2 ] : 0 ) )
2000-09-30 00:08:00 +04:00
usage ( False ) ;
}
return ( 0 ) ;
2000-09-13 11:07:17 +04:00
}