/* Config parse function.  Implements the original form of the 'interfaces' config option.  Parses a
 * comma-separated list of interface rules (see cf_opt_network_interface_legacy() for the format of
 * each rule), then parses the regular config array-of-struct style interface option settings so
 * that both forms are supported.
 *
 * @author Andrew Bettison <*****@*****.**>
 */
int cf_opt_interface_list(struct config_interface_list *listp, const struct cf_om_node *node)
{
  if (!node->text)
    return cf_opt_config_interface_list(listp, node);
  if (node->nodc) {
    cf_warn_incompatible_children(node);
    return CFINCOMPATIBLE;
  }
  const char *p;
  const char *arg = NULL;
  unsigned n = listp->ac;
  int result = CFOK;
  for (p = node->text; n < NELS(listp->av); ++p) {
    if (*p == '\0' || *p == ',' || isspace(*p)) {
      if (arg) {
	int len = p - arg;
	if (len > 80) {
	  result |= CFSTRINGOVERFLOW;
	  goto bye;
	}
	char buf[len + 1];
	strncpy(buf, arg, len)[len] = '\0';
	int ret = cf_opt_network_interface_legacy(&listp->av[n].value, buf);
	switch (ret) {
	case CFERROR: return CFERROR;
	case CFOK:
	  listp->av[n].key = n;
	  ++n;
	  break;
	default: {
	    strbuf b = strbuf_alloca(180);
	    strbuf_cf_flag_reason(b, ret);
	    cf_warn_node(node, NULL, "invalid interface rule %s -- %s", alloca_str_toprint(buf), strbuf_str(b)); \
	    result |= CFSUB(ret);
	    break;
	  }
	}
	arg = NULL;
      }
      if (!*p)
	break;
    } else if (!arg)
      arg = p;
  }
  if (*p) {
    result |= CFARRAYOVERFLOW;
    goto bye;
  }
  assert(n <= NELS(listp->av));
  listp->ac = n;
bye:
  if (listp->ac == 0)
    result |= CFEMPTY;
  return result;
}
Esempio n. 2
0
char const *
hxmode(int mode)
{
    static char const *modev[] = {
        "READ",
        "UPDATE",
        "CHECK",
        "REPAIR",
        "READ,MMAP",
        "UPDATE,MMAP",
        "INVALID:CHECK+MMAP",
        "INVALID:REPAIR+MMAP",
        "DUBIOUS:READ+MPROTECT",
        "DUBIOUS:UPDATE+MPROTECT",
        "INVALID:CHECK+MPROTECT",
        "INVALID:REPAIR+MPROTECT",
        "READ+MPROTECT",
        "UPDATE+MPROTECT",
        "INVALID:CHECK+MMAP+MPROTECT",
        "INVALID:REPAIR+MMAP+MPROTECT",
        "DUBIOUS:READ+FSYNC",
        "UPDATE,FSYNC",
        "DUBIOUS:CHECK+FSYNC",
        "REPAIR,FSYNC",
    };

    return mode < 0 ? hxerror(mode) :
        mode < NELS(modev) ? modev[mode] : "INVALID";
}
int cf_opt_pattern_list(struct pattern_list *listp, const char *text)
{
  struct pattern_list list;
  memset(&list, 0, sizeof list);
  const char *word = NULL;
  const char *p;
  for (p = text; ; ++p) {
    if (!*p || isspace(*p) || *p == ',') {
      if (word) {
	size_t len = p - word;
	if (list.patc >= NELS(list.patv) || len >= sizeof(list.patv[list.patc]))
	  return CFARRAYOVERFLOW;
	strncpy(list.patv[list.patc++], word, len)[len] = '\0';
	word = NULL;
      }
      if (!*p)
	break;
    } else if (!word)
      word = p;
  }
  assert(word == NULL);
  if (list.patc == 0)
    return CFEMPTY;
  *listp = list;
  return CFOK;
}
Esempio n. 4
0
char const *
hxerror(HXRET ret)
{
#   undef   _C
#   undef   _E
#   define  _C	    ,
#   define  _E(x)   #x
    static char const *errv[] = { "ok", HXERRS };
    static char num[11];

    if (ret > 0 || -ret >= NELS(errv))
        return (sprintf(num, "%d", ret), num);
    return errv[-ret];
}
static int restful_rhizome_bundlelist_json_content_chunk(struct http_request *hr, strbuf b)
{
  httpd_request *r = (httpd_request *) hr;
  const char *headers[] = {
    ".token",
    "_id",
    "service",
    "id",
    "version",
    "date",
    ".inserttime",
    ".author",
    ".fromhere",
    "filesize",
    "filehash",
    "sender",
    "recipient",
    "name"
  };
  switch (r->u.rhlist.phase) {
    case LIST_HEADER:
      strbuf_puts(b, "{\n\"header\":[");
      unsigned i;
      for (i = 0; i != NELS(headers); ++i) {
	if (i)
	  strbuf_putc(b, ',');
	strbuf_json_string(b, headers[i]);
      }
      strbuf_puts(b, "],\n\"rows\":[");
      if (!strbuf_overrun(b))
	r->u.rhlist.phase = LIST_ROWS;
      return 1;
    case LIST_ROWS:
      {
	int ret = rhizome_list_next(&r->u.rhlist.cursor);
	if (ret == -1)
	  return -1;
	if (ret == 0) {
	  time_ms_t now;
	  if (r->u.rhlist.cursor.rowid_since == 0 || (now = gettime_ms()) >= r->u.rhlist.end_time) {
	    r->u.rhlist.phase = LIST_END;
	    return 1;
	  }
	  time_ms_t wake_at = now + config.rhizome.api.restful.newsince_poll_ms;
	  if (wake_at > r->u.rhlist.end_time)
	    wake_at = r->u.rhlist.end_time;
	  http_request_pause_response(&r->http, wake_at);
	  return 0;
	}
	rhizome_manifest *m = r->u.rhlist.cursor.manifest;
	assert(m->filesize != RHIZOME_SIZE_UNSET);
	rhizome_lookup_author(m);
	if (r->u.rhlist.rowcount != 0)
	  strbuf_putc(b, ',');
	strbuf_puts(b, "\n[");
	if (m->rowid > r->u.rhlist.rowid_highest) {
	  strbuf_json_string(b, alloca_list_token(m->rowid));
	  r->u.rhlist.rowid_highest = m->rowid;
	} else
	  strbuf_json_null(b);
	strbuf_putc(b, ',');
	strbuf_sprintf(b, "%"PRIu64, m->rowid);
	strbuf_putc(b, ',');
	strbuf_json_string(b, m->service);
	strbuf_putc(b, ',');
	strbuf_json_hex(b, m->cryptoSignPublic.binary, sizeof m->cryptoSignPublic.binary);
	strbuf_putc(b, ',');
	strbuf_sprintf(b, "%"PRIu64, m->version);
	strbuf_putc(b, ',');
	if (m->has_date)
	  strbuf_sprintf(b, "%"PRItime_ms_t, m->date);
	else
	  strbuf_json_null(b);
	strbuf_putc(b, ',');
	strbuf_sprintf(b, "%"PRItime_ms_t",", m->inserttime);
	switch (m->authorship) {
	  case AUTHOR_LOCAL:
	  case AUTHOR_AUTHENTIC:
	    strbuf_json_hex(b, m->author.binary, sizeof m->author.binary);
	    strbuf_puts(b, ",1,");
	    break;
	  default:
	    strbuf_json_null(b);
	    strbuf_puts(b, ",1,");
	    break;
	}
	strbuf_sprintf(b, "%"PRIu64, m->filesize);
	strbuf_putc(b, ',');
	strbuf_json_hex(b, m->filesize ? m->filehash.binary : NULL, sizeof m->filehash.binary);
	strbuf_putc(b, ',');
	strbuf_json_hex(b, m->has_sender ? m->sender.binary : NULL, sizeof m->sender.binary);
	strbuf_putc(b, ',');
	strbuf_json_hex(b, m->has_recipient ? m->recipient.binary : NULL, sizeof m->recipient.binary);
	strbuf_putc(b, ',');
	strbuf_json_string(b, m->name);
	strbuf_puts(b, "]");
	if (!strbuf_overrun(b)) {
	  rhizome_list_commit(&r->u.rhlist.cursor);
	  ++r->u.rhlist.rowcount;
	}
      }
      return 1;
    case LIST_END:
      strbuf_puts(b, "\n]\n}\n");
      if (!strbuf_overrun(b))
	r->u.rhlist.phase = LIST_DONE;
      // fall through...
    case LIST_DONE:
      return 0;
  }
  abort();
}
Esempio n. 6
0
/* Returns 0 if a command is matched and parsed, with the results of the parsing in the '*parsed'
 * structure.
 *
 * Returns 1 and logs an error if no command matches the argument list, contents of '*parsed' are
 * undefined.
 *
 * Returns 2 if the argument list is ambiguous, ie, matches more than one command, contents of
 * '*parsed' are undefined.
 *
 * Returns -1 and logs an error if the parsing fails due to an internal error (eg, malformed command
 * schema), contents of '*parsed' are undefined.
 *
 * @author Andrew Bettison <*****@*****.**>
 */
int cli_parse(const int argc, const char *const *args, const struct cli_schema *commands, struct cli_parsed *parsed)
{
  int ambiguous = 0;
  int matched_cmd = -1;
  int cmd;
  for (cmd = 0; commands[cmd].function; ++cmd) {
    struct cli_parsed cmdpa;
    memset(&cmdpa, 0, sizeof cmdpa);
    cmdpa.commands = commands;
    cmdpa.cmdi = cmd;
    cmdpa.args = args;
    cmdpa.argc = argc;
    cmdpa.labelc = 0;
    cmdpa.varargi = -1;
    const char *pattern = NULL;
    unsigned arg = 0;
    unsigned opt = 0;
    while ((pattern = commands[cmd].words[opt])) {
      //DEBUGF("cmd=%d opt=%d pattern='%s' args[arg=%d]='%s'", cmd, opt, pattern, arg, arg < argc ? args[arg] : "");
      unsigned patlen = strlen(pattern);
      if (cmdpa.varargi != -1)
	return WHYF("Internal error: commands[%d].word[%d]=\"%s\" - more words not allowed after \"...\"", cmd, opt, commands[cmd].words[opt]);
      /* These are the argument matching rules:
       *
       * "..." consumes all remaining arguments
       *
       * "word" consumes one argument that exactly matches "word", does not label it (this is the
       * "simple" case in the code below; all other rules label something that matched)
       *
       * "word1|word2|...|wordN" consumes one argument that exactly matches "word1" or "word2" etc.
       * or "wordN", labels it with the matched word (an empty alternative, eg "|word" does not
       * match an empty argument)
       *
       * (as a special case of the above rule, "|word" consumes one argument that exactly matches
       * "word" and labels it "word", but it appears in the help description as "word")
       *
       * "<label>" consumes exactly one argument "ANY", records it with label "label"
       *
       * "prefix=<any>" consumes one argument "prefix=ANY" or two arguments "prefix" "ANY",
       * and records the text matching ANY with label "prefix"
       *
       * "prefix <any>" consumes one argyment "prefix ANY" if available or two arguments "prefix"
       * "ANY", and records the text matching ANY with label "prefix"
       *
       * "prefix<any>" consumes one argument "prefixANY", and records the text matching ANY with
       * label "prefix"
       *
       * "[ANY]..." consumes all remaining arguments which match ANY, as defined below
       *
       * "[word]" consumes one argument if it exactly matches "word", records it with label
       * "word"
       *
       * "[word1|word2|...|wordN]" consumes one argument if it exactly matches "word1" or "word2"
       * etc. or "wordN", labels it with the matched word
       *
       * "[<label>]" consumes one argument "ANY" if available, records it with label "label"
       *
       * "[prefix=<any>]" consumes one argument "prefix=ANY" if available or two arguments
       * "prefix" "ANY" if available, records the text matching ANY with label "prefix"
       *
       * "[prefix <any>]" consumes one argument "prefix ANY" if available or two arguments
       * "prefix" "ANY" if available, records the text matching ANY with label "prefix"
       *
       * "[prefix<any>]" consumes one argument "prefixANY" if available, records the text matching
       * ANY with label "prefix"
       */
      if (patlen == 3 && pattern[0] == '.' && pattern[1] == '.' && pattern[2] == '.') {
	cmdpa.varargi = arg;
	arg = argc;
	++opt;
      } else {
	int optional = 0;
	int repeating = 0;
	if (patlen > 5 && pattern[0] == '[' && pattern[patlen-4] == ']' && pattern[patlen-3] == '.' && pattern[patlen-2] == '.' && pattern[patlen-1] == '.') {
	  optional = repeating = 1;
	  pattern += 1;
	  patlen -= 5;
	}
	else if (patlen > 2 && pattern[0] == '[' && pattern[patlen-1] == ']') {
	  optional = 1;
	  pattern += 1;
	  patlen -= 2;
	}
	unsigned oarg = arg;
	const char *text = NULL;
	const char *label = NULL;
	unsigned labellen = 0;
	const char *word = pattern;
	unsigned wordlen = 0;
	char simple = 0;
	unsigned alt = 0;
	if (patlen && *word == '|') {
	  ++alt;
	  ++word;
	}
	if (patlen == 0)
	  return WHYF("Internal error: commands[%d].word[%d]=\"%s\" - empty words not allowed", cmd, opt, commands[cmd].words[opt]);
	for (; word < &pattern[patlen]; word += wordlen + 1, ++alt) {
	  // Skip over empty "||word" alternative (but still count it).
	  if (*word == '|')
	    return WHYF("Internal error: commands[%d].word[%d]=\"%s\" - empty alternatives not allowed", cmd, opt, commands[cmd].words[opt]);
	  // Find end of "word|" alternative.
	  wordlen = 1;
	  while (&word[wordlen] < &pattern[patlen] && word[wordlen] != '|')
	    ++wordlen;
	  // Skip remaining alternatives if we already got a match.
	  if (text)
	    continue;
	  // Look for a match.
	  const char *prefix = NULL;
	  unsigned prefixlen = 0;
	  char prefixarglen = 0;
	  const char *caret = strchr(word, '<');
	  if (wordlen > 2 && caret && word[wordlen-1] == '>') {
	    if ((prefixarglen = prefixlen = caret - word)) {
	      prefix = word;
	      if (prefixlen > 1 && (prefix[prefixlen-1] == '=' || prefix[prefixlen-1] == ' '))
		--prefixarglen;
	      label = prefix;
	      labellen = prefixarglen;
	      if (arg < argc) {
		unsigned arglen = strlen(args[arg]);
		if (arglen >= prefixlen && strncmp(args[arg], prefix, prefixlen) == 0) {
		  text = args[arg++] + prefixlen;
		} else if (arg + 1 < argc && arglen == prefixarglen && strncmp(args[arg], prefix, prefixarglen) == 0) {
		  ++arg;
		  text = args[arg++];
		}
	      }
	    } else {
	      label = &word[1];
	      labellen = wordlen - 2;
	      if (arg < argc)
		text = args[arg++];
	    }
	  } else if (arg < argc && strlen(args[arg]) == wordlen && strncmp(args[arg], word, wordlen) == 0) {
	    simple = 1;
	    text = args[arg];
	    label = word;
	    labellen = wordlen;
	    ++arg;
	  }
	}
	assert(alt > 0);
	if (arg == oarg && !optional)
	  break;
	if (labellen && text && (optional || !simple || alt > 1)) {
	  if (cmdpa.labelc >= NELS(cmdpa.labelv))
	    return WHYF("Internal error: commands[%d].word[%d]=\"%s\" - label limit exceeded", cmd, opt, commands[cmd].words[opt]);
	  cmdpa.labelv[cmdpa.labelc].label = label;
	  cmdpa.labelv[cmdpa.labelc].len = labellen;
	  cmdpa.labelv[cmdpa.labelc].text = text;
	  ++cmdpa.labelc;
	  if (!repeating)
	    ++opt;
	} else
	  ++opt;
      }
    }
    //DEBUGF("cmd=%d opt=%d args[arg=%d]='%s'", cmd, opt, arg, arg < argc ? args[arg] : "");
    if (!pattern && arg == argc) {
      /* A match!  We got through the command definition with no internal errors and all literal
      args matched and we have a proper number of args.  If we have multiple matches, then note
      that the call is ambiguous. */
      if (matched_cmd >= 0)
	++ambiguous;
      if (ambiguous == 1) {
	NOWHENCE(WHY_argv("Ambiguous command:", argc, args));
	NOWHENCE(HINT("Matches the following:"));
	NOWHENCE(HINT_argv("   ", argc, commands[matched_cmd].words));
      }
      if (ambiguous)
	NOWHENCE(HINT_argv("   ", argc, commands[cmd].words));
      matched_cmd = cmd;
      *parsed = cmdpa;
    }
  }
  /* Don't process ambiguous calls */
  if (ambiguous)
    return 2;
  /* Complain if we found no matching calls */
  if (matched_cmd < 0) {
    if (argc)
      NOWHENCE(WHY_argv("Unknown command:", argc, args));
    return 1;
  }
  return 0;
}