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