#include "includes.h"
#ifdef WITH_PROFILE
#define IPC_PERMS ((S_IRUSR | S_IWUSR) | S_IRGRP | S_IROTH)
#endif
#ifdef WITH_PROFILE
static int shm_id;
static BOOL read_only;
#if defined(HAVE_CLOCK_GETTIME)
clockid_t __profile_clock;
BOOL have_profiling_clock = False;
#endif
#if defined(WITH_KDEBUG_TRACE)
unsigned int kdebug_enable;
#endif
#endif
struct profile_header *profile_h;
struct profile_stats *profile_p;
BOOL do_profile_flag = False;
BOOL do_profile_times = False;
void set_profile_level(int level, struct process_id src)
{
#ifdef WITH_PROFILE
switch (level) {
case 0:
do_profile_flag = False;
do_profile_times = False;
kdebug_enable = False;
DEBUG(1,("INFO: Profiling turned OFF from pid %d\n",
(int)procid_to_pid(&src)));
break;
case 1:
do_profile_flag = True;
kdebug_enable = True;
do_profile_times = False;
DEBUG(1,("INFO: Profiling counts turned ON from pid %d\n",
(int)procid_to_pid(&src)));
break;
case 2:
#if defined(HAVE_CLOCK_GETTIME)
if (!have_profiling_clock) {
do_profile_flag = True;
do_profile_times = False;
DEBUG(1,("INFO: Profiling counts turned ON from "
"pid %d\n", (int)procid_to_pid(&src)));
DEBUGADD(1,("INFO: Profiling times disabled "
"due to lack of a suitable clock\n"));
break;
}
#endif
kdebug_enable = True;
do_profile_flag = True;
do_profile_times = True;
DEBUG(1,("INFO: Full profiling turned ON from pid %d\n",
(int)procid_to_pid(&src)));
break;
case 3:
memset((char *)profile_p, 0, sizeof(*profile_p));
DEBUG(1,("INFO: Profiling values cleared from pid %d\n",
(int)procid_to_pid(&src)));
break;
}
#else
DEBUG(1,("INFO: Profiling support unavailable in this build.\n"));
#endif
}
void profile_message(int msg_type, struct process_id src, void *buf, size_t len, void *private_data)
{
int level;
memcpy(&level, buf, sizeof(int));
set_profile_level(level, src);
}
void reqprofile_message(int msg_type, struct process_id src,
void *buf, size_t len, void *private_data)
{
int level;
#ifdef WITH_PROFILE
level = 1 + (do_profile_flag?2:0) + (do_profile_times?4:0);
#else
level = 0;
#endif
DEBUG(1,("INFO: Received REQ_PROFILELEVEL message from PID %u\n",
(unsigned int)procid_to_pid(&src)));
message_send_pid(src, MSG_PROFILELEVEL, &level, sizeof(int), True);
}
#ifdef WITH_PROFILE
#ifdef HAVE_CLOCK_GETTIME
static void init_clock_gettime(void)
{
struct timespec ts;
have_profiling_clock = False;
#ifdef HAVE_CLOCK_PROCESS_CPUTIME_ID
if (!this_is_smp()) {
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == 0) {
DEBUG(10, ("Using CLOCK_PROCESS_CPUTIME_ID "
"for profile_clock\n"));
__profile_clock = CLOCK_PROCESS_CPUTIME_ID;
have_profiling_clock = True;
}
}
#endif
#ifdef HAVE_CLOCK_MONOTONIC
if (!have_profiling_clock &&
clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
DEBUG(10, ("Using CLOCK_MONOTONIC for profile_clock\n"));
__profile_clock = CLOCK_MONOTONIC;
have_profiling_clock = True;
}
#endif
#ifdef HAVE_CLOCK_REALTIME
if (!have_profiling_clock &&
clock_gettime(CLOCK_REALTIME, &ts) == 0) {
__profile_clock = CLOCK_REALTIME;
have_profiling_clock = True;
SMB_WARN(__profile_clock != CLOCK_REALTIME,
("forced to use a slow profiling clock"));
}
#endif
SMB_WARN(have_profiling_clock == True,
("could not find a working clock for profiling"));
return;
}
#endif
BOOL profile_setup(BOOL rdonly)
{
struct shmid_ds shm_ds;
read_only = rdonly;
#ifdef HAVE_CLOCK_GETTIME
init_clock_gettime();
#endif
again:
shm_id = shmget(PROF_SHMEM_KEY, 0, 0);
if (shm_id == -1) {
if (read_only) return False;
shm_id = shmget(PROF_SHMEM_KEY, sizeof(*profile_h),
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;
}
profile_h = (struct profile_header *)shmat(shm_id, 0,
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;
}
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;
}
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, uid %u, gid %u)\n",
shm_ds.shm_perm.cuid,
shm_ds.shm_perm.cgid));
return False;
}
if (shm_ds.shm_segsz != sizeof(*profile_h)) {
DEBUG(0,("WARNING: profile size is %d (expected %lu). Deleting\n",
(int)shm_ds.shm_segsz, sizeof(*profile_h)));
if (shmctl(shm_id, IPC_RMID, &shm_ds) == 0) {
goto again;
} else {
return False;
}
}
if (!read_only && (shm_ds.shm_nattch == 1)) {
memset((char *)profile_h, 0, sizeof(*profile_h));
profile_h->prof_shm_magic = PROF_SHM_MAGIC;
profile_h->prof_shm_version = PROF_SHM_VERSION;
DEBUG(3,("Initialised profile area\n"));
}
profile_p = &profile_h->stats;
message_register(MSG_PROFILE, profile_message, NULL);
message_register(MSG_REQ_PROFILELEVEL, reqprofile_message, NULL);
return True;
}
const char * profile_value_name(enum profile_stats_values val)
{
static const char * valnames[PR_VALUE_MAX + 1] =
{
"smbd_idle",
"syscall_opendir",
"syscall_readdir",
"syscall_seekdir",
"syscall_telldir",
"syscall_rewinddir",
"syscall_mkdir",
"syscall_rmdir",
"syscall_closedir",
"syscall_open",
"syscall_close",
"syscall_read",
"syscall_pread",
"syscall_write",
"syscall_pwrite",
"syscall_lseek",
"syscall_sendfile",
"syscall_rename",
"syscall_fsync",
"syscall_stat",
"syscall_fstat",
"syscall_lstat",
"syscall_unlink",
"syscall_chmod",
"syscall_fchmod",
"syscall_chown",
"syscall_fchown",
"syscall_chdir",
"syscall_getwd",
"syscall_ntimes",
"syscall_ftruncate",
"syscall_fcntl_lock",
"syscall_kernel_flock",
"syscall_linux_setlease",
"syscall_fcntl_getlock",
"syscall_readlink",
"syscall_symlink",
"syscall_link",
"syscall_mknod",
"syscall_realpath",
"syscall_get_quota",
"syscall_set_quota",
"SMBmkdir",
"SMBrmdir",
"SMBopen",
"SMBcreate",
"SMBclose",
"SMBflush",
"SMBunlink",
"SMBmv",
"SMBgetatr",
"SMBsetatr",
"SMBread",
"SMBwrite",
"SMBlock",
"SMBunlock",
"SMBctemp",
"SMBmknew",
"SMBcheckpath",
"SMBexit",
"SMBlseek",
"SMBlockread",
"SMBwriteunlock",
"SMBreadbraw",
"SMBreadBmpx",
"SMBreadBs",
"SMBwritebraw",
"SMBwriteBmpx",
"SMBwriteBs",
"SMBwritec",
"SMBsetattrE",
"SMBgetattrE",
"SMBlockingX",
"SMBtrans",
"SMBtranss",
"SMBioctl",
"SMBioctls",
"SMBcopy",
"SMBmove",
"SMBecho",
"SMBwriteclose",
"SMBopenX",
"SMBreadX",
"SMBwriteX",
"SMBtrans2",
"SMBtranss2",
"SMBfindclose",
"SMBfindnclose",
"SMBtcon",
"SMBtdis",
"SMBnegprot",
"SMBsesssetupX",
"SMBulogoffX",
"SMBtconX",
"SMBdskattr",
"SMBsearch",
"SMBffirst",
"SMBfunique",
"SMBfclose",
"SMBnttrans",
"SMBnttranss",
"SMBntcreateX",
"SMBntcancel",
"SMBntrename",
"SMBsplopen",
"SMBsplwr",
"SMBsplclose",
"SMBsplretq",
"SMBsends",
"SMBsendb",
"SMBfwdname",
"SMBcancelf",
"SMBgetmac",
"SMBsendstrt",
"SMBsendend",
"SMBsendtxt",
"SMBinvalid",
"pathworks_setdir",
"Trans2_open",
"Trans2_findfirst",
"Trans2_findnext",
"Trans2_qfsinfo",
"Trans2_setfsinfo",
"Trans2_qpathinfo",
"Trans2_setpathinfo",
"Trans2_qfileinfo",
"Trans2_setfileinfo",
"Trans2_fsctl",
"Trans2_ioctl",
"Trans2_findnotifyfirst",
"Trans2_findnotifynext",
"Trans2_mkdir",
"Trans2_session_setup",
"Trans2_get_dfs_referral",
"Trans2_report_dfs_inconsistancy",
"NT_transact_create",
"NT_transact_ioctl",
"NT_transact_set_security_desc",
"NT_transact_notify_change",
"NT_transact_rename",
"NT_transact_query_security_desc",
"NT_transact_get_user_quota",
"NT_transact_set_user_quota",
"get_nt_acl",
"fget_nt_acl",
"set_nt_acl",
"fset_nt_acl",
"chmod_acl",
"fchmod_acl",
"name_release",
"name_refresh",
"name_registration",
"node_status",
"name_query",
"host_announce",
"workgroup_announce",
"local_master_announce",
"master_browser_announce",
"lm_host_announce",
"get_backup_list",
"reset_browser",
"announce_request",
"lm_announce_request",
"domain_logon",
"sync_browse_lists",
"run_elections",
"election",
""
};
SMB_ASSERT(val >= 0);
SMB_ASSERT(val < PR_VALUE_MAX);
return valnames[val];
}
#endif
#ifdef WITH_DARWIN_STATS
# ifndef IPC_PERMS
#define IPC_PERMS ((SHM_R | SHM_W) | (SHM_R>>3) | (SHM_R>>6))
#endif
struct service_header *service_h;
struct service_stats *service_c;
static int service_stat_shm_id;
static BOOL stat_read_only;
BOOL service_stats_setup(BOOL rdonly)
{
int size = 0;
int count = 0;
struct shmid_ds shm_ds;
stat_read_only = rdonly;
again:
count = lp_numservices();
size = (sizeof(service_stats) * count) + sizeof(int);
service_stat_shm_id = shmget(SERV_STAT_SHMEM_KEY, 0, 0);
if (service_stat_shm_id == -1) {
if (stat_read_only)
return False;
service_stat_shm_id = shmget(SERV_STAT_SHMEM_KEY,
size,
IPC_CREAT | IPC_EXCL | IPC_PERMS);
if (service_stat_shm_id == -1) {
DEBUG(0,("Can't create or use IPC area. Error was %s\n",
strerror(errno)));
return False;
}
}
service_h = (service_header *)shmat(service_stat_shm_id, 0,
stat_read_only?SHM_RDONLY:0);
if ((long)service_h == -1) {
DEBUG(0,("Can't attach to IPC area. Error was %s\n",
strerror(errno)));
return False;
}
if (shmctl(service_stat_shm_id, IPC_STAT, &shm_ds) != 0) {
DEBUG(0,("ERROR shmctl : can't IPC_STAT. Error was %s\n",
strerror(errno)));
return False;
}
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"));
return False;
}
if (shm_ds.shm_segsz < size) {
DEBUG(0,("WARNING: service_stat struct size is %d (expected %d). Deleting\n",
(int)shm_ds.shm_segsz, size));
if (shmctl(service_stat_shm_id, IPC_RMID, &shm_ds) == 0)
goto again;
else
return False;
}
if (!stat_read_only && (shm_ds.shm_nattch == 1)) {
memset((char *)service_h, 0, size);
service_h->count = count;
DEBUG(3,("Initialised service stats area\n"));
}
service_c = &service_h->service_detail[0];
return True;
}
#endif