1999-04-01 09:35:22 +04:00
/*
Unix SMB / Netbios implementation .
Version 1.9 .
store smbd profiling information in shared memory
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
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"
# define IPC_PERMS ((SHM_R | SHM_W) | (SHM_R>>3) | (SHM_R>>6))
static int shm_id ;
static BOOL read_only ;
2000-10-11 09:31:39 +04:00
struct profile_header * profile_h ;
struct profile_stats * profile_p ;
1999-04-01 09:35:22 +04:00
2000-10-06 22:13:52 +04:00
BOOL do_profile_flag = False ;
2000-10-07 03:01:47 +04:00
BOOL do_profile_times = False ;
2000-10-06 22:13:52 +04:00
struct timeval profile_starttime ;
struct timeval profile_endtime ;
2000-10-11 09:31:39 +04:00
struct timeval profile_starttime_nested ;
struct timeval profile_endtime_nested ;
2000-10-06 22:13:52 +04:00
2000-10-07 03:01:47 +04:00
/****************************************************************************
receive a set profile level message
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void profile_message ( int msg_type , pid_t src , void * buf , size_t len )
{
int level ;
memcpy ( & level , buf , sizeof ( int ) ) ;
switch ( level ) {
2000-10-11 09:31:39 +04:00
case 0 : /* turn off profiling */
2000-10-07 03:01:47 +04:00
do_profile_flag = False ;
do_profile_times = False ;
2000-11-11 01:07:57 +03:00
DEBUG ( 1 , ( " INFO: Profiling turned OFF from pid %d \n " , ( int ) src ) ) ;
2000-10-07 03:01:47 +04:00
break ;
2000-10-11 09:31:39 +04:00
case 1 : /* turn on counter profiling only */
2000-10-07 03:01:47 +04:00
do_profile_flag = True ;
do_profile_times = False ;
2000-11-11 01:07:57 +03:00
DEBUG ( 1 , ( " INFO: Profiling counts turned ON from pid %d \n " , ( int ) src ) ) ;
2000-10-07 03:01:47 +04:00
break ;
2000-10-11 09:31:39 +04:00
case 2 : /* turn on complete profiling */
2000-10-07 03:01:47 +04:00
do_profile_flag = True ;
do_profile_times = True ;
2000-11-11 01:07:57 +03:00
DEBUG ( 1 , ( " INFO: Full profiling turned ON from pid %d \n " , ( int ) src ) ) ;
2000-10-07 03:01:47 +04:00
break ;
2000-10-11 09:31:39 +04:00
case 3 : /* reset profile values */
memset ( ( char * ) profile_p , 0 , sizeof ( * profile_p ) ) ;
2000-11-11 01:07:57 +03:00
DEBUG ( 1 , ( " INFO: Profiling values cleared from pid %d \n " , ( int ) src ) ) ;
2000-10-11 09:31:39 +04:00
break ;
2000-10-07 03:01:47 +04:00
}
}
2000-11-11 03:33:33 +03:00
/****************************************************************************
receive a request profile level message
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void reqprofile_message ( int msg_type , pid_t src , void * buf , size_t len )
{
int level ;
# ifdef WITH_PROFILE
level = 1 + ( do_profile_flag ? 2 : 0 ) + ( do_profile_times ? 4 : 0 ) ;
# else
level = 0 ;
# endif
2001-04-28 02:02:23 +04:00
DEBUG ( 1 , ( " INFO: Received REQ_PROFILELEVEL message from PID %u \n " , ( unsigned int ) src ) ) ;
2000-11-17 00:38:24 +03:00
message_send_pid ( src , MSG_PROFILELEVEL , & level , sizeof ( int ) , True ) ;
2000-11-11 03:33:33 +03:00
}
1999-04-01 09:35:22 +04:00
/*******************************************************************
open the profiling shared memory area
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL profile_setup ( BOOL rdonly )
{
struct shmid_ds shm_ds ;
read_only = rdonly ;
again :
/* try to use an existing key */
1999-12-13 16:27:58 +03:00
shm_id = shmget ( PROF_SHMEM_KEY , 0 , 0 ) ;
1999-04-01 09:35:22 +04:00
/* if that failed then create one. There is a race condition here
if we are running from inetd . Bad luck . */
if ( shm_id = = - 1 ) {
if ( read_only ) return False ;
2000-10-11 09:31:39 +04:00
shm_id = shmget ( PROF_SHMEM_KEY , sizeof ( * profile_h ) ,
1999-04-01 09:35:22 +04:00
IPC_CREAT | IPC_EXCL | IPC_PERMS ) ;
}
if ( shm_id = = - 1 ) {
DEBUG ( 0 , ( " Can't create or use IPC area. Error was %s \n " ,
strerror ( errno ) ) ) ;
return False ;
}
2000-10-11 09:31:39 +04:00
profile_h = ( struct profile_header * ) shmat ( shm_id , 0 ,
1999-04-01 09:35:22 +04:00
read_only ? SHM_RDONLY : 0 ) ;
if ( ( long ) profile_p = = - 1 ) {
DEBUG ( 0 , ( " Can't attach to IPC area. Error was %s \n " ,
strerror ( errno ) ) ) ;
return False ;
}
/* find out who created this memory area */
if ( shmctl ( shm_id , IPC_STAT , & shm_ds ) ! = 0 ) {
DEBUG ( 0 , ( " ERROR shmctl : can't IPC_STAT. Error was %s \n " ,
strerror ( errno ) ) ) ;
return False ;
}
2001-09-15 06:10:22 +04:00
if ( shm_ds . shm_perm . cuid ! = sec_initial_uid ( ) | | shm_ds . shm_perm . cgid ! = sec_initial_gid ( ) ) {
DEBUG ( 0 , ( " ERROR: we did not create the shmem (owned by another user) \n " ) ) ;
1999-04-01 09:35:22 +04:00
return False ;
}
2000-10-11 09:31:39 +04:00
if ( shm_ds . shm_segsz ! = sizeof ( * profile_h ) ) {
1999-04-01 09:35:22 +04:00
DEBUG ( 0 , ( " WARNING: profile size is %d (expected %d). Deleting \n " ,
2000-10-11 09:31:39 +04:00
( int ) shm_ds . shm_segsz , sizeof ( * profile_h ) ) ) ;
1999-04-01 09:35:22 +04:00
if ( shmctl ( shm_id , IPC_RMID , & shm_ds ) = = 0 ) {
goto again ;
} else {
return False ;
}
}
if ( ! read_only & & ( shm_ds . shm_nattch = = 1 ) ) {
2000-10-11 09:31:39 +04:00
memset ( ( char * ) profile_h , 0 , sizeof ( * profile_h ) ) ;
profile_h - > prof_shm_magic = PROF_SHM_MAGIC ;
profile_h - > prof_shm_version = PROF_SHM_VERSION ;
1999-04-01 09:35:22 +04:00
DEBUG ( 3 , ( " Initialised profile area \n " ) ) ;
}
2000-10-11 09:31:39 +04:00
profile_p = & profile_h - > stats ;
2000-10-07 03:01:47 +04:00
message_register ( MSG_PROFILE , profile_message ) ;
2000-11-11 03:33:33 +03:00
message_register ( MSG_REQ_PROFILELEVEL , reqprofile_message ) ;
1999-04-01 09:35:22 +04:00
return True ;
}