diff --git a/include/proto/log.h b/include/proto/log.h index c92217c9d..05a7acc55 100644 --- a/include/proto/log.h +++ b/include/proto/log.h @@ -82,6 +82,10 @@ int add_to_logformat_list(char *start, char *end, int type, struct list *list_fo * You can set arguments using { } : %{many arguments}varname */ int parse_logformat_string(const char *str, struct proxy *curproxy, struct list *list_format, int options, int cap, char **err); + +/* Parse "log" keyword and update the linked list. */ +int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err); + /* * Displays the message on stderr with the date and pid. Overrides the quiet * mode during startup. diff --git a/src/cfgparse.c b/src/cfgparse.c index c40e71dc7..6100f86ac 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -1500,130 +1500,12 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) goto out; } } - else if (!strcmp(args[0], "log") && kwm == KWM_NO) { /* no log */ - /* delete previous herited or defined syslog servers */ - struct logsrv *back; - struct logsrv *tmp; - - if (*(args[1]) != 0) { - ha_alert("parsing [%s:%d]:%s : 'no log' does not expect arguments.\n", file, linenum, args[1]); + else if (!strcmp(args[0], "log")) { /* "no log" or "log ..." */ + if (!parse_logsrv(args, &global.logsrvs, (kwm == KWM_NO), &errmsg)) { + ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg); err_code |= ERR_ALERT | ERR_FATAL; goto out; } - - list_for_each_entry_safe(tmp, back, &global.logsrvs, list) { - LIST_DEL(&tmp->list); - free(tmp); - } - } - else if (!strcmp(args[0], "log")) { /* syslog server address */ - struct sockaddr_storage *sk; - int port1, port2; - struct logsrv *logsrv; - int arg = 0; - int len = 0; - - if (alertif_too_many_args(8, file, linenum, args, &err_code)) /* does not strictly check optional arguments */ - goto out; - - if (*(args[1]) == 0 || *(args[2]) == 0) { - ha_alert("parsing [%s:%d] : '%s' expects
and as arguments.\n", file, linenum, args[0]); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - - logsrv = calloc(1, sizeof(*logsrv)); - - /* just after the address, a length may be specified */ - if (strcmp(args[arg+2], "len") == 0) { - len = atoi(args[arg+3]); - if (len < 80 || len > 65535) { - ha_alert("parsing [%s:%d] : invalid log length '%s', must be between 80 and 65535.\n", - file, linenum, args[arg+3]); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - logsrv->maxlen = len; - - /* skip these two args */ - arg += 2; - } - else - logsrv->maxlen = MAX_SYSLOG_LEN; - - if (logsrv->maxlen > global.max_syslog_len) - global.max_syslog_len = logsrv->maxlen; - - /* after the length, a format may be specified */ - if (strcmp(args[arg+2], "format") == 0) { - logsrv->format = get_log_format(args[arg+3]); - if (logsrv->format < 0) { - ha_alert("parsing [%s:%d] : unknown log format '%s'\n", file, linenum, args[arg+3]); - err_code |= ERR_ALERT | ERR_FATAL; - free(logsrv); - goto out; - } - - /* skip these two args */ - arg += 2; - } - - if (alertif_too_many_args_idx(3, arg + 1, file, linenum, args, &err_code)) { - free(logsrv); - goto out; - } - - logsrv->facility = get_log_facility(args[arg+2]); - if (logsrv->facility < 0) { - ha_alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[arg+2]); - err_code |= ERR_ALERT | ERR_FATAL; - logsrv->facility = 0; - } - - logsrv->level = 7; /* max syslog level = debug */ - if (*(args[arg+3])) { - logsrv->level = get_log_level(args[arg+3]); - if (logsrv->level < 0) { - ha_alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[arg+3]); - err_code |= ERR_ALERT | ERR_FATAL; - logsrv->level = 0; - } - } - - logsrv->minlvl = 0; /* limit syslog level to this level (emerg) */ - if (*(args[arg+4])) { - logsrv->minlvl = get_log_level(args[arg+4]); - if (logsrv->minlvl < 0) { - ha_alert("parsing [%s:%d] : unknown optional minimum log level '%s'\n", file, linenum, args[arg+4]); - err_code |= ERR_ALERT | ERR_FATAL; - logsrv->minlvl = 0; - } - } - - sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1); - if (!sk) { - ha_alert("parsing [%s:%d] : '%s': %s\n", file, linenum, args[0], errmsg); - err_code |= ERR_ALERT | ERR_FATAL; - free(logsrv); - goto out; - } - logsrv->addr = *sk; - - if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) { - if (port1 != port2) { - ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n", - file, linenum, args[0], args[1]); - err_code |= ERR_ALERT | ERR_FATAL; - free(logsrv); - goto out; - } - - logsrv->addr = *sk; - if (!port1) - set_host_port(&logsrv->addr, SYSLOG_PORT); - } - - LIST_ADDQ(&global.logsrvs, &logsrv->list); } else if (!strcmp(args[0], "log-send-hostname")) { /* set the hostname in syslog header */ char *name; @@ -6165,133 +6047,9 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) chunk_destroy(&curproxy->log_tag); chunk_initstr(&curproxy->log_tag, strdup(args[1])); } - else if (!strcmp(args[0], "log") && kwm == KWM_NO) { - /* delete previous herited or defined syslog servers */ - struct logsrv *back; - - if (*(args[1]) != 0) { - ha_alert("parsing [%s:%d]:%s : 'no log' does not expect arguments.\n", file, linenum, args[1]); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - - list_for_each_entry_safe(tmplogsrv, back, &curproxy->logsrvs, list) { - LIST_DEL(&tmplogsrv->list); - free(tmplogsrv); - } - } - else if (!strcmp(args[0], "log")) { /* syslog server address */ - struct logsrv *logsrv; - - if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) { - /* copy global.logrsvs linked list to the end of curproxy->logsrvs */ - list_for_each_entry(tmplogsrv, &global.logsrvs, list) { - struct logsrv *node = malloc(sizeof(*node)); - memcpy(node, tmplogsrv, sizeof(struct logsrv)); - LIST_INIT(&node->list); - LIST_ADDQ(&curproxy->logsrvs, &node->list); - } - } - else if (*(args[1]) && *(args[2])) { - struct sockaddr_storage *sk; - int port1, port2; - int arg = 0; - int len = 0; - - logsrv = calloc(1, sizeof(*logsrv)); - - /* just after the address, a length may be specified */ - if (strcmp(args[arg+2], "len") == 0) { - len = atoi(args[arg+3]); - if (len < 80 || len > 65535) { - ha_alert("parsing [%s:%d] : invalid log length '%s', must be between 80 and 65535.\n", - file, linenum, args[arg+3]); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - logsrv->maxlen = len; - - /* skip these two args */ - arg += 2; - } - else - logsrv->maxlen = MAX_SYSLOG_LEN; - - if (logsrv->maxlen > global.max_syslog_len) - global.max_syslog_len = logsrv->maxlen; - - /* after the length, a format may be specified */ - if (strcmp(args[arg+2], "format") == 0) { - logsrv->format = get_log_format(args[arg+3]); - if (logsrv->format < 0) { - ha_alert("parsing [%s:%d] : unknown log format '%s'\n", file, linenum, args[arg+3]); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - - /* skip these two args */ - arg += 2; - } - - if (alertif_too_many_args_idx(3, arg + 1, file, linenum, args, &err_code)) - goto out; - - logsrv->facility = get_log_facility(args[arg+2]); - if (logsrv->facility < 0) { - ha_alert("parsing [%s:%d] : unknown log facility '%s'\n", file, linenum, args[arg+2]); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - - } - - logsrv->level = 7; /* max syslog level = debug */ - if (*(args[arg+3])) { - logsrv->level = get_log_level(args[arg+3]); - if (logsrv->level < 0) { - ha_alert("parsing [%s:%d] : unknown optional log level '%s'\n", file, linenum, args[arg+3]); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - - } - } - - logsrv->minlvl = 0; /* limit syslog level to this level (emerg) */ - if (*(args[arg+4])) { - logsrv->minlvl = get_log_level(args[arg+4]); - if (logsrv->minlvl < 0) { - ha_alert("parsing [%s:%d] : unknown optional minimum log level '%s'\n", file, linenum, args[arg+4]); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - - } - } - - sk = str2sa_range(args[1], NULL, &port1, &port2, &errmsg, NULL, NULL, 1); - if (!sk) { - ha_alert("parsing [%s:%d] : '%s': %s\n", file, linenum, args[0], errmsg); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - - logsrv->addr = *sk; - - if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) { - if (port1 != port2) { - ha_alert("parsing [%s:%d] : '%s' : port ranges and offsets are not allowed in '%s'\n", - file, linenum, args[0], args[1]); - err_code |= ERR_ALERT | ERR_FATAL; - goto out; - } - - if (!port1) - set_host_port(&logsrv->addr, SYSLOG_PORT); - } - - LIST_ADDQ(&curproxy->logsrvs, &logsrv->list); - } - else { - ha_alert("parsing [%s:%d] : 'log' expects either and or 'global' as arguments.\n", - file, linenum); + else if (!strcmp(args[0], "log")) { /* "no log" or "log ..." */ + if (!parse_logsrv(args, &curproxy->logsrvs, (kwm == KWM_NO), &errmsg)) { + ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg); err_code |= ERR_ALERT | ERR_FATAL; goto out; } diff --git a/src/log.c b/src/log.c index e2dde84f0..1be6dccee 100644 --- a/src/log.c +++ b/src/log.c @@ -671,6 +671,166 @@ int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list return 1; } +/* + * Parse "log" keyword and update list accordingly. + * + * When is set, it means the "no log" line was parsed, so all log + * servers in are released. + * + * Otherwise, we try to parse the "log" line. First of all, when the list is not + * the global one, we look for the parameter "global". If we find it, + * global.logsrvs is copied. Else we parse each arguments. + * + * The function returns 1 in success case, otherwise, it returns 0 and err is + * filled. + */ +int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err) +{ + struct sockaddr_storage *sk; + struct logsrv *logsrv = NULL; + int port1, port2; + int cur_arg; + + /* + * "no log": delete previous herited or defined syslog + * servers. + */ + if (do_del) { + struct logsrv *back; + + if (*(args[1]) != 0) { + memprintf(err, "'no log' does not expect arguments"); + goto error; + } + + list_for_each_entry_safe(logsrv, back, logsrvs, list) { + LIST_DEL(&logsrv->list); + free(logsrv); + } + return 1; + } + + /* + * "log global": copy global.logrsvs linked list to the end of logsrvs + * list. But first, we check (logsrvs != global.logsrvs). + */ + if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) { + if (logsrvs == &global.logsrvs) { + memprintf(err, "'global' is not supported for a global syslog server"); + goto error; + } + list_for_each_entry(logsrv, &global.logsrvs, list) { + struct logsrv *node = malloc(sizeof(*node)); + memcpy(node, logsrv, sizeof(struct logsrv)); + LIST_INIT(&node->list); + LIST_ADDQ(logsrvs, &node->list); + } + return 1; + } + + /* + * "log
...: parse a syslog server line + */ + if (*(args[1]) == 0 || *(args[2]) == 0) { + memprintf(err, "expects
and %s as arguments", + ((logsrvs == &global.logsrvs) ? "" : "or global")); + goto error; + } + + logsrv = calloc(1, sizeof(*logsrv)); + if (!logsrv) { + memprintf(err, "out of memory"); + goto error; + } + + /* skip address for now, it will be parsed at the end */ + cur_arg = 2; + + /* just after the address, a length may be specified */ + logsrv->maxlen = MAX_SYSLOG_LEN; + if (strcmp(args[cur_arg], "len") == 0) { + int len = atoi(args[cur_arg+1]); + if (len < 80 || len > 65535) { + memprintf(err, "invalid log length '%s', must be between 80 and 65535", + args[cur_arg+1]); + goto error; + } + logsrv->maxlen = len; + cur_arg += 2; + } + if (logsrv->maxlen > global.max_syslog_len) + global.max_syslog_len = logsrv->maxlen; + + /* after the length, a format may be specified */ + if (strcmp(args[cur_arg], "format") == 0) { + logsrv->format = get_log_format(args[cur_arg+1]); + if (logsrv->format < 0) { + memprintf(err, "unknown log format '%s'", args[cur_arg+1]); + goto error; + } + cur_arg += 2; + } + + /* parse the facility */ + logsrv->facility = get_log_facility(args[cur_arg]); + if (logsrv->facility < 0) { + memprintf(err, "unknown log facility '%s'", args[cur_arg]); + goto error; + } + cur_arg++; + + /* parse the max syslog level (default: debug) */ + logsrv->level = 7; + if (*(args[cur_arg])) { + logsrv->level = get_log_level(args[cur_arg]); + if (logsrv->level < 0) { + memprintf(err, "unknown optional log level '%s'", args[cur_arg]); + goto error; + } + cur_arg++; + } + + /* parse the limit syslog level (default: emerg) */ + logsrv->minlvl = 0; + if (*(args[cur_arg])) { + logsrv->minlvl = get_log_level(args[cur_arg]); + if (logsrv->minlvl < 0) { + memprintf(err, "unknown optional minimum log level '%s'", args[cur_arg]); + goto error; + } + cur_arg++; + } + + /* Too many args */ + if (*(args[cur_arg])) { + memprintf(err, "cannot handle unexpected argument '%s'", args[cur_arg]); + goto error; + } + + /* now, back to the address */ + sk = str2sa_range(args[1], NULL, &port1, &port2, err, NULL, NULL, 1); + if (!sk) + goto error; + logsrv->addr = *sk; + + if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) { + if (port1 != port2) { + memprintf(err, "port ranges and offsets are not allowed in '%s'", args[1]); + goto error; + } + logsrv->addr = *sk; + if (!port1) + set_host_port(&logsrv->addr, SYSLOG_PORT); + } + LIST_ADDQ(logsrvs, &logsrv->list); + return 1; + + error: + free(logsrv); + return 0; +} + + /* Generic function to display messages prefixed by a label */ static void print_message(const char *label, const char *fmt, va_list argp) {