Add /exec
parent
4405b89f6c
commit
46f61dfcdc
|
@ -93,6 +93,7 @@ The default is the first available of
|
||||||
Disable the
|
Disable the
|
||||||
.Ic /copy ,
|
.Ic /copy ,
|
||||||
.Ic /debug ,
|
.Ic /debug ,
|
||||||
|
.Ic /exec ,
|
||||||
.Ic /join ,
|
.Ic /join ,
|
||||||
.Ic /msg ,
|
.Ic /msg ,
|
||||||
.Ic /open ,
|
.Ic /open ,
|
||||||
|
@ -280,6 +281,14 @@ or matching
|
||||||
Toggle logging in the
|
Toggle logging in the
|
||||||
.Sy <debug>
|
.Sy <debug>
|
||||||
window.
|
window.
|
||||||
|
.It Ic /exec Ar command
|
||||||
|
Run
|
||||||
|
.Ar command
|
||||||
|
with
|
||||||
|
.Ev SHELL
|
||||||
|
and interpret its output
|
||||||
|
as input to the current window,
|
||||||
|
including as commands.
|
||||||
.It Ic /help Op Ar search
|
.It Ic /help Op Ar search
|
||||||
View this manual.
|
View this manual.
|
||||||
Type
|
Type
|
||||||
|
|
41
chat.c
41
chat.c
|
@ -79,17 +79,31 @@ static void exitSave(void) {
|
||||||
uint32_t hashInit;
|
uint32_t hashInit;
|
||||||
|
|
||||||
int utilPipe[2] = { -1, -1 };
|
int utilPipe[2] = { -1, -1 };
|
||||||
|
int execPipe[2] = { -1, -1 };
|
||||||
|
|
||||||
static void utilRead(void) {
|
static void utilRead(void) {
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
ssize_t len = read(utilPipe[0], buf, sizeof(buf) - 1);
|
ssize_t len = read(utilPipe[0], buf, sizeof(buf) - 1);
|
||||||
if (len < 0) err(EX_IOERR, "read");
|
if (len < 0) err(EX_IOERR, "read");
|
||||||
if (!len) return;
|
if (!len) return;
|
||||||
buf[len - 1] = '\0';
|
buf[len] = '\0';
|
||||||
char *ptr = buf;
|
char *ptr = buf;
|
||||||
while (ptr) {
|
while (ptr) {
|
||||||
char *line = strsep(&ptr, "\n");
|
char *line = strsep(&ptr, "\n");
|
||||||
uiFormat(Network, Warm, NULL, "%s", line);
|
if (line[0]) uiFormat(Network, Warm, NULL, "%s", line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void execRead(void) {
|
||||||
|
char buf[1024];
|
||||||
|
ssize_t len = read(execPipe[0], buf, sizeof(buf) - 1);
|
||||||
|
if (len < 0) err(EX_IOERR, "read");
|
||||||
|
if (!len) return;
|
||||||
|
buf[len] = '\0';
|
||||||
|
char *ptr = buf;
|
||||||
|
while (ptr) {
|
||||||
|
char *line = strsep(&ptr, "\n");
|
||||||
|
if (line[0]) command(execID, line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,25 +235,34 @@ int main(int argc, char *argv[]) {
|
||||||
signal(SIGCHLD, signalHandler);
|
signal(SIGCHLD, signalHandler);
|
||||||
sig_t cursesWinch = signal(SIGWINCH, signalHandler);
|
sig_t cursesWinch = signal(SIGWINCH, signalHandler);
|
||||||
|
|
||||||
int error = pipe(utilPipe);
|
|
||||||
if (error) err(EX_OSERR, "pipe");
|
|
||||||
|
|
||||||
fcntl(irc, F_SETFD, FD_CLOEXEC);
|
fcntl(irc, F_SETFD, FD_CLOEXEC);
|
||||||
fcntl(utilPipe[0], F_SETFD, FD_CLOEXEC);
|
if (!self.restricted) {
|
||||||
fcntl(utilPipe[1], F_SETFD, FD_CLOEXEC);
|
int error = pipe(utilPipe);
|
||||||
|
if (error) err(EX_OSERR, "pipe");
|
||||||
|
|
||||||
struct pollfd fds[3] = {
|
error = pipe(execPipe);
|
||||||
|
if (error) err(EX_OSERR, "pipe");
|
||||||
|
|
||||||
|
fcntl(utilPipe[0], F_SETFD, FD_CLOEXEC);
|
||||||
|
fcntl(utilPipe[1], F_SETFD, FD_CLOEXEC);
|
||||||
|
fcntl(execPipe[0], F_SETFD, FD_CLOEXEC);
|
||||||
|
fcntl(execPipe[1], F_SETFD, FD_CLOEXEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pollfd fds[] = {
|
||||||
{ .events = POLLIN, .fd = STDIN_FILENO },
|
{ .events = POLLIN, .fd = STDIN_FILENO },
|
||||||
{ .events = POLLIN, .fd = irc },
|
{ .events = POLLIN, .fd = irc },
|
||||||
{ .events = POLLIN, .fd = utilPipe[0] },
|
{ .events = POLLIN, .fd = utilPipe[0] },
|
||||||
|
{ .events = POLLIN, .fd = execPipe[0] },
|
||||||
};
|
};
|
||||||
while (!self.quit) {
|
while (!self.quit) {
|
||||||
int nfds = poll(fds, ARRAY_LEN(fds), -1);
|
int nfds = poll(fds, (self.restricted ? 2 : ARRAY_LEN(fds)), -1);
|
||||||
if (nfds < 0 && errno != EINTR) err(EX_IOERR, "poll");
|
if (nfds < 0 && errno != EINTR) err(EX_IOERR, "poll");
|
||||||
if (nfds > 0) {
|
if (nfds > 0) {
|
||||||
if (fds[0].revents) uiRead();
|
if (fds[0].revents) uiRead();
|
||||||
if (fds[1].revents) ircRecv();
|
if (fds[1].revents) ircRecv();
|
||||||
if (fds[2].revents) utilRead();
|
if (fds[2].revents) utilRead();
|
||||||
|
if (fds[3].revents) execRead();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signals[SIGHUP]) self.quit = "zzz";
|
if (signals[SIGHUP]) self.quit = "zzz";
|
||||||
|
|
3
chat.h
3
chat.h
|
@ -138,6 +138,9 @@ extern struct Replies {
|
||||||
size_t whois;
|
size_t whois;
|
||||||
} replies;
|
} replies;
|
||||||
|
|
||||||
|
size_t execID;
|
||||||
|
int execPipe[2];
|
||||||
|
|
||||||
void handle(struct Message msg);
|
void handle(struct Message msg);
|
||||||
void command(size_t id, char *input);
|
void command(size_t id, char *input);
|
||||||
const char *commandIsPrivmsg(size_t id, const char *input);
|
const char *commandIsPrivmsg(size_t id, const char *input);
|
||||||
|
|
19
command.c
19
command.c
|
@ -195,6 +195,24 @@ static void commandCopy(size_t id, char *params) {
|
||||||
urlCopyMatch(id, params);
|
urlCopyMatch(id, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void commandExec(size_t id, char *params) {
|
||||||
|
execID = id;
|
||||||
|
|
||||||
|
pid_t pid = fork();
|
||||||
|
if (pid < 0) err(EX_OSERR, "fork");
|
||||||
|
if (pid) return;
|
||||||
|
|
||||||
|
const char *shell = getenv("SHELL");
|
||||||
|
if (!shell) shell = "/bin/sh";
|
||||||
|
|
||||||
|
close(STDIN_FILENO);
|
||||||
|
dup2(execPipe[1], STDOUT_FILENO);
|
||||||
|
dup2(utilPipe[1], STDERR_FILENO);
|
||||||
|
execlp(shell, shell, "-c", params, NULL);
|
||||||
|
warn("%s", shell);
|
||||||
|
_exit(EX_UNAVAILABLE);
|
||||||
|
}
|
||||||
|
|
||||||
static void commandHelp(size_t id, char *params) {
|
static void commandHelp(size_t id, char *params) {
|
||||||
(void)id;
|
(void)id;
|
||||||
uiHide();
|
uiHide();
|
||||||
|
@ -220,6 +238,7 @@ static const struct Handler {
|
||||||
{ "/close", .fn = commandClose },
|
{ "/close", .fn = commandClose },
|
||||||
{ "/copy", .fn = commandCopy, .restricted = true },
|
{ "/copy", .fn = commandCopy, .restricted = true },
|
||||||
{ "/debug", .fn = commandDebug, .restricted = true },
|
{ "/debug", .fn = commandDebug, .restricted = true },
|
||||||
|
{ "/exec", .fn = commandExec, .restricted = true },
|
||||||
{ "/help", .fn = commandHelp },
|
{ "/help", .fn = commandHelp },
|
||||||
{ "/join", .fn = commandJoin, .restricted = true },
|
{ "/join", .fn = commandJoin, .restricted = true },
|
||||||
{ "/list", .fn = commandList },
|
{ "/list", .fn = commandList },
|
||||||
|
|
Loading…
Reference in New Issue