1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2011, 2013 Oracle and/or its affiliates.  All rights reserved.
5  *
6  * $Id$
7  */
8 
9 #include "db_config.h"
10 #include "db_int.h"
11 #include "dbinc/db_page.h"
12 #include "dbinc/db_am.h"
13 #include "dbinc/heap.h"
14 #include "dbinc/mp.h"
15 #include "dbinc/partition.h"
16 
17 #ifdef HAVE_QUEUE
18 #include "dbinc/qam.h"
19 #endif
20 
21 static void save_error __P((const DB_ENV *, const char *, const char *));
22 static int backup_read_log_dir __P((DB_ENV *, const char *, int *, u_int32_t));
23 static int backup_read_data_dir
24     __P((DB_ENV *, DB_THREAD_INFO *, const char *, const char *, u_int32_t));
25 static int backup_dir_clean
26     __P((DB_ENV *, const char *, const char *, int *, u_int32_t));
27 static int backup_data_copy
28     __P((DB_ENV *, const char *, const char *, const char *, int));
29 static int __db_backup
30     __P((DB_ENV *, const char *, DB_THREAD_INFO *, int, u_int32_t));
31 
32 /*
33  * __db_dbbackup_pp --
34  *	Copy a database file coordinated with mpool.
35  *
36  * PUBLIC: int __db_dbbackup_pp __P((DB_ENV *,
37  * PUBLIC:     const char *, const char *, u_int32_t));
38  */
39 int
__db_dbbackup_pp(dbenv,dbfile,target,flags)40 __db_dbbackup_pp(dbenv, dbfile, target, flags)
41 	DB_ENV *dbenv;
42 	const char *dbfile, *target;
43 	u_int32_t flags;
44 {
45 	DB_THREAD_INFO *ip;
46 	int ret;
47 
48 	if ((ret = __db_fchk(dbenv->env,
49 	    "DB_ENV->dbbackup", flags, DB_EXCL)) != 0)
50 		return (ret);
51 	ENV_ENTER(dbenv->env, ip);
52 	REPLICATION_WRAP(dbenv->env,
53 	    (__db_dbbackup(dbenv, ip, dbfile, target, flags)), 0, ret);
54 	ENV_LEAVE(dbenv->env, ip);
55 	return (ret);
56 }
57 
58 /*
59  * __db_dbbackup --
60  *	Copy a database file coordinated with mpool.
61  *
62  * PUBLIC: int __db_dbbackup __P((DB_ENV *, DB_THREAD_INFO *,
63  * PUBLIC:     const char *, const char *, u_int32_t));
64  */
65 int
__db_dbbackup(dbenv,ip,dbfile,target,flags)66 __db_dbbackup(dbenv, ip, dbfile, target, flags)
67 	DB_ENV *dbenv;
68 	DB_THREAD_INFO *ip;
69 	const char *dbfile, *target;
70 	u_int32_t flags;
71 {
72 	DB *dbp;
73 	DB_FH *fp;
74 	void *handle;
75 	int ret, retry_count, t_ret;
76 
77 	dbp = NULL;
78 	retry_count = 0;
79 
80 retry:	if ((ret = __db_create_internal(&dbp, dbenv->env, 0)) == 0 &&
81 	    (ret = __db_open(dbp, ip, NULL, dbfile, NULL,
82 	    DB_UNKNOWN, DB_AUTO_COMMIT | DB_RDONLY, 0, PGNO_BASE_MD)) != 0) {
83 		if (ret == DB_LOCK_DEADLOCK || ret == DB_LOCK_NOTGRANTED) {
84 			(void)__db_close(dbp, NULL, DB_NOSYNC);
85 			dbp = NULL;
86 			if (++retry_count > 100)
87 				return (ret);
88 			__db_errx(dbenv->env, DB_STR_A("0702",
89 		    "Deadlock while opening %s, retrying", "%s"), dbfile);
90 			__os_yield(dbenv->env, 1, 0);
91 			goto retry;
92 		}
93 	}
94 
95 	if (ret == 0) {
96 		if ((ret = __memp_backup_open(dbenv->env,
97 		    dbp->mpf, dbfile, target, flags, &fp, &handle)) == 0) {
98 			if (dbp->type == DB_HEAP)
99 				ret = __heap_backup(
100 				    dbenv, dbp, ip, fp, handle, flags);
101 			else
102 				ret = __memp_backup_mpf(
103 				    dbenv->env, dbp->mpf,
104 				    ip, 0, dbp->mpf->mfp->last_pgno,
105 				    fp, handle, flags);
106 		}
107 		if ((t_ret = __memp_backup_close(dbenv->env,
108 		    dbp->mpf, dbfile, fp, handle)) != 0 && ret == 0)
109 			ret = t_ret;
110 	}
111 
112 #ifdef HAVE_QUEUE
113 	/*
114 	 * For compatibility with the 5.2 and patch versions of db_copy
115 	 * dump the queue extents here.
116 	 */
117 	if (ret == 0 && dbp->type == DB_QUEUE)
118 		ret = __qam_backup_extents(dbp, ip, target, flags);
119 #endif
120 
121 	if (dbp != NULL &&
122 	    (t_ret = __db_close(dbp, NULL, DB_NOSYNC)) != 0 && ret == 0)
123 		ret = t_ret;
124 
125 	if (ret != 0)
126 		__db_err(dbenv->env, ret, "Backup Failed");
127 	return (ret);
128 }
129 
130 /*
131  * backup_dir_clean --
132  *	Clean out the backup directory.
133  */
134 static int
backup_dir_clean(dbenv,backup_dir,log_dir,remove_maxp,flags)135 backup_dir_clean(dbenv, backup_dir, log_dir, remove_maxp, flags)
136 	DB_ENV *dbenv;
137 	const char *backup_dir, *log_dir;
138 	int *remove_maxp;
139 	u_int32_t flags;
140 {
141 	ENV *env;
142 	int cnt, fcnt, ret, v;
143 	const char *dir;
144 	char **names, buf[DB_MAXPATHLEN], path[DB_MAXPATHLEN];
145 
146 	env = dbenv->env;
147 
148 	/* We may be cleaning a log directory separate from the target. */
149 	if (log_dir != NULL) {
150 		if ((ret = __os_concat_path(buf,
151 		    sizeof(buf), backup_dir, log_dir)) != 0) {
152 			buf[sizeof(buf) - 1] = '\0';
153 			__db_errx(env,  DB_STR_A("0717",
154 			    "%s: path too long", "%s"), buf);
155 			return (EINVAL);
156 		}
157 		dir = buf;
158 	} else
159 		dir = backup_dir;
160 
161 	/* Get a list of file names. */
162 	if ((ret = __os_dirlist(env, dir, 0, &names, &fcnt)) != 0) {
163 		if (log_dir != NULL && !LF_ISSET(DB_BACKUP_UPDATE))
164 			return (0);
165 		__db_err(env,
166 		    ret, DB_STR_A("0718", "%s: directory read", "%s"), dir);
167 		return (ret);
168 	}
169 	for (cnt = fcnt; --cnt >= 0;) {
170 		/*
171 		 * Skip non-log files (if update was specified).
172 		 */
173 		if (!IS_LOG_FILE(names[cnt])) {
174 			if (LF_ISSET(DB_BACKUP_UPDATE))
175 				continue;
176 		} else {
177 			/* Track the highest-numbered log file removed. */
178 			v = atoi(names[cnt] + sizeof(LFPREFIX) - 1);
179 			if (*remove_maxp < v)
180 				*remove_maxp = v;
181 		}
182 		if ((ret = __os_concat_path(path,
183 		    sizeof(path), dir, names[cnt])) != 0) {
184 			path[sizeof(path) - 1] = '\0';
185 			__db_errx(env, DB_STR_A("0714",
186 			    "%s: path too long", "%s"), path);
187 			return (EINVAL);
188 		}
189 		if (FLD_ISSET(dbenv->verbose, DB_VERB_BACKUP))
190 			__db_msg(env, DB_STR_A("0715", "removing %s",
191 			    "%s"),  path);
192 		if ((ret = __os_unlink(env, path, 0)) != 0)
193 			return (ret);
194 	}
195 
196 	__os_dirfree(env, names, fcnt);
197 
198 	if (FLD_ISSET(dbenv->verbose, DB_VERB_BACKUP) && *remove_maxp != 0)
199 		__db_msg(env, DB_STR_A("0719",
200 		    "highest numbered log file removed: %d", "%d"),
201 		    *remove_maxp);
202 
203 	return (0);
204 }
205 
206 /*
207  * backup_data_copy --
208  *	Copy a non-database file into the backup directory.
209  */
210 static int
backup_data_copy(dbenv,file,from_dir,to_dir,log)211 backup_data_copy(dbenv, file, from_dir, to_dir, log)
212 	DB_ENV *dbenv;
213 	const char *file, *from_dir, *to_dir;
214 	int log;
215 {
216 	DB_BACKUP *backup;
217 	DB_FH *rfhp, *wfhp;
218 	ENV *env;
219 	u_int32_t gigs, off;
220 	size_t nr, nw;
221 	int ret, t_ret;
222 	char *buf;
223 	void *handle;
224 	char from[DB_MAXPATHLEN], to[DB_MAXPATHLEN];
225 
226 	rfhp = wfhp = NULL;
227 	handle = NULL;
228 	buf = NULL;
229 	env = dbenv->env;
230 	backup = env->backup_handle;
231 
232 	if ((ret = __os_concat_path(from,
233 	    sizeof(from), from_dir, file)) != 0) {
234 		from[sizeof(from) - 1] = '\0';
235 		__db_errx(env, DB_STR_A("0728",
236 		     "%s: path too long", "%s"), from);
237 		goto err;
238 	}
239 	if ((ret = __os_concat_path(to,
240 	    sizeof(to), to_dir, file)) != 0) {
241 		to[sizeof(to) - 1] = '\0';
242 		__db_errx(env, DB_STR_A("0729",
243 		     "%s: path too long", "%s"), to);
244 		goto err;
245 	}
246 	if (FLD_ISSET(dbenv->verbose, DB_VERB_BACKUP))
247 		__db_msg(env, DB_STR_A("0726",
248 		    "copying %s to %s", "%s %s"), from, to);
249 
250 	if ((ret = __os_malloc(env, MEGABYTE, &buf)) != 0) {
251 		__db_err(env, ret, DB_STR_A("0727",
252 		    "%lu buffer allocation", "%lu"), (u_long)MEGABYTE);
253 		return (ret);
254 	}
255 
256 	/* Open the input file. */
257 	if ((ret = __os_open(env, from, 0, DB_OSO_RDONLY, 0, &rfhp)) != 0) {
258 		if (ret == ENOENT && !log) {
259 			ret = 0;
260 			if (FLD_ISSET(dbenv->verbose, DB_VERB_BACKUP))
261 				__db_msg(env, DB_STR_A("0730",
262 				    "%s%c%s not present", "%s %c %s"),
263 				    from_dir, PATH_SEPARATOR[0], file);
264 			goto done;
265 		}
266 		__db_err(env, ret, "%s", buf);
267 		goto err;
268 	}
269 
270 	/* Open the output file. */
271 	if (backup != NULL && backup->open != NULL)
272 		ret = backup->open(env->dbenv, file, to_dir, &handle);
273 	else {
274 		if ((ret = __os_open(env, to, 0,
275 		    DB_OSO_CREATE | DB_OSO_TRUNC, DB_MODE_600, &wfhp)) != 0) {
276 			__db_err(env, ret, "%s", to);
277 			goto err;
278 		}
279 	}
280 
281 	off = 0;
282 	gigs = 0;
283 	/* Copy the data. */
284 	while ((ret = __os_read(env, rfhp, buf, MEGABYTE, &nr)) == 0 &&
285 	    nr > 0) {
286 		if (backup != NULL && backup->write != NULL) {
287 			if ((ret = backup->write(env->dbenv, gigs,
288 			     off, (u_int32_t)nr, (u_int8_t *)buf, handle)) != 0)
289 				break;
290 		} else {
291 			if ((ret = __os_write(env, wfhp, buf, nr, &nw)) != 0)
292 				break;
293 			if (nr != nw) {
294 				ret = EIO;
295 				break;
296 			}
297 		}
298 		off += (u_int32_t)nr;
299 		if (off >= GIGABYTE) {
300 			gigs++;
301 			off -= GIGABYTE;
302 		}
303 	}
304 	if (ret != 0)
305 		__db_err(env, ret, DB_STR("0748", "Write failed."));
306 
307 err:
308 done:	if (buf != NULL)
309 		__os_free(env, buf);
310 
311 	if (backup != NULL && backup->close != NULL &&
312 	    (t_ret = backup->close(env->dbenv, file, handle)) != 0 && ret != 0)
313 		ret = t_ret;
314 	if (rfhp != NULL &&
315 	    (t_ret = __os_closehandle(env, rfhp)) != 0 && ret == 0)
316 		ret = t_ret;
317 
318 	/* We may be running on a remote filesystem; force the flush. */
319 	if (ret == 0 && wfhp != NULL) {
320 		ret = __os_fsync(env, wfhp);
321 		if (ret != 0)
322 			__db_err(env, ret, DB_STR("0731", "Sync failed"));
323 	}
324 	if (wfhp != NULL &&
325 	    (t_ret = __os_closehandle(env, wfhp)) != 0 && ret == 0)
326 		ret = t_ret;
327 	return (ret);
328 }
329 
save_error(dbenv,prefix,errstr)330 static void save_error(dbenv, prefix, errstr)
331 	const DB_ENV *dbenv;
332 	const char *prefix;
333 	const char *errstr;
334 {
335 	COMPQUIET(prefix, NULL);
336 	if (DB_GLOBAL(saved_errstr) != NULL)
337 		__os_free(dbenv->env, DB_GLOBAL(saved_errstr));
338 	(void)__os_strdup(dbenv->env, errstr, &DB_GLOBAL(saved_errstr));
339 }
340 
341 /*
342  * backup_read_data_dir --
343  *	Read a directory looking for databases to copy.
344  */
345 static int
backup_read_data_dir(dbenv,ip,dir,backup_dir,flags)346 backup_read_data_dir(dbenv, ip, dir, backup_dir, flags)
347 	DB_ENV *dbenv;
348 	DB_THREAD_INFO *ip;
349 	const char *dir, *backup_dir;
350 	u_int32_t flags;
351 {
352 	DB_MSGBUF mb;
353 	ENV *env;
354 	FILE *savefile;
355 	int fcnt, ret;
356 	size_t cnt;
357 	const char *bd;
358 	char **names, buf[DB_MAXPATHLEN], bbuf[DB_MAXPATHLEN];
359 	void (*savecall) (const DB_ENV *, const char *, const char *);
360 
361 	env = dbenv->env;
362 	memset(bbuf, 0, sizeof(bbuf));
363 
364 	bd = backup_dir;
365 	if (!LF_ISSET(DB_BACKUP_SINGLE_DIR) && dir != env->db_home) {
366 		cnt = sizeof(bbuf);
367 		/* Build a path name to the destination. */
368 		if ((ret = __os_concat_path(bbuf, sizeof(bbuf),
369 		    backup_dir, dir)) != 0 ||
370 		    (((cnt = strlen(bbuf)) == sizeof(bbuf) ||
371 		    (cnt == sizeof(bbuf) - 1 &&
372 		    strchr(PATH_SEPARATOR, bbuf[cnt - 1]) == NULL)) &&
373 		    LF_ISSET(DB_CREATE))) {
374 			bbuf[sizeof(bbuf) - 1] = '\0';
375 			__db_errx(env, DB_STR_A("0720",
376 			    "%s: path too long", "%s"), bbuf);
377 			return (1);
378 		}
379 
380 		/* Create the path. */
381 		if (LF_ISSET(DB_CREATE)) {
382 			if (strchr(PATH_SEPARATOR, bbuf[cnt - 1]) == NULL)
383 				bbuf[cnt] = PATH_SEPARATOR[0];
384 
385 			if ((ret = __db_mkpath(env, bbuf)) != 0) {
386 				__db_err(env,  ret, DB_STR_A("0721",
387 				    "%s: cannot create", "%s"), bbuf);
388 				return (ret);
389 			}
390 			/* step on the trailing '/' */
391 			bbuf[cnt] = '\0';
392 		}
393 		bd = bbuf;
394 
395 	}
396 	if (!__os_abspath(dir) && dir != env->db_home) {
397 		/* Build a path name to the source. */
398 		if ((ret = __os_concat_path(buf,
399 		    sizeof(buf), env->db_home, dir)) != 0) {
400 			buf[sizeof(buf) - 1] = '\0';
401 			__db_errx(env, DB_STR_A("0722",
402 			    "%s: path too long", "%s"), buf);
403 			return (EINVAL);
404 		}
405 		dir = buf;
406 	}
407 	/* Get a list of file names. */
408 	if ((ret = __os_dirlist(env, dir, 0, &names, &fcnt)) != 0) {
409 		__db_err(env, ret, DB_STR_A("0723", "%s: directory read",
410 		    "%s"), dir);
411 		return (ret);
412 	}
413 	for (cnt = (size_t)fcnt; cnt-- > 0;) {
414 		/*
415 		 * Skip files in DB's name space, except replication dbs.
416 		 */
417 		if (IS_LOG_FILE(names[cnt]))
418 			continue;
419 		if (IS_DB_FILE(names[cnt]) && !IS_REP_FILE(names[cnt])
420 #ifdef HAVE_PARTITION
421 		    && !IS_PARTITION_DB_FILE(names[cnt])
422 #endif
423 		)
424 			continue;
425 
426 		/*
427 		 * Skip DB_CONFIG.
428 		 */
429 		if (LF_ISSET(DB_BACKUP_SINGLE_DIR) &&
430 		     !strncmp(names[cnt], "DB_CONFIG", sizeof("DB_CONFIG")))
431 			continue;
432 
433 		/*
434 		 * Copy the database.
435 		 */
436 
437 		DB_MSGBUF_INIT(&mb);
438 		if (FLD_ISSET(dbenv->verbose, DB_VERB_BACKUP))
439 			__db_msgadd(env, &mb, DB_STR_A("0724",
440 			    "copying database %s%c%s to %s%c%s",
441 			    "%s%c%s %s%c%s"),
442 			    dir, PATH_SEPARATOR[0], names[cnt],
443 			    bd, PATH_SEPARATOR[0], names[cnt]);
444 
445 		/*
446 		 * Suppress errors on non-db files.
447 		 */
448 		savecall = dbenv->db_errcall;
449 		dbenv->db_errcall = save_error;
450 		savefile = dbenv->db_errfile;
451 		dbenv->db_errfile = NULL;
452 
453 		ret = __db_dbbackup(dbenv, ip, names[cnt], bd, flags);
454 
455 		dbenv->db_errcall = savecall;
456 		dbenv->db_errfile = savefile;
457 
458 		/* The file might not be a database. */
459 		if (ret == ENOENT || ret == EINVAL) {
460 			if (FLD_ISSET(dbenv->verbose, DB_VERB_BACKUP)) {
461 				__db_msgadd(env, &mb, " -- Not a database");
462 				DB_MSGBUF_FLUSH(env, &mb);
463 			}
464 			if (LF_ISSET(DB_BACKUP_FILES))
465 				ret = backup_data_copy(
466 				    dbenv, names[cnt], dir, bd, 0);
467 			else
468 				ret = 0;
469 		} else if (FLD_ISSET(dbenv->verbose, DB_VERB_BACKUP))
470 			DB_MSGBUF_FLUSH(env, &mb);
471 
472 		if (ret != 0) {
473 			if (DB_GLOBAL(saved_errstr) != NULL) {
474 				__db_errx(env, "%s", DB_GLOBAL(saved_errstr));
475 				__os_free(env, DB_GLOBAL(saved_errstr));
476 				DB_GLOBAL(saved_errstr) = NULL;
477 			}
478 			break;
479 		}
480 	}
481 
482 	__os_dirfree(env, names, fcnt);
483 
484 	return (ret);
485 }
486 
487 /*
488  * backup_read_log_dir --
489  *	Read a directory looking for log files to copy.
490  */
491 static int
backup_read_log_dir(dbenv,backup_dir,copy_minp,flags)492 backup_read_log_dir(dbenv, backup_dir, copy_minp, flags)
493 	DB_ENV *dbenv;
494 	const char *backup_dir;
495 	int *copy_minp;
496 	u_int32_t flags;
497 {
498 	ENV *env;
499 	u_int32_t aflag;
500 	size_t cnt;
501 	int ret, update, v;
502 	const char *backupd;
503 	char **begin, **names, *logd;
504 	char from[DB_MAXPATHLEN], to[DB_MAXPATHLEN];
505 
506 	env = dbenv->env;
507 	ret = 0;
508 	begin = NULL;
509 	memset(to, 0, sizeof(to));
510 
511 	/*
512 	 * Figure out where the log files are and create the log
513 	 * destination directory if necessary.
514 	 */
515 	backupd = backup_dir;
516 	if ((logd = dbenv->db_log_dir) == NULL)
517 		logd = env->db_home;
518 	else {
519 		if (!LF_ISSET(DB_BACKUP_SINGLE_DIR)) {
520 			cnt = sizeof(to);
521 			if ((ret = __os_concat_path(to,
522 			    sizeof(to), backup_dir, logd)) != 0 ||
523 			    (((cnt = strlen(to)) == sizeof(to) ||
524 			    (cnt == sizeof(to) - 1 &&
525 			    strchr(PATH_SEPARATOR, to[cnt - 1]) == NULL)) &&
526 			    LF_ISSET(DB_CREATE))) {
527 				to[sizeof(to) - 1] = '\0';
528 				__db_errx(env, DB_STR_A("0733",
529 				    "%s: path too long", "%s"), to);
530 				goto err;
531 			}
532 			if (LF_ISSET(DB_CREATE)) {
533 				if (strchr(PATH_SEPARATOR, to[cnt - 1]) == NULL)
534 					to[cnt] = PATH_SEPARATOR[0];
535 
536 				if ((ret = __db_mkpath(env, to)) != 0) {
537 					__db_err(env, ret, DB_STR_A("0734",
538 					    "%s: cannot create", "%s"), to);
539 					goto err;
540 				}
541 				to[cnt] = '\0';
542 			}
543 			if ((ret = __os_strdup(env, to, (void*) &backupd)) != 0)
544 				goto err;
545 		}
546 		if (!__os_abspath(logd)) {
547 			if ((ret = __os_concat_path(from,
548 			    sizeof(from), env->db_home, logd)) != 0) {
549 				from[sizeof(from) - 1] = '\0';
550 				__db_errx(env, DB_STR_A("0732",
551 				    "%s: path too long", "%s"), from);
552 				goto err;
553 			}
554 			if ((ret = __os_strdup(env, from, &logd)) != 0)
555 				goto err;
556 		}
557 	}
558 
559 	update = LF_ISSET(DB_BACKUP_UPDATE);
560 again:	aflag = DB_ARCH_LOG;
561 
562 	/*
563 	 * If this is an update and we are deleting files, first process
564 	 * those files that can be removed, then repeat with the rest.
565 	 */
566 	if (update)
567 		aflag = 0;
568 
569 	/* Flush the log to get latest info. */
570 	if ((ret = __log_flush(env, NULL)) != 0) {
571 		__db_err(env, ret, DB_STR("0735", "Can't flush log"));
572 		goto err;
573 	}
574 
575 	/* Get a list of file names to be copied. */
576 	if ((ret = __log_archive(env, &names, aflag)) != 0) {
577 		__db_err(env, ret, DB_STR("0736", "Can't get log file names"));
578 		goto err;
579 	}
580 	if (names == NULL)
581 		goto done;
582 	begin = names;
583 	for (; *names != NULL; names++) {
584 		/* Track the lowest-numbered log file copied. */
585 		v = atoi(*names + sizeof(LFPREFIX) - 1);
586 		if (*copy_minp == 0 || *copy_minp > v)
587 			*copy_minp = v;
588 
589 		if ((ret = __os_concat_path(from,
590 		    sizeof(from), logd, *names)) != 0) {
591 			from[sizeof(from) - 1] = '\0';
592 			__db_errx(env, DB_STR_A("0737",
593 			    "%s: path too long", "%s"), from);
594 			goto err;
595 		}
596 
597 		/*
598 		 * If we're going to remove the file, attempt to rename it
599 		 * instead of copying and then removing.  The likely failure
600 		 * is EXDEV (source and destination are on different volumes).
601 		 * Fall back to a copy, regardless of the error.  We don't
602 		 * worry about partial contents, the copy truncates the file
603 		 * on open.
604 		 */
605 		if (update) {
606 			if ((ret = __os_concat_path(to,
607 			    sizeof(to), backupd, *names)) != 0) {
608 				to[sizeof(to) - 1] = '\0';
609 				__db_errx(env, DB_STR_A("0738",
610 				    "%s: path too long", "%s"), to);
611 				goto err;
612 			}
613 			if (__os_rename(env, from, to, 1) == 0) {
614 				if (FLD_ISSET(dbenv->verbose, DB_VERB_BACKUP))
615 					__db_msg(env, DB_STR_A("0739",
616 					    "moving %s to %s",
617 					    "%s %s"), from, to);
618 				continue;
619 			}
620 		}
621 
622 		/* Copy the file. */
623 		if (backup_data_copy(dbenv, *names, logd, backupd, 1) != 0) {
624 			ret = 1;
625 			goto err;
626 		}
627 
628 		if (update) {
629 			if (FLD_ISSET(dbenv->verbose, DB_VERB_BACKUP))
630 				__db_msg(env, DB_STR_A("0740",
631 				    "removing %s", "%s"), from);
632 			if ((ret = __os_unlink(env, from, 0)) != 0) {
633 				__db_err(env, ret, DB_STR_A("0741",
634 				    "unlink of %s failed", "%s"), from);
635 				goto err;
636 			}
637 		}
638 
639 	}
640 
641 	__os_ufree(env, begin);
642 	begin = NULL;
643 done:	if (update) {
644 		update = 0;
645 		goto again;
646 	}
647 
648 	if (FLD_ISSET(dbenv->verbose, DB_VERB_BACKUP) && *copy_minp != 0)
649 		__db_msg(env, DB_STR_A("0742",
650 		    "lowest numbered log file copied: %d", "%d"),
651 		    *copy_minp);
652 err:	if (logd != dbenv->db_log_dir && logd != env->db_home)
653 		__os_free(env, logd);
654 	if (backupd != NULL && backupd != backup_dir)
655 		__os_free(env, (void *)backupd);
656 	if (begin != NULL)
657 		__os_ufree(env, begin);
658 
659 	return (ret);
660 }
661 
662 /*
663  * __db_backup --
664  *	Backup databases in the enviornment.
665  *
666  * PUBLIC: int __db_backup_pp __P((DB_ENV *, const char *, u_int32_t));
667  */
668 int
__db_backup_pp(dbenv,target,flags)669 __db_backup_pp(dbenv, target, flags)
670 	DB_ENV *dbenv;
671 	const char *target;
672 	u_int32_t flags;
673 {
674 	DB_THREAD_INFO *ip;
675 	ENV *env;
676 	int remove_max, ret;
677 
678 	env = dbenv->env;
679 	remove_max = 0;
680 
681 #undef	OKFLAGS
682 #define	OKFLAGS								\
683 	(DB_CREATE | DB_EXCL | DB_BACKUP_FILES | DB_BACKUP_SINGLE_DIR |	\
684 	DB_BACKUP_UPDATE | DB_BACKUP_NO_LOGS | DB_BACKUP_CLEAN)
685 
686 	if ((ret = __db_fchk(env, "DB_ENV->backup", flags, OKFLAGS)) != 0)
687 		return (ret);
688 
689 	if (target == NULL) {
690 		__db_errx(env,
691 		    DB_STR("0716", "Target directory may not be null."));
692 		return (EINVAL);
693 	}
694 
695 	/*
696 	 * If the target directory for the backup does not exist, create it
697 	 * with mode read-write-execute for the owner.  Ignore errors here,
698 	 * it's simpler and more portable to just always try the create.  If
699 	 * there's a problem, we'll fail with reasonable errors later.
700 	 */
701 	if (LF_ISSET(DB_CREATE))
702 		(void)__os_mkdir(NULL, target, DB_MODE_700);
703 
704 	if (LF_ISSET(DB_BACKUP_CLEAN)) {
705 		if (!LF_ISSET(DB_BACKUP_SINGLE_DIR) &&
706 		    dbenv->db_log_dir != NULL &&
707 		    (ret = backup_dir_clean(dbenv, target,
708 		    dbenv->db_log_dir, &remove_max, flags)) != 0)
709 			return (ret);
710 		if ((ret = backup_dir_clean(dbenv,
711 		    target, NULL, &remove_max, flags)) != 0)
712 			return (ret);
713 
714 	}
715 
716 	ENV_ENTER(env, ip);
717 	REPLICATION_WRAP(env,
718 	    (__db_backup(dbenv, target, ip, remove_max, flags)), 0, ret);
719 	ENV_LEAVE(env, ip);
720 	return (ret);
721 }
722 
723 /*
724  * __db_backup --
725  *	Backup databases in the enviornment.
726  */
727 static int
__db_backup(dbenv,target,ip,remove_max,flags)728 __db_backup(dbenv, target, ip, remove_max, flags)
729 	DB_ENV *dbenv;
730 	const char *target;
731 	DB_THREAD_INFO *ip;
732 	int remove_max;
733 	u_int32_t flags;
734 {
735 	ENV *env;
736 	int copy_min, ret;
737 	char **dir;
738 
739 	env = dbenv->env;
740 	copy_min = 0;
741 
742 	/*
743 	 * If the UPDATE option was not specified, copy all database
744 	 * files found in the database environment home directory and
745 	 * data directories..
746 	 */
747 	if ((ret = __env_set_backup(env, 1)) != 0)
748 		goto end;
749 	F_SET(dbenv, DB_ENV_HOTBACKUP);
750 	if (!LF_ISSET(DB_BACKUP_UPDATE)) {
751 		if ((ret = backup_read_data_dir(dbenv,
752 		    ip, env->db_home, target, flags)) != 0)
753 			goto err;
754 		for (dir = dbenv->db_data_dir;
755 		    dir != NULL && *dir != NULL; ++dir) {
756 			/*
757 			 * Don't allow absolute path names taken from the
758 			 * enviroment  -- running recovery with them would
759 			 * corrupt the source files.
760 			 */
761 			if (!LF_ISSET(DB_BACKUP_SINGLE_DIR)
762 			   && __os_abspath(*dir)) {
763 				__db_errx(env, DB_STR_A("0725",
764 "data directory '%s' is absolute path, not permitted unless backup is to a single directory",
765 				    "%s"), *dir);
766 				ret = EINVAL;
767 				goto err;
768 			}
769 			if ((ret = backup_read_data_dir(
770 			    dbenv, ip, *dir, target, flags)) != 0)
771 				goto err;
772 		}
773 	}
774 
775 	/*
776 	 * Copy all log files found in the log directory.
777 	 * The log directory defaults to the home directory.
778 	 */
779 	if ((ret = backup_read_log_dir(dbenv, target, &copy_min, flags)) != 0)
780 		goto err;
781 	/*
782 	 * If we're updating a snapshot, the lowest-numbered log file copied
783 	 * into the backup directory should be less than, or equal to, the
784 	 * highest-numbered log file removed from the backup directory during
785 	 * cleanup.
786 	 */
787 	if (LF_ISSET(DB_BACKUP_UPDATE) && remove_max < copy_min &&
788 	     !(remove_max == 0 && copy_min == 1)) {
789 		__db_errx(env, DB_STR_A("0743",
790 "the largest log file removed (%d) must be greater than or equal the smallest log file copied (%d)",
791 		    "%d %d"), remove_max, copy_min);
792 		ret = EINVAL;
793 	}
794 
795 err:	F_CLR(dbenv, DB_ENV_HOTBACKUP);
796 	(void)__env_set_backup(env, 0);
797 end:	return (ret);
798 }
799