1 /* Copyright (c) 1998-2019 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, see
17 <https://www.gnu.org/licenses/>. */
26 #include <sys/socket.h>
34 # include <selinux/selinux.h>
35 # include <selinux/avc.h>
36 #endif /* HAVE_SELINUX */
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
42 #define STATDATA_VERSION 0x01020000U
45 # define STATDATA_VERSION_SELINUX_FLAG 0x0001U
47 # define STATDATA_VERSION_SELINUX_FLAG 0x0000U
50 /* All flags affecting the struct statdata layout. */
51 #define STATDATA_VERSION_FLAGS STATDATA_VERSION_SELINUX_FLAG
53 /* The full version number for struct statdata. */
54 #define STATDATA_VERSION_FULL (STATDATA_VERSION | STATDATA_VERSION_FLAGS)
56 /* Statistic data for one database. */
65 unsigned long int postimeout
;
66 unsigned long int negtimeout
;
79 uintmax_t rdlockdelayed
;
80 uintmax_t wrlockdelayed
;
85 /* Record for transmitting statistics. If this definition changes,
86 update STATDATA_VERSION above. */
89 unsigned int version
; /* Must be STATDATA_VERSION_FULL. */
92 unsigned long int client_queued
;
96 time_t restart_interval
;
97 unsigned int reload_count
;
99 struct dbstat dbs
[lastdb
];
101 struct avc_cache_stats cstats
;
102 #endif /* HAVE_SELINUX */
107 send_stats (int fd
, struct database_dyn dbs
[lastdb
])
109 struct statdata data
;
112 memset (&data
, 0, sizeof (data
));
114 data
.version
= STATDATA_VERSION_FULL
;
115 data
.debug_level
= debug_level
;
116 data
.runtime
= time (NULL
) - start_time
;
117 data
.client_queued
= client_queued
;
118 data
.nthreads
= nthreads
;
119 data
.max_nthreads
= max_nthreads
;
120 data
.paranoia
= paranoia
;
121 data
.restart_interval
= restart_interval
;
122 data
.reload_count
= reload_count
;
125 for (cnt
= 0; cnt
< lastdb
; ++cnt
)
127 memset (&data
.dbs
[cnt
], 0, sizeof (data
.dbs
[cnt
]));
128 data
.dbs
[cnt
].enabled
= dbs
[cnt
].enabled
;
129 data
.dbs
[cnt
].check_file
= dbs
[cnt
].check_file
;
130 data
.dbs
[cnt
].shared
= dbs
[cnt
].shared
;
131 data
.dbs
[cnt
].persistent
= dbs
[cnt
].persistent
;
132 data
.dbs
[cnt
].postimeout
= dbs
[cnt
].postimeout
;
133 data
.dbs
[cnt
].negtimeout
= dbs
[cnt
].negtimeout
;
134 if (dbs
[cnt
].head
!= NULL
)
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
;
153 nscd_avc_cache_stats (&data
.cstats
);
155 if (TEMP_FAILURE_RETRY (send (fd
, &data
, sizeof (data
), MSG_NOSIGNAL
))
159 dbg_log (_("cannot write statistics: %s"),
160 strerror_r (errno
, buf
, sizeof (buf
)));
166 receive_print_stats (void)
168 struct statdata data
;
173 uid_t uid
= getuid ();
174 const char *yesstr
= _("yes");
175 const char *nostr
= _("no");
177 /* Find out whether there is another user but root allowed to
178 request statistics. */
181 /* User specified? */
182 if(stat_user
== NULL
|| stat_uid
!= uid
)
184 if (stat_user
!= NULL
)
185 error (EXIT_FAILURE
, 0,
186 _("Only root or %s is allowed to use this option!"),
189 error (EXIT_FAILURE
, 0,
190 _("Only root is allowed to use this option!"));
194 /* Open a socket to the running nscd. */
195 fd
= nscd_open_socket ();
197 error (EXIT_FAILURE
, 0, _("nscd not running!\n"));
199 /* Send the request. */
200 req
.version
= NSCD_VERSION
;
203 nbytes
= TEMP_FAILURE_RETRY (send (fd
, &req
, sizeof (request_header
),
205 if (nbytes
!= sizeof (request_header
))
209 error (EXIT_FAILURE
, err
, _("write incomplete"));
212 /* Read as much data as we expect. */
213 if (TEMP_FAILURE_RETRY (read (fd
, &data
, sizeof (data
))) != sizeof (data
)
214 || (data
.version
!= STATDATA_VERSION_FULL
215 /* Yes, this is an assignment! */
216 && (errno
= EINVAL
)))
218 /* Not the right version. */
221 error (EXIT_FAILURE
, err
, _("cannot read statistics data"));
224 printf (_("nscd configuration:\n\n%15d server debug level\n"),
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)
234 ndays
= diff
/ (24 * 60 * 60);
235 diff
%= 24 * 60 * 60;
239 nhours
= diff
/ (60 * 60);
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
);
253 printf (_(" %2um %2lus server runtime\n"), nmins
, diff
);
255 printf (_(" %2lus server runtime\n"), diff
);
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"
260 "%15s paranoia mode enabled\n"
261 "%15lu restart internal\n"
262 "%15u reload count\n"),
263 data
.nthreads
, data
.max_nthreads
, data
.client_queued
,
264 data
.paranoia
? yesstr
: nostr
,
265 (unsigned long int) data
.restart_interval
, data
.reload_count
);
267 for (i
= 0; i
< lastdb
; ++i
)
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
;
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
;
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. */
280 enabled
= data
.dbs
[i
].enabled
? yesstr
: nostr
;
281 if (check_file
[0] == '\0')
282 check_file
= data
.dbs
[i
].check_file
? yesstr
: nostr
;
283 if (shared
[0] == '\0')
284 shared
= data
.dbs
[i
].shared
? yesstr
: nostr
;
285 if (persistent
[0] == '\0')
286 persistent
= data
.dbs
[i
].persistent
? yesstr
: nostr
;
289 /* If nothing happened so far report a 0% hit rate. */
292 printf (_("\n%s cache:\n\n"
293 "%15s cache is enabled\n"
294 "%15s cache is persistent\n"
295 "%15s cache is shared\n"
296 "%15zu suggested size\n"
297 "%15zu total data pool size\n"
298 "%15zu used data pool size\n"
299 "%15lu seconds time to live for positive entries\n"
300 "%15lu seconds time to live for negative entries\n"
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"
305 "%15lu%% cache hit rate\n"
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"
312 "%15s check /etc/%s for changes\n"),
313 dbnames
[i
], enabled
, persistent
, shared
,
315 data
.dbs
[i
].datasize
, data
.dbs
[i
].dataused
,
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
,
320 data
.dbs
[i
].nentries
, data
.dbs
[i
].maxnentries
,
321 data
.dbs
[i
].maxnsearched
,
322 data
.dbs
[i
].rdlockdelayed
,
323 data
.dbs
[i
].wrlockdelayed
,
324 data
.dbs
[i
].addfailed
, check_file
, dbnames
[i
]);
328 nscd_avc_print_stats (&data
.cstats
);