1 #include "config.h"
2 
3 #include <iostream>
4 #include <vector>
5 #include <map>
6 #include <string>
7 #include <cassert>
8 
9 #include "asserts.h"
10 #include "error.h"
11 #include "rmath.h"
12 #include "fs.h"
13 #include "rconfig.h"
14 #include "logger.h"
15 #include "timer.h"
16 #include "estat.h"
17 #include "reporter.h"
18 #include "strfmt.h"
19 
20 #include "vaulter.h"
21 
22 /** C'tor */
vault_manager()23 vault_manager::vault_manager()
24 {
25 	if (this != &vaulter)
26 		throw(INTERNAL_ERROR(0,"Attempt to allocate multiple vault managers"));
27 	clear();
28 }
29 
30 /** Clear the vault manager */
clear(void)31 void vault_manager::clear(void)
32 {
33 	m_lock.clear();
34 	m_selected_vault.erase();
35 	m_deleted_archives.clear();
36 	m_da_err = false;
37 	m_initialized = false;
38 }
39 
40 /** Initialize the vault manager */
init(void)41 void vault_manager::init(void)
42 {
43 	clear();
44 	m_initialized = true;
45 }
46 
47 /** Return the initialized status of the vault manager */
initialized(void) const48 const bool vault_manager::initialized(void) const
49 {
50 	return(m_initialized);
51 }
52 
53 /** Select a vault
54 
55 	If an archive of the same timestamp for the given timestamp resolution
56 	already exists on any vault, then that vault is selected.  Otherwise select
57 	a vault according to vault-selection-behavior.
58 
59  */
select(void)60 void vault_manager::select(void)
61 {
62 	std::string es;
63 	std::string ts;
64 	configuration_manager::vaults_type::const_iterator vi;
65 	std::string lockfile;
66 	std::string lstr;
67 
68 	if (!initialized())
69 		throw(INTERNAL_ERROR(0,"Vault manager not initialized"));
70 
71 	TRY_nomem(es = "Could not select a vault");
72 	try {
73 		// If an archive exists in any vault by the same timestamp as conf.stamp(),
74 		// then use that vault regardless of the selection behavior.
75 		for (
76 			vi = config.vaults().begin();
77 			vi != config.vaults().end();
78 			vi++
79 			)
80 		{
81 			subdirectory subdir;
82 			subdirectory::iterator sdi;
83 
84 			subdir.path(*vi);
85 			for (sdi = subdir.begin(); sdi != subdir.end(); sdi++) {
86 				TRY_nomem(ts = config.timestamp().str());
87 
88 				if (*sdi == ts) {
89 					TRY_nomem(lstr = "Existing archive directory found in vault: \"");
90 					TRY_nomem(lstr += *vi);
91 					TRY_nomem(lstr += "\"\n");
92 					logger.write(lstr);
93 
94 					if (config.vault_locking()) {
95 						TRY_nomem(lockfile = *vi);
96 						TRY_nomem(lockfile += "/.rvm_lock");
97 						m_lock.clear();
98 						m_lock.lockfile(lockfile);
99 						if (!m_lock.lock()) {
100 							error e(ENOLCK);
101 							e.push_back(ERROR_INSTANCE(es));
102 							TRY_nomem(es = "Could not lock vault: \"");
103 							TRY_nomem(es += *vi);
104 							TRY_nomem(es += "\"");
105 							e.push_back(ERROR_INSTANCE(es));
106 							if (m_lock.is_locked()) {
107 								TRY_nomem(es = "Vault is locked by PID: ");
108 								TRY_nomem(es += estring(m_lock.locked_by()));
109 								e.push_back(ERROR_INSTANCE(es));
110 							}
111 							throw(e);
112 						}
113 					}
114 					TRY_nomem(m_selected_vault = *vi);
115 					return;
116 				}
117 
118 				TRY_nomem(ts += ".incomplete");
119 
120 				if (*sdi == ts) {
121 					TRY_nomem(lstr = "Existing archive directory found in vault: \"");
122 					TRY_nomem(lstr += *vi);
123 					TRY_nomem(lstr += "\"\n");
124 					logger.write(lstr);
125 
126 					if (config.vault_locking()) {
127 						TRY_nomem(lockfile = *vi);
128 						TRY_nomem(lockfile += "/.rvm_lock");
129 						m_lock.clear();
130 						m_lock.lockfile(lockfile);
131 						if (!m_lock.lock()) {
132 							error e(ENOLCK);
133 							e.push_back(ERROR_INSTANCE(es));
134 							TRY_nomem(es = "Could not lock vault: \"");
135 							TRY_nomem(es += *vi);
136 							TRY_nomem(es += "\"");
137 							e.push_back(ERROR_INSTANCE(es));
138 							if (m_lock.is_locked()) {
139 								TRY_nomem(es = "Vault is locked by PID: ");
140 								TRY_nomem(es += estring(m_lock.locked_by()));
141 								e.push_back(ERROR_INSTANCE(es));
142 							}
143 							throw(e);
144 						}
145 					}
146 					TRY_nomem(m_selected_vault = *vi);
147 					return;
148 				}
149 			}
150 		}
151 
152 		// If an archive by the same timestamp does not already exist, then select
153 		// a vault.
154 		if (config.vault_selection_behavior()
155 			== configuration_manager::selection_round_robin)
156 		{
157 			std::pair<std::string,std::string> youngest;
158 
159 			for (
160 				vi = config.vaults().begin();
161 				vi != config.vaults().end();
162 				vi++
163 				)
164 			{
165 				subdirectory subdir;
166 				subdirectory::iterator sdi;
167 
168 				if (config.vault_locking()) {
169 					TRY_nomem(lockfile = *vi);
170 					TRY_nomem(lockfile += "/.rvm_lock");
171 					m_lock.clear();
172 					m_lock.lockfile(lockfile);
173 					if (m_lock.is_locked()) {
174 						std::string lstr;
175 
176 						TRY_nomem(lstr = "Skipping locked vault: \"");
177 						TRY_nomem(lstr += *vi);
178 						TRY_nomem(lstr += "\"\n");
179 						logger.write(lstr);
180 
181 						continue;
182 					}
183 				}
184 
185 				subdir.path(*vi);
186 				for (sdi = subdir.begin(); sdi != subdir.end(); sdi++) {
187 					if ((youngest.first < *sdi) || (youngest.first.size() == 0)) {
188 						TRY_nomem(youngest.first = *sdi);
189 						TRY_nomem(youngest.second = *vi);
190 					}
191 				}
192 			}
193 
194 			TRY_nomem(m_selected_vault = "");
195 			if (youngest.second.size() == 0) {
196 				TRY_nomem(m_selected_vault = config.vaults()[0]);
197 			}
198 			else {
199 				for (
200 					vi = config.vaults().begin();
201 					vi != config.vaults().end();
202 					vi++
203 					)
204 				{
205 					if (*vi == youngest.second) {
206 						if ((vi+1) == config.vaults().end()) {
207 							TRY_nomem(m_selected_vault = config.vaults()[0]);
208 						}
209 						else {
210 							TRY_nomem(m_selected_vault = *(vi+1));
211 						}
212 					}
213 				}
214 			}
215 		}
216 		else {
217 			std::pair<std::string,filesystem::size_type> most_space;
218 			filesystem fsys;
219 
220 			TRY_nomem(most_space.first = config.vaults()[0]);
221 			fsys.path(config.vaults()[0]);
222 			most_space.second = fsys.free_blocks();
223 			for (
224 				vi = (config.vaults().begin()+1);
225 				vi != config.vaults().end();
226 				vi++
227 				)
228 			{
229 				fsys.path(*vi);
230 				if (most_space.second < fsys.free_blocks()) {
231 					TRY_nomem(most_space.first = *vi);
232 					most_space.second = fsys.free_blocks();
233 				}
234 			}
235 			TRY_nomem(m_selected_vault = most_space.first);
236 		}
237 	}
238 	catch(error e) {
239 		e.push_back(es);
240 		throw(e);
241 	}
242 	catch(...) {
243 		error e(0);
244 		if (errno == ENOMEM) {
245 			e = err_nomem;
246 			e.push_back(es);
247 			throw(e);
248 		}
249 		e = err_unknown;
250 		e.push_back(es);
251 		throw(e);
252 	}
253 
254 	if (m_selected_vault.size() == 0)
255 		throw(ERROR(0,es));
256 }
257 
258 /** Return a list of archive directories in the selected vault
259 
260 	Return a list of archive directories in the selected vault, including
261 	incomplete archives.  Ignore all other directories.
262  */
get_archive_list(void)263 const subdirectory vault_manager::get_archive_list(void)
264 {
265 	subdirectory subdir;
266 	subdirectory::iterator sdi;
267 
268 	if (!initialized())
269 		throw(INTERNAL_ERROR(0,"Vault manager not initialized"));
270 
271 	if (!selected())
272 		throw(INTERNAL_ERROR(0,"No vault selected"));
273 
274 	subdir.path(vault());
275 
276 	sdi = subdir.begin();
277 	while (sdi != subdir.end()) {
278 		if (!is_timestamp((*sdi).substr(0,(*sdi).find(".incomplete"))))
279 		{
280 			subdir.erase(sdi);
281 			sdi = subdir.begin();
282 		}
283 		else {
284 			sdi++;
285 		}
286 	}
287 
288 	return(subdir);
289 }
290 
291 /** Return the path to the selected vault */
vault(void) const292 const std::string vault_manager::vault(void) const
293 {
294 	if (!initialized())
295 		throw(INTERNAL_ERROR(0,"Vault manager not initialized"));
296 
297 	if (!selected())
298 		throw(INTERNAL_ERROR(0,"No vault selected"));
299 
300 	return(m_selected_vault);
301 }
302 
303 /** Return whether or not a vault has been selected yet */
selected(void) const304 const bool vault_manager::selected(void) const
305 {
306 	bool value = true;
307 
308 	if (!initialized())
309 		throw(INTERNAL_ERROR(0,"Vault manager not initialized"));
310 
311 	if (m_selected_vault.size() == 0)
312 		value = false;
313 
314 	return(value);
315 }
316 
317 /** Return the percent of used blocks and used inodes in the selected vault */
usage(uint16 & a_blocks,uint16 & a_inodes) const318 void vault_manager::usage(uint16 &a_blocks, uint16 &a_inodes) const
319 {
320 	filesystem fsys;
321 	safe_num<uint64> blocks, inodes;
322 
323 	if (!initialized())
324 		throw(INTERNAL_ERROR(0,"Vault manager not initialized"));
325 
326 	if (!selected())
327 		throw(INTERNAL_ERROR(0,"No vault selected"));
328 
329 	fsys.path(vault());
330 
331 	if (fsys.total_blocks() == 0)
332 		blocks = 0;
333 	else {
334 		try {
335 			blocks = fsys.free_blocks();
336 			// blocks *= 100;
337 			// blocks /= fsys.total_blocks();
338 			blocks /= fsys.total_blocks() / 100;
339 		}
340 		catch(error e) {
341 			logger.write("*** ERROR: Overflow error detected in vault_manager::usage() while calculating percent blocks used\n");
342 			logger.write(e.str());
343 			blocks = 0;
344 		}
345 		catch(...) {
346 			logger.write("*** ERROR: Unknown error detected in vault_manager::usage() while calculating percent blocks used\n");
347 			blocks = 0;
348 		}
349 	}
350 
351 	if (fsys.free_inodes() == 0)
352 		inodes = 0;
353 	else {
354 		try {
355 			inodes = fsys.free_inodes();
356 			// inodes *= 100;
357 			// inodes /= fsys.total_inodes();
358 			inodes /= fsys.total_inodes() / 100;
359 		}
360 		catch(error e) {
361 			logger.write("*** ERROR: Overflow error detected in vault_manager::usage() while calculating percent inodes used\n");
362 			logger.write(e.str());
363 			blocks = 0;
364 		}
365 		catch(...) {
366 			logger.write("*** ERROR: Unknown error detected in vault_manager::usage() while calculating percent inodes used\n");
367 			blocks = 0;
368 		}
369 	}
370 
371 	ASSERT(blocks <= max_limit(blocks));
372 	ASSERT(inodes <= max_limit(inodes));
373 
374 	a_blocks = blocks.value();
375 	a_inodes = inodes.value();
376 }
377 
378 /** Test to see if a vault has exceeded it's overflow threshold */
overflow(bool a_report)379 const bool vault_manager::overflow(bool a_report)
380 {
381 	uint16 free_blocks;
382 	uint16 free_inodes;
383 	bool value = false;
384 	std::string lstr;
385 
386 	if (!initialized())
387 		throw(INTERNAL_ERROR(0,"Vault manager not initialized"));
388 
389 	if (!selected())
390 		throw(INTERNAL_ERROR(0,"No vault selected"));
391 
392 	usage(free_blocks, free_inodes);
393 	if (free_blocks < config.vault_overflow_blocks())
394 		value = true;
395 	if (free_inodes < config.vault_overflow_inodes())
396 		value = true;
397 
398 	if (value && a_report) {
399 		TRY_nomem(lstr = "Vault overflow detected: ");
400 		TRY_nomem(lstr += vault());
401 		TRY_nomem(lstr += "\n");
402 		logger.write(lstr);
403 
404 		TRY_nomem(lstr = "     Threshold: ");
405 		TRY_nomem(lstr +=
406 			percent_string(config.vault_overflow_blocks(),
407 				static_cast<uint16>(100)));
408 		TRY_nomem(lstr += " free blocks, ");
409 		TRY_nomem(lstr +=
410 			percent_string(config.vault_overflow_inodes(),
411 				static_cast<uint16>(100)));
412 		TRY_nomem(lstr += " free inodes");
413 		TRY_nomem(lstr += "\n");
414 		logger.write(lstr);
415 
416 		TRY_nomem(lstr = "Vault capacity: ");
417 		TRY_nomem(lstr += percent_string(free_blocks,static_cast<uint16>(100)));
418 		TRY_nomem(lstr += " free blocks, ");
419 		TRY_nomem(lstr += percent_string(free_inodes,static_cast<uint16>(100)));
420 		TRY_nomem(lstr += " free inodes");
421 		TRY_nomem(lstr += "\n");
422 		logger.write(lstr);
423 
424 		estring __e = estring("Overflow Detected:");
425 		reporter.vault().add_report(
426 			vault_stats_report(estring("Overflow Detected:"),filesystem(vault()))
427 			);
428 	}
429 
430 	return(value);
431 }
432 
433 /** Find the oldest archive in the vault and delete it */
delete_oldest_archive(void)434 void vault_manager::delete_oldest_archive(void)
435 {
436 	std::string es;
437 	estring ts;
438 	estring tsi;
439 	std::string lstr;
440 	subdirectory archive_list;
441 	std::string oldest;
442 	std::string dir;
443 	std::string delete_dir;
444 	estring estr;
445 	timer t;
446 	uint16 free_blocks, free_inodes;
447 	subdirectory logfile_list;
448 	subdirectory::const_iterator ilf;
449 
450 	if (!initialized())
451 		throw(INTERNAL_ERROR(0,"Vault manager not initialized"));
452 
453 	if (!selected())
454 		throw(INTERNAL_ERROR(0,"No vault selected"));
455 
456 	TRY_nomem(ts = config.timestamp().str());
457 	TRY_nomem(tsi = ts + ".incomplete");
458 
459 	archive_list = get_archive_list();
460 	if (
461 		(archive_list.size() == 0)
462 		|| (
463 			(archive_list.size() == 1)
464 			&& (archive_list[0] == ts || archive_list[0] == tsi)
465 			)
466 		)
467 	{
468 		TRY_nomem(es = "Vault has insufficient space: \"");
469 		TRY_nomem(es += vault());
470 		TRY_nomem(es += "\"");
471 		exit_manager.assign(exitstat::vault_full);
472 		throw(ERROR(0,es));
473 	}
474 
475 	TRY_nomem(oldest = archive_list[0]);
476 	if (oldest == ts || oldest == tsi) {
477 		TRY_nomem(lstr = "Oldest is actually archive in use: \"");
478 		TRY_nomem(lstr += oldest);
479 		TRY_nomem(lstr += "\"  Skipping to next archive...\n");
480 		logger.write(lstr);
481 		TRY_nomem(oldest = archive_list[1]);
482 	}
483 
484 	if (oldest.find(".incomplete") != std::string::npos) {
485 		TRY_nomem(lstr = "WARNING: Oldest archive found is incomplete.\n");
486 		logger.write(lstr);
487 	}
488 
489 	TRY_nomem(lstr = "Deleting oldest archive: \"");
490 	TRY_nomem(lstr += oldest);
491 	TRY_nomem(lstr += "\"\n");
492 	logger.write(lstr);
493 
494 	TRY_nomem(dir = vault());
495 	TRY_nomem(dir += "/");
496 	TRY_nomem(dir += oldest);
497 	t.start();
498 	try {
499 		m_deleted_archives.push_back(oldest);
500 	}
501 	catch(...) {
502 		m_da_err = true;
503 	}
504 
505 	delete_dir = dir;
506 	if (delete_dir.find(".deleting") == std::string::npos)
507 		delete_dir += ".deleting";
508 	rename_file(dir, delete_dir);
509 	if (config.delete_command_path().size() == 0)
510 		rm_recursive(delete_dir);
511 	else {
512 		std::string es;
513 		std::string cmdline;
514 
515 		TRY_nomem(es = "Delete command returned non-zero exit value: \"");
516 		TRY_nomem(es += oldest);
517 		TRY_nomem(es += "\"");
518 		cmdline = config.delete_command_path();
519 		cmdline += " \"";
520 		cmdline += delete_dir;
521 		cmdline += "\"";
522 		if (system(cmdline.c_str()) != 0)
523 			throw(ERROR(1,es));
524 	}
525 	t.stop();
526 
527 	TRY_nomem(lstr = "Deletion complete, duration: ");
528 	TRY_nomem(lstr += t.duration());
529 	TRY_nomem(lstr += "\n");
530 	logger.write(lstr);
531 
532 	usage(free_blocks, free_inodes);
533 	TRY_nomem(lstr = "Vault capacity: ");
534 	TRY_nomem(lstr += percent_string(free_blocks,static_cast<uint16>(100)));
535 	TRY_nomem(lstr += " free blocks, ");
536 	TRY_nomem(lstr += percent_string(free_inodes,static_cast<uint16>(100)));
537 	TRY_nomem(lstr += " free inodes");
538 	TRY_nomem(lstr += "\n");
539 	logger.write(lstr);
540 
541 	estr = "Deleted ";
542 	estr += oldest;
543 	estr += ":";
544 	reporter.vault().add_report(vault_stats_report(estr,filesystem(vault())));
545 
546 	// This is a grey area for me: Should log/report file removal be managed by
547 	// log_manager/report_manager, or is it OK to do it here?  For simplicity
548 	// sake, I do it here.
549 	//
550 	if (config.delete_old_log_files()) {
551 		estring wildcard;
552 
553 		logger.write("Searching for old log files to delete...\n");
554 		wildcard = oldest;
555 		wildcard += ".log*";
556 		logfile_list.path(config.log_dir(), wildcard);
557 		for (ilf = logfile_list.begin(); ilf != logfile_list.end(); ilf++) {
558 			estring file;
559 
560 			file = config.log_dir();
561 			file += "/";
562 			file += *ilf;
563 
564 			try {
565 				rm_file(file);
566 			}
567 			catch(error e) {
568 				estring es;
569 
570 				es = "*** ERROR: Could not remove log file: ";
571 				es += *ilf;
572 
573 				logger.write(es);
574 				logger.write(e.str());
575 
576 				// Should I throw an error here, or should deletion of old log files
577 				// not be considered important enough to interrupt archiving?
578 			}
579 			catch(...) {
580 				estring es;
581 
582 				es = "*** ERROR: Unknown error detected in vault_manager::delete_oldest_archive() while deleting old log file: ";
583 				es += *ilf;
584 				es += '\n';
585 
586 				logger.write(es);
587 
588 				// Should I throw an error here, or should deletion of old log files
589 				// not be considered important enough to interrupt archiving?
590 			}
591 		}
592 
593 		wildcard = oldest;
594 		wildcard += ".relink*";
595 		logfile_list.path(config.log_dir(), wildcard);
596 		for (ilf = logfile_list.begin(); ilf != logfile_list.end(); ilf++) {
597 			estring file;
598 
599 			file = config.log_dir();
600 			file += "/";
601 			file += *ilf;
602 
603 			try {
604 				rm_file(file);
605 			}
606 			catch(error e) {
607 				estring es;
608 
609 				es = "*** ERROR: Could not remove relink file: ";
610 				es += *ilf;
611 
612 				logger.write(es);
613 				logger.write(e.str());
614 
615 				// Should I throw an error here, or should deletion of old log files
616 				// not be considered important enough to interrupt archiving?
617 			}
618 			catch(...) {
619 				estring es;
620 
621 				es = "*** ERROR: Unknown error detected in vault_manager::delete_oldest_archive() while deleting old relink file: ";
622 				es += *ilf;
623 				es += '\n';
624 
625 				logger.write(es);
626 
627 				// Should I throw an error here, or should deletion of old log files
628 				// not be considered important enough to interrupt archiving?
629 			}
630 		}
631 	}
632 
633 	if (config.delete_old_report_files()) {
634 		estring wildcard;
635 
636 		logger.write("Searching for old report files to delete...\n");
637 		wildcard = oldest;
638 		wildcard += ".report*";
639 		logfile_list.path(config.log_dir(), wildcard);
640 		for (ilf = logfile_list.begin(); ilf != logfile_list.end(); ilf++) {
641 			estring file;
642 
643 			file = config.log_dir();
644 			file += "/";
645 			file += *ilf;
646 
647 			try {
648 				rm_file(file);
649 			}
650 			catch(error e) {
651 				estring es;
652 
653 				es = "*** ERROR: Could not remove report file: ";
654 				es += *ilf;
655 
656 				logger.write(es);
657 				logger.write(e.str());
658 
659 				// Should I throw an error here, or should deletion of old log files
660 				// not be considered important enough to interrupt archiving?
661 			}
662 			catch(...) {
663 				estring es;
664 
665 				es = "*** ERROR: Unknown error detected in vault_manager::delete_oldest_archive() while deleting old log file: ";
666 				es += *ilf;
667 				es += '\n';
668 
669 				logger.write(es);
670 
671 				// Should I throw an error here, or should deletion of old log files
672 				// not be considered important enough to interrupt archiving?
673 			}
674 		}
675 	}
676 }
677 
678 /** Prepare the selected vault
679 
680 	Check the selected vault for overflow.  If the overflow threshold has been
681 	exceeded and the vault-overflow-behavior setting is not quit, then delete
682 	the oldest archive in the vault.  Depending on vault-overflow-behavior,
683 	possibly repeat this action until either there is space free or there are no
684 	archives left in the vault.
685 
686 */
prepare(bool a_assume_overflow)687 void vault_manager::prepare(bool a_assume_overflow)
688 {
689 	std::string es;
690 	std::string lstr;
691 
692 	/*
693 	estring debug_estr;
694 
695 	debug_estr = "[DEBUG]: vault_manager::prepare() - a_assume_overflow = ";
696 	debug_estr += estring(a_assume_overflow);
697 	debug_estr += "\n";
698 	logger.write(debug_estr);
699 	*/
700 
701 	if (!initialized())
702 		throw(INTERNAL_ERROR(0,"Vault manager not initialized"));
703 
704 	if (!selected())
705 		throw(INTERNAL_ERROR(0,"No vault selected"));
706 
707 	if (!overflow() && !a_assume_overflow)
708 		return;
709 
710 	// logger.write("Vault has insufficient space\n");
711 	// logger.write("[DEBUG]: vault_manager::prepare() - Cleaning vault...\n");
712 
713 	if (config.vault_overflow_behavior()
714 		== configuration_manager::overflow_quit)
715 	{
716 		TRY_nomem(es = "Vault has insufficient space: \"");
717 		TRY_nomem(es += vault());
718 		TRY_nomem(es += "\"");
719 		throw(ERROR(0,es));
720 	}
721 
722 	if (config.vault_overflow_behavior()
723 			== configuration_manager::overflow_delete_oldest)
724 	{
725 		if (m_deleted_archives.size() == 0) {
726 			TRY(delete_oldest_archive(),"Failure preparing vault");
727 			a_assume_overflow = false;
728 		}
729 		else {
730 			logger.write("Vault has insufficient space\n");
731 			throw(ERROR(0,"Vault has insufficient space"));
732 		}
733 	}
734 
735 	if (!overflow() && !a_assume_overflow)
736 		return;
737 
738 	if (config.vault_overflow_behavior()
739 		== configuration_manager::overflow_delete_until_free)
740 	{
741 		while (overflow() || a_assume_overflow) {
742 			// logger.write("Vault has insufficient space\n");
743 			TRY(delete_oldest_archive(),"Failure preparing vault");
744 			a_assume_overflow = false;
745 		}
746 	}
747 	else {
748 		// logger.write("Vault has insufficient space\n");
749 		exit_manager.assign(exitstat::vault_full);
750 		// throw(ERROR(0,"Vault has insufficient space"));
751 	}
752 }
753 
754 /** Return a list of deleted archives */
deleted_archives(void) const755 const std::vector<std::string>& vault_manager::deleted_archives(void) const
756 {
757 	if (!initialized())
758 		throw(INTERNAL_ERROR(0,"Vault manager not initialized"));
759 
760 	return(m_deleted_archives);
761 }
762 
763 /** Return whether or not there was an error deleting archives */
err_deleted_archives(void) const764 const bool vault_manager::err_deleted_archives(void) const
765 {
766 	if (!initialized())
767 		throw(INTERNAL_ERROR(0,"Vault manager not initialized"));
768 
769 	return(m_da_err);
770 }
771 
772 /** The global vault manager */
773 vault_manager vaulter;
774 
775