mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-10 16:00:08 +00:00
CONTRIB: tcploop: add action "X" to execute a command
Sometimes it's convenient to be able to execute a command directly on the stream, whether we're connecting or accepting an incoming connection. New command 'X' makes this possible. It simply calls execvp() on the next arguments and branches stdin/stdout/stderr on the socket. Optionally it's possible to limit the passed FDs to any combination of them by appending 'i', 'o', 'e' after the X. In any case the program ends just after executing this command. Examples : - chargen server tcploop 8001 L A Xo cat /dev/zero - telnet server tcploop 8001 L W N A X /usr/sbin/in.telnetd
This commit is contained in:
parent
23953686da
commit
b7a6d0d8d7
@ -122,6 +122,8 @@ __attribute__((noreturn)) void usage(int code, const char *arg0)
|
||||
" O : wait for Output queue to be empty (POLLOUT + TIOCOUTQ)\n"
|
||||
" F : FIN : shutdown(SHUT_WR)\n"
|
||||
" N<max> : fork New process, limited to <max> concurrent (default 1)\n"
|
||||
" X[i|o|e]* ** : execvp() next args passing socket as stdin/stdout/stderr.\n"
|
||||
" If i/o/e present, only stdin/out/err are mapped to socket.\n"
|
||||
"\n"
|
||||
"It's important to note that a single FD is used at once and that Accept\n"
|
||||
"replaces the listening FD with the accepted one. Thus always do it after\n"
|
||||
@ -138,6 +140,12 @@ __attribute__((noreturn)) void usage(int code, const char *arg0)
|
||||
"\n"
|
||||
"Example TCP client with pauses at each step :\n"
|
||||
" tcploop 8001 C T W P100 S10 O P100 R S10 O R G K\n"
|
||||
"\n"
|
||||
"Simple chargen server :\n"
|
||||
" tcploop 8001 L A Xo cat /dev/zero\n"
|
||||
"\n"
|
||||
"Simple telnet server :\n"
|
||||
" tcploop 8001 L W N A X /usr/sbin/in.telnetd\n"
|
||||
"", arg0);
|
||||
}
|
||||
|
||||
@ -727,6 +735,7 @@ int main(int argc, char **argv)
|
||||
int arg;
|
||||
int ret;
|
||||
int sock;
|
||||
int errfd;
|
||||
|
||||
arg0 = argv[0];
|
||||
|
||||
@ -899,6 +908,28 @@ int main(int argc, char **argv)
|
||||
arg = loop_arg - 1;
|
||||
continue;
|
||||
|
||||
case 'X': // execute command. Optionally supports redirecting only i/o/e
|
||||
if (arg + 1 >= argc)
|
||||
die(1, "Fatal: missing argument after %s\n", argv[arg]);
|
||||
|
||||
errfd = dup(2);
|
||||
fcntl(errfd, F_SETFD, fcntl(errfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
|
||||
fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, O_NONBLOCK) & ~O_NONBLOCK);
|
||||
if (!argv[arg][1] || strchr(argv[arg], 'i'))
|
||||
dup2(sock, 0);
|
||||
if (!argv[arg][1] || strchr(argv[arg], 'o'))
|
||||
dup2(sock, 1);
|
||||
if (!argv[arg][1] || strchr(argv[arg], 'e'))
|
||||
dup2(sock, 2);
|
||||
argv += arg + 1;
|
||||
if (execvp(argv[0], argv) == -1) {
|
||||
int e = errno;
|
||||
|
||||
dup2(errfd, 2); // restore original stderr
|
||||
close(errfd);
|
||||
die(1, "Fatal: execvp(%s) failed : %s\n", argv[0], strerror(e));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
usage(1, arg0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user