1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996,2008 Oracle. All rights reserved. 5 * 6 * $Id: db_deadlock.c,v 12.22 2008/01/08 20:58:13 bostic Exp $ 7 */ 8 9#include "db_config.h" 10 11#include "db_int.h" 12 13#ifndef lint 14static const char copyright[] = 15 "Copyright (c) 1996,2008 Oracle. All rights reserved.\n"; 16#endif 17 18int main __P((int, char *[])); 19int usage __P((void)); 20int version_check __P((void)); 21 22const char *progname; 23 24int 25main(argc, argv) 26 int argc; 27 char *argv[]; 28{ 29 extern char *optarg; 30 extern int optind; 31 DB_ENV *dbenv; 32 u_int32_t atype; 33 time_t now; 34 u_long secs, usecs; 35 int rejected, ch, exitval, ret, verbose; 36 char *home, *logfile, *passwd, *str, time_buf[CTIME_BUFLEN]; 37 38 if ((progname = __db_rpath(argv[0])) == NULL) 39 progname = argv[0]; 40 else 41 ++progname; 42 43 if ((ret = version_check()) != 0) 44 return (ret); 45 46 dbenv = NULL; 47 atype = DB_LOCK_DEFAULT; 48 home = logfile = passwd = NULL; 49 secs = usecs = 0; 50 exitval = verbose = 0; 51 while ((ch = getopt(argc, argv, "a:h:L:P:t:Vv")) != EOF) 52 switch (ch) { 53 case 'a': 54 switch (optarg[0]) { 55 case 'e': 56 atype = DB_LOCK_EXPIRE; 57 break; 58 case 'm': 59 atype = DB_LOCK_MAXLOCKS; 60 break; 61 case 'n': 62 atype = DB_LOCK_MINLOCKS; 63 break; 64 case 'o': 65 atype = DB_LOCK_OLDEST; 66 break; 67 case 'W': 68 atype = DB_LOCK_MAXWRITE; 69 break; 70 case 'w': 71 atype = DB_LOCK_MINWRITE; 72 break; 73 case 'y': 74 atype = DB_LOCK_YOUNGEST; 75 break; 76 default: 77 return (usage()); 78 /* NOTREACHED */ 79 } 80 if (optarg[1] != '\0') 81 return (usage()); 82 break; 83 case 'h': 84 home = optarg; 85 break; 86 case 'L': 87 logfile = optarg; 88 break; 89 case 'P': 90 passwd = strdup(optarg); 91 memset(optarg, 0, strlen(optarg)); 92 if (passwd == NULL) { 93 fprintf(stderr, "%s: strdup: %s\n", 94 progname, strerror(errno)); 95 return (EXIT_FAILURE); 96 } 97 break; 98 case 't': 99 if ((str = strchr(optarg, '.')) != NULL) { 100 *str++ = '\0'; 101 if (*str != '\0' && __db_getulong( 102 NULL, progname, str, 0, LONG_MAX, &usecs)) 103 return (EXIT_FAILURE); 104 } 105 if (*optarg != '\0' && __db_getulong( 106 NULL, progname, optarg, 0, LONG_MAX, &secs)) 107 return (EXIT_FAILURE); 108 if (secs == 0 && usecs == 0) 109 return (usage()); 110 111 break; 112 case 'V': 113 printf("%s\n", db_version(NULL, NULL, NULL)); 114 return (EXIT_SUCCESS); 115 case 'v': 116 verbose = 1; 117 break; 118 case '?': 119 default: 120 return (usage()); 121 } 122 argc -= optind; 123 argv += optind; 124 125 if (argc != 0) 126 return (usage()); 127 128 /* Handle possible interruptions. */ 129 __db_util_siginit(); 130 131 /* Log our process ID. */ 132 if (logfile != NULL && __db_util_logset(progname, logfile)) 133 goto shutdown; 134 135 /* 136 * Create an environment object and initialize it for error 137 * reporting. 138 */ 139 if ((ret = db_env_create(&dbenv, 0)) != 0) { 140 fprintf(stderr, 141 "%s: db_env_create: %s\n", progname, db_strerror(ret)); 142 goto shutdown; 143 } 144 145 dbenv->set_errfile(dbenv, stderr); 146 dbenv->set_errpfx(dbenv, progname); 147 148 if (passwd != NULL && (ret = dbenv->set_encrypt(dbenv, 149 passwd, DB_ENCRYPT_AES)) != 0) { 150 dbenv->err(dbenv, ret, "set_passwd"); 151 goto shutdown; 152 } 153 154 if (verbose) { 155 (void)dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK, 1); 156 (void)dbenv->set_verbose(dbenv, DB_VERB_WAITSFOR, 1); 157 } 158 159 /* An environment is required. */ 160 if ((ret = dbenv->open(dbenv, home, DB_USE_ENVIRON, 0)) != 0) { 161 dbenv->err(dbenv, ret, "open"); 162 goto shutdown; 163 } 164 165 while (!__db_util_interrupted()) { 166 if (verbose) { 167 (void)time(&now); 168 dbenv->errx(dbenv, 169 "running at %.24s", __os_ctime(&now, time_buf)); 170 } 171 172 if ((ret = 173 dbenv->lock_detect(dbenv, 0, atype, &rejected)) != 0) { 174 dbenv->err(dbenv, ret, "DB_ENV->lock_detect"); 175 goto shutdown; 176 } 177 if (verbose) 178 dbenv->errx(dbenv, "rejected %d locks", rejected); 179 180 /* Make a pass every "secs" secs and "usecs" usecs. */ 181 if (secs == 0 && usecs == 0) 182 break; 183 __os_yield(dbenv->env, secs, usecs); 184 } 185 186 if (0) { 187shutdown: exitval = 1; 188 } 189 190 /* Clean up the logfile. */ 191 if (logfile != NULL) 192 (void)remove(logfile); 193 194 /* Clean up the environment. */ 195 if (dbenv != NULL && (ret = dbenv->close(dbenv, 0)) != 0) { 196 exitval = 1; 197 fprintf(stderr, 198 "%s: dbenv->close: %s\n", progname, db_strerror(ret)); 199 } 200 201 if (passwd != NULL) 202 free(passwd); 203 204 /* Resend any caught signal. */ 205 __db_util_sigresend(); 206 207 return (exitval == 0 ? EXIT_SUCCESS : EXIT_FAILURE); 208} 209 210int 211usage() 212{ 213 (void)fprintf(stderr, 214 "usage: %s [-Vv] [-a e | m | n | o | W | w | y]\n\t%s\n", progname, 215 "[-h home] [-L file] [-P password] [-t sec.usec]"); 216 return (EXIT_FAILURE); 217} 218 219int 220version_check() 221{ 222 int v_major, v_minor, v_patch; 223 224 /* Make sure we're loaded with the right version of the DB library. */ 225 (void)db_version(&v_major, &v_minor, &v_patch); 226 if (v_major != DB_VERSION_MAJOR || v_minor != DB_VERSION_MINOR) { 227 fprintf(stderr, 228 "%s: version %d.%d doesn't match library version %d.%d\n", 229 progname, DB_VERSION_MAJOR, DB_VERSION_MINOR, 230 v_major, v_minor); 231 return (EXIT_FAILURE); 232 } 233 return (0); 234} 235