~ubuntu-branches/ubuntu/maverick/evolution-data-server/maverick-proposed

« back to all changes in this revision

Viewing changes to libdb/rpc_server/c/db_server_util.c

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2010-05-17 17:02:06 UTC
  • mfrom: (1.10.5 upstream)
  • mto: This revision was merged to the branch mainline in revision 128.
  • Revision ID: james.westby@ubuntu.com-20100517170206-xu1wmjuy40nt2sk0
Tags: upstream-2.30.1
ImportĀ upstreamĀ versionĀ 2.30.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*-
2
 
 * See the file LICENSE for redistribution information.
3
 
 *
4
 
 * Copyright (c) 2000-2002
5
 
 *      Sleepycat Software.  All rights reserved.
6
 
 */
7
 
 
8
 
#include "db_config.h"
9
 
 
10
 
#ifndef lint
11
 
static const char revid[] = "$Id$";
12
 
#endif /* not lint */
13
 
 
14
 
#ifndef NO_SYSTEM_INCLUDES
15
 
#include <sys/types.h>
16
 
 
17
 
#if TIME_WITH_SYS_TIME
18
 
#include <sys/time.h>
19
 
#include <time.h>
20
 
#else
21
 
#if HAVE_SYS_TIME_H
22
 
#include <sys/time.h>
23
 
#else
24
 
#include <time.h>
25
 
#endif
26
 
#endif
27
 
 
28
 
#include <rpc/rpc.h>
29
 
 
30
 
#include <limits.h>
31
 
#include <signal.h>
32
 
#include <stdio.h>
33
 
#include <stdlib.h>
34
 
#include <string.h>
35
 
#include <unistd.h>
36
 
#endif
37
 
#include "dbinc_auto/db_server.h"
38
 
 
39
 
#include "db_int.h"
40
 
#include "dbinc_auto/clib_ext.h"
41
 
#include "dbinc/db_server_int.h"
42
 
#include "dbinc_auto/rpc_server_ext.h"
43
 
#include "dbinc_auto/common_ext.h"
44
 
 
45
 
extern int __dbsrv_main  __P((void));
46
 
static int add_home __P((char *));
47
 
static int add_passwd __P((char *));
48
 
static int env_recover __P((char *));
49
 
static void __dbclear_child __P((ct_entry *));
50
 
 
51
 
static LIST_HEAD(cthead, ct_entry) __dbsrv_head;
52
 
static LIST_HEAD(homehead, home_entry) __dbsrv_home;
53
 
static long __dbsrv_defto = DB_SERVER_TIMEOUT;
54
 
static long __dbsrv_maxto = DB_SERVER_MAXTIMEOUT;
55
 
static long __dbsrv_idleto = DB_SERVER_IDLETIMEOUT;
56
 
static char *logfile = NULL;
57
 
static char *prog;
58
 
 
59
 
static void usage __P((char *));
60
 
static void version_check __P((void));
61
 
 
62
 
int __dbsrv_verbose = 0;
63
 
 
64
 
int
65
 
main(argc, argv)
66
 
        int argc;
67
 
        char **argv;
68
 
{
69
 
        extern char *optarg;
70
 
        CLIENT *cl;
71
 
        int ch, ret;
72
 
        char *passwd;
73
 
 
74
 
        prog = argv[0];
75
 
 
76
 
        version_check();
77
 
 
78
 
        ret = 0;
79
 
        /*
80
 
         * Check whether another server is running or not.  There
81
 
         * is a race condition where two servers could be racing to
82
 
         * register with the portmapper.  The goal of this check is to
83
 
         * forbid running additional servers (like those started from
84
 
         * the test suite) if the user is already running one.
85
 
         *
86
 
         * XXX
87
 
         * This does not solve nor prevent two servers from being
88
 
         * started at the same time and running recovery at the same
89
 
         * time on the same environments.
90
 
         */
91
 
        if ((cl = clnt_create("localhost",
92
 
            DB_RPC_SERVERPROG, DB_RPC_SERVERVERS, "tcp")) != NULL) {
93
 
                fprintf(stderr,
94
 
                    "%s: Berkeley DB RPC server already running.\n", prog);
95
 
                clnt_destroy(cl);
96
 
                return (EXIT_FAILURE);
97
 
        }
98
 
 
99
 
        LIST_INIT(&__dbsrv_home);
100
 
        while ((ch = getopt(argc, argv, "h:I:L:P:t:T:Vv")) != EOF)
101
 
                switch (ch) {
102
 
                case 'h':
103
 
                        (void)add_home(optarg);
104
 
                        break;
105
 
                case 'I':
106
 
                        if (__db_getlong(NULL, prog,
107
 
                            optarg, 1, LONG_MAX, &__dbsrv_idleto))
108
 
                                return (EXIT_FAILURE);
109
 
                        break;
110
 
                case 'L':
111
 
                        logfile = optarg;
112
 
                        break;
113
 
                case 'P':
114
 
                        passwd = strdup(optarg);
115
 
                        memset(optarg, 0, strlen(optarg));
116
 
                        if (passwd == NULL) {
117
 
                                fprintf(stderr, "%s: strdup: %s\n",
118
 
                                    prog, strerror(errno));
119
 
                                return (EXIT_FAILURE);
120
 
                        }
121
 
                        if ((ret = add_passwd(passwd)) != 0) {
122
 
                                fprintf(stderr, "%s: strdup: %s\n",
123
 
                                    prog, strerror(ret));
124
 
                                return (EXIT_FAILURE);
125
 
                        }
126
 
                        break;
127
 
                case 't':
128
 
                        if (__db_getlong(NULL, prog,
129
 
                            optarg, 1, LONG_MAX, &__dbsrv_defto))
130
 
                                return (EXIT_FAILURE);
131
 
                        break;
132
 
                case 'T':
133
 
                        if (__db_getlong(NULL, prog,
134
 
                            optarg, 1, LONG_MAX, &__dbsrv_maxto))
135
 
                                return (EXIT_FAILURE);
136
 
                        break;
137
 
                case 'V':
138
 
                        printf("%s\n", db_version(NULL, NULL, NULL));
139
 
                        return (EXIT_SUCCESS);
140
 
                case 'v':
141
 
                        __dbsrv_verbose = 1;
142
 
                        break;
143
 
                default:
144
 
                        usage(prog);
145
 
                }
146
 
        /*
147
 
         * Check default timeout against maximum timeout
148
 
         */
149
 
        if (__dbsrv_defto > __dbsrv_maxto)
150
 
                __dbsrv_defto = __dbsrv_maxto;
151
 
 
152
 
        /*
153
 
         * Check default timeout against idle timeout
154
 
         * It would be bad to timeout environments sooner than txns.
155
 
         */
156
 
        if (__dbsrv_defto > __dbsrv_idleto)
157
 
                fprintf(stderr,
158
 
                    "%s: WARNING: Idle timeout %ld is less than resource timeout %ld\n",
159
 
                    prog, __dbsrv_idleto, __dbsrv_defto);
160
 
 
161
 
        LIST_INIT(&__dbsrv_head);
162
 
 
163
 
        /*
164
 
         * If a client crashes during an RPC, our reply to it
165
 
         * generates a SIGPIPE.  Ignore SIGPIPE so we don't exit unnecessarily.
166
 
         */
167
 
#ifdef SIGPIPE
168
 
        signal(SIGPIPE, SIG_IGN);
169
 
#endif
170
 
 
171
 
        if (logfile != NULL && __db_util_logset("berkeley_db_svc", logfile))
172
 
                return (EXIT_FAILURE);
173
 
 
174
 
        /*
175
 
         * Now that we are ready to start, run recovery on all the
176
 
         * environments specified.
177
 
         */
178
 
        if (env_recover(prog) != 0)
179
 
                return (EXIT_FAILURE);
180
 
 
181
 
        /*
182
 
         * We've done our setup, now call the generated server loop
183
 
         */
184
 
        if (__dbsrv_verbose)
185
 
                printf("%s:  Ready to receive requests\n", prog);
186
 
        __dbsrv_main();
187
 
 
188
 
        /* NOTREACHED */
189
 
        abort();
190
 
}
191
 
 
192
 
static void
193
 
usage(prog)
194
 
        char *prog;
195
 
{
196
 
        fprintf(stderr, "usage: %s %s\n\t%s\n", prog,
197
 
            "[-Vv] [-h home] [-P passwd]",
198
 
            "[-I idletimeout] [-L logfile] [-t def_timeout] [-T maxtimeout]");
199
 
        exit(EXIT_FAILURE);
200
 
}
201
 
 
202
 
static void
203
 
version_check()
204
 
{
205
 
        int v_major, v_minor, v_patch;
206
 
 
207
 
        /* Make sure we're loaded with the right version of the DB library. */
208
 
        (void)db_version(&v_major, &v_minor, &v_patch);
209
 
        if (v_major != DB_VERSION_MAJOR ||
210
 
            v_minor != DB_VERSION_MINOR || v_patch != DB_VERSION_PATCH) {
211
 
                fprintf(stderr,
212
 
        "%s: version %d.%d.%d doesn't match library version %d.%d.%d\n",
213
 
                    prog, DB_VERSION_MAJOR, DB_VERSION_MINOR,
214
 
                    DB_VERSION_PATCH, v_major, v_minor, v_patch);
215
 
                exit(EXIT_FAILURE);
216
 
        }
217
 
}
218
 
 
219
 
/*
220
 
 * PUBLIC: void __dbsrv_settimeout __P((ct_entry *, u_int32_t));
221
 
 */
222
 
void
223
 
__dbsrv_settimeout(ctp, to)
224
 
        ct_entry *ctp;
225
 
        u_int32_t to;
226
 
{
227
 
        if (to > (u_int32_t)__dbsrv_maxto)
228
 
                ctp->ct_timeout = __dbsrv_maxto;
229
 
        else if (to <= 0)
230
 
                ctp->ct_timeout = __dbsrv_defto;
231
 
        else
232
 
                ctp->ct_timeout = to;
233
 
}
234
 
 
235
 
/*
236
 
 * PUBLIC: void __dbsrv_timeout __P((int));
237
 
 */
238
 
void
239
 
__dbsrv_timeout(force)
240
 
        int force;
241
 
{
242
 
        static long to_hint = -1;
243
 
        time_t t;
244
 
        long to;
245
 
        ct_entry *ctp, *nextctp;
246
 
 
247
 
        if ((t = time(NULL)) == -1)
248
 
                return;
249
 
 
250
 
        /*
251
 
         * Check hint.  If hint is further in the future
252
 
         * than now, no work to do.
253
 
         */
254
 
        if (!force && to_hint > 0 && t < to_hint)
255
 
                return;
256
 
        to_hint = -1;
257
 
        /*
258
 
         * Timeout transactions or cursors holding DB resources.
259
 
         * Do this before timing out envs to properly release resources.
260
 
         *
261
 
         * !!!
262
 
         * We can just loop through this list looking for cursors and txns.
263
 
         * We do not need to verify txn and cursor relationships at this
264
 
         * point because we maintain the list in LIFO order *and* we
265
 
         * maintain activity in the ultimate txn parent of any cursor
266
 
         * so either everything in a txn is timing out, or nothing.
267
 
         * So, since we are LIFO, we will correctly close/abort all the
268
 
         * appropriate handles, in the correct order.
269
 
         */
270
 
        for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL; ctp = nextctp) {
271
 
                nextctp = LIST_NEXT(ctp, entries);
272
 
                switch (ctp->ct_type) {
273
 
                case CT_TXN:
274
 
                        to = *(ctp->ct_activep) + ctp->ct_timeout;
275
 
                        /* TIMEOUT */
276
 
                        if (to < t) {
277
 
                                if (__dbsrv_verbose)
278
 
                                        printf("Timing out txn id %ld\n",
279
 
                                            ctp->ct_id);
280
 
                                (void)((DB_TXN *)ctp->ct_anyp)->
281
 
                                    abort((DB_TXN *)ctp->ct_anyp);
282
 
                                __dbdel_ctp(ctp);
283
 
                                /*
284
 
                                 * If we timed out an txn, we may have closed
285
 
                                 * all sorts of ctp's.
286
 
                                 * So start over with a guaranteed good ctp.
287
 
                                 */
288
 
                                nextctp = LIST_FIRST(&__dbsrv_head);
289
 
                        } else if ((to_hint > 0 && to_hint > to) ||
290
 
                            to_hint == -1)
291
 
                                to_hint = to;
292
 
                        break;
293
 
                case CT_CURSOR:
294
 
                case (CT_JOINCUR | CT_CURSOR):
295
 
                        to = *(ctp->ct_activep) + ctp->ct_timeout;
296
 
                        /* TIMEOUT */
297
 
                        if (to < t) {
298
 
                                if (__dbsrv_verbose)
299
 
                                        printf("Timing out cursor %ld\n",
300
 
                                            ctp->ct_id);
301
 
                                (void)__dbc_close_int(ctp);
302
 
                                /*
303
 
                                 * Start over with a guaranteed good ctp.
304
 
                                 */
305
 
                                nextctp = LIST_FIRST(&__dbsrv_head);
306
 
                        } else if ((to_hint > 0 && to_hint > to) ||
307
 
                            to_hint == -1)
308
 
                                to_hint = to;
309
 
                        break;
310
 
                default:
311
 
                        break;
312
 
                }
313
 
        }
314
 
        /*
315
 
         * Timeout idle handles.
316
 
         * If we are forcing a timeout, we'll close all env handles.
317
 
         */
318
 
        for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL; ctp = nextctp) {
319
 
                nextctp = LIST_NEXT(ctp, entries);
320
 
                if (ctp->ct_type != CT_ENV)
321
 
                        continue;
322
 
                to = *(ctp->ct_activep) + ctp->ct_idle;
323
 
                /* TIMEOUT */
324
 
                if (to < t || force) {
325
 
                        if (__dbsrv_verbose)
326
 
                                printf("Timing out env id %ld\n", ctp->ct_id);
327
 
                        (void)__dbenv_close_int(ctp->ct_id, 0, 1);
328
 
                        /*
329
 
                         * If we timed out an env, we may have closed
330
 
                         * all sorts of ctp's (maybe even all of them.
331
 
                         * So start over with a guaranteed good ctp.
332
 
                         */
333
 
                        nextctp = LIST_FIRST(&__dbsrv_head);
334
 
                }
335
 
        }
336
 
}
337
 
 
338
 
/*
339
 
 * RECURSIVE FUNCTION.  We need to clear/free any number of levels of nested
340
 
 * layers.
341
 
 */
342
 
static void
343
 
__dbclear_child(parent)
344
 
        ct_entry *parent;
345
 
{
346
 
        ct_entry *ctp, *nextctp;
347
 
 
348
 
        for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL;
349
 
            ctp = nextctp) {
350
 
                nextctp = LIST_NEXT(ctp, entries);
351
 
                if (ctp->ct_type == 0)
352
 
                        continue;
353
 
                if (ctp->ct_parent == parent) {
354
 
                        __dbclear_child(ctp);
355
 
                        /*
356
 
                         * Need to do this here because le_next may
357
 
                         * have changed with the recursive call and we
358
 
                         * don't want to point to a removed entry.
359
 
                         */
360
 
                        nextctp = LIST_NEXT(ctp, entries);
361
 
                        __dbclear_ctp(ctp);
362
 
                }
363
 
        }
364
 
}
365
 
 
366
 
/*
367
 
 * PUBLIC: void __dbclear_ctp __P((ct_entry *));
368
 
 */
369
 
void
370
 
__dbclear_ctp(ctp)
371
 
        ct_entry *ctp;
372
 
{
373
 
        LIST_REMOVE(ctp, entries);
374
 
        __os_free(NULL, ctp);
375
 
}
376
 
 
377
 
/*
378
 
 * PUBLIC: void __dbdel_ctp __P((ct_entry *));
379
 
 */
380
 
void
381
 
__dbdel_ctp(parent)
382
 
        ct_entry *parent;
383
 
{
384
 
        __dbclear_child(parent);
385
 
        __dbclear_ctp(parent);
386
 
}
387
 
 
388
 
/*
389
 
 * PUBLIC: ct_entry *new_ct_ent __P((int *));
390
 
 */
391
 
ct_entry *
392
 
new_ct_ent(errp)
393
 
        int *errp;
394
 
{
395
 
        time_t t;
396
 
        ct_entry *ctp, *octp;
397
 
        int ret;
398
 
 
399
 
        if ((ret = __os_malloc(NULL, sizeof(ct_entry), &ctp)) != 0) {
400
 
                *errp = ret;
401
 
                return (NULL);
402
 
        }
403
 
        memset(ctp, 0, sizeof(ct_entry));
404
 
        /*
405
 
         * Get the time as ID.  We may service more than one request per
406
 
         * second however.  If we are, then increment id value until we
407
 
         * find an unused one.  We insert entries in LRU fashion at the
408
 
         * head of the list.  So, if the first entry doesn't match, then
409
 
         * we know for certain that we can use our entry.
410
 
         */
411
 
        if ((t = time(NULL)) == -1) {
412
 
                *errp = __os_get_errno();
413
 
                __os_free(NULL, ctp);
414
 
                return (NULL);
415
 
        }
416
 
        octp = LIST_FIRST(&__dbsrv_head);
417
 
        if (octp != NULL && octp->ct_id >= t)
418
 
                t = octp->ct_id + 1;
419
 
        ctp->ct_id = t;
420
 
        ctp->ct_idle = __dbsrv_idleto;
421
 
        ctp->ct_activep = &ctp->ct_active;
422
 
        ctp->ct_origp = NULL;
423
 
        ctp->ct_refcount = 1;
424
 
 
425
 
        LIST_INSERT_HEAD(&__dbsrv_head, ctp, entries);
426
 
        return (ctp);
427
 
}
428
 
 
429
 
/*
430
 
 * PUBLIC: ct_entry *get_tableent __P((long));
431
 
 */
432
 
ct_entry *
433
 
get_tableent(id)
434
 
        long id;
435
 
{
436
 
        ct_entry *ctp;
437
 
 
438
 
        for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL;
439
 
            ctp = LIST_NEXT(ctp, entries))
440
 
                if (ctp->ct_id == id)
441
 
                        return (ctp);
442
 
        return (NULL);
443
 
}
444
 
 
445
 
/*
446
 
 * PUBLIC: ct_entry *__dbsrv_sharedb __P((ct_entry *, const char *,
447
 
 * PUBLIC:    const char *, DBTYPE, u_int32_t));
448
 
 */
449
 
ct_entry *
450
 
__dbsrv_sharedb(db_ctp, name, subdb, type, flags)
451
 
        ct_entry *db_ctp;
452
 
        const char *name, *subdb;
453
 
        DBTYPE type;
454
 
        u_int32_t flags;
455
 
{
456
 
        ct_entry *ctp;
457
 
 
458
 
        /*
459
 
         * Check if we can share a db handle.  Criteria for sharing are:
460
 
         * If any of the non-sharable flags are set, we cannot share.
461
 
         * Must be a db ctp, obviously.
462
 
         * Must share the same env parent.
463
 
         * Must be the same type, or current one DB_UNKNOWN.
464
 
         * Must be same byteorder, or current one must not care.
465
 
         * All flags must match.
466
 
         * Must be same name, but don't share in-memory databases.
467
 
         * Must be same subdb name.
468
 
         */
469
 
        if (flags & DB_SERVER_DBNOSHARE)
470
 
                return (NULL);
471
 
        for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL;
472
 
            ctp = LIST_NEXT(ctp, entries)) {
473
 
                /*
474
 
                 * Skip ourselves.
475
 
                 */
476
 
                if (ctp == db_ctp)
477
 
                        continue;
478
 
                if (ctp->ct_type != CT_DB)
479
 
                        continue;
480
 
                if (ctp->ct_envparent != db_ctp->ct_envparent)
481
 
                        continue;
482
 
                if (type != DB_UNKNOWN && ctp->ct_dbdp.type != type)
483
 
                        continue;
484
 
                if (ctp->ct_dbdp.dbflags != LF_ISSET(DB_SERVER_DBFLAGS))
485
 
                        continue;
486
 
                if (db_ctp->ct_dbdp.setflags != 0 &&
487
 
                    ctp->ct_dbdp.setflags != db_ctp->ct_dbdp.setflags)
488
 
                        continue;
489
 
                if (name == NULL || ctp->ct_dbdp.db == NULL ||
490
 
                    strcmp(name, ctp->ct_dbdp.db) != 0)
491
 
                        continue;
492
 
                if (subdb != ctp->ct_dbdp.subdb &&
493
 
                    (subdb == NULL || ctp->ct_dbdp.subdb == NULL ||
494
 
                    strcmp(subdb, ctp->ct_dbdp.subdb) != 0))
495
 
                        continue;
496
 
                /*
497
 
                 * If we get here, then we match.
498
 
                 */
499
 
                ctp->ct_refcount++;
500
 
                return (ctp);
501
 
        }
502
 
 
503
 
        return (NULL);
504
 
}
505
 
 
506
 
/*
507
 
 * PUBLIC: ct_entry *__dbsrv_shareenv __P((ct_entry *, home_entry *, u_int32_t));
508
 
 */
509
 
ct_entry *
510
 
__dbsrv_shareenv(env_ctp, home, flags)
511
 
        ct_entry *env_ctp;
512
 
        home_entry *home;
513
 
        u_int32_t flags;
514
 
{
515
 
        ct_entry *ctp;
516
 
 
517
 
        /*
518
 
         * Check if we can share an env.  Criteria for sharing are:
519
 
         * Must be an env ctp, obviously.
520
 
         * Must share the same home env.
521
 
         * All flags must match.
522
 
         */
523
 
        for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL;
524
 
            ctp = LIST_NEXT(ctp, entries)) {
525
 
                /*
526
 
                 * Skip ourselves.
527
 
                 */
528
 
                if (ctp == env_ctp)
529
 
                        continue;
530
 
                if (ctp->ct_type != CT_ENV)
531
 
                        continue;
532
 
                if (ctp->ct_envdp.home != home)
533
 
                        continue;
534
 
                if (ctp->ct_envdp.envflags != flags)
535
 
                        continue;
536
 
                if (ctp->ct_envdp.onflags != env_ctp->ct_envdp.onflags)
537
 
                        continue;
538
 
                if (ctp->ct_envdp.offflags != env_ctp->ct_envdp.offflags)
539
 
                        continue;
540
 
                /*
541
 
                 * If we get here, then we match.  The only thing left to
542
 
                 * check is the timeout.  Since the server timeout set by
543
 
                 * the client is a hint, for sharing we'll give them the
544
 
                 * benefit of the doubt and grant them the longer timeout.
545
 
                 */
546
 
                if (ctp->ct_timeout < env_ctp->ct_timeout)
547
 
                        ctp->ct_timeout = env_ctp->ct_timeout;
548
 
                ctp->ct_refcount++;
549
 
                return (ctp);
550
 
        }
551
 
 
552
 
        return (NULL);
553
 
}
554
 
 
555
 
/*
556
 
 * PUBLIC: void __dbsrv_active __P((ct_entry *));
557
 
 */
558
 
void
559
 
__dbsrv_active(ctp)
560
 
        ct_entry *ctp;
561
 
{
562
 
        time_t t;
563
 
        ct_entry *envctp;
564
 
 
565
 
        if (ctp == NULL)
566
 
                return;
567
 
        if ((t = time(NULL)) == -1)
568
 
                return;
569
 
        *(ctp->ct_activep) = t;
570
 
        if ((envctp = ctp->ct_envparent) == NULL)
571
 
                return;
572
 
        *(envctp->ct_activep) = t;
573
 
        return;
574
 
}
575
 
 
576
 
/*
577
 
 * PUBLIC: int __db_close_int __P((long, u_int32_t));
578
 
 */
579
 
int
580
 
__db_close_int(id, flags)
581
 
        long id;
582
 
        u_int32_t flags;
583
 
{
584
 
        DB *dbp;
585
 
        int ret;
586
 
        ct_entry *ctp;
587
 
 
588
 
        ret = 0;
589
 
        ctp = get_tableent(id);
590
 
        if (ctp == NULL)
591
 
                return (DB_NOSERVER_ID);
592
 
        DB_ASSERT(ctp->ct_type == CT_DB);
593
 
        if (__dbsrv_verbose && ctp->ct_refcount != 1)
594
 
                printf("Deref'ing dbp id %ld, refcount %d\n",
595
 
                    id, ctp->ct_refcount);
596
 
        if (--ctp->ct_refcount != 0)
597
 
                return (ret);
598
 
        dbp = ctp->ct_dbp;
599
 
        if (__dbsrv_verbose)
600
 
                printf("Closing dbp id %ld\n", id);
601
 
 
602
 
        ret = dbp->close(dbp, flags);
603
 
        __dbdel_ctp(ctp);
604
 
        return (ret);
605
 
}
606
 
 
607
 
/*
608
 
 * PUBLIC: int __dbc_close_int __P((ct_entry *));
609
 
 */
610
 
int
611
 
__dbc_close_int(dbc_ctp)
612
 
        ct_entry *dbc_ctp;
613
 
{
614
 
        DBC *dbc;
615
 
        int ret;
616
 
        ct_entry *ctp;
617
 
 
618
 
        dbc = (DBC *)dbc_ctp->ct_anyp;
619
 
 
620
 
        ret = dbc->c_close(dbc);
621
 
        /*
622
 
         * If this cursor is a join cursor then we need to fix up the
623
 
         * cursors that it was joined from so that they are independent again.
624
 
         */
625
 
        if (dbc_ctp->ct_type & CT_JOINCUR)
626
 
                for (ctp = LIST_FIRST(&__dbsrv_head); ctp != NULL;
627
 
                    ctp = LIST_NEXT(ctp, entries)) {
628
 
                        /*
629
 
                         * Test if it is a join cursor, and if it is part
630
 
                         * of this one.
631
 
                         */
632
 
                        if ((ctp->ct_type & CT_JOIN) &&
633
 
                            ctp->ct_activep == &dbc_ctp->ct_active) {
634
 
                                ctp->ct_type &= ~CT_JOIN;
635
 
                                ctp->ct_activep = ctp->ct_origp;
636
 
                                __dbsrv_active(ctp);
637
 
                        }
638
 
                }
639
 
        __dbclear_ctp(dbc_ctp);
640
 
        return (ret);
641
 
 
642
 
}
643
 
 
644
 
/*
645
 
 * PUBLIC: int __dbenv_close_int __P((long, u_int32_t, int));
646
 
 */
647
 
int
648
 
__dbenv_close_int(id, flags, force)
649
 
        long id;
650
 
        u_int32_t flags;
651
 
        int force;
652
 
{
653
 
        DB_ENV *dbenv;
654
 
        int ret;
655
 
        ct_entry *ctp;
656
 
 
657
 
        ret = 0;
658
 
        ctp = get_tableent(id);
659
 
        if (ctp == NULL)
660
 
                return (DB_NOSERVER_ID);
661
 
        DB_ASSERT(ctp->ct_type == CT_ENV);
662
 
        if (__dbsrv_verbose && ctp->ct_refcount != 1)
663
 
                printf("Deref'ing env id %ld, refcount %d\n",
664
 
                    id, ctp->ct_refcount);
665
 
        /*
666
 
         * If we are timing out, we need to force the close, no matter
667
 
         * what the refcount.
668
 
         */
669
 
        if (--ctp->ct_refcount != 0 && !force)
670
 
                return (ret);
671
 
        dbenv = ctp->ct_envp;
672
 
        if (__dbsrv_verbose)
673
 
                printf("Closing env id %ld\n", id);
674
 
 
675
 
        ret = dbenv->close(dbenv, flags);
676
 
        __dbdel_ctp(ctp);
677
 
        return (ret);
678
 
}
679
 
 
680
 
static int
681
 
add_home(home)
682
 
        char *home;
683
 
{
684
 
        home_entry *hp, *homep;
685
 
        int ret;
686
 
 
687
 
        if ((ret = __os_malloc(NULL, sizeof(home_entry), &hp)) != 0)
688
 
                return (ret);
689
 
        if ((ret = __os_malloc(NULL, strlen(home)+1, &hp->home)) != 0)
690
 
                return (ret);
691
 
        memcpy(hp->home, home, strlen(home)+1);
692
 
        hp->dir = home;
693
 
        hp->passwd = NULL;
694
 
        /*
695
 
         * This loop is to remove any trailing path separators,
696
 
         * to assure hp->name points to the last component.
697
 
         */
698
 
        hp->name = __db_rpath(home);
699
 
        *(hp->name) = '\0';
700
 
        hp->name++;
701
 
        while (*(hp->name) == '\0') {
702
 
                hp->name = __db_rpath(home);
703
 
                *(hp->name) = '\0';
704
 
                hp->name++;
705
 
        }
706
 
        /*
707
 
         * Now we have successfully added it.  Make sure there are no
708
 
         * identical names.
709
 
         */
710
 
        for (homep = LIST_FIRST(&__dbsrv_home); homep != NULL;
711
 
            homep = LIST_NEXT(homep, entries))
712
 
                if (strcmp(homep->name, hp->name) == 0) {
713
 
                        printf("Already added home name %s, at directory %s\n",
714
 
                            hp->name, homep->dir);
715
 
                        __os_free(NULL, hp->home);
716
 
                        __os_free(NULL, hp);
717
 
                        return (-1);
718
 
                }
719
 
        LIST_INSERT_HEAD(&__dbsrv_home, hp, entries);
720
 
        if (__dbsrv_verbose)
721
 
                printf("Added home %s in dir %s\n", hp->name, hp->dir);
722
 
        return (0);
723
 
}
724
 
 
725
 
static int
726
 
add_passwd(passwd)
727
 
        char *passwd;
728
 
{
729
 
        home_entry *hp;
730
 
 
731
 
        /*
732
 
         * We add the passwd to the last given home dir.  If there
733
 
         * isn't a home dir, or the most recent one already has a
734
 
         * passwd, then there is a user error.
735
 
         */
736
 
        hp = LIST_FIRST(&__dbsrv_home);
737
 
        if (hp == NULL || hp->passwd != NULL)
738
 
                return (EINVAL);
739
 
        /*
740
 
         * We've already strdup'ed the passwd above, so we don't need
741
 
         * to malloc new space, just point to it.
742
 
         */
743
 
        hp->passwd = passwd;
744
 
        return (0);
745
 
}
746
 
 
747
 
/*
748
 
 * PUBLIC: home_entry *get_home __P((char *));
749
 
 */
750
 
home_entry *
751
 
get_home(name)
752
 
        char *name;
753
 
{
754
 
        home_entry *hp;
755
 
 
756
 
        for (hp = LIST_FIRST(&__dbsrv_home); hp != NULL;
757
 
            hp = LIST_NEXT(hp, entries))
758
 
                if (strcmp(name, hp->name) == 0)
759
 
                        return (hp);
760
 
        return (NULL);
761
 
}
762
 
 
763
 
static int
764
 
env_recover(progname)
765
 
        char *progname;
766
 
{
767
 
        DB_ENV *dbenv;
768
 
        home_entry *hp;
769
 
        u_int32_t flags;
770
 
        int exitval, ret;
771
 
 
772
 
        for (hp = LIST_FIRST(&__dbsrv_home); hp != NULL;
773
 
            hp = LIST_NEXT(hp, entries)) {
774
 
                exitval = 0;
775
 
                if ((ret = db_env_create(&dbenv, 0)) != 0) {
776
 
                        fprintf(stderr, "%s: db_env_create: %s\n",
777
 
                            progname, db_strerror(ret));
778
 
                        exit(EXIT_FAILURE);
779
 
                }
780
 
                if (__dbsrv_verbose == 1) {
781
 
                        (void)dbenv->set_verbose(dbenv, DB_VERB_RECOVERY, 1);
782
 
                        (void)dbenv->set_verbose(dbenv, DB_VERB_CHKPOINT, 1);
783
 
                }
784
 
                dbenv->set_errfile(dbenv, stderr);
785
 
                dbenv->set_errpfx(dbenv, progname);
786
 
                if (hp->passwd != NULL)
787
 
                        (void)dbenv->set_encrypt(dbenv, hp->passwd,
788
 
                            DB_ENCRYPT_AES);
789
 
 
790
 
                /*
791
 
                 * Initialize the env with DB_RECOVER.  That is all we
792
 
                 * have to do to run recovery.
793
 
                 */
794
 
                if (__dbsrv_verbose)
795
 
                        printf("Running recovery on %s\n", hp->home);
796
 
                flags = DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL |
797
 
                    DB_INIT_TXN | DB_USE_ENVIRON | DB_RECOVER;
798
 
                if ((ret = dbenv->open(dbenv, hp->home, flags, 0)) != 0) {
799
 
                        dbenv->err(dbenv, ret, "DB_ENV->open");
800
 
                        goto error;
801
 
                }
802
 
 
803
 
                if (0) {
804
 
error:                  exitval = 1;
805
 
                }
806
 
                if ((ret = dbenv->close(dbenv, 0)) != 0) {
807
 
                        exitval = 1;
808
 
                        fprintf(stderr, "%s: dbenv->close: %s\n",
809
 
                            progname, db_strerror(ret));
810
 
                }
811
 
                if (exitval)
812
 
                        return (exitval);
813
 
        }
814
 
        return (0);
815
 
}