doveadm-cmd.c (dovecot-2.3.16) | : | doveadm-cmd.c (dovecot-2.3.17) | ||
---|---|---|---|---|
skipping to change at line 15 | skipping to change at line 15 | |||
#include "istream.h" | #include "istream.h" | |||
#include "str.h" | #include "str.h" | |||
#include "net.h" | #include "net.h" | |||
#include "doveadm.h" | #include "doveadm.h" | |||
#include "doveadm-cmd.h" | #include "doveadm-cmd.h" | |||
#include <stdio.h> | #include <stdio.h> | |||
#include <unistd.h> | #include <unistd.h> | |||
#include <getopt.h> | #include <getopt.h> | |||
static struct doveadm_cmd *doveadm_commands[] = { | ||||
&doveadm_cmd_mailbox_mutf7, | ||||
&doveadm_cmd_sis_deduplicate, | ||||
&doveadm_cmd_sis_find, | ||||
}; | ||||
static struct doveadm_cmd_ver2 *doveadm_commands_ver2[] = { | static struct doveadm_cmd_ver2 *doveadm_commands_ver2[] = { | |||
&doveadm_cmd_mailbox_mutf7, | ||||
&doveadm_cmd_service_stop_ver2, | &doveadm_cmd_service_stop_ver2, | |||
&doveadm_cmd_service_status_ver2, | &doveadm_cmd_service_status_ver2, | |||
&doveadm_cmd_sis_deduplicate, | ||||
&doveadm_cmd_sis_find, | ||||
&doveadm_cmd_process_status_ver2, | &doveadm_cmd_process_status_ver2, | |||
&doveadm_cmd_stop_ver2, | &doveadm_cmd_stop_ver2, | |||
&doveadm_cmd_reload_ver2, | &doveadm_cmd_reload_ver2, | |||
&doveadm_cmd_stats_dump_ver2, | &doveadm_cmd_stats_dump_ver2, | |||
&doveadm_cmd_stats_add_ver2, | ||||
&doveadm_cmd_stats_remove_ver2, | ||||
&doveadm_cmd_oldstats_dump_ver2, | &doveadm_cmd_oldstats_dump_ver2, | |||
&doveadm_cmd_oldstats_reset_ver2, | &doveadm_cmd_oldstats_reset_ver2, | |||
&doveadm_cmd_penalty_ver2, | &doveadm_cmd_penalty_ver2, | |||
&doveadm_cmd_kick_ver2, | &doveadm_cmd_kick_ver2, | |||
&doveadm_cmd_who_ver2 | &doveadm_cmd_who_ver2 | |||
}; | }; | |||
static const struct exit_code_str { | static const struct exit_code_str { | |||
int code; | int code; | |||
const char *str; | const char *str; | |||
skipping to change at line 50 | skipping to change at line 49 | |||
{ EX_TEMPFAIL, "TEMPFAIL" }, | { EX_TEMPFAIL, "TEMPFAIL" }, | |||
{ EX_USAGE, "USAGE" }, | { EX_USAGE, "USAGE" }, | |||
{ EX_NOUSER, "NOUSER" }, | { EX_NOUSER, "NOUSER" }, | |||
{ EX_NOPERM, "NOPERM" }, | { EX_NOPERM, "NOPERM" }, | |||
{ EX_PROTOCOL, "PROTOCOL" }, | { EX_PROTOCOL, "PROTOCOL" }, | |||
{ EX_DATAERR, "DATAERR" }, | { EX_DATAERR, "DATAERR" }, | |||
{ DOVEADM_EX_NOREPLICATE, "NOREPLICATE" }, | { DOVEADM_EX_NOREPLICATE, "NOREPLICATE" }, | |||
{ DOVEADM_EX_NOTFOUND, "NOTFOUND" } | { DOVEADM_EX_NOTFOUND, "NOTFOUND" } | |||
}; | }; | |||
ARRAY_TYPE(doveadm_cmd) doveadm_cmds; | ||||
ARRAY_TYPE(doveadm_cmd_ver2) doveadm_cmds_ver2; | ARRAY_TYPE(doveadm_cmd_ver2) doveadm_cmds_ver2; | |||
ARRAY_DEFINE_TYPE(getopt_option_array, struct option); | ARRAY_DEFINE_TYPE(getopt_option_array, struct option); | |||
const char *doveadm_exit_code_to_str(int code) | const char *doveadm_exit_code_to_str(int code) | |||
{ | { | |||
for(size_t i = 0; i < N_ELEMENTS(exit_code_strings); i++) { | for(size_t i = 0; i < N_ELEMENTS(exit_code_strings); i++) { | |||
const struct exit_code_str *ptr = &exit_code_strings[i]; | const struct exit_code_str *ptr = &exit_code_strings[i]; | |||
if (ptr->code == code) | if (ptr->code == code) | |||
return ptr->str; | return ptr->str; | |||
} | } | |||
skipping to change at line 74 | skipping to change at line 72 | |||
int doveadm_str_to_exit_code(const char *reason) | int doveadm_str_to_exit_code(const char *reason) | |||
{ | { | |||
for(size_t i = 0; i < N_ELEMENTS(exit_code_strings); i++) { | for(size_t i = 0; i < N_ELEMENTS(exit_code_strings); i++) { | |||
const struct exit_code_str *ptr = &exit_code_strings[i]; | const struct exit_code_str *ptr = &exit_code_strings[i]; | |||
if (strcmp(ptr->str, reason) == 0) | if (strcmp(ptr->str, reason) == 0) | |||
return ptr->code; | return ptr->code; | |||
} | } | |||
return DOVEADM_EX_UNKNOWN; | return DOVEADM_EX_UNKNOWN; | |||
} | } | |||
void doveadm_register_cmd(const struct doveadm_cmd *cmd) | ||||
{ | ||||
array_push_back(&doveadm_cmds, cmd); | ||||
} | ||||
void doveadm_cmd_register_ver2(struct doveadm_cmd_ver2 *cmd) | void doveadm_cmd_register_ver2(struct doveadm_cmd_ver2 *cmd) | |||
{ | { | |||
if (cmd->cmd == NULL) { | if (cmd->cmd == NULL) { | |||
if (cmd->mail_cmd != NULL) | if (cmd->mail_cmd != NULL) | |||
cmd->cmd = doveadm_cmd_ver2_to_mail_cmd_wrapper; | cmd->cmd = doveadm_cmd_ver2_to_mail_cmd_wrapper; | |||
else if (cmd->old_cmd != NULL) | ||||
cmd->cmd = doveadm_cmd_ver2_to_cmd_wrapper; | ||||
else i_unreached(); | else i_unreached(); | |||
} | } | |||
array_push_back(&doveadm_cmds_ver2, cmd); | array_push_back(&doveadm_cmds_ver2, cmd); | |||
} | } | |||
const struct doveadm_cmd_ver2 *doveadm_cmd_find_ver2(const char *cmd_name) | const struct doveadm_cmd_ver2 *doveadm_cmd_find_ver2(const char *cmd_name) | |||
{ | { | |||
const struct doveadm_cmd_ver2 *cmd; | const struct doveadm_cmd_ver2 *cmd; | |||
array_foreach(&doveadm_cmds_ver2, cmd) { | array_foreach(&doveadm_cmds_ver2, cmd) { | |||
if (strcmp(cmd_name, cmd->name)==0) | if (strcmp(cmd_name, cmd->name) == 0) | |||
return cmd; | return cmd; | |||
} | } | |||
return NULL; | return NULL; | |||
} | } | |||
const struct doveadm_cmd_ver2 * | const struct doveadm_cmd_ver2 * | |||
doveadm_cmd_find_with_args_ver2(const char *cmd_name, int *argc, | doveadm_cmd_find_with_args_ver2(const char *cmd_name, int *argc, | |||
const char *const *argv[]) | const char *const *argv[]) | |||
{ | { | |||
int i, k; | int i, k; | |||
const struct doveadm_cmd_ver2 *cmd; | const struct doveadm_cmd_ver2 *cmd; | |||
const char *cptr; | const char *cptr; | |||
for(i=0;i<*argc;i++) { | for (i = 0; i < *argc; i++) { | |||
if (strcmp((*argv)[i],cmd_name)==0) break; | if (strcmp((*argv)[i], cmd_name) == 0) | |||
break; | ||||
} | } | |||
i_assert(i != *argc); | i_assert(i != *argc); | |||
array_foreach(&doveadm_cmds_ver2, cmd) { | array_foreach(&doveadm_cmds_ver2, cmd) { | |||
cptr = cmd->name; | cptr = cmd->name; | |||
/* cannot reuse i here because this needs be | /* cannot reuse i here because this needs be | |||
done more than once */ | done more than once */ | |||
for (k=0; *cptr != '\0' && i+k < *argc; k++) { | for (k = 0; *cptr != '\0' && i + k < *argc; k++) { | |||
size_t alen = strlen((*argv)[i+k]); | size_t alen = strlen((*argv)[i + k]); | |||
/* make sure we don't overstep */ | /* make sure we don't overstep */ | |||
if (strlen(cptr) < alen) break; | if (strlen(cptr) < alen) | |||
break; | ||||
/* did not match */ | /* did not match */ | |||
if (strncmp(cptr, (*argv)[i+k], alen) != 0) break; | if (strncmp(cptr, (*argv)[i+k], alen) != 0) | |||
break; | ||||
/* do not accept abbreviations */ | /* do not accept abbreviations */ | |||
if (cptr[alen] != ' ' && cptr[alen] != '\0') break; | if (cptr[alen] != ' ' && cptr[alen] != '\0') | |||
break; | ||||
cptr += alen; | cptr += alen; | |||
if (*cptr != '\0') cptr++; /* consume space */ | if (*cptr != '\0') | |||
cptr++; /* consume space */ | ||||
} | } | |||
/* name was fully consumed */ | /* name was fully consumed */ | |||
if (*cptr == '\0') { | if (*cptr == '\0') { | |||
if (k > 1) { | if (k > 1) { | |||
*argc -= k-1; | *argc -= k-1; | |||
*argv += k-1; | *argv += k-1; | |||
} | } | |||
return cmd; | return cmd; | |||
} | } | |||
} | } | |||
return NULL; | return NULL; | |||
} | } | |||
static bool | ||||
doveadm_cmd_find_multi_word(const char *cmdname, int *_argc, | ||||
const char *const *_argv[]) | ||||
{ | ||||
int argc = *_argc; | ||||
const char *const *argv = *_argv; | ||||
size_t len; | ||||
if (argc < 2) | ||||
return FALSE; | ||||
len = strlen(argv[1]); | ||||
if (!str_begins(cmdname, argv[1])) | ||||
return FALSE; | ||||
argc--; argv++; | ||||
if (cmdname[len] == ' ') { | ||||
/* more args */ | ||||
if (!doveadm_cmd_find_multi_word(cmdname + len + 1, | ||||
&argc, &argv)) | ||||
return FALSE; | ||||
} else { | ||||
if (cmdname[len] != '\0') | ||||
return FALSE; | ||||
} | ||||
*_argc = argc; | ||||
*_argv = argv; | ||||
return TRUE; | ||||
} | ||||
const struct doveadm_cmd * | ||||
doveadm_cmd_find_with_args(const char *cmd_name, int *argc, | ||||
const char *const *argv[]) | ||||
{ | ||||
const struct doveadm_cmd *cmd; | ||||
size_t cmd_name_len; | ||||
i_assert(*argc > 0); | ||||
cmd_name_len = strlen(cmd_name); | ||||
array_foreach(&doveadm_cmds, cmd) { | ||||
if (strcmp(cmd->name, cmd_name) == 0) | ||||
return cmd; | ||||
/* see if it matches a multi-word command */ | ||||
if (strncmp(cmd->name, cmd_name, cmd_name_len) == 0 && | ||||
cmd->name[cmd_name_len] == ' ') { | ||||
const char *subcmd_name = cmd->name + cmd_name_len + 1; | ||||
if (doveadm_cmd_find_multi_word(subcmd_name, | ||||
argc, argv)) | ||||
return cmd; | ||||
} | ||||
} | ||||
return NULL; | ||||
} | ||||
void doveadm_cmds_init(void) | void doveadm_cmds_init(void) | |||
{ | { | |||
unsigned int i; | unsigned int i; | |||
i_array_init(&doveadm_cmds, 32); | ||||
i_array_init(&doveadm_cmds_ver2, 2); | i_array_init(&doveadm_cmds_ver2, 2); | |||
for (i = 0; i < N_ELEMENTS(doveadm_commands); i++) | ||||
doveadm_register_cmd(doveadm_commands[i]); | ||||
for (i = 0; i < N_ELEMENTS(doveadm_commands_ver2); i++) | for (i = 0; i < N_ELEMENTS(doveadm_commands_ver2); i++) | |||
doveadm_cmd_register_ver2(doveadm_commands_ver2[i]); | doveadm_cmd_register_ver2(doveadm_commands_ver2[i]); | |||
doveadm_register_director_commands(); | doveadm_register_director_commands(); | |||
doveadm_register_instance_commands(); | doveadm_register_instance_commands(); | |||
doveadm_register_proxy_commands(); | doveadm_register_proxy_commands(); | |||
doveadm_register_log_commands(); | doveadm_register_log_commands(); | |||
doveadm_register_replicator_commands(); | doveadm_register_replicator_commands(); | |||
doveadm_register_dict_commands(); | doveadm_register_dict_commands(); | |||
doveadm_register_fs_commands(); | doveadm_register_fs_commands(); | |||
} | } | |||
void doveadm_cmds_deinit(void) | void doveadm_cmds_deinit(void) | |||
{ | { | |||
array_free(&doveadm_cmds); | ||||
array_free(&doveadm_cmds_ver2); | array_free(&doveadm_cmds_ver2); | |||
} | } | |||
static const struct doveadm_cmd_param* | static const struct doveadm_cmd_param * | |||
doveadm_cmd_param_get(const struct doveadm_cmd_context *cctx, | doveadm_cmd_param_get(const struct doveadm_cmd_context *cctx, | |||
const char *name) | const char *name) | |||
{ | { | |||
i_assert(cctx != NULL); | i_assert(cctx != NULL); | |||
i_assert(cctx->argv != NULL); | i_assert(cctx->argv != NULL); | |||
for(int i = 0; i < cctx->argc; i++) { | for(int i = 0; i < cctx->argc; i++) { | |||
if (strcmp(cctx->argv[i].name, name) == 0 && cctx->argv[i].value_ | if (strcmp(cctx->argv[i].name, name) == 0 && | |||
set) | cctx->argv[i].value_set) | |||
return &cctx->argv[i]; | return &cctx->argv[i]; | |||
} | } | |||
return NULL; | return NULL; | |||
} | } | |||
bool doveadm_cmd_param_bool(const struct doveadm_cmd_context *cctx, | bool doveadm_cmd_param_bool(const struct doveadm_cmd_context *cctx, | |||
const char *name, bool *value_r) | const char *name, bool *value_r) | |||
{ | { | |||
const struct doveadm_cmd_param *param; | const struct doveadm_cmd_param *param; | |||
if ((param = doveadm_cmd_param_get(cctx, name))==NULL) return FALSE; | if ((param = doveadm_cmd_param_get(cctx, name)) == NULL) | |||
return FALSE; | ||||
if (param->type == CMD_PARAM_BOOL) { | if (param->type == CMD_PARAM_BOOL) { | |||
*value_r = param->value.v_bool; | *value_r = param->value.v_bool; | |||
return TRUE; | return TRUE; | |||
} | } | |||
return FALSE; | return FALSE; | |||
} | } | |||
bool doveadm_cmd_param_int64(const struct doveadm_cmd_context *cctx, | bool doveadm_cmd_param_int64(const struct doveadm_cmd_context *cctx, | |||
const char *name, int64_t *value_r) | const char *name, int64_t *value_r) | |||
{ | { | |||
const struct doveadm_cmd_param *param; | const struct doveadm_cmd_param *param; | |||
if ((param = doveadm_cmd_param_get(cctx, name))==NULL) return FALSE; | if ((param = doveadm_cmd_param_get(cctx, name)) == NULL) | |||
return FALSE; | ||||
if (param->type == CMD_PARAM_INT64) { | if (param->type == CMD_PARAM_INT64) { | |||
*value_r = param->value.v_int64; | *value_r = param->value.v_int64; | |||
return TRUE; | return TRUE; | |||
} | } | |||
return FALSE; | return FALSE; | |||
} | } | |||
bool doveadm_cmd_param_str(const struct doveadm_cmd_context *cctx, | bool doveadm_cmd_param_str(const struct doveadm_cmd_context *cctx, | |||
const char *name, const char **value_r) | const char *name, const char **value_r) | |||
{ | { | |||
const struct doveadm_cmd_param *param; | const struct doveadm_cmd_param *param; | |||
if ((param = doveadm_cmd_param_get(cctx, name))==NULL) return FALSE; | if ((param = doveadm_cmd_param_get(cctx, name)) == NULL) | |||
return FALSE; | ||||
if (param->type == CMD_PARAM_STR) { | if (param->type == CMD_PARAM_STR) { | |||
*value_r = param->value.v_string; | *value_r = param->value.v_string; | |||
return TRUE; | return TRUE; | |||
} | } | |||
return FALSE; | return FALSE; | |||
} | } | |||
bool doveadm_cmd_param_ip(const struct doveadm_cmd_context *cctx, | bool doveadm_cmd_param_ip(const struct doveadm_cmd_context *cctx, | |||
const char *name, struct ip_addr *value_r) | const char *name, struct ip_addr *value_r) | |||
{ | { | |||
const struct doveadm_cmd_param *param; | const struct doveadm_cmd_param *param; | |||
if ((param = doveadm_cmd_param_get(cctx, name))==NULL) return FALSE; | if ((param = doveadm_cmd_param_get(cctx, name)) == NULL) | |||
return FALSE; | ||||
if (param->type == CMD_PARAM_IP) { | if (param->type == CMD_PARAM_IP) { | |||
memcpy(value_r, ¶m->value.v_ip, sizeof(struct ip_addr)); | memcpy(value_r, ¶m->value.v_ip, sizeof(struct ip_addr)); | |||
return TRUE; | return TRUE; | |||
} | } | |||
return FALSE; | return FALSE; | |||
} | } | |||
bool doveadm_cmd_param_array(const struct doveadm_cmd_context *cctx, | bool doveadm_cmd_param_array(const struct doveadm_cmd_context *cctx, | |||
const char *name, const char *const **value_r) | const char *name, const char *const **value_r) | |||
{ | { | |||
const struct doveadm_cmd_param *param; | const struct doveadm_cmd_param *param; | |||
unsigned int count; | unsigned int count; | |||
if ((param = doveadm_cmd_param_get(cctx, name))==NULL) return FALSE; | if ((param = doveadm_cmd_param_get(cctx, name)) == NULL) | |||
return FALSE; | ||||
if (param->type == CMD_PARAM_ARRAY) { | if (param->type == CMD_PARAM_ARRAY) { | |||
*value_r = array_get(¶m->value.v_array, &count); | *value_r = array_get(¶m->value.v_array, &count); | |||
/* doveadm_cmd_params_null_terminate_arrays() should have been | /* doveadm_cmd_params_null_terminate_arrays() should have been | |||
called, which guarantees that we're NULL-terminated */ | called, which guarantees that we're NULL-terminated */ | |||
i_assert((*value_r)[count] == NULL); | i_assert((*value_r)[count] == NULL); | |||
return TRUE; | return TRUE; | |||
} | } | |||
return FALSE; | return FALSE; | |||
} | } | |||
bool doveadm_cmd_param_istream(const struct doveadm_cmd_context *cctx, | bool doveadm_cmd_param_istream(const struct doveadm_cmd_context *cctx, | |||
const char *name, struct istream **value_r) | const char *name, struct istream **value_r) | |||
{ | { | |||
const struct doveadm_cmd_param *param; | const struct doveadm_cmd_param *param; | |||
if ((param = doveadm_cmd_param_get(cctx, name))==NULL) return FALSE; | if ((param = doveadm_cmd_param_get(cctx, name)) == NULL) | |||
return FALSE; | ||||
if (param->type == CMD_PARAM_ISTREAM) { | if (param->type == CMD_PARAM_ISTREAM) { | |||
*value_r = param->value.v_istream; | *value_r = param->value.v_istream; | |||
return TRUE; | return TRUE; | |||
} | } | |||
return FALSE; | return FALSE; | |||
} | } | |||
void doveadm_cmd_params_clean(ARRAY_TYPE(doveadm_cmd_param_arr_t) *pargv) | void doveadm_cmd_params_clean(ARRAY_TYPE(doveadm_cmd_param_arr_t) *pargv) | |||
{ | { | |||
struct doveadm_cmd_param *param; | struct doveadm_cmd_param *param; | |||
array_foreach_modifiable(pargv, param) { | array_foreach_modifiable(pargv, param) { | |||
if (param->type == CMD_PARAM_ISTREAM && | if (param->type == CMD_PARAM_ISTREAM && | |||
param->value.v_istream != NULL) | param->value.v_istream != NULL) | |||
i_stream_destroy(¶m->value.v_istream); | i_stream_destroy(¶m->value.v_istream); | |||
} | } | |||
array_clear(pargv); | array_clear(pargv); | |||
} | } | |||
void doveadm_cmd_params_null_terminate_arrays(ARRAY_TYPE(doveadm_cmd_param_arr_t | void doveadm_cmd_params_null_terminate_arrays( | |||
) *pargv) | ARRAY_TYPE(doveadm_cmd_param_arr_t) *pargv) | |||
{ | { | |||
struct doveadm_cmd_param *param; | struct doveadm_cmd_param *param; | |||
array_foreach_modifiable(pargv, param) { | array_foreach_modifiable(pargv, param) { | |||
if (param->type == CMD_PARAM_ARRAY && | if (param->type == CMD_PARAM_ARRAY && | |||
array_is_created(¶m->value.v_array)) { | array_is_created(¶m->value.v_array)) { | |||
array_append_zero(¶m->value.v_array); | array_append_zero(¶m->value.v_array); | |||
array_pop_back(¶m->value.v_array); | array_pop_back(¶m->value.v_array); | |||
} | } | |||
} | } | |||
} | } | |||
static void | static void | |||
doveadm_cmd_params_to_argv(const char *name, int pargc, const struct doveadm_cmd | ||||
_param* params, | ||||
ARRAY_TYPE(const_string) *argv) | ||||
{ | ||||
bool array_add_opt; | ||||
int i; | ||||
const char * const * cptr; | ||||
i_assert(array_count(argv) == 0); | ||||
array_push_back(argv, &name); | ||||
ARRAY_TYPE(const_string) pargv; | ||||
t_array_init(&pargv, 8); | ||||
for(i=0;i<pargc;i++) { | ||||
const char *optarg = NULL; | ||||
ARRAY_TYPE(const_string) *target = argv; | ||||
if ((params[i].flags & CMD_PARAM_FLAG_POSITIONAL) != 0) | ||||
target = &pargv; | ||||
/* istreams are special */ | ||||
i_assert(params[i].type != CMD_PARAM_ISTREAM); | ||||
if (params[i].value_set) { | ||||
array_add_opt = FALSE; | ||||
if (params[i].short_opt != '\0') { | ||||
if (params[i].type == CMD_PARAM_ARRAY) { | ||||
array_add_opt = TRUE; | ||||
} else { | ||||
optarg = t_strdup_printf("-%c", params[i] | ||||
.short_opt); | ||||
array_push_back(argv, &optarg); | ||||
} | ||||
} | ||||
/* CMD_PARAM_BOOL is implicitly handled above */ | ||||
if (params[i].type == CMD_PARAM_STR) { | ||||
array_push_back(target, | ||||
¶ms[i].value.v_string); | ||||
} else if (params[i].type == CMD_PARAM_INT64) { | ||||
const char *tmp = t_strdup_printf("%lld", | ||||
(long long)params[i].value.v_int64); | ||||
array_push_back(target, &tmp); | ||||
} else if (params[i].type == CMD_PARAM_IP) { | ||||
const char *tmp = net_ip2addr(¶ms[i].value.v_ | ||||
ip); | ||||
array_push_back(target, &tmp); | ||||
} else if (params[i].type == CMD_PARAM_ARRAY) { | ||||
array_foreach(¶ms[i].value.v_array, cptr) { | ||||
if (array_add_opt) | ||||
array_push_back(argv, &optarg); | ||||
array_push_back(target, cptr); | ||||
} | ||||
} | ||||
} | ||||
} | ||||
if (array_count(&pargv) > 0) { | ||||
const char *dashdash = "--"; | ||||
array_push_back(argv, &dashdash); | ||||
array_append_array(argv, &pargv); | ||||
} | ||||
array_append_zero(argv); | ||||
} | ||||
void | ||||
doveadm_cmd_ver2_to_cmd_wrapper(struct doveadm_cmd_context *cctx) | ||||
{ | ||||
unsigned int pargc; | ||||
const char **pargv; | ||||
i_assert(cctx->cmd->old_cmd != NULL); | ||||
ARRAY_TYPE(const_string) nargv; | ||||
t_array_init(&nargv, 8); | ||||
doveadm_cmd_params_to_argv(cctx->cmd->name, cctx->argc, cctx->argv, &narg | ||||
v); | ||||
pargv = array_get_modifiable(&nargv, &pargc); | ||||
i_getopt_reset(); | ||||
cctx->cmd->old_cmd(pargc-1, (char**)pargv); | ||||
} | ||||
static void | ||||
doveadm_build_options(const struct doveadm_cmd_param par[], | doveadm_build_options(const struct doveadm_cmd_param par[], | |||
string_t *shortopts, | string_t *shortopts, | |||
ARRAY_TYPE(getopt_option_array) *longopts) | ARRAY_TYPE(getopt_option_array) *longopts) | |||
{ | { | |||
for(size_t i=0; par[i].name != NULL; i++) { | for (size_t i = 0; par[i].name != NULL; i++) { | |||
struct option longopt; | struct option longopt; | |||
i_zero(&longopt); | i_zero(&longopt); | |||
longopt.name = par[i].name; | longopt.name = par[i].name; | |||
if (par[i].short_opt != '\0') { | if (par[i].short_opt != '\0') { | |||
longopt.val = par[i].short_opt; | longopt.val = par[i].short_opt; | |||
str_append_c(shortopts, par[i].short_opt); | str_append_c(shortopts, par[i].short_opt); | |||
if (par[i].type != CMD_PARAM_BOOL) | if (par[i].type != CMD_PARAM_BOOL) | |||
str_append_c(shortopts, ':'); | str_append_c(shortopts, ':'); | |||
} | } | |||
if (par[i].type != CMD_PARAM_BOOL) | if (par[i].type != CMD_PARAM_BOOL) | |||
longopt.has_arg = 1; | longopt.has_arg = 1; | |||
array_push_back(longopts, &longopt); | array_push_back(longopts, &longopt); | |||
} | } | |||
array_append_zero(longopts); | array_append_zero(longopts); | |||
} | } | |||
static void doveadm_fill_param(struct doveadm_cmd_param *param, | static void | |||
const char *value, pool_t pool) | doveadm_fill_param(struct doveadm_cmd_param *param, | |||
const char *value, pool_t pool) | ||||
{ | { | |||
param->value_set = TRUE; | param->value_set = TRUE; | |||
switch(param->type) { | switch (param->type) { | |||
case CMD_PARAM_BOOL: | case CMD_PARAM_BOOL: | |||
param->value.v_bool = TRUE; break; | param->value.v_bool = TRUE; | |||
break; | ||||
case CMD_PARAM_INT64: | case CMD_PARAM_INT64: | |||
if (str_to_int64(value, ¶m->value.v_int64) != 0) { | if (str_to_int64(value, ¶m->value.v_int64) != 0) | |||
param->value_set = FALSE; | param->value_set = FALSE; | |||
} | ||||
break; | break; | |||
case CMD_PARAM_IP: | case CMD_PARAM_IP: | |||
if (net_addr2ip(value, ¶m->value.v_ip) != 0) { | if (net_addr2ip(value, ¶m->value.v_ip) != 0) | |||
param->value_set = FALSE; | param->value_set = FALSE; | |||
} | ||||
break; | break; | |||
case CMD_PARAM_STR: | case CMD_PARAM_STR: | |||
param->value.v_string = p_strdup(pool, value); | param->value.v_string = p_strdup(pool, value); | |||
break; | break; | |||
case CMD_PARAM_ARRAY: | case CMD_PARAM_ARRAY: | |||
if (!array_is_created(¶m->value.v_array)) | if (!array_is_created(¶m->value.v_array)) | |||
p_array_init(¶m->value.v_array, pool, 8); | p_array_init(¶m->value.v_array, pool, 8); | |||
const char *val = p_strdup(pool, value); | const char *val = p_strdup(pool, value); | |||
array_push_back(¶m->value.v_array, &val); | array_push_back(¶m->value.v_array, &val); | |||
break; | break; | |||
case CMD_PARAM_ISTREAM: { | case CMD_PARAM_ISTREAM: { | |||
struct istream *is; | struct istream *is; | |||
if (strcmp(value,"-") == 0) { | if (strcmp(value,"-") == 0) | |||
is = i_stream_create_fd(STDIN_FILENO, IO_BLOCK_SIZE); | is = i_stream_create_fd(STDIN_FILENO, IO_BLOCK_SIZE); | |||
} else { | else | |||
is = i_stream_create_file(value, IO_BLOCK_SIZE); | is = i_stream_create_file(value, IO_BLOCK_SIZE); | |||
} | ||||
param->value.v_istream = is; | param->value.v_istream = is; | |||
break; | ||||
} | } | |||
} | } | |||
} | } | |||
bool doveadm_cmd_try_run_ver2(const char *cmd_name, | bool doveadm_cmd_try_run_ver2(const char *cmd_name, | |||
int argc, const char *const argv[], | int argc, const char *const argv[], | |||
struct doveadm_cmd_context *cctx) | struct doveadm_cmd_context *cctx) | |||
{ | { | |||
const struct doveadm_cmd_ver2 *cmd; | const struct doveadm_cmd_ver2 *cmd; | |||
cmd = doveadm_cmd_find_with_args_ver2(cmd_name, &argc, &argv); | cmd = doveadm_cmd_find_with_args_ver2(cmd_name, &argc, &argv); | |||
if (cmd == NULL) | if (cmd == NULL) | |||
return FALSE; | return FALSE; | |||
cctx->cmd = cmd; | cctx->cmd = cmd; | |||
if (doveadm_cmd_run_ver2(argc, argv, cctx) < 0) | if (doveadm_cmd_run_ver2(argc, argv, cctx) < 0) | |||
doveadm_exit_code = EX_USAGE; | doveadm_exit_code = EX_USAGE; | |||
return TRUE; | return TRUE; | |||
} | } | |||
int doveadm_cmd_run_ver2(int argc, const char *const argv[], | static int | |||
struct doveadm_cmd_context *cctx) | doveadm_cmd_process_options(int argc, const char *const argv[], | |||
struct doveadm_cmd_context *cctx, pool_t pool, | ||||
ARRAY_TYPE(doveadm_cmd_param_arr_t) *pargv) | ||||
{ | { | |||
struct doveadm_cmd_param *param; | struct doveadm_cmd_param *param; | |||
ARRAY_TYPE(doveadm_cmd_param_arr_t) pargv; | ||||
ARRAY_TYPE(getopt_option_array) opts; | ARRAY_TYPE(getopt_option_array) opts; | |||
unsigned int pargc; | ||||
int c,li; | ||||
pool_t pool = pool_datastack_create(); | ||||
string_t *optbuf = str_new(pool, 64); | string_t *optbuf = str_new(pool, 64); | |||
p_array_init(&opts, pool, 4); | p_array_init(&opts, pool, 4); | |||
// build parameters | // build parameters | |||
if ((cctx->cmd->flags & CMD_FLAG_NO_UNORDERED_OPTIONS) != 0) | ||||
str_append_c(optbuf, '+'); | ||||
doveadm_build_options(cctx->cmd->parameters, optbuf, &opts); | doveadm_build_options(cctx->cmd->parameters, optbuf, &opts); | |||
p_array_init(&pargv, pool, 20); | unsigned int pargc; | |||
for (pargc = 0; cctx->cmd->parameters[pargc].name != NULL; pargc++) { | ||||
for(pargc=0;cctx->cmd->parameters[pargc].name != NULL;pargc++) { | param = array_append_space(pargv); | |||
param = array_append_space(&pargv); | memcpy(param, &cctx->cmd->parameters[pargc], | |||
memcpy(param, &cctx->cmd->parameters[pargc], sizeof(struct dovead | sizeof(struct doveadm_cmd_param)); | |||
m_cmd_param)); | ||||
param->value_set = FALSE; | param->value_set = FALSE; | |||
} | } | |||
i_assert(pargc == array_count(&opts)-1); /* opts is NULL-terminated */ | i_assert(pargc == array_count(&opts)-1); /* opts is NULL-terminated */ | |||
while((c = getopt_long(argc, (char*const*)argv, str_c(optbuf), array_fron | if ((cctx->cmd->flags & CMD_FLAG_NO_OPTIONS) != 0) { | |||
t(&opts), &li)) > -1) { | /* process -parameters as if they were regular parameters */ | |||
switch(c) { | optind = 1; | |||
return 0; | ||||
} | ||||
int c, li; | ||||
while ((c = getopt_long(argc, (char *const *)argv, str_c(optbuf), | ||||
array_front(&opts), &li)) > -1) { | ||||
switch (c) { | ||||
case 0: | case 0: | |||
for(unsigned int i = 0; i < array_count(&pargv); i++) { | for (unsigned int i = 0; i < array_count(pargv); i++) { | |||
const struct option *opt = array_idx(&opts,li); | const struct option *opt = array_idx(&opts, li); | |||
param = array_idx_modifiable(&pargv,i); | param = array_idx_modifiable(pargv, i); | |||
if (opt->name == param->name) | if (opt->name == param->name) | |||
doveadm_fill_param(param, optarg, pool); | doveadm_fill_param(param, optarg, pool); | |||
} | } | |||
break; | break; | |||
case '?': | case '?': | |||
case ':': | case ':': | |||
doveadm_cmd_params_clean(&pargv); | doveadm_cmd_params_clean(pargv); | |||
return -1; | return -1; | |||
default: | default: | |||
// hunt the option | // hunt the option | |||
for(unsigned int i = 0; i < pargc; i++) { | for (unsigned int i = 0; i < pargc; i++) { | |||
const struct option *longopt = array_idx(&opts,i) | const struct option *longopt = | |||
; | array_idx(&opts, i); | |||
if (longopt->val == c) | if (longopt->val == c) | |||
doveadm_fill_param(array_idx_modifiable(& | doveadm_fill_param(array_idx_modifiable(p | |||
pargv,i), optarg, pool); | argv, i), | |||
optarg, pool); | ||||
} | } | |||
} | } | |||
} | } | |||
return 0; | ||||
} | ||||
int doveadm_cmd_run_ver2(int argc, const char *const argv[], | ||||
struct doveadm_cmd_context *cctx) | ||||
{ | ||||
ARRAY_TYPE(doveadm_cmd_param_arr_t) pargv; | ||||
unsigned int pargc; | ||||
pool_t pool = pool_datastack_create(); | ||||
p_array_init(&pargv, pool, 20); | ||||
if (doveadm_cmd_process_options(argc, argv, cctx, pool, &pargv) < 0) | ||||
return -1; | ||||
/* process positional arguments */ | /* process positional arguments */ | |||
for(;optind<argc;optind++) { | for (; optind < argc; optind++) { | |||
struct doveadm_cmd_param *ptr; | struct doveadm_cmd_param *ptr; | |||
bool found = FALSE; | bool found = FALSE; | |||
array_foreach_modifiable(&pargv, ptr) { | array_foreach_modifiable(&pargv, ptr) { | |||
if ((ptr->flags & CMD_PARAM_FLAG_POSITIONAL) != 0 && | if ((ptr->flags & CMD_PARAM_FLAG_POSITIONAL) != 0 && | |||
(ptr->value_set == FALSE || ptr->type == CMD_PARAM_AR | (ptr->value_set == FALSE || | |||
RAY)) { | ptr->type == CMD_PARAM_ARRAY)) { | |||
doveadm_fill_param(ptr, argv[optind], pool); | doveadm_fill_param(ptr, argv[optind], pool); | |||
found = TRUE; | found = TRUE; | |||
break; | break; | |||
} | } | |||
} | } | |||
if (!found) { | if (!found) { | |||
i_error("Extraneous arguments found: %s", | i_error("Extraneous arguments found: %s", | |||
t_strarray_join(argv+optind, " ")); | t_strarray_join(argv + optind, " ")); | |||
doveadm_cmd_params_clean(&pargv); | doveadm_cmd_params_clean(&pargv); | |||
return -1; | return -1; | |||
} | } | |||
} | } | |||
doveadm_cmd_params_null_terminate_arrays(&pargv); | doveadm_cmd_params_null_terminate_arrays(&pargv); | |||
cctx->argv = array_get_modifiable(&pargv, &pargc); | cctx->argv = array_get_modifiable(&pargv, &pargc); | |||
cctx->argc = pargc; | cctx->argc = pargc; | |||
cctx->cmd->cmd(cctx); | cctx->cmd->cmd(cctx); | |||
End of changes. 55 change blocks. | ||||
218 lines changed or deleted | 98 lines changed or added |