Skip to content

Commit

Permalink
bcopy: replacing custom CLI parsing with CLI11
Browse files Browse the repository at this point in the history
  • Loading branch information
alaaeddineelamri committed Jul 11, 2022
1 parent c5dfef4 commit c76e399
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 113 deletions.
2 changes: 1 addition & 1 deletion core/src/stored/CMakeLists.txt
Expand Up @@ -246,7 +246,7 @@ target_link_libraries(btape PRIVATE bareossd bareos)

add_executable(bcopy ${BCOPYSRCS})

target_link_libraries(bcopy PRIVATE bareossd bareos)
target_link_libraries(bcopy PRIVATE bareossd bareos CLI11::CLI11)

install(TARGETS bareossd DESTINATION ${libdir})

Expand Down
200 changes: 101 additions & 99 deletions core/src/stored/bcopy.cc
Expand Up @@ -3,7 +3,7 @@
Copyright (C) 2002-2012 Free Software Foundation Europe e.V.
Copyright (C) 2011-2012 Planets Communications B.V.
Copyright (C) 2013-2020 Bareos GmbH & Co. KG
Copyright (C) 2013-2022 Bareos GmbH & Co. KG
This program is Free Software; you can redistribute it and/or
modify it under the terms of version three of the GNU Affero General Public
Expand Down Expand Up @@ -38,6 +38,7 @@
#include "stored/mount.h"
#include "stored/read_record.h"
#include "lib/address_conf.h"
#include "lib/cli.h"
#include "lib/bsignal.h"
#include "lib/parse_bsr.h"
#include "lib/parse_conf.h"
Expand All @@ -62,123 +63,124 @@ static Device* out_dev = NULL;
static JobControlRecord* in_jcr; /* input jcr */
static JobControlRecord* out_jcr; /* output jcr */
static BootStrapRecord* bsr = NULL;
static const char* wd = "/tmp";
static bool list_records = false;
static uint32_t records = 0;
static uint32_t jobs = 0;
static DeviceBlock* out_block;
static Session_Label sessrec;

static void usage()
{
kBareosVersionStrings.PrintCopyrightWithFsfAndPlanets(stderr, 2002);
fprintf(
stderr,
_("Usage: bcopy [-d debug_level] <input-archive> <output-archive>\n"
" -b bootstrap specify a bootstrap file\n"
" -c <path> specify a Storage configuration file or "
"directory\n"
" -D <director> specify a director name specified in the "
"Storage\n"
" configuration file for the Key Encryption Key "
"selection\n"
" -d <nn> set debug level to <nn>\n"
" -dt print timestamp in debug output\n"
" -i specify input Volume names (separated by |)\n"
" -o specify output Volume names (separated by |)\n"
" -p proceed inspite of errors\n"
" -v verbose\n"
" -w <dir> specify working directory (default /tmp)\n"
" -? print this message\n\n"));
exit(1);
}

int main(int argc, char* argv[])
{
int ch;
bool ok;
char* iVolumeName = NULL;
char* oVolumeName = NULL;
char* DirectorName = NULL;
DirectorResource* director = NULL;
bool ignore_label_errors = false;
DeviceControlRecord *in_dcr, *out_dcr;

setlocale(LC_ALL, "");
tzset();
bindtextdomain("bareos", LOCALEDIR);
textdomain("bareos");
InitStackDump();

MyNameIs(argc, argv, "bcopy");
InitMsg(NULL, NULL);

while ((ch = getopt(argc, argv, "b:c:D:d:i:o:pvw:?")) != -1) {
switch (ch) {
case 'b':
bsr = libbareos::parse_bsr(NULL, optarg);
break;

case 'c': /* specify config file */
if (configfile != NULL) { free(configfile); }
configfile = strdup(optarg);
break;

case 'D': /* specify director name */
if (DirectorName != NULL) { free(DirectorName); }
DirectorName = strdup(optarg);
break;

case 'd': /* debug level */
if (*optarg == 't') {
dbg_timestamp = true;
} else {
debug_level = atoi(optarg);
if (debug_level <= 0) { debug_level = 1; }
}
break;
InitMsg(nullptr, nullptr);

CLI::App bcopy_app;
InitCLIApp(bcopy_app, "The Bareos Volume Copy tool.", 2002);

bcopy_app
.add_option(
"-b,--parse-bootstrap",
[](std::vector<std::string> vals) {
bsr = libbareos::parse_bsr(nullptr, vals.front().data());
return true;
},
"Specify a bootstrap file.")
->check(CLI::ExistingFile)
->type_name("<bootstrap>");

bcopy_app
.add_option(
"-c,--config",
[](std::vector<std::string> val) {
if (configfile != nullptr) { free(configfile); }
configfile = strdup(val.front().c_str());
return true;
},
"Use <path> as configuration file or directory.")
->check(CLI::ExistingPath)
->type_name("<path>");

case 'i': /* input Volume name */
iVolumeName = optarg;
break;

case 'o': /* output Volume name */
oVolumeName = optarg;
break;
char* DirectorName = NULL;
bcopy_app
.add_option(
"-D,--director",
[&DirectorName](std::vector<std::string> val) {
if (DirectorName != nullptr) { free(DirectorName); }
DirectorName = strdup(val.front().c_str());
return true;
},
"Specify a director name specified in the storage. "
"Configuration file for the Key Encryption Key selection.")
->type_name("<director>");

AddDebugOptions(bcopy_app);

char* inputVolumes = nullptr;
bcopy_app
.add_option("-i,--input-volumes", inputVolumes,
"specify input Volume names (separated by |)")
->type_name("<vol1|vol2|...>");

char* outputVolumes = nullptr;
bcopy_app
.add_option("-o,--output-volumes", outputVolumes,
"specify output Volume names (separated by |)")
->type_name("<vol1|vol2|...>");

case 'p':
bool ignore_label_errors = false;
bcopy_app.add_flag(
"-p,--ignore-errors",
[&ignore_label_errors](bool val) {
ignore_label_errors = true;
forge_on = true;
break;

case 'v':
verbose++;
break;

case 'w':
wd = optarg;
break;

case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;

if (argc != 2) {
Pmsg0(0, _("Wrong number of arguments: \n"));
usage();
}
},
"Proceed inspite of errors.");

AddVerboseOption(bcopy_app);

std::string work_dir = "/tmp";
bcopy_app
.add_option("-w,--working-directory", work_dir,
"specify working directory.")
->type_name("<directory>")
->capture_default_str();

std::string input_archive;
bcopy_app
.add_option("input-archive", input_archive,
"Specify the input device name "
"(either as name of a Bareos Storage Daemon Device resource "
"or identical to the "
"Archive Device in a Bareos Storage Daemon Device resource).")
->required()
->type_name(" ");

std::string output_archive;
bcopy_app
.add_option("ouput-archive", output_archive,
"Specify the output device name "
"(either as name of a Bareos Storage Daemon Device resource "
"or identical to the "
"Archive Device in a Bareos Storage Daemon Device resource).")
->required()
->type_name(" ");

CLI11_PARSE(bcopy_app, argc, argv);

OSDependentInit();

working_directory = wd;
working_directory = work_dir.c_str();

my_config = InitSdConfig(configfile, M_ERROR_TERM);
ParseSdConfig(configfile, M_ERROR_TERM);

DirectorResource* director = NULL;
if (DirectorName) {
foreach_res (director, R_DIRECTOR) {
if (bstrcmp(director->resource_name_, DirectorName)) { break; }
Expand All @@ -199,9 +201,9 @@ int main(int argc, char* argv[])
// Setup and acquire input device for reading
Dmsg0(100, "About to setup input jcr\n");

in_dcr = new DeviceControlRecord;
in_jcr = SetupJcr("bcopy", argv[0], bsr, director, in_dcr, iVolumeName,
true); /* read device */
DeviceControlRecord* in_dcr = new DeviceControlRecord;
in_jcr = SetupJcr("bcopy", input_archive.data(), bsr, director, in_dcr,
inputVolumes, true); /* read device */
if (!in_jcr) { exit(1); }

in_jcr->impl->ignore_label_errors = ignore_label_errors;
Expand All @@ -212,9 +214,9 @@ int main(int argc, char* argv[])
// Setup output device for writing
Dmsg0(100, "About to setup output jcr\n");

out_dcr = new DeviceControlRecord;
out_jcr = SetupJcr("bcopy", argv[1], bsr, director, out_dcr, oVolumeName,
false); /* write device */
DeviceControlRecord* out_dcr = new DeviceControlRecord;
out_jcr = SetupJcr("bcopy", output_archive.data(), bsr, director, out_dcr,
outputVolumes, false); /* write device */
if (!out_jcr) { exit(1); }

out_dev = out_jcr->impl->dcr->dev;
Expand All @@ -236,7 +238,7 @@ int main(int argc, char* argv[])
}
out_block = out_jcr->impl->dcr->block;

ok = ReadRecords(in_jcr->impl->dcr, RecordCb, MountNextReadVolume);
bool ok = ReadRecords(in_jcr->impl->dcr, RecordCb, MountNextReadVolume);

if (ok || out_dev->CanWrite()) {
if (!out_jcr->impl->dcr->WriteBlockToDevice()) {
Expand Down
34 changes: 21 additions & 13 deletions docs/manuals/source/Appendix/BareosPrograms.rst
Expand Up @@ -819,19 +819,27 @@ wish to be able to use the Volume with the Console restore command, for example,

.. code-block:: shell-session
Usage: bcopy [-d debug_level] <input-archive> <output-archive>
-b bootstrap specify a bootstrap file
-c <file> specify configuration file
-D <director> specify a director name specified in the Storage
configuration file for the Key Encryption Key selection
-dnn set debug level to nn
-dt print timestamp in debug output
-i specify input Volume names (separated by |)
-o specify output Volume names (separated by |)
-p proceed inspite of I/O errors
-v verbose
-w dir specify working directory (default /tmp)
-? print this message
Usage: bcopy [OPTIONS] input-archive ouput-archive
Positionals:
input-archive REQUIRED Specify input archive names.
ouput-archive REQUIRED Specify output archive names.
Options:
-h,--help Print this help message and exit
-b,--parse-bootstrap <bootstrap> Specify a bootstrap file.
-c,--config <path> Use <path> as configuration file or directory.
-D,--director <director> Specify a director name specified in the storage.
Configuration file for the Key Encryption Key selection.
-d,--debug-level <level> Set debug level to <level>.
--dt,--debug-timestamps Print timestamp in debug output.
-i,--input-volumes <vol1|vol2|...>
Specify input Volume names (separated by |).
-o,--output-volumes <vol1|vol2|...>
Specify output Volume names (separated by |).
-p,--ignore-errors Proceed inspite of errors.
-v,--verbose Verbose user messages.
-w,--working-directory Specify working directory (default is /tmp).
By using a bootstrap file, you can copy parts of a Bareos archive file to another archive.

Expand Down

0 comments on commit c76e399

Please sign in to comment.