/*----- doubly linked lists -----*/
-#define ISNODE(T) struct { T *succ, *pred; } node /* must be at start */
-#define DEFLIST(T) typedef struct { T *hd, *tl, *tp; int count; } T##List
+#define ISNODE(T) struct node list_node
+#define DEFLIST(T) \
+ typedef struct { \
+ union { struct list li; T *for_type; } u; \
+ int count; \
+ } T##List
-#define NODE(n) (assert((void*)&(n)->node == &(n)), \
- (struct node*)&(n)->node)
+#define NODE(n) (assert((void*)&(n)->list_node == &(n)), &(n)->list_node)
#define LIST_CHECKCANHAVENODE(l,n) \
- ((void)((n) == ((l).hd))) /* just for the type check */
+ ((void)((n) == ((l).u.for_type))) /* just for the type check */
-#define LIST_ADDSOMEHOW(l,n,list_addsomehow) \
- ( LIST_CHECKCANHAVENODE(l,n), \
- list_addsomehow((struct list*)&(l), NODE((n))), \
- (void)(l).count++ \
+#define LIST_ADDSOMEHOW(l,n,list_addsomehow) \
+ ( LIST_CHECKCANHAVENODE(l,n), \
+ list_addsomehow(&(l).u.li, NODE((n))), \
+ (void)(l).count++ \
)
#define LIST_REMSOMEHOW(l,list_remsomehow) \
- ( (typeof((l).hd)) \
+ ( (typeof((l).u.for_type)) \
( (l).count \
? ( (l).count--, \
- list_remsomehow((struct list*)&(l)) ) \
+ list_remsomehow(&(l).u.li) ) \
: 0 \
) \
)
#define LIST_REMHEAD(l) LIST_REMSOMEHOW((l),list_remhead)
#define LIST_REMTAIL(l) LIST_REMSOMEHOW((l),list_remtail)
-#define LIST_INIT(l) ((l).hd, list_new((struct list*)&(l)))
-#define LIST_HEAD(l) ((typeof((l).hd))(list_head((struct list*)&(l))))
+#define LIST_INIT(l) (list_new(&(l).u.li))
+#define LIST_HEAD(l) ((typeof((l).u.for_type))(list_head((struct list*)&(l))))
#define LIST_NEXT(n) ((typeof(n))list_succ(NODE((n))))
#define LIST_BACK(n) ((typeof(n))list_pred(NODE((n))))
if (WIFEXITED(status)) {
int es= WEXITSTATUS(status);
if (es)
- warn("%s: child died with error exit status %d",es);
+ warn("%s: child died with error exit status %d", what, es);
} else if (WIFSIGNALED(status)) {
int sig= WTERMSIG(status);
const char *sigstr= strsignal(sig);
warn("%s: child died due to unknown fatal signal %d%s",
what, sig, coredump);
} else {
- warn("%s: child died with unknown wait status %d", status);
+ warn("%s: child died with unknown wait status %d", what,status);
}
}
/*========== option parsing ==========*/
-/*---------- generic option parser and logging ----------*/
-
static void vbadusage(const char *fmt, va_list al) NORET_PRINTF(1,0);
static void vbadusage(const char *fmt, va_list al) {
- abort();
+ char *m= xvasprintf(fmt,al);
+ fprintf(stderr, "bad usage: %s\n%s"
+ "say --help for help, or read the manpage\n",
+ m);
+ if (become_daemon)
+ syslog(LOG_CRIT,"innduct: invoked with bad usage: %s",m);
+ exit(8);
}
+
+/*---------- generic option parser ----------*/
+
static void badusage(const char *fmt, ...) NORET_PRINTF(1,2);
static void badusage(const char *fmt, ...) {
va_list al;
struct Option {
int shrt;
- const char *lng;
+ const char *lng, *formarg;
void *store;
OptionParser *fn;
- int noarg, intval;
+ int intval;
};
+static void parse_options(const Option *options, char ***argvp) {
+ /* on return *argvp is first non-option arg; argc is not updated */
+
+ for (;;) {
+ const char *arg= *++(*argvp);
+ if (!arg) break;
+ if (*arg != '-') break;
+ if (!strcmp(arg,"--")) { arg= *++(*argvp); break; }
+ int a;
+ while ((a= *++arg)) {
+ const Option *o;
+ if (a=='-') {
+ arg++;
+ char *equals= strchr(arg,'=');
+ int len= equals ? (equals - arg) : strlen(arg);
+ for (o=options; o->shrt || o->lng; o++)
+ if (strlen(o->lng) == len && !memcmp(o->lng,arg,len))
+ goto found_long;
+ badusage("unknown long option --%s",arg);
+ found_long:
+ if (!o->formarg) {
+ if (equals) badusage("option --%s does not take a value",o->lng);
+ arg= 0;
+ } else if (equals) {
+ arg= equals+1;
+ } else {
+ arg= *++(*argvp);
+ if (!arg) badusage("option --%s needs a value for %s",
+ o->lng, o->formarg);
+ }
+ o->fn(o, arg);
+ break; /* eaten the whole argument now */
+ }
+ for (o=options; o->shrt || o->lng; o++)
+ if (a == o->shrt)
+ goto found_short;
+ badusage("unknown short option -%c",a);
+ found_short:
+ if (!o->formarg) {
+ o->fn(o,0);
+ } else {
+ if (!*++arg) {
+ arg= *++(*argvp);
+ if (!arg) badusage("option -%c needs a value for %s",
+ o->shrt, o->formarg);
+ }
+ o->fn(o,arg);
+ break; /* eaten the whole argument now */
+ }
+ }
+ }
+}
+
+#define DELIMPERHAPS(delim,str) (str) ? (delim) : "", (str) ? (str) : ""
+
+static void print_options(const Option *options, FILE *f) {
+ const Option *o;
+ for (o=options; o->shrt || o->lng; o++) {
+ char shrt[2] = { o->shrt, 0 };
+ char *optspec= xasprintf("%s%s%s%s%s",
+ o->shrt ? "-" : "", o->shrt,
+ o->shrt && o->lng ? "|" : "",
+ DELIMPERHAPS("--", o->lng));
+ fprintf(f, " %s%s%s\n", optspec, DELIMPERHAPS(" ", o->formarg));
+ free(optspec);
+ }
+}
+
/*---------- specific option types ----------*/
static void op_integer(const Option *o, const char *val) {
/*---------- specific options ----------*/
-static const Option options[]= {
-{'f',"feedfile", &feedfile, op_string },
-{'q',"quiet-multiple", &quiet_multiple, op_setint, 1,1 },
+static void help(const Option *o, const char *val);
+
+static const Option innduct_options[]= {
+{'f',"feedfile", "F", &feedfile, op_string },
+{'q',"quiet-multiple", 0, &quiet_multiple, op_setint, 1 },
+{0,"help", 0, help },
-{ 0, "max-connections", &max_connections, op_integer },
-{ 0, "max-queue-per-conn", &max_queue_per_conn, op_integer },
+{0,"max-connections", "N", &max_connections, op_integer },
+{0,"max-queue-per-conn", "N", &max_queue_per_conn, op_integer },
-{ 0, "streaming", &try_stream, op_setint, 1,1 },
-{ 0, "no-streaming", &try_stream, op_setint, 1,0 },
-{'P',"port", &port, op_integer },
-{ 0, "inndconf", &inndconffile, op_string },
-{'d',"daemon", &become_daemon, op_setint, 1,1 },
-{ 0, "no-daemon", &become_daemon, op_setint, 1,0 },
+{0,"streaming", 0, &try_stream, op_setint, 1 },
+{0,"no-streaming", 0, &try_stream, op_setint, 0 },
+{'P',"port", "PORT",&port, op_integer },
+{0,"inndconf", "F", &inndconffile, op_string },
+{0,"no-daemon", 0, &become_daemon, op_setint, 0 },
-{ 0, "no-check-proportion", &nocheck_thresh_pct, op_double },
-{ 0, "no-check-filter", &nocheck_decay_articles, op_double },
+{0,"no-check-proportion","PERCENT", &nocheck_thresh_pct, op_double },
+{0,"no-check-filter", "ARTICLES", &nocheck_decay_articles, op_double },
-{ 0, "reconnect-interval", &reconnect_delay_periods, op_periods_rndup },
-{ 0, "flush-retry-interval", &flushfail_retry_periods, op_periods_rndup },
-{ 0, "inndcomm-timeout", &inndcomm_flush_timeout, op_seconds },
+{0,"reconnect-interval", "TIME", &reconnect_delay_periods, op_periods_rndup },
+{0,"flush-retry-interval","TIME", &flushfail_retry_periods, op_periods_rndup },
+{0,"inndcomm-timeout", "TIME", &inndcomm_flush_timeout, op_seconds },
+{0,0}
};
-int main(int argc, char **argv) {
- const char *arg;
+static void printusage(FILE *f) {
+ fputs("usage: innduct [options] site [fqdn]\n"
+ "available options are:\n", f);
+ print_options(innduct_options, f);
+}
- for (;;) {
- arg= *++argv;
- if (!arg) break;
- if (*arg != '-') break;
- if (!strcmp(arg,"--")) { arg= *++argv; break; }
- int a;
- while ((a= *++arg)) {
- const Option *o;
- if (a=='-') {
- arg++;
- char *equals= strchr(arg,'=');
- int len= equals ? (equals - arg) : strlen(arg);
- for (o=options; o->lng; o++)
- if (strlen(o->lng) == len && !memcmp(o->lng,arg,len))
- goto found_long;
- badusage("unknown long option --%s",arg);
- found_long:
- if (o->noarg) {
- if (equals) badusage("option --%s does not take a value",o->lng);
- arg= 0;
- } else if (equals) {
- arg= equals+1;
- } else {
- arg= *++argv;
- if (!arg) badusage("option --%s needs a value",o->lng);
- }
- o->fn(o, arg);
- break; /* eaten the whole argument now */
- }
- for (o=options; o->lng; o++)
- if (a == o->shrt)
- goto found_short;
- badusage("unknown short option -%c",a);
- found_short:
- if (o->noarg) {
- o->fn(o,0);
- } else {
- if (!*++arg) {
- arg= *++argv;
- if (!arg) badusage("option -%c needs a value",o->shrt);
- }
- o->fn(o,arg);
- break; /* eaten the whole argument now */
- }
- }
+static void help(const Option *o, const char *val) {
+ printusage(stdout);
+ if (ferror(stdout) || fflush(stdout)) {
+ perror("innduct: writing help");
+ exit(12);
}
+ exit(0);
+}
- if (!arg) badusage("need site name argument");
- sitename= arg;
+int main(int argc, char **argv) {
+ if (!argv[1]) {
+ printusage(stderr);
+ exit(12);
+ }
- if ((arg= *++argv))
- remote_host= arg;
+ parse_options(innduct_options, &argv);
- if (*++argv) badusage("too many non-option arguments");
+ /* arguments */
+
+ sitename= *argv++;
+ if (!sitename) badusage("need site name argument");
+ remote_host= *argv++;
+ if (*argv) badusage("too many non-option arguments");
+
+ /* defaults */
+
+ if (!remote_host) remote_host= sitename;
if (nocheck_thresh_pct < 0 || nocheck_thresh_pct > 100)
badusage("nocheck threshold percentage must be between 0..100");
if (strchr(feedfile, c))
badusage("feed filename may not contain metacharacter %c",c);
+ /* set things up */
+
oop_source_sys *sysloop= oop_sys_new();
if (!sysloop) sysdie("could not create liboop event loop");
loop= (oop_source*)sysloop;
statemc_init();
+ /* let's go */
+
void *r= oop_sys_run(sysloop);
assert(r == OOP_ERROR);
sysdie("event loop failed");