Commit 71d7f795 authored by Daniel Salzman's avatar Daniel Salzman

knotc: parameters processing refactoring

parent 3d2796c5
......@@ -38,167 +38,127 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.INDENT 0.0
.TP
\fB\-c\fP, \fB\-\-config\fP \fIfile\fP
Use a textual configuration file (default is \fB@conf_dir@/knot.conf\fP).
Use a textual configuration file (default is \fB@config_dir@/knot.conf\fP).
.TP
\fB\-C\fP, \fB\-\-confdb\fP \fIdirectory\fP
Use a binary configuration database.
Use a binary configuration database directory (default is \fB@storage_dir@/confdb\fP).
The default configuration database, if exists, has a preference to the default
configuration file.
.TP
\fB\-s\fP, \fB\-\-server\fP \fIserver\fP
Remote UNIX socket/IP address (default is \fB@run_dir@/knot.sock\fP).
.TP
\fB\-p\fP, \fB\-\-port\fP \fIport\fP
Remote server port (only for IP).
.TP
\fB\-y\fP, \fB\-\-key\fP [\fIalg\fP:]\fIname\fP:\fIkey\fP
Use the TSIG key specified on the command line (default algorithm is hmac\-md5).
.TP
\fB\-k\fP, \fB\-\-keyfile\fP \fIfile\fP
Use the TSIG key stored in a file \fIfile\fP to authenticate the request. The
file must contain the key in the same format, which is accepted by the
\fB\-y\fP option.
\fB\-s\fP, \fB\-\-socket\fP \fIpath\fP
Use a remote control UNIX socket path (default is \fB@run_dir@/knot.sock\fP).
.TP
\fB\-f\fP, \fB\-\-force\fP
Force operation. Overrides some checks.
Forced operation. Overrides some checks.
.TP
\fB\-v\fP, \fB\-\-verbose\fP
Verbose mode. Print additional runtime information.
Enable debug output.
.TP
\fB\-h\fP, \fB\-\-help\fP
Print the program help.
.TP
\fB\-V\fP, \fB\-\-version\fP
Print the program version.
.TP
\fB\-h\fP, \fB\-\-help\fP
Print help and usage.
.UNINDENT
.SS Actions
.sp
If the optional \fIzone\fP argument is not specified, the command is applied to all
zones.
Configuration \fIitem\fP is in the \fIsection\fP[\fB[\fP\fIid\fP\fB]\fP][\fB\&.\fP\fIitem\fP]
format.
.INDENT 0.0
.TP
\fBstatus\fP
Check if the server is running.
.TP
\fBstop\fP
Stop server (no\-op if not running).
Stop the server if running.
.TP
\fBreload\fP [\fIzone\fP\&...]
Reload particular zones or reload the whole configuration and changed zones.
\fBreload\fP
Reload the server configuration.
.TP
\fBflush\fP [\fIzone\fP\&...]
Flush journal and update zone files.
\fBzone\-check\fP [\fIzone\fP\&...]
Check the zone. (*)
.TP
\fBstatus\fP
Check if server is running.
\fBzone\-memstats\fP [\fIzone\fP\&...]
Estimate memory use for the zone. (*)
.TP
\fBzone\-status\fP [\fIzone\fP\&...]
Show the status of the zone. (*)
.TP
\fBzonestatus\fP [\fIzone\fP\&...]
Show the status of listed zones.
\fBzone\-reload\fP [\fIzone\fP\&...]
Trigger a zone reload.
.TP
\fBrefresh\fP [\fIzone\fP\&...]
Refresh slave zones. The \fB\-f\fP flag forces re\-transfer (zones must be specified).
\fBzone\-refresh\fP [\fIzone\fP\&...]
Trigger a zone refresh (if slave).
.TP
\fBcheckconf\fP
Check the current configuration.
\fBzone\-retransfer\fP [\fIzone\fP\&...]
Trigger a zone retransfer (if slave).
.TP
\fBcheckzone\fP [\fIzone\fP\&...]
Check zones.
\fBzone\-flush\fP [\fIzone\fP\&...]
Trigger a zone journal flush into the zone file.
.TP
\fBmemstats\fP [\fIzone\fP\&...]
Estimate memory consumption for zones.
\fBzone\-sing\fP [\fIzone\fP\&...]
Trigger a zone resign (if enabled).
.TP
\fBsignzone\fP \fIzone\fP\&...
Re\-sign the zone (drop all existing signatures and create new ones).
\fBconf\-check\fP
Check the server configuration. (*)
.TP
\fBconf\-import\fP \fIfilename\fP
Offline import of the configuration DB from a file. This is a
potentially dangerous operation so the \fB\-f\fP flag is required. Also the
destination configuration DB must be specified via \fB\-C\fP\&. Ensure the server
is not running!
Import a config file into the confdb. Ensure the server is not accessing
the confdb! (*)
.TP
\fBconf\-export\fP \fIfilename\fP
Export the configuration DB to a file. If no source configuration DB is
specified, the temporary DB, corresponding to textual configuration file, is
used.
Export the confdb into a config file. (*)
.TP
\fBconf\-desc\fP [\fIsection\fP]
Get the configuration section items list. If no section is specified,
the list of sections is returned.
\fBconf\-list\fP [\fIitem\fP]
List the confdb sections or section items.
.TP
\fBconf\-read\fP [\fIitem\fP]
Read from the current configuration DB.
Read the item from the active confdb.
.TP
\fBconf\-begin\fP
Begin a writing configuration DB transaction. Only one transaction can be
opened at a time.
Begin a writing confdb transaction. Only one transaction can be opened at a time.
.TP
\fBconf\-commit\fP
Commit the current writing configuration DB transaction.
Commit the confdb transaction.
.TP
\fBconf\-abort\fP
Abort the current writing configuration DB transaction.
Rollback the confdb transaction.
.TP
\fBconf\-diff\fP [\fIitem\fP]
Get the difference between the active writing transaction and the current
configuration DB. Requires active writing configuration DB transaction.
Get the item difference in the transaction.
.TP
\fBconf\-get\fP [\fIitem\fP]
Read from the active writing configuration DB transaction.
Requires active writing configuration DB transaction.
Get the item data from the transaction.
.TP
\fBconf\-set\fP \fIitem\fP [\fIdata\fP\&...]
Write to the active writing configuration DB transaction.
Requires active writing configuration DB transaction.
Set the item data in the transaction.
.TP
\fBconf\-unset\fP [\fIitem\fP] [\fIdata\fP\&...]
Delete from the active writing configuration DB transaction.
Requires active writing configuration DB transaction.
.UNINDENT
.SH EXAMPLES
.SS Setup a key file for remote control
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
$ keymgr tsig generate knotc\-key > knotc\-key.conf
.ft P
.fi
.UNINDENT
Unset the item data in the transaction.
.UNINDENT
.SH NOTE
.sp
The generated key file contains a key in the server configuration format and
thus can be directly included into the server configuration file.
.sp
Knot DNS utilities accept one\-line format which is included in the generated
key file on the first line as a comment. It can be extracted easily:
.INDENT 0.0
.INDENT 3.5
Empty \fIzone\fP parameter means all zones.
.sp
.nf
.ft C
$ head \-1 knotc\-key.conf | sed \(aqs/^#\es*//\(aq > knotc.key
.ft P
.fi
.UNINDENT
.UNINDENT
Type \fIitem\fP parameter in the form of \fIsection\fP[\fB[\fP\fIid\fP\fB]\fP][\fB\&.\fP\fIname\fP].
.sp
Make sure the key file can be read only by the owner for security reasons.
.SS Reload server remotely
(*) indicates a local operation requiring a configuration specified.
.SH EXAMPLES
.SS Reload the whole server configuration
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
$ knotc \-s 127.0.0.1 \-k knotc.key reload
$ knotc reload
.ft P
.fi
.UNINDENT
.UNINDENT
.SS Flush all zones locally
.SS Flush the example.com and example.eu zones
.INDENT 0.0
.INDENT 3.5
.sp
.nf
.ft C
$ knotc \-c knot.conf flush
$ knotc zone\-flush example.com example.eu
.ft P
.fi
.UNINDENT
......
......@@ -41,7 +41,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
Use a textual configuration file (default is \fB@config_dir@/knot.conf\fP).
.TP
\fB\-C\fP, \fB\-\-confdb\fP \fIdirectory\fP
Use a binary configuration database directory.
Use a binary configuration database directory (default is \fB@storage_dir@/confdb\fP).
The default configuration database, if exists, has a preference to the default
configuration file.
.TP
\fB\-d\fP, \fB\-\-daemonize\fP [\fIdirectory\fP]
Run the server as a daemon. New root directory may be specified
......
......@@ -15,152 +15,131 @@ Parameters
..........
**-c**, **--config** *file*
Use a textual configuration file (default is :file:`@conf_dir@/knot.conf`).
Use a textual configuration file (default is :file:`@config_dir@/knot.conf`).
**-C**, **--confdb** *directory*
Use a binary configuration database.
Use a binary configuration database directory (default is :file:`@storage_dir@/confdb`).
The default configuration database, if exists, has a preference to the default
configuration file.
**-s**, **--server** *server*
Remote UNIX socket/IP address (default is :file:`@run_dir@/knot.sock`).
**-p**, **--port** *port*
Remote server port (only for IP).
**-y**, **--key** [*alg*:]\ *name*:*key*
Use the TSIG key specified on the command line (default algorithm is hmac-md5).
**-k**, **--keyfile** *file*
Use the TSIG key stored in a file *file* to authenticate the request. The
file must contain the key in the same format, which is accepted by the
**-y** option.
**-s**, **--socket** *path*
Use a remote control UNIX socket path (default is :file:`@run_dir@/knot.sock`).
**-f**, **--force**
Force operation. Overrides some checks.
Forced operation. Overrides some checks.
**-v**, **--verbose**
Verbose mode. Print additional runtime information.
Enable debug output.
**-h**, **--help**
Print the program help.
**-V**, **--version**
Print the program version.
**-h**, **--help**
Print help and usage.
Actions
.......
If the optional *zone* argument is not specified, the command is applied to all
zones.
Configuration *item* is in the *section*\ [**[**\ *id*\ **]**\ ][**.**\ *item*]
format.
**status**
Check if the server is running.
**stop**
Stop server (no-op if not running).
Stop the server if running.
**reload** [*zone*...]
Reload particular zones or reload the whole configuration and changed zones.
**reload**
Reload the server configuration.
**flush** [*zone*...]
Flush journal and update zone files.
**status**
Check if server is running.
**zone-check** [*zone*...]
Check the zone. (*)
**zone-memstats** [*zone*...]
Estimate memory use for the zone. (*)
**zone-status** [*zone*...]
Show the status of the zone. (*)
**zonestatus** [*zone*...]
Show the status of listed zones.
**zone-reload** [*zone*...]
Trigger a zone reload.
**refresh** [*zone*...]
Refresh slave zones. The **-f** flag forces re-transfer (zones must be specified).
**zone-refresh** [*zone*...]
Trigger a zone refresh (if slave).
**checkconf**
Check the current configuration.
**zone-retransfer** [*zone*...]
Trigger a zone retransfer (if slave).
**checkzone** [*zone*...]
Check zones.
**zone-flush** [*zone*...]
Trigger a zone journal flush into the zone file.
**memstats** [*zone*...]
Estimate memory consumption for zones.
**zone-sing** [*zone*...]
Trigger a zone resign (if enabled).
**signzone** *zone*...
Re-sign the zone (drop all existing signatures and create new ones).
**conf-init**
Initialize the confdb. (*)
**conf-check**
Check the server configuration. (*)
**conf-import** *filename*
Offline import of the configuration DB from a file. This is a
potentially dangerous operation so the **-f** flag is required. Also the
destination configuration DB must be specified via **-C**. Ensure the server
is not running!
Import a config file into the confdb. Ensure the server is not accessing
the confdb! (*)
**conf-export** *filename*
Export the configuration DB to a file. If no source configuration DB is
specified, the temporary DB, corresponding to textual configuration file, is
used.
Export the confdb into a config file. (*)
**conf-desc** [*section*]
Get the configuration section items list. If no section is specified,
the list of sections is returned.
**conf-list** [*item*]
List the confdb sections or section items.
**conf-read** [*item*]
Read from the current configuration DB.
Read the item from the active confdb.
**conf-begin**
Begin a writing configuration DB transaction. Only one transaction can be
opened at a time.
Begin a writing confdb transaction. Only one transaction can be opened at a time.
**conf-commit**
Commit the current writing configuration DB transaction.
Commit the confdb transaction.
**conf-abort**
Abort the current writing configuration DB transaction.
Rollback the confdb transaction.
**conf-diff** [*item*]
Get the difference between the active writing transaction and the current
configuration DB. Requires active writing configuration DB transaction.
Get the item difference in the transaction.
**conf-get** [*item*]
Read from the active writing configuration DB transaction.
Requires active writing configuration DB transaction.
Get the item data from the transaction.
**conf-set** *item* [*data*...]
Write to the active writing configuration DB transaction.
Requires active writing configuration DB transaction.
Set the item data in the transaction.
**conf-unset** [*item*] [*data*...]
Delete from the active writing configuration DB transaction.
Requires active writing configuration DB transaction.
Examples
--------
Unset the item data in the transaction.
Setup a key file for remote control
...................................
Note
----
::
$ keymgr tsig generate knotc-key > knotc-key.conf
The generated key file contains a key in the server configuration format and
thus can be directly included into the server configuration file.
Empty *zone* parameter means all zones.
Knot DNS utilities accept one-line format which is included in the generated
key file on the first line as a comment. It can be extracted easily::
Type *item* parameter in the form of *section*\ [**[**\ *id*\ **]**\ ][**.**\ *name*].
$ head -1 knotc-key.conf | sed 's/^#\s*//' > knotc.key
(*) indicates a local operation requiring a configuration specified.
Make sure the key file can be read only by the owner for security reasons.
Examples
--------
Reload server remotely
......................
Reload the whole server configuration
.....................................
::
$ knotc -s 127.0.0.1 -k knotc.key reload
$ knotc reload
Flush all zones locally
.......................
Flush the example.com and example.eu zones
..........................................
::
$ knotc -c knot.conf flush
$ knotc zone-flush example.com example.eu
Get the current server configuration
....................................
......
......@@ -18,7 +18,9 @@ Parameters
Use a textual configuration file (default is :file:`@config_dir@/knot.conf`).
**-C**, **--confdb** *directory*
Use a binary configuration database directory.
Use a binary configuration database directory (default is :file:`@storage_dir@/confdb`).
The default configuration database, if exists, has a preference to the default
configuration file.
**-d**, **--daemonize** [*directory*]
Run the server as a daemon. New root directory may be specified
......
......@@ -18,114 +18,191 @@
#include <stdio.h>
#include <sys/stat.h>
#include "contrib/sockaddr.h"
#include "dnssec/crypto.h"
#include "knot/common/log.h"
#include "knot/conf/conf.h"
#include "libknot/libknot.h"
#include "utils/knotc/commands.h"
#include "utils/common/params.h"
/*! \brief Print help. */
static void help(void)
#define PROGRAM_NAME "knotc"
static void print_help(void)
{
printf("Usage: knotc [parameters] <action> [action_args]\n"
printf("Usage: %s [parameters] <action> [action_args]\n"
"\n"
"Parameters:\n"
" -c, --config <file> Select configuration file.\n"
" (default %s)\n"
" -C, --confdb <dir> Select configuration database directory.\n"
" -s, --socket <path> Remote control UNIX socket.\n"
" (default %s)\n"
" -f, --force Force operation - override some checks.\n"
" -v, --verbose Verbose mode - additional runtime information.\n"
" -V, --version Print %s server version.\n"
" -h, --help Print help and usage.\n"
" -c, --config <file> Use a textual configuration file.\n"
" (default %s)\n"
" -C, --confdb <dir> Use a binary configuration database directory.\n"
" (default %s)\n"
" -s, --socket <path> Use a remote control UNIX socket path.\n"
" (default %s)\n"
" -f, --force Forced operation. Overrides some checks.\n"
" -v, --verbose Enable debug output.\n"
" -h, --help Print the program help.\n"
" -V, --version Print the program version.\n"
"\n"
"Actions:\n",
CONF_DEFAULT_FILE, RUN_DIR "/knot.sock", PACKAGE_NAME);
cmd_help_t *c = cmd_help_table;
while (c->name != NULL) {
printf(" %-13s %-20s %s\n", c->name, c->params, c->desc);
++c;
}
printf("\nThe item argument must be in the section[identifier].item format.\n");
printf("\nIf optional <zone> parameter is not specified, command is applied to all zones.\n\n");
PROGRAM_NAME, CONF_DEFAULT_FILE, CONF_DEFAULT_DBDIR, RUN_DIR "/knot.sock");
for (const cmd_help_t *cmd = cmd_help_table; cmd->name != NULL; cmd++) {
printf(" %-15s %-20s %s\n", cmd->name, cmd->params, cmd->desc);
}
printf("\n"
"Note:\n"
" Empty <zone> parameter means all zones.\n"
" Type <item> parameter in the form of <section>[<identifier>].<name>.\n"
" (*) indicates a local operation requiring a configuration specified.\n");
}
static int set_config(const cmd_desc_t *desc, const char *confdb,
const char *config, char *socket)
{
if (config != NULL && confdb != NULL) {
log_error("ambiguous configuration source");
return KNOT_EINVAL;
}
/* Choose the optimal config source. */
struct stat st;
bool import = false;
if (desc->flags == CMD_CONF_FNONE && socket != NULL) {
import = false;
confdb = NULL;
} else if (confdb != NULL) {
import = false;
} else if (desc->flags == CMD_CONF_FWRITE) {
import = false;
confdb = CONF_DEFAULT_DBDIR;
} else if (config != NULL){
import = true;
} else if (stat(CONF_DEFAULT_DBDIR, &st) == 0) {
import = false;
confdb = CONF_DEFAULT_DBDIR;
} else if (stat(CONF_DEFAULT_FILE, &st) == 0) {
import = true;
config = CONF_DEFAULT_FILE;
} else if (desc->flags != CMD_CONF_FNONE) {
log_error("no configuration source available");
return KNOT_EINVAL;
}
const char *src = import ? config : confdb;
log_debug("%s '%s'", import ? "config" : "confdb",
(src != NULL) ? src : "empty");
/* Prepare config flags. */
conf_flag_t conf_flags = CONF_FNONE;
if (confdb != NULL && !(desc->flags & CMD_CONF_FWRITE)) {
conf_flags |= CONF_FREADONLY;
}
/* Open confdb. */
conf_t *new_conf = NULL;
int ret = conf_new(&new_conf, conf_scheme, confdb, conf_flags);
if (ret != KNOT_EOK) {
log_error("failed to open configuration database '%s' (%s)",
(confdb != NULL) ? confdb : "", knot_strerror(ret));
return ret;
}
/* Import the config file. */
if (import) {
ret = conf_import(new_conf, config, true);
if (ret != KNOT_EOK) {
log_error("failed to load configuration file '%s' (%s)",
config, knot_strerror(ret));
conf_free(new_conf);
return ret;
}
}
/* Finalize the config (needed for conf check and cached items). */
ret = conf_post_open(new_conf);
if (ret != KNOT_EOK) {
log_error("failed to use configuration (%s)", knot_strerror(ret));
conf_free(new_conf);
return ret;
}
/* Update to the new config. */
conf_update(new_conf);
return KNOT_EOK;
}
int main(int argc, char **argv)
{
/* Parse command line arguments */
int c = 0, li = 0, rc = 0;
unsigned flags = CMD_NONE;
const char *config_fn = CONF_DEFAULT_FILE;
const char *config_db = NULL;
cmd_flag_t flags = CMD_FNONE;
const char *config = NULL;
const char *confdb = NULL;
char *socket = NULL;
/* Initialize. */
log_init();
log_levels_set(LOG_SYSLOG, LOG_ANY, 0);
bool verbose = false;
/* Long options. */
struct option opts[] = {
{ "config", required_argument, 0, 'c' },
{ "confdb", required_argument, 0, 'C' },
{ "socket", required_argument, 0, 's' },
{ "force", no_argument, 0, 'f' },
{ "verbose", no_argument, 0, 'v' },
{ "help", no_argument, 0, 'h' },
{ "version", no_argument, 0, 'V' },
{ "config", required_argument, NULL, 'c' },
{ "confdb", required_argument, NULL, 'C' },
{ "socket", required_argument, NULL, 's' },
{ "force", no_argument, NULL, 'f' },
{ "verbose", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{ NULL }
};
while ((c = getopt_long(argc, argv, "s:fc:C:vVh", opts, &li)) != -1) {
switch (c) {
/* Parse command line arguments */
int opt = 0, li = 0;
while ((opt = getopt_long(argc, argv, "c:C:s:fvhV", opts, &li)) != -1) {
switch (opt) {
case 'c':
config_fn = optarg;
config = optarg;
break;
case 'C':
config_db = optarg;
confdb = optarg;
break;
case 's':
socket = strdup(optarg);
socket = optarg;
break;
case 'f':
flags |= CMD_FORCE;
flags |= CMD_FFORCE;
break;
case 'v':
log_levels_add(LOGT_STDOUT, LOG_ANY,
LOG_MASK(LOG_INFO) | LOG_MASK(LOG_DEBUG));
verbose = true;
break;
case 'V':
rc = 0;
printf("%s, version %s\n", "Knot DNS", PACKAGE_VERSION);
goto exit;
case 'h':
case '?':
rc = 0;
help();
goto exit;
print_help();
return EXIT_SUCCESS;
case 'V':
print_version(PROGRAM_NAME);
return EXIT_SUCCESS;
default:
rc = 1;
help();
goto exit;
print_help();
return EXIT_FAILURE;
}
}
/* Check if there's at least one remaining non-option. */
if (argc - optind < 1) {
rc = 1;
help();
goto exit;
print_help();
return EXIT_FAILURE;
}
/* Check for existing config DB destination. */
struct stat st;
if (config_db != NULL && stat(config_db, &st) != 0) {
flags |= CMD_NOCONFDB;
/* Set up simplified logging just to stdout/stderr. */
log_init();
log_levels_set(LOGT_STDOUT, LOG_ANY, LOG_MASK(LOG_INFO) | LOG_MASK(LOG_NOTICE));
log_levels_set(LOGT_STDERR, LOG_ANY, LOG_UPTO(LOG_WARNING));
log_levels_set(LOGT_SYSLOG, LOG_ANY, 0);
log_flag_set(LOG_FNO_TIMESTAMP | LOG_FNO_INFO);
if (verbose) {
log_levels_add(LOGT_STDOUT, LOG_ANY, LOG_MASK(LOG_DEBUG));
}
/* Translate old command name. */
const char *command = argv[optind];
for (cmd_desc_old_t *desc = cmd_table_old; desc->old_name != NULL; desc++) {
for (const cmd_desc_old_t *desc = cmd_table_old; desc->old_name != NULL; desc++) {
if (strcmp(desc->old_name, command) == 0) {
log_notice("obsolete command '%s', using '%s' instead",
desc->old_name, desc->new_name);
......@@ -135,94 +212,56 @@ int main(int argc, char **argv)
}
/* Find requested command. */
cmd_desc_t *desc = cmd_table;
const cmd_desc_t *desc = cmd_table;
while (desc->name != NULL) {
if (strcmp(desc->name, command) == 0) {
break;
}
++desc;
desc++;
}
/* Command not found. */
if (desc->name == NULL) {
log_fatal("invalid command: '%s'", argv[optind]);
rc = 1;
goto exit;
log_error("invalid command '%s'", command);
log_close();
return EXIT_FAILURE;
}
/* Open configuration. */
conf_t *new_conf = NULL;
if (config_db == NULL) {
int ret = conf_new(&new_conf, conf_scheme, NULL, false);
if (ret != KNOT_EOK) {
log_fatal("failed to initialize configuration database "
"(%s)", knot_strerror(ret));
rc = 1;
goto exit;
}
/* Import the configuration file. */
ret = conf_import(new_conf, config_fn, true);
if (ret != KNOT_EOK) {
log_fatal("failed to load configuration file (%s)",
knot_strerror(ret));
conf_free(new_conf, false);
rc = 1;
goto exit;
}