1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20: #include <errno.h>
21: #include <error.h>
22: #include <inttypes.h>
23: #include <langinfo.h>
24: #include <stdio.h>
25: #include <stdlib.h>
26: #include <string.h>
27: #include <sys/socket.h>
28: #include <unistd.h>
29: #include <libintl.h>
30:
31: #include "nscd.h"
32: #include "dbg_log.h"
33: #include "selinux.h"
34: #ifdef HAVE_SELINUX
35: # include <selinux/selinux.h>
36: # include <selinux/avc.h>
37: #endif
38:
39:
40:
41: static const char compilation[21] = __DATE__ " " __TIME__;
42:
43:
44: struct dbstat
45: {
46: int enabled;
47: int check_file;
48: int shared;
49: int persistent;
50: size_t module;
51:
52: unsigned long int postimeout;
53: unsigned long int negtimeout;
54:
55: size_t nentries;
56: size_t maxnentries;
57: size_t maxnsearched;
58: size_t datasize;
59: size_t dataused;
60:
61: uintmax_t poshit;
62: uintmax_t neghit;
63: uintmax_t posmiss;
64: uintmax_t negmiss;
65:
66: uintmax_t rdlockdelayed;
67: uintmax_t wrlockdelayed;
68:
69: uintmax_t addfailed;
70: };
71:
72:
73: struct statdata
74: {
75: char version[sizeof (compilation)];
76: int debug_level;
77: time_t runtime;
78: unsigned long int client_queued;
79: int nthreads;
80: int max_nthreads;
81: int paranoia;
82: time_t restart_interval;
83: int ndbs;
84: struct dbstat dbs[lastdb];
85: #ifdef HAVE_SELINUX
86: struct avc_cache_stats cstats;
87: #endif
88: };
89:
90:
91: void
92: send_stats (int fd, struct database_dyn dbs[lastdb])
93: {
94: struct statdata data;
95: int cnt;
96:
97: memcpy (data.version, compilation, sizeof (compilation));
98: data.debug_level = debug_level;
99: data.runtime = time (NULL) - start_time;
100: data.client_queued = client_queued;
101: data.nthreads = nthreads;
102: data.max_nthreads = max_nthreads;
103: data.paranoia = paranoia;
104: data.restart_interval = restart_interval;
105: data.ndbs = lastdb;
106:
107: for (cnt = 0; cnt < lastdb; ++cnt)
108: {
109: memset (&data.dbs[cnt], 0, sizeof (data.dbs[cnt]));
110: data.dbs[cnt].enabled = dbs[cnt].enabled;
111: data.dbs[cnt].check_file = dbs[cnt].check_file;
112: data.dbs[cnt].shared = dbs[cnt].shared;
113: data.dbs[cnt].persistent = dbs[cnt].persistent;
114: data.dbs[cnt].postimeout = dbs[cnt].postimeout;
115: data.dbs[cnt].negtimeout = dbs[cnt].negtimeout;
116: if (dbs[cnt].head != NULL)
117: {
118: data.dbs[cnt].module = dbs[cnt].head->module;
119: data.dbs[cnt].poshit = dbs[cnt].head->poshit;
120: data.dbs[cnt].neghit = dbs[cnt].head->neghit;
121: data.dbs[cnt].posmiss = dbs[cnt].head->posmiss;
122: data.dbs[cnt].negmiss = dbs[cnt].head->negmiss;
123: data.dbs[cnt].nentries = dbs[cnt].head->nentries;
124: data.dbs[cnt].maxnentries = dbs[cnt].head->maxnentries;
125: data.dbs[cnt].datasize = dbs[cnt].head->data_size;
126: data.dbs[cnt].dataused = dbs[cnt].head->first_free;
127: data.dbs[cnt].maxnsearched = dbs[cnt].head->maxnsearched;
128: data.dbs[cnt].rdlockdelayed = dbs[cnt].head->rdlockdelayed;
129: data.dbs[cnt].wrlockdelayed = dbs[cnt].head->wrlockdelayed;
130: data.dbs[cnt].addfailed = dbs[cnt].head->addfailed;
131: }
132: }
133:
134: if (selinux_enabled)
135: nscd_avc_cache_stats (&data.cstats);
136:
137: if (TEMP_FAILURE_RETRY (send (fd, &data, sizeof (data), MSG_NOSIGNAL))
138: != sizeof (data))
139: {
140: char buf[256];
141: dbg_log (_("cannot write statistics: %s"),
142: strerror_r (errno, buf, sizeof (buf)));
143: }
144: }
145:
146:
147: int
148: receive_print_stats (void)
149: {
150: struct statdata data;
151: request_header req;
152: ssize_t nbytes;
153: int fd;
154: int i;
155: uid_t uid = getuid ();
156: const char *yesstr = _("yes");
157: const char *nostr = _("no");
158:
159:
160:
161: if (uid != 0)
162: {
163:
164: if(stat_user == NULL || stat_uid != uid)
165: {
166: if (stat_user != NULL)
167: error (EXIT_FAILURE, 0,
168: _("Only root or %s is allowed to use this option!"),
169: stat_user);
170: else
171: error (EXIT_FAILURE, 0,
172: _("Only root is allowed to use this option!"));
173: }
174: }
175:
176:
177: fd = nscd_open_socket ();
178: if (fd == -1)
179: error (EXIT_FAILURE, 0, _("nscd not running!\n"));
180:
181:
182: req.version = NSCD_VERSION;
183: req.type = GETSTAT;
184: req.key_len = 0;
185: nbytes = TEMP_FAILURE_RETRY (send (fd, &req, sizeof (request_header),
186: MSG_NOSIGNAL));
187: if (nbytes != sizeof (request_header))
188: {
189: int err = errno;
190: close (fd);
191: error (EXIT_FAILURE, err, _("write incomplete"));
192: }
193:
194:
195: if (TEMP_FAILURE_RETRY (read (fd, &data, sizeof (data))) != sizeof (data)
196: || (memcmp (data.version, compilation, sizeof (compilation)) != 0
197:
198: && (errno = EINVAL)))
199: {
200:
201: int err = errno;
202: close (fd);
203: error (EXIT_FAILURE, err, _("cannot read statistics data"));
204: }
205:
206: printf (_("nscd configuration:\n\n%15d server debug level\n"),
207: data.debug_level);
208:
209:
210: unsigned long int diff = data.runtime;
211: unsigned int ndays = 0;
212: unsigned int nhours = 0;
213: unsigned int nmins = 0;
214: if (diff > 24 * 60 * 60)
215: {
216: ndays = diff / (24 * 60 * 60);
217: diff %= 24 * 60 * 60;
218: }
219: if (diff > 60 * 60)
220: {
221: nhours = diff / (60 * 60);
222: diff %= 60 * 60;
223: }
224: if (diff > 60)
225: {
226: nmins = diff / 60;
227: diff %= 60;
228: }
229: if (ndays != 0)
230: printf (_("%3ud %2uh %2um %2lus server runtime\n"),
231: ndays, nhours, nmins, diff);
232: else if (nhours != 0)
233: printf (_(" %2uh %2um %2lus server runtime\n"), nhours, nmins, diff);
234: else if (nmins != 0)
235: printf (_(" %2um %2lus server runtime\n"), nmins, diff);
236: else
237: printf (_(" %2lus server runtime\n"), diff);
238:
239: printf (_("%15d current number of threads\n"
240: "%15d maximum number of threads\n"
241: "%15lu number of times clients had to wait\n"
242: "%15s paranoia mode enabled\n"
243: "%15lu restart internal\n"),
244: data.nthreads, data.max_nthreads, data.client_queued,
245: data.paranoia ? yesstr : nostr,
246: (unsigned long int) data.restart_interval);
247:
248: for (i = 0; i < lastdb; ++i)
249: {
250: unsigned long int hit = data.dbs[i].poshit + data.dbs[i].neghit;
251: unsigned long int all = hit + data.dbs[i].posmiss + data.dbs[i].negmiss;
252: const char *enabled = data.dbs[i].enabled ? yesstr : nostr;
253: const char *check_file = data.dbs[i].check_file ? yesstr : nostr;
254: const char *shared = data.dbs[i].shared ? yesstr : nostr;
255: const char *persistent = data.dbs[i].persistent ? yesstr : nostr;
256:
257: if (enabled[0] == '\0')
258:
259:
260:
261: enabled = data.dbs[i].enabled ? yesstr : nostr;
262: if (check_file[0] == '\0')
263: check_file = data.dbs[i].check_file ? yesstr : nostr;
264: if (shared[0] == '\0')
265: shared = data.dbs[i].shared ? yesstr : nostr;
266: if (persistent[0] == '\0')
267: persistent = data.dbs[i].persistent ? yesstr : nostr;
268:
269: if (all == 0)
270:
271: all = 1;
272:
273: printf (_("\n%s cache:\n\n"
274: "%15s cache is enabled\n"
275: "%15s cache is persistent\n"
276: "%15s cache is shared\n"
277: "%15zu suggested size\n"
278: "%15zu total data pool size\n"
279: "%15zu used data pool size\n"
280: "%15lu seconds time to live for positive entries\n"
281: "%15lu seconds time to live for negative entries\n"
282: "%15" PRIuMAX " cache hits on positive entries\n"
283: "%15" PRIuMAX " cache hits on negative entries\n"
284: "%15" PRIuMAX " cache misses on positive entries\n"
285: "%15" PRIuMAX " cache misses on negative entries\n"
286: "%15lu%% cache hit rate\n"
287: "%15zu current number of cached values\n"
288: "%15zu maximum number of cached values\n"
289: "%15zu maximum chain length searched\n"
290: "%15" PRIuMAX " number of delays on rdlock\n"
291: "%15" PRIuMAX " number of delays on wrlock\n"
292: "%15" PRIuMAX " memory allocations failed\n"
293: "%15s check /etc/%s for changes\n"),
294: dbnames[i], enabled, persistent, shared,
295: data.dbs[i].module,
296: data.dbs[i].datasize, data.dbs[i].dataused,
297: data.dbs[i].postimeout, data.dbs[i].negtimeout,
298: data.dbs[i].poshit, data.dbs[i].neghit,
299: data.dbs[i].posmiss, data.dbs[i].negmiss,
300: (100 * hit) / all,
301: data.dbs[i].nentries, data.dbs[i].maxnentries,
302: data.dbs[i].maxnsearched,
303: data.dbs[i].rdlockdelayed,
304: data.dbs[i].wrlockdelayed,
305: data.dbs[i].addfailed, check_file, dbnames[i]);
306: }
307:
308: if (selinux_enabled)
309: nscd_avc_print_stats (&data.cstats);
310:
311: close (fd);
312:
313: exit (0);
314: }