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

db_hotbackup.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: db_hotbackup.c,v 1.16 2005/10/27 01:25:54 mjc Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef lint
00013 static const char copyright[] =
00014     "Copyright (c) 1996-2005\nSleepycat Software Inc.  All rights reserved.\n";
00015 #endif
00016 
00017 #ifndef NO_SYSTEM_INCLUDES
00018 #include <sys/types.h>
00019 #include <sys/stat.h>
00020 
00021 #include <fcntl.h>
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025 #include <time.h>
00026 #include <unistd.h>
00027 #endif
00028 
00029 #include "db_int.h"
00030 #include "dbinc/log.h"
00031 
00032 enum which_open { OPEN_ORIGINAL, OPEN_HOT_BACKUP };
00033 
00034 int backup_dir_clean __P((DB_ENV *, char *, int *, int, int));
00035 int data_copy __P((DB_ENV *, char *, char *, char *, int));
00036 int env_init __P((DB_ENV **, char *, char *, char *, enum which_open));
00037 int main __P((int, char *[]));
00038 int read_data_dir __P((DB_ENV *, char *, char *, int));
00039 int read_log_dir __P((DB_ENV *, char *, char *, int *, int, int));
00040 int usage __P((void));
00041 int version_check __P((void));
00042 
00043 const char *progname;
00044 
00045 int
00046 main(argc, argv)
00047         int argc;
00048         char *argv[];
00049 {
00050         extern char *optarg;
00051         extern int optind;
00052         time_t now;
00053         DB_ENV *dbenv;
00054         u_int data_cnt, data_next;
00055         int ch, checkpoint, copy_min, exitval, remove_max, ret, update, verbose;
00056         char *backup_dir, **data_dir, **dir, *home, *log_dir, *passwd;
00057 
00058         if ((progname = strrchr(argv[0], '/')) == NULL)
00059                 progname = argv[0];
00060         else
00061                 ++progname;
00062 
00063         if ((ret = version_check()) != 0)
00064                 return (ret);
00065 
00066         checkpoint = data_cnt = data_next = exitval = update = verbose = 0;
00067         data_dir = NULL;
00068         backup_dir = home = log_dir = passwd = NULL;
00069         copy_min = remove_max = 0;
00070         while ((ch = getopt(argc, argv, "b:cd:h:l:P:uVv")) != EOF)
00071                 switch (ch) {
00072                 case 'b':
00073                         backup_dir = optarg;
00074                         break;
00075                 case 'c':
00076                         checkpoint = 1;
00077                         break;
00078                 case 'd':
00079                         /*
00080                          * User can specify a list of directories -- keep an
00081                          * array, leaving room for the trailing NULL.
00082                          */
00083                         if (data_dir == NULL || data_next >= data_cnt - 2) {
00084                                 data_cnt = data_cnt == 0 ? 20 : data_cnt * 2;
00085                                 if ((data_dir = realloc(data_dir,
00086                                     data_cnt * sizeof(*data_dir))) == NULL) {
00087                                         fprintf(stderr, "%s: %s\n",
00088                                             progname, strerror(errno));
00089                                         return (EXIT_FAILURE);
00090                                 }
00091                         }
00092                         data_dir[data_next++] = optarg;
00093                         break;
00094                 case 'h':
00095                         home = optarg;
00096                         break;
00097                 case 'l':
00098                         log_dir = optarg;
00099                         break;
00100                 case 'P':
00101                         passwd = strdup(optarg);
00102                         memset(optarg, 0, strlen(optarg));
00103                         if (passwd == NULL) {
00104                                 fprintf(stderr, "%s: strdup: %s\n",
00105                                     progname, strerror(errno));
00106                                 return (EXIT_FAILURE);
00107                         }
00108                         break;
00109                 case 'u':
00110                         update = 1;
00111                         break;
00112                 case 'V':
00113                         printf("%s\n", db_version(NULL, NULL, NULL));
00114                         return (EXIT_SUCCESS);
00115                 case 'v':
00116                         verbose = 1;
00117                         break;
00118                 case '?':
00119                 default:
00120                         return (usage());
00121                 }
00122         argc -= optind;
00123         argv += optind;
00124 
00125         if (argc != 0)
00126                 return (usage());
00127 
00128         /* Handle possible interruptions. */
00129         __db_util_siginit();
00130 
00131         /*
00132          * The home directory defaults to the environment variable DB_HOME.
00133          * The log directory defaults to the home directory.
00134          *
00135          * We require a source database environment directory and a target
00136          * backup directory.
00137          */
00138         if (home == NULL)
00139                 home = getenv("DB_HOME");
00140         if (home == NULL) {
00141                 fprintf(stderr,
00142                     "%s: no source database environment specified\n", progname);
00143                 return (usage());
00144         }
00145         if (log_dir == NULL)
00146                 log_dir = home;
00147         if (backup_dir == NULL) {
00148                 fprintf(stderr,
00149                     "%s: no target backup directory specified\n", progname);
00150                 return (usage());
00151         }
00152 
00153         /* NULL-terminate any list of data directories. */
00154         if (data_dir != NULL)
00155                 data_dir[data_next] = NULL;
00156 
00157         if (verbose) {
00158                 (void)time(&now);
00159                 printf("%s: hot backup started at %s", progname, ctime(&now));
00160         }
00161 
00162         /* Open the source environment. */
00163         if ((ret = env_init(&dbenv, home, log_dir, passwd, OPEN_ORIGINAL)) != 0)
00164                 goto shutdown;
00165 
00166         /*
00167          * If the -c option is specified, checkpoint the source home
00168          * database environment, and remove any unnecessary log files.
00169          */
00170         if (checkpoint) {
00171                 if (verbose)
00172                         printf("%s: %s: force checkpoint\n", progname, home);
00173                 if ((ret =
00174                     dbenv->txn_checkpoint(dbenv, 0, 0, DB_FORCE)) != 0) {
00175                         dbenv->err(dbenv, ret, "DB_ENV->txn_checkpoint");
00176                         goto shutdown;
00177                 }
00178                 if (!update) {
00179                         if (verbose)
00180                                 printf("%s: %s: remove unnecessary log files\n",
00181                                     progname, home);
00182                         if ((ret = dbenv->log_archive(dbenv,
00183                              NULL, DB_ARCH_REMOVE)) != 0) {
00184                                 dbenv->err(dbenv, ret, "DB_ENV->log_archive");
00185                                 goto shutdown;
00186                         }
00187                 }
00188         }
00189 
00190         /*
00191          * If the target directory for the backup does not exist, create it
00192          * with mode read-write-execute for the owner.  Ignore errors here,
00193          * it's simpler and more portable to just always try the create.  If
00194          * there's a problem, we'll fail with reasonable errors later.
00195          */
00196         (void)__os_mkdir(NULL, backup_dir, __db_omode("rwx------"));
00197 
00198         /*
00199          * If the target directory for the backup does exist and the -u option
00200          * was specified, all log files in the target directory are removed;
00201          * if the -u option was not specified, all files in the target directory
00202          * are removed.
00203          */
00204         if ((ret = backup_dir_clean(
00205             dbenv, backup_dir, &remove_max, update, verbose)) != 0)
00206                 goto shutdown;
00207 
00208         /*
00209          * If the -u option was not specified, copy all database files found in
00210          * the database environment home directory, or any directory specified
00211          * using the -d option, into the target directory for the backup.
00212          */
00213         if (!update) {
00214                 if (read_data_dir(dbenv, backup_dir, home, verbose) != 0)
00215                         goto shutdown;
00216                 if (data_dir != NULL)
00217                         for (dir = &data_dir[0]; *dir != NULL; ++dir)
00218                                 if (read_data_dir(
00219                                     dbenv, backup_dir, *dir, verbose) != 0)
00220                                         goto shutdown;
00221         }
00222 
00223         /*
00224          * Copy all log files found in the directory specified by the -l option
00225          * (or in the database environment home directory, if no -l option was
00226          * specified), into the target directory for the backup.
00227          *
00228          * The log directory defaults to the home directory.
00229          */
00230         if (read_log_dir(dbenv,
00231              backup_dir, log_dir, &copy_min, update, verbose) != 0)
00232                 goto shutdown;
00233 
00234         /*
00235          * If we're updating a snapshot, the lowest-numbered log file copied
00236          * into the backup directory should be less than, or equal to, the
00237          * highest-numbered log file removed from the backup directory during
00238          * cleanup.
00239          */
00240         if (update && remove_max < copy_min &&
00241              !(remove_max == 0 && copy_min == 1)) {
00242                 fprintf(stderr,
00243                     "%s: the largest log file removed (%d) must be greater\n",
00244                     progname, remove_max);
00245                 fprintf(stderr,
00246                     "%s: than or equal the smallest log file copied (%d)\n",
00247                     progname, copy_min);
00248                 goto shutdown;
00249         }
00250 
00251         /* Close the source environment. */
00252         if ((ret = dbenv->close(dbenv, 0)) != 0) {
00253                 fprintf(stderr,
00254                     "%s: dbenv->close: %s\n", progname, db_strerror(ret));
00255                 dbenv = NULL;
00256                 goto shutdown;
00257         }
00258         /* Perform catastrophic recovery on the hot backup. */
00259         if (verbose)
00260                 printf("%s: %s: run catastrophic recovery\n",
00261                     progname, backup_dir);
00262         if ((ret = env_init(
00263             &dbenv, backup_dir, NULL, passwd, OPEN_HOT_BACKUP)) != 0)
00264                 goto shutdown;
00265 
00266         /*
00267          * Remove any unnecessary log files from the hot backup.
00268          */
00269         if (verbose)
00270                 printf("%s: %s: remove unnecessary log files\n",
00271                     progname, backup_dir);
00272         if ((ret =
00273             dbenv->log_archive(dbenv, NULL, DB_ARCH_REMOVE)) != 0) {
00274                 dbenv->err(dbenv, ret, "DB_ENV->log_archive");
00275                 goto shutdown;
00276         }
00277 
00278         if (0) {
00279 shutdown:       exitval = 1;
00280         }
00281         if (dbenv != NULL && (ret = dbenv->close(dbenv, 0)) != 0) {
00282                 exitval = 1;
00283                 fprintf(stderr,
00284                     "%s: dbenv->close: %s\n", progname, db_strerror(ret));
00285         }
00286 
00287         if (data_dir != NULL)
00288                 free(data_dir);
00289         if (passwd != NULL)
00290                 free(passwd);
00291 
00292         if (exitval == 0) {
00293                 if (verbose) {
00294                         (void)time(&now);
00295                         printf("%s: hot backup completed at %s",
00296                             progname, ctime(&now));
00297                 }
00298         } else {
00299                 fprintf(stderr, "%s: HOT BACKUP FAILED!\n", progname);
00300         }
00301 
00302         /* Resend any caught signal. */
00303         __db_util_sigresend();
00304 
00305         return (exitval == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
00306 
00307 }
00308 
00309 /*
00310  * env_init --
00311  *      Open a database environment.
00312  */
00313 int
00314 env_init(dbenvp, home, log_dir, passwd, which)
00315         DB_ENV **dbenvp;
00316         char *home, *log_dir, *passwd;
00317         enum which_open which;
00318 {
00319         DB_ENV *dbenv;
00320         int ret;
00321 
00322         *dbenvp = NULL;
00323 
00324         /*
00325          * Create an environment object and initialize it for error reporting.
00326          */
00327         if ((ret = db_env_create(&dbenv, 0)) != 0) {
00328                 fprintf(stderr,
00329                     "%s: db_env_create: %s\n", progname, db_strerror(ret));
00330                 return (1);
00331         }
00332 
00333         dbenv->set_errfile(dbenv, stderr);
00334         setbuf(stderr, NULL);
00335         dbenv->set_errpfx(dbenv, progname);
00336         setvbuf(stdout, NULL, _IOLBF, 0);
00337 
00338         /*
00339          * If a log directory has been specified, and it's not the same as the
00340          * home directory, set it for the environment.
00341          */
00342         if (log_dir != NULL && log_dir != home &&
00343             (ret = dbenv->set_lg_dir(dbenv, log_dir)) != 0) {
00344                 dbenv->err(dbenv, ret, "DB_ENV->set_lg_dir: %s", log_dir);
00345                 return (1);
00346         }
00347 
00348         /* Optionally set the password. */
00349         if (passwd != NULL &&
00350             (ret = dbenv->set_encrypt(dbenv, passwd, DB_ENCRYPT_AES)) != 0) {
00351                 dbenv->err(dbenv, ret, "DB_ENV->set_encrypt");
00352                 return (1);
00353         }
00354 
00355         switch (which) {
00356         case OPEN_ORIGINAL:
00357                 /*
00358                  * Opening the database environment we're trying to back up.
00359                  * We try to attach to a pre-existing environment; if that
00360                  * fails, we create a private environment and try again.
00361                  */
00362                 if ((ret = dbenv->open(dbenv, home, DB_USE_ENVIRON, 0)) != 0 &&
00363                     (ret == DB_VERSION_MISMATCH ||
00364                     (ret = dbenv->open(dbenv, home, DB_CREATE |
00365                     DB_INIT_LOG | DB_INIT_TXN | DB_PRIVATE | DB_USE_ENVIRON,
00366                     0)) != 0)) {
00367                         dbenv->err(dbenv, ret, "DB_ENV->open: %s", home);
00368                         return (1);
00369                 }
00370                 break;
00371         case OPEN_HOT_BACKUP:
00372                 /*
00373                  * Opening the backup copy of the database environment.  We
00374                  * better be the only user, we're running recovery.
00375                  */
00376                 if ((ret = dbenv->open(dbenv, home, DB_CREATE |
00377                     DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN | DB_PRIVATE |
00378                     DB_RECOVER_FATAL | DB_USE_ENVIRON, 0)) != 0) {
00379                         dbenv->err(dbenv, ret, "DB_ENV->open: %s", home);
00380                         return (1);
00381                 }
00382                 break;
00383         }
00384 
00385         *dbenvp = dbenv;
00386         return (0);
00387 }
00388 
00389 /*
00390  * backup_dir_clean --
00391  *      Clean out the backup directory.
00392  */
00393 int
00394 backup_dir_clean(dbenv, backup_dir, remove_maxp, update, verbose)
00395         DB_ENV *dbenv;
00396         char *backup_dir;
00397         int *remove_maxp, update, verbose;
00398 {
00399         int cnt, fcnt, ret, v;
00400         char **names;
00401         char buf[2048];                 /* MAXPATHLEN is too hard to find. */
00402 
00403         /* Get a list of file names. */
00404         if ((ret = __os_dirlist(dbenv, backup_dir, &names, &fcnt)) != 0) {
00405                 dbenv->err(dbenv, ret, "%s: directory read", backup_dir);
00406                 return (1);
00407         }
00408         for (cnt = fcnt; --cnt >= 0;) {
00409                 /*
00410                  * Skip ".", ".." and log files (if update wasn't specified).
00411                  */
00412                 if (!strcmp(names[cnt], ".") || !strcmp(names[cnt], ".."))
00413                         continue;
00414                 if (strncmp(names[cnt], LFPREFIX, sizeof(LFPREFIX) - 1)) {
00415                         if (update)
00416                                 continue;
00417                 } else {
00418                         /* Track the highest-numbered log file removed. */
00419                         v = atoi(names[cnt] + sizeof(LFPREFIX) - 1);
00420                         if (*remove_maxp < v)
00421                                 *remove_maxp = v;
00422                 }
00423                 if ((size_t)snprintf(buf, sizeof(buf),
00424                     "%s/%s", backup_dir, names[cnt]) == sizeof(buf)) {
00425                         dbenv->err(dbenv, ret,
00426                             "%s/%s: path too long", backup_dir, names[cnt]);
00427                         return (1);
00428                 }
00429                 if (verbose)
00430                         printf("%s: removing %s\n", progname, buf);
00431                 if ((ret = remove(buf)) != 0) {
00432                         dbenv->err(dbenv, ret, "%s: remove", buf);
00433                         return (1);
00434                 }
00435         }
00436 
00437         __os_dirfree(dbenv, names, fcnt);
00438 
00439         if (verbose && *remove_maxp != 0)
00440                 printf("%s: highest numbered log file removed: %d\n",
00441                     progname, *remove_maxp);
00442 
00443         return (0);
00444 }
00445 
00446 /*
00447  * read_data_dir --
00448  *      Read a directory looking for databases to copy.
00449  */
00450 int
00451 read_data_dir(dbenv, backup_dir, dir, verbose)
00452         DB_ENV *dbenv;
00453         char *backup_dir, *dir;
00454         int verbose;
00455 {
00456         int cnt, fcnt, ret;
00457         char **names;
00458         char buf[2048];                 /* MAXPATHLEN is too hard to find. */
00459 
00460         /* Get a list of file names. */
00461         if ((ret = __os_dirlist(dbenv, dir, &names, &fcnt)) != 0) {
00462                 dbenv->err(dbenv, ret, "%s: directory read", dir);
00463                 return (1);
00464         }
00465         for (cnt = fcnt; --cnt >= 0;) {
00466                 /*
00467                  * Skip ".", ".." and files in DB's name space (but not Queue
00468                  * extent files, we need them).
00469                  */
00470                 if (!strcmp(names[cnt], ".") || !strcmp(names[cnt], ".."))
00471                         continue;
00472                 if (!strncmp(names[cnt], LFPREFIX, sizeof(LFPREFIX) - 1))
00473                         continue;
00474                 if (!strncmp(names[cnt],
00475                     DB_REGION_PREFIX, sizeof(DB_REGION_PREFIX) - 1))
00476                         continue;
00477 
00478                 /* Build a path name to the source. */
00479                 if ((size_t)snprintf(buf, sizeof(buf),
00480                     "%s/%s", dir, names[cnt]) == sizeof(buf)) {
00481                         dbenv->errx(dbenv,
00482                             "%s/%s: path too long", dir, names[cnt]);
00483                         return (1);
00484                 }
00485 
00486                 /* Copy the file. */
00487                 if ((ret = data_copy(
00488                     dbenv, buf, backup_dir, names[cnt], verbose)) != 0)
00489                         return (1);
00490         }
00491 
00492         __os_dirfree(dbenv, names, fcnt);
00493 
00494         return (0);
00495 }
00496 
00497 /*
00498  * read_log_dir --
00499  *      Read a directory looking for log files to copy.
00500  */
00501 int
00502 read_log_dir(dbenv, backup_dir, log_dir, copy_minp, update, verbose)
00503         DB_ENV *dbenv;
00504         char *backup_dir, *log_dir;
00505         int *copy_minp, update, verbose;
00506 {
00507         int aflag, ret, v;
00508         char **begin, **names;
00509         char from[2048], to[2048];      /* MAXPATHLEN is too hard to find. */
00510 
00511 again:  aflag = DB_ARCH_LOG;
00512 
00513         /*
00514          * If this is an update and we are deleting files, first process
00515          * those files that can be removed, then repeat with the rest.
00516          */
00517         if (update)
00518                 aflag = 0;
00519         /* Get a list of file names to be copied. */
00520         if ((ret = dbenv->log_archive(dbenv, &names, aflag)) != 0) {
00521                 dbenv->err(dbenv, ret, "%s: log_archive", log_dir);
00522                 return (1);
00523         }
00524         if (names == NULL)
00525                 goto done;
00526         begin = names;
00527         for (; *names != NULL; names++) {
00528                 /* Track the lowest-numbered log file copied. */
00529                 v = atoi(*names + sizeof(LFPREFIX) - 1);
00530                 if (*copy_minp == 0 || *copy_minp > v)
00531                         *copy_minp = v;
00532 
00533                 /* Build a path name to the source. */
00534                 if ((size_t)snprintf(from, sizeof(from),
00535                     "%s/%s", log_dir, *names) == sizeof(from)) {
00536                         dbenv->errx(dbenv,
00537                             "%s/%s: path too long", log_dir, *names);
00538                         return (1);
00539                 }
00540 
00541                 /*
00542                  * If we're going to remove the file, attempt to rename the
00543                  * instead of copying and then removing.  The likely failure
00544                  * is EXDEV (source and destination are on different volumes).
00545                  * Fall back to a copy, regardless of the error.  We don't
00546                  * worry about partial contents, the copy truncates the file
00547                  * on open.
00548                  */
00549                 if (update) {
00550                         if ((size_t)snprintf(to, sizeof(to),
00551                             "%s/%s", backup_dir, *names) == sizeof(to)) {
00552                                 dbenv->errx(dbenv,
00553                                     "%s/%s: path too long", backup_dir, *names);
00554                                 return (1);
00555                         }
00556                         if (rename(from, to) == 0) {
00557                                 if (verbose)
00558                                         printf("%s: moving %s to %s\n",
00559                                            progname, from, to);
00560                                 continue;
00561                         }
00562                 }
00563 
00564                 /* Copy the file. */
00565                 if ((ret = data_copy(dbenv,
00566                     from, backup_dir, *names, verbose)) != 0)
00567                         return (1);
00568 
00569                 if (update) {
00570                         if (verbose)
00571                                 printf("%s: removing %s\n", progname, from);
00572                         if ((ret = __os_unlink(dbenv, from)) != 0) {
00573                                 dbenv->err(dbenv, ret,
00574                                      "unlink of %s failed", from);
00575                                 return (1);
00576                         }
00577                 }
00578 
00579         }
00580 
00581         free(begin);
00582 done:   if (update) {
00583                 update = 0;
00584                 goto again;
00585         }
00586 
00587         if (verbose && *copy_minp != 0)
00588                 printf("%s: lowest numbered log file copied: %d\n",
00589                     progname, *copy_minp);
00590 
00591         return (0);
00592 }
00593 
00594 /*
00595  * data_copy --
00596  *      Copy a file into the backup directory.
00597  */
00598 int
00599 data_copy(dbenv, from, to_dir, to_file, verbose)
00600         DB_ENV *dbenv;
00601         char *from, *to_dir, *to_file;
00602         int verbose;
00603 {
00604         ssize_t nr, nw;
00605         size_t offset;
00606         int ret, rfd, wfd;
00607         char *buf, *taddr;
00608 
00609         ret = 0;
00610         rfd = wfd = -1;
00611 
00612         if (verbose)
00613                 printf("%s: copying %s to %s/%s\n",
00614                     progname, from, to_dir, to_file);
00615 
00616         /*
00617          * We MUST copy multiples of the page size, atomically, to ensure a
00618          * database page is not updated by another thread of control during
00619          * the copy.
00620          *
00621          * !!!
00622          * The current maximum page size for Berkeley DB is 64KB; we will have
00623          * to increase this value if the maximum page size is ever more than a
00624          * megabyte
00625          */
00626         if ((buf = malloc(MEGABYTE)) == NULL) {
00627                 dbenv->err(dbenv,
00628                     errno, "%lu buffer allocation", (u_long)MEGABYTE);
00629                 return (1);
00630         }
00631 
00632         /* Open the input file. */
00633         if ((rfd = open(from, O_RDONLY, 0)) == -1) {
00634                 dbenv->err(dbenv, errno, "%s", from);
00635                 goto err;
00636         }
00637 
00638         /* Open the output file. */
00639         if ((u_int32_t)snprintf(
00640             buf, MEGABYTE, "%s/%s", to_dir, to_file) == MEGABYTE) {
00641                 dbenv->errx(dbenv, "%s/%s: path too long", to_dir, to_file);
00642                 goto err;
00643         }
00644         if ((wfd = open(
00645             buf, O_CREAT | O_TRUNC | O_WRONLY, __db_omode(OWNER_RW))) == -1)
00646                 goto err;
00647 
00648         /* Copy the data. */
00649         while ((nr = read(rfd, buf, MEGABYTE)) > 0)
00650                 for (taddr = buf, offset = 0;
00651                     offset < (size_t)nr; taddr += nw, offset += (size_t)nw) {
00652                         RETRY_CHK(((nw = write(wfd,
00653                             taddr, (u_int)(nr - offset))) < 0 ? 1 : 0), ret);
00654                         if (ret != 0)
00655                                 break;
00656                 }
00657         if (nr == -1) {
00658                 dbenv->err(dbenv, errno, "%s: read", from);
00659                 goto err;
00660         }
00661 
00662         if (ret != 0) {
00663                 dbenv->err(dbenv, errno, "%s: write %s/%s", to_dir, to_file);
00664                 goto err;
00665         }
00666 
00667         if (0) {
00668 err:            ret = 1;
00669         }
00670         if (buf != NULL)
00671                 free(buf);
00672 
00673         if (rfd != -1)
00674                 (void)close(rfd);
00675 
00676         /* We may be running on a remote filesystem; force the flush. */
00677         if (wfd != -1 && (fsync(wfd) != 0 || close(wfd) != 0)) {
00678                 dbenv->err(dbenv,
00679                     errno, "%s: fsync %s/%s", to_dir, to_file);
00680                 ret = 1;
00681         }
00682         return (ret);
00683 }
00684 
00685 int
00686 usage()
00687 {
00688         (void)fprintf(stderr, "usage: %s [-cuVv]\n\t%s\n", progname,
00689     "[-d data_dir ...] [-h home] [-l log_dir] [-P password] -b backup_dir");
00690         return (EXIT_FAILURE);
00691 }
00692 
00693 int
00694 version_check()
00695 {
00696         int v_major, v_minor, v_patch;
00697 
00698         /* Make sure we're loaded with the right version of the DB library. */
00699         (void)db_version(&v_major, &v_minor, &v_patch);
00700         if (v_major != DB_VERSION_MAJOR || v_minor != DB_VERSION_MINOR) {
00701                 fprintf(stderr,
00702         "%s: version %d.%d doesn't match library version %d.%d\n",
00703                     progname, DB_VERSION_MAJOR, DB_VERSION_MINOR,
00704                     v_major, v_minor);
00705                 return (EXIT_FAILURE);
00706         }
00707         return (0);
00708 }

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