Imported Upstream version 5.3.21
[platform/upstream/libdb.git] / util / db_stat.c
1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1996, 2012 Oracle and/or its affiliates.  All rights reserved.
5  *
6  * $Id$
7  */
8
9 #include "db_config.h"
10
11 #include "db_int.h"
12
13 #ifndef lint
14 static const char copyright[] =
15     "Copyright (c) 1996, 2012 Oracle and/or its affiliates.  All rights reserved.\n";
16 #endif
17
18 typedef enum { T_NOTSET, T_DB,
19     T_ENV, T_LOCK, T_LOG, T_MPOOL, T_MUTEX, T_REP, T_TXN } test_t;
20
21 int      db_init __P((DB_ENV *, char *, test_t, u_int32_t, int *));
22 int      main __P((int, char *[]));
23 int      usage __P((void));
24 int      version_check __P((void));
25
26 const char *progname;
27
28 int
29 main(argc, argv)
30         int argc;
31         char *argv[];
32 {
33         extern char *optarg;
34         extern int optind;
35         DB_ENV  *dbenv;
36         DB *dbp;
37         test_t ttype;
38         u_int32_t cache, flags;
39         int ch, exitval;
40         int nflag, private, resize, ret;
41         char *db, *home, *p, *passwd, *subdb;
42
43         if ((progname = __db_rpath(argv[0])) == NULL)
44                 progname = argv[0];
45         else
46                 ++progname;
47
48         if ((ret = version_check()) != 0)
49                 return (ret);
50
51         dbenv = NULL;
52         dbp = NULL;
53         ttype = T_NOTSET;
54         cache = MEGABYTE;
55         exitval = flags = nflag = private = 0;
56         db = home = passwd = subdb = NULL;
57
58         while ((ch = getopt(argc,
59             argv, "aC:cd:Eefgh:L:lM:mNP:R:rs:tVxX:Z")) != EOF)
60                 switch (ch) {
61                 case 'a':
62                         LF_SET(DB_STAT_ALLOC);
63                         break;
64                 case 'C': case 'c':
65                         if (ttype != T_NOTSET && ttype != T_LOCK)
66                                 goto argcombo;
67                         ttype = T_LOCK;
68                         if (ch != 'c')
69                                 for (p = optarg; *p; ++p)
70                                         switch (*p) {
71                                         case 'A':
72                                                 LF_SET(DB_STAT_ALL);
73                                                 break;
74                                         case 'c':
75                                                 LF_SET(DB_STAT_LOCK_CONF);
76                                                 break;
77                                         case 'l':
78                                                 LF_SET(DB_STAT_LOCK_LOCKERS);
79                                                 break;
80                                         case 'm': /* Backward compatible. */
81                                                 break;
82                                         case 'o':
83                                                 LF_SET(DB_STAT_LOCK_OBJECTS);
84                                                 break;
85                                         case 'p':
86                                                 LF_SET(DB_STAT_LOCK_PARAMS);
87                                                 break;
88                                         default:
89                                                 return (usage());
90                                         }
91                         break;
92                 case 'd':
93                         if (ttype != T_NOTSET && ttype != T_DB)
94                                 goto argcombo;
95                         ttype = T_DB;
96                         db = optarg;
97                         break;
98                 case 'E': case 'e':
99                         if (ttype != T_NOTSET && ttype != T_ENV)
100                                 goto argcombo;
101                         ttype = T_ENV;
102                         LF_SET(DB_STAT_SUBSYSTEM);
103                         if (ch == 'E')
104                                 LF_SET(DB_STAT_ALL);
105                         break;
106                 case 'f':
107                         if (ttype != T_NOTSET && ttype != T_DB)
108                                 goto argcombo;
109                         ttype = T_DB;
110                         LF_SET(DB_FAST_STAT);
111                         break;
112                 case 'h':
113                         home = optarg;
114                         break;
115                 case 'L': case 'l':
116                         if (ttype != T_NOTSET && ttype != T_LOG)
117                                 goto argcombo;
118                         ttype = T_LOG;
119                         if (ch != 'l')
120                                 for (p = optarg; *p; ++p)
121                                         switch (*p) {
122                                         case 'A':
123                                                 LF_SET(DB_STAT_ALL);
124                                                 break;
125                                         default:
126                                                 return (usage());
127                                         }
128                         break;
129                 case 'M': case 'm':
130                         if (ttype != T_NOTSET && ttype != T_MPOOL)
131                                 goto argcombo;
132                         ttype = T_MPOOL;
133                         if (ch != 'm')
134                                 for (p = optarg; *p; ++p)
135                                         switch (*p) {
136                                         case 'A':
137                                                 LF_SET(DB_STAT_ALL);
138                                                 break;
139                                         case 'h':
140                                                 LF_SET(DB_STAT_MEMP_HASH);
141                                                 break;
142                                         case 'm': /* Backward compatible. */
143                                                 break;
144                                         default:
145                                                 return (usage());
146                                         }
147                         break;
148                 case 'N':
149                         nflag = 1;
150                         break;
151                 case 'P':
152                         if (passwd != NULL) {
153                                 fprintf(stderr, DB_STR("5139",
154                                         "Password may not be specified twice"));
155                                 free(passwd);
156                                 return (EXIT_FAILURE);
157                         }
158                         passwd = strdup(optarg);
159                         memset(optarg, 0, strlen(optarg));
160                         if (passwd == NULL) {
161                                 fprintf(stderr, DB_STR_A("5005",
162                                     "%s: strdup: %s\n", "%s %s\n"),
163                                     progname, strerror(errno));
164                                 return (EXIT_FAILURE);
165                         }
166                         break;
167                 case 'R': case 'r':
168                         if (ttype != T_NOTSET && ttype != T_REP)
169                                 goto argcombo;
170                         ttype = T_REP;
171                         if (ch != 'r')
172                                 for (p = optarg; *p; ++p)
173                                         switch (*p) {
174                                         case 'A':
175                                                 LF_SET(DB_STAT_ALL);
176                                                 break;
177                                         default:
178                                                 return (usage());
179                                         }
180                         break;
181                 case 's':
182                         if (ttype != T_NOTSET && ttype != T_DB)
183                                 goto argcombo;
184                         ttype = T_DB;
185                         subdb = optarg;
186                         break;
187                 case 't':
188                         if (ttype != T_NOTSET) {
189 argcombo:                       fprintf(stderr, DB_STR_A("5006",
190                                     "%s: illegal option combination\n",
191                                     "%s\n"), progname);
192                                 return (usage());
193                         }
194                         ttype = T_TXN;
195                         break;
196                 case 'V':
197                         printf("%s\n", db_version(NULL, NULL, NULL));
198                         return (EXIT_SUCCESS);
199                 case 'X': case 'x':
200                         if (ttype != T_NOTSET && ttype != T_MUTEX)
201                                 goto argcombo;
202                         ttype = T_MUTEX;
203                         if (ch != 'x')
204                                 for (p = optarg; *p; ++p)
205                                         switch (*p) {
206                                                 case 'A':
207                                                         LF_SET(DB_STAT_ALL);
208                                                         break;
209                                                 default:
210                                                         return (usage());
211                                         }
212                         break;
213                 case 'Z':
214                         LF_SET(DB_STAT_CLEAR);
215                         break;
216                 case '?':
217                 default:
218                         return (usage());
219                 }
220         argc -= optind;
221         argv += optind;
222
223         switch (ttype) {
224         case T_DB:
225                 if (db == NULL)
226                         return (usage());
227                 break;
228         case T_ENV:
229         case T_LOCK:
230         case T_LOG:
231         case T_MPOOL:
232         case T_MUTEX:
233         case T_REP:
234         case T_TXN:
235                 break;
236         case T_NOTSET:
237                 return (usage());
238         }
239
240         if (LF_ISSET(DB_STAT_ALL | DB_STAT_ALLOC) == DB_STAT_ALLOC)
241                 return (usage());
242
243         /* Handle possible interruptions. */
244         __db_util_siginit();
245
246         /*
247          * Create an environment object and initialize it for error
248          * reporting.
249          */
250 retry:  if ((ret = db_env_create(&dbenv, 0)) != 0) {
251                 fprintf(stderr,
252                     "%s: db_env_create: %s\n", progname, db_strerror(ret));
253                 goto err;
254         }
255
256         dbenv->set_errfile(dbenv, stderr);
257         dbenv->set_errpfx(dbenv, progname);
258
259         if (nflag) {
260                 if ((ret = dbenv->set_flags(dbenv, DB_NOLOCKING, 1)) != 0) {
261                         dbenv->err(dbenv, ret, "set_flags: DB_NOLOCKING");
262                         goto err;
263                 }
264                 if ((ret = dbenv->set_flags(dbenv, DB_NOPANIC, 1)) != 0) {
265                         dbenv->err(dbenv, ret, "set_flags: DB_NOPANIC");
266                         goto err;
267                 }
268         }
269
270         if (passwd != NULL &&
271             (ret = dbenv->set_encrypt(dbenv, passwd, DB_ENCRYPT_AES)) != 0) {
272                 dbenv->err(dbenv, ret, "set_passwd");
273                 goto err;
274         }
275
276         /* Initialize the environment. */
277         if (db_init(dbenv, home, ttype, cache, &private) != 0)
278                 goto err;
279
280         switch (ttype) {
281         case T_DB:
282                 /* Create the DB object and open the file. */
283                 if ((ret = db_create(&dbp, dbenv, 0)) != 0) {
284                         dbenv->err(dbenv, ret, "db_create");
285                         goto err;
286                 }
287
288                 /*
289                  * We open the database for writing so we can update the cached
290                  * statistics, but it's OK to fail, we can open read-only and
291                  * proceed.
292                  *
293                  * Turn off error messages for now -- we can't open lots of
294                  * databases read-write (for example, master databases and
295                  * hash databases for which we don't know the hash function).
296                  */
297                 dbenv->set_errfile(dbenv, NULL);
298                 ret = dbp->open(dbp, NULL, db, subdb, DB_UNKNOWN, 0, 0);
299                 dbenv->set_errfile(dbenv, stderr);
300                 if (ret != 0) {
301                         /* Handles cannot be reused after a failed DB->open. */
302                         (void)dbp->close(dbp, 0);
303                         if ((ret = db_create(&dbp, dbenv, 0)) != 0) {
304                                 dbenv->err(dbenv, ret, "db_create");
305                                 goto err;
306                         }
307
308                         if ((ret = dbp->open(dbp,
309                             NULL, db, subdb, DB_UNKNOWN, DB_RDONLY, 0)) != 0) {
310                                 dbenv->err(dbenv, ret, "DB->open: %s", db);
311                                 goto err;
312                         }
313                 }
314
315                 /* Check if cache is too small for this DB's pagesize. */
316                 if (private) {
317                         if ((ret = __db_util_cache(dbp, &cache, &resize)) != 0)
318                                 goto err;
319                         if (resize) {
320                                 (void)dbp->close(dbp, DB_NOSYNC);
321                                 dbp = NULL;
322
323                                 (void)dbenv->close(dbenv, 0);
324                                 dbenv = NULL;
325                                 goto retry;
326                         }
327                 }
328
329                 if (dbp->stat_print(dbp, flags))
330                         goto err;
331                 break;
332         case T_ENV:
333                 if (dbenv->stat_print(dbenv, flags))
334                         goto err;
335                 break;
336         case T_LOCK:
337                 if (dbenv->lock_stat_print(dbenv, flags))
338                         goto err;
339                 break;
340         case T_LOG:
341                 if (dbenv->log_stat_print(dbenv, flags))
342                         goto err;
343                 break;
344         case T_MPOOL:
345                 if (dbenv->memp_stat_print(dbenv, flags))
346                         goto err;
347                 break;
348         case T_MUTEX:
349                 if (dbenv->mutex_stat_print(dbenv, flags))
350                         goto err;
351                 break;
352         case T_REP:
353 #ifdef HAVE_REPLICATION_THREADS
354                 if (dbenv->repmgr_stat_print(dbenv, flags))
355                         goto err;
356 #endif
357                 if (dbenv->rep_stat_print(dbenv, flags))
358                         goto err;
359                 break;
360         case T_TXN:
361                 if (dbenv->txn_stat_print(dbenv, flags))
362                         goto err;
363                 break;
364         case T_NOTSET:
365                 dbenv->errx(dbenv, DB_STR("5007",
366                     "Unknown statistics flag"));
367                 goto err;
368         }
369
370         if (0) {
371 err:            exitval = 1;
372         }
373         if (dbp != NULL && (ret = dbp->close(dbp, DB_NOSYNC)) != 0) {
374                 exitval = 1;
375                 dbenv->err(dbenv, ret, DB_STR("5008", "close"));
376         }
377         if (dbenv != NULL && (ret = dbenv->close(dbenv, 0)) != 0) {
378                 exitval = 1;
379                 fprintf(stderr,
380                     "%s: dbenv->close: %s\n", progname, db_strerror(ret));
381         }
382
383         if (passwd != NULL)
384                 free(passwd);
385
386         /* Resend any caught signal. */
387         __db_util_sigresend();
388
389         return (exitval == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
390 }
391
392 /*
393  * db_init --
394  *      Initialize the environment.
395  */
396 int
397 db_init(dbenv, home, ttype, cache, is_private)
398         DB_ENV *dbenv;
399         char *home;
400         test_t ttype;
401         u_int32_t cache;
402         int *is_private;
403 {
404         u_int32_t oflags;
405         int ret;
406
407         /*
408          * If our environment open fails, and we're trying to look at a
409          * shared region, it's a hard failure.
410          *
411          * We will probably just drop core if the environment we join does
412          * not include a memory pool.  This is probably acceptable; trying
413          * to use an existing environment that does not contain a memory
414          * pool to look at a database can be safely construed as operator
415          * error, I think.
416          */
417         *is_private = 0;
418         if ((ret = dbenv->open(dbenv, home, DB_USE_ENVIRON, 0)) == 0)
419                 return (0);
420         if (ret == DB_VERSION_MISMATCH)
421                 goto err;
422         if (ttype != T_DB && ttype != T_LOG) {
423                 dbenv->err(dbenv, ret, "DB_ENV->open%s%s",
424                     home == NULL ? "" : ": ", home == NULL ? "" : home);
425                 return (1);
426         }
427
428         /*
429          * We're looking at a database or set of log files and no environment
430          * exists.  Create one, but make it private so no files are actually
431          * created.  Declare a reasonably large cache so that we don't fail
432          * when reporting statistics on large databases.
433          *
434          * An environment is required to look at databases because we may be
435          * trying to look at databases in directories other than the current
436          * one.
437          */
438         if ((ret = dbenv->set_cachesize(dbenv, 0, cache, 1)) != 0) {
439                 dbenv->err(dbenv, ret, "set_cachesize");
440                 return (1);
441         }
442         *is_private = 1;
443         oflags = DB_CREATE | DB_PRIVATE | DB_USE_ENVIRON;
444         if (ttype == T_DB)
445                 oflags |= DB_INIT_MPOOL;
446         if (ttype == T_LOG)
447                 oflags |= DB_INIT_LOG;
448         if ((ret = dbenv->open(dbenv, home, oflags, 0)) == 0)
449                 return (0);
450
451         /* An environment is required. */
452 err:    dbenv->err(dbenv, ret, "DB_ENV->open");
453         return (1);
454 }
455
456 int
457 usage()
458 {
459         fprintf(stderr, "usage: %s %s\n", progname,
460             "-d file [-fN] [-h home] [-P password] [-s database]");
461         fprintf(stderr, "usage: %s %s\n\t%s\n", progname,
462             "[-cEelmrtVx] [-C Aclop]",
463             "[-h home] [-L A] [-M A] [-P password] [-R A] [-X A] [-aNZ]");
464         return (EXIT_FAILURE);
465 }
466
467 int
468 version_check()
469 {
470         int v_major, v_minor, v_patch;
471
472         /* Make sure we're loaded with the right version of the DB library. */
473         (void)db_version(&v_major, &v_minor, &v_patch);
474         if (v_major != DB_VERSION_MAJOR || v_minor != DB_VERSION_MINOR) {
475                 fprintf(stderr, DB_STR_A("5009",
476                     "%s: version %d.%d doesn't match library version %d.%d\n",
477                     "%s %d %d %d %d\n"), progname,
478                     DB_VERSION_MAJOR, DB_VERSION_MINOR,
479                     v_major, v_minor);
480                 return (EXIT_FAILURE);
481         }
482         return (0);
483 }