#define SET_TRACEDITF 25
#define SET_TRACESVC 26
#endif
-
+#define SET_TRAP_FAULTS 27
+#define ADD_CALL 28
#if defined(WITH_DBUS_TRANSPARENCY)
# define ADD_DBUS_CLIENT 30
# define ADD_DBUS_SERVICE 31
#endif
-
#define ADD_AUTO_API 'A'
#define ADD_BINDING 'b'
#define SET_CONFIG 'C'
-#define ADD_CALL 'c'
+#define SET_COLOR 'c'
#define SET_DAEMON 'D'
#define SET_EXEC 'e'
#define GET_HELP 'h'
#define SET_PORT 'p'
#define SET_QUIET 'q'
#define SET_RANDOM_TOKEN 'r'
+#define ADD_SET 's'
#define SET_TOKEN 't'
#define SET_UPLOAD_DIR 'u'
#define GET_VERSION 'V'
#define SET_VERBOSE 'v'
#define SET_WORK_DIR 'w'
+#define DUMP_CONFIG 'Z'
/* structure for defining of options */
struct option_desc {
static struct option_desc optdefs[] = {
/* *INDENT-OFF* */
{SET_VERBOSE, 0, "verbose", "Verbose Mode, repeat to increase verbosity"},
+ {SET_COLOR, 0, "color", "Colorize the ouput"},
{SET_QUIET, 0, "quiet", "Quiet Mode, repeat to decrease verbosity"},
{SET_LOG, 1, "log", "Tune log level"},
{SET_CACHE_TIMEOUT, 1, "cache-eol", "Client cache end of live [default " d2s(DEFAULT_CACHE_TIMEOUT) "]"},
{SET_WORK_DIR, 1, "workdir", "Set the working directory [default: $PWD or current working directory]"},
- {SET_UPLOAD_DIR, 1, "uploaddir", "Directory for uploading files [default: workdir]"},
- {SET_ROOT_DIR, 1, "rootdir", "Root Directory of the application [default: workdir]"},
+ {SET_UPLOAD_DIR, 1, "uploaddir", "Directory for uploading files [default: workdir] relative to workdir"},
+ {SET_ROOT_DIR, 1, "rootdir", "Root Directory of the application [default: workdir] relative to workdir"},
{ADD_LDPATH, 1, "ldpaths", "Load bindings from dir1:dir2:... [default = " BINDING_INSTALL_DIR "]"},
{ADD_BINDING, 1, "binding", "Load the binding of path"},
#endif
{SET_CONFIG, 1, "config", "Load options from the given config file"},
+ {DUMP_CONFIG, 0, "dump-config", "Dump the config to stdout and exit"},
+
+ {ADD_SET, 1, "set", "Set parameters ([API]/[KEY]:JSON or {\"API\":{\"KEY\":JSON}}" },
{SET_OUTPUT, 1, "output", "Redirect stdout and stderr to output file (when --daemon)"},
+ {SET_TRAP_FAULTS, 1, "trap-faults", "Trap faults: on, off, yes, no, true, false, 1, 0 (default: true)"},
+
{0, 0, NULL, NULL}
/* *INDENT-ON* */
};
name);
}
-/*---------------------------------------------------------
- | helpers for argument scanning
- +--------------------------------------------------------- */
-
-static const char *current_argument(int optid)
+static void dump(struct json_object *config, FILE *file, const char *prefix, const char *title)
{
- if (optarg == 0) {
- ERROR("option [--%s] needs a value i.e. --%s=xxx",
- name_of_optid(optid), name_of_optid(optid));
- exit(1);
- }
- return optarg;
-}
+ const char *head, *tail;
-static char *argvalstr(int optid)
-{
- char *result = strdup(current_argument(optid));
- if (result == NULL) {
- ERROR("can't alloc memory");
- exit(1);
+ if (title)
+ fprintf(file, "%s----BEGIN OF %s-----\n", prefix ?: "", title);
+
+ head = json_object_to_json_string_ext(config, JSON_C_TO_STRING_PRETTY
+ |JSON_C_TO_STRING_SPACED|JSON_C_TO_STRING_NOSLASHESCAPE);
+
+ if (!prefix)
+ fprintf(file, "%s\n", head);
+ else {
+ while(*head) {
+ for (tail = head ; *tail && *tail != '\n' ; tail++);
+ fprintf(file, "%s %.*s\n", prefix, (int)(tail - head), head);
+ head = tail + !!*tail;
+ }
}
- return result;
+
+ if (title)
+ fprintf(file, "%s----END OF %s-----\n", prefix ?: "", title);
}
/**********************************
* arguments helpers
***********************************/
+static int string_to_bool(const char *value)
+{
+ static const char true_names[] = "1\0yes\0true\0on";
+ static const char false_names[] = "0\0no\0false\0off";
+ size_t pos;
+
+ pos = 0;
+ while (pos < sizeof true_names)
+ if (strcasecmp(value, &true_names[pos]))
+ pos += 1 + strlen(&true_names[pos]);
+ else
+ return 1;
+
+ pos = 0;
+ while (pos < sizeof false_names)
+ if (strcasecmp(value, &false_names[pos]))
+ pos += 1 + strlen(&false_names[pos]);
+ else
+ return 0;
+
+ return -1;
+}
+
static void noarg(int optid)
{
if (optarg) {
return optarg;
}
+static int get_arg_bool(int optid)
+{
+ int value = string_to_bool(get_arg(optid));
+ if (value < 0) {
+ ERROR("option [--%s] needs a boolean value: yes/no, true/false, on/off, 1/0",
+ name_of_optid(optid));
+ exit(1);
+ }
+ return value;
+}
+
static void config_del(struct json_object *config, int optid)
{
return json_object_object_del(config, name_of_optid(optid));
{
struct json_object *a;
if (!json_object_object_get_ex(config, name_of_optid(optid), &a)) {
- a = json_object_new_array();
- oomchk(a);
+ a = joomchk(json_object_new_array());
json_object_object_add(config, name_of_optid(optid), a);
}
json_object_array_add(a, val);
config_add_str(config, optid, get_arg(optid));
}
+static void config_mix2_cb(void *closure, struct json_object *obj, const char *name)
+{
+ struct json_object *dest, *base = closure;
+
+ if (!name)
+ name = "";
+
+ if (!json_object_object_get_ex(base, name, &dest)) {
+ dest = joomchk(json_object_new_object());
+ json_object_object_add(base, name, dest);
+ }
+ if (json_object_is_type(obj, json_type_object))
+ wrap_json_object_add(dest, obj);
+ else
+ json_object_object_add(dest, "", json_object_get(obj));
+}
+
+static void config_mix2(struct json_object *config, int optid, struct json_object *val)
+{
+ struct json_object *obj;
+
+ if (!json_object_object_get_ex(config, name_of_optid(optid), &obj)) {
+ obj = joomchk(json_object_new_object());
+ json_object_object_add(config, name_of_optid(optid), obj);
+ }
+ wrap_json_for_all(val, config_mix2_cb, obj);
+}
+
+static void config_mix2_str(struct json_object *config, int optid, const char *val)
+{
+ size_t st1, st2;
+ const char *api, *key;
+ struct json_object *obj, *sub;
+ enum json_tokener_error jerr;
+
+ st1 = strcspn(val, "/:{[\"");
+ st2 = strcspn(&val[st1], ":{[\"");
+ if (val[st1] != '/' || val[st1 + st2] != ':') {
+ obj = json_tokener_parse_verbose(val, &jerr);
+ if (jerr != json_tokener_success)
+ obj = json_object_new_string(val);
+ } else {
+ api = st1 == 0 ? "*" : strndupa(val, st1);
+ val += st1 + 1;
+ key = st2 <= 1 || (st2 == 2 && *val == '*') ? NULL : strndupa(val, st2 - 1);
+ val += st2;
+ sub = json_tokener_parse_verbose(val, &jerr);
+ if (jerr != json_tokener_success)
+ sub = json_object_new_string(val);
+
+ if (key) {
+ obj = json_object_new_object();
+ json_object_object_add(obj, key, sub);
+ sub = obj;
+ }
+ obj = json_object_new_object();
+ json_object_object_add(obj, api, sub);
+ }
+ config_mix2(config, optid, obj);
+ json_object_put(obj);
+}
+
+static void config_mix2_optstr(struct json_object *config, int optid)
+{
+ config_mix2_str(config, optid, get_arg(optid));
+}
+
/*---------------------------------------------------------
| set the log levels
+--------------------------------------------------------- */
-static void set_log(char *args)
+static void set_log(const char *args)
{
- char o = 0, s, *p, *i = args;
+ char o = 0, s, *p, *i = strdupa(args);
int lvl;
for(;;) switch (*i) {
static void parse_arguments_inner(int argc, char **argv, struct json_object *config, struct option *options)
{
struct json_object *conf;
- int optid, cind;
+ int optid, cind, dodump = 0;
for (;;) {
cind = optind;
verbose_inc();
break;
+ case SET_COLOR:
+ verbose_colorize();
+ break;
+
case SET_QUIET:
verbose_dec();
break;
case SET_LOG:
- set_log(argvalstr(optid));
+ set_log(get_arg(optid));
break;
case SET_PORT:
config_add_optstr(config, optid);
break;
+ case ADD_SET:
+ config_mix2_optstr(config, optid);
+ break;
+
#if defined(WITH_MONITORING_OPTION)
case SET_MONITORING:
#endif
config_set_bool(config, SET_DAEMON, optid != SET_FOREGROUND);
break;
+ case SET_TRAP_FAULTS:
+ config_set_bool(config, optid, get_arg_bool(optid));
+ break;
+
+
case SET_TRACEREQ:
config_set_optenum(config, optid, afb_hook_flags_xreq_from_text);
break;
json_object_put(conf);
break;
+ case DUMP_CONFIG:
+ noarg(optid);
+ dodump = 1;
+ break;
+
case GET_VERSION:
noarg(optid);
printVersion(stdout);
}
}
/* TODO: check for extra value */
+
+ if (dodump) {
+ dump(config, stdout, NULL, NULL);
+ exit(0);
+ }
}
static void parse_arguments(int argc, char **argv, struct json_object *config)
#endif
}
-static void dump(struct json_object *config, FILE *file, const char *prefix, const char *title)
-{
- char z;
- const char *head, *tail;
-
- if (!prefix) {
- z = 0;
- prefix = &z;
- }
-
- if (title)
- fprintf(file, "%s----BEGIN OF %s-----\n", prefix, title);
-
- head = json_object_to_json_string_ext(config, JSON_C_TO_STRING_PRETTY
- |JSON_C_TO_STRING_SPACED|JSON_C_TO_STRING_NOSLASHESCAPE);
-
- if (head) {
- while(*head) {
- for (tail = head ; *tail && *tail != '\n' ; tail++);
- fprintf(file, "%s %.*s\n", prefix, (int)(tail - head), head);
- head = tail + !!*tail;
- }
- }
-
- if (title)
- fprintf(file, "%s----END OF %s-----\n", prefix, title);
-}
-
void afb_config_dump(struct json_object *config)
{
dump(config, stderr, "--", "CONFIG");
}
-static void on_environment_add(struct json_object *config, int optid, const char *name)
+static void on_environment(struct json_object *config, int optid, const char *name, void (*func)(struct json_object*, int, const char*))
{
char *value = getenv(name);
if (value && *value)
- config_add_str(config, optid, value);
+ func(config, optid, value);
}
static void on_environment_enum(struct json_object *config, int optid, const char *name, int (*func)(const char*))
}
}
+static void on_environment_bool(struct json_object *config, int optid, const char *name)
+{
+ char *value = getenv(name);
+ int asbool;
+
+ if (value) {
+ asbool = string_to_bool(value);
+ if (asbool < 0)
+ WARNING("Unknown value %s for environment variable %s, ignored", value, name);
+ else
+ config_set_bool(config, optid, asbool);
+ }
+}
+
static void parse_environment(struct json_object *config)
{
on_environment_enum(config, SET_TRACEREQ, "AFB_TRACEREQ", afb_hook_flags_xreq_from_text);
on_environment_enum(config, SET_TRACESES, "AFB_TRACESES", afb_hook_flags_session_from_text);
on_environment_enum(config, SET_TRACEAPI, "AFB_TRACEAPI", afb_hook_flags_api_from_text);
on_environment_enum(config, SET_TRACEGLOB, "AFB_TRACEGLOB", afb_hook_flags_global_from_text);
- on_environment_add(config, ADD_LDPATH, "AFB_LDPATHS");
+ on_environment(config, ADD_LDPATH, "AFB_LDPATHS", config_add_str);
+ on_environment(config, ADD_SET, "AFB_SET", config_mix2_str);
#if !defined(REMOVE_LEGACY_TRACE)
on_environment_enum(config, SET_TRACEDITF, "AFB_TRACEDITF", afb_hook_flags_legacy_ditf_from_text);
on_environment_enum(config, SET_TRACESVC, "AFB_TRACESVC", afb_hook_flags_legacy_svc_from_text);
#endif
+ on_environment_bool(config, SET_TRAP_FAULTS, "AFB_TRAP_FAULTS");
}
struct json_object *afb_config_parse_arguments(int argc, char **argv)