Remove bundled testtools.
[Samba.git] / source3 / profile / profile.c
blobc720638502783126045d351b41ab9031a8057034
1 /*
2 Unix SMB/CIFS implementation.
3 store smbd profiling information in shared memory
4 Copyright (C) Andrew Tridgell 1999
5 Copyright (C) James Peach 2006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "system/shmem.h"
24 #include "system/filesys.h"
25 #include "messages.h"
26 #include "smbprofile.h"
28 #define PROF_SHMEM_KEY ((key_t)0x07021999)
29 #define PROF_SHM_MAGIC 0x6349985
30 #define PROF_SHM_VERSION 15
32 #define IPC_PERMS ((S_IRUSR | S_IWUSR) | S_IRGRP | S_IROTH)
34 static int shm_id;
35 static bool read_only;
37 struct profile_header {
38 int prof_shm_magic;
39 int prof_shm_version;
40 struct profile_stats stats;
43 static struct profile_header *profile_h;
44 struct profile_stats *profile_p;
46 bool do_profile_flag = False;
47 bool do_profile_times = False;
49 /****************************************************************************
50 Set a profiling level.
51 ****************************************************************************/
52 void set_profile_level(int level, struct server_id src)
54 switch (level) {
55 case 0: /* turn off profiling */
56 do_profile_flag = False;
57 do_profile_times = False;
58 DEBUG(1,("INFO: Profiling turned OFF from pid %d\n",
59 (int)procid_to_pid(&src)));
60 break;
61 case 1: /* turn on counter profiling only */
62 do_profile_flag = True;
63 do_profile_times = False;
64 DEBUG(1,("INFO: Profiling counts turned ON from pid %d\n",
65 (int)procid_to_pid(&src)));
66 break;
67 case 2: /* turn on complete profiling */
68 do_profile_flag = True;
69 do_profile_times = True;
70 DEBUG(1,("INFO: Full profiling turned ON from pid %d\n",
71 (int)procid_to_pid(&src)));
72 break;
73 case 3: /* reset profile values */
74 memset((char *)profile_p, 0, sizeof(*profile_p));
75 DEBUG(1,("INFO: Profiling values cleared from pid %d\n",
76 (int)procid_to_pid(&src)));
77 break;
81 /****************************************************************************
82 receive a set profile level message
83 ****************************************************************************/
84 static void profile_message(struct messaging_context *msg_ctx,
85 void *private_data,
86 uint32_t msg_type,
87 struct server_id src,
88 DATA_BLOB *data)
90 int level;
92 if (data->length != sizeof(level)) {
93 DEBUG(0, ("got invalid profile message\n"));
94 return;
97 memcpy(&level, data->data, sizeof(level));
98 set_profile_level(level, src);
101 /****************************************************************************
102 receive a request profile level message
103 ****************************************************************************/
104 static void reqprofile_message(struct messaging_context *msg_ctx,
105 void *private_data,
106 uint32_t msg_type,
107 struct server_id src,
108 DATA_BLOB *data)
110 int level;
112 level = 1 + (do_profile_flag?2:0) + (do_profile_times?4:0);
114 DEBUG(1,("INFO: Received REQ_PROFILELEVEL message from PID %u\n",
115 (unsigned int)procid_to_pid(&src)));
116 messaging_send_buf(msg_ctx, src, MSG_PROFILELEVEL,
117 (uint8 *)&level, sizeof(level));
120 /*******************************************************************
121 open the profiling shared memory area
122 ******************************************************************/
123 bool profile_setup(struct messaging_context *msg_ctx, bool rdonly)
125 struct shmid_ds shm_ds;
127 read_only = rdonly;
129 again:
130 /* try to use an existing key */
131 shm_id = shmget(PROF_SHMEM_KEY, 0, 0);
133 /* if that failed then create one. There is a race condition here
134 if we are running from inetd. Bad luck. */
135 if (shm_id == -1) {
136 if (read_only) return False;
137 shm_id = shmget(PROF_SHMEM_KEY, sizeof(*profile_h),
138 IPC_CREAT | IPC_EXCL | IPC_PERMS);
141 if (shm_id == -1) {
142 DEBUG(0,("Can't create or use IPC area. Error was %s\n",
143 strerror(errno)));
144 return False;
147 profile_h = (struct profile_header *)shmat(shm_id, 0,
148 read_only?SHM_RDONLY:0);
149 if ((long)profile_h == -1) {
150 DEBUG(0,("Can't attach to IPC area. Error was %s\n",
151 strerror(errno)));
152 return False;
155 /* find out who created this memory area */
156 if (shmctl(shm_id, IPC_STAT, &shm_ds) != 0) {
157 DEBUG(0,("ERROR shmctl : can't IPC_STAT. Error was %s\n",
158 strerror(errno)));
159 return False;
162 if (shm_ds.shm_perm.cuid != sec_initial_uid() ||
163 shm_ds.shm_perm.cgid != sec_initial_gid()) {
164 DEBUG(0,("ERROR: we did not create the shmem "
165 "(owned by another user, uid %u, gid %u)\n",
166 shm_ds.shm_perm.cuid,
167 shm_ds.shm_perm.cgid));
168 return False;
171 if (shm_ds.shm_segsz != sizeof(*profile_h)) {
172 DEBUG(0,("WARNING: profile size is %d (expected %d). Deleting\n",
173 (int)shm_ds.shm_segsz, (int)sizeof(*profile_h)));
174 if (shmctl(shm_id, IPC_RMID, &shm_ds) == 0) {
175 goto again;
176 } else {
177 return False;
181 if (!read_only && (shm_ds.shm_nattch == 1)) {
182 memset((char *)profile_h, 0, sizeof(*profile_h));
183 profile_h->prof_shm_magic = PROF_SHM_MAGIC;
184 profile_h->prof_shm_version = PROF_SHM_VERSION;
185 DEBUG(3,("Initialised profile area\n"));
188 profile_p = &profile_h->stats;
189 if (msg_ctx != NULL) {
190 messaging_register(msg_ctx, NULL, MSG_PROFILE,
191 profile_message);
192 messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
193 reqprofile_message);
195 return True;