void taskmain(int argc, char *argv[]) { dbg_set_log(stderr); int i = 0; bstring arguments = bfromcstr(argv[0]); for(i = 1; i < argc; i++) { bstring a = bfromcstr(argv[i]); // compensate for quotes getting taken off by the shell // TODO: also need to escape " to bring back that if(bstrchr(a, ' ') != -1) { bcatcstr(arguments, " \""); bconcat(arguments, a); bcatcstr(arguments, "\""); } else { bcatcstr(arguments, " "); bconcat(arguments, a); } bdestroy(a); } debug("RUNNING: %s", bdata(arguments)); taskexitall(Command_run(arguments)); }
static const unsigned char * bstrstr(const unsigned char *s1, size_t l1, const unsigned char *s2, size_t l2) { /* find first occurrence of s2[] in s1[] for length l1*/ const unsigned char *ss1 = s1; const unsigned char *ss2 = s2; /* handle special case */ if(l1 == 0) return (NULL); if(l2 == 0) return s1; /* match prefix */ for (; (s1 = bstrchr(s1, *s2, (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1)) != NULL && (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1 != 0; ++s1) { /* match rest of prefix */ const unsigned char *sc1, *sc2; for (sc1 = s1, sc2 = s2; ;) if (++sc2 >= ss2+l2) return s1; else if (*++sc1 != *sc2) break; } return NULL; }
Dir *Dir_create(const char *base, const char *prefix, const char *index_file, const char *default_ctype) { Dir *dir = calloc(sizeof(Dir), 1); check_mem(dir); dir->base = bfromcstr(base); check(blength(dir->base) < MAX_DIR_PATH, "Base directory is too long, must be less than %d", MAX_DIR_PATH); // dir can come from the routing table so it could have a pattern in it, strip that off bstring pattern = bfromcstr(prefix); int first_paren = bstrchr(pattern, '('); dir->prefix = first_paren >= 0 ? bHead(pattern, first_paren) : bstrcpy(pattern); bdestroy(pattern); check(blength(dir->prefix) < MAX_DIR_PATH, "Prefix is too long, must be less than %d", MAX_DIR_PATH); check(bchar(dir->prefix, 0) == '/' && bchar(dir->prefix, blength(dir->prefix)-1) == '/', "Dir route prefix (%s) must start with / and end with / or else you break the internet.", prefix); dir->index_file = bfromcstr(index_file); dir->default_ctype = bfromcstr(default_ctype); dir->fr_cache = Cache_create(FR_CACHE_SIZE, filerecord_cache_lookup, filerecord_cache_evict); check(dir->fr_cache, "Failed to create FileRecord cache"); return dir; error: if(dir) free(dir); return NULL; }
struct bstr bstr_getline(struct bstr str, struct bstr *rest) { int pos = bstrchr(str, '\n'); if (pos < 0) pos = str.len; if (rest) *rest = bstr_cut(str, pos + 1); return bstr_splice(str, 0, pos + 1); }
struct bstr bstr_splitchar(struct bstr str, struct bstr *rest, const char c) { int pos = bstrchr(str, c); if (pos < 0) pos = str.len; if (rest) *rest = bstr_cut(str, pos + 1); return bstr_splice(str, 0, pos + 1); }
static char *read_quoted(void *talloc_ctx, struct bstr *data) { *data = bstr_lstrip(*data); if (!eat_char(data, '"')) return NULL; int end = bstrchr(*data, '"'); if (end < 0) return NULL; struct bstr res = bstr_splice(*data, 0, end); *data = bstr_cut(*data, end + 1); return bstrto0(talloc_ctx, res); }
static void header_done_cb(void *data, const char *at, size_t length) { (void)at; (void)length; Request *req = (Request *)data; // extract content_len const char *clen = bdata(Request_get(req, &HTTP_CONTENT_LENGTH)); if(clen) req->parser.content_len = atoi(clen); // extract host header req->host = Request_get(req, &HTTP_HOST); int colon = bstrchr(req->host, ':'); if(req->host) { req->host_name = colon > 0 ? bHead(req->host, colon) : bstrcpy(req->host); } }
// Returns 0 if a valid option/file is available, <0 on error, 1 on end of args. static int split_opt_silent(struct parse_state *p) { assert(!p->error); if (p->argc < 1) return 1; p->mp_opt = NULL; p->arg = bstr0(p->argv[0]); p->param = bstr0(NULL); p->argc--; p->argv++; if (p->no_more_opts || !bstr_startswith0(p->arg, "-") || p->arg.len == 1) return 0; if (bstrcmp0(p->arg, "--") == 0) { p->no_more_opts = true; return split_opt_silent(p); } bool old_syntax = !bstr_startswith0(p->arg, "--"); if (old_syntax) { p->arg = bstr_cut(p->arg, 1); } else { p->arg = bstr_cut(p->arg, 2); int idx = bstrchr(p->arg, '='); if (idx > 0) { p->param = bstr_cut(p->arg, idx + 1); p->arg = bstr_splice(p->arg, 0, idx); } } p->mp_opt = m_config_get_option(p->config, p->arg); if (!p->mp_opt) { // Automagic "no-" arguments: "--no-bla" turns into "--bla=no". if (!bstr_startswith0(p->arg, "no-")) return -1; struct bstr s = bstr_cut(p->arg, 3); p->mp_opt = m_config_get_option(p->config, s); if (!p->mp_opt || p->mp_opt->type != &m_option_type_flag) return -1; // Avoid allowing "--no-no-bla". if (bstr_startswith(bstr0(p->mp_opt->name), bstr0("no-"))) return -1; // Flag options never have parameters. old_syntax = false; if (p->param.len) return -2; p->arg = s; p->param = bstr0("no"); } if (bstr_endswith0(p->arg, "-clr")) old_syntax = false; if (old_syntax && !(p->mp_opt->type->flags & M_OPT_TYPE_OLD_SYNTAX_NO_PARAM)) { if (p->argc < 1) return -3; p->param = bstr0(p->argv[0]); p->argc--; p->argv++; } return 0; }
/* ---------------------------------------------------------- * FUNCTION : parse_line * DESCRIPTION : This function will process a line of data * : from a configuration file. * INPUT : 0 - Line (bstring) * ---------------------------------------------------------- */ void parse_line (bstring line) { bstring param, value; struct bstrList *list; int i; /* Check to see if this line has something to read. */ if (line->data[0] == '\0' || line->data[0] == '#') return; /* Check to see if this line has a comment in it. */ if ((list = bsplit(line, '#')) != NULL) { if ((bassign(line, list->entry[0])) == -1) { log_message("warning: 'bassign' in function 'parse_line' failed."); } if (list != NULL) bstrListDestroy(list); } /* Seperate line into a parameter and a value. */ if ((i = bstrchr(line, ' ')) == BSTR_ERR) return; if ((param = bmidstr(line, 0, i)) == NULL) return; if ((value = bmidstr(line, i + 1, line->slen - i)) == NULL) return; /* Normalize Strings */ if ((btolower(param)) != 0) log_message("warning: 'btolower' in function 'parse_line' failed."); if ((bltrim(value)) != 0) log_message("warning: 'bltrim' in function 'parse_line' failed."); if ((brtrim(value)) != 0) log_message("warning: 'brtrim' in function 'parse_line' failed."); /* Do something based upon value. */ if ((biseqcstr(param, "daemon")) == 1) { /* DAEMON */ if (!gc.daemon_mode) { if (value->data[0] == '1') gc.daemon_mode = 1; else gc.daemon_mode = 0; } } else if ((biseqcstr(param, "pid_file")) == 1) { /* PID FILE */ gc.pid_file = bstrcpy(value); } else if ((biseqcstr(param, "sig_file")) == 1) { /* SIGNATURE FILE */ gc.sig_file = bstrcpy(value); } else if ((biseqcstr(param, "mac_file")) == 1) { /* MAC / VENDOR RESOLUTION FILE */ gc.mac_file = bstrcpy(value); } else if ((biseqcstr(param, "output")) == 1) { /* OUTPUT */ conf_module_plugin(value, &activate_output_plugin); } else if ((biseqcstr(param, "user")) == 1) { /* USER */ gc.priv_user = bstrcpy(value); } else if ((biseqcstr(param, "group")) == 1) { /* GROUP */ gc.priv_group = bstrcpy(value); } else if ((biseqcstr(param, "interface")) == 1) { /* INTERFACE */ gc.dev = bstr2cstr(value, '-'); } else if ((biseqcstr(param, "filter")) == 1) { /* FILTER */ gc.pcap_filter = bstr2cstr(value, '-'); } else if ((biseqcstr(param, "network")) == 1) { /* NETWORK */ parse_networks(bdata(value)); } verbose_message("config - PARAM: |%s| / VALUE: |%s|", bdata(param), bdata(value)); /* Clean Up */ if (param != NULL) bdestroy(param); if (value != NULL) bdestroy(value); }
int m_config_parse(m_config_t *config, const char *location, bstr data, char *initial_section, int flags) { m_profile_t *profile = m_config_add_profile(config, initial_section); void *tmp = talloc_new(NULL); int line_no = 0; int errors = 0; bstr_eatstart0(&data, "\xEF\xBB\xBF"); // skip BOM while (data.len) { talloc_free_children(tmp); bool ok = false; line_no++; char loc[512]; snprintf(loc, sizeof(loc), "%s:%d:", location, line_no); bstr line = bstr_strip_linebreaks(bstr_getline(data, &data)); if (!skip_ws(&line)) continue; // Profile declaration if (bstr_eatstart0(&line, "[")) { bstr profilename; if (!bstr_split_tok(line, "]", &profilename, &line)) { MP_ERR(config, "%s missing closing ]\n", loc); goto error; } if (skip_ws(&line)) { MP_ERR(config, "%s unparseable extra characters: '%.*s'\n", loc, BSTR_P(line)); goto error; } profile = m_config_add_profile(config, bstrto0(tmp, profilename)); continue; } bstr_eatstart0(&line, "--"); bstr option = line; while (line.len && (mp_isalnum(line.start[0]) || line.start[0] == '_' || line.start[0] == '-')) line = bstr_cut(line, 1); option.len = option.len - line.len; skip_ws(&line); bstr value = {0}; if (bstr_eatstart0(&line, "=")) { skip_ws(&line); if (line.len && (line.start[0] == '"' || line.start[0] == '\'')) { // Simple quoting, like "value" char term[2] = {line.start[0], 0}; line = bstr_cut(line, 1); if (!bstr_split_tok(line, term, &value, &line)) { MP_ERR(config, "%s unterminated quote\n", loc); goto error; } } else if (bstr_eatstart0(&line, "%")) { // Quoting with length, like %5%value bstr rest; long long len = bstrtoll(line, &rest, 10); if (rest.len == line.len || !bstr_eatstart0(&rest, "%") || len > rest.len) { MP_ERR(config, "%s fixed-length quoting expected - put " "\"quotes\" around the option value if you did not " "intend to use this, but your option value starts " "with '%%'\n", loc); goto error; } value = bstr_splice(rest, 0, len); line = bstr_cut(rest, len); } else { // No quoting; take everything until the comment or end of line int end = bstrchr(line, '#'); value = bstr_strip(end < 0 ? line : bstr_splice(line, 0, end)); line.len = 0; } } if (skip_ws(&line)) { MP_ERR(config, "%s unparseable extra characters: '%.*s'\n", loc, BSTR_P(line)); goto error; } int res; if (profile) { if (bstr_equals0(option, "profile-desc")) { m_profile_set_desc(profile, value); res = 0; } else { res = m_config_set_profile_option(config, profile, option, value); } } else { res = m_config_set_option_ext(config, option, value, flags); } if (res < 0) { MP_ERR(config, "%s setting option %.*s='%.*s' failed.\n", loc, BSTR_P(option), BSTR_P(value)); goto error; } ok = true; error: if (!ok) errors++; if (errors > 16) { MP_ERR(config, "%s: too many errors, stopping.\n", location); break; } } talloc_free(tmp); return 1; }
FileRecord *Dir_resolve_file(Dir *dir, bstring pattern, bstring path) { FileRecord *file = NULL; bstring target = NULL; bstring prefix = NULL; check(Dir_lazy_normalize_base(dir) == 0, "Failed to normalize base path when requesting %s", bdata(path)); file = FileRecord_cache_check(dir, path); if(file) { // TODO: double check this gives the right users count file->users++; return file; } int paren = bstrchr(pattern, '('); prefix = (paren > 0) ? bHead(pattern, paren) : bstrcpy(pattern); check(bchar(prefix, 0) == '/', "Route '%s' pointing to directory must have pattern with leading '/'", bdata(pattern)); check(blength(prefix) < MAX_DIR_PATH, "Prefix is too long, must be less than %d", MAX_DIR_PATH); debug("Building target from base: %s pattern: %s prefix: %s path: %s index_file: %s", bdata(dir->normalized_base), bdata(pattern), bdata(prefix), bdata(path), bdata(dir->index_file)); if(bchar(path, blength(path) - 1) == '/') { // a directory so figureo out the index file target = bformat("%s%s%s", bdata(dir->normalized_base), path->data + blength(prefix) - 1, bdata(dir->index_file)); } else if(biseq(prefix, path)) { target = bformat("%s%s", bdata(dir->normalized_base), bdata(path)); } else { target = bformat("%s%s", bdata(dir->normalized_base), path->data + blength(prefix) - 1); } check(target, "Couldn't construct target path for %s", bdata(path)); check_debug(normalize_path(target) == 0, "Failed to normalize target path: %s", bdata(target)); check_debug(bstrncmp(target, dir->normalized_base, blength(dir->normalized_base)) == 0, "Request for path %s does not start with %s base after normalizing.", bdata(target), bdata(dir->base)); // the FileRecord now owns the target file = Dir_find_file(target, dir->default_ctype); check_debug(file, "Error opening file: %s", bdata(target)); // Increment the user count because we're adding it to the cache file->users++; file->request_path = bstrcpy(path); Cache_add(dir->fr_cache, file); return file; error: bdestroy(target); FileRecord_release(file); return NULL; }
static struct bstr read_quoted(struct bstr *data) { *data = bstr_lstrip(*data); if (!eat_char(data, '"')) return (struct bstr) {0}; int end = bstrchr(*data, '"'); if (end < 0) return (struct bstr) {0}; struct bstr res = bstr_splice(*data, 0, end); *data = bstr_cut(*data, end + 1); return res; } // Read a 2 digit unsigned decimal integer. // Return -1 on failure. static int read_int_2(struct bstr *data) { *data = bstr_lstrip(*data); if (data->len && data->start[0] == '-') return -1; struct bstr s = *data; int res = (int)bstrtoll(s, &s, 10); if (data->len == s.len || data->len - s.len > 2) return -1; *data = s; return res; } static double read_time(struct bstr *data) { struct bstr s = *data; bool ok = true; double t1 = read_int_2(&s); ok = eat_char(&s, ':') && ok; double t2 = read_int_2(&s); ok = eat_char(&s, ':') && ok; double t3 = read_int_2(&s); ok = ok && t1 >= 0 && t2 >= 0 && t3 >= 0; return ok ? t1 * 60.0 + t2 + t3 * SECS_PER_CUE_FRAME : 0; } static struct bstr skip_utf8_bom(struct bstr data) { return bstr_startswith0(data, "\xEF\xBB\xBF") ? bstr_cut(data, 3) : data; } // Check if the text in data is most likely CUE data. This is used by the // demuxer code to check the file type. // data is the start of the probed file, possibly cut off at a random point. bool mp_probe_cue(struct bstr data) { bool valid = false; data = skip_utf8_bom(data); for (;;) { enum cue_command cmd = read_cmd(&data, NULL); // End reached. Since the line was most likely cut off, don't use the // result of the last parsing call. if (data.len == 0) break; if (cmd == CUE_ERROR) return false; if (cmd != CUE_EMPTY) valid = true; } return valid; }
static int parse_server_xport_option(allium_ptcfg *cfg, const bstring arg_str) { struct allium_ptcfg_method_s *m; struct allium_ptcfg_xport_opt_s *opt; bstring transport; bstring key; bstring value; int i, j; assert(cfg); assert(arg_str); if (0 == blength(arg_str)) return (-1); /* * Figure out what transport this argument is for. We don't need to * unescape method names as they conform to "[a-zA-Z_][a-zA-Z0-9_]*" */ i = bstrchr(arg_str, ':'); if (BSTR_ERR == i) return (-1); transport = bmidstr(arg_str, 0, i); if (NULL == transport) return (-1); m = get_method(cfg, bdata(transport)); bdestroy(transport); /* Done with the transport at this point */ if (NULL == m) return (-1); /* * Figure out what key the transport is expecting the value for. * * XXX: If people want to use the escaped characters in their keys they * get what they deserve (Note this as a gotcha and fix it when people * cry about it). */ j = bstrchrp(arg_str, '=', i); if (BSTR_ERR == j) return (-1); key = bmidstr(arg_str, i + 1, j - i - 1); if (NULL == key) return (-1); opt = get_xport_opt(m, key); if ((NULL != opt) || (0 == blength(key))) { /* We don't support redefining existing key/value pairs */ bdestroy(key); return (-1); } /* Parse the value, unescaping as needed */ value = bmidstr(arg_str, j + 1, blength(arg_str) - j - 1); if (NULL == value) { bdestroy(key); return (-1); } unescape_opt_value(value); /* Stash it away so people can get to it */ opt = calloc(1, sizeof(*opt)); if (NULL == opt) { bdestroy(key); bdestroy_safe(value); return (-1); } opt->key = key; opt->value = value; opt->next = m->xport_opts; m->xport_opts = opt; return (0); }