/*
* Copyright (c) 2004-2006 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*/
#include "sm/generic.h"
SM_RCSID("@(#)$Id: t-conf-0.c,v 1.19 2006/12/24 00:20:24 ca Exp $")
#if SM_LIBCONF_ALONE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sm-conf.h"
#else /* SM_LIBCONF_ALONE */
#include "sm/string.h"
#include "sm/net.h"
#include "sm/sm-conf.h"
#include <stdio.h>
#endif /* SM_LIBCONF_ALONE */
/*
** Just a test program to play around with libconf.
** However, this is used in t-conf-0.sh, so don't break it.
*/
#define SM_SSPEC_MAGIC SM_MAGIC('S', 'S', 'P', 'E')
#define SM_SUB_MAGIC SM_MAGIC('S', 'S', 'U', 'B')
#define SM_SS_MAGIC SM_MAGIC('S', 'S', '_', '_')
#define SM_S_MAGIC SM_MAGIC('S', '_', '_', '_')
typedef struct
{
sm_magic_T sm_magic;
int sspec_type;
short sspec_port;
ipv4_T sspec_addr;
char *sspec_host;
} sockspec;
typedef struct
{
sm_magic_T sm_magic;
unsigned int sub_int_u32;
unsigned short sub_limit; /* between 2 and 12 */
unsigned long sub_duration;
sockspec *sub_bind;
unsigned int sub_sockets_n;
} sub;
typedef struct
{
sm_magic_T sm_magic;
unsigned short ss_port;
char *ss_name;
} ss;
typedef struct
{
sm_magic_T sm_magic;
char const *s_socket;
ipv4_T s_ipv4;
uint32_t s_flags;
uint32_t s_int;
sub s_sub;
ss s_ss;
} structure;
sm_conf_definition_T const flag_names[] =
{
{ SM_CONF_DEF_MAGIC, "Flag1", sm_conf_type_choice_value, 0x01 },
{ SM_CONF_DEF_MAGIC, "Flag2", sm_conf_type_choice_value, 0x02 },
/* Sentinel */
{ SM_CONF_DEF_MAGIC, NULL }
};
sm_conf_definition_T const limit_constraints[] =
{
{ SM_CONF_DEF_MAGIC, "", sm_conf_type_u32_minimum, 2 },
{ SM_CONF_DEF_MAGIC, "", sm_conf_type_u32_maximum, 12 },
/* Sentinel */
{ SM_CONF_DEF_MAGIC, NULL }
};
sm_conf_definition_T const duration_suffixes[] =
{
{ SM_CONF_DEF_MAGIC, "s", sm_conf_type_u32_suffix, 1 },
{ SM_CONF_DEF_MAGIC, "m", sm_conf_type_u32_suffix, 60 },
{ SM_CONF_DEF_MAGIC, "h", sm_conf_type_u32_suffix, 60 * 60 },
{ SM_CONF_DEF_MAGIC, "d", sm_conf_type_u32_suffix, 60 * 60 * 24 },
{ SM_CONF_DEF_MAGIC, "w", sm_conf_type_u32_suffix, 60 * 60 * 24 * 7 },
{ SM_CONF_DEF_MAGIC, "y", sm_conf_type_u32_suffix, 60 * 60 * 24 * 365 },
/* Sentinel */
{ SM_CONF_DEF_MAGIC, NULL }
};
#define SM_SOCK_INET 1
#define SM_SOCK_UNIX 2
#define SM_SOCK_INET6 4
sm_conf_definition_T const sock_types[] =
{
{ SM_CONF_DEF_MAGIC, "inet", sm_conf_type_choice_value, SM_SOCK_INET},
{ SM_CONF_DEF_MAGIC, "unix", sm_conf_type_choice_value, SM_SOCK_UNIX},
{ SM_CONF_DEF_MAGIC, "inet6", sm_conf_type_choice_value, SM_SOCK_INET6},
/* Sentinel */
{ SM_CONF_DEF_MAGIC, NULL }
};
static sm_conf_definition_T sock_spec_defs[] =
{
{ SM_CONF_DEF_MAGIC, "type", sm_conf_type_choice,
offsetof(sockspec, sspec_type),
sizeof(int),
"inet", SM_CONF_FLAG_KEEP_DEFAULT, sock_types
},
{ SM_CONF_DEF_MAGIC, "port", sm_conf_type_u32,
offsetof(sockspec, sspec_port),
sizeof(short),
"1234", SM_CONF_FLAG_KEEP_DEFAULT
},
{ SM_CONF_DEF_MAGIC, "address", sm_conf_type_ipv4,
offsetof(sockspec, sspec_addr),
sizeof(ipv4_T),
"127.0.0.1", SM_CONF_FLAG_KEEP_DEFAULT
},
{ SM_CONF_DEF_MAGIC, "host", sm_conf_type_string,
offsetof(sockspec, sspec_host),
0,
NULL, 0
},
/* sentinel */
{ SM_CONF_DEF_MAGIC, NULL }
};
static sm_conf_definition_T
sockets_defs[] =
{
{ SM_CONF_DEF_MAGIC, "listen",
sm_conf_type_section,
offsetof(sub, sub_bind),
sizeof(sockspec),
NULL,
SM_CONF_FLAG_MULTIPLE|SM_CONF_FLAG_KEEP_DEFAULT,
sock_spec_defs
},
/* counter: unsigned int */
{ SM_CONF_DEF_MAGIC, "", sm_conf_type_array_n,
offsetof(sub, sub_sockets_n),
sizeof(unsigned int)
},
/* sentinel */
{ SM_CONF_DEF_MAGIC, NULL }
};
static sm_conf_definition_T subdefinitions[] =
{
{ SM_CONF_DEF_MAGIC, "value",
sm_conf_type_u32,
offsetof(sub, sub_int_u32),
sizeof(unsigned int),
NULL,
0, NULL, NULL, NULL,
"value"
#if SM_LIBCONF_ISSET
, 0
#endif
#if SM_LIBCONF_MAGIC
, SM_SUB_MAGIC
#endif
},
{ SM_CONF_DEF_MAGIC, "limit",
sm_conf_type_u32,
offsetof(sub, sub_limit),
sizeof(unsigned short),
NULL,
0,
limit_constraints
},
/* A number with suffix multipliers. */
{ SM_CONF_DEF_MAGIC, "duration",
sm_conf_type_u32,
offsetof(sub, sub_duration),
sizeof(unsigned long),
"0",
0,
duration_suffixes
},
{ SM_CONF_DEF_MAGIC, "listen",
sm_conf_type_array,
0, /* offset (n/a; see contents) */
10, /* size: maximum number of elements */
NULL,
SM_CONF_FLAG_MULTIPLE|SM_CONF_FLAG_KEEP_DEFAULT,
sockets_defs,
NULL, NULL, "listen socket(s)"
},
#if 0
{ SM_CONF_DEF_MAGIC, "listen",
sm_conf_type_section,
offsetof(sub, sub_bind),
sizeof(sockspec),
NULL,
SM_CONF_FLAG_MULTIPLE|SM_CONF_FLAG_KEEP_DEFAULT,
sock_spec_defs
},
#endif /* 0 */
/* sentinel */
{ SM_CONF_DEF_MAGIC, NULL }
};
static sm_conf_definition_T smtps_defs[] =
{
{ SM_CONF_DEF_MAGIC, "port",
sm_conf_type_u32,
offsetof(ss, ss_port),
sizeof(unsigned short),
"25",
0, NULL, NULL, NULL,
"port"
#if SM_LIBCONF_ISSET
, 0
#endif
#if SM_LIBCONF_MAGIC
, SM_SS_MAGIC
#endif
},
/* sentinel */
{ SM_CONF_DEF_MAGIC, NULL }
};
sm_conf_definition_T definitions[] =
{
{ SM_CONF_DEF_MAGIC, "socket",
sm_conf_type_string,
offsetof(structure, s_socket),
0,
"path/to/socket",
0, NULL, NULL, NULL,
"socket"
#if SM_LIBCONF_ISSET
, 0
#endif
#if SM_LIBCONF_MAGIC
, SM_S_MAGIC
#endif
},
{ SM_CONF_DEF_MAGIC, "nameserver",
sm_conf_type_ipv4,
offsetof(structure, s_ipv4),
sizeof(ipv4_T),
"127.0.0.1",
0, NULL, NULL, NULL,
"nameserver"
#if SM_LIBCONF_ISSET
, 0
#endif
#if SM_LIBCONF_MAGIC
, SM_S_MAGIC
#endif
},
{ SM_CONF_DEF_MAGIC, "flags",
sm_conf_type_choice,
offsetof(structure, s_flags),
sizeof(uint32_t),
NULL,
SM_CONF_FLAG_MULTIPLE,
flag_names,
NULL, NULL,
"flags"
#if SM_LIBCONF_ISSET
, 0
#endif
#if SM_LIBCONF_MAGIC
, SM_S_MAGIC
#endif
},
{ SM_CONF_DEF_MAGIC, "int",
sm_conf_type_u32,
offsetof(structure, s_int),
sizeof(unsigned int),
NULL,
0, NULL, NULL, NULL,
"int"
#if SM_LIBCONF_ISSET
, 0
#endif
#if SM_LIBCONF_MAGIC
, SM_S_MAGIC
#endif
},
{ SM_CONF_DEF_MAGIC, "qmgr",
sm_conf_type_section,
offsetof(structure, s_sub),
sizeof(sub),
NULL, SM_CONF_FLAG_KEEP_DEFAULT, subdefinitions,
NULL, NULL,
"qmgr"
#if SM_LIBCONF_ISSET
, 0
#endif
#if SM_LIBCONF_MAGIC
, SM_S_MAGIC
#endif
},
{ SM_CONF_DEF_MAGIC, "smtps",
sm_conf_type_section,
offsetof(structure, s_ss),
sizeof(ss),
NULL,
SM_CONF_FLAG_MULTIPLE|SM_CONF_FLAG_PARSE_ONLY,
smtps_defs,
NULL, NULL,
"smtp server"
#if SM_LIBCONF_ISSET
, 0
#endif
#if SM_LIBCONF_MAGIC
, SM_S_MAGIC
#endif
},
/* sentinel */
{ SM_CONF_DEF_MAGIC, NULL }
};
static structure st;
static void
print_ipv4(ipv4_T ipv4, const char *name)
{
sm_ret_T ret;
sm_str_P ipv4s;
ipv4s = sm_str_new(NULL, 20, 32);
if (ipv4s == NULL)
{
printf("out of memory\n");
return;
}
ret = sm_inet_ipv4str(ipv4, ipv4s);
if (ret != SM_SUCCESS)
{
printf("sm_inet_ipv4str=0x%x\n", ret);
return;
}
printf("%s= %s\n", name, sm_str_getdata(ipv4s));
}
static void
print_sock_spec(sockspec *ss, char *sockspecname, const char *name, int l)
{
printf("\nsockspec= %s\n", sockspecname);
printf("name= %s\n", name == NULL ? "(none)" : name);
printf("type= %u\n", ss->sspec_type);
if (ss->sspec_type == SM_SOCK_INET)
{
printf("port= %hu\n", ss->sspec_port);
printf("host= \"%s\"\n", (ss->sspec_host == NULL) ? "(NULL)"
: ss->sspec_host);
print_ipv4(ss->sspec_addr, "address");
}
else if (ss->sspec_type == SM_SOCK_UNIX)
{
printf("path= \"%s\"\n", (ss->sspec_host == NULL) ? "(NULL)"
: ss->sspec_host);
}
else
{
printf("type=unknown\n");
}
printf("\n");
}
static void
print_structure(structure *strct)
{
unsigned int u;
char *name;
printf("value= %u\n", strct->s_sub.sub_int_u32);
printf("limit= %hu\n", strct->s_sub.sub_limit);
printf("duration= %lu\n", strct->s_sub.sub_duration);
printf("socket= \"%s\"\n", strct->s_socket);
printf("flags= %X\n", strct->s_flags);
print_ipv4(strct->s_ipv4, "nameserver");
for (u = 0; u < strct->s_sub.sub_sockets_n; u++)
print_sock_spec(&(strct->s_sub.sub_bind[u]), "struct", NULL, 0);
name = strct->s_ss.ss_name;
#if 0
printf("smtps= %s\n", name == NULL ? "(NoName)" : name);
printf("smtps.port= %d\n", strct->s_ss.ss_port);
#endif /* 0 */
}
static int
process(char const *name, FILE *fp, int show, const char *opt, const char *ssname, int flags)
{
sm_conf_T *stream;
int err;
unsigned int v;
char const *service_name;
size_t service_name_n;
sm_conf_iterator_T service_iter;
sockspec sock_spec;
char buf[SM_CONF_ERROR_BUFFER_SIZE];
char const *e = NULL;
if (((stream = sm_conf_new(name ? name : "*stdin*"))) == NULL)
{
fprintf(stderr, "error -- sm_conf_new() returns NULL!\n");
return 1;
}
if ((err = sm_conf_read_FILE(stream, name, fp)) != 0)
{
fprintf(stderr, "%s: %s\n",
name ? name : "*stdin*",
sm_conf_strerror(err, buf, sizeof buf));
while ((e = sm_conf_syntax_error(stream, e)) != NULL)
fprintf(stderr, "%s\n", e);
sm_conf_destroy(stream);
return 2;
}
st.sm_magic = SM_S_MAGIC;
st.s_sub.sm_magic = SM_SUB_MAGIC;
st.s_ss.sm_magic = SM_SS_MAGIC;
st.s_flags = flags;
if ((err = sm_conf_scan(stream, definitions, 0, &st)) != 0)
{
fprintf(stderr, "(while scanning) %s: %s\n",
name ? name : "*stdin*",
sm_conf_strerror(err, buf, sizeof buf));
while ((e = sm_conf_syntax_error(stream, e)) != NULL)
fprintf(stderr, "%s\n", e);
sm_conf_destroy(stream);
return 3;
}
if (show)
print_structure(&st);
if (opt != NULL && *opt != '\0')
{
err = sm_conf_get(stream, opt,
sm_conf_type_u32, NULL,
0,
(void *) &v, sizeof(v));
fprintf(stdout, "opt=%s, conf_get=%d, text=%s\n",
opt != NULL ? opt : "(null)", err,
err == 0 ? "OK" : sm_conf_strerror(err, buf,
sizeof buf));
}
service_iter = NULL;
while ((err = sm_conf_scan_next(stream, "qmgr.listen",
sock_spec_defs, 0,
&service_name, &service_name_n,
&sock_spec, &service_iter)) == 0)
{
print_sock_spec(&sock_spec, "loop"
, service_name, service_name_n);
}
service_iter = NULL;
while ((err = sm_conf_scan_next(stream, "smtps",
smtps_defs, 0,
&service_name, &service_name_n,
&(st.s_ss), &service_iter)) == 0)
{
if (ssname == NULL || (
strlen(ssname) == service_name_n &&
strncmp(ssname, service_name, service_name_n) == 0))
{
const char *n;
#if 0
print_structure(&st);
#endif /* 0 */
n = service_name;
printf("smtps= %s\n", n == NULL ? "(NoName)" : n);
printf("smtps.port= %hu\n", st.s_ss.ss_port);
}
}
if (ssname != NULL)
{
service_iter = NULL;
snprintf(buf, sizeof(buf), "smtps{%s}", ssname);
while ((err = sm_conf_scan_next(stream, buf, smtps_defs, 0,
&service_name, &service_name_n,
&(st.s_ss), &service_iter)) == 0)
{
{
const char *n;
n = service_name;
printf("smtps{%s}= %s\n", ssname,
n == NULL ? "(NoName)" : n);
printf("smtps.port= %hu\n", st.s_ss.ss_port);
}
}
}
#if 0
sm_conf_destroy(stream);
#endif /* 0 */
return 0;
}
int
main(int ac, char **av)
{
int ai, c, ret, done, flags;
char *opt, *ssname;
done = 0;
opt = "qmgr.limit";
ssname = NULL;
flags = 0;
while ((c = getopt(ac, av, "F:f:l:N:o:v:")) != -1)
{
switch (c)
{
case 'F':
flags = strtol(optarg, NULL, 0);
break;
case 'f':
ret = process(optarg, NULL, 0, opt, ssname, flags);
if (ret != 0)
return ret;
done = 1;
break;
case 'l':
st.s_sub.sub_limit = atoi(optarg);
break;
case 'N':
ssname = strdup(optarg);
if (ssname == NULL)
return ENOMEM;
break;
case 'o':
opt = strdup(optarg);
if (opt == NULL)
return ENOMEM;
break;
case 'v':
st.s_sub.sub_int_u32 = atoi(optarg);
break;
}
}
ac -= optind;
av += optind;
if (done)
{
print_structure(&st);
return 0;
}
if (ac == 0)
return process("*stdin*", stdin, 1, opt, ssname, flags);
for (ai = 0; ai < ac; ai++)
{
int ret = process(av[ai], NULL, 1, opt, ssname, flags);
if (ret != 0)
return ret;
}
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1