auth/credentials: a temporary MEMORY ccache needs krb5_cc_destroy()
[Samba.git] / source3 / profile / profile.c
blob0b02e36fcd01e72ad8b6629e1e76e0b6d6c8acb7
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/filesys.h"
24 #include "system/time.h"
25 #include "messages.h"
26 #include "smbprofile.h"
27 #include "lib/tdb_wrap/tdb_wrap.h"
28 #include <tevent.h>
29 #include "../lib/crypto/crypto.h"
31 #ifdef HAVE_SYS_RESOURCE_H
32 #include <sys/resource.h>
33 #endif
35 struct profile_stats *profile_p;
36 struct smbprofile_global_state smbprofile_state;
38 /****************************************************************************
39 Set a profiling level.
40 ****************************************************************************/
41 void set_profile_level(int level, const struct server_id *src)
43 SMB_ASSERT(smbprofile_state.internal.db != NULL);
45 switch (level) {
46 case 0: /* turn off profiling */
47 smbprofile_state.config.do_count = false;
48 smbprofile_state.config.do_times = false;
49 DEBUG(1,("INFO: Profiling turned OFF from pid %d\n",
50 (int)procid_to_pid(src)));
51 break;
52 case 1: /* turn on counter profiling only */
53 smbprofile_state.config.do_count = true;
54 smbprofile_state.config.do_times = false;
55 DEBUG(1,("INFO: Profiling counts turned ON from pid %d\n",
56 (int)procid_to_pid(src)));
57 break;
58 case 2: /* turn on complete profiling */
59 smbprofile_state.config.do_count = true;
60 smbprofile_state.config.do_times = true;
61 DEBUG(1,("INFO: Full profiling turned ON from pid %d\n",
62 (int)procid_to_pid(src)));
63 break;
64 case 3: /* reset profile values */
65 ZERO_STRUCT(profile_p->values);
66 tdb_wipe_all(smbprofile_state.internal.db->tdb);
67 DEBUG(1,("INFO: Profiling values cleared from pid %d\n",
68 (int)procid_to_pid(src)));
69 break;
73 /****************************************************************************
74 receive a set profile level message
75 ****************************************************************************/
76 static void profile_message(struct messaging_context *msg_ctx,
77 void *private_data,
78 uint32_t msg_type,
79 struct server_id src,
80 DATA_BLOB *data)
82 int level;
84 if (data->length != sizeof(level)) {
85 DEBUG(0, ("got invalid profile message\n"));
86 return;
89 memcpy(&level, data->data, sizeof(level));
90 set_profile_level(level, &src);
93 /****************************************************************************
94 receive a request profile level message
95 ****************************************************************************/
96 static void reqprofile_message(struct messaging_context *msg_ctx,
97 void *private_data,
98 uint32_t msg_type,
99 struct server_id src,
100 DATA_BLOB *data)
102 int level;
104 level = 1;
105 if (smbprofile_state.config.do_count) {
106 level += 2;
108 if (smbprofile_state.config.do_times) {
109 level += 4;
112 DEBUG(1,("INFO: Received REQ_PROFILELEVEL message from PID %u\n",
113 (unsigned int)procid_to_pid(&src)));
114 messaging_send_buf(msg_ctx, src, MSG_PROFILELEVEL,
115 (uint8_t *)&level, sizeof(level));
118 /*******************************************************************
119 open the profiling shared memory area
120 ******************************************************************/
121 bool profile_setup(struct messaging_context *msg_ctx, bool rdonly)
123 char *db_name;
124 bool ok = false;
125 int rc;
127 if (smbprofile_state.internal.db != NULL) {
128 return true;
131 db_name = cache_path(talloc_tos(), "smbprofile.tdb");
132 if (db_name == NULL) {
133 return false;
136 smbprofile_state.internal.db = tdb_wrap_open(
137 NULL, db_name, 0,
138 rdonly ? 0 : TDB_CLEAR_IF_FIRST|TDB_MUTEX_LOCKING,
139 O_CREAT | (rdonly ? O_RDONLY : O_RDWR), 0644);
140 TALLOC_FREE(db_name);
141 if (smbprofile_state.internal.db == NULL) {
142 return false;
145 if (msg_ctx != NULL) {
146 messaging_register(msg_ctx, NULL, MSG_PROFILE,
147 profile_message);
148 messaging_register(msg_ctx, NULL, MSG_REQ_PROFILELEVEL,
149 reqprofile_message);
152 profile_p = &smbprofile_state.stats.global;
154 rc = smbprofile_magic(profile_p, &profile_p->magic);
155 if (rc != 0) {
156 goto out;
159 ok = true;
160 out:
162 return ok;
165 void smbprofile_dump_setup(struct tevent_context *ev)
167 TALLOC_FREE(smbprofile_state.internal.te);
168 smbprofile_state.internal.ev = ev;
171 static void smbprofile_dump_timer(struct tevent_context *ev,
172 struct tevent_timer *te,
173 struct timeval current_time,
174 void *private_data)
176 smbprofile_dump();
179 void smbprofile_dump_schedule_timer(void)
181 struct timeval tv;
183 GetTimeOfDay(&tv);
184 tv.tv_sec += 1;
186 smbprofile_state.internal.te = tevent_add_timer(
187 smbprofile_state.internal.ev,
188 smbprofile_state.internal.ev,
190 smbprofile_dump_timer,
191 NULL);
194 static int profile_stats_parser(TDB_DATA key, TDB_DATA value,
195 void *private_data)
197 struct profile_stats *s = private_data;
199 if (value.dsize != sizeof(struct profile_stats)) {
200 *s = (struct profile_stats) {};
201 return 0;
204 memcpy(s, value.dptr, value.dsize);
205 if (s->magic != profile_p->magic) {
206 *s = (struct profile_stats) {};
207 return 0;
210 return 0;
213 void smbprofile_dump(void)
215 pid_t pid = 0;
216 TDB_DATA key = { .dptr = (uint8_t *)&pid, .dsize = sizeof(pid) };
217 struct profile_stats s = {};
218 int ret;
219 #ifdef HAVE_GETRUSAGE
220 struct rusage rself;
221 #endif /* HAVE_GETRUSAGE */
223 TALLOC_FREE(smbprofile_state.internal.te);
225 if (! (smbprofile_state.config.do_count ||
226 smbprofile_state.config.do_times)) {
227 return;
230 if (smbprofile_state.internal.db == NULL) {
231 return;
234 pid = tevent_cached_getpid();
236 ret = tdb_chainlock(smbprofile_state.internal.db->tdb, key);
237 if (ret != 0) {
238 return;
241 tdb_parse_record(smbprofile_state.internal.db->tdb,
242 key, profile_stats_parser, &s);
244 smbprofile_stats_accumulate(profile_p, &s);
246 #ifdef HAVE_GETRUSAGE
247 ret = getrusage(RUSAGE_SELF, &rself);
248 if (ret != 0) {
249 ZERO_STRUCT(rself);
252 profile_p->values.cpu_user_stats.time =
253 (rself.ru_utime.tv_sec * 1000000) +
254 rself.ru_utime.tv_usec;
255 profile_p->values.cpu_system_stats.time =
256 (rself.ru_stime.tv_sec * 1000000) +
257 rself.ru_stime.tv_usec;
258 #endif /* HAVE_GETRUSAGE */
260 tdb_store(smbprofile_state.internal.db->tdb, key,
261 (TDB_DATA) {
262 .dptr = (uint8_t *)profile_p,
263 .dsize = sizeof(*profile_p)
267 tdb_chainunlock(smbprofile_state.internal.db->tdb, key);
268 ZERO_STRUCT(profile_p->values);
270 return;
273 void smbprofile_cleanup(pid_t pid, pid_t dst)
275 TDB_DATA key = { .dptr = (uint8_t *)&pid, .dsize = sizeof(pid) };
276 struct profile_stats s = {};
277 struct profile_stats acc = {};
278 int ret;
280 if (smbprofile_state.internal.db == NULL) {
281 return;
284 ret = tdb_chainlock(smbprofile_state.internal.db->tdb, key);
285 if (ret != 0) {
286 return;
288 ret = tdb_parse_record(smbprofile_state.internal.db->tdb,
289 key, profile_stats_parser, &s);
290 if (ret == -1) {
291 tdb_chainunlock(smbprofile_state.internal.db->tdb, key);
292 return;
294 tdb_delete(smbprofile_state.internal.db->tdb, key);
295 tdb_chainunlock(smbprofile_state.internal.db->tdb, key);
297 pid = dst;
298 ret = tdb_chainlock(smbprofile_state.internal.db->tdb, key);
299 if (ret != 0) {
300 return;
302 tdb_parse_record(smbprofile_state.internal.db->tdb,
303 key, profile_stats_parser, &acc);
306 * We may have to fix the disconnect count
307 * in case the process died
309 s.values.disconnect_stats.count = s.values.connect_stats.count;
311 smbprofile_stats_accumulate(&acc, &s);
313 acc.magic = profile_p->magic;
314 tdb_store(smbprofile_state.internal.db->tdb, key,
315 (TDB_DATA) {
316 .dptr = (uint8_t *)&acc,
317 .dsize = sizeof(acc)
321 tdb_chainunlock(smbprofile_state.internal.db->tdb, key);
324 void smbprofile_collect(struct profile_stats *stats)
326 if (smbprofile_state.internal.db == NULL) {
327 return;
329 smbprofile_collect_tdb(smbprofile_state.internal.db->tdb,
330 profile_p->magic,
331 stats);