00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "db_config.h"
00011
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014
00015 #if TIME_WITH_SYS_TIME
00016 #include <sys/time.h>
00017 #include <time.h>
00018 #else
00019 #if HAVE_SYS_TIME_H
00020 #include <sys/time.h>
00021 #else
00022 #include <time.h>
00023 #endif
00024 #endif
00025
00026 #include <rpc/rpc.h>
00027
00028 #include <limits.h>
00029 #include <signal.h>
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <unistd.h>
00034 #endif
00035
00036 #include "db_server.h"
00037
00038 #include "db_int.h"
00039 #include "db_cxx.h"
00040 #include "dbinc_auto/clib_ext.h"
00041
00042 extern "C" {
00043 #include "dbinc/db_server_int.h"
00044 #include "dbinc_auto/rpc_server_ext.h"
00045 #include "dbinc_auto/common_ext.h"
00046
00047 extern int __dbsrv_main __P((void));
00048 }
00049
00050 static int add_home __P((char *));
00051 static int add_passwd __P((char *));
00052 static int env_recover __P((char *));
00053 static void __dbclear_child __P((ct_entry *));
00054
00055 static LIST_HEAD(cthead, ct_entry) __dbsrv_head;
00056 static LIST_HEAD(homehead, home_entry) __dbsrv_home;
00057 static long __dbsrv_defto = DB_SERVER_TIMEOUT;
00058 static long __dbsrv_maxto = DB_SERVER_MAXTIMEOUT;
00059 static long __dbsrv_idleto = DB_SERVER_IDLETIMEOUT;
00060 static char *logfile = NULL;
00061 static char *prog;
00062
00063 static void usage __P((char *));
00064 static void version_check __P((void));
00065
00066 int __dbsrv_verbose = 0;
00067
00068 int
00069 main(
00070 int argc,
00071 char **argv)
00072 {
00073 extern char *optarg;
00074 CLIENT *cl;
00075 int ch, ret;
00076 char *passwd;
00077
00078 prog = argv[0];
00079
00080 version_check();
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 if ((cl = clnt_create("localhost",
00095 DB_RPC_SERVERPROG, DB_RPC_SERVERVERS, "tcp")) != NULL) {
00096 fprintf(stderr,
00097 "%s: Berkeley DB RPC server already running.\n", prog);
00098 clnt_destroy(cl);
00099 return (EXIT_FAILURE);
00100 }
00101
00102 LIST_INIT(&__dbsrv_home);
00103 while ((ch = getopt(argc, argv, "h:I:L:P:t:T:Vv")) != EOF)
00104 switch (ch) {
00105 case 'h':
00106 (void)add_home(optarg);
00107 break;
00108 case 'I':
00109 if (__db_getlong(NULL, prog,
00110 optarg, 1, LONG_MAX, &__dbsrv_idleto))
00111 return (EXIT_FAILURE);
00112 break;
00113 case 'L':
00114 logfile = optarg;
00115 break;
00116 case 'P':
00117 passwd = strdup(optarg);
00118 memset(optarg, 0, strlen(optarg));
00119 if (passwd == NULL) {
00120 fprintf(stderr, "%s: strdup: %s\n",
00121 prog, strerror(errno));
00122 return (EXIT_FAILURE);
00123 }
00124 if ((ret = add_passwd(passwd)) != 0) {
00125 fprintf(stderr, "%s: strdup: %s\n",
00126 prog, strerror(ret));
00127 return (EXIT_FAILURE);
00128 }
00129 break;
00130 case 't':
00131 if (__db_getlong(NULL, prog,
00132 optarg, 1, LONG_MAX, &__dbsrv_defto))
00133 return (EXIT_FAILURE);
00134 break;
00135 case 'T':
00136 if (__db_getlong(NULL, prog,
00137 optarg, 1, LONG_MAX, &__dbsrv_maxto))
00138 return (EXIT_FAILURE);
00139 break;
00140 case 'V':
00141 printf("%s\n", db_version(NULL, NULL, NULL));
00142 return (EXIT_SUCCESS);
00143 case 'v':
00144 __dbsrv_verbose = 1;
00145 break;
00146 default:
00147 usage(prog);
00148 }
00149
00150
00151
00152 if (__dbsrv_defto > __dbsrv_maxto)
00153 __dbsrv_defto = __dbsrv_maxto;
00154
00155
00156
00157
00158
00159 if (__dbsrv_defto > __dbsrv_idleto)
00160 fprintf(stderr,
00161 "%s: WARNING: Idle timeout %ld is less than resource timeout %ld\n",
00162 prog, __dbsrv_idleto, __dbsrv_defto);
00163
00164 LIST_INIT(&__dbsrv_head);
00165
00166
00167
00168
00169
00170 #ifdef SIGPIPE
00171 signal(SIGPIPE, SIG_IGN);
00172 #endif
00173
00174 if (logfile != NULL && __db_util_logset("berkeley_db_svc", logfile))
00175 return (EXIT_FAILURE);
00176
00177
00178
00179
00180
00181 if (env_recover(prog) != 0)
00182 return (EXIT_FAILURE);
00183
00184
00185
00186
00187 if (__dbsrv_verbose)
00188 printf("%s: Ready to receive requests\n", prog);
00189 __dbsrv_main();
00190
00191
00192 abort();
00193 }
00194
00195 static void
00196 usage(char *prog)
00197 {
00198 fprintf(stderr, "usage: %s %s\n\t%s\n", prog,
00199 "[-Vv] [-h home] [-P passwd]",
00200 "[-I idletimeout] [-L logfile] [-t def_timeout] [-T maxtimeout]");
00201 exit(EXIT_FAILURE);
00202 }
00203
00204 static void
00205 version_check()
00206 {
00207 int v_major, v_minor, v_patch;
00208
00209
00210 (void)db_version(&v_major, &v_minor, &v_patch);
00211 if (v_major != DB_VERSION_MAJOR ||
00212 v_minor != DB_VERSION_MINOR || v_patch != DB_VERSION_PATCH) {
00213 fprintf(stderr,
00214 "%s: version %d.%d.%d doesn't match library version %d.%d.%d\n",
00215 prog, DB_VERSION_MAJOR, DB_VERSION_MINOR,
00216 DB_VERSION_PATCH, v_major, v_minor, v_patch);
00217 exit(EXIT_FAILURE);
00218 }
00219 }
00220
00221 extern "C" void
00222 __dbsrv_settimeout(
00223 ct_entry *ctp,
00224 u_int32_t to)
00225 {
00226 if (to > (u_int32_t)__dbsrv_maxto)
00227 ctp->ct_timeout = __dbsrv_maxto;
00228 else if (to <= 0)
00229 ctp->ct_timeout = __dbsrv_defto;
00230 else
00231 ctp->ct_timeout = to;
00232 }
00233
00234 extern "C" void
00235 __dbsrv_timeout(int force)
00236 {
00237 static long to_hint = -1;
00238 time_t t;
00239 long to;
00240 ct_entry *ctp, *nextctp;
00241
00242 if ((t = time(NULL)) == -1)
00243 return;
00244
00245
00246
00247
00248
00249 if (!force && to_hint > 0 && t < to_hint)
00250 return;
00251 to_hint = -1;
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265 for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL; ctp = nextctp) {
00266 nextctp = LIST_NEXT(ctp, entries);
00267 switch (ctp->ct_type) {
00268 case CT_TXN:
00269 to = *(ctp->ct_activep) + ctp->ct_timeout;
00270
00271 if (to < t) {
00272 if (__dbsrv_verbose)
00273 printf("Timing out txn id %ld\n",
00274 ctp->ct_id);
00275 (void)((DbTxn *)ctp->ct_anyp)->abort();
00276 __dbdel_ctp(ctp);
00277
00278
00279
00280
00281
00282 nextctp = LIST_FIRST(&__dbsrv_head);
00283 } else if ((to_hint > 0 && to_hint > to) ||
00284 to_hint == -1)
00285 to_hint = to;
00286 break;
00287 case CT_CURSOR:
00288 case (CT_JOINCUR | CT_CURSOR):
00289 to = *(ctp->ct_activep) + ctp->ct_timeout;
00290
00291 if (to < t) {
00292 if (__dbsrv_verbose)
00293 printf("Timing out cursor %ld\n",
00294 ctp->ct_id);
00295 (void)__dbc_close_int(ctp);
00296
00297
00298
00299 nextctp = LIST_FIRST(&__dbsrv_head);
00300 } else if ((to_hint > 0 && to_hint > to) ||
00301 to_hint == -1)
00302 to_hint = to;
00303 break;
00304 default:
00305 break;
00306 }
00307 }
00308
00309
00310
00311
00312 for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL; ctp = nextctp) {
00313 nextctp = LIST_NEXT(ctp, entries);
00314 if (ctp->ct_type != CT_ENV)
00315 continue;
00316 to = *(ctp->ct_activep) + ctp->ct_idle;
00317
00318 if (to < t || force) {
00319 if (__dbsrv_verbose)
00320 printf("Timing out env id %ld\n", ctp->ct_id);
00321 (void)__env_close_int(ctp->ct_id, 0, 1);
00322
00323
00324
00325
00326
00327 nextctp = LIST_FIRST(&__dbsrv_head);
00328 }
00329 }
00330 }
00331
00332
00333
00334
00335
00336 static void
00337 __dbclear_child(ct_entry *parent)
00338 {
00339 ct_entry *ctp, *nextctp;
00340
00341 for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL;
00342 ctp = nextctp) {
00343 nextctp = LIST_NEXT(ctp, entries);
00344 if (ctp->ct_type == 0)
00345 continue;
00346 if (ctp->ct_parent == parent) {
00347 __dbclear_child(ctp);
00348
00349
00350
00351
00352
00353 nextctp = LIST_NEXT(ctp, entries);
00354 __dbclear_ctp(ctp);
00355 }
00356 }
00357 }
00358
00359 extern "C" void
00360 __dbclear_ctp(ct_entry *ctp)
00361 {
00362 LIST_REMOVE(ctp, entries);
00363 __os_free(NULL, ctp);
00364 }
00365
00366 extern "C" void
00367 __dbdel_ctp(ct_entry *parent)
00368 {
00369 __dbclear_child(parent);
00370 __dbclear_ctp(parent);
00371 }
00372
00373 extern "C" ct_entry *
00374 new_ct_ent(int *errp)
00375 {
00376 time_t t;
00377 ct_entry *ctp, *octp;
00378 int ret;
00379
00380 if ((ret = __os_malloc(NULL, sizeof(ct_entry), &ctp)) != 0) {
00381 *errp = ret;
00382 return (NULL);
00383 }
00384 memset(ctp, 0, sizeof(ct_entry));
00385
00386
00387
00388
00389
00390
00391
00392 if ((t = time(NULL)) == -1) {
00393 *errp = __os_get_errno();
00394 __os_free(NULL, ctp);
00395 return (NULL);
00396 }
00397 octp = LIST_FIRST(&__dbsrv_head);
00398 if (octp != NULL && octp->ct_id >= t)
00399 t = octp->ct_id + 1;
00400 ctp->ct_id = t;
00401 ctp->ct_idle = __dbsrv_idleto;
00402 ctp->ct_activep = &ctp->ct_active;
00403 ctp->ct_origp = NULL;
00404 ctp->ct_refcount = 1;
00405
00406 LIST_INSERT_HEAD(&__dbsrv_head, ctp, entries);
00407 return (ctp);
00408 }
00409
00410 extern "C" ct_entry *
00411 get_tableent(long id)
00412 {
00413 ct_entry *ctp;
00414
00415 for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL;
00416 ctp = LIST_NEXT(ctp, entries))
00417 if (ctp->ct_id == id)
00418 return (ctp);
00419 return (NULL);
00420 }
00421
00422 extern "C" ct_entry *
00423 __dbsrv_sharedb(ct_entry *db_ctp,
00424 const char *name, const char *subdb, DBTYPE type, u_int32_t flags)
00425 {
00426 ct_entry *ctp;
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439 if (flags & DB_SERVER_DBNOSHARE)
00440 return (NULL);
00441 for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL;
00442 ctp = LIST_NEXT(ctp, entries)) {
00443
00444
00445
00446 if (ctp == db_ctp)
00447 continue;
00448 if (ctp->ct_type != CT_DB)
00449 continue;
00450 if (ctp->ct_envparent != db_ctp->ct_envparent)
00451 continue;
00452 if (type != DB_UNKNOWN && ctp->ct_dbdp.type != type)
00453 continue;
00454 if (ctp->ct_dbdp.dbflags != LF_ISSET(DB_SERVER_DBFLAGS))
00455 continue;
00456 if (db_ctp->ct_dbdp.setflags != 0 &&
00457 ctp->ct_dbdp.setflags != db_ctp->ct_dbdp.setflags)
00458 continue;
00459 if (name == NULL || ctp->ct_dbdp.db == NULL ||
00460 strcmp(name, ctp->ct_dbdp.db) != 0)
00461 continue;
00462 if (subdb != ctp->ct_dbdp.subdb &&
00463 (subdb == NULL || ctp->ct_dbdp.subdb == NULL ||
00464 strcmp(subdb, ctp->ct_dbdp.subdb) != 0))
00465 continue;
00466
00467
00468
00469 ctp->ct_refcount++;
00470 return (ctp);
00471 }
00472
00473 return (NULL);
00474 }
00475
00476 extern "C" ct_entry *
00477 __dbsrv_shareenv(ct_entry *env_ctp, home_entry *home, u_int32_t flags)
00478 {
00479 ct_entry *ctp;
00480
00481
00482
00483
00484
00485
00486
00487 for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL;
00488 ctp = LIST_NEXT(ctp, entries)) {
00489
00490
00491
00492 if (ctp == env_ctp)
00493 continue;
00494 if (ctp->ct_type != CT_ENV)
00495 continue;
00496 if (ctp->ct_envdp.home != home)
00497 continue;
00498 if (ctp->ct_envdp.envflags != flags)
00499 continue;
00500 if (ctp->ct_envdp.onflags != env_ctp->ct_envdp.onflags)
00501 continue;
00502 if (ctp->ct_envdp.offflags != env_ctp->ct_envdp.offflags)
00503 continue;
00504
00505
00506
00507
00508
00509
00510 if (ctp->ct_timeout < env_ctp->ct_timeout)
00511 ctp->ct_timeout = env_ctp->ct_timeout;
00512 ctp->ct_refcount++;
00513 return (ctp);
00514 }
00515
00516 return (NULL);
00517 }
00518
00519 extern "C" void
00520 __dbsrv_active(ct_entry *ctp)
00521 {
00522 time_t t;
00523 ct_entry *envctp;
00524
00525 if (ctp == NULL)
00526 return;
00527 if ((t = time(NULL)) == -1)
00528 return;
00529 *(ctp->ct_activep) = t;
00530 if ((envctp = ctp->ct_envparent) == NULL)
00531 return;
00532 *(envctp->ct_activep) = t;
00533 return;
00534 }
00535
00536 extern "C" int
00537 __db_close_int(long id, u_int32_t flags)
00538 {
00539 Db *dbp;
00540 int ret;
00541 ct_entry *ctp;
00542
00543 ret = 0;
00544 ctp = get_tableent(id);
00545 if (ctp == NULL)
00546 return (DB_NOSERVER_ID);
00547 DB_ASSERT(ctp->ct_type == CT_DB);
00548 if (__dbsrv_verbose && ctp->ct_refcount != 1)
00549 printf("Deref'ing dbp id %ld, refcount %d\n",
00550 id, ctp->ct_refcount);
00551 if (--ctp->ct_refcount != 0)
00552 return (ret);
00553 dbp = ctp->ct_dbp;
00554 if (__dbsrv_verbose)
00555 printf("Closing dbp id %ld\n", id);
00556
00557 ret = dbp->close(flags);
00558 __dbdel_ctp(ctp);
00559 return (ret);
00560 }
00561
00562 extern "C" int
00563 __dbc_close_int(ct_entry *dbc_ctp)
00564 {
00565 Dbc *dbc;
00566 int ret;
00567 ct_entry *ctp;
00568
00569 dbc = (Dbc *)dbc_ctp->ct_anyp;
00570
00571 ret = dbc->close();
00572
00573
00574
00575
00576 if (dbc_ctp->ct_type & CT_JOINCUR)
00577 for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL;
00578 ctp = LIST_NEXT(ctp, entries)) {
00579
00580
00581
00582
00583 if ((ctp->ct_type & CT_JOIN) &&
00584 ctp->ct_activep == &dbc_ctp->ct_active) {
00585 ctp->ct_type &= ~CT_JOIN;
00586 ctp->ct_activep = ctp->ct_origp;
00587 __dbsrv_active(ctp);
00588 }
00589 }
00590 __dbclear_ctp(dbc_ctp);
00591 return (ret);
00592
00593 }
00594
00595 extern "C" int
00596 __env_close_int(long id, u_int32_t flags, int force)
00597 {
00598 DbEnv *dbenv;
00599 int ret;
00600 ct_entry *ctp, *dbctp, *nextctp;
00601
00602 ret = 0;
00603 ctp = get_tableent(id);
00604 if (ctp == NULL)
00605 return (DB_NOSERVER_ID);
00606 DB_ASSERT(ctp->ct_type == CT_ENV);
00607 if (__dbsrv_verbose && ctp->ct_refcount != 1)
00608 printf("Deref'ing env id %ld, refcount %d\n",
00609 id, ctp->ct_refcount);
00610
00611
00612
00613
00614 if (--ctp->ct_refcount != 0 && !force)
00615 return (ret);
00616 dbenv = ctp->ct_envp;
00617 if (__dbsrv_verbose)
00618 printf("Closing env id %ld\n", id);
00619
00620
00621
00622
00623
00624
00625 if (force)
00626 for (dbctp = LIST_FIRST(&__dbsrv_head);
00627 dbctp != NULL; dbctp = nextctp) {
00628 nextctp = LIST_NEXT(dbctp, entries);
00629 if (dbctp->ct_type != CT_DB)
00630 continue;
00631 if (dbctp->ct_envparent != ctp)
00632 continue;
00633
00634
00635
00636
00637 __db_close_int(dbctp->ct_id, 0);
00638
00639
00640
00641
00642
00643 nextctp = LIST_FIRST(&__dbsrv_head);
00644 }
00645
00646 ret = dbenv->close(flags);
00647 __dbdel_ctp(ctp);
00648 return (ret);
00649 }
00650
00651 static int
00652 add_home(char *home)
00653 {
00654 home_entry *hp, *homep;
00655 int ret;
00656
00657 if ((ret = __os_malloc(NULL, sizeof(home_entry), &hp)) != 0)
00658 return (ret);
00659 if ((ret = __os_malloc(NULL, strlen(home)+1, &hp->home)) != 0)
00660 return (ret);
00661 memcpy(hp->home, home, strlen(home)+1);
00662 hp->dir = home;
00663 hp->passwd = NULL;
00664
00665
00666
00667
00668 hp->name = __db_rpath(home);
00669 if (hp->name != NULL) {
00670 *(hp->name) = '\0';
00671 hp->name++;
00672 } else
00673 hp->name = home;
00674 while (*(hp->name) == '\0') {
00675 hp->name = __db_rpath(home);
00676 *(hp->name) = '\0';
00677 hp->name++;
00678 }
00679
00680
00681
00682
00683 for (homep = LIST_FIRST(&__dbsrv_home); homep != NULL;
00684 homep = LIST_NEXT(homep, entries))
00685 if (strcmp(homep->name, hp->name) == 0) {
00686 printf("Already added home name %s, at directory %s\n",
00687 hp->name, homep->dir);
00688 return (-1);
00689 }
00690 LIST_INSERT_HEAD(&__dbsrv_home, hp, entries);
00691 if (__dbsrv_verbose)
00692 printf("Added home %s in dir %s\n", hp->name, hp->dir);
00693 return (0);
00694 }
00695
00696 static int
00697 add_passwd(char *passwd)
00698 {
00699 home_entry *hp;
00700
00701
00702
00703
00704
00705
00706 hp = LIST_FIRST(&__dbsrv_home);
00707 if (hp == NULL || hp->passwd != NULL)
00708 return (EINVAL);
00709
00710
00711
00712
00713 hp->passwd = passwd;
00714 return (0);
00715 }
00716
00717 extern "C" home_entry *
00718 get_fullhome(char *name)
00719 {
00720 home_entry *hp;
00721
00722 if (name == NULL)
00723 return (NULL);
00724
00725 for (hp = LIST_FIRST(&__dbsrv_home); hp != NULL;
00726 hp = LIST_NEXT(hp, entries))
00727 if (strcmp(name, hp->name) == 0)
00728 return (hp);
00729 return (NULL);
00730 }
00731
00732 static int
00733 env_recover(char *progname)
00734 {
00735 DbEnv *dbenv;
00736 home_entry *hp;
00737 u_int32_t flags;
00738 int exitval, ret;
00739
00740 for (hp = LIST_FIRST(&__dbsrv_home); hp != NULL;
00741 hp = LIST_NEXT(hp, entries)) {
00742 exitval = 0;
00743 dbenv = new DbEnv(DB_CXX_NO_EXCEPTIONS);
00744 if (__dbsrv_verbose == 1)
00745 (void)dbenv->set_verbose(DB_VERB_RECOVERY, 1);
00746 dbenv->set_errfile(stderr);
00747 dbenv->set_errpfx(progname);
00748 if (hp->passwd != NULL)
00749 (void)dbenv->set_encrypt(hp->passwd, DB_ENCRYPT_AES);
00750
00751
00752
00753
00754
00755 if (__dbsrv_verbose)
00756 printf("Running recovery on %s\n", hp->home);
00757 flags = DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL |
00758 DB_INIT_TXN | DB_USE_ENVIRON | DB_RECOVER;
00759 if ((ret = dbenv->open(hp->home, flags, 0)) != 0) {
00760 dbenv->err(ret, "DbEnv->open");
00761 goto error;
00762 }
00763
00764 if (0) {
00765 error: exitval = 1;
00766 }
00767 if ((ret = dbenv->close(0)) != 0) {
00768 exitval = 1;
00769 fprintf(stderr, "%s: dbenv->close: %s\n",
00770 progname, db_strerror(ret));
00771 }
00772 if (exitval)
00773 return (exitval);
00774 }
00775 return (0);
00776 }