(handle_request): Check access SELinux permissions before processing request.
[kopensolaris-gnu/glibc.git] / nscd / nscd_stat.c
1 /* Copyright (c) 1998, 2003, 2004 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.
4
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.
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
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
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 <unistd.h>
28 #include <libintl.h>
29
30 #include "nscd.h"
31 #include "dbg_log.h"
32
33 /* We use this to make sure the receiver is the same.  */
34 static const char compilation[21] = __DATE__ " " __TIME__;
35
36 /* Statistic data for one database.  */
37 struct dbstat
38 {
39   int enabled;
40   int check_file;
41   int shared;
42   int persistent;
43   size_t module;
44
45   unsigned long int postimeout;
46   unsigned long int negtimeout;
47
48   size_t nentries;
49   size_t maxnentries;
50   size_t maxnsearched;
51   size_t datasize;
52   size_t dataused;
53
54   uintmax_t poshit;
55   uintmax_t neghit;
56   uintmax_t posmiss;
57   uintmax_t negmiss;
58
59   uintmax_t rdlockdelayed;
60   uintmax_t wrlockdelayed;
61
62   uintmax_t addfailed;
63 };
64
65 /* Record for transmitting statistics.  */
66 struct statdata
67 {
68   char version[sizeof (compilation)];
69   int debug_level;
70   time_t runtime;
71   unsigned long int client_queued;
72   int ndbs;
73   struct dbstat dbs[lastdb];
74 };
75
76
77 void
78 send_stats (int fd, struct database_dyn dbs[lastdb])
79 {
80   struct statdata data;
81   int cnt;
82
83   memcpy (data.version, compilation, sizeof (compilation));
84   data.debug_level = debug_level;
85   data.runtime = time (NULL) - start_time;
86   data.client_queued = client_queued;
87   data.ndbs = lastdb;
88
89   for (cnt = 0; cnt < lastdb; ++cnt)
90     {
91       memset (&data.dbs[cnt], 0, sizeof (data.dbs[cnt]));
92       data.dbs[cnt].enabled = dbs[cnt].enabled;
93       data.dbs[cnt].check_file = dbs[cnt].check_file;
94       data.dbs[cnt].shared = dbs[cnt].shared;
95       data.dbs[cnt].persistent = dbs[cnt].persistent;
96       data.dbs[cnt].postimeout = dbs[cnt].postimeout;
97       data.dbs[cnt].negtimeout = dbs[cnt].negtimeout;
98       if (dbs[cnt].head != NULL)
99         {
100           data.dbs[cnt].module = dbs[cnt].head->module;
101           data.dbs[cnt].poshit = dbs[cnt].head->poshit;
102           data.dbs[cnt].neghit = dbs[cnt].head->neghit;
103           data.dbs[cnt].posmiss = dbs[cnt].head->posmiss;
104           data.dbs[cnt].negmiss = dbs[cnt].head->negmiss;
105           data.dbs[cnt].nentries = dbs[cnt].head->nentries;
106           data.dbs[cnt].maxnentries = dbs[cnt].head->maxnentries;
107           data.dbs[cnt].datasize = dbs[cnt].head->data_size;
108           data.dbs[cnt].dataused = dbs[cnt].head->first_free;
109           data.dbs[cnt].maxnsearched = dbs[cnt].head->maxnsearched;
110           data.dbs[cnt].rdlockdelayed = dbs[cnt].head->rdlockdelayed;
111           data.dbs[cnt].wrlockdelayed = dbs[cnt].head->wrlockdelayed;
112           data.dbs[cnt].addfailed = dbs[cnt].head->addfailed;
113         }
114     }
115
116   if (TEMP_FAILURE_RETRY (write (fd, &data, sizeof (data))) != sizeof (data))
117     {
118       char buf[256];
119       dbg_log (_("cannot write statistics: %s"),
120                strerror_r (errno, buf, sizeof (buf)));
121     }
122 }
123
124
125 int
126 receive_print_stats (void)
127 {
128   struct statdata data;
129   request_header req;
130   ssize_t nbytes;
131   int fd;
132   int i;
133   uid_t uid = getuid ();
134
135   /* Find out whether there is another user but root allowed to
136      request statistics.  */
137   if (uid != 0)
138     {
139       /* User specified?  */
140       if(stat_user == NULL || stat_uid != uid)
141         {
142           if (stat_user != NULL)
143             error (EXIT_FAILURE, 0,
144                    _("Only root or %s is allowed to use this option!"),
145                    stat_user);
146           else
147             error (EXIT_FAILURE, 0,
148                    _("Only root is allowed to use this option!"));
149         }
150     }
151
152   /* Open a socket to the running nscd.  */
153   fd = nscd_open_socket ();
154   if (fd == -1)
155     error (EXIT_FAILURE, 0, _("nscd not running!\n"));
156
157   /* Send the request.  */
158   req.version = NSCD_VERSION;
159   req.type = GETSTAT;
160   req.key_len = 0;
161   nbytes = TEMP_FAILURE_RETRY (write (fd, &req, sizeof (request_header)));
162   if (nbytes != sizeof (request_header))
163     {
164       int err = errno;
165       close (fd);
166       error (EXIT_FAILURE, err, _("write incomplete"));
167     }
168
169   /* Read as much data as we expect.  */
170   if (TEMP_FAILURE_RETRY (read (fd, &data, sizeof (data))) != sizeof (data)
171       || (memcmp (data.version, compilation, sizeof (compilation)) != 0
172           /* Yes, this is an assignment!  */
173           && (errno = EINVAL)))
174     {
175       /* Not the right version.  */
176       int err = errno;
177       close (fd);
178       error (EXIT_FAILURE, err, _("cannot read statistics data"));
179     }
180
181   printf (_("nscd configuration:\n\n%15d  server debug level\n"),
182           data.debug_level);
183
184   /* We know that we can simply subtract time_t values.  */
185   unsigned long int diff = data.runtime;
186   unsigned int ndays = 0;
187   unsigned int nhours = 0;
188   unsigned int nmins = 0;
189   if (diff > 24 * 60 * 60)
190     {
191       ndays = diff / (24 * 60 * 60);
192       diff %= 24 * 60 * 60;
193     }
194   if (diff > 60 * 60)
195     {
196       nhours = diff / (60 * 60);
197       diff %= 60 * 60;
198     }
199   if (diff > 60)
200     {
201       nmins = diff / 60;
202       diff %= 60;
203     }
204   if (ndays != 0)
205     printf (_("%3ud %2uh %2um %2lus  server runtime\n"),
206             ndays, nhours, nmins, diff);
207   else if (nhours != 0)
208     printf (_("    %2uh %2um %2lus  server runtime\n"), nhours, nmins, diff);
209   else if (nmins != 0)
210     printf (_("        %2um %2lus  server runtime\n"), nmins, diff);
211   else
212     printf (_("            %2lus  server runtime\n"), diff);
213
214   printf (_("%15lu  number of times clients had to wait\n"),
215           data.client_queued);
216
217   for (i = 0; i < lastdb; ++i)
218     {
219       unsigned long int hit = data.dbs[i].poshit + data.dbs[i].neghit;
220       unsigned long int all = hit + data.dbs[i].posmiss + data.dbs[i].negmiss;
221       const char *enabled = nl_langinfo (data.dbs[i].enabled ? YESSTR : NOSTR);
222       const char *check_file = nl_langinfo (data.dbs[i].check_file
223                                             ? YESSTR : NOSTR);
224       const char *shared = nl_langinfo (data.dbs[i].shared ? YESSTR : NOSTR);
225       const char *persistent = nl_langinfo (data.dbs[i].persistent
226                                             ? YESSTR : NOSTR);
227
228       if (enabled[0] == '\0')
229         /* The locale does not provide this information so we have to
230            translate it ourself.  Since we should avoid short translation
231            terms we artifically increase the length.  */
232         enabled = data.dbs[i].enabled ? _("     yes") : _("      no");
233       if (check_file[0] == '\0')
234         check_file = data.dbs[i].check_file ? _("     yes") : _("      no");
235       if (shared[0] == '\0')
236         shared = data.dbs[i].shared ? _("     yes") : _("      no");
237       if (persistent[0] == '\0')
238         persistent = data.dbs[i].persistent ? _("     yes") : _("      no");
239
240       if (all == 0)
241         /* If nothing happened so far report a 0% hit rate.  */
242         all = 1;
243
244       printf (_("\n%s cache:\n\n"
245                 "%15s  cache is enabled\n"
246                 "%15s  cache is persistent\n"
247                 "%15s  cache is shared\n"
248                 "%15zu  suggested size\n"
249                 "%15zu  total data pool size\n"
250                 "%15zu  used data pool size\n"
251                 "%15lu  seconds time to live for positive entries\n"
252                 "%15lu  seconds time to live for negative entries\n"
253                 "%15" PRIuMAX "  cache hits on positive entries\n"
254                 "%15" PRIuMAX "  cache hits on negative entries\n"
255                 "%15" PRIuMAX "  cache misses on positive entries\n"
256                 "%15" PRIuMAX "  cache misses on negative entries\n"
257                 "%15lu%% cache hit rate\n"
258                 "%15zu  current number of cached values\n"
259                 "%15zu  maximum number of cached values\n"
260                 "%15zu  maximum chain length searched\n"
261                 "%15" PRIuMAX "  number of delays on rdlock\n"
262                 "%15" PRIuMAX "  number of delays on wrlock\n"
263                 "%15" PRIuMAX "  memory allocations failed\n"
264                 "%15s  check /etc/%s for changes\n"),
265               dbnames[i], enabled, persistent, shared,
266               data.dbs[i].module,
267               data.dbs[i].datasize, data.dbs[i].dataused,
268               data.dbs[i].postimeout, data.dbs[i].negtimeout,
269               data.dbs[i].poshit, data.dbs[i].neghit,
270               data.dbs[i].posmiss, data.dbs[i].negmiss,
271               (100 * hit) / all,
272               data.dbs[i].nentries, data.dbs[i].maxnentries,
273               data.dbs[i].maxnsearched,
274               data.dbs[i].rdlockdelayed,
275               data.dbs[i].wrlockdelayed,
276               data.dbs[i].addfailed, check_file, dbnames[i]);
277     }
278
279   close (fd);
280
281   exit (0);
282 }