1 /* Copyright (c) 1998-2024 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
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.
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
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
25 #include <sys/socket.h>
33 # include <selinux/selinux.h>
34 # include <selinux/avc.h>
35 #endif /* HAVE_SELINUX */
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
41 #define STATDATA_VERSION 0x01020000U
44 # define STATDATA_VERSION_SELINUX_FLAG 0x0001U
46 # define STATDATA_VERSION_SELINUX_FLAG 0x0000U
49 /* All flags affecting the struct statdata layout. */
50 #define STATDATA_VERSION_FLAGS STATDATA_VERSION_SELINUX_FLAG
52 /* The full version number for struct statdata. */
53 #define STATDATA_VERSION_FULL (STATDATA_VERSION | STATDATA_VERSION_FLAGS)
55 /* Statistic data for one database. */
64 unsigned long int postimeout
;
65 unsigned long int negtimeout
;
78 uintmax_t rdlockdelayed
;
79 uintmax_t wrlockdelayed
;
84 /* Record for transmitting statistics. If this definition changes,
85 update STATDATA_VERSION above. */
88 unsigned int version
; /* Must be STATDATA_VERSION_FULL. */
91 unsigned long int client_queued
;
95 time_t restart_interval
;
96 unsigned int reload_count
;
98 struct dbstat dbs
[lastdb
];
100 struct avc_cache_stats cstats
;
101 #endif /* HAVE_SELINUX */
106 send_stats (int fd
, struct database_dyn dbs
[lastdb
])
108 struct statdata data
;
111 memset (&data
, 0, sizeof (data
));
113 data
.version
= STATDATA_VERSION_FULL
;
114 data
.debug_level
= debug_level
;
115 data
.runtime
= time (NULL
) - start_time
;
116 data
.client_queued
= client_queued
;
117 data
.nthreads
= nthreads
;
118 data
.max_nthreads
= max_nthreads
;
119 data
.paranoia
= paranoia
;
120 data
.restart_interval
= restart_interval
;
121 data
.reload_count
= reload_count
;
124 for (cnt
= 0; cnt
< lastdb
; ++cnt
)
126 memset (&data
.dbs
[cnt
], 0, sizeof (data
.dbs
[cnt
]));
127 data
.dbs
[cnt
].enabled
= dbs
[cnt
].enabled
;
128 data
.dbs
[cnt
].check_file
= dbs
[cnt
].check_file
;
129 data
.dbs
[cnt
].shared
= dbs
[cnt
].shared
;
130 data
.dbs
[cnt
].persistent
= dbs
[cnt
].persistent
;
131 data
.dbs
[cnt
].postimeout
= dbs
[cnt
].postimeout
;
132 data
.dbs
[cnt
].negtimeout
= dbs
[cnt
].negtimeout
;
133 if (dbs
[cnt
].head
!= NULL
)
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
;
152 nscd_avc_cache_stats (&data
.cstats
);
154 if (TEMP_FAILURE_RETRY (send (fd
, &data
, sizeof (data
), MSG_NOSIGNAL
))
158 dbg_log (_("cannot write statistics: %s"),
159 strerror_r (errno
, buf
, sizeof (buf
)));
165 receive_print_stats (void)
167 struct statdata data
;
172 uid_t uid
= getuid ();
173 const char *yesstr
= _("yes");
174 const char *nostr
= _("no");
176 /* Find out whether there is another user but root allowed to
177 request statistics. */
180 /* User specified? */
181 if(stat_user
== NULL
|| stat_uid
!= uid
)
183 if (stat_user
!= NULL
)
184 error (EXIT_FAILURE
, 0,
185 _("Only root or %s is allowed to use this option!"),
188 error (EXIT_FAILURE
, 0,
189 _("Only root is allowed to use this option!"));
193 /* Open a socket to the running nscd. */
194 fd
= nscd_open_socket ();
196 error (EXIT_FAILURE
, 0, _("nscd not running!\n"));
198 /* Send the request. */
199 req
.version
= NSCD_VERSION
;
202 nbytes
= TEMP_FAILURE_RETRY (send (fd
, &req
, sizeof (request_header
),
204 if (nbytes
!= sizeof (request_header
))
208 error (EXIT_FAILURE
, err
, _("write incomplete"));
211 /* Read as much data as we expect. */
212 if (TEMP_FAILURE_RETRY (read (fd
, &data
, sizeof (data
))) != sizeof (data
)
213 || (data
.version
!= STATDATA_VERSION_FULL
214 /* Yes, this is an assignment! */
215 && (errno
= EINVAL
)))
217 /* Not the right version. */
220 error (EXIT_FAILURE
, err
, _("cannot read statistics data"));
223 printf (_("nscd configuration:\n\n%15d server debug level\n"),
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)
233 ndays
= diff
/ (24 * 60 * 60);
234 diff
%= 24 * 60 * 60;
238 nhours
= diff
/ (60 * 60);
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
);
252 printf (_(" %2um %2lus server runtime\n"), nmins
, diff
);
254 printf (_(" %2lus server runtime\n"), diff
);
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"
259 "%15s paranoia mode enabled\n"
260 "%15lu restart internal\n"
261 "%15u reload count\n"),
262 data
.nthreads
, data
.max_nthreads
, data
.client_queued
,
263 data
.paranoia
? yesstr
: nostr
,
264 (unsigned long int) data
.restart_interval
, data
.reload_count
);
266 for (i
= 0; i
< lastdb
; ++i
)
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
;
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
;
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 artificially increase the length. */
279 enabled
= data
.dbs
[i
].enabled
? yesstr
: nostr
;
280 if (check_file
[0] == '\0')
281 check_file
= data
.dbs
[i
].check_file
? yesstr
: nostr
;
282 if (shared
[0] == '\0')
283 shared
= data
.dbs
[i
].shared
? yesstr
: nostr
;
284 if (persistent
[0] == '\0')
285 persistent
= data
.dbs
[i
].persistent
? yesstr
: nostr
;
288 /* If nothing happened so far report a 0% hit rate. */
291 printf (_("\n%s cache:\n\n"
292 "%15s cache is enabled\n"
293 "%15s cache is persistent\n"
294 "%15s cache is shared\n"
295 "%15zu suggested size\n"
296 "%15zu total data pool size\n"
297 "%15zu used data pool size\n"
298 "%15lu seconds time to live for positive entries\n"
299 "%15lu seconds time to live for negative entries\n"
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"
304 "%15lu%% cache hit rate\n"
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"
311 "%15s check /etc/%s for changes\n"),
312 dbnames
[i
], enabled
, persistent
, shared
,
314 data
.dbs
[i
].datasize
, data
.dbs
[i
].dataused
,
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
,
319 data
.dbs
[i
].nentries
, data
.dbs
[i
].maxnentries
,
320 data
.dbs
[i
].maxnsearched
,
321 data
.dbs
[i
].rdlockdelayed
,
322 data
.dbs
[i
].wrlockdelayed
,
323 data
.dbs
[i
].addfailed
, check_file
, dbnames
[i
]);
327 nscd_avc_print_stats (&data
.cstats
);