]> git.ipfire.org Git - thirdparty/glibc.git/blame - nscd/nscd_stat.c
Update copyright dates with scripts/update-copyrights
[thirdparty/glibc.git] / nscd / nscd_stat.c
CommitLineData
2b778ceb 1/* Copyright (c) 1998-2021 Free Software Foundation, Inc.
d67281a7
UD
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
4
5 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
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.
d67281a7
UD
9
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
41bdb6e2 13 Lesser General Public License for more details.
d67281a7 14
41bdb6e2 15 You should have received a copy of the GNU Lesser General Public
59ba27a6 16 License along with the GNU C Library; if not, see
5a82c748 17 <https://www.gnu.org/licenses/>. */
d67281a7 18
67479a70
UD
19#include <errno.h>
20#include <error.h>
a95a08b4 21#include <inttypes.h>
67479a70 22#include <langinfo.h>
d67281a7
UD
23#include <stdio.h>
24#include <stdlib.h>
67479a70 25#include <string.h>
0b20008e 26#include <sys/socket.h>
d67281a7 27#include <unistd.h>
4360eafd 28#include <libintl.h>
67479a70 29
d67281a7 30#include "nscd.h"
67479a70 31#include "dbg_log.h"
74a30a58
UD
32#include "selinux.h"
33#ifdef HAVE_SELINUX
34# include <selinux/selinux.h>
35# include <selinux/avc.h>
36#endif /* HAVE_SELINUX */
37
1e9522c6
FW
38/* We use this to make sure the receiver is the same. The lower 16
39 bits are reserved for flags indicating compilation variants. This
40 version needs to be updated if the definition of struct statdata
41 changes. */
42#define STATDATA_VERSION 0x01020000U
67479a70 43
1e9522c6
FW
44#ifdef HAVE_SELINUX
45# define STATDATA_VERSION_SELINUX_FLAG 0x0001U
46#else
47# define STATDATA_VERSION_SELINUX_FLAG 0x0000U
48#endif
49
50/* All flags affecting the struct statdata layout. */
51#define STATDATA_VERSION_FLAGS STATDATA_VERSION_SELINUX_FLAG
52
53/* The full version number for struct statdata. */
54#define STATDATA_VERSION_FULL (STATDATA_VERSION | STATDATA_VERSION_FLAGS)
67479a70
UD
55
56/* Statistic data for one database. */
57struct dbstat
58{
59 int enabled;
60 int check_file;
d13a3c57
UD
61 int shared;
62 int persistent;
67479a70
UD
63 size_t module;
64
65 unsigned long int postimeout;
66 unsigned long int negtimeout;
67
a95a08b4
UD
68 size_t nentries;
69 size_t maxnentries;
70 size_t maxnsearched;
71 size_t datasize;
72 size_t dataused;
c86e6aec 73
a95a08b4
UD
74 uintmax_t poshit;
75 uintmax_t neghit;
76 uintmax_t posmiss;
77 uintmax_t negmiss;
c86e6aec 78
a95a08b4
UD
79 uintmax_t rdlockdelayed;
80 uintmax_t wrlockdelayed;
81
82 uintmax_t addfailed;
67479a70
UD
83};
84
1e9522c6
FW
85/* Record for transmitting statistics. If this definition changes,
86 update STATDATA_VERSION above. */
67479a70
UD
87struct statdata
88{
1e9522c6 89 unsigned int version; /* Must be STATDATA_VERSION_FULL. */
67479a70 90 int debug_level;
c86e6aec 91 time_t runtime;
a16e3585 92 unsigned long int client_queued;
4630012f
UD
93 int nthreads;
94 int max_nthreads;
95 int paranoia;
96 time_t restart_interval;
d55d558b 97 unsigned int reload_count;
67479a70
UD
98 int ndbs;
99 struct dbstat dbs[lastdb];
74a30a58
UD
100#ifdef HAVE_SELINUX
101 struct avc_cache_stats cstats;
102#endif /* HAVE_SELINUX */
67479a70
UD
103};
104
d67281a7
UD
105
106void
a95a08b4 107send_stats (int fd, struct database_dyn dbs[lastdb])
d67281a7 108{
67479a70
UD
109 struct statdata data;
110 int cnt;
111
3cb26316
SP
112 memset (&data, 0, sizeof (data));
113
1e9522c6 114 data.version = STATDATA_VERSION_FULL;
67479a70 115 data.debug_level = debug_level;
c86e6aec 116 data.runtime = time (NULL) - start_time;
a16e3585 117 data.client_queued = client_queued;
4630012f
UD
118 data.nthreads = nthreads;
119 data.max_nthreads = max_nthreads;
120 data.paranoia = paranoia;
121 data.restart_interval = restart_interval;
d55d558b 122 data.reload_count = reload_count;
67479a70
UD
123 data.ndbs = lastdb;
124
125 for (cnt = 0; cnt < lastdb; ++cnt)
126 {
aadd7d9d 127 memset (&data.dbs[cnt], 0, sizeof (data.dbs[cnt]));
67479a70
UD
128 data.dbs[cnt].enabled = dbs[cnt].enabled;
129 data.dbs[cnt].check_file = dbs[cnt].check_file;
d13a3c57
UD
130 data.dbs[cnt].shared = dbs[cnt].shared;
131 data.dbs[cnt].persistent = dbs[cnt].persistent;
67479a70
UD
132 data.dbs[cnt].postimeout = dbs[cnt].postimeout;
133 data.dbs[cnt].negtimeout = dbs[cnt].negtimeout;
aadd7d9d
UD
134 if (dbs[cnt].head != NULL)
135 {
136 data.dbs[cnt].module = dbs[cnt].head->module;
137 data.dbs[cnt].poshit = dbs[cnt].head->poshit;
138 data.dbs[cnt].neghit = dbs[cnt].head->neghit;
139 data.dbs[cnt].posmiss = dbs[cnt].head->posmiss;
140 data.dbs[cnt].negmiss = dbs[cnt].head->negmiss;
141 data.dbs[cnt].nentries = dbs[cnt].head->nentries;
142 data.dbs[cnt].maxnentries = dbs[cnt].head->maxnentries;
143 data.dbs[cnt].datasize = dbs[cnt].head->data_size;
144 data.dbs[cnt].dataused = dbs[cnt].head->first_free;
145 data.dbs[cnt].maxnsearched = dbs[cnt].head->maxnsearched;
146 data.dbs[cnt].rdlockdelayed = dbs[cnt].head->rdlockdelayed;
147 data.dbs[cnt].wrlockdelayed = dbs[cnt].head->wrlockdelayed;
148 data.dbs[cnt].addfailed = dbs[cnt].head->addfailed;
149 }
67479a70 150 }
d67281a7 151
74a30a58
UD
152 if (selinux_enabled)
153 nscd_avc_cache_stats (&data.cstats);
154
2c210d1e
UD
155 if (TEMP_FAILURE_RETRY (send (fd, &data, sizeof (data), MSG_NOSIGNAL))
156 != sizeof (data))
d67281a7 157 {
67479a70
UD
158 char buf[256];
159 dbg_log (_("cannot write statistics: %s"),
160 strerror_r (errno, buf, sizeof (buf)));
d67281a7 161 }
67479a70
UD
162}
163
164
165int
166receive_print_stats (void)
167{
168 struct statdata data;
169 request_header req;
170 ssize_t nbytes;
171 int fd;
172 int i;
a12ce44f 173 uid_t uid = getuid ();
bb6e8ca3
UD
174 const char *yesstr = _("yes");
175 const char *nostr = _("no");
a12ce44f
UD
176
177 /* Find out whether there is another user but root allowed to
178 request statistics. */
179 if (uid != 0)
180 {
181 /* User specified? */
182 if(stat_user == NULL || stat_uid != uid)
183 {
184 if (stat_user != NULL)
185 error (EXIT_FAILURE, 0,
186 _("Only root or %s is allowed to use this option!"),
187 stat_user);
188 else
189 error (EXIT_FAILURE, 0,
190 _("Only root is allowed to use this option!"));
191 }
192 }
d67281a7 193
67479a70
UD
194 /* Open a socket to the running nscd. */
195 fd = nscd_open_socket ();
196 if (fd == -1)
197 error (EXIT_FAILURE, 0, _("nscd not running!\n"));
198
199 /* Send the request. */
d67281a7
UD
200 req.version = NSCD_VERSION;
201 req.type = GETSTAT;
202 req.key_len = 0;
2c210d1e
UD
203 nbytes = TEMP_FAILURE_RETRY (send (fd, &req, sizeof (request_header),
204 MSG_NOSIGNAL));
d67281a7
UD
205 if (nbytes != sizeof (request_header))
206 {
67479a70
UD
207 int err = errno;
208 close (fd);
209 error (EXIT_FAILURE, err, _("write incomplete"));
d67281a7
UD
210 }
211
67479a70
UD
212 /* Read as much data as we expect. */
213 if (TEMP_FAILURE_RETRY (read (fd, &data, sizeof (data))) != sizeof (data)
1e9522c6 214 || (data.version != STATDATA_VERSION_FULL
67479a70 215 /* Yes, this is an assignment! */
c86e6aec 216 && (errno = EINVAL)))
d67281a7 217 {
67479a70
UD
218 /* Not the right version. */
219 int err = errno;
220 close (fd);
221 error (EXIT_FAILURE, err, _("cannot read statistics data"));
d67281a7
UD
222 }
223
67479a70
UD
224 printf (_("nscd configuration:\n\n%15d server debug level\n"),
225 data.debug_level);
226
c86e6aec
UD
227 /* We know that we can simply subtract time_t values. */
228 unsigned long int diff = data.runtime;
229 unsigned int ndays = 0;
230 unsigned int nhours = 0;
231 unsigned int nmins = 0;
232 if (diff > 24 * 60 * 60)
233 {
234 ndays = diff / (24 * 60 * 60);
235 diff %= 24 * 60 * 60;
236 }
237 if (diff > 60 * 60)
238 {
239 nhours = diff / (60 * 60);
240 diff %= 60 * 60;
241 }
242 if (diff > 60)
243 {
244 nmins = diff / 60;
245 diff %= 60;
246 }
247 if (ndays != 0)
248 printf (_("%3ud %2uh %2um %2lus server runtime\n"),
249 ndays, nhours, nmins, diff);
250 else if (nhours != 0)
251 printf (_(" %2uh %2um %2lus server runtime\n"), nhours, nmins, diff);
252 else if (nmins != 0)
253 printf (_(" %2um %2lus server runtime\n"), nmins, diff);
254 else
255 printf (_(" %2lus server runtime\n"), diff);
256
27e82856
UD
257 printf (_("%15d current number of threads\n"
258 "%15d maximum number of threads\n"
259 "%15lu number of times clients had to wait\n"
4401d759 260 "%15s paranoia mode enabled\n"
d55d558b
UD
261 "%15lu restart internal\n"
262 "%15u reload count\n"),
4630012f
UD
263 data.nthreads, data.max_nthreads, data.client_queued,
264 data.paranoia ? yesstr : nostr,
d55d558b 265 (unsigned long int) data.restart_interval, data.reload_count);
a16e3585 266
67479a70
UD
267 for (i = 0; i < lastdb; ++i)
268 {
269 unsigned long int hit = data.dbs[i].poshit + data.dbs[i].neghit;
270 unsigned long int all = hit + data.dbs[i].posmiss + data.dbs[i].negmiss;
27e82856
UD
271 const char *enabled = data.dbs[i].enabled ? yesstr : nostr;
272 const char *check_file = data.dbs[i].check_file ? yesstr : nostr;
273 const char *shared = data.dbs[i].shared ? yesstr : nostr;
274 const char *persistent = data.dbs[i].persistent ? yesstr : nostr;
67479a70
UD
275
276 if (enabled[0] == '\0')
277 /* The locale does not provide this information so we have to
278 translate it ourself. Since we should avoid short translation
279 terms we artifically increase the length. */
4401d759 280 enabled = data.dbs[i].enabled ? yesstr : nostr;
67479a70 281 if (check_file[0] == '\0')
4401d759 282 check_file = data.dbs[i].check_file ? yesstr : nostr;
d13a3c57 283 if (shared[0] == '\0')
4401d759 284 shared = data.dbs[i].shared ? yesstr : nostr;
d13a3c57 285 if (persistent[0] == '\0')
4401d759 286 persistent = data.dbs[i].persistent ? yesstr : nostr;
67479a70
UD
287
288 if (all == 0)
289 /* If nothing happened so far report a 0% hit rate. */
290 all = 1;
291
292 printf (_("\n%s cache:\n\n"
293 "%15s cache is enabled\n"
d13a3c57
UD
294 "%15s cache is persistent\n"
295 "%15s cache is shared\n"
a95a08b4
UD
296 "%15zu suggested size\n"
297 "%15zu total data pool size\n"
298 "%15zu used data pool size\n"
c86e6aec
UD
299 "%15lu seconds time to live for positive entries\n"
300 "%15lu seconds time to live for negative entries\n"
a95a08b4
UD
301 "%15" PRIuMAX " cache hits on positive entries\n"
302 "%15" PRIuMAX " cache hits on negative entries\n"
303 "%15" PRIuMAX " cache misses on positive entries\n"
304 "%15" PRIuMAX " cache misses on negative entries\n"
c86e6aec 305 "%15lu%% cache hit rate\n"
a95a08b4
UD
306 "%15zu current number of cached values\n"
307 "%15zu maximum number of cached values\n"
308 "%15zu maximum chain length searched\n"
309 "%15" PRIuMAX " number of delays on rdlock\n"
310 "%15" PRIuMAX " number of delays on wrlock\n"
311 "%15" PRIuMAX " memory allocations failed\n"
67479a70 312 "%15s check /etc/%s for changes\n"),
d13a3c57 313 dbnames[i], enabled, persistent, shared,
67479a70 314 data.dbs[i].module,
a95a08b4 315 data.dbs[i].datasize, data.dbs[i].dataused,
67479a70
UD
316 data.dbs[i].postimeout, data.dbs[i].negtimeout,
317 data.dbs[i].poshit, data.dbs[i].neghit,
318 data.dbs[i].posmiss, data.dbs[i].negmiss,
319 (100 * hit) / all,
c86e6aec
UD
320 data.dbs[i].nentries, data.dbs[i].maxnentries,
321 data.dbs[i].maxnsearched,
322 data.dbs[i].rdlockdelayed,
a95a08b4
UD
323 data.dbs[i].wrlockdelayed,
324 data.dbs[i].addfailed, check_file, dbnames[i]);
67479a70
UD
325 }
326
74a30a58
UD
327 if (selinux_enabled)
328 nscd_avc_print_stats (&data.cstats);
329
67479a70
UD
330 close (fd);
331
332 exit (0);
d67281a7 333}