Beispiel #1
0
/*
  Implemented using rolling hash function.
 */
int rabin_karp(const char *needle, const char *haystack)
{
    // Rolling hash function for needle is calculated.
    int len = strlen(needle);
    int maxpow = mod_pow(PRIME_BASE, len - 1, MOD);
    int hash_needle = hash(needle, len);
    int roll_hash = hash(haystack, len);
    const char *win_start = haystack;
    const char *win_end = haystack + len;
    for(; hash_needle != roll_hash; ++win_end, ++win_start) {
        if(*win_end == '\0')
            return -1;
        roll_hash = rehash(roll_hash, *win_start, *win_end, maxpow);
    }
    if(strstarts(needle, win_start) == 0)
        return win_start - haystack;
    else
        return -1;
}
Beispiel #2
0
int perf_callchain_config(const char *var, const char *value)
{
	char *endptr;

	if (!strstarts(var, "call-graph."))
		return 0;
	var += sizeof("call-graph.") - 1;

	if (!strcmp(var, "record-mode"))
		return parse_callchain_record_opt(value, &callchain_param);
	if (!strcmp(var, "dump-size")) {
		unsigned long size = 0;
		int ret;

		ret = get_stack_size(value, &size);
		callchain_param.dump_size = size;

		return ret;
	}
	if (!strcmp(var, "print-type"))
		return parse_callchain_mode(value);
	if (!strcmp(var, "order"))
		return parse_callchain_order(value);
	if (!strcmp(var, "sort-key"))
		return parse_callchain_sort_key(value);
	if (!strcmp(var, "threshold")) {
		callchain_param.min_percent = strtod(value, &endptr);
		if (value == endptr) {
			pr_err("Invalid callchain threshold: %s\n", value);
			return -1;
		}
	}
	if (!strcmp(var, "print-limit")) {
		callchain_param.print_limit = strtod(value, &endptr);
		if (value == endptr) {
			pr_err("Invalid callchain print limit: %s\n", value);
			return -1;
		}
	}

	return 0;
}
Beispiel #3
0
/* Simple test code to create a gateway transaction */
int main(int argc, char *argv[])
{
	char *ret;
	struct protocol_address addr;
	bool testnet;

	err_set_progname(argv[0]);

	if (argc != 2)
		errx(1, "Usage: %s <address>", argv[0]);

	if (!pettycoin_from_base58(&testnet, &addr, argv[1], strlen(argv[1])))
		errx(1, "Address '%s' not valid", argv[1]);

	ret = pettycoin_to_base58(NULL, testnet, &addr,
				  !strstarts(argv[1], "P-"));
	printf("%s\n", ret);
	tal_free(ret);
	return 0;
}
Beispiel #4
0
/*
 * TASK to handle an incoming request
 */
int server_request (void *parm)
{
  SERVERPARM *s;
  DBUF *req, *res;
  char *curl;

  s = (SERVERPARM *) parm;
  curl = xml_get_text (s->xml, "Phineas.Console.Url");
  res = NULL;
  while ((req = server_receive (s->conn)) != NULL)
  {
    debug ("received %d bytes\n", dbuf_size (req));
    if (dbuf_size (req) == 0)
    {
      dbuf_free (req);
      net_close (s->conn);
      return (-1);
    }
    dbuf_putc (req, 0);
    /*
     * log the request, but filter out GET requests for the console... 
     * noise
     */
    if (!(*curl && strstarts (dbuf_getbuf (req) + 4, curl)))
      server_logrequest (s->conn, dbuf_size (req), dbuf_getbuf (req));
    if ((res = server_response (s->xml, dbuf_getbuf (req))) == NULL)
    {
      res = server_respond (500,
	    "<h3>Failure processing ebXML request</h3>");
    }
    server_header (res);
    net_write (s->conn, dbuf_getbuf (res), dbuf_size (res));
    dbuf_free (res);
    dbuf_free (req);
  }
  net_close (s->conn);
  debug ("request completed\n");
  return (0);
}
Beispiel #5
0
static void list_commands_in_dir(struct cmdnames *cmds,
					 const char *path,
					 const char *prefix)
{
	int prefix_len;
	DIR *dir = opendir(path);
	struct dirent *de;
	char *buf = NULL;

	if (!dir)
		return;
	if (!prefix)
		prefix = "perf-";
	prefix_len = strlen(prefix);

	astrcatf(&buf, "%s/", path);

	while ((de = readdir(dir)) != NULL) {
		int entlen;

		if (!strstarts(de->d_name, prefix))
			continue;

		astrcat(&buf, de->d_name);
		if (!is_executable(buf))
			continue;

		entlen = strlen(de->d_name) - prefix_len;
		if (has_extension(de->d_name, ".exe"))
			entlen -= 4;

		add_cmdname(cmds, de->d_name + prefix_len, entlen);
	}
	closedir(dir);
	free(buf);
}
Beispiel #6
0
void InsertBasicStyle(const char *rtf, int how)

/******************************************************************************
  purpose: uses data from style.cfg to try and insert RTF commands
           that correspond to the appropriate style sheet or character style
           for example
                InsertBasicStyle(rtf, INSERT_STYLE_NORMAL);
                
           where rtf="\rtfsequence,\rtfheader"
 ******************************************************************************/
{
    char *style, *comma;
    char *style_end = NULL;

    if (rtf == NULL) return;
    
/* skip over 0,0, */
    style = strchr((char *) rtf, ',') + 1;
    if (style == NULL) return;

    style = strchr(style+1, ',');
    if (style == NULL) return;

/* skip blanks */
    style++;
    while (*style == ' ')
        style++;                

/* locate end of style */
    comma = strchr(style, ',');
    if (comma == NULL) return;

    switch (how) {
    
        case INSERT_STYLE_NORMAL:
            style_end = comma;
            break;
            
        case INSERT_STYLE_FOR_HEADER:
            style_end = style + strlen(style);
            break;

        case INSERT_STYLE_NO_STYLE:
            /* move start just past style bit e.g., \s2 */
            if (strstarts(style,"\\s")) {
                style += 2;
                while (*style >= '0' && *style <= '9') 
                    style++;
            }
            style_end = comma;
            break;
    }
    
    while (style < style_end) {

        if (style == comma)
            fprintRTF(" ");
        else if (*style == '*') 
            WriteCFGFontNumber(&style);
        else
            fprintRTF("%c", *style);

        style++;
    }
    
 /* emit final blank to make sure that RTF is properly terminated */
 /*   if (how != INSERT_STYLE_FOR_HEADER)
        fprintRTF(" "); */
}
Beispiel #7
0
/* Simple test code to create a gateway transaction */
int main(int argc, char *argv[])
{
	int fd, i, off;
	const char *method;
	char *cmd, *resp, *idstr, *rpc_filename;
	char *result_end;
	struct sockaddr_un addr;
	jsmntok_t *toks;
	const jsmntok_t *result, *error, *id;
	char *pettycoin_dir;
	const tal_t *ctx = tal(NULL, char);
	size_t num_opens, num_closes;
	bool valid;

	err_set_progname(argv[0]);

	opt_set_alloc(opt_allocfn, tal_reallocfn, tal_freefn);
	pettycoin_dir_register_opts(ctx, &pettycoin_dir, &rpc_filename);

	opt_register_noarg("--help|-h", opt_usage_and_exit,
			   "<command> [<params>...]", "Show this message");
	opt_register_noarg("--version|-V", opt_version_and_exit, VERSION,
			   "Display version and exit");

	opt_early_parse(argc, argv, opt_log_stderr_exit);
	opt_parse(&argc, argv, opt_log_stderr_exit);

	method = argv[1];
	if (!method)
		errx(ERROR_USAGE, "Need at least one argument\n%s",
		     opt_usage(argv[0], NULL));

	if (chdir(pettycoin_dir) != 0)
		err(ERROR_TALKING_TO_PETTYCOIN, "Moving into '%s'",
		    pettycoin_dir);

	fd = socket(AF_UNIX, SOCK_STREAM, 0);
	if (strlen(rpc_filename) + 1 > sizeof(addr.sun_path))
		errx(ERROR_USAGE, "rpc filename '%s' too long", rpc_filename);
	strcpy(addr.sun_path, rpc_filename);
	addr.sun_family = AF_UNIX;

	if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
		err(ERROR_TALKING_TO_PETTYCOIN,
		    "Connecting to '%s'", rpc_filename);

	idstr = tal_fmt(ctx, "pettycoin_query-%i", getpid());
	cmd = tal_fmt(ctx,
		      "{ \"method\" : \"%s\", \"id\" : \"%s\", \"params\" : [ ",
		      method, idstr);

	for (i = 2; i < argc; i++) {
		/* Numbers are left unquoted, and quoted things left alone. */
		if (strspn(argv[i], "0123456789") == strlen(argv[i])
		    || argv[i][0] == '"')
			tal_append_fmt(&cmd, "%s", argv[i]);
		else
			tal_append_fmt(&cmd, "\"%s\"", argv[i]);
		if (i != argc - 1)
			tal_append_fmt(&cmd, ", ");
	}
	tal_append_fmt(&cmd, "] }");

	if (!write_all(fd, cmd, strlen(cmd)))
		err(ERROR_TALKING_TO_PETTYCOIN, "Writing command");

	resp = tal_arr(cmd, char, 100);
	off = 0;
	num_opens = num_closes = 0;
	while ((i = read(fd, resp + off, tal_count(resp) - 1 - off)) > 0) {
		resp[off + i] = '\0';
		num_opens += strcount(resp + off, "{");
		num_closes += strcount(resp + off, "}");

		off += i;
		if (off == tal_count(resp) - 1)
			tal_resize(&resp, tal_count(resp) * 2);

		/* parsing huge outputs is slow: do quick check first. */
		if (num_opens == num_closes && strstr(resp, "\"result\""))
			break;
	}
	if (i < 0)
		err(ERROR_TALKING_TO_PETTYCOIN, "reading response");

	/* Parsing huge results is too slow, so hack fastpath common case */
	result_end = tal_fmt(ctx, ", \"error\" : null, \"id\" : \"%s\" }\n",
			     idstr);

	if (strstarts(resp, "{ \"result\" : ") && strends(resp, result_end)) {
		/* Result is OK, so dump it */
		resp += strlen("{ \"result\" : ");
		printf("%.*s\n", (int)(strlen(resp) - strlen(result_end)), resp);
		tal_free(ctx);
		return 0;
	}

	toks = json_parse_input(resp, off, &valid);
	if (!toks || !valid)
		errx(ERROR_TALKING_TO_PETTYCOIN,
		     "Malformed response '%s'", resp);

	result = json_get_member(resp, toks, "result");
	if (!result)
		errx(ERROR_TALKING_TO_PETTYCOIN,
		     "Missing 'result' in response '%s'", resp);
	error = json_get_member(resp, toks, "error");
	if (!error)
		errx(ERROR_TALKING_TO_PETTYCOIN,
		     "Missing 'error' in response '%s'", resp);
	id = json_get_member(resp, toks, "id");
	if (!id)
		errx(ERROR_TALKING_TO_PETTYCOIN,
		     "Missing 'id' in response '%s'", resp);
	if (!json_tok_streq(resp, id, idstr))
		errx(ERROR_TALKING_TO_PETTYCOIN,
		     "Incorrect 'id' in response: %.*s",
		     json_tok_len(id), json_tok_contents(resp, id));

	if (json_tok_is_null(resp, error)) {
		printf("%.*s\n",
		       json_tok_len(result),
		       json_tok_contents(resp, result));
		tal_free(ctx);
		return 0;
	}

	printf("%.*s\n",
	       json_tok_len(error), json_tok_contents(resp, error));
	tal_free(ctx);
	return 1;
}
Beispiel #8
0
static void add_files(struct manifest *m, const char *base, const char *subdir)
{
	DIR *d;
	struct dirent *ent;
	char **subs = tal_arr(m, char *, 0);
	const char *thisdir;

	if (!subdir)
		thisdir = base;
	else
		thisdir = path_join(subs, base, subdir);

	d = opendir(thisdir);
	if (!d)
		err(1, "Opening directory %s", thisdir);

	while ((ent = readdir(d)) != NULL) {
		struct stat st;
		struct ccan_file *f;
		struct list_head *dest;
		bool is_c_src;

		if (ent->d_name[0] == '.')
			continue;

		f = new_ccan_file(m, m->dir,
				  subdir ? path_join(m, subdir, ent->d_name)
				  : ent->d_name);
		if (lstat(f->fullname, &st) != 0)
			err(1, "lstat %s", f->fullname);

		if (S_ISDIR(st.st_mode)) {
			size_t len = tal_count(subs);
			tal_resize(&subs, len+1);
			subs[len] = tal_strcat(subs, f->name, "/");
			continue;
		}
		if (!S_ISREG(st.st_mode)) {
			tal_free(f);
			continue;
		}

		if (streq(f->name, "_info")) {
			m->info_file = f;
			continue;
		}

		is_c_src = strends(f->name, ".c");
		if (!is_c_src && !strends(f->name, ".h")) {
			dest = &m->other_files;
		} else if (!strchr(f->name, '/')) {
			if (is_c_src)
				dest = &m->c_files;
			else
				dest = &m->h_files;
		} else if (strstarts(f->name, "test/")) {
			if (is_c_src) {
				if (strstarts(f->name, "test/api"))
					dest = &m->api_tests;
				else if (strstarts(f->name, "test/run"))
					dest = &m->run_tests;
				else if (strstarts(f->name, "test/compile_ok"))
					dest = &m->compile_ok_tests;
				else if (strstarts(f->name, "test/compile_fail"))
					dest = &m->compile_fail_tests;
				else
					dest = &m->other_test_c_files;
			} else
				dest = &m->other_test_files;
		} else
			dest = &m->other_files;

		list_add(dest, &f->list);
	}
	closedir(d);

	/* Before we recurse, sanity check this is a ccan module. */
	if (!subdir) {
		size_t i;

		if (!m->info_file
		    && list_empty(&m->c_files)
		    && list_empty(&m->h_files))
			errx(1, "No _info, C or H files found here!");

		for (i = 0; i < tal_count(subs); i++)
			add_files(m, base, subs[i]);
	}
	tal_free(subs);
}
Beispiel #9
0
static int handle_options(const char ***argv, int *argc, int *envchanged)
{
	int handled = 0;

	while (*argc > 0) {
		const char *cmd = (*argv)[0];
		if (cmd[0] != '-')
			break;

		/*
		 * For legacy reasons, the "version" and "help"
		 * commands can be written with "--" prepended
		 * to make them look like flags.
		 */
		if (!strcmp(cmd, "--help") || !strcmp(cmd, "--version"))
			break;

		/*
		 * Shortcut for '-h' and '-v' options to invoke help
		 * and version command.
		 */
		if (!strcmp(cmd, "-h")) {
			(*argv)[0] = "--help";
			break;
		}

		if (!strcmp(cmd, "-v")) {
			(*argv)[0] = "--version";
			break;
		}

		if (!strcmp(cmd, "-vv")) {
			(*argv)[0] = "version";
			version_verbose = 1;
			break;
		}

		/*
		 * Check remaining flags.
		 */
		if (strstarts(cmd, CMD_EXEC_PATH)) {
			cmd += strlen(CMD_EXEC_PATH);
			if (*cmd == '=')
				set_argv_exec_path(cmd + 1);
			else {
				puts(get_argv_exec_path());
				exit(0);
			}
		} else if (!strcmp(cmd, "--html-path")) {
			puts(system_path(PERF_HTML_PATH));
			exit(0);
		} else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
			use_pager = 1;
		} else if (!strcmp(cmd, "--no-pager")) {
			use_pager = 0;
			if (envchanged)
				*envchanged = 1;
		} else if (!strcmp(cmd, "--debugfs-dir")) {
			if (*argc < 2) {
				fprintf(stderr, "No directory given for --debugfs-dir.\n");
				usage(perf_usage_string);
			}
			tracing_path_set((*argv)[1]);
			if (envchanged)
				*envchanged = 1;
			(*argv)++;
			(*argc)--;
		} else if (!strcmp(cmd, "--buildid-dir")) {
			if (*argc < 2) {
				fprintf(stderr, "No directory given for --buildid-dir.\n");
				usage(perf_usage_string);
			}
			set_buildid_dir((*argv)[1]);
			if (envchanged)
				*envchanged = 1;
			(*argv)++;
			(*argc)--;
		} else if (strstarts(cmd, CMD_DEBUGFS_DIR)) {
			tracing_path_set(cmd + strlen(CMD_DEBUGFS_DIR));
			fprintf(stderr, "dir: %s\n", tracing_path);
			if (envchanged)
				*envchanged = 1;
		} else if (!strcmp(cmd, "--list-cmds")) {
			unsigned int i;

			for (i = 0; i < ARRAY_SIZE(commands); i++) {
				struct cmd_struct *p = commands+i;
				printf("%s ", p->cmd);
			}
			putchar('\n');
			exit(0);
		} else if (!strcmp(cmd, "--list-opts")) {
			unsigned int i;

			for (i = 0; i < ARRAY_SIZE(options)-1; i++) {
				struct option *p = options+i;
				printf("--%s ", p->long_name);
			}
			putchar('\n');
			exit(0);
		} else if (!strcmp(cmd, "--debug")) {
			if (*argc < 2) {
				fprintf(stderr, "No variable specified for --debug.\n");
				usage(perf_usage_string);
			}
			if (perf_debug_option((*argv)[1]))
				usage(perf_usage_string);

			(*argv)++;
			(*argc)--;
		} else {
			fprintf(stderr, "Unknown option: %s\n", cmd);
			usage(perf_usage_string);
		}

		(*argv)++;
		(*argc)--;
		handled++;
	}
	return handled;
}
Beispiel #10
0
int main(int argc, const char **argv)
{
	int err;
	const char *cmd;
	char sbuf[STRERR_BUFSIZE];
	int value;

	/* libsubcmd init */
	exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT);
	pager_init(PERF_PAGER_ENVIRONMENT);

	/* The page_size is placed in util object. */
	page_size = sysconf(_SC_PAGE_SIZE);
	cache_line_size(&cacheline_size);

	if (sysctl__read_int("kernel/perf_event_max_stack", &value) == 0)
		sysctl_perf_event_max_stack = value;

	if (sysctl__read_int("kernel/perf_event_max_contexts_per_stack", &value) == 0)
		sysctl_perf_event_max_contexts_per_stack = value;

	cmd = extract_argv0_path(argv[0]);
	if (!cmd)
		cmd = "perf-help";

	srandom(time(NULL));

	perf_config__init();
	err = perf_config(perf_default_config, NULL);
	if (err)
		return err;
	set_buildid_dir(NULL);

	/* get debugfs/tracefs mount point from /proc/mounts */
	tracing_path_mount();

	/*
	 * "perf-xxxx" is the same as "perf xxxx", but we obviously:
	 *
	 *  - cannot take flags in between the "perf" and the "xxxx".
	 *  - cannot execute it externally (since it would just do
	 *    the same thing over again)
	 *
	 * So we just directly call the internal command handler. If that one
	 * fails to handle this, then maybe we just run a renamed perf binary
	 * that contains a dash in its name. To handle this scenario, we just
	 * fall through and ignore the "xxxx" part of the command string.
	 */
	if (strstarts(cmd, "perf-")) {
		cmd += 5;
		argv[0] = cmd;
		handle_internal_command(argc, argv);
		/*
		 * If the command is handled, the above function does not
		 * return undo changes and fall through in such a case.
		 */
		cmd -= 5;
		argv[0] = cmd;
	}
	if (strstarts(cmd, "trace")) {
#if defined(HAVE_LIBAUDIT_SUPPORT) || defined(HAVE_SYSCALL_TABLE_SUPPORT)
		setup_path();
		argv[0] = "trace";
		return cmd_trace(argc, argv);
#else
		fprintf(stderr,
			"trace command not available: missing audit-libs devel package at build time.\n");
		goto out;
#endif
	}
	/* Look for flags.. */
	argv++;
	argc--;
	handle_options(&argv, &argc, NULL);
	commit_pager_choice();

	if (argc > 0) {
		if (strstarts(argv[0], "--"))
			argv[0] += 2;
	} else {
		/* The user didn't specify a command; give them help */
		printf("\n usage: %s\n\n", perf_usage_string);
		list_common_cmds_help();
		printf("\n %s\n\n", perf_more_info_string);
		goto out;
	}
	cmd = argv[0];

	test_attr__init();

	/*
	 * We use PATH to find perf commands, but we prepend some higher
	 * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH
	 * environment, and the $(perfexecdir) from the Makefile at build
	 * time.
	 */
	setup_path();
	/*
	 * Block SIGWINCH notifications so that the thread that wants it can
	 * unblock and get syscalls like select interrupted instead of waiting
	 * forever while the signal goes to some other non interested thread.
	 */
	pthread__block_sigwinch();

	perf_debug_setup();

	while (1) {
		static int done_help;

		run_argv(&argc, &argv);

		if (errno != ENOENT)
			break;

		if (!done_help) {
			cmd = argv[0] = help_unknown_cmd(cmd);
			done_help = 1;
		} else
			break;
	}

	fprintf(stderr, "Failed to run command '%s': %s\n",
		cmd, str_error_r(errno, sbuf, sizeof(sbuf)));
out:
	return 1;
}
Beispiel #11
0
int main(void)
{
	void *ctx = tal(NULL, char);
	char *p;
	bool test_net;
	struct protocol_address addr, addr2;
	struct protocol_pubkey pubkey, pubkey2;
	EC_KEY *key;

	memset(&addr, 0xFF, sizeof(addr));
	/* Normal net */
	p = pettycoin_to_base58(ctx, false, &addr, false);
	assert(tal_parent(p) == ctx);
	assert(p[0] == 'P');
	assert(strlen(p) < BASE58_ADDR_MAX_LEN);
	assert(strspn(p, enc) == strlen(p));
	memset(&addr2, 0, sizeof(addr2));
	assert(pettycoin_from_base58(&test_net, &addr2, p, strlen(p)));
	assert(test_net == false);
	assert(structeq(&addr, &addr2));

	/* Test net */
	p = pettycoin_to_base58(ctx, true, &addr, false);
	assert(tal_parent(p) == ctx);
	assert(p[0] == 'q');
	assert(strlen(p) < BASE58_ADDR_MAX_LEN);
	assert(strspn(p, enc) == strlen(p));
	memset(&addr2, 0, sizeof(addr2));
	assert(pettycoin_from_base58(&test_net, &addr2, p, strlen(p)));
	assert(test_net == true);
	assert(structeq(&addr, &addr2));

	/* Bitcoin-style, normal net */
	p = pettycoin_to_base58(ctx, false, &addr, true);
	assert(tal_parent(p) == ctx);
	assert(strstarts(p, "P-1"));
	assert(strlen(p) < BASE58_ADDR_MAX_LEN + 2);
	assert(strspn(p+2, enc) == strlen(p+2));
	memset(&addr2, 0, sizeof(addr2));
	assert(pettycoin_from_base58(&test_net, &addr2, p, strlen(p)));
	assert(test_net == false);
	assert(structeq(&addr, &addr2));

	/* Bitcoin-style, test net */
	p = pettycoin_to_base58(ctx, true, &addr, true);
	assert(tal_parent(p) == ctx);
	assert(strstarts(p, "P-m") || strstarts(p, "P-n"));
	assert(strlen(p) < BASE58_ADDR_MAX_LEN + 2);
	assert(strspn(p+2, enc) == strlen(p+2));
	memset(&addr2, 0, sizeof(addr2));
	assert(pettycoin_from_base58(&test_net, &addr2, p, strlen(p)));
	assert(test_net == true);
	assert(structeq(&addr, &addr2));

	/* From our test gateway key */
	key = key_from_base58("P-cRhETWFwVpi7q8Vjs7KqvYYGZC5htvT3ddnd9hJk5znSohTBHRkT",
			      strlen("P-cRhETWFwVpi7q8Vjs7KqvYYGZC5htvT3ddnd9hJk5znSohTBHRkT"),
			      &test_net, &pubkey);
	assert(key);
	assert(test_net == true);

	/* Check pubkey is correct. */
	pubkey_to_addr(&pubkey, &addr);
	p = pettycoin_to_base58(ctx, true, &addr, true);
	assert(streq(p, "P-muzRJJzenB7uKzokx21W2QGobfDEZfiH1u"));

	/* Check we can return it OK (bitcoin style) */
	p = key_to_base58(ctx, true, key, true);
	assert(streq(p, "P-cRhETWFwVpi7q8Vjs7KqvYYGZC5htvT3ddnd9hJk5znSohTBHRkT"));

	/* Now, turn it into pettcoin-style key. */
	p = key_to_base58(ctx, true, key, false);
	assert(strspn(p, enc) == strlen(p));

	/* Convert back, check it is OK. */
	EC_KEY_free(key);
	key = key_from_base58(p, strlen(p), &test_net, &pubkey2);
	assert(key);
	assert(test_net == true);
	assert(structeq(&pubkey, &pubkey2));
	EC_KEY_free(key);

	/* FIXME: Test non-test network keys! */

	tal_free(ctx);
	return 0;
}
Beispiel #12
0
static char *ask_process(const tal_t *ctx,
			 const char *name,
			 const char *arg1,
			 const char *arg2,
			 const char *arg3,
			 const char *arg4,
			 const char *arg5)
{
	struct json_result *response = new_json_result(ctx);

	if (streq(name, "bitcoind")) {
		assert(streq(arg1, "-testnet"));
		if (streq(arg2, "listtransactions")) {
			unsigned int i, num, skip;

			assert(streq(arg3, "gateway"));
			num = atoi(arg4 ? arg4 : "10");
			assert(num);
			skip = atoi(arg5 ? arg5 : "0");

			json_array_start(response, NULL);
			/* Like bitcoind, list oldest first. */
			for (i = skip; i < skip+num; i++) {
				unsigned int confs;

				if (i >= ARRAY_SIZE(listtxs_response))
					break;
				/* We only show one the first time. */
				if (i > sleeps)
					break;
				/* First one is 16 confs, then 4, 1, then 0,
				 * plus one each time you ask. */
				confs = (1 << ((ARRAY_SIZE(listtxs_response)
						- i) * 2)) + sleeps;

				result_append_fmt(response, listtxs_response[i],
						  confs);
			}
			json_array_end(response);
			assert(!response->indent);
			return response->s;
		} else if (streq(arg2, "getrawtransaction")) {
			unsigned int i;

			/* We only do verbose mode */
			assert(streq(arg4, "1"));
			assert(arg5 == NULL);

			/* Search through responses for this txid */
			for (i = 0; i < ARRAY_SIZE(getrawtxs_response); i++) {
				const char *p;
				p = strstr(getrawtxs_response[i],
					   "    \"txid\" : \"");
				if (strstarts(p + strlen("    \"txid\" : \""),
					      arg3))
					return tal_strdup(ctx,
							  getrawtxs_response[i]);
			}
		} else if (streq(arg2, "getinfo")) {
			return tal_strdup(ctx, getinfo_response);
		} else if (streq(arg2, "sendtoaddress")) {
			if (mark_off_payment(arg3,
					     amount_in_satoshis(arg4,
								strlen(arg4))))
				return tal_strdup(ctx, "some-new-bitcoin-txid");
		}
	} else if (streq(name, "pettycoin-tx")) {
		assert(streq(arg1, "--no-fee"));
		assert(streq(arg2, "from-gateway"));
		assert(streq(arg3, "FAKE-gateway-privkey"));

		if (mark_off_payment(arg4, atol(arg5)))
			return tal_fmt(ctx, "raw-transaction-%s", arg4);
	} else if (streq(name, "pettycoin-query")) {
		assert(streq(arg1, "sendrawtransaction"));
		assert(strstarts(arg2, "raw-transaction-"));
		assert(arg3 == NULL);
		assert(arg4 == NULL);
		assert(arg5 == NULL);
		return tal_fmt(ctx, "txid for %s", arg2);
	}

	printf("ask_process: name=%s arg1=%s arg2=%s arg3=%s arg4=%s arg5=%s",
	       name, arg1, arg2, arg3, arg4, arg5);
	return NULL;
}
Beispiel #13
0
/* Takes complete update history, gets summary of last state. */
struct channel_state *gather_updates(const tal_t *ctx,
                                     const OpenChannel *o1, const OpenChannel *o2,
                                     const OpenAnchor *oa, uint64_t fee,
                                     char **argv,
                                     size_t *num_updates,
                                     struct sha256 *our_rhash,
                                     struct sha256 *their_rhash,
                                     struct signature *their_commit_sig)
{
    Signature *sig = NULL;
    struct sha256 old_our_rhash, old_their_rhash, rhash1, rhash2;
    struct channel_state *cstate;

    /* Start sanity check. */
    cstate = initial_funding(NULL, o1, o2, oa, fee);
    if (!cstate)
        errx(1, "Invalid open combination (need 1 anchor offer)");

    /* If they don't want these, use dummy ones. */
    if (!our_rhash)
        our_rhash = &rhash1;

    if (!their_rhash)
        their_rhash = &rhash2;

    proto_to_sha256(o1->revocation_hash, our_rhash);
    proto_to_sha256(o2->revocation_hash, their_rhash);

    assert(tal_count(cstate->a.htlcs) == 0);
    assert(tal_count(cstate->b.htlcs) == 0);

    /* If o2 sent anchor, it contains their commit sig. */
    if (o2->anch == OPEN_CHANNEL__ANCHOR_OFFER__WILL_CREATE_ANCHOR)
        sig = oa->commit_sig;

    if (num_updates)
        *num_updates = 0;
    while (*argv) {
        int64_t delta, amount;
        size_t n;
        bool received;
        Pkt *pkt;

        /* + marks messages sent by us, - for messages from them */
        if (strstarts(*argv, "+")) {
            received = false;
        } else if (strstarts(*argv, "-")) {
            received = true;
        } else
            errx(1, "%s does not start with +/-", *argv);

        pkt = any_pkt_from_file(*argv + 1);
        switch (pkt->pkt_case) {
        case PKT__PKT_OPEN_COMMIT_SIG:
            if (received)
                sig = pkt->open_commit_sig->sig;
            break;
        case PKT__PKT_UPDATE_ADD_HTLC:
            amount = pkt->update_add_htlc->amount_msat;
            if (received) {
                if (!funding_delta(o2, o1, oa, 0, amount,
                                   &cstate->b, &cstate->a))
                    errx(1, "Impossible htlc %llu %s",
                         (long long)amount, *argv);
                add_htlc(&cstate->b, pkt->update_add_htlc,
                         *argv);
            } else {
                if (!funding_delta(o1, o2, oa, 0, amount,
                                   &cstate->a, &cstate->b))
                    errx(1, "Impossible htlc %llu %s",
                         (long long)amount, *argv);
                add_htlc(&cstate->a, pkt->update_add_htlc,
                         *argv);
            }

            update_rhash(pkt->update_add_htlc->revocation_hash,
                         received, num_updates,
                         &old_our_rhash, &old_their_rhash,
                         our_rhash, their_rhash);
            break;

        case PKT__PKT_UPDATE_TIMEDOUT_HTLC:
            if (received) {
                n = find_htlc(&cstate->b,
                              pkt->update_timedout_htlc->r_hash);
                if (n == tal_count(cstate->b.htlcs))
                    errx(1, "Unknown R hash in %s", *argv);
                amount = cstate->b.htlcs[n]->amount_msat;
                if (!funding_delta(o2, o1, oa, 0, -amount,
                                   &cstate->b, &cstate->a))
                    errx(1, "Impossible htlc %llu %s",
                         (long long)amount, *argv);
                remove_htlc(&cstate->b, n);
            } else {
                n = find_htlc(&cstate->a,
                              pkt->update_timedout_htlc->r_hash);
                if (n == tal_count(cstate->a.htlcs))
                    errx(1, "Unknown R hash in %s", *argv);
                amount = cstate->a.htlcs[n]->amount_msat;
                if (!funding_delta(o1, o2, oa, 0, -amount,
                                   &cstate->a, &cstate->b))
                    errx(1, "Impossible htlc %llu %s",
                         (long long)amount, *argv);
                remove_htlc(&cstate->a, n);
            }
            update_rhash(pkt->update_timedout_htlc->revocation_hash,
                         received, num_updates,
                         &old_our_rhash, &old_their_rhash,
                         our_rhash, their_rhash);
            break;

        /* HTLC acceptor sends this to initiator. */
        case PKT__PKT_UPDATE_ROUTEFAIL_HTLC:
            if (received) {
                n = find_htlc(&cstate->a,
                              pkt->update_routefail_htlc->r_hash);
                if (n == tal_count(cstate->a.htlcs))
                    errx(1, "Unknown R hash in %s", *argv);
                amount = cstate->a.htlcs[n]->amount_msat;
                if (!funding_delta(o1, o2, oa, 0, -amount,
                                   &cstate->a, &cstate->b))
                    errx(1, "Impossible htlc %llu %s",
                         (long long)amount, *argv);
                remove_htlc(&cstate->a, n);
            } else {
                n = find_htlc(&cstate->b,
                              pkt->update_routefail_htlc->r_hash);
                if (n == tal_count(cstate->b.htlcs))
                    errx(1, "Unknown R hash in %s", *argv);
                amount = cstate->b.htlcs[n]->amount_msat;
                if (!funding_delta(o2, o1, oa, 0, -amount,
                                   &cstate->b, &cstate->a))
                    errx(1, "Impossible htlc %llu %s",
                         (long long)amount, *argv);
                remove_htlc(&cstate->b, n);
            }
            update_rhash(pkt->update_routefail_htlc->revocation_hash,
                         received, num_updates,
                         &old_our_rhash, &old_their_rhash,
                         our_rhash, their_rhash);
            break;

        case PKT__PKT_UPDATE_FULFILL_HTLC: {
            struct sha256 r_hash, r_val;
            Sha256Hash *rh;

            /* Get hash, to find the HTLC. */
            proto_to_sha256(pkt->update_fulfill_htlc->r, &r_val);
            sha256(&r_hash, &r_val, sizeof(r_val));
            rh = sha256_to_proto(ctx, &r_hash);

            if (received) {
                /* HTLC was us->them, funds go to them. */
                n = find_htlc(&cstate->a, rh);
                if (n == tal_count(cstate->a.htlcs))
                    errx(1, "Unknown R hash in %s", *argv);
                amount = cstate->a.htlcs[n]->amount_msat;
                if (!funding_delta(o1, o2, oa, amount, -amount,
                                   &cstate->a, &cstate->b))
                    errx(1, "Impossible htlc %llu %s",
                         (long long)amount, *argv);
                remove_htlc(&cstate->a, n);
            } else {
                /* HTLC was them->us, funds go to us. */
                n = find_htlc(&cstate->b, rh);
                if (n == tal_count(cstate->b.htlcs))
                    errx(1, "Unknown R hash in %s", *argv);
                amount = cstate->b.htlcs[n]->amount_msat;
                if (!funding_delta(o2, o1, oa, amount, -amount,
                                   &cstate->b, &cstate->a))
                    errx(1, "Impossible htlc %llu %s",
                         (long long)amount, *argv);
                remove_htlc(&cstate->b, n);
            }
            update_rhash(pkt->update_fulfill_htlc->revocation_hash,
                         received, num_updates,
                         &old_our_rhash, &old_their_rhash,
                         our_rhash, their_rhash);
            break;
        }

        case PKT__PKT_UPDATE:
            if (received)
                delta = -pkt->update->delta_msat;
            else
                delta = pkt->update->delta_msat;
            if (!funding_delta(o1, o2, oa, delta, 0,
                               &cstate->a, &cstate->b))
                errx(1, "Impossible funding update %lli %s",
                     (long long)delta, *argv);

            update_rhash(pkt->update->revocation_hash,
                         received, num_updates,
                         &old_our_rhash, &old_their_rhash,
                         our_rhash, their_rhash);
            break;
        case PKT__PKT_UPDATE_ACCEPT:
            if (received)
                sig = pkt->update_accept->sig;

            /* Does not increase num_updates */
            update_rhash(pkt->update_accept->revocation_hash,
                         received, NULL,
                         &old_our_rhash, &old_their_rhash,
                         our_rhash, their_rhash);
            break;
        case PKT__PKT_UPDATE_SIGNATURE:
            if (received) {
                sig = pkt->update_signature->sig;
                check_preimage(pkt->update_signature
                               ->revocation_preimage,
                               &old_their_rhash, their_rhash,
                               *argv);
            } else {
                check_preimage(pkt->update_signature
                               ->revocation_preimage,
                               &old_our_rhash, our_rhash,
                               *argv);
            }
            break;
        case PKT__PKT_UPDATE_COMPLETE:
            if (received) {
                check_preimage(pkt->update_complete
                               ->revocation_preimage,
                               &old_their_rhash, their_rhash,
                               *argv);
            } else {
                check_preimage(pkt->update_complete
                               ->revocation_preimage,
                               &old_our_rhash, our_rhash,
                               *argv);
            }
            break;
        default:
            errx(1, "Unexpected packet type %u", pkt->pkt_case);
        }
        argv++;
    }

    if (their_commit_sig) {
        if (!sig)
            errx(1, "No commit signature message found");
        if (!proto_to_signature(sig, their_commit_sig))
            errx(1, "Invalid signature");
    }

    return cstate;
}
Beispiel #14
0
int
main(int argc, char **argv)
{
	int rv = -1;
	int opt;
	char *dstr = NULL;
	char *cstr = NULL;
	char *wstr = NULL;
	char *sstr = NULL;
	int aopt = 0;
	int iopt = 0;
	int vopt = 0;
	int eopt = 0;
	int oopt = 0;
	int Copt = 0;
	int sopt = 0;
	int ropt = 0;
	int ovopt = 0;
	mlist_t *mlistp = NULL;

	(void) setlocale(LC_ALL, "");
	(void) textdomain(TEXT_DOMAIN);

	while ((opt = getopt(argc, argv, "Cd:c:w:fs:r:ivhaeo")) != EOF) {
		switch (opt) {
		case 'C':
			Copt++;
			break;
		case 'a':
			aopt++;
			break;
		case 'e':
			eopt++;
			break;
		case 'f':
			ovopt++;
			break;
		case 'o':
			oopt++;
			break;
		case 'd':
			dstr = optarg;
			break;

		case 'c':
			cstr = strdup(optarg);
			break;
		case 'w':
			wstr = strdup(optarg);
			break;
		case 's':
			sopt++;
			sstr = strdup(optarg);
			break;
		case 'r':
			ropt++;
			sstr = strdup(optarg);
			break;
		case 'i':
			iopt++;
			break;
		case 'v':
			vopt++;
			break;
		case 'h':
			help();
			rv = 0;
			goto OUT;
		default:
			help();
			rv = EINVAL;
			goto OUT;
		}
	}

	if (((eopt || oopt) && (Copt || sopt || ropt)) ||
	    (Copt && cstr) ||
	    ((Copt || cstr) && (sopt || ropt)) ||
	    (aopt && dstr) ||
	    (sopt && ropt)) {
		warn(_("Illegal combination of options.\n"));
		rv = EINVAL;
		goto OUT;
	}

	if ((Copt) && (dstr == NULL)) {
		/* asume -a when dumping controls with -C */
		aopt++;
	}

	if ((!aopt) && (dstr == NULL)) {
		/* if no mixer specified, assume a default */
		dstr = getenv("AUDIODEV");
		if (dstr == NULL) {
			dstr = "/dev/audio";
		}
	}

	if (oopt) {
		/* legacy option, nuke it */
		warn(_("Cannot disable audio mixer\n"));
		rv = EINVAL;
		goto OUT;
	}

	if (dstr != NULL) {
		char	scratch[MAXPATHLEN + 1];
		char	*s;
		char *bn;
		int num = -1;
		/*
		 * User may have specified:
		 *
		 * /dev/dsp[<num>]
		 * /dev/mixer[<num>]
		 * /dev/audio[<num>9]
		 * /dev/audioctl[<num>]
		 * /dev/sound/<num>{,ctl,dsp,mixer}
		 * /dev/sound/<driver>:<num>{,ctl,dsp,mixer}
		 *
		 * We want to deal only with SADA names though.
		 */

		if (strcmp(dstr, "/dev/mixer") == 0) {
			/* /dev/mixer node doesn't point to real hw */
			dstr = "/dev/dsp";
		}
		if ((bn = strrchr(dstr, '/')) != NULL) {
			bn++;
		} else {
			bn = dstr;
		}
		if ((strstarts(dstr, "/dev/sound/") == 0) &&
		    ((strrchr(dstr, ':')) != NULL)) {
			char	*colon;
			int	n;

			(void) strlcpy(scratch, dstr, sizeof (scratch));
			colon = strrchr(scratch, ':');
			colon++;
			n = atoi(colon);
			*colon = '\0';
			(void) snprintf(colon,
			    sizeof (scratch) - strlen(scratch), "%dmixer", n);

			dstr = strdup(scratch);

		} else if ((strcmp(dstr, "/dev/audio") == 0) ||
		    (strcmp(dstr, "/dev/audioctl") == 0) ||
		    (strcmp(dstr, "/dev/dsp") == 0)) {
			/*
			 * "default" device, read the link,
			 * ensuring NULL termination.
			 */
			if (readlink(dstr, scratch, MAXPATHLEN) >= 0) {
				scratch[MAXPATHLEN] = 0;
				if ((s = strchr(scratch, '/')) != NULL) {
					num = atoi(s + 1);
				}
			}

		} else if ((strstarts(dstr, "/dev/sound/") == 0) &&
		    (isdigit(bn[0]))) {
			num = atoi(bn);
		}
		if (num >= 0) {
			/* Convert SADA name to OSS name */
			(void) snprintf(scratch, sizeof (scratch),
			    "/dev/mixer%d", num);
			dstr = strdup(scratch);
		} else {
			dstr = strdup(dstr);
		}
	}

	if (wstr != NULL && cstr == NULL) {
		warn(_("Control value specified without name\n"));
		rv = EINVAL;
		goto OUT;
	}

	if ((cstr == NULL) && (Copt == 0) && (eopt == 0) &&
	    (ropt == 0) && (sopt == 0)) {
		iopt = 1;
	}

	rv = mixers_getinfo(dstr, &mlistp);
	if (rv != 0)
		goto OUT;

	if (wstr != NULL) {
		rv = mixers_set(mlistp, cstr, wstr, vopt);
		goto OUT;
	}

	if (ropt) {
		rv = mixers_restore(mlistp, sstr, vopt);
		goto OUT;
	}

	if (sopt) {
		rv = mixers_save(mlistp, sstr, ovopt, vopt);
		goto OUT;
	}

	rv = mixers_sav_prt(stdout, 0, mlistp, cstr, eopt, iopt, vopt);
	if (rv != 0)
		goto OUT;

	rv = 0;

OUT:
	if (dstr != NULL)
		free(dstr);
	if (cstr != NULL)
		free(cstr);
	if (wstr != NULL)
		free(wstr);
	if (sstr != NULL)
		free(sstr);

	mixers_free(&mlistp);
	return (rv);
}
Beispiel #15
0
static void check_has_license(struct manifest *m,
			      unsigned int *timeleft, struct score *score)
{
	char buf[PATH_MAX];
	ssize_t len;
	char *license = path_join(m, m->dir, "LICENSE");
	const char *expected;
	struct doc_section *d;
	const char *prefix = link_prefix(m);

	d = find_license_tag(m);
	if (!d) {
		score->error = tal_strdup(score, "No License: tag in _info");
		return;
	}

	m->license = which_license(d);
	if (m->license == LICENSE_UNKNOWN) {
		score_file_error(score, m->info_file, d->srcline,
				 "WARNING: unknown License: in _info: %s",
				 d->lines[0]);
		/* FIXME: For historical reasons, don't fail here. */
		score->pass = true;
		return;
	}

	/* If they have a license tag at all, we pass. */
	score->pass = true;

	expected = expected_link(m, prefix, m->license);

	len = readlink(license, buf, sizeof(buf));
	if (len < 0) {
		/* Could be a real file... OK if not a standard license. */
		if (errno == EINVAL) {
			if (!expected) {
				score->score = score->total;
				return;
			}
			score->error
				= tal_fmt(score,
					  "License in _info is '%s',"
					  " expect LICENSE symlink '%s'",
					  d->lines[0], expected);
			return;
		}
		if (errno == ENOENT) {
			/* Public domain doesn't really need a file. */
			if (m->license == LICENSE_PUBLIC_DOMAIN) {
				score->score = score->total;
				return;
			}
			score->error = tal_strdup(score,
						     "LICENSE does not exist");
			if (expected)
				license_exists.handle = handle_license_link;
			return;
		}
		err(1, "readlink on %s", license);
	}
	if (len >= sizeof(buf))
		errx(1, "Reading symlink %s gave huge result", license);

	buf[len] = '\0';

	if (!strstarts(buf, prefix)) {
		score->error = tal_fmt(score,
				       "Expected symlink into %s not %s",
				       prefix, buf);
		return;
	}

	if (!expected) {
		score->error = tal_fmt(score,
				       "License in _info is unknown '%s',"
				       " but LICENSE symlink is '%s'",
				       d->lines[0], buf);
		return;
	}

	if (!streq(buf, expected)) {
		score->error = tal_fmt(score,
				       "Expected symlink to %s not %s",
				       expected, buf);
		return;
	}
	score->pass = true;
	score->score = score->total;
}
Beispiel #16
0
int main(int argc, char *argv[])
{
	unsigned int i;
	const char *type;
	const char *function = NULL;

	if (argc < 3)
		errx(1, "Usage: doc_extract [--function=<funcname>] TYPE <file>...\n"
		     "Where TYPE is functions|author|license|maintainer|summary|description|example|see_also|all");

	if (strstarts(argv[1], "--function=")) {
		function = argv[1] + strlen("--function=");
		argv++;
		argc--;
	}

	type = argv[1];
	for (i = 2; i < argc; i++) {
		char *file, **lines;
		struct list_head *list;
		struct doc_section *d;

		file = grab_file(NULL, argv[i], NULL);
		if (!file)
			err(1, "Reading file %s", argv[i]);
		lines = strsplit(file, file, "\n");

		list = extract_doc_sections(lines);
		if (list_empty(list))
			errx(1, "No documentation in file %s", argv[i]);
		talloc_free(file);

		if (streq(type, "functions")) {
			const char *last = NULL;
			list_for_each(list, d, list) {
				if (d->function) {
					if (!last || !streq(d->function, last))
						printf("%s\n", d->function);
					last = d->function;
				}
			}
		} else {
			unsigned int j;
			list_for_each(list, d, list) {
				if (function) {
					if (!d->function)
						continue;
					if (!streq(d->function, function))
						continue;
				}
				if (streq(type, "all"))
					printf("%s:\n", d->type);
				else if (!typematch(d->type, type))
					continue;

				for (j = 0; j < d->num_lines; j++)
					printf("%s\n", d->lines[j]);
			}
		}
		talloc_free(list);
	}
Beispiel #17
0
static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
                          const struct option *options)
{
	const char *arg_end = strchr(arg, '=');
	const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
	int abbrev_flags = 0, ambiguous_flags = 0;

	if (!arg_end)
		arg_end = arg + strlen(arg);

retry:
	for (; options->type != OPTION_END; options++) {
		const char *rest;
		int flags = 0;

		if (!options->long_name)
			continue;

		rest = skip_prefix(arg, options->long_name);
		if (options->type == OPTION_ARGUMENT) {
			if (!rest)
				continue;
			if (*rest == '=')
				return opterror(options, "takes no value", flags);
			if (*rest)
				continue;
			p->out[p->cpidx++] = arg - 2;
			return 0;
		}
		if (!rest) {
			if (strstarts(options->long_name, "no-")) {
				/*
				 * The long name itself starts with "no-", so
				 * accept the option without "no-" so that users
				 * do not have to enter "no-no-" to get the
				 * negation.
				 */
				rest = skip_prefix(arg, options->long_name + 3);
				if (rest) {
					flags |= OPT_UNSET;
					goto match;
				}
				/* Abbreviated case */
				if (strstarts(options->long_name + 3, arg)) {
					flags |= OPT_UNSET;
					goto is_abbreviated;
				}
			}
			/* abbreviated? */
			if (!strncmp(options->long_name, arg, arg_end - arg)) {
is_abbreviated:
				if (abbrev_option) {
					/*
					 * If this is abbreviated, it is
					 * ambiguous. So when there is no
					 * exact match later, we need to
					 * error out.
					 */
					ambiguous_option = abbrev_option;
					ambiguous_flags = abbrev_flags;
				}
				if (!(flags & OPT_UNSET) && *arg_end)
					p->opt = arg_end + 1;
				abbrev_option = options;
				abbrev_flags = flags;
				continue;
			}
			/* negated and abbreviated very much? */
			if (strstarts("no-", arg)) {
				flags |= OPT_UNSET;
				goto is_abbreviated;
			}
			/* negated? */
			if (strncmp(arg, "no-", 3))
				continue;
			flags |= OPT_UNSET;
			rest = skip_prefix(arg + 3, options->long_name);
			/* abbreviated and negated? */
			if (!rest && strstarts(options->long_name, arg + 3))
				goto is_abbreviated;
			if (!rest)
				continue;
		}
match:
		if (*rest) {
			if (*rest != '=')
				continue;
			p->opt = rest + 1;
		}
		return get_value(p, options, flags);
	}

	if (ambiguous_option) {
		 fprintf(stderr,
			 " Error: Ambiguous option: %s (could be --%s%s or --%s%s)\n",
			 arg,
			 (ambiguous_flags & OPT_UNSET) ?  "no-" : "",
			 ambiguous_option->long_name,
			 (abbrev_flags & OPT_UNSET) ?  "no-" : "",
			 abbrev_option->long_name);
		 return -1;
	}
	if (abbrev_option)
		return get_value(p, abbrev_option, abbrev_flags);

	if (options->parent) {
		options = options->parent;
		goto retry;
	}

	return -2;
}