Commit b909a109 authored by Daniel Salzman's avatar Daniel Salzman

knotc: add history and completion support based on libedit

parent 1cca7f9e
......@@ -429,6 +429,8 @@ src/utils/common/exec.c
src/utils/common/exec.h
src/utils/common/hex.c
src/utils/common/hex.h
src/utils/common/lookup.c
src/utils/common/lookup.h
src/utils/common/msg.c
src/utils/common/msg.h
src/utils/common/netio.c
......@@ -465,7 +467,11 @@ src/utils/knotc/commands.c
src/utils/knotc/commands.h
src/utils/knotc/estimator.c
src/utils/knotc/estimator.h
src/utils/knotc/interactive.c
src/utils/knotc/interactive.h
src/utils/knotc/main.c
src/utils/knotc/process.c
src/utils/knotc/process.h
src/utils/knotd/main.c
src/utils/knsupdate/knsupdate_exec.c
src/utils/knsupdate/knsupdate_exec.h
......@@ -530,6 +536,7 @@ tests/server.c
tests/sockaddr.c
tests/test_conf.h
tests/tsig_key.c
tests/utils/test_lookup.c
tests/wire.c
tests/wire_ctx.c
tests/worker_pool.c
......
......@@ -7,6 +7,7 @@ Knot DNS has several dependencies:
* liburcu >= 0.5.4
* gnutls >= 3.0
* jansson >= 2.3
* libedit
Embedded libraries:
* lmdb (system library is preferred)
......
......@@ -447,6 +447,38 @@ AS_IF([test "$with_libidn" != "no"],[
]) # Knot DNS utilities dependencies
PKG_CHECK_MODULES([libedit], [libedit], [], [
save_CFLAGS="$CFLAGS"
save_LIBS="$LIBS"
with_libedit=no
for try_path in "" "/usr" "/usr/local"; do
AS_IF([test -d "$try_path"], [
libedit_CFLAGS="-I$try_path/include"
libedit_LIBS="-L$try_path/lib"
],[
continue
])
CFLAGS="$CFLAGS $libedit_CFLAGS"
LIBS="$LIBS $libedit_LIBS"
AC_CHECK_HEADERS([histedit.h], [], [continue])
AC_SEARCH_LIBS([el_init], [edit], [], [continue])
with_libedit=yes
libedit_LIBS="$libedit_LIBS -ledit"
break
done
CFLAGS="$save_CFLAGS"
LIBS="$save_LIBS"
AS_IF([test "$with_libedit" = "no"], [
AC_MSG_ERROR([libedit library not found])
])
])
# Bash completions
AC_ARG_WITH([bash-completions],
AC_HELP_STRING([--with-bash-completions=[DIR]], [Bash completions directory [default=no]]),
......
......@@ -34,6 +34,7 @@ Knot DNS requires few libraries to be compiled:
* GnuTLS, at least 3.0
* Jansson, at least 2.3
* Userspace RCU, at least 0.5.4
* libedit
* lmdb (included)
* libcap-ng, at least 0.6.4 (optional)
* libidn (optional)
......
......@@ -34,6 +34,11 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.sp
\fBknotc\fP [\fIparameters\fP] \fIaction\fP [\fIaction_args\fP]
.SH DESCRIPTION
.sp
If no \fIaction\fP is specified, the program is executed in interactive mode. Then
various command or parameters completion is available via the TAB key. And
command history is enabled (see \fIeditrc(5)\fP for additional
customization).
.SS Parameters
.INDENT 0.0
.TP
......@@ -225,7 +230,7 @@ $ knotc conf\-commit
.UNINDENT
.SH SEE ALSO
.sp
\fIknotd(8)\fP, \fIknot.conf(5)\fP\&.
\fIknotd(8)\fP, \fIknot.conf(5)\fP, \fIeditrc(5)\fP\&.
.SH AUTHOR
CZ.NIC Labs <http://www.knot-dns.cz>
.SH COPYRIGHT
......
......@@ -11,6 +11,11 @@ Synopsis
Description
-----------
If no *action* is specified, the program is executed in interactive mode. Then
various command or parameters completion is available via the TAB key. And
command history is enabled (see :manpage:`editrc(5)` for additional
customization).
Parameters
..........
......@@ -185,4 +190,4 @@ Add example.org zone with a zonefile location
See Also
--------
:manpage:`knotd(8)`, :manpage:`knot.conf(5)`.
:manpage:`knotd(8)`, :manpage:`knot.conf(5)`, :manpage:`editrc(5)`.
......@@ -211,6 +211,10 @@ knotc_SOURCES = \
utils/knotc/commands.h \
utils/knotc/estimator.c \
utils/knotc/estimator.h \
utils/knotc/interactive.c \
utils/knotc/interactive.h \
utils/knotc/process.c \
utils/knotc/process.h \
utils/knotc/main.c
knotd_SOURCES = \
......@@ -370,7 +374,7 @@ libknotd_la_LIBADD = libknot.la libknot-yparser.la zscanner/libzscanner.la $(lib
knotd_CPPFLAGS = $(AM_CPPFLAGS) $(liburcu_CFLAGS)
knotd_LDADD = libknotd.la $(liburcu_LIBS)
knotc_LDADD = libknotd.la
knotc_LDADD = libknotd.la libknotus.la $(libedit_LIBS)
knot1to2_LDADD = libcontrib.la
####################################
......@@ -437,6 +441,8 @@ libknotus_la_SOURCES = \
utils/common/exec.h \
utils/common/hex.c \
utils/common/hex.h \
utils/common/lookup.c \
utils/common/lookup.h \
utils/common/msg.c \
utils/common/msg.h \
utils/common/netio.c \
......
......@@ -30,6 +30,8 @@
#include "utils/knotc/commands.h"
#include "utils/knotc/estimator.h"
#define CMD_EXIT "exit"
#define CMD_STATUS "status"
#define CMD_STOP "stop"
#define CMD_RELOAD "reload"
......@@ -97,10 +99,10 @@ static int check_conf_args(cmd_args_t *args)
return KNOT_EINVAL;
}
static int get_conf_key(char *key, knot_ctl_data_t *data)
static int get_conf_key(const char *key, knot_ctl_data_t *data)
{
// Get key0.
char *key0 = key;
const char *key0 = key;
// Check for id.
char *id = strchr(key, '[');
......@@ -410,7 +412,8 @@ static int zone_memstats(const knot_dname_t *dname, void *data)
.node_table = hattrie_create_n(TRIE_BUCKET_SIZE, &mem_ctx),
};
char *zone_name = knot_dname_to_str_alloc(dname);
char buff[KNOT_DNAME_TXT_MAXLEN + 1];
char *zone_name = knot_dname_to_str(buff, dname, sizeof(buff));
char *zone_file = conf_zonefile(conf(), dname);
zs_scanner_t *zs = malloc(sizeof(zs_scanner_t));
......@@ -419,7 +422,6 @@ static int zone_memstats(const knot_dname_t *dname, void *data)
log_zone_error(dname, "%s", knot_strerror(KNOT_ENOMEM));
hattrie_free(est.node_table);
free(zone_file);
free(zone_name);
free(zs);
return KNOT_ENOMEM;
}
......@@ -434,13 +436,11 @@ static int zone_memstats(const knot_dname_t *dname, void *data)
hattrie_apply_rev(est.node_table, estimator_free_trie_node, NULL);
hattrie_free(est.node_table);
free(zone_file);
free(zone_name);
zs_deinit(zs);
free(zs);
return KNOT_EPARSEFAIL;
}
free(zone_file);
free(zone_name);
zs_deinit(zs);
free(zs);
......@@ -663,48 +663,40 @@ static int cmd_conf_ctl(cmd_args_t *args)
}
const cmd_desc_t cmd_table[] = {
{ CMD_EXIT, NULL, CTL_NONE },
{ CMD_STATUS, cmd_ctl, CTL_STATUS },
{ CMD_STOP, cmd_ctl, CTL_STOP },
{ CMD_RELOAD, cmd_ctl, CTL_RELOAD },
{ CMD_ZONE_CHECK, cmd_zone_check, CTL_NONE, CMD_CONF_FREAD },
{ CMD_ZONE_MEMSTATS, cmd_zone_memstats, CTL_NONE, CMD_CONF_FREAD },
{ CMD_ZONE_STATUS, cmd_zone_ctl, CTL_ZONE_STATUS },
{ CMD_ZONE_RELOAD, cmd_zone_ctl, CTL_ZONE_RELOAD },
{ CMD_ZONE_REFRESH, cmd_zone_ctl, CTL_ZONE_REFRESH },
{ CMD_ZONE_RETRANSFER, cmd_zone_ctl, CTL_ZONE_RETRANSFER },
{ CMD_ZONE_FLUSH, cmd_zone_ctl, CTL_ZONE_FLUSH },
{ CMD_ZONE_SIGN, cmd_zone_ctl, CTL_ZONE_SIGN },
{ CMD_CONF_INIT, cmd_conf_init, CTL_NONE, CMD_CONF_FWRITE },
{ CMD_CONF_CHECK, cmd_conf_check, CTL_NONE, CMD_CONF_FREAD },
{ CMD_CONF_IMPORT, cmd_conf_import, CTL_NONE, CMD_CONF_FWRITE },
{ CMD_CONF_EXPORT, cmd_conf_export, CTL_NONE, CMD_CONF_FREAD },
{ CMD_CONF_LIST, cmd_conf_ctl, CTL_CONF_LIST, CMD_CONF_FOPT_ITEM },
{ CMD_CONF_READ, cmd_conf_ctl, CTL_CONF_READ, CMD_CONF_FOPT_ITEM },
{ CMD_ZONE_CHECK, cmd_zone_check, CTL_NONE, CMD_CONF_FOPT_ZONE | CMD_CONF_FREAD },
{ CMD_ZONE_MEMSTATS, cmd_zone_memstats, CTL_NONE, CMD_CONF_FOPT_ZONE | CMD_CONF_FREAD },
{ CMD_ZONE_STATUS, cmd_zone_ctl, CTL_ZONE_STATUS, CMD_CONF_FOPT_ZONE },
{ CMD_ZONE_RELOAD, cmd_zone_ctl, CTL_ZONE_RELOAD, CMD_CONF_FOPT_ZONE },
{ CMD_ZONE_REFRESH, cmd_zone_ctl, CTL_ZONE_REFRESH, CMD_CONF_FOPT_ZONE },
{ CMD_ZONE_RETRANSFER, cmd_zone_ctl, CTL_ZONE_RETRANSFER, CMD_CONF_FOPT_ZONE },
{ CMD_ZONE_FLUSH, cmd_zone_ctl, CTL_ZONE_FLUSH, CMD_CONF_FOPT_ZONE },
{ CMD_ZONE_SIGN, cmd_zone_ctl, CTL_ZONE_SIGN, CMD_CONF_FOPT_ZONE },
{ CMD_CONF_INIT, cmd_conf_init, CTL_NONE, CMD_CONF_FWRITE },
{ CMD_CONF_CHECK, cmd_conf_check, CTL_NONE, CMD_CONF_FREAD },
{ CMD_CONF_IMPORT, cmd_conf_import, CTL_NONE, CMD_CONF_FWRITE },
{ CMD_CONF_EXPORT, cmd_conf_export, CTL_NONE, CMD_CONF_FREAD },
{ CMD_CONF_LIST, cmd_conf_ctl, CTL_CONF_LIST, CMD_CONF_FOPT_ITEM },
{ CMD_CONF_READ, cmd_conf_ctl, CTL_CONF_READ, CMD_CONF_FOPT_ITEM },
{ CMD_CONF_BEGIN, cmd_conf_ctl, CTL_CONF_BEGIN },
{ CMD_CONF_COMMIT, cmd_conf_ctl, CTL_CONF_COMMIT },
{ CMD_CONF_ABORT, cmd_conf_ctl, CTL_CONF_ABORT },
{ CMD_CONF_DIFF, cmd_conf_ctl, CTL_CONF_DIFF, CMD_CONF_FOPT_ITEM },
{ CMD_CONF_GET, cmd_conf_ctl, CTL_CONF_GET, CMD_CONF_FOPT_ITEM },
{ CMD_CONF_SET, cmd_conf_ctl, CTL_CONF_SET, CMD_CONF_FREQ_ITEM | CMD_CONF_FOPT_DATA },
{ CMD_CONF_UNSET, cmd_conf_ctl, CTL_CONF_UNSET, CMD_CONF_FOPT_ITEM | CMD_CONF_FOPT_DATA },
{ NULL }
};
const cmd_desc_old_t cmd_table_old[] = {
{ "checkzone", CMD_ZONE_CHECK },
{ "memstats", CMD_ZONE_MEMSTATS },
{ "zonestatus", CMD_ZONE_STATUS },
{ "refresh", CMD_ZONE_REFRESH },
{ "flush", CMD_ZONE_FLUSH },
{ "signzone", CMD_ZONE_SIGN },
{ "checkconf", CMD_CONF_CHECK },
{ "conf-desc", CMD_CONF_LIST },
{ CMD_CONF_DIFF, cmd_conf_ctl, CTL_CONF_DIFF, CMD_CONF_FOPT_ITEM | CMD_CONF_FREQ_TXN },
{ CMD_CONF_GET, cmd_conf_ctl, CTL_CONF_GET, CMD_CONF_FOPT_ITEM | CMD_CONF_FREQ_TXN },
{ CMD_CONF_SET, cmd_conf_ctl, CTL_CONF_SET, CMD_CONF_FREQ_ITEM | CMD_CONF_FOPT_DATA | CMD_CONF_FREQ_TXN },
{ CMD_CONF_UNSET, cmd_conf_ctl, CTL_CONF_UNSET, CMD_CONF_FOPT_ITEM | CMD_CONF_FOPT_DATA | CMD_CONF_FREQ_TXN },
{ NULL }
};
const cmd_help_t cmd_help_table[] = {
static const cmd_help_t cmd_help_table[] = {
{ CMD_EXIT, "", "Exit interactive mode." },
{ "", "", "" },
{ CMD_STATUS, "", "Check if the server is running." },
{ CMD_STOP, "", "Stop the server if running." },
{ CMD_RELOAD, "", "Reload the server configuration and modified zones." },
......@@ -733,3 +725,18 @@ const cmd_help_t cmd_help_table[] = {
{ CMD_CONF_UNSET, "[<item>] [<data>...]", "Unset the item data in the transaction." },
{ NULL }
};
void print_commands(void)
{
printf("\nActions:\n");
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 which requires a configuration.\n");
}
......@@ -41,6 +41,8 @@ typedef enum {
CMD_CONF_FOPT_ITEM = 1 << 2, /*!< Optional item argument. */
CMD_CONF_FREQ_ITEM = 1 << 3, /*!< Required item argument. */
CMD_CONF_FOPT_DATA = 1 << 4, /*!< Optional item data argument. */
CMD_CONF_FOPT_ZONE = 1 << 5, /*!< Optional zone name argument. */
CMD_CONF_FREQ_TXN = 1 << 6, /*!< Required opened confdb transaction. */
} cmd_conf_flag_t;
struct cmd_desc;
......@@ -51,7 +53,7 @@ typedef struct {
const cmd_desc_t *desc;
knot_ctl_t *ctl;
int argc;
char **argv;
const char **argv;
cmd_flag_t flags;
} cmd_args_t;
......@@ -63,12 +65,6 @@ struct cmd_desc {
cmd_conf_flag_t flags;
};
/*! \brief Old command name translation. */
typedef struct {
const char *old_name;
const char *new_name;
} cmd_desc_old_t;
/*! \brief Command description. */
typedef struct {
const char *name;
......@@ -79,10 +75,7 @@ typedef struct {
/*! \brief Table of commands. */
extern const cmd_desc_t cmd_table[];
/*! \brief Table of command translations. */
extern const cmd_desc_old_t cmd_table_old[];
/*! \brief Table of command descriptions. */
extern const cmd_help_t cmd_help_table[];
/*! \brief Prints commands help. */
void print_commands(void);
/*! @} */
This diff is collapsed.
/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*!
* \file
*
* \brief Knot control interactive mode.
*
* \addtogroup knot_utils
* @{
*/
#pragma once
#include "utils/knotc/process.h"
/*!
* Executes an interactive processing loop.
*
* \param[in] params Utility parameters.
*/
int interactive_loop(params_t *params);
/*! @} */
This diff is collapsed.
/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <sys/stat.h>
#include "knot/conf/conf.h"
#include "knot/common/log.h"
#include "utils/knotc/commands.h"
#include "utils/knotc/process.h"
static const cmd_desc_t* get_cmd_desc(const char *command)
{
/* Find requested command. */
const cmd_desc_t *desc = cmd_table;
while (desc->name != NULL) {
if (strcmp(desc->name, command) == 0) {
break;
}
desc++;
}
if (desc->name == NULL) {
log_error("invalid command '%s'", command);
return NULL;
}
return desc;
}
int set_config(const cmd_desc_t *desc, params_t *params)
{
if (params->config != NULL && params->confdb != NULL) {
log_error("ambiguous configuration source");
return KNOT_EINVAL;
}
/* Mask relevant flags. */
cmd_conf_flag_t flags = desc->flags & (CMD_CONF_FREAD | CMD_CONF_FWRITE);
/* Choose the optimal config source. */
struct stat st;
bool import = false;
if (flags == CMD_CONF_FNONE && params->socket != NULL) {
import = false;
params->confdb = NULL;
} else if (params->confdb != NULL) {
import = false;
} else if (flags == CMD_CONF_FWRITE) {
import = false;
params->confdb = CONF_DEFAULT_DBDIR;
} else if (params->config != NULL){
import = true;
} else if (stat(CONF_DEFAULT_DBDIR, &st) == 0) {
import = false;
params->confdb = CONF_DEFAULT_DBDIR;
} else if (stat(CONF_DEFAULT_FILE, &st) == 0) {
import = true;
params->config = CONF_DEFAULT_FILE;
} else if (flags != CMD_CONF_FNONE) {
log_error("no configuration source available");
return KNOT_EINVAL;
}
const char *src = import ? params->config : params->confdb;
log_debug("%s '%s'", import ? "config" : "confdb",
(src != NULL) ? src : "empty");
/* Prepare config flags. */
conf_flag_t conf_flags = CONF_FNOHOSTNAME;
if (params->confdb != NULL && !(flags & CMD_CONF_FWRITE)) {
conf_flags |= CONF_FREADONLY;
}
/* Open confdb. */
conf_t *new_conf = NULL;
int ret = conf_new(&new_conf, conf_scheme, params->confdb, conf_flags);
if (ret != KNOT_EOK) {
log_error("failed to open configuration database '%s' (%s)",
(params->confdb != NULL) ? params->confdb : "",
knot_strerror(ret));
return ret;
}
/* Import the config file. */
if (import) {
ret = conf_import(new_conf, params->config, true);
if (ret != KNOT_EOK) {
log_error("failed to load configuration file '%s' (%s)",
params->config, knot_strerror(ret));
conf_free(new_conf);
return ret;
}
}
/* Update to the new config. */
conf_update(new_conf);
return KNOT_EOK;
}
int set_ctl(knot_ctl_t **ctl, const cmd_desc_t *desc, params_t *params)
{
if (desc == NULL) {
*ctl = NULL;
return KNOT_EINVAL;
}
/* Mask relevant flags. */
cmd_conf_flag_t flags = desc->flags & (CMD_CONF_FREAD | CMD_CONF_FWRITE);
/* Check if control socket is required. */
if (flags != CMD_CONF_FNONE) {
*ctl = NULL;
return KNOT_EOK;
}
/* Get control socket path. */
char *path = NULL;
if (params->socket != NULL) {
path = strdup(params->socket);
} else {
conf_val_t listen_val = conf_get(conf(), C_CTL, C_LISTEN);
conf_val_t rundir_val = conf_get(conf(), C_SRV, C_RUNDIR);
char *rundir = conf_abs_path(&rundir_val, NULL);
path = conf_abs_path(&listen_val, rundir);
free(rundir);
}
if (path == NULL) {
log_error("empty control socket path");
return KNOT_EINVAL;
}
log_debug("socket '%s'", path);
*ctl = knot_ctl_alloc();
if (*ctl == NULL) {
free(path);
return KNOT_ENOMEM;
}
knot_ctl_set_timeout(*ctl, params->timeout);
int ret = knot_ctl_connect(*ctl, path);
if (ret != KNOT_EOK) {
knot_ctl_free(*ctl);
log_error("failed to connect to socket '%s' (%s)", path,
knot_strerror(ret));
free(path);
return ret;
}
free(path);
return KNOT_EOK;
}
void unset_ctl(knot_ctl_t *ctl)
{
if (ctl == NULL) {
return;
}
int ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_END, NULL);
if (ret != KNOT_EOK && ret != KNOT_ECONN) {
log_error("failed to finish control (%s)", knot_strerror(ret));
}
knot_ctl_close(ctl);
knot_ctl_free(ctl);
}
int process_cmd(int argc, const char **argv, params_t *params)
{
if (argc == 0) {
return KNOT_ENOTSUP;
}
/* Check the command name. */
const cmd_desc_t *desc = get_cmd_desc(argv[0]);
if (desc == NULL) {
return KNOT_ENOENT;
}
/* Check for exit. */
if (desc->fcn == NULL) {
return KNOT_CTL_ESTOP;
}
/* Set up the configuration. */
int ret = set_config(desc, params);
if (ret != KNOT_EOK) {
return ret;
}
/* Prepare command parameters. */
cmd_args_t args = {
.desc = desc,
.argc = argc - 1,
.argv = argv + 1,
.flags = params->flags
};
/* Set control interface if necessary. */
ret = set_ctl(&args.ctl, desc, params);
if (ret != KNOT_EOK) {
conf_update(NULL);
return ret;
}
/* Execute the command. */
ret = desc->fcn(&args);
/* Cleanup */
unset_ctl(args.ctl);
conf_update(NULL);
return KNOT_EOK;
}
/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*!
* \file
*
* \brief Knot control processing.
*
* \addtogroup knot_utils
* @{
*/
#pragma once
#include "utils/knotc/commands.h"
/*! Utility command line parameters. */
typedef struct {
cmd_flag_t flags;
const char *config;
const char *confdb;
const char *socket;
bool verbose;
uint16_t timeout;
} params_t;
/*!
* Prepares a proper configuration according to the specified command.
*
* \param[in] params Utility parameters.
*
* \return Error code, KNOT_EOK if successful.
*/
int set_config(const cmd_desc_t *desc, params_t *params);
/*!
* Estabilishes a control interface if necessary.
*
* \param[in] ctl Control context.
* \param[in] desc Utility command descriptor.
* \param[in] params Utility parameters.
*
* \return Error code, KNOT_EOK if successful.
*/
int set_ctl(knot_ctl_t **ctl, const cmd_desc_t *desc, params_t *params);
/*!
* Cleans up the control context.
*
* \param[in] ctl Control context.
*/
void unset_ctl(knot_ctl_t *ctl);
/*!
* Processes the given utility command.
*
* \param[in] argc Number of command arguments.
* \param[in] argv Command arguments.
* \param[in] params Utility parameters.
*
* \return Error code, KNOT_EOK if successful.
*/
int process_cmd(int argc, const char **argv, params_t *params);
/*! @} */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment