1 /* Copyright (c) 1998, 2003, 2004, 2005, 2010 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 #include <sys/socket.h>
35 # include <selinux/selinux.h>
36 # include <selinux/avc.h>
37 #endif /* HAVE_SELINUX */
40 /* We use this to make sure the receiver is the same. */
41 static const char compilation
[21] = __DATE__
" " __TIME__
;
43 /* Statistic data for one database. */
52 unsigned long int postimeout
;
53 unsigned long int negtimeout
;
66 uintmax_t rdlockdelayed
;
67 uintmax_t wrlockdelayed
;
72 /* Record for transmitting statistics. */
75 char version
[sizeof (compilation
)];
78 unsigned long int client_queued
;
82 time_t restart_interval
;
83 unsigned int reload_count
;
85 struct dbstat dbs
[lastdb
];
87 struct avc_cache_stats cstats
;
88 #endif /* HAVE_SELINUX */
93 send_stats (int fd
, struct database_dyn dbs
[lastdb
])
98 memcpy (data
.version
, compilation
, sizeof (compilation
));
99 data
.debug_level
= debug_level
;
100 data
.runtime
= time (NULL
) - start_time
;
101 data
.client_queued
= client_queued
;
102 data
.nthreads
= nthreads
;
103 data
.max_nthreads
= max_nthreads
;
104 data
.paranoia
= paranoia
;
105 data
.restart_interval
= restart_interval
;
106 data
.reload_count
= reload_count
;
109 for (cnt
= 0; cnt
< lastdb
; ++cnt
)
111 memset (&data
.dbs
[cnt
], 0, sizeof (data
.dbs
[cnt
]));
112 data
.dbs
[cnt
].enabled
= dbs
[cnt
].enabled
;
113 data
.dbs
[cnt
].check_file
= dbs
[cnt
].check_file
;
114 data
.dbs
[cnt
].shared
= dbs
[cnt
].shared
;
115 data
.dbs
[cnt
].persistent
= dbs
[cnt
].persistent
;
116 data
.dbs
[cnt
].postimeout
= dbs
[cnt
].postimeout
;
117 data
.dbs
[cnt
].negtimeout
= dbs
[cnt
].negtimeout
;
118 if (dbs
[cnt
].head
!= NULL
)
120 data
.dbs
[cnt
].module
= dbs
[cnt
].head
->module
;
121 data
.dbs
[cnt
].poshit
= dbs
[cnt
].head
->poshit
;
122 data
.dbs
[cnt
].neghit
= dbs
[cnt
].head
->neghit
;
123 data
.dbs
[cnt
].posmiss
= dbs
[cnt
].head
->posmiss
;
124 data
.dbs
[cnt
].negmiss
= dbs
[cnt
].head
->negmiss
;
125 data
.dbs
[cnt
].nentries
= dbs
[cnt
].head
->nentries
;
126 data
.dbs
[cnt
].maxnentries
= dbs
[cnt
].head
->maxnentries
;
127 data
.dbs
[cnt
].datasize
= dbs
[cnt
].head
->data_size
;
128 data
.dbs
[cnt
].dataused
= dbs
[cnt
].head
->first_free
;
129 data
.dbs
[cnt
].maxnsearched
= dbs
[cnt
].head
->maxnsearched
;
130 data
.dbs
[cnt
].rdlockdelayed
= dbs
[cnt
].head
->rdlockdelayed
;
131 data
.dbs
[cnt
].wrlockdelayed
= dbs
[cnt
].head
->wrlockdelayed
;
132 data
.dbs
[cnt
].addfailed
= dbs
[cnt
].head
->addfailed
;
137 nscd_avc_cache_stats (&data
.cstats
);
139 if (TEMP_FAILURE_RETRY (send (fd
, &data
, sizeof (data
), MSG_NOSIGNAL
))
143 dbg_log (_("cannot write statistics: %s"),
144 strerror_r (errno
, buf
, sizeof (buf
)));
150 receive_print_stats (void)
152 struct statdata data
;
157 uid_t uid
= getuid ();
158 const char *yesstr
= _("yes");
159 const char *nostr
= _("no");
161 /* Find out whether there is another user but root allowed to
162 request statistics. */
165 /* User specified? */
166 if(stat_user
== NULL
|| stat_uid
!= uid
)
168 if (stat_user
!= NULL
)
169 error (EXIT_FAILURE
, 0,
170 _("Only root or %s is allowed to use this option!"),
173 error (EXIT_FAILURE
, 0,
174 _("Only root is allowed to use this option!"));
178 /* Open a socket to the running nscd. */
179 fd
= nscd_open_socket ();
181 error (EXIT_FAILURE
, 0, _("nscd not running!\n"));
183 /* Send the request. */
184 req
.version
= NSCD_VERSION
;
187 nbytes
= TEMP_FAILURE_RETRY (send (fd
, &req
, sizeof (request_header
),
189 if (nbytes
!= sizeof (request_header
))
193 error (EXIT_FAILURE
, err
, _("write incomplete"));
196 /* Read as much data as we expect. */
197 if (TEMP_FAILURE_RETRY (read (fd
, &data
, sizeof (data
))) != sizeof (data
)
198 || (memcmp (data
.version
, compilation
, sizeof (compilation
)) != 0
199 /* Yes, this is an assignment! */
200 && (errno
= EINVAL
)))
202 /* Not the right version. */
205 error (EXIT_FAILURE
, err
, _("cannot read statistics data"));
208 printf (_("nscd configuration:\n\n%15d server debug level\n"),
211 /* We know that we can simply subtract time_t values. */
212 unsigned long int diff
= data
.runtime
;
213 unsigned int ndays
= 0;
214 unsigned int nhours
= 0;
215 unsigned int nmins
= 0;
216 if (diff
> 24 * 60 * 60)
218 ndays
= diff
/ (24 * 60 * 60);
219 diff
%= 24 * 60 * 60;
223 nhours
= diff
/ (60 * 60);
232 printf (_("%3ud %2uh %2um %2lus server runtime\n"),
233 ndays
, nhours
, nmins
, diff
);
234 else if (nhours
!= 0)
235 printf (_(" %2uh %2um %2lus server runtime\n"), nhours
, nmins
, diff
);
237 printf (_(" %2um %2lus server runtime\n"), nmins
, diff
);
239 printf (_(" %2lus server runtime\n"), diff
);
241 printf (_("%15d current number of threads\n"
242 "%15d maximum number of threads\n"
243 "%15lu number of times clients had to wait\n"
244 "%15s paranoia mode enabled\n"
245 "%15lu restart internal\n"
246 "%15u reload count\n"),
247 data
.nthreads
, data
.max_nthreads
, data
.client_queued
,
248 data
.paranoia
? yesstr
: nostr
,
249 (unsigned long int) data
.restart_interval
, data
.reload_count
);
251 for (i
= 0; i
< lastdb
; ++i
)
253 unsigned long int hit
= data
.dbs
[i
].poshit
+ data
.dbs
[i
].neghit
;
254 unsigned long int all
= hit
+ data
.dbs
[i
].posmiss
+ data
.dbs
[i
].negmiss
;
255 const char *enabled
= data
.dbs
[i
].enabled
? yesstr
: nostr
;
256 const char *check_file
= data
.dbs
[i
].check_file
? yesstr
: nostr
;
257 const char *shared
= data
.dbs
[i
].shared
? yesstr
: nostr
;
258 const char *persistent
= data
.dbs
[i
].persistent
? yesstr
: nostr
;
260 if (enabled
[0] == '\0')
261 /* The locale does not provide this information so we have to
262 translate it ourself. Since we should avoid short translation
263 terms we artifically increase the length. */
264 enabled
= data
.dbs
[i
].enabled
? yesstr
: nostr
;
265 if (check_file
[0] == '\0')
266 check_file
= data
.dbs
[i
].check_file
? yesstr
: nostr
;
267 if (shared
[0] == '\0')
268 shared
= data
.dbs
[i
].shared
? yesstr
: nostr
;
269 if (persistent
[0] == '\0')
270 persistent
= data
.dbs
[i
].persistent
? yesstr
: nostr
;
273 /* If nothing happened so far report a 0% hit rate. */
276 printf (_("\n%s cache:\n\n"
277 "%15s cache is enabled\n"
278 "%15s cache is persistent\n"
279 "%15s cache is shared\n"
280 "%15zu suggested size\n"
281 "%15zu total data pool size\n"
282 "%15zu used data pool size\n"
283 "%15lu seconds time to live for positive entries\n"
284 "%15lu seconds time to live for negative entries\n"
285 "%15" PRIuMAX
" cache hits on positive entries\n"
286 "%15" PRIuMAX
" cache hits on negative entries\n"
287 "%15" PRIuMAX
" cache misses on positive entries\n"
288 "%15" PRIuMAX
" cache misses on negative entries\n"
289 "%15lu%% cache hit rate\n"
290 "%15zu current number of cached values\n"
291 "%15zu maximum number of cached values\n"
292 "%15zu maximum chain length searched\n"
293 "%15" PRIuMAX
" number of delays on rdlock\n"
294 "%15" PRIuMAX
" number of delays on wrlock\n"
295 "%15" PRIuMAX
" memory allocations failed\n"
296 "%15s check /etc/%s for changes\n"),
297 dbnames
[i
], enabled
, persistent
, shared
,
299 data
.dbs
[i
].datasize
, data
.dbs
[i
].dataused
,
300 data
.dbs
[i
].postimeout
, data
.dbs
[i
].negtimeout
,
301 data
.dbs
[i
].poshit
, data
.dbs
[i
].neghit
,
302 data
.dbs
[i
].posmiss
, data
.dbs
[i
].negmiss
,
304 data
.dbs
[i
].nentries
, data
.dbs
[i
].maxnentries
,
305 data
.dbs
[i
].maxnsearched
,
306 data
.dbs
[i
].rdlockdelayed
,
307 data
.dbs
[i
].wrlockdelayed
,
308 data
.dbs
[i
].addfailed
, check_file
, dbnames
[i
]);
312 nscd_avc_print_stats (&data
.cstats
);