1/* 2 Unix SMB/CIFS implementation. 3 store smbd profiling information in shared memory 4 Copyright (C) Andrew Tridgell 1999 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 20*/ 21 22#include "includes.h" 23 24#ifdef WITH_PROFILE 25#define IPC_PERMS ((S_IRUSR | S_IWUSR) | S_IRGRP | S_IROTH) 26#endif /* WITH_PROFILE */ 27 28#ifdef WITH_PROFILE 29static int shm_id; 30static BOOL read_only; 31#endif 32 33struct profile_header *profile_h; 34struct profile_stats *profile_p; 35 36BOOL do_profile_flag = False; 37BOOL do_profile_times = False; 38 39struct timeval profile_starttime; 40struct timeval profile_endtime; 41struct timeval profile_starttime_nested; 42struct timeval profile_endtime_nested; 43 44/**************************************************************************** 45receive a set profile level message 46****************************************************************************/ 47void profile_message(int msg_type, pid_t src, void *buf, size_t len) 48{ 49 int level; 50 51 memcpy(&level, buf, sizeof(int)); 52#ifdef WITH_PROFILE 53 switch (level) { 54 case 0: /* turn off profiling */ 55 do_profile_flag = False; 56 do_profile_times = False; 57 DEBUG(1,("INFO: Profiling turned OFF from pid %d\n", (int)src)); 58 break; 59 case 1: /* turn on counter profiling only */ 60 do_profile_flag = True; 61 do_profile_times = False; 62 DEBUG(1,("INFO: Profiling counts turned ON from pid %d\n", (int)src)); 63 break; 64 case 2: /* turn on complete profiling */ 65 do_profile_flag = True; 66 do_profile_times = True; 67 DEBUG(1,("INFO: Full profiling turned ON from pid %d\n", (int)src)); 68 break; 69 case 3: /* reset profile values */ 70 memset((char *)profile_p, 0, sizeof(*profile_p)); 71 DEBUG(1,("INFO: Profiling values cleared from pid %d\n", (int)src)); 72 break; 73 } 74#else /* WITH_PROFILE */ 75 DEBUG(1,("INFO: Profiling support unavailable in this build.\n")); 76#endif /* WITH_PROFILE */ 77} 78 79/**************************************************************************** 80receive a request profile level message 81****************************************************************************/ 82void reqprofile_message(int msg_type, pid_t src, void *buf, size_t len) 83{ 84 int level; 85 86#ifdef WITH_PROFILE 87 level = 1 + (do_profile_flag?2:0) + (do_profile_times?4:0); 88#else 89 level = 0; 90#endif 91 DEBUG(1,("INFO: Received REQ_PROFILELEVEL message from PID %u\n",(unsigned int)src)); 92 message_send_pid(src, MSG_PROFILELEVEL, &level, sizeof(int), True); 93} 94 95/******************************************************************* 96 open the profiling shared memory area 97 ******************************************************************/ 98#ifdef WITH_PROFILE 99BOOL profile_setup(BOOL rdonly) 100{ 101 struct shmid_ds shm_ds; 102 103 read_only = rdonly; 104 105 again: 106 /* try to use an existing key */ 107 shm_id = shmget(PROF_SHMEM_KEY, 0, 0); 108 109 /* if that failed then create one. There is a race condition here 110 if we are running from inetd. Bad luck. */ 111 if (shm_id == -1) { 112 if (read_only) return False; 113 shm_id = shmget(PROF_SHMEM_KEY, sizeof(*profile_h), 114 IPC_CREAT | IPC_EXCL | IPC_PERMS); 115 } 116 117 if (shm_id == -1) { 118 DEBUG(0,("Can't create or use IPC area. Error was %s\n", 119 strerror(errno))); 120 return False; 121 } 122 123 124 profile_h = (struct profile_header *)shmat(shm_id, 0, 125 read_only?SHM_RDONLY:0); 126 if ((long)profile_p == -1) { 127 DEBUG(0,("Can't attach to IPC area. Error was %s\n", 128 strerror(errno))); 129 return False; 130 } 131 132 /* find out who created this memory area */ 133 if (shmctl(shm_id, IPC_STAT, &shm_ds) != 0) { 134 DEBUG(0,("ERROR shmctl : can't IPC_STAT. Error was %s\n", 135 strerror(errno))); 136 return False; 137 } 138 139 if (shm_ds.shm_perm.cuid != sec_initial_uid() || shm_ds.shm_perm.cgid != sec_initial_gid()) { 140 DEBUG(0,("ERROR: we did not create the shmem (owned by another user)\n")); 141 return False; 142 } 143 144 if (shm_ds.shm_segsz != sizeof(*profile_h)) { 145 DEBUG(0,("WARNING: profile size is %d (expected %d). Deleting\n", 146 (int)shm_ds.shm_segsz, sizeof(*profile_h))); 147 if (shmctl(shm_id, IPC_RMID, &shm_ds) == 0) { 148 goto again; 149 } else { 150 return False; 151 } 152 } 153 154 if (!read_only && (shm_ds.shm_nattch == 1)) { 155 memset((char *)profile_h, 0, sizeof(*profile_h)); 156 profile_h->prof_shm_magic = PROF_SHM_MAGIC; 157 profile_h->prof_shm_version = PROF_SHM_VERSION; 158 DEBUG(3,("Initialised profile area\n")); 159 } 160 161 profile_p = &profile_h->stats; 162 message_register(MSG_PROFILE, profile_message); 163 message_register(MSG_REQ_PROFILELEVEL, reqprofile_message); 164 return True; 165} 166#endif /* WITH_PROFILE */ 167