예제 #1
0
void
cmd_if_shell_callback(struct job *job)
{
	struct cmd_if_shell_data	*cdata = job->data;
	struct cmd_ctx			*ctx = &cdata->ctx;
	struct cmd_list			*cmdlist;
	char				*cause;

	if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0)
		return;

	if (cmd_string_parse(cdata->cmd, &cmdlist, &cause) != 0) {
		if (cause != NULL) {
			ctx->error(ctx, "%s", cause);
			xfree(cause);
		}
		return;
	}

	if (cmd_list_exec(cmdlist, ctx) < 0) {
		cmd_list_free(cmdlist);
		return;
	}

	cmd_list_free(cmdlist);
}
예제 #2
0
파일: control.c 프로젝트: CraZySacX/tmux
/* Control input callback. Read lines and fire commands. */
void
control_callback(struct client *c, int closed, __unused void *data)
{
	char			*line, *cause;
	struct cmd_list		*cmdlist;
	struct cmd		*cmd;
	struct cmdq_item	*item;

	if (closed)
		c->flags |= CLIENT_EXIT;

	for (;;) {
		line = evbuffer_readln(c->stdin_data, NULL, EVBUFFER_EOL_LF);
		if (line == NULL)
			break;
		if (*line == '\0') { /* empty line exit */
			c->flags |= CLIENT_EXIT;
			break;
		}

		if (cmd_string_parse(line, &cmdlist, NULL, 0, &cause) != 0) {
			item = cmdq_get_callback(control_error, cause);
			cmdq_append(c, item);
		} else {
			TAILQ_FOREACH(cmd, &cmdlist->list, qentry)
				cmd->flags |= CMD_CONTROL;
			item = cmdq_get_command(cmdlist, NULL, NULL, 0);
			cmdq_append(c, item);
			cmd_list_free(cmdlist);
		}

		free(line);
	}
}
예제 #3
0
void
cmd_if_shell_callback(struct job *job)
{
	struct cmd_if_shell_data	*cdata = job->data;
	struct cmd_q			*cmdq = cdata->cmdq, *cmdq1;
	struct cmd_list			*cmdlist;
	char				*cause, *cmd;

	if (cmdq->flags & CMD_Q_DEAD)
		return;

	if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0)
		cmd = cdata->cmd_else;
	else
		cmd = cdata->cmd_if;
	if (cmd == NULL)
		return;

	if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) {
		if (cause != NULL) {
			cmdq_error(cmdq, "%s", cause);
			free(cause);
		}
		return;
	}

	cmdq1 = cmdq_new(cmdq->client);
	cmdq1->emptyfn = cmd_if_shell_done;
	cmdq1->data = cdata;

	cdata->references++;
	cmdq_run(cmdq1, cmdlist, &cdata->mouse);
	cmd_list_free(cmdlist);
}
예제 #4
0
int
cmd_confirm_before_callback(void *data, const char *s)
{
	struct cmd_confirm_before_data	*cdata = data;
	struct client			*c = cdata->client;
	struct cmd_list			*cmdlist;
	char				*cause;

	if (c->flags & CLIENT_DEAD)
		return (0);

	if (s == NULL || *s == '\0')
		return (0);
	if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
		return (0);

	if (cmd_string_parse(cdata->cmd, &cmdlist, NULL, 0, &cause) != 0) {
		if (cause != NULL) {
			cmdq_error(c->cmdq, "%s", cause);
			free(cause);
		}
		return (0);
	}

	cmdq_run(c->cmdq, cmdlist);
	cmd_list_free(cmdlist);

	return (0);
}
예제 #5
0
int
cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx)
{
	struct args		*args = self->args;
	struct key_binding	*bd;
	int			 key;

	if (args_has(args, 'a')) {
		while (!SPLAY_EMPTY(&key_bindings)) {
			bd = SPLAY_ROOT(&key_bindings);
			SPLAY_REMOVE(key_bindings, &key_bindings, bd);
			cmd_list_free(bd->cmdlist);
			xfree(bd);
		}
		return (0);
	}

	key = key_string_lookup_string(args->argv[0]);
	if (key == KEYC_NONE) {
		ctx->error(ctx, "unknown key: %s", args->argv[0]);
		return (-1);
	}

	if (args_has(args, 't'))
		return (cmd_unbind_key_table(self, ctx, key));

	if (!args_has(args, 'n'))
		key |= KEYC_PREFIX;
	key_bindings_remove(key);
	return (0);
}
예제 #6
0
static int
cmd_confirm_before_callback(void *data, const char *s, __unused int done)
{
	struct cmd_confirm_before_data	*cdata = data;
	struct client			*c = cdata->client;
	struct cmd_list			*cmdlist;
	struct cmdq_item		*new_item;
	char				*cause;

	if (c->flags & CLIENT_DEAD)
		return (0);

	if (s == NULL || *s == '\0')
		return (0);
	if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
		return (0);

	cmdlist = cmd_string_parse(cdata->cmd, NULL, 0, &cause);
	if (cmdlist == NULL) {
		if (cause != NULL) {
			new_item = cmdq_get_callback(cmd_confirm_before_error,
			    cause);
		} else
			new_item = NULL;
	} else {
		new_item = cmdq_get_command(cmdlist, NULL, NULL, 0);
		cmd_list_free(cmdlist);
	}

	if (new_item != NULL)
		cmdq_append(c, new_item);

	return (0);
}
예제 #7
0
static void tmate_client_exec_cmd(struct tmate_unpacker *uk)
{
	struct cmd_q *cmd_q;
	struct cmd_list *cmdlist;
	char *cause;

	int client_id = unpack_int(uk);
	char *cmd_str = unpack_string(uk);

	if (cmd_string_parse(cmd_str, &cmdlist, NULL, 0, &cause) != 0) {
		tmate_failed_cmd(client_id, cause);
		free(cause);
		goto out;
	}

	/* error messages land in cfg_causes */
	ARRAY_FREE(&cfg_causes);

	cmd_q = cmdq_new(NULL);
	cmdq_run(cmd_q, cmdlist);
	cmd_list_free(cmdlist);
	cmdq_free(cmd_q);

	if (!ARRAY_EMPTY(&cfg_causes)) {
		cause = ARRAY_ITEM(&cfg_causes, 0);
		tmate_failed_cmd(client_id, cause);
		free(cause);
		ARRAY_FREE(&cfg_causes);
	}

out:
	free(cmd_str);
}
예제 #8
0
static void handle_exec_cmd_str(__unused struct tmate_session *session,
				struct tmate_unpacker *uk)
{
	struct cmd_q *cmd_q;
	struct cmd_list *cmdlist;
	char *cause;
	u_int i;

	int client_id = unpack_int(uk);
	char *cmd_str = unpack_string(uk);

	if (cmd_string_parse(cmd_str, &cmdlist, NULL, 0, &cause) != 0) {
		tmate_failed_cmd(client_id, cause);
		free(cause);
		goto out;
	}

	cmd_q = cmdq_new(NULL);
	cmdq_run(cmd_q, cmdlist, NULL);
	cmd_list_free(cmdlist);
	cmdq_free(cmd_q);

	/* error messages land in cfg_causes */
	for (i = 0; i < cfg_ncauses; i++) {
		tmate_failed_cmd(client_id, cfg_causes[i]);
		free(cfg_causes[i]);
	}

	free(cfg_causes);
	cfg_causes = NULL;
	cfg_ncauses = 0;

out:
	free(cmd_str);
}
예제 #9
0
int
cmd_confirm_before_callback(void *data, const char *s)
{
	struct cmd_confirm_before_data	*cdata = data;
	struct client			*c = cdata->c;
	struct cmd_list			*cmdlist;
	struct cmd_ctx	 	 	*ctx;
	char				*cause;

	if (s == NULL || *s == '\0')
		return (0);
	if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
		return (0);

	if (cmd_string_parse(cdata->cmd, &cmdlist, &cause) != 0) {
		if (cause != NULL) {
			*cause = toupper((u_char) *cause);
			status_message_set(c, "%s", cause);
			free(cause);
		}
		return (0);
	}

	ctx = cmd_get_ctx();
	ctx->curclient = c;
	ctx->error = key_bindings_error;
	ctx->print = key_bindings_print;
	ctx->info = key_bindings_info;

	cmd_list_exec(cmdlist, ctx);
	cmd_list_free(cmdlist);
	cmd_free_ctx(ctx);

	return (0);
}
예제 #10
0
void
key_bindings_clean(void)
{
	struct key_binding	*bd;

	while (!SPLAY_EMPTY(&dead_key_bindings)) {
		bd = SPLAY_ROOT(&dead_key_bindings);
		SPLAY_REMOVE(key_bindings, &dead_key_bindings, bd);
		cmd_list_free(bd->cmdlist);
		xfree(bd);
	}
}
예제 #11
0
파일: cfg.c 프로젝트: mosconi/openbsd
int
load_cfg(const char *path, struct cmd_q *cmdq, int quiet)
{
	FILE		*f;
	char		 delim[3] = { '\\', '\\', '\0' };
	u_int		 found;
	size_t		 line = 0;
	char		*buf, *cause1, *p;
	struct cmd_list	*cmdlist;

	log_debug("loading %s", path);
	if ((f = fopen(path, "rb")) == NULL) {
		if (errno == ENOENT && quiet)
			return (0);
		cfg_add_cause("%s: %s", path, strerror(errno));
		return (-1);
	}

	found = 0;
	while ((buf = fparseln(f, NULL, &line, delim, 0)) != NULL) {
		log_debug("%s: %s", path, buf);

		/* Skip empty lines. */
		p = buf;
		while (isspace((u_char) *p))
			p++;
		if (*p == '\0') {
			free(buf);
			continue;
		}

		/* Parse and run the command. */
		if (cmd_string_parse(p, &cmdlist, path, line, &cause1) != 0) {
			free(buf);
			if (cause1 == NULL)
				continue;
			cfg_add_cause("%s:%zu: %s", path, line, cause1);
			free(cause1);
			continue;
		}
		free(buf);

		if (cmdlist == NULL)
			continue;
		cmdq_append(cmdq, cmdlist, NULL);
		cmd_list_free(cmdlist);
		found++;
	}
	fclose(f);

	return (found);
}
예제 #12
0
파일: cmd-bind-key.c 프로젝트: ddollar/tmux
void
cmd_bind_key_free(struct cmd *self)
{
	struct cmd_bind_key_data	*data = self->data;

	if (data->cmdlist != NULL)
		cmd_list_free(data->cmdlist);
	if (data->tablename != NULL)
		xfree(data->tablename);
	if (data->modecmd != NULL)
		xfree(data->modecmd);
	xfree(data);
}
예제 #13
0
struct cmd_list *
cmd_list_parse(int argc, char **argv, char **cause)
{
	struct cmd_list	*cmdlist;
	struct cmd	*cmd;
	int		 i, lastsplit;
	size_t		 arglen, new_argc;
	char	       **new_argv;

	cmdlist = xmalloc(sizeof *cmdlist);
	TAILQ_INIT(cmdlist);

	lastsplit = 0;
	for (i = 0; i < argc; i++) {
		arglen = strlen(argv[i]);
		if (arglen == 0 || argv[i][arglen - 1] != ';')
			continue;
		argv[i][arglen - 1] = '\0';

		if (arglen > 1 && argv[i][arglen - 2] == '\\') {
			argv[i][arglen - 2] = ';';
			continue;
		}

		new_argc = i - lastsplit;
		new_argv = argv + lastsplit;
		if (arglen != 1)
			new_argc++;

		cmd = cmd_parse(new_argc, new_argv, cause);
		if (cmd == NULL)
			goto bad;
		TAILQ_INSERT_TAIL(cmdlist, cmd, qentry);

		lastsplit = i + 1;
	}

	if (lastsplit != argc) {
		cmd = cmd_parse(argc - lastsplit, argv + lastsplit, cause);
		if (cmd == NULL)
			goto bad;
		TAILQ_INSERT_TAIL(cmdlist, cmd, qentry);
	}

	return (cmdlist);

bad:
	cmd_list_free(cmdlist);
	return (NULL);
}
예제 #14
0
static void handle_exec_cmd(__unused struct tmate_session *session,
			    struct tmate_unpacker *uk)
{
	struct cmd_q *cmd_q;
	struct cmd_list *cmdlist;
	struct cmd *cmd;
	char *cause;
	u_int i;
	unsigned int argc;
	char **argv;

	int client_id = unpack_int(uk);

	argc = uk->argc;
	argv = xmalloc(sizeof(char *) * argc);
	for (i = 0; i < argc; i++)
		argv[i] = unpack_string(uk);

	cmd = cmd_parse(argc, argv, NULL, 0, &cause);
	if (!cmd) {
		tmate_failed_cmd(client_id, cause);
		free(cause);
		goto out;
	}

	cmdlist = xcalloc(1, sizeof *cmdlist);
	cmdlist->references = 1;
	TAILQ_INIT(&cmdlist->list);
	TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);

	cmd_q = cmdq_new(NULL);
	cmdq_run(cmd_q, cmdlist, NULL);
	cmd_list_free(cmdlist);
	cmdq_free(cmd_q);

	/* error messages land in cfg_causes */
	for (i = 0; i < cfg_ncauses; i++) {
		tmate_failed_cmd(client_id, cfg_causes[i]);
		free(cfg_causes[i]);
	}

	free(cfg_causes);
	cfg_causes = NULL;
	cfg_ncauses = 0;

out:
	cmd_free_argv(argc, argv);
}
예제 #15
0
파일: control.c 프로젝트: bholt/tmux
/* Control input callback. */
void
control_read_callback(unused struct bufferevent *bufev, void *data)
{
	struct client		*c = data;
	struct bufferevent	*out = c->stdout_event;
	char			*line;
	struct cmd_ctx		 ctx;
	struct cmd_list		*cmdlist;
	char			*cause;

	/* Read all available input lines. */
	line = evbuffer_readln(c->stdin_event->input, NULL, EVBUFFER_EOL_ANY);
	while (line) {
	    /* Parse command. */
	    ctx.msgdata = NULL;
	    ctx.cmdclient = NULL;
	    ctx.curclient = c;

	    ctx.error = control_msg_error;
	    ctx.print = control_msg_print;
	    ctx.info = control_msg_info;

	    if (cmd_string_parse(line, &cmdlist, &cause) != 0) {
		    /* Error */
		    if (cause) {
			    /* cause should always be set if there's an
			     * error.  */
			    evbuffer_add_printf(out->output,
						"%%error in line \"%s\": %s",
						line, cause);
			    bufferevent_write(out, "\n", 1);
			    xfree(cause);
		    }
	    } else {
		    /* Parsed ok. Run command. */
		    cmd_list_exec(cmdlist, &ctx);
		    cmd_list_free(cmdlist);
	    }

	    xfree(line);
	    /* Read input line. */
	    line = evbuffer_readln(c->stdin_event->input, NULL,
				   EVBUFFER_EOL_ANY);
	}
}
예제 #16
0
/* Control input callback. Read lines and fire commands. */
void
control_callback(struct client *c, int closed, unused void *data)
{
	char		*line, *cause;
	struct cmd_ctx	 ctx;
	struct cmd_list	*cmdlist;

	if (closed)
		c->flags |= CLIENT_EXIT;

	for (;;) {
		line = evbuffer_readln(c->stdin_data, NULL, EVBUFFER_EOL_LF);
		if (line == NULL)
			break;
		if (*line == '\0') { /* empty line exit */
			c->flags |= CLIENT_EXIT;
			break;
		}

		ctx.msgdata = NULL;
		ctx.cmdclient = NULL;
		ctx.curclient = c;

		ctx.error = control_msg_error;
		ctx.print = control_msg_print;
		ctx.info = control_msg_info;

		if (cmd_string_parse(line, &cmdlist, &cause) != 0) {
			control_write(c, "%%error in line \"%s\": %s", line,
			    cause);
			xfree(cause);
		} else {
			cmd_list_exec(cmdlist, &ctx);
			cmd_list_free(cmdlist);
		}

		xfree(line);
	}
}
예제 #17
0
파일: cmd-if-shell.c 프로젝트: willame/tmux
static void
cmd_if_shell_callback(struct job *job)
{
	struct cmd_if_shell_data	*cdata = job->data;
	struct client			*c = cdata->client;
	struct cmd_list			*cmdlist;
	struct cmdq_item		*new_item;
	char				*cause, *cmd, *file = cdata->file;
	u_int				 line = cdata->line;

	if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0)
		cmd = cdata->cmd_else;
	else
		cmd = cdata->cmd_if;
	if (cmd == NULL)
		goto out;

	cmdlist = cmd_string_parse(cmd, file, line, &cause);
	if (cmdlist == NULL) {
		if (cause != NULL)
			new_item = cmdq_get_callback(cmd_if_shell_error, cause);
		else
			new_item = NULL;
	} else {
		new_item = cmdq_get_command(cmdlist, NULL, &cdata->mouse, 0);
		cmd_list_free(cmdlist);
	}

	if (new_item != NULL) {
		if (cdata->item == NULL)
			cmdq_append(c, new_item);
		else
			cmdq_insert_after(cdata->item, new_item);
	}

out:
	if (cdata->item != NULL)
		cdata->item->flags &= ~CMDQ_WAITING;
}
/* Control input callback. Read lines and fire commands. */
void
control_callback(struct client *c, int closed, unused void *data)
{
	char		*line, *cause;
	struct cmd_list	*cmdlist;
	struct cmd	*cmd;

	if (closed)
		c->flags |= CLIENT_EXIT;

	for (;;) {
		line = evbuffer_readln(c->stdin_data, NULL, EVBUFFER_EOL_LF);
		if (line == NULL)
			break;
		if (*line == '\0') { /* empty line exit */
			c->flags |= CLIENT_EXIT;
			break;
		}

		if (cmd_string_parse(line, &cmdlist, NULL, 0, &cause) != 0) {
			c->cmdq->time = time(NULL);
			c->cmdq->number++;

			cmdq_guard(c->cmdq, "begin", 1);
			control_write(c, "parse error: %s", cause);
			cmdq_guard(c->cmdq, "error", 1);

			free(cause);
		} else {
			TAILQ_FOREACH(cmd, &cmdlist->list, qentry)
				cmd->flags |= CMD_CONTROL;
			cmdq_run(c->cmdq, cmdlist);
			cmd_list_free(cmdlist);
		}

		free(line);
	}
}
예제 #19
0
int
cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx)
{
	struct cmd_unbind_key_data	*data = self->data;
	struct key_binding		*bd;

	if (data == NULL)
		return (0);
	if (data->flag_all) {
		while (!SPLAY_EMPTY(&key_bindings)) {
			bd = SPLAY_ROOT(&key_bindings);
			SPLAY_REMOVE(key_bindings, &key_bindings, bd);
			cmd_list_free(bd->cmdlist);
			xfree(bd);
		}
	} else {
		if (data->tablename != NULL)
			return (cmd_unbind_key_table(self, ctx));

		key_bindings_remove(data->key);
	}

	return (0);
}
예제 #20
0
int
main(int argc, char **argv)
{
	struct client_ctx	 cctx;
	struct msg_command_data	 cmddata;
	struct buffer		*b;
	struct cmd_list		*cmdlist;
 	struct cmd		*cmd;
	struct pollfd	 	 pfd;
	struct hdr	 	 hdr;
	const char		*shell;
	struct passwd		*pw;
	char			*path, *label, *cause, *home, *pass = NULL;
	char			 cwd[MAXPATHLEN];
	int	 		 retcode, opt, flags, unlock, start_server;

	unlock = flags = 0;
	label = path = NULL;
        while ((opt = getopt(argc, argv, "28df:L:qS:uUVv")) != -1) {
                switch (opt) {
		case '2':
			flags |= IDENTIFY_256COLOURS;
			flags &= ~IDENTIFY_88COLOURS;
			break;
		case '8':
			flags |= IDENTIFY_88COLOURS;
			flags &= ~IDENTIFY_256COLOURS;
			break;
		case 'f':
			cfg_file = xstrdup(optarg);
			break;
		case 'L':
			if (path != NULL) {
				log_warnx("-L and -S cannot be used together");
				exit(1);
			}
			if (label != NULL)
				xfree(label);
			label = xstrdup(optarg);
			break;
		case 'S':
			if (label != NULL) {
				log_warnx("-L and -S cannot be used together");
				exit(1);
			}
			if (path != NULL)
				xfree(path);
			path = xstrdup(optarg);
			break;
		case 'q':
			be_quiet = 1;
			break;
		case 'u':
			flags |= IDENTIFY_UTF8;
			break;
		case 'U':
			unlock = 1;
			break;
		case 'd':
			flags |= IDENTIFY_HASDEFAULTS;
			break;
		case 'v':
			debug_level++;
			break;
		case 'V':
			printf("%s " BUILD "\n", __progname);
			exit(0);
                default:
			usage();
                }
        }
	argc -= optind;
	argv += optind;

	log_open_tty(debug_level);
	siginit();

	options_init(&global_options, NULL);
	options_set_number(&global_options, "bell-action", BELL_ANY);
	options_set_number(&global_options, "buffer-limit", 9);
	options_set_number(&global_options, "display-time", 750);
	options_set_number(&global_options, "history-limit", 2000);
	options_set_number(&global_options, "message-bg", 3);
	options_set_number(&global_options, "message-fg", 0);
	options_set_number(&global_options, "message-attr", GRID_ATTR_REVERSE);
	options_set_number(&global_options, "prefix", META);
	options_set_number(&global_options, "repeat-time", 500);
	options_set_number(&global_options, "set-titles", 1);
	options_set_number(&global_options, "lock-after-time", 0);
	options_set_number(&global_options, "set-remain-on-exit", 0);
	options_set_number(&global_options, "status", 1);
	options_set_number(&global_options, "status-bg", 2);
	options_set_number(&global_options, "status-fg", 0);
	options_set_number(&global_options, "status-attr", GRID_ATTR_REVERSE);
	options_set_number(&global_options, "status-interval", 15);
	options_set_number(&global_options, "status-left-length", 10);
	options_set_number(&global_options, "status-right-length", 40);
	options_set_string(&global_options, "status-left", "[#S]");
	options_set_string(
	    &global_options, "status-right", "\"#24T\" %%H:%%M %%d-%%b-%%y");
	options_set_number(&global_options, "status-keys", MODEKEY_EMACS);
	options_init(&global_window_options, NULL);
	options_set_number(&global_window_options, "aggressive-resize", 0);
	options_set_number(&global_window_options, "clock-mode-colour", 4);
	options_set_number(&global_window_options, "clock-mode-style", 1);
	options_set_number(&global_window_options, "force-height", 0);
	options_set_number(&global_window_options, "force-width", 0);
	options_set_number(&global_window_options, "automatic-rename", 1);
	options_set_number(&global_window_options, "mode-bg", 3);
	options_set_number(&global_window_options, "mode-fg", 0);
	options_set_number(
	    &global_window_options, "mode-attr", GRID_ATTR_REVERSE);
	options_set_number(&global_window_options, "mode-keys", MODEKEY_EMACS);
	options_set_number(&global_window_options, "monitor-activity", 0);
	options_set_number(&global_window_options, "utf8", 0);
	options_set_number(&global_window_options, "xterm-keys", 0);
 	options_set_number(&global_window_options, "remain-on-exit", 0);
	options_set_number(&global_window_options, "window-status-bg", 8);
	options_set_number(&global_window_options, "window-status-fg", 8);
	options_set_number(&global_window_options, "window-status-attr", 0);

	if (cfg_file == NULL) {
		home = getenv("HOME");
		if (home == NULL || *home == '\0') {
			pw = getpwuid(getuid());
			if (pw != NULL)
				home = pw->pw_dir;
			endpwent();
		}
		xasprintf(&cfg_file, "%s/%s", home, DEFAULT_CFG);
		if (access(cfg_file, R_OK) != 0) {
			xfree(cfg_file);
			cfg_file = NULL;
		}
	} else {
		if (access(cfg_file, R_OK) != 0) {
			log_warn("%s", cfg_file);
			exit(1);
		}
	}

	if (label == NULL)
		label = xstrdup("default");
	if (path == NULL && (path = makesockpath(label)) == NULL) {
		log_warn("can't create socket");
		exit(1);
	}
	xfree(label);

	shell = getenv("SHELL");
	if (shell == NULL || *shell == '\0') {
		pw = getpwuid(getuid());
		if (pw != NULL)
			shell = pw->pw_shell;
		endpwent();
		if (shell == NULL || *shell == '\0')
			shell = _PATH_BSHELL;
	}
	options_set_string(
	    &global_options, "default-command", "exec %s", shell);
	

	if (getcwd(cwd, sizeof cwd) == NULL) {
		log_warn("getcwd");
		exit(1);
	}
	options_set_string(&global_options, "default-path", "%s", cwd);

	if (unlock) {
		if (argc != 0) {
			log_warnx("can't specify a command when unlocking");
			exit(1);
		}
		cmdlist = NULL;
		if ((pass = getpass("Password: "******"%s", cause);
				exit(1);
			}
		}
		start_server = 0;
		TAILQ_FOREACH(cmd, cmdlist, qentry) {
			if (cmd->entry->flags & CMD_STARTSERVER) {
				start_server = 1;
				break;
			}
		}
	}
	
 	memset(&cctx, 0, sizeof cctx);
	if (client_init(path, &cctx, start_server, flags) != 0)
		exit(1);
	xfree(path);

	b = buffer_create(BUFSIZ);
	if (unlock) {
		cmd_send_string(b, pass);
		client_write_server(
		    &cctx, MSG_UNLOCK, BUFFER_OUT(b), BUFFER_USED(b));
	} else {
		cmd_list_send(cmdlist, b);
		cmd_list_free(cmdlist);
		client_fill_session(&cmddata);
		client_write_server2(&cctx, MSG_COMMAND,
		    &cmddata, sizeof cmddata, BUFFER_OUT(b), BUFFER_USED(b));
	}
	buffer_destroy(b);

	retcode = 0;
	for (;;) {
		pfd.fd = cctx.srv_fd;
		pfd.events = POLLIN;
		if (BUFFER_USED(cctx.srv_out) > 0)
			pfd.events |= POLLOUT;

		if (poll(&pfd, 1, INFTIM) == -1) {
			if (errno == EAGAIN || errno == EINTR)
				continue;
			fatal("poll failed");
		}

		if (buffer_poll(&pfd, cctx.srv_in, cctx.srv_out) != 0)
			goto out;

	restart:
		if (BUFFER_USED(cctx.srv_in) < sizeof hdr)
			continue;
		memcpy(&hdr, BUFFER_OUT(cctx.srv_in), sizeof hdr);
		if (BUFFER_USED(cctx.srv_in) < (sizeof hdr) + hdr.size)
			continue;
		buffer_remove(cctx.srv_in, sizeof hdr);

		switch (hdr.type) {
		case MSG_EXIT:
		case MSG_SHUTDOWN:
			goto out;
		case MSG_ERROR:
			retcode = 1;
			/* FALLTHROUGH */
		case MSG_PRINT:
			if (hdr.size > INT_MAX - 1)
				fatalx("bad MSG_PRINT size");
			log_info("%.*s",
			    (int) hdr.size, BUFFER_OUT(cctx.srv_in));
			if (hdr.size != 0)
				buffer_remove(cctx.srv_in, hdr.size);
			goto restart;
		case MSG_READY:
			retcode = client_main(&cctx);
			goto out;
		default:
			fatalx("unexpected command");
		}
	}

out:
	options_free(&global_options);
	options_free(&global_window_options);

	close(cctx.srv_fd);
	buffer_destroy(cctx.srv_in);
	buffer_destroy(cctx.srv_out);

#ifdef DEBUG
	xmalloc_report(getpid(), "client");
#endif
	return (retcode);
}
예제 #21
0
/* The following function deletes the value associated with a
** symbol.  The symbol can be either a terminal or nonterminal.
** "yymajor" is the symbol code, and "yypminor" is a pointer to
** the value.
*/
static void yy_destructor(
  yyParser *yypParser,    /* The parser */
  YYCODETYPE yymajor,     /* Type code for object to destroy */
  YYMINORTYPE *yypminor   /* The object to be destroyed */
){
  LineParserARG_FETCH;
  switch( yymajor ){
    /* Here is inserted the actions which take place when a
    ** terminal or non-terminal is destroyed.  This can happen
    ** when the symbol is popped from the stack during a
    ** reduce or during error processing or when a parser is 
    ** being destroyed before it is finished parsing.
    **
    ** Note: during a reduce, the only symbols destroyed are those
    ** which appear on the RHS of the rule, but which are not used
    ** inside the C code.
    */
      /* TERMINAL Destructor */
    case 1: /* REDIRECT_INPUT_FROM_FILE */
    case 2: /* ARGUMENT */
    case 3: /* REDIRECT_INPUT_FROM_FILE_DESCRIPTOR */
    case 4: /* REDIRECT_OUTPUT_TO_FILE */
    case 5: /* REDIRECT_OUTPUT_TO_FILE_DESCRIPTOR */
    case 6: /* REDIRECT_OUTPUT_APPEND_TO_FILE */
    case 7: /* PIPE */
    case 8: /* OR */
    case 9: /* AND */
    case 10: /* BACKGROUND */
    case 11: /* SEMICOLON */
{
#line 24 "line_parser.y"

    free((yypminor->yy0));

#line 416 "line_parser.c"
}
      break;
    case 13: /* redirection */
{
#line 29 "line_parser.y"

    redir_free((yypminor->yy4));

#line 425 "line_parser.c"
}
      break;
    case 14: /* command */
{
#line 33 "line_parser.y"

    cmd_free((yypminor->yy2));

#line 434 "line_parser.c"
}
      break;
    case 15: /* commandList */
{
#line 37 "line_parser.y"

    cmd_list_free((yypminor->yy13));

#line 443 "line_parser.c"
}
      break;
    case 16: /* start */
{
#line 41 "line_parser.y"

#line 450 "line_parser.c"
}
      break;
    default:  break;   /* If no destructor action specified: do nothing */
  }
}
예제 #22
0
파일: cfg.c 프로젝트: akracun/tmux
/*
 * Load configuration file. Returns -1 for an error with a list of messages in
 * causes. Note that causes must be initialised by the caller!
 */
enum cmd_retval
load_cfg(const char *path, struct cmd_ctx *ctx, struct causelist *causes)
{
	FILE		*f;
	u_int		 n;
	char		*buf, *copy, *line, *cause;
	size_t		 len, oldlen;
	struct cmd_list	*cmdlist;
	enum cmd_retval	 retval;

	if ((f = fopen(path, "rb")) == NULL) {
		cfg_add_cause(causes, "%s: %s", path, strerror(errno));
		return (CMD_RETURN_ERROR);
	}

	cfg_references++;

	if (ctx != NULL)
		cmd_ref_ctx(ctx);
	else {
		ctx = cmd_get_ctx();
		ctx->error = cfg_error;
		ctx->print = cfg_print;
		ctx->info = cfg_print;
	}

	n = 0;
	line = NULL;
	retval = CMD_RETURN_NORMAL;
	while ((buf = fgetln(f, &len))) {
		/* Trim \n. */
		if (buf[len - 1] == '\n')
			len--;
		log_debug("%s: %.*s", path, (int)len, buf);

		/* Current line is the continuation of the previous one. */
		if (line != NULL) {
			oldlen = strlen(line);
			line = xrealloc(line, 1, oldlen + len + 1);
		} else {
			oldlen = 0;
			line = xmalloc(len + 1);
		}

		/* Append current line to the previous. */
		memcpy(line + oldlen, buf, len);
		line[oldlen + len] = '\0';
		n++;

		/* Continuation: get next line? */
		len = strlen(line);
		if (len > 0 && line[len - 1] == '\\') {
			line[len - 1] = '\0';

			/* Ignore escaped backslash at EOL. */
			if (len > 1 && line[len - 2] != '\\')
				continue;
		}
		copy = line;
		line = NULL;

		/* Skip empty lines. */
		buf = copy;
		while (isspace((u_char)*buf))
			buf++;
		if (*buf == '\0') {
			free(copy);
			continue;
		}

		if (cmd_string_parse(buf, &cmdlist, &cause) != 0) {
			free(copy);
			if (cause == NULL)
				continue;
			cfg_add_cause(causes, "%s: %u: %s", path, n, cause);
			free(cause);
			continue;
		}
		free(copy);
		if (cmdlist == NULL)
			continue;

		cfg_cause = NULL;
		switch (cmd_list_exec(cmdlist, ctx)) {
		case CMD_RETURN_YIELD:
			if (retval != CMD_RETURN_ATTACH)
				retval = CMD_RETURN_YIELD;
			break;
		case CMD_RETURN_ATTACH:
			retval = CMD_RETURN_ATTACH;
			break;
		case CMD_RETURN_ERROR:
		case CMD_RETURN_NORMAL:
			break;
		}
		cmd_list_free(cmdlist);
		if (cfg_cause != NULL) {
			cfg_add_cause(causes, "%s: %d: %s", path, n, cfg_cause);
			free(cfg_cause);
		}
	}
	if (line != NULL) {
		cfg_add_cause(causes,
		    "%s: %d: line continuation at end of file", path, n);
		free(line);
	}
	fclose(f);

	cmd_free_ctx(ctx);

	cfg_references--;

	return (retval);
}
예제 #23
0
static enum cmd_retval
cmd_set_hook_exec(struct cmd *self, struct cmdq_item *item)
{
    struct args	*args = self->args;
    struct cmd_list	*cmdlist;
    struct hooks	*hooks;
    struct hook	*hook;
    char		*cause, *tmp;
    const char	*name, *cmd, *target;

    if (args_has(args, 'g'))
        hooks = global_hooks;
    else {
        if (item->state.tflag.s == NULL) {
            target = args_get(args, 't');
            if (target != NULL)
                cmdq_error(item, "no such session: %s", target);
            else
                cmdq_error(item, "no current session");
            return (CMD_RETURN_ERROR);
        }
        hooks = item->state.tflag.s->hooks;
    }

    if (self->entry == &cmd_show_hooks_entry) {
        hook = hooks_first(hooks);
        while (hook != NULL) {
            tmp = cmd_list_print(hook->cmdlist);
            cmdq_print(item, "%s -> %s", hook->name, tmp);
            free(tmp);

            hook = hooks_next(hook);
        }
        return (CMD_RETURN_NORMAL);
    }

    name = args->argv[0];
    if (*name == '\0') {
        cmdq_error(item, "invalid hook name");
        return (CMD_RETURN_ERROR);
    }
    if (args->argc < 2)
        cmd = NULL;
    else
        cmd = args->argv[1];

    if (args_has(args, 'u')) {
        if (cmd != NULL) {
            cmdq_error(item, "command passed to unset hook: %s",
                       name);
            return (CMD_RETURN_ERROR);
        }
        hooks_remove(hooks, name);
        return (CMD_RETURN_NORMAL);
    }

    if (cmd == NULL) {
        cmdq_error(item, "no command to set hook: %s", name);
        return (CMD_RETURN_ERROR);
    }
    if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) {
        if (cause != NULL) {
            cmdq_error(item, "%s", cause);
            free(cause);
        }
        return (CMD_RETURN_ERROR);
    }
    hooks_add(hooks, name, cmdlist);
    cmd_list_free(cmdlist);

    return (CMD_RETURN_NORMAL);
}
예제 #24
0
/*
 * Load configuration file. Returns -1 for an error with a list of messages in
 * causes. Note that causes must be initialised by the caller!
 */
int
load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes)
{
	FILE		*f;
	u_int		 n;
	char		*buf, *line, *cause;
	size_t		 len;
	struct cmd_list	*cmdlist;
	struct cmd_ctx	 ctx;
	int		 retval;

	if ((f = fopen(path, "rb")) == NULL) {
		cfg_add_cause(causes, "%s: %s", path, strerror(errno));
		return (-1);
	}
	n = 0;

	line = NULL;
	retval = 0;
	while ((buf = fgetln(f, &len))) {
		if (buf[len - 1] == '\n')
			buf[len - 1] = '\0';
		else {
			line = xrealloc(line, 1, len + 1);
			memcpy(line, buf, len);
			line[len] = '\0';
			buf = line;
		}
		n++;

		if (cmd_string_parse(buf, &cmdlist, &cause) != 0) {
			if (cause == NULL)
				continue;
			cfg_add_cause(causes, "%s: %u: %s", path, n, cause);
			xfree(cause);
			continue;
		}
		if (cmdlist == NULL)
			continue;
		cfg_cause = NULL;

		if (ctxin == NULL) {
			ctx.msgdata = NULL;
			ctx.curclient = NULL;
			ctx.cmdclient = NULL;
		} else {
			ctx.msgdata = ctxin->msgdata;
			ctx.curclient = ctxin->curclient;
			ctx.cmdclient = ctxin->cmdclient;
		}

		ctx.error = cfg_error;
		ctx.print = cfg_print;
		ctx.info = cfg_print;

		cfg_cause = NULL;
		if (cmd_list_exec(cmdlist, &ctx) == 1)
			retval = 1;
		cmd_list_free(cmdlist);
		if (cfg_cause != NULL) {
			cfg_add_cause(causes, "%s: %d: %s", path, n, cfg_cause);
			xfree(cfg_cause);
		}
	}
	if (line != NULL)
		xfree(line);
	fclose(f);

	return (retval);
}
예제 #25
0
int
load_cfg(const char *path, char **cause)
{
	FILE   	        *f;
	u_int		 n;
	struct stat	 sb;
	char	        *buf, *line, *ptr;
	size_t		 len;
	struct cmd_list	*cmdlist;
	struct cmd_ctx	 ctx;

	if (stat(path, &sb) != 0) {
		xasprintf(cause, "%s: %s", path, strerror(errno));
		return (-1);
	}
	if (!S_ISREG(sb.st_mode)) {
		xasprintf(cause, "%s: not a regular file", path);
		return (-1);
	}

	if ((f = fopen(path, "rb")) == NULL) {
		xasprintf(cause, "%s: %s", path, strerror(errno));
		return (1);
	}
	n = 0;

	line = NULL;
	while ((buf = fgetln(f, &len))) {
		if (buf[len - 1] == '\n')
			buf[len - 1] = '\0';
		else {
			line = xrealloc(line, 1, len + 1);
			memcpy(line, buf, len);
			line[len] = '\0';
			buf = line;
		}
		n++;

		if (cmd_string_parse(buf, &cmdlist, cause) != 0) {
			if (*cause == NULL)
				continue;
			goto error;
		}
		if (cmdlist == NULL)
			continue;
		cfg_cause = NULL;

		ctx.msgdata = NULL;
		ctx.cursession = NULL;
		ctx.curclient = NULL;

		ctx.error = cfg_error;
		ctx.print = cfg_print;
		ctx.info = cfg_print;

		ctx.cmdclient = NULL;

		cfg_cause = NULL;
		cmd_list_exec(cmdlist, &ctx);
		cmd_list_free(cmdlist);
		if (cfg_cause != NULL) {
			*cause = cfg_cause;
			goto error;
		}
	}
	if (line != NULL)
		xfree(line);
	fclose(f);

	return (0);

error:
	fclose(f);

	xasprintf(&ptr, "%s: %s at line %u", path, *cause, n);
	xfree(*cause);
	*cause = ptr;
	return (1);
}
예제 #26
0
파일: cfg.c 프로젝트: FauxFaux/tmux
int
load_cfg(const char *path, struct cmd_q *cmdq, char **cause)
{
	FILE		*f;
	u_int		 n, found;
	char		*buf, *copy, *line, *cause1, *msg;
	size_t		 len, oldlen;
	struct cmd_list	*cmdlist;

	log_debug("loading %s", path);
	if ((f = fopen(path, "rb")) == NULL) {
		xasprintf(cause, "%s: %s", path, strerror(errno));
		return (-1);
	}

	n = found = 0;
	line = NULL;
	while ((buf = fgetln(f, &len))) {
		/* Trim \n. */
		if (buf[len - 1] == '\n')
			len--;
		log_debug("%s: %.*s", path, (int)len, buf);

		/* Current line is the continuation of the previous one. */
		if (line != NULL) {
			oldlen = strlen(line);
			line = xrealloc(line, 1, oldlen + len + 1);
		} else {
			oldlen = 0;
			line = xmalloc(len + 1);
		}

		/* Append current line to the previous. */
		memcpy(line + oldlen, buf, len);
		line[oldlen + len] = '\0';
		n++;

		/* Continuation: get next line? */
		len = strlen(line);
		if (len > 0 && line[len - 1] == '\\') {
			line[len - 1] = '\0';

			/* Ignore escaped backslash at EOL. */
			if (len > 1 && line[len - 2] != '\\')
				continue;
		}
		copy = line;
		line = NULL;

		/* Skip empty lines. */
		buf = copy;
		while (isspace((u_char)*buf))
			buf++;
		if (*buf == '\0') {
			free(copy);
			continue;
		}

		/* Parse and run the command. */
		if (cmd_string_parse(buf, &cmdlist, path, n, &cause1) != 0) {
			free(copy);
			if (cause1 == NULL)
				continue;
			xasprintf(&msg, "%s:%u: %s", path, n, cause1);
			ARRAY_ADD(&cfg_causes, msg);
			free(cause1);
			continue;
		}
		free(copy);

		if (cmdlist == NULL)
			continue;
		cmdq_append(cmdq, cmdlist);
		cmd_list_free(cmdlist);
		found++;
	}
	if (line != NULL)
		free(line);
	fclose(f);

	return (found);
}
예제 #27
0
enum cmd_retval
cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq)
{
	struct args			*args = self->args;
	struct cmd_if_shell_data	*cdata;
	char				*shellcmd, *cmd, *cause;
	struct cmd_list			*cmdlist;
	struct client			*c;
	struct session			*s = NULL;
	struct winlink			*wl = NULL;
	struct window_pane		*wp = NULL;
	struct format_tree		*ft;
	int				 cwd;

	if (args_has(args, 't')) {
		wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
		cwd = wp->cwd;
	} else {
		c = cmd_find_client(cmdq, NULL, 1);
		if (c != NULL && c->session != NULL) {
			s = c->session;
			wl = s->curw;
			wp = wl->window->active;
		}
		if (cmdq->client != NULL && cmdq->client->session == NULL)
			cwd = cmdq->client->cwd;
		else if (s != NULL)
			cwd = s->cwd;
		else
			cwd = -1;
	}

	ft = format_create();
	format_defaults(ft, NULL, s, wl, wp);
	shellcmd = format_expand(ft, args->argv[0]);
	format_free(ft);

	if (args_has(args, 'F')) {
		cmd = NULL;
		if (*shellcmd != '0' && *shellcmd != '\0')
			cmd = args->argv[1];
		else if (args->argc == 3)
			cmd = args->argv[2];
		if (cmd == NULL)
			return (CMD_RETURN_NORMAL);
		if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) {
			if (cause != NULL) {
				cmdq_error(cmdq, "%s", cause);
				free(cause);
			}
			return (CMD_RETURN_ERROR);
		}
		cmdq_run(cmdq, cmdlist, &cmdq->item->mouse);
		cmd_list_free(cmdlist);
		return (CMD_RETURN_NORMAL);
	}

	cdata = xmalloc(sizeof *cdata);

	cdata->cmd_if = xstrdup(args->argv[1]);
	if (args->argc == 3)
		cdata->cmd_else = xstrdup(args->argv[2]);
	else
		cdata->cmd_else = NULL;

	cdata->bflag = args_has(args, 'b');

	cdata->cmdq = cmdq;
	memcpy(&cdata->mouse, &cmdq->item->mouse, sizeof cdata->mouse);
	cmdq->references++;

	cdata->references = 1;
	job_run(shellcmd, s, cwd, cmd_if_shell_callback, cmd_if_shell_free,
	    cdata);
	free(shellcmd);

	if (cdata->bflag)
		return (CMD_RETURN_NORMAL);
	return (CMD_RETURN_WAIT);
}
예제 #28
0
파일: cfg.c 프로젝트: cowboyrushforth/tmux2
/*
 * Load configuration file. Returns -1 for an error with a list of messages in
 * causes. Note that causes must be initialised by the caller!
 */
int
load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes)
{
	FILE		*f;
	u_int		 n;
	char		*buf, *line, *cause;
	size_t		 len;
	struct cmd_list	*cmdlist;
	struct cmd_ctx	 ctx;
	int		 retval;

	if ((f = fopen(path, "rb")) == NULL) {
		cfg_add_cause(causes, "%s: %s", path, strerror(errno));
		return (-1);
	}
	n = 0;

	line = NULL;
	retval = 0;
	while ((buf = fgetln(f, &len))) {
		if (buf[len - 1] == '\n')
			len--;

		if (line != NULL)
			line = xrealloc(line, 1, strlen(line) + len + 1);
		else {
			line = xmalloc(len + 1);
			*line = '\0';
		}

		/* Append buffer to line. strncat will terminate. */
		strncat(line, buf, len);
		n++;

		/* Continuation: get next line? */
		len = strlen(line);
		if (len > 0 && line[len - 1] == '\\') {
			line[len - 1] = '\0';
			/* Ignore escaped backslash at EOL. */
			if (len > 1 && line[len - 2] != '\\')
				continue;
		}
		buf = line;
		line = NULL;

		if (cmd_string_parse(buf, &cmdlist, &cause) != 0) {
			xfree(buf);
			if (cause == NULL)
				continue;
			cfg_add_cause(causes, "%s: %u: %s", path, n, cause);
			xfree(cause);
			continue;
		} else
			xfree(buf);
		if (cmdlist == NULL)
			continue;
		cfg_cause = NULL;

		if (ctxin == NULL) {
			ctx.msgdata = NULL;
			ctx.curclient = NULL;
			ctx.cmdclient = NULL;
		} else {
			ctx.msgdata = ctxin->msgdata;
			ctx.curclient = ctxin->curclient;
			ctx.cmdclient = ctxin->cmdclient;
		}

		ctx.error = cfg_error;
		ctx.print = cfg_print;
		ctx.info = cfg_print;

		cfg_cause = NULL;
		if (cmd_list_exec(cmdlist, &ctx) == 1)
			retval = 1;
		cmd_list_free(cmdlist);
		if (cfg_cause != NULL) {
			cfg_add_cause(
			    causes, "%s: %d: %s", path, n, cfg_cause);
			xfree(cfg_cause);
		}
	}
	if (line != NULL) {
		cfg_add_cause(causes,
		    "%s: %d: line continuation at end of file", path, n);
		xfree(line);
	}
	fclose(f);

	return (retval);
}
예제 #29
0
파일: cmd-if-shell.c 프로젝트: willame/tmux
static enum cmd_retval
cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
{
	struct args			*args = self->args;
	struct cmd_if_shell_data	*cdata;
	char				*shellcmd, *cmd, *cause;
	struct cmd_list			*cmdlist;
	struct cmdq_item		*new_item;
	struct client			*c = item->state.c;
	struct session			*s = item->state.tflag.s;
	struct winlink			*wl = item->state.tflag.wl;
	struct window_pane		*wp = item->state.tflag.wp;
	const char			*cwd;

	if (item->client != NULL && item->client->session == NULL)
		cwd = item->client->cwd;
	else if (s != NULL)
		cwd = s->cwd;
	else
		cwd = NULL;

	shellcmd = format_single(item, args->argv[0], c, s, wl, wp);
	if (args_has(args, 'F')) {
		cmd = NULL;
		if (*shellcmd != '0' && *shellcmd != '\0')
			cmd = args->argv[1];
		else if (args->argc == 3)
			cmd = args->argv[2];
		free(shellcmd);
		if (cmd == NULL)
			return (CMD_RETURN_NORMAL);
		cmdlist = cmd_string_parse(cmd, NULL, 0, &cause);
		if (cmdlist == NULL) {
			if (cause != NULL) {
				cmdq_error(item, "%s", cause);
				free(cause);
			}
			return (CMD_RETURN_ERROR);
		}
		new_item = cmdq_get_command(cmdlist, NULL, &item->mouse, 0);
		cmdq_insert_after(item, new_item);
		cmd_list_free(cmdlist);
		return (CMD_RETURN_NORMAL);
	}

	cdata = xcalloc(1, sizeof *cdata);
	if (self->file != NULL) {
		cdata->file = xstrdup(self->file);
		cdata->line = self->line;
	}

	cdata->cmd_if = xstrdup(args->argv[1]);
	if (args->argc == 3)
		cdata->cmd_else = xstrdup(args->argv[2]);
	else
		cdata->cmd_else = NULL;

	cdata->client = item->client;
	cdata->client->references++;

	if (!args_has(args, 'b'))
		cdata->item = item;
	else
		cdata->item = NULL;
	memcpy(&cdata->mouse, &item->mouse, sizeof cdata->mouse);

	job_run(shellcmd, s, cwd, cmd_if_shell_callback, cmd_if_shell_free,
	    cdata);
	free(shellcmd);

	if (args_has(args, 'b'))
		return (CMD_RETURN_NORMAL);
	return (CMD_RETURN_WAIT);
}