From 62024a979624d9debf41fad878c67b3a9a988eaf Mon Sep 17 00:00:00 2001 From: Alaa Eddine Elamri Date: Fri, 8 Jul 2022 11:23:14 +0200 Subject: [PATCH] dird: replacing custom CLI parsing with CLI11 --- core/manpages/bareos-dir.8 | 35 ++- core/scripts/bareos-config-lib.sh.in | 8 +- core/src/dird/CMakeLists.txt | 6 +- core/src/dird/dird.cc | 253 +++++++----------- core/src/lib/bnet_network_dump.cc | 12 +- docs/manuals/CMakeLists.txt | 6 +- .../source/Appendix/BareosPrograms.rst | 25 +- .../TasksAndConcepts/CatalogMaintenance.rst | 4 +- systemtests/tests/config-dump/testrunner | 30 ++- 9 files changed, 176 insertions(+), 203 deletions(-) diff --git a/core/manpages/bareos-dir.8 b/core/manpages/bareos-dir.8 index df30d76fb51..67d189c1ce9 100644 --- a/core/manpages/bareos-dir.8 +++ b/core/manpages/bareos-dir.8 @@ -22,43 +22,52 @@ network backup system: it is responsible for scheduling and coordinating backups across the network. .SH OPTIONS .TP -.BI \-c\ path +.BI \-c,--config\ path Specify the configuration file or directory to use. .TP -.BI \-d\ nn +.BI \-d,--debug-level\ nn Set debug level to \fInn\fP. .TP -.BI \-dt +.BI \--dt,--debug-timestamps Print timestamp in debug output. .TP -.BI \-f +.BI \-f,--foreground Run in foreground (for debugging). .TP -.BI \-g\ group +.BI \-g,--group\ group Set the group/gid to run as. .TP -.BI \-m +.BI \-m,--print-kaboom Print kaboom output (for debugging). .TP -.BI \-p\ file +.BI \-p,--pid-file\ file Specify the full path to the pidfile. .TP -.BI \-r\ job +.BI \-r,--run-job\ job Run . .TP -.BI \-s +.BI \-s,--no-signals No signals (for debugging). .TP -.B \-t +.BI \-t,--test-config Test the configuration and report errors. .TP -.BI \-u\ user +.BI \-u,--user\ user Set the username/uid to run as. .TP -.BI \-v +.BI \-v,--verbose Set verbose mode. .TP -.BI \-? +.BI \--xc,--export-config\ [ []] +Print all or specific configuration resources and exit. +.TP +.BI \--xs,--export-schema +Print configuration schema in JSON format and exit. +.TP +.BI \-z,--network-debugging +Switch network debugging on. +.TP +.BI \-h,--help,-? Show version and usage of program. .SH SEE ALSO .BR bareos-fd (8), diff --git a/core/scripts/bareos-config-lib.sh.in b/core/scripts/bareos-config-lib.sh.in index 35d74903c8a..3b072e7e6bc 100644 --- a/core/scripts/bareos-config-lib.sh.in +++ b/core/scripts/bareos-config-lib.sh.in @@ -580,13 +580,13 @@ set_config_param() # - multiple directives in one line, # separated by ";" # (could by handled by RS="\n|;", but this could cause problems with other lines) - # Possible workaround: get expanded config by "bareos-* -xc" + # Possible workaround: get expanded config by "bareos-* --xc" # - "}" must be the only character in a line # - between "{" and the first directive must be a line break # - Name directive must come before directive to modify, # preferably Name is the first directive of a resource # - does not handle includes ("@" and include scripts) - # Possible workaround: get expanded config by "bareos-* -xc" + # Possible workaround: get expanded config by "bareos-* --xc" # configuration component (either file or bareos-dir, ...) COMPONENT="${1}" @@ -767,7 +767,7 @@ get_database_param() # Retrieve PARAM line in configuration section output # Beware we can be called before bareos-dir is installed on system (Debian like) if [ -x "${BAREOS_DIRECTOR_BINARY}" ];then - CONFIG=$(${BAREOS_DIRECTOR_BINARY} -c "${BAREOS_CONFIG_DIR}" -xcCatalog="$CATALOG") + CONFIG=$(${BAREOS_DIRECTOR_BINARY} -c "${BAREOS_CONFIG_DIR}" --xc Catalog "$CATALOG") if ! VALUE="$(get_config_line_parameter "${CONFIG}" "${PARAM}")" then # if default value is given, return it anyway @@ -819,7 +819,7 @@ set_postgresql_environment_variables() { CATALOG="${1:-MyCatalog}" - if ! CONFIG=$(${BAREOS_DIRECTOR_BINARY} -c "${BAREOS_CONFIG_DIR}" -xcCatalog="${CATALOG}"); then + if ! CONFIG=$(${BAREOS_DIRECTOR_BINARY} -c "${BAREOS_CONFIG_DIR}" --xc Catalog "${CATALOG}"); then error "Failed to get configuration of catalog $CATALOG" error "${CONFIG}" return 1 diff --git a/core/src/dird/CMakeLists.txt b/core/src/dird/CMakeLists.txt index edac5f9db95..86e38d3b83d 100644 --- a/core/src/dird/CMakeLists.txt +++ b/core/src/dird/CMakeLists.txt @@ -1,6 +1,6 @@ # BAREOS® - Backup Archiving REcovery Open Sourced # -# Copyright (C) 2017-2021 Bareos GmbH & Co. KG +# Copyright (C) 2017-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 @@ -158,7 +158,9 @@ target_link_libraries( add_executable(bareos-dir) target_sources(bareos-dir PRIVATE dird.cc) -target_link_libraries(bareos-dir PRIVATE dird_objects bareossql bareosfind) +target_link_libraries( + bareos-dir PRIVATE dird_objects bareossql bareosfind CLI11::CLI11 +) if(HAVE_WIN32) target_sources( diff --git a/core/src/dird/dird.cc b/core/src/dird/dird.cc index f629622a121..f8b1970f301 100644 --- a/core/src/dird/dird.cc +++ b/core/src/dird/dird.cc @@ -47,6 +47,7 @@ #include "lib/thread_specific_data.h" #include "lib/util.h" #include "lib/watchdog.h" +#include "lib/cli.h" #ifndef HAVE_REGEX_H # include "lib/bregex.h" @@ -90,7 +91,6 @@ void StoreMigtype(LEX* lc, ResourceItem* item, int index, int pass); void InitDeviceResources(); static char* runjob = nullptr; -static bool background = true; static bool test_config = false; struct resource_table_reference; static alist* reload_table = nullptr; @@ -177,38 +177,6 @@ static bool DirDbLogInsert(JobControlRecord* jcr, return jcr->db->SqlQuery(query.c_str()); } -static void usage() -{ - kBareosVersionStrings.PrintCopyrightWithFsfAndPlanets(stderr, 2000); - fprintf( - stderr, - _("Usage: bareos-dir [options]\n" - " -c use as configuration file or " - "directory\n" - " -d set debug level to \n" - " -dt print timestamp in debug output\n" - " -f run in foreground (for debugging)\n" - " -g run as group \n" - " -m print kaboom output (for debugging)\n" -#if !defined(HAVE_WIN32) - " -p full path to pidfile (default: none)\n" -#endif - " -r run now\n" - " -s no signals (for debugging)\n" - " -t test - read configuration and exit\n" - " -u run as user \n" - " -v verbose user messages\n" - " -xc[resource[=]] print all or specific configuration " - "resources and exit\n" - " -xs print configuration schema in JSON " - "format and exit\n" - " -? print this message\n" - "\n")); - - exit(1); -} - - /********************************************************************* * * Main BAREOS Director Server program @@ -220,16 +188,6 @@ static void usage() int main(int argc, char* argv[]) { - int ch; - cat_op mode; - bool no_signals = false; - bool export_config = false; - std::string export_config_resourcetype; - std::string export_config_resourcename; - bool export_config_schema = false; - char* uid = nullptr; - char* gid = nullptr; - setlocale(LC_ALL, ""); tzset(); bindtextdomain("bareos", LOCALEDIR); @@ -242,121 +200,116 @@ int main(int argc, char* argv[]) console_command = RunConsoleCommand; -#if HAVE_WIN32 - std::string allowed_parameters("c:d:fg:mr:stu:vx:z:?"); + CLI::App dir_app; + InitCLIApp(dir_app, "The Bareos Director Daemon.", 2000); + + dir_app + .add_option( + "-c,--config", + [](std::vector val) { + if (configfile != nullptr) { free(configfile); } + configfile = strdup(val.front().c_str()); + return true; + }, + "Use as configuration file or directory.") + ->check(CLI::ExistingPath) + ->type_name(""); + + AddDebugOptions(dir_app); + + bool foreground = false; + CLI::Option* foreground_option + = dir_app.add_flag("-f,--foreground", foreground, "Run in foreground."); + + char* gid = nullptr; + dir_app.add_option("-g,--group", gid, "Run as group .") + ->type_name(""); + + dir_app.add_flag("-m,--print-kaboom", prt_kaboom, + "Print kaboom output (for debugging)."); + + auto testconfig_option = dir_app.add_flag( + "-t,--test-config", test_config, "Test - read configuration and exit."); + +#if !defined(HAVE_WIN32) + dir_app + .add_option("-p,--pid-file", pidfile_path, + "Full path to pidfile (default: none).") + ->excludes(foreground_option) + ->excludes(testconfig_option) + ->type_name(""); #else - std::string allowed_parameters("c:d:fg:mr:p:stu:vx:z:?"); + // to silence unused variable error on windows + (void)testconfig_option; + (void)foreground_option; #endif - while ((ch = getopt(argc, argv, allowed_parameters.c_str())) != -1) { - switch (ch) { - case 'c': /* specify config file */ - if (configfile != nullptr) { free(configfile); } - configfile = strdup(optarg); - break; - - case 'd': /* set debug level */ - if (*optarg == 't') { - dbg_timestamp = true; - } else { - debug_level = atoi(optarg); - if (debug_level <= 0) { debug_level = 1; } - } - Dmsg1(10, "Debug level = %d\n", debug_level); - break; - - case 'f': /* run in foreground */ - background = false; - break; - - case 'g': /* set group id */ - gid = optarg; - break; - - case 'm': /* print kaboom output */ - prt_kaboom = true; - break; - - case 'p': - pidfile_path = strdup(optarg); - break; - - case 'r': /* run job */ - if (runjob != nullptr) { free(runjob); } - if (optarg) { runjob = strdup(optarg); } - break; - - case 's': /* turn off signals */ - no_signals = true; - break; - - case 't': /* test config */ - test_config = true; - break; - - case 'u': /* set uid */ - uid = optarg; - break; - - case 'v': /* verbose */ - verbose++; - break; - - case 'x': /* export configuration/schema and exit */ - if (*optarg == 's') { - export_config_schema = true; - } else if (*optarg == 'c') { - export_config = true; - // erase first char ('c') - std::string export_config_parameter = std::string(optarg).erase(0, 1); - size_t splitpos = export_config_parameter.find('='); - if (splitpos == export_config_parameter.npos) { - export_config_resourcetype = export_config_parameter; - } else { - export_config_resourcetype - = export_config_parameter.substr(0, splitpos); - export_config_resourcename - = export_config_parameter.substr(splitpos + 1); - } - } else { - usage(); - } - break; + dir_app + .add_option( + "-r,--run-job", + [](std::vector val) { + if (runjob != nullptr) { free(runjob); } + runjob = strdup(val.front().c_str()); + return true; + }, + "Run specified job now.") + ->type_name(""); - case 'z': /* switch network debugging on */ - if (!BnetDump::EvaluateCommandLineArgs(optarg)) { exit(1); } - break; + bool no_signals = false; + dir_app.add_flag("-s,--no-signals", no_signals, + "No signals (for debugging)."); - case '?': - default: - usage(); - break; - } - } - argc -= optind; - argv += optind; + char* uid = nullptr; + dir_app.add_option("-u,--user", uid, "Run as given user .") + ->type_name(""); - if (!background && pidfile_path) { - Emsg0(M_WARNING, 0, - "Options -p and -f cannot be used together. You cannot create a " - "pid file when in foreground mode.\n"); + AddVerboseOption(dir_app); - exit(0); - } + bool export_config = false; + std::string export_config_resourcetype; + std::string export_config_resourcename; + CLI::Option* xc + = dir_app + .add_option( + "--xc,--export-config", + [&export_config, &export_config_resourcetype, + &export_config_resourcename](std::vector val) { + export_config = true; + if (val.size() >= 1) { + export_config_resourcetype = val[0]; + if (val.size() >= 2) { + export_config_resourcename = val[1]; + } + } + return true; + }, + "Print all or specific configuration resources and exit.") + ->type_name("[ []]") + ->expected(0, 2); - if (!no_signals) { InitSignals(TerminateDird); } + bool export_config_schema = false; + dir_app + .add_flag("--xs,--export-schema", export_config_schema, + "Print configuration schema in JSON format and exit.") + ->excludes(xc); + + dir_app.add_option( + "-z,--network-debugging", + [](std::vector val) { + if (!BnetDump::EvaluateCommandLineArgs(val.front().c_str())) { + exit(1); + } + return true; + }, + "Switch network debugging on."); - if (argc) { - if (configfile != nullptr) { free(configfile); } - configfile = strdup(*argv); - argc--; - argv++; - } - if (argc) { usage(); } + CLI11_PARSE(dir_app, argc, argv); + + if (!no_signals) { InitSignals(TerminateDird); } int pidfile_fd = -1; #if !defined(HAVE_WIN32) - if (!test_config && background && pidfile_path) { + if (!test_config && !foreground && pidfile_path) { pidfile_fd = CreatePidFile("bareos-dir", pidfile_path); } #endif @@ -365,10 +318,10 @@ int main(int argc, char* argv[]) drop(uid, gid, false); /* reduce privileges if requested */ } + my_config = InitDirConfig(configfile, M_ERROR_TERM); if (export_config_schema) { PoolMem buffer; - my_config = InitDirConfig(configfile, M_ERROR_TERM); PrintConfigSchemaJson(buffer); printf("%s\n", buffer.c_str()); @@ -376,7 +329,6 @@ int main(int argc, char* argv[]) return 0; } - my_config = InitDirConfig(configfile, M_ERROR_TERM); my_config->ParseConfig(); if (export_config) { @@ -400,7 +352,7 @@ int main(int argc, char* argv[]) } if (!test_config) { /* we don't need to do this block in test mode */ - if (background) { + if (!foreground) { daemon_start("bareos-dir", pidfile_fd, pidfile_path); InitStackDump(); /* grab new pid */ } @@ -431,8 +383,9 @@ int main(int argc, char* argv[]) #endif LoadDirPlugins(me->plugin_directory, me->plugin_names); + // If we are in testing mode, we don't try to fix the catalog - mode = (test_config) ? CHECK_CONNECTION : UPDATE_AND_FIX; + cat_op mode = (test_config) ? CHECK_CONNECTION : UPDATE_AND_FIX; if (!CheckCatalog(mode)) { Jmsg((JobControlRecord*)nullptr, M_ERROR_TERM, 0, diff --git a/core/src/lib/bnet_network_dump.cc b/core/src/lib/bnet_network_dump.cc index f2043d02ff0..f0cf335445d 100644 --- a/core/src/lib/bnet_network_dump.cc +++ b/core/src/lib/bnet_network_dump.cc @@ -1,7 +1,7 @@ /* BAREOS® - Backup Archiving REcovery Open Sourced - Copyright (C) 2019-2019 Bareos GmbH & Co. KG + Copyright (C) 2019-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 @@ -57,15 +57,15 @@ void BnetDump::SetDestinationQualifiedName( bool BnetDump::EvaluateCommandLineArgs(const char* cmdline_optarg) { - if (strlen(optarg) == 1) { - if (*optarg == 'p') { BnetDumpPrivate::plantuml_mode_ = true; } - } else if (std::isdigit(optarg[0]) || optarg[0] == '-') { + if (strlen(cmdline_optarg) == 1) { + if (*cmdline_optarg == 'p') { BnetDumpPrivate::plantuml_mode_ = true; } + } else if (std::isdigit(cmdline_optarg[0]) || cmdline_optarg[0] == '-') { try { - BnetDumpPrivate::stack_level_amount_ = std::stoi(optarg); + BnetDumpPrivate::stack_level_amount_ = std::stoi(cmdline_optarg); } catch (const std::exception& e) { return false; } - } else if (!BnetDumpPrivate::SetFilename(optarg)) { + } else if (!BnetDumpPrivate::SetFilename(cmdline_optarg)) { return false; } return true; diff --git a/docs/manuals/CMakeLists.txt b/docs/manuals/CMakeLists.txt index 65997628503..8b5e98bd37f 100644 --- a/docs/manuals/CMakeLists.txt +++ b/docs/manuals/CMakeLists.txt @@ -1,6 +1,6 @@ # BAREOS® - Backup Archiving REcovery Open Sourced # -# Copyright (C) 2019-2021 Bareos GmbH & Co. KG +# Copyright (C) 2019-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 @@ -27,9 +27,9 @@ set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM 1) add_custom_command( OUTPUT ${PROJECT_SOURCE_DIR}/source/include/autogenerated/bareos-dir-config-schema.json - COMMAND bareos-dir -xs >/dev/null + COMMAND bareos-dir --xs >/dev/null COMMAND - bareos-dir -xs + bareos-dir --xs >${PROJECT_SOURCE_DIR}/source/include/autogenerated/bareos-dir-config-schema.json COMMAND sed --in-place --expression="/\\\"version\\\":/d" diff --git a/docs/manuals/source/Appendix/BareosPrograms.rst b/docs/manuals/source/Appendix/BareosPrograms.rst index 132096d7f28..9c7a19b59db 100644 --- a/docs/manuals/source/Appendix/BareosPrograms.rst +++ b/docs/manuals/source/Appendix/BareosPrograms.rst @@ -16,37 +16,40 @@ Daemon Command Line Options Each of the three daemons (Director, File, Storage) accepts a small set of options on the command line. In general, each of the daemons as well as the Console program accepts the following options: --c +-c,\--config Define the file or directory to use for the configuration. See :ref:`section-ConfigurationPathLayout`. --d nnn +-d,\--debug-level nnn Set the debug level to nnn. Generally anything between 50 and 200 is reasonable. The higher the number, the more output is produced. The output is written to standard output. The debug level can also be set during runtime, see section :ref:`bconsole: setdebug `. --f +\--dt,\--debug-timestamps + Print timestamp in debug output. + +-f,\--foreground Run the daemon in the foreground. This option is needed to run the daemon under the debugger. --g +-g,\--group Run the daemon under this group. This must be a group name, not a GID. --s +-s,\--no-signals Do not trap signals. This option is needed to run the daemon under the debugger. --t +-t,\--test-config Read the configuration file and print any error messages, then immediately exit. Useful for syntax testing of new configuration files. --u +-u,\--user Run the daemon as this user. This must be a user name, not a UID. --v +-v,\--verbose Be more verbose or more complete in printing error and informational messages. --xc +\--xc,\--export-configuration Print the current configuration and exit. --xs +\--xs,\--export-schema Print configuration schema in JSON format and exit. --? +-h,\--help,-? Print the version and list of options. .. _command-bareos-dir: diff --git a/docs/manuals/source/TasksAndConcepts/CatalogMaintenance.rst b/docs/manuals/source/TasksAndConcepts/CatalogMaintenance.rst index 02c90fb4e80..afcaaef3953 100644 --- a/docs/manuals/source/TasksAndConcepts/CatalogMaintenance.rst +++ b/docs/manuals/source/TasksAndConcepts/CatalogMaintenance.rst @@ -102,7 +102,7 @@ To view and test the currently configured settings, use following commands: .. code-block:: shell-session :caption: Show current database configuration - /usr/sbin/bareos-dir -xcCatalog=MyCatalog + /usr/sbin/bareos-dir --xc Catalog MyCatalog Catalog { Name = "MyCatalog" DbPassword = YourPassword @@ -283,7 +283,7 @@ Set the PostgreSQL server IP as :config:option:`dir/catalog/DbAddress`\ in :ref .. code-block:: shell-session :caption: Show current database configuration - /usr/sbin/bareos-dir -xcCatalog=MyCatalog + /usr/sbin/bareos-dir --xc Catalog MyCatalog Catalog { Name = "MyCatalog" DbAddress = bareos-database.example.com diff --git a/systemtests/tests/config-dump/testrunner b/systemtests/tests/config-dump/testrunner index 28bb55d491e..fd7644789a8 100755 --- a/systemtests/tests/config-dump/testrunner +++ b/systemtests/tests/config-dump/testrunner @@ -68,7 +68,7 @@ dump_config() DESC="dump_config ${configfile} ext=${ext}" print_debug "*** start $DESC" - "${BAREOS_DIRECTOR_BINARY}" -c "${configfile}" -xc > $tmp/bareos-dir-xc-${ext}.conf + "${BAREOS_DIRECTOR_BINARY}" -c "${configfile}" --xc > $tmp/bareos-dir-xc-${ext}.conf start_bareos_dir -c "${configfile}" @@ -129,39 +129,43 @@ compare_export_config() { configfile="$1" comparefile="$2" - directorparameter="$3" + ressource="$3" + ressourcename="${4-}" if ! [ -e "${configfile}" ]; then set_error "Director config file \"${configfile}\" does not exist." exit 1 fi - DESC="compare_export_config ${configfile} compare=${comparefile} parameter=${directorparameter}" + outputfileextension=$(echo "$ressource-$ressourcename") + + DESC="compare_export_config ${configfile} compare=${comparefile} parameter1=${ressource} parameter2=${ressourcename}" print_debug "*** start $DESC" - "${BAREOS_DIRECTOR_BINARY}" -c "${configfile}" -xc"${directorparameter}" > $tmp/bareos-dir-xc-${directorparameter}.conf + "${BAREOS_DIRECTOR_BINARY}" -c "${configfile}" --xc "${ressource}" "${ressourcename}" > $tmp/bareos-dir-xc-${outputfileextension}.conf print_debug "*** end $DESC" - diff_files "${comparefile}" "$tmp/bareos-dir-xc-${directorparameter}.conf" + diff_files "${comparefile}" "$tmp/bareos-dir-xc-${outputfileextension}.conf" } bareos_dir_failing() { configfile="$1" - directorparameter="$2" + ressource="$2" + ressourcename="${3-}" if ! [ -e "${configfile}" ]; then set_error "Director config file \"${configfile}\" does not exist." exit 1 fi - DESC="bareos_dir_failing ${configfile} parameter=${directorparameter}" + DESC="bareos_dir_failing ${configfile} parameter1=${ressource} parameter2=${ressourcename}" print_debug "*** start $DESC" - if OUT=$("${BAREOS_DIRECTOR_BINARY}" -c "${configfile}" -xc"${directorparameter}"); then + if OUT=$("${BAREOS_DIRECTOR_BINARY}" -c "${configfile}" --xc "${ressource}" "${ressourcename}"); then echo "${OUT}" - set_error "Starting Director with -xc"${directorparameter}" should fail." + set_error "Starting Director with --xc "${ressource} ${ressourcename}" should fail." exit 1 fi @@ -185,7 +189,7 @@ JobName=backup-bareos-fd start_test # bareos-dir-19.2.7-xc.conf: -# output of bareos-dir -xc (manually adapted) +# output of bareos-dir --xc (manually adapted) # from a default installation of version 19.2.7 dump_config "${conf}/bareos-dir-19.2.7-xc.conf" "1" @@ -224,9 +228,11 @@ diff_files "${tmp}/bareos-dir-show-verbose-full1.conf" "$tmp/bareos-dir-show-ver # export all resources of a type compare_export_config "${conf}/bareos-dir-19.2.7-xc.conf" "etc/compare/Console.conf" "console" # export single resource -compare_export_config "${conf}/bareos-dir-19.2.7-xc.conf" "etc/compare/Console-admin.conf" "console=admin" +compare_export_config "${conf}/bareos-dir-19.2.7-xc.conf" "etc/compare/Console-admin.conf" "console" "admin" +# resource type with spaces instead of seperate resource name +bareos_dir_failing "${conf}/bareos-dir-19.2.7-xc.conf" "console admin" # try export non-existing resource -bareos_dir_failing "${conf}/bareos-dir-19.2.7-xc.conf" "console=DOESNOTEXIST" +bareos_dir_failing "${conf}/bareos-dir-19.2.7-xc.conf" "console" "DOESNOTEXIST" # try export non-existing resource type bareos_dir_failing "${conf}/bareos-dir-19.2.7-xc.conf" "DOESNOTEXIST" # export unused (empty) resource type