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

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