(linenum→info "unix/slp.c:2238")

glibc/2.7/nscd/nscd_stat.c

    1: /* Copyright (c) 1998, 2003, 2004, 2005 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 <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 /* HAVE_SELINUX */
   38: 
   39: 
   40: /* We use this to make sure the receiver is the same.  */
   41: static const char compilation[21] = __DATE__ " " __TIME__;
   42: 
   43: /* Statistic data for one database.  */
   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: /* Record for transmitting statistics.  */
   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 /* HAVE_SELINUX */
   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:   /* Find out whether there is another user but root allowed to
  160:      request statistics.  */
  161:   if (uid != 0)
  162:     {
  163:       /* User specified?  */
  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:   /* Open a socket to the running nscd.  */
  177:   fd = nscd_open_socket ();
  178:   if (fd == -1)
  179:     error (EXIT_FAILURE, 0, _("nscd not running!\n"));
  180: 
  181:   /* Send the request.  */
  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:   /* Read as much data as we expect.  */
  195:   if (TEMP_FAILURE_RETRY (read (fd, &data, sizeof (data))) != sizeof (data)
  196:       || (memcmp (data.version, compilation, sizeof (compilation)) != 0
  197:           /* Yes, this is an assignment!  */
  198:           && (errno = EINVAL)))
  199:     {
  200:       /* Not the right version.  */
  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:   /* We know that we can simply subtract time_t values.  */
  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:         /* The locale does not provide this information so we have to
  259:            translate it ourself.  Since we should avoid short translation
  260:            terms we artifically increase the length.  */
  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:         /* If nothing happened so far report a 0% hit rate.  */
  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: }
Syntax (Markdown)