#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <sys/types.h>
+#include <sys/wait.h>
#include <unistd.h>
#include <algorithm>
// Store a copy of the object if one does not yet exist
if (ref.get_segment().size() == 0) {
LbsObject *o = new LbsObject;
+ int object_group;
/* We might still have seen this checksum before, if the object
* was stored at some time in the past, but we have decided to
* Additionally, keep track of the age of the data by looking
* up the age of the block which was expired and using that
* instead of the current time. */
- if (db->IsOldObject(block_csum, bytes, &block_age)) {
- o->set_group("compacted");
+ if (db->IsOldObject(block_csum, bytes,
+ &block_age, &object_group)) {
+ if (object_group == 0) {
+ o->set_group("data");
+ } else {
+ char group[32];
+ sprintf(group, "compacted-%d", object_group);
+ o->set_group(group);
+ }
if (status == NULL)
status = "partial";
} else {
{
fprintf(
stderr,
+ "LBS %s\n\n"
"Usage: %s [OPTION]... --dest=DEST PATHS...\n"
"Produce backup snapshot of files in SOURCE and store to DEST.\n"
"\n"
" --filter-extension=EXT\n"
" string to append to segment files\n"
" (defaults to \".bz2\")\n"
+ " --signature-filter=COMMAND\n"
+ " program though which to filter descriptor\n"
" --scheme=NAME optional name for this snapshot\n",
- program
+ lbs_version, program
);
}
string backup_dest = "";
string localdb_dir = "";
string backup_scheme = "";
+ string signature_filter = "";
while (1) {
static struct option long_options[] = {
{"filter-extension", 1, 0, 0}, // 3
{"dest", 1, 0, 0}, // 4
{"scheme", 1, 0, 0}, // 5
+ {"signature-filter", 1, 0, 0}, // 6
{NULL, 0, 0, 0},
};
case 5: // --scheme
backup_scheme = optarg;
break;
+ case 6: // --signature-filter
+ signature_filter = optarg;
+ break;
default:
fprintf(stderr, "Unhandled long option!\n");
return 1;
/* Write a backup descriptor file, which says which segments are needed and
* where to start to restore this snapshot. The filename is based on the
- * current time. */
+ * current time. If a signature filter program was specified, filter the
+ * data through that to give a chance to sign the descriptor contents. */
string desc_filename = backup_dest + "/snapshot-";
if (backup_scheme.size() > 0)
desc_filename += backup_scheme + "-";
desc_filename = desc_filename + desc_buf + ".lbs";
- std::ofstream descriptor(desc_filename.c_str());
- descriptor << "Format: LBS Snapshot v0.2\n";
- descriptor << "Producer: LBS " << lbs_version << "\n";
+ int descriptor_fd = open(desc_filename.c_str(), O_WRONLY | O_CREAT, 0666);
+ if (descriptor_fd < 0) {
+ fprintf(stderr, "Unable to open descriptor output file: %m\n");
+ return 1;
+ }
+ pid_t signature_pid = 0;
+ if (signature_filter.size() > 0) {
+ int new_fd = spawn_filter(descriptor_fd, signature_filter.c_str(),
+ &signature_pid);
+ close(descriptor_fd);
+ descriptor_fd = new_fd;
+ }
+ FILE *descriptor = fdopen(descriptor_fd, "w");
+
+ fprintf(descriptor, "Format: LBS Snapshot v0.2\n");
+ fprintf(descriptor, "Producer: LBS %s\n", lbs_version);
strftime(desc_buf, sizeof(desc_buf), "%Y-%m-%d %H:%M:%S %z", &time_buf);
- descriptor << "Date: " << desc_buf << "\n";
+ fprintf(descriptor, "Date: %s\n", desc_buf);
if (backup_scheme.size() > 0)
- descriptor << "Scheme: " << backup_scheme << "\n";
- descriptor << "Root: " << backup_root << "\n";
+ fprintf(descriptor, "Scheme: %s\n", backup_scheme.c_str());
+ fprintf(descriptor, "Root: %s\n", backup_root.c_str());
SHA1Checksum checksum_csum;
if (checksum_csum.process_file(checksum_filename.c_str())) {
- descriptor << "Checksums: " << checksum_csum.checksum_str() << "\n";
+ string csum = checksum_csum.checksum_str();
+ fprintf(descriptor, "Checksums: %s\n", csum.c_str());
}
- descriptor << "Segments:\n";
+ fprintf(descriptor, "Segments:\n");
for (std::set<string>::iterator i = segment_list.begin();
i != segment_list.end(); ++i) {
- descriptor << " " << *i << "\n";
+ fprintf(descriptor, " %s\n", i->c_str());
+ }
+
+ fclose(descriptor);
+
+ if (signature_pid) {
+ int status;
+ waitpid(signature_pid, &status, 0);
+
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ throw IOException("Signature filter process error");
+ }
}
return 0;