opt_serv.h
#ifndef OPT_SERV_H
#define OPT_SERV_H
#include "opt.h"
#include "conf.h"
#include "evnt.h"
#define OPT_SERV_CONF_BUF_SZ (128 - sizeof(Vstr_node_buf))
#define OPT_SERV_CONF_VSTR_PREALLOC_MAX 8
#define OPT_SERV_CONF_MEM_PREALLOC_MAX (128 * 1024)
#define OPT_SERV_CONF_USE_DAEMON FALSE
#define OPT_SERV_CONF_USE_DROP_PRIVS FALSE
#define OPT_SERV_CONF_USE_PDEATHSIG FALSE
#define OPT_SERV_CONF_DEF_RLIM_AS_CALL FALSE
#define OPT_SERV_CONF_DEF_RLIM_CORE_CALL FALSE
#define OPT_SERV_CONF_DEF_RLIM_FILE_CALL FALSE
#define OPT_SERV_CONF_DEF_TCP_DEFER_ACCEPT 8
#define OPT_SERV_CONF_DEF_PRIV_UID 60001
#define OPT_SERV_CONF_DEF_PRIV_GID 60001
#define OPT_SERV_CONF_DEF_NUM_PROCS 1
#define OPT_SERV_CONF_DEF_IDLE_TIMEOUT (2 * 60)
#define OPT_SERV_CONF_DEF_MAX_TIMEOUT 0
#define OPT_SERV_CONF_USE_INSTA_CLOSE FALSE
#define OPT_SERV_CONF_DEF_Q_LISTEN_LEN 128
#define OPT_SERV_CONF_DEF_MAX_CONNECTIONS 0
#define OPT_SERV_CONF_DEF_RLIM_AS_NUM 0
#define OPT_SERV_CONF_DEF_RLIM_CORE_NUM 0
#define OPT_SERV_CONF_DEF_RLIM_FILE_NUM 0
#define OPT_SERV_CONF_USE_CAP_FOWNER FALSE
#define OPT_SERV_CONF_USE_DUMPABLE FALSE
#define OPT_SERV_CONF_VLG_DATE_FMT_TYPE VLG_DATE_FMT_SYSLOG_TRAD
#define OPT_SERV_CONF_VLG_SYSLOG_NATIVE FALSE
#define OPT_SERV_CONF_VLG_TWEAKED_SIZE FALSE
#define OPT_SERV_CONF_VLG_SIZE_DEF 0
#define OPT_SERV_CONF_VLG_SIZE_UNTWEAKED_CONSOLE 0
#define OPT_SERV_CONF_VLG_SIZE_UNTWEAKED_DAEMON 1024
typedef struct Opt_serv_policy_opts
{
Vstr_ref *ref;
struct Opt_serv_policy_opts *next;
struct Opt_serv_opts *beg;
Vstr_base *policy_name;
struct Evnt_limit io_limit;
Vstr_ref *ref_io_limit;
struct Evnt_limit io_nslimit;
unsigned int idle_timeout;
unsigned int max_timeout;
unsigned int max_connections;
unsigned int use_insta_close : 1;
} Opt_serv_policy_opts;
typedef struct Opt_serv_addr_opts
{
struct Opt_serv_addr_opts *next;
Vstr_base *acpt_filter_file;
Vstr_base *acpt_address;
Vstr_base *acpt_cong;
Vstr_base *def_policy;
unsigned short tcp_port;
unsigned int defer_accept;
unsigned int q_listen_len;
unsigned int max_connections;
} Opt_serv_addr_opts;
typedef struct Opt_serv_opts
{
Opt_serv_policy_opts *def_policy;
Opt_serv_policy_opts *(*make_policy)(struct Opt_serv_opts *);
int (*copy_policy)(struct Opt_serv_policy_opts *,
const struct Opt_serv_policy_opts *);
const char *vers_cstr;
const size_t vers_len;
const char *name_cstr;
size_t name_len;
unsigned int become_daemon : 1;
unsigned int drop_privs : 1;
unsigned int use_pdeathsig : 1;
unsigned int no_conf_listen : 1;
unsigned int rlim_as_call : 1;
unsigned int rlim_core_call : 1;
unsigned int rlim_file_call : 1;
unsigned int keep_cap_fowner : 1;
unsigned int make_dumpable : 1;
unsigned int vlg_date_fmt_type : 2;
unsigned int vlg_syslog_native : 1;
unsigned int vlg_tweaked_size : 1;
size_t vlg_size;
Vstr_base *pid_file;
Vstr_base *cntl_file;
Vstr_base *chroot_dir;
Vstr_base *vpriv_uid;
uid_t priv_uid;
Vstr_base *vpriv_gid;
gid_t priv_gid;
unsigned int num_procs;
unsigned int syslog_facility;
unsigned int rlim_as_num;
unsigned int rlim_core_num;
unsigned int rlim_file_num;
struct Evnt_limit io_limit;
Vstr_ref *ref_io_limit;
struct Evnt_limit io_nslimit;
unsigned int max_spare_bases;
unsigned int max_spare_buf_nodes;
unsigned int max_spare_ptr_nodes;
unsigned int max_spare_ref_nodes;
Opt_serv_addr_opts *addr_beg;
} Opt_serv_opts;
#define OPT_SERV_CONF_INIT_OPTS(x, y) \
NULL, \
opt_policy_make, \
opt_policy_copy, \
x, \
sizeof(x) - 1, \
y, \
sizeof(y) - 1, \
OPT_SERV_CONF_USE_DAEMON, \
OPT_SERV_CONF_USE_DROP_PRIVS, \
OPT_SERV_CONF_USE_PDEATHSIG, \
FALSE, \
OPT_SERV_CONF_DEF_RLIM_AS_CALL, \
OPT_SERV_CONF_DEF_RLIM_CORE_CALL, \
OPT_SERV_CONF_DEF_RLIM_FILE_CALL, \
OPT_SERV_CONF_USE_CAP_FOWNER, \
OPT_SERV_CONF_USE_DUMPABLE, \
OPT_SERV_CONF_VLG_DATE_FMT_TYPE, \
OPT_SERV_CONF_VLG_SYSLOG_NATIVE, \
OPT_SERV_CONF_VLG_TWEAKED_SIZE, \
OPT_SERV_CONF_VLG_SIZE_DEF, \
NULL, NULL, NULL, \
NULL, OPT_SERV_CONF_DEF_PRIV_UID, \
NULL, OPT_SERV_CONF_DEF_PRIV_GID, \
OPT_SERV_CONF_DEF_NUM_PROCS, \
LOG_DAEMON, \
OPT_SERV_CONF_DEF_RLIM_AS_NUM, \
OPT_SERV_CONF_DEF_RLIM_CORE_NUM, \
OPT_SERV_CONF_DEF_RLIM_FILE_NUM, \
{0, 0, {0,0}, 0, 0, {0,0}}, NULL, \
{0, 0, {0,0}, 0, 0, {0,0}}, \
OPT_SERV_CONF_VSTR_PREALLOC_MAX, \
(OPT_SERV_CONF_MEM_PREALLOC_MAX / OPT_SERV_CONF_BUF_SZ), \
(OPT_SERV_CONF_MEM_PREALLOC_MAX / OPT_SERV_CONF_BUF_SZ), \
(OPT_SERV_CONF_MEM_PREALLOC_MAX / OPT_SERV_CONF_BUF_SZ), \
NULL
#define OPT_SERV_CONF_DECL_OPTS(N, x, y) \
Opt_serv_opts N[1] = {{OPT_SERV_CONF_INIT_OPTS(x, y)}}
extern void opt_serv_conf_free_beg(Opt_serv_opts *);
extern void opt_serv_conf_free_end(Opt_serv_opts *);
extern int opt_serv_conf_init(Opt_serv_opts *);
extern int opt_serv_conf(Opt_serv_opts *, Conf_parse *, Conf_token *)
COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET();
extern int opt_serv_conf_parse_cstr(Vstr_base *, Opt_serv_opts *, const char *)
COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET();
extern int opt_serv_conf_parse_file(Vstr_base *, Opt_serv_opts *, const char *)
COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET();
extern void opt_serv_logger(Vlg *)
COMPILE_ATTR_NONNULL_A();
extern int opt_serv_sc_tst(Conf_parse *, Conf_token *, int *, int,
int (*tst_func)(Conf_parse *, Conf_token *,
int *, int, void *), void *)
COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET();
extern int opt_serv_match_init(struct Opt_serv_opts *,
Conf_parse *, Conf_token *)
COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET();
extern void opt_serv_sc_drop_privs(Opt_serv_opts *)
COMPILE_ATTR_NONNULL_A();
extern void opt_serv_sc_rlim_as_num(unsigned int);
extern void opt_serv_sc_rlim_core_num(unsigned int);
extern void opt_serv_sc_rlim_file_num(unsigned int);
extern int opt_serv_sc_acpt_end(const Opt_serv_policy_opts *,
struct Evnt *, struct Evnt *)
COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET();
extern void opt_serv_sc_free_beg(struct Evnt *, const char *)
COMPILE_ATTR_NONNULL_A();
extern void opt_serv_sc_signals(void);
extern void opt_serv_sc_check_children(void);
extern void opt_serv_sc_cntl_resources(const Opt_serv_opts *)
COMPILE_ATTR_NONNULL_A();
extern int opt_serv_sc_append_hostname(Vstr_base *, size_t)
COMPILE_ATTR_NONNULL_A();
extern int opt_serv_sc_append_cwd(Vstr_base *, size_t)
COMPILE_ATTR_NONNULL_A();
extern int opt_serv_build_single_str(struct Opt_serv_opts *,
const Conf_parse *, Conf_token *, int, int)
COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET();
extern int opt_serv_sc_make_str(struct Opt_serv_opts *,
Conf_parse *, Conf_token *,
Vstr_base *, size_t, size_t)
COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET();
extern int opt_serv_sc_make_static_path(struct Opt_serv_opts *,
Conf_parse *, Conf_token *,
Vstr_base *)
COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET();
extern int opt_serv_sc_make_uint(Conf_parse *, Conf_token *, unsigned int *)
COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET();
extern int opt_serv_sc_make_ulong(Conf_parse *, Conf_token *, unsigned long *)
COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET();
extern int opt_serv_sc_make_uintmax(Conf_parse *, Conf_token *, uintmax_t *)
COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET();
#ifndef CONF_FULL_STATIC
extern void opt_serv_sc_resolve_uid(struct Opt_serv_opts *, const char *,
void (*)(const char *, int, const char *))
COMPILE_ATTR_NONNULL_A();
extern void opt_serv_sc_resolve_gid(struct Opt_serv_opts *, const char *,
void (*)(const char *, int, const char *))
COMPILE_ATTR_NONNULL_A();
#endif
extern int opt_serv_sc_config_dir(Vstr_base *, void *, const char *,
int (*)(Vstr_base *, void *, const char *))
COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET();
#define OPT_SERV_DECL_GETOPTS() \
{"help", no_argument, NULL, 'h'}, \
{"daemon", optional_argument, NULL, 1}, \
{"chroot", required_argument, NULL, 2}, \
{"drop-privs", optional_argument, NULL, 3}, \
{"priv-uid", required_argument, NULL, 4}, \
{"priv-gid", required_argument, NULL, 5}, \
{"pid-file", required_argument, NULL, 6}, \
{"cntl-file", required_argument, NULL, 7}, \
{"acpt-filter-file", required_argument, NULL, 8}, \
{"accept-filter-file", required_argument, NULL, 8}, \
{"processes", required_argument, NULL, 9}, \
{"procs", required_argument, NULL, 9}, \
{"debug", no_argument, NULL, 'd'}, \
{"host", required_argument, NULL, 'H'}, \
{"port", required_argument, NULL, 'P'}, \
{"nagle", optional_argument, NULL, 'n'}, \
{"max-connections", required_argument, NULL, 'M'}, \
{"idle-timeout", required_argument, NULL, 't'}, \
{"defer-accept", required_argument, NULL, 10}, \
{"io-r-limit-process", required_argument, NULL, 11}, \
{"io-w-limit-process", required_argument, NULL, 12}, \
{"io-r-limit-connection", required_argument, NULL, 13}, \
{"io-w-limit-connection", required_argument, NULL, 14}, \
{"version", no_argument, NULL, 'V'}
#define OPT_SERV_GETOPTS(opts) \
case 't': opts->def_policy->idle_timeout = atoi(optarg); break; \
case 'H': OPT_VSTR_ARG(opts->addr_beg->acpt_address); break; \
case 'M': OPT_NUM_NR_ARG(opts->addr_beg->max_connections, \
"max connections"); \
opts->def_policy->max_connections = opts->addr_beg->max_connections; \
break; \
case 'P': OPT_NUM_ARG(opts->addr_beg->tcp_port, "tcp port", \
0, 65535, ""); \
opts->no_conf_listen = FALSE; break; \
case 'd': vlg_debug(vlg); break; \
\
case 'n': OPT_TOGGLE_ARG(evnt_opt_nagle); break; \
\
case 1: OPT_TOGGLE_ARG(opts->become_daemon); break; \
case 2: OPT_VSTR_ARG(opts->chroot_dir); break; \
case 3: OPT_TOGGLE_ARG(opts->drop_privs); break; \
case 4: OPT_VSTR_ARG(opts->vpriv_uid); break; \
case 5: OPT_VSTR_ARG(opts->vpriv_gid); break; \
case 6: OPT_VSTR_ARG(opts->pid_file); break; \
case 7: OPT_VSTR_ARG(opts->cntl_file); break; \
case 8: OPT_VSTR_ARG(opts->addr_beg->acpt_filter_file); break; \
case 9: OPT_NUM_ARG(opts->num_procs, "number of processes", \
1, 255, ""); break; \
case 10: OPT_NUM_ARG(opts->addr_beg->defer_accept, \
"seconds to defer connections", \
0, 4906, " (1 hour 8 minutes)"); break; \
case 11: OPT_NUM_NR_ARG(opts->io_limit.io_w_max, \
"process read limit"); break; \
case 12: OPT_NUM_NR_ARG(opts->io_limit.io_w_max, \
"process write limit"); break; \
case 13: OPT_NUM_NR_ARG(opts->io_nslimit.io_w_max, \
"connection read limit"); break; \
case 14: OPT_NUM_NR_ARG(opts->io_nslimit.io_w_max, \
"connection write limit"); break
#define OPT_SERV_SYM_EQ(x) \
conf_token_cmp_sym_cstr_eq(conf, token, x)
#define OPT_SERV_X_TOGGLE(x) do { \
int opt__val = (x); \
\
if (conf_sc_token_parse_toggle(conf, token, &opt__val)) \
return (FALSE); \
(x) = opt__val; \
} while (FALSE)
#define OPT_SERV_X_NEG_TOGGLE(x) do { \
int opt__val = !(x); \
\
if (conf_sc_token_parse_toggle(conf, token, &opt__val)) \
return (FALSE); \
(x) = !opt__val; \
} while (FALSE)
#define OPT_SERV_X_SINGLE_UINT(x) do { \
unsigned int opt__val = 0; \
\
if (conf_sc_token_parse_uint(conf, token, &opt__val)) \
return (FALSE); \
(x) = opt__val; \
} while (FALSE)
#define OPT_SERV_X_UINT(x) do { \
unsigned int opt__val = 0; \
\
if (!opt_serv_sc_make_uint(conf, token, &opt__val)) \
return (FALSE); \
(x) = opt__val; \
} while (FALSE)
#define OPT_SERV_X_SINGLE_ULONG(x) do { \
unsigned long opt__val = 0; \
\
if (conf_sc_token_parse_uint(conf, token, &opt__val)) \
return (FALSE); \
(x) = opt__val; \
} while (FALSE)
#define OPT_SERV_X_ULONG(x) do { \
unsigned long opt__val = 0; \
\
if (!opt_serv_sc_make_ulong(conf, token, &opt__val)) \
return (FALSE); \
(x) = opt__val; \
} while (FALSE)
#define OPT_SERV_X_SINGLE_UINTMAX(x) do { \
uintmax_t opt__val = 0; \
\
if (conf_sc_token_parse_uintmax(conf, token, &opt__val)) \
return (FALSE); \
(x) = opt__val; \
} while (FALSE)
#define OPT_SERV_X_UINTMAX(x) do { \
uintmax_t opt__val = 0; \
\
if (!opt_serv_sc_make_uintmax(conf, token, &opt__val)) \
return (FALSE); \
(x) = opt__val; \
} while (FALSE)
#define OPT_SERV_X_SYM__NUM_BEG(x) \
if (!ern) \
(x) = val; \
else \
{ \
const Vstr_sect_node *pv = NULL; \
int clist_num = FALSE; \
\
if ((ern == CONF_SC_TYPE_RET_ERR_PARSE) && \
!(pv = conf_token_value(token))) \
CONF_SC_TOGGLE_CLIST_VAR(clist_num); \
if (ern && !(pv = conf_token_value(token))) \
return (FALSE); \
\
if (0) do { } while (FALSE)
#define OPT_SERV_X_SYM_SINGLE_UINT_BEG(x) do { \
unsigned int val = 0; \
int ern = 0; \
\
ern = conf_sc_token_parse_uint(conf, token, &val); \
OPT_SERV_X_SYM__NUM_BEG(x)
#define OPT_SERV_X_SYM_UINT_BEG(x) do { \
unsigned int val = (x); \
int ern = CONF_SC_TYPE_RET_OK; \
Conf_token save; \
\
save = *token; \
if (!opt_serv_sc_make_uint(conf, token, &val)) \
{ \
ern = CONF_SC_TYPE_RET_ERR_PARSE; \
*token = save; \
conf_parse_token(conf, token); \
} \
OPT_SERV_X_SYM__NUM_BEG(x)
#define OPT_SERV_X_SYM_SINGLE_ULONG_BEG(x) do { \
unsigned long val = 0; \
int ern = 0; \
\
ern = conf_sc_token_parse_ulong(conf, token, &val); \
OPT_SERV_X_SYM__NUM_BEG(x)
#define OPT_SERV_X_SYM_ULONG_BEG(x) do { \
unsigned long val = (x); \
int ern = CONF_SC_TYPE_RET_OK; \
Conf_token save; \
\
save = *token; \
if (!opt_serv_sc_make_ulong(conf, token, &val)) \
{ \
ern = CONF_SC_TYPE_RET_ERR_PARSE; \
*token = save; \
conf_parse_token(conf, token); \
} \
OPT_SERV_X_SYM__NUM_BEG(x)
#define OPT_SERV_X_SYM_SINGLE_UINTMAX_BEG(x) do { \
uintmax_t val = 0; \
int ern = 0; \
\
ern = conf_sc_token_parse_uintmax(conf, token, &val); \
OPT_SERV_X_SYM__NUM_BEG(x)
#define OPT_SERV_X_SYM_UINTMAX_BEG(x) do { \
uintmax_t val = (x); \
int ern = CONF_SC_TYPE_RET_OK; \
Conf_token save; \
\
save = *token; \
if (!opt_serv_sc_make_uintmax(conf, token, &val)) \
{ \
ern = CONF_SC_TYPE_RET_ERR_PARSE; \
*token = save; \
conf_parse_token(conf, token); \
} \
OPT_SERV_X_SYM__NUM_BEG(x)
#define OPT_SERV_X_SYM_NUM_END() \
else return (FALSE); \
} \
} while (FALSE)
#define OPT_SERV_X__ESC_VSTR(x, p, l) do { \
if ((token->type == CONF_TOKEN_TYPE_QUOTE_ESC_D) || \
(token->type == CONF_TOKEN_TYPE_QUOTE_ESC_DDD) || \
(token->type == CONF_TOKEN_TYPE_QUOTE_ESC_S) || \
(token->type == CONF_TOKEN_TYPE_QUOTE_ESC_SSS) || \
FALSE) \
if (!conf_sc_conv_unesc((x), p, l, NULL)) \
return (FALSE); \
} while (FALSE)
#define OPT_SERV_X__SINGLE_VSTR(x, p, l) do { \
if (conf_sc_token_sub_vstr(conf, token, x, p, l)) \
return (FALSE); \
\
if ((x)->conf->malloc_bad) \
return (FALSE); \
OPT_SERV_X__ESC_VSTR(x, p, token->u.node->len); \
} while (FALSE)
#define OPT_SERV_X_SINGLE_VSTR(x) OPT_SERV_X__SINGLE_VSTR(x, 1, (x)->len)
#define OPT_SERV_X__VSTR(o, x, p, l) do { \
if (!opt_serv_sc_make_str(o, conf, token, x, p, l)) \
return (FALSE); \
} while (FALSE)
#define OPT_SERV_X_VSTR(o, x) OPT_SERV_X__VSTR(o, x, 1, (x)->len)
#define OPT_SERV_X_EQ(x) do { \
if (conf_sc_token_parse_eq(conf, token, (x), 1, (x)->len, matches)) \
return (FALSE); \
} while (FALSE)
#define OPT_SERV_X_CSTR_EQ(x) do { \
if (conf_sc_token_parse_cstr_eq(conf, token, (x), matches)) \
return (FALSE); \
} while (FALSE)
#define OPT_SERV_SC_MATCH_INIT(x, y) do { \
unsigned int match_init__depth = token->depth_num; \
\
if (!opt_serv_match_init(x, conf, token)) \
return (FALSE); \
\
while (conf_token_list_num(token, match_init__depth)) \
{ \
CONF_SC_PARSE_DEPTH_TOKEN_RET(conf, token, match_init__depth, FALSE); \
CONF_SC_TOGGLE_CLIST_VAR(clist); \
if (y) continue; \
\
return (FALSE); \
} \
} while (FALSE)
#ifndef CONF_FULL_STATIC
# define OPT_SERV_SC_RESOLVE_UID(opts) \
opt_serv_sc_resolve_uid(opts, program_name, usage)
# define OPT_SERV_SC_RESOLVE_GID(opts) \
opt_serv_sc_resolve_gid(opts, program_name, usage)
#else
# define OPT_SERV_SC_RESOLVE_UID(opts)
# define OPT_SERV_SC_RESOLVE_GID(opts)
#endif
#endif