Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

db_server_cxxutil.cpp

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 2000-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: db_server_cxxutil.cpp,v 12.2 2005/06/16 20:23:40 bostic Exp $
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          * Check whether another server is running or not.  There
00084          * is a race condition where two servers could be racing to
00085          * register with the portmapper.  The goal of this check is to
00086          * forbid running additional servers (like those started from
00087          * the test suite) if the user is already running one.
00088          *
00089          * XXX
00090          * This does not solve nor prevent two servers from being
00091          * started at the same time and running recovery at the same
00092          * time on the same environments.
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          * Check default timeout against maximum timeout
00151          */
00152         if (__dbsrv_defto > __dbsrv_maxto)
00153                 __dbsrv_defto = __dbsrv_maxto;
00154 
00155         /*
00156          * Check default timeout against idle timeout
00157          * It would be bad to timeout environments sooner than txns.
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          * If a client crashes during an RPC, our reply to it
00168          * generates a SIGPIPE.  Ignore SIGPIPE so we don't exit unnecessarily.
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          * Now that we are ready to start, run recovery on all the
00179          * environments specified.
00180          */
00181         if (env_recover(prog) != 0)
00182                 return (EXIT_FAILURE);
00183 
00184         /*
00185          * We've done our setup, now call the generated server loop
00186          */
00187         if (__dbsrv_verbose)
00188                 printf("%s:  Ready to receive requests\n", prog);
00189         __dbsrv_main();
00190 
00191         /* NOTREACHED */
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         /* Make sure we're loaded with the right version of the DB library. */
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          * Check hint.  If hint is further in the future
00247          * than now, no work to do.
00248          */
00249         if (!force && to_hint > 0 && t < to_hint)
00250                 return;
00251         to_hint = -1;
00252         /*
00253          * Timeout transactions or cursors holding DB resources.
00254          * Do this before timing out envs to properly release resources.
00255          *
00256          * !!!
00257          * We can just loop through this list looking for cursors and txns.
00258          * We do not need to verify txn and cursor relationships at this
00259          * point because we maintain the list in LIFO order *and* we
00260          * maintain activity in the ultimate txn parent of any cursor
00261          * so either everything in a txn is timing out, or nothing.
00262          * So, since we are LIFO, we will correctly close/abort all the
00263          * appropriate handles, in the correct order.
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                         /* TIMEOUT */
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                                  * If we timed out an txn, we may have closed
00279                                  * all sorts of ctp's.
00280                                  * So start over with a guaranteed good ctp.
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                         /* TIMEOUT */
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                                  * Start over with a guaranteed good ctp.
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          * Timeout idle handles.
00310          * If we are forcing a timeout, we'll close all env handles.
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                 /* TIMEOUT */
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                          * If we timed out an env, we may have closed
00324                          * all sorts of ctp's (maybe even all of them.
00325                          * So start over with a guaranteed good ctp.
00326                          */
00327                         nextctp = LIST_FIRST(&__dbsrv_head);
00328                 }
00329         }
00330 }
00331 
00332 /*
00333  * RECURSIVE FUNCTION.  We need to clear/free any number of levels of nested
00334  * layers.
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                          * Need to do this here because le_next may
00350                          * have changed with the recursive call and we
00351                          * don't want to point to a removed entry.
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          * Get the time as ID.  We may service more than one request per
00387          * second however.  If we are, then increment id value until we
00388          * find an unused one.  We insert entries in LRU fashion at the
00389          * head of the list.  So, if the first entry doesn't match, then
00390          * we know for certain that we can use our entry.
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          * Check if we can share a db handle.  Criteria for sharing are:
00430          * If any of the non-sharable flags are set, we cannot share.
00431          * Must be a db ctp, obviously.
00432          * Must share the same env parent.
00433          * Must be the same type, or current one DB_UNKNOWN.
00434          * Must be same byteorder, or current one must not care.
00435          * All flags must match.
00436          * Must be same name, but don't share in-memory databases.
00437          * Must be same subdb name.
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                  * Skip ourselves.
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                  * If we get here, then we match.
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          * Check if we can share an env.  Criteria for sharing are:
00483          * Must be an env ctp, obviously.
00484          * Must share the same home env.
00485          * All flags must match.
00486          */
00487         for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL;
00488             ctp = LIST_NEXT(ctp, entries)) {
00489                 /*
00490                  * Skip ourselves.
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                  * If we get here, then we match.  The only thing left to
00506                  * check is the timeout.  Since the server timeout set by
00507                  * the client is a hint, for sharing we'll give them the
00508                  * benefit of the doubt and grant them the longer timeout.
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          * If this cursor is a join cursor then we need to fix up the
00574          * cursors that it was joined from so that they are independent again.
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                          * Test if it is a join cursor, and if it is part
00581                          * of this one.
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          * If we are timing out, we need to force the close, no matter
00612          * what the refcount.
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          * If we're timing out an env, we want to close all of its
00622          * database handles as well.  All of the txns and cursors
00623          * must have been timed out prior to timing out the env.
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                          * We found a DB handle that is part of this
00635                          * environment.  Close it.
00636                          */
00637                         __db_close_int(dbctp->ct_id, 0);
00638                         /*
00639                          * If we timed out a dbp, we may have removed
00640                          * multiple ctp entries.  Start over with a
00641                          * guaranteed good ctp.
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          * This loop is to remove any trailing path separators,
00666          * to assure hp->name points to the last component.
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          * Now we have successfully added it.  Make sure there are no
00681          * identical names.
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          * We add the passwd to the last given home dir.  If there
00703          * isn't a home dir, or the most recent one already has a
00704          * passwd, then there is a user error.
00705          */
00706         hp = LIST_FIRST(&__dbsrv_home);
00707         if (hp == NULL || hp->passwd != NULL)
00708                 return (EINVAL);
00709         /*
00710          * We've already strdup'ed the passwd above, so we don't need
00711          * to malloc new space, just point to it.
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                  * Initialize the env with DB_RECOVER.  That is all we
00753                  * have to do to run recovery.
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 }

Generated on Sun Dec 25 12:14:47 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2