Merge changes I6ba143f5,I3f2398d5,I13a06f60
* changes: Merge remote-tracking branch 'toybox/master' into HEAD netcat: Add UNIX domain socket support (-U) More toysh flow control plumbing.
This commit is contained in:
commit
654d5f24bf
@ -1892,12 +1892,13 @@
|
||||
#undef FLAG_n
|
||||
#endif
|
||||
|
||||
// netcat ^tlLw#<1W#<1p#<1>65535q#<1s:f:46u[!tlL][!Lw][!46] ^tlLw#<1W#<1p#<1>65535q#<1s:f:46u[!tlL][!Lw][!46]
|
||||
// netcat ^tlLw#<1W#<1p#<1>65535q#<1s:f:46uU[!tlL][!Lw][!46U] ^tlLw#<1W#<1p#<1>65535q#<1s:f:46uU[!tlL][!Lw][!46U]
|
||||
#undef OPTSTR_netcat
|
||||
#define OPTSTR_netcat "^tlLw#<1W#<1p#<1>65535q#<1s:f:46u[!tlL][!Lw][!46]"
|
||||
#define OPTSTR_netcat "^tlLw#<1W#<1p#<1>65535q#<1s:f:46uU[!tlL][!Lw][!46U]"
|
||||
#ifdef CLEANUP_netcat
|
||||
#undef CLEANUP_netcat
|
||||
#undef FOR_netcat
|
||||
#undef FLAG_U
|
||||
#undef FLAG_u
|
||||
#undef FLAG_6
|
||||
#undef FLAG_4
|
||||
@ -4922,18 +4923,19 @@
|
||||
#ifndef TT
|
||||
#define TT this.netcat
|
||||
#endif
|
||||
#define FLAG_u (1<<0)
|
||||
#define FLAG_6 (1<<1)
|
||||
#define FLAG_4 (1<<2)
|
||||
#define FLAG_f (1<<3)
|
||||
#define FLAG_s (1<<4)
|
||||
#define FLAG_q (1<<5)
|
||||
#define FLAG_p (1<<6)
|
||||
#define FLAG_W (1<<7)
|
||||
#define FLAG_w (1<<8)
|
||||
#define FLAG_L (1<<9)
|
||||
#define FLAG_l (1<<10)
|
||||
#define FLAG_t (1<<11)
|
||||
#define FLAG_U (1<<0)
|
||||
#define FLAG_u (1<<1)
|
||||
#define FLAG_6 (1<<2)
|
||||
#define FLAG_4 (1<<3)
|
||||
#define FLAG_f (1<<4)
|
||||
#define FLAG_s (1<<5)
|
||||
#define FLAG_q (1<<6)
|
||||
#define FLAG_p (1<<7)
|
||||
#define FLAG_W (1<<8)
|
||||
#define FLAG_w (1<<9)
|
||||
#define FLAG_L (1<<10)
|
||||
#define FLAG_l (1<<11)
|
||||
#define FLAG_t (1<<12)
|
||||
#endif
|
||||
|
||||
#ifdef FOR_netstat
|
||||
|
@ -122,7 +122,7 @@
|
||||
|
||||
#define HELP_netstat "usage: netstat [-pWrxwutneal]\n\nDisplay networking information. Default is netstat -tuwx\n\n-r Routing table\n-a All sockets (not just connected)\n-l Listening server sockets\n-t TCP sockets\n-u UDP sockets\n-w Raw sockets\n-x Unix sockets\n-e Extended info\n-n Don't resolve names\n-W Wide display\n-p Show PID/program name of sockets"
|
||||
|
||||
#define HELP_netcat "usage: netcat [-46t] [-lL COMMAND...] [-u] [-wpq #] [-s addr] {IPADDR PORTNUM|-f FILENAME}\n\nForward stdin/stdout to a file or network connection.\n\n-4 Force IPv4\n-6 Force IPv6\n-L Listen for multiple incoming connections (server mode)\n-W SECONDS timeout for more data on an idle connection\n-f Use FILENAME (ala /dev/ttyS0) instead of network\n-l Listen for one incoming connection\n-p Local port number\n-q Quit SECONDS after EOF on stdin, even if stdout hasn't closed yet\n-s Local source address\n-t Allocate tty (must come before -l or -L)\n-u Use UDP\n-w SECONDS timeout to establish connection\n\nUse \"stty 115200 -F /dev/ttyS0 && stty raw -echo -ctlecho\" with\nnetcat -f to connect to a serial port.\n\nThe command line after -l or -L is executed (as a child process) to handle\neach incoming connection. If blank -l waits for a connection and forwards\nit to stdin/stdout. If no -p specified, -l prints port it bound to and\nbackgrounds itself (returning immediately).\n\nFor a quick-and-dirty server, try something like:\nnetcat -s 127.0.0.1 -p 1234 -tL /bin/bash -l"
|
||||
#define HELP_netcat "usage: netcat [-46Ut] [-lL COMMAND...] [-u] [-wpq #] [-s addr] {IPADDR PORTNUM|-f FILENAME}\n\nForward stdin/stdout to a file or network connection.\n\n-4 Force IPv4\n-6 Force IPv6\n-L Listen for multiple incoming connections (server mode)\n-U Use a UNIX domain socket\n-W SECONDS timeout for more data on an idle connection\n-f Use FILENAME (ala /dev/ttyS0) instead of network\n-l Listen for one incoming connection\n-p Local port number\n-q Quit SECONDS after EOF on stdin, even if stdout hasn't closed yet\n-s Local source address\n-t Allocate tty (must come before -l or -L)\n-u Use UDP\n-w SECONDS timeout to establish connection\n\nUse \"stty 115200 -F /dev/ttyS0 && stty raw -echo -ctlecho\" with\nnetcat -f to connect to a serial port.\n\nThe command line after -l or -L is executed (as a child process) to handle\neach incoming connection. If blank -l waits for a connection and forwards\nit to stdin/stdout. If no -p specified, -l prints port it bound to and\nbackgrounds itself (returning immediately).\n\nFor a quick-and-dirty server, try something like:\nnetcat -s 127.0.0.1 -p 1234 -tL /bin/bash -l"
|
||||
|
||||
#define HELP_microcom "usage: microcom [-s SPEED] [-X] DEVICE\n\nSimple serial console.\n\n-s Set baud rate to SPEED\n-X Ignore ^@ (send break) and ^] (exit)"
|
||||
|
||||
|
@ -169,7 +169,7 @@ USE_MV(NEWTOY(mv, "<2vnF(remove-destination)fi[-ni]", TOYFLAG_BIN))
|
||||
USE_NBD_CLIENT(OLDTOY(nbd-client, nbd_client, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_NBD_CLIENT(NEWTOY(nbd_client, "<3>3ns", 0))
|
||||
USE_NETCAT(OLDTOY(nc, netcat, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_NETCAT(NEWTOY(netcat, USE_NETCAT_LISTEN("^tlL")"w#<1W#<1p#<1>65535q#<1s:f:46u"USE_NETCAT_LISTEN("[!tlL][!Lw]")"[!46]", TOYFLAG_BIN))
|
||||
USE_NETCAT(NEWTOY(netcat, USE_NETCAT_LISTEN("^tlL")"w#<1W#<1p#<1>65535q#<1s:f:46uU"USE_NETCAT_LISTEN("[!tlL][!Lw]")"[!46U]", TOYFLAG_BIN))
|
||||
USE_NETSTAT(NEWTOY(netstat, "pWrxwutneal", TOYFLAG_BIN))
|
||||
USE_NICE(NEWTOY(nice, "^<1n#", TOYFLAG_BIN))
|
||||
USE_NL(NEWTOY(nl, "v#<1=1l#w#<0=6Eb:n:s:", TOYFLAG_USR|TOYFLAG_BIN))
|
||||
|
@ -7,13 +7,13 @@
|
||||
* netcat -L zombies
|
||||
|
||||
USE_NETCAT(OLDTOY(nc, netcat, TOYFLAG_USR|TOYFLAG_BIN))
|
||||
USE_NETCAT(NEWTOY(netcat, USE_NETCAT_LISTEN("^tlL")"w#<1W#<1p#<1>65535q#<1s:f:46u"USE_NETCAT_LISTEN("[!tlL][!Lw]")"[!46]", TOYFLAG_BIN))
|
||||
USE_NETCAT(NEWTOY(netcat, USE_NETCAT_LISTEN("^tlL")"w#<1W#<1p#<1>65535q#<1s:f:46uU"USE_NETCAT_LISTEN("[!tlL][!Lw]")"[!46U]", TOYFLAG_BIN))
|
||||
|
||||
config NETCAT
|
||||
bool "netcat"
|
||||
default y
|
||||
help
|
||||
usage: netcat [-46] [-u] [-wpq #] [-s addr] {IPADDR PORTNUM|-f FILENAME}
|
||||
usage: netcat [-46U] [-u] [-wpq #] [-s addr] {IPADDR PORTNUM|-f FILENAME}
|
||||
|
||||
Forward stdin/stdout to a file or network connection.
|
||||
|
||||
@ -24,6 +24,7 @@ config NETCAT
|
||||
-q Quit SECONDS after EOF on stdin, even if stdout hasn't closed yet
|
||||
-s Local source address
|
||||
-u Use UDP
|
||||
-U Use a UNIX domain socket
|
||||
-w SECONDS timeout to establish connection
|
||||
-W SECONDS timeout for more data on an idle connection
|
||||
|
||||
@ -85,11 +86,13 @@ void netcat_main(void)
|
||||
// The argument parsing logic can't make "<2" conditional on other
|
||||
// arguments like -f and -l, so do it by hand here.
|
||||
if ((toys.optflags&FLAG_f) ? toys.optc :
|
||||
(!(toys.optflags&(FLAG_l|FLAG_L)) && toys.optc!=2))
|
||||
(!(toys.optflags&(FLAG_l|FLAG_L)) &&
|
||||
toys.optc!=(toys.optflags&FLAG_U?1:2)))
|
||||
help_exit("bad argument count");
|
||||
|
||||
if (toys.optflags&FLAG_4) family = AF_INET;
|
||||
else if (toys.optflags&FLAG_6) family = AF_INET6;
|
||||
else if (toys.optflags&FLAG_U) family = AF_UNIX;
|
||||
|
||||
if (toys.optflags&FLAG_u) type = SOCK_DGRAM;
|
||||
|
||||
@ -97,9 +100,28 @@ void netcat_main(void)
|
||||
else {
|
||||
// Setup socket
|
||||
if (!(toys.optflags&(FLAG_L|FLAG_l))) {
|
||||
struct addrinfo *addr = xgetaddrinfo(toys.optargs[0], toys.optargs[1],
|
||||
family, type, 0, 0);
|
||||
sockfd = xconnect(addr);
|
||||
if (toys.optflags&FLAG_U) {
|
||||
struct sockaddr_un sockaddr;
|
||||
|
||||
memset(&sockaddr, 0, sizeof(struct sockaddr_un));
|
||||
|
||||
if (strlen(toys.optargs[0]) + 1 > sizeof(sockaddr.sun_path))
|
||||
error_exit("socket path too long %s", toys.optargs[0]);
|
||||
strcpy(sockaddr.sun_path, toys.optargs[0]);
|
||||
sockaddr.sun_family = AF_UNIX;
|
||||
|
||||
sockfd = xsocket(AF_UNIX, type | SOCK_CLOEXEC, 0);
|
||||
if (connect(sockfd, (struct sockaddr*)&sockaddr,
|
||||
sizeof(sockaddr)) != 0) {
|
||||
perror_exit("could not bind to unix domain socket");
|
||||
}
|
||||
|
||||
} else {
|
||||
struct addrinfo *addr = xgetaddrinfo(toys.optargs[0], toys.optargs[1],
|
||||
family, type, 0, 0);
|
||||
|
||||
sockfd = xconnect(addr);
|
||||
}
|
||||
|
||||
// We have a connection. Disarm timeout.
|
||||
set_alarm(0);
|
||||
@ -109,14 +131,33 @@ void netcat_main(void)
|
||||
pollinate(in1, in2, out1, out2, TT.W, TT.q);
|
||||
} else {
|
||||
// Listen for incoming connections
|
||||
struct sockaddr* address = (void*)toybuf;
|
||||
socklen_t len = sizeof(struct sockaddr_storage);
|
||||
if (toys.optflags&FLAG_U) {
|
||||
struct sockaddr_un sockaddr;
|
||||
|
||||
sprintf(toybuf, "%ld", TT.p);
|
||||
sockfd = xbind(xgetaddrinfo(TT.s, toybuf, family, type, 0, 0));
|
||||
memset(&sockaddr, 0, sizeof(struct sockaddr_un));
|
||||
|
||||
if (!(toys.optflags&FLAG_s))
|
||||
error_exit("-s must be provided if using -U with -L/-l");
|
||||
|
||||
if (strlen(TT.s) + 1 > sizeof(sockaddr.sun_path))
|
||||
error_exit("socket path too long %s", TT.s);
|
||||
strcpy(sockaddr.sun_path, TT.s);
|
||||
sockaddr.sun_family = AF_UNIX;
|
||||
|
||||
sockfd = xsocket(AF_UNIX, type | SOCK_CLOEXEC, 0);
|
||||
if (bind(sockfd, (struct sockaddr*)&sockaddr,
|
||||
sizeof(struct sockaddr_un)) != 0) {
|
||||
perror_exit("unable to bind to UNIX domain socket");
|
||||
}
|
||||
} else {
|
||||
sprintf(toybuf, "%ld", TT.p);
|
||||
sockfd = xbind(xgetaddrinfo(TT.s, toybuf, family, type, 0, 0));
|
||||
}
|
||||
|
||||
if (listen(sockfd, 5)) error_exit("listen");
|
||||
if (!TT.p) {
|
||||
if (!TT.p && !(toys.optflags&FLAG_U)) {
|
||||
struct sockaddr* address = (void*)toybuf;
|
||||
socklen_t len = sizeof(struct sockaddr_storage);
|
||||
short port_be;
|
||||
|
||||
getsockname(sockfd, address, &len);
|
||||
@ -136,7 +177,7 @@ void netcat_main(void)
|
||||
|
||||
do {
|
||||
child = 0;
|
||||
in1 = out2 = accept(sockfd, (struct sockaddr *)address, &len);
|
||||
in1 = out2 = accept(sockfd, NULL, NULL);
|
||||
if (in1<0) perror_exit("accept");
|
||||
|
||||
// We have a connection. Disarm timeout.
|
||||
|
@ -184,7 +184,7 @@ static void run_command(struct sh_process *pp)
|
||||
pipe[0] = 0;
|
||||
pipe[1] = 1;
|
||||
if (-1 == (pp->pid = xpopen_both(pp->arg.v, pipe)))
|
||||
perror_msg("%s: not found", *pp->arg.v);
|
||||
perror_msg("%s: vfork", *pp->arg.v);
|
||||
else pp->exit = xpclose_both(pp->pid, 0);
|
||||
}
|
||||
|
||||
@ -290,7 +290,7 @@ static char *parse_word(char *start)
|
||||
// pointer to start of unused part of line if it needs another line of input.
|
||||
static char *parse_line(char *line, struct double_list **pipeline)
|
||||
{
|
||||
char *start = line, *end, *s;
|
||||
char *start = line, *end, *s, *ex, *add;
|
||||
struct sh_arg *arg = 0;
|
||||
struct double_list *pl, *expect = 0;
|
||||
unsigned i, paren = 0;
|
||||
@ -350,40 +350,81 @@ static char *parse_line(char *line, struct double_list **pipeline)
|
||||
for (pl = *pipeline; pl ; pl = (pl->next == *pipeline) ? 0 : pl->next) {
|
||||
arg = (void *)pl->data;
|
||||
if (!arg->c) continue;
|
||||
add = 0;
|
||||
|
||||
// parse flow control statements in this command line
|
||||
for (i = 0; i<arg->c; i++) {
|
||||
char *ex = expect ? expect->prev->data : 0;
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
ex = expect ? expect->prev->data : 0;
|
||||
s = arg->v[i];
|
||||
if (!strcmp(s, "if")) ex = "then";
|
||||
else if (!strcmp(s, "for") || !strcmp(s, "select")
|
||||
|| !strcmp(s, "while") || !strcmp(s, "until")) ex = "do";
|
||||
else if (!strcmp(s, "case")) ex = "esac";
|
||||
else if (!strcmp(s, "{")) ex = "}";
|
||||
else if (!strcmp(s, "[[")) ex = "]]";
|
||||
|
||||
// If we expect a non-flow-control command, eat rest of line
|
||||
else if (expect && !ex) {
|
||||
// push word to expect to end this block, and expect a command first
|
||||
if (add) {
|
||||
dlist_add(&expect, add);
|
||||
dlist_add(&expect, add = 0);
|
||||
}
|
||||
|
||||
// end of statement?
|
||||
if (i == arg->c) break;
|
||||
|
||||
// When waiting for { it must be next symbol, but can be on a new line.
|
||||
if (ex && !strcmp(ex, "{") && (strcmp(s, "{") || (!i && end))) {
|
||||
syntax_err("need {");
|
||||
goto flush;
|
||||
}
|
||||
|
||||
if (!strcmp(s, "if")) add = "then";
|
||||
else if (!strcmp(s, "for") || !strcmp(s, "select")
|
||||
|| !strcmp(s, "while") || !strcmp(s, "until")) add = "do";
|
||||
else if (!strcmp(s, "case")) add = "esac";
|
||||
else if (!strcmp(s, "{")) add = "}";
|
||||
else if (!strcmp(s, "[[")) add = "]]";
|
||||
|
||||
// function NAME () [nl] { [nl] body ; }
|
||||
// Why can you to declare functions inside other functions?
|
||||
else if (arg->c>i+1 && !strcmp(arg->v[i+1], "(")) goto funky;
|
||||
else if (!strcmp(s, "function")) {
|
||||
i++;
|
||||
funky:
|
||||
// At this point we can only have a function: barf if it's invalid
|
||||
if (arg->c<i+3 || !strcmp(arg->v[i+1], "(")
|
||||
|| !strcmp(arg->v[i+2], ")"))
|
||||
{
|
||||
syntax_err("bad function ()");
|
||||
goto flush;
|
||||
}
|
||||
dlist_add(&expect, "}");
|
||||
dlist_add(&expect, 0);
|
||||
dlist_add(&expect, "{");
|
||||
|
||||
// Expecting NULL will take any otherwise unrecognized word
|
||||
} else if (expect && !ex) {
|
||||
free(dlist_pop(&expect));
|
||||
continue;
|
||||
|
||||
// Did we find a specific word we were waiting for?
|
||||
} else if (ex && !strcmp(arg->v[i], ex)) {
|
||||
// If we expect nothing and didn't just start a new flow control block,
|
||||
// rest of statement is a command and arguments, so stop now
|
||||
} else if (!ex) break;
|
||||
|
||||
if (add) continue;
|
||||
|
||||
// If we got here we expect a word to end this block: is this it?
|
||||
if (!strcmp(arg->v[i], ex)) {
|
||||
free(dlist_pop(&expect));
|
||||
|
||||
// can't "if | then" or "while && do", only ; or newline works
|
||||
if (end && !strcmp(end, ";")) {
|
||||
// can't if | then or while && do, only ; or newline counts
|
||||
syntax_err("bad %s", end);
|
||||
goto flush;
|
||||
}
|
||||
if (!strcmp(s, "do")) dlist_add(&expect, "done");
|
||||
else if (!strcmp(s, "then")) dlist_add(&expect, "fi\0A");
|
||||
break;
|
||||
|
||||
// if it's a multipart block, what comes next?
|
||||
if (!strcmp(s, "do")) ex = "done";
|
||||
else if (!strcmp(s, "then")) add = "fi\0A";
|
||||
// fi could have elif, which queues a then.
|
||||
} else if (ex && !strcmp(ex, "fi")) {
|
||||
} else if (!strcmp(ex, "fi")) {
|
||||
if (!strcmp(s, "elif")) {
|
||||
free(dlist_pop(&expect));
|
||||
dlist_add(&expect, "then");
|
||||
add = "then";
|
||||
// catch duplicate else while we're here
|
||||
} else if (!strcmp(s, "else")) {
|
||||
if (ex[3] != 'A') {
|
||||
@ -391,23 +432,21 @@ static char *parse_line(char *line, struct double_list **pipeline)
|
||||
goto flush;
|
||||
}
|
||||
free(dlist_pop(&expect));
|
||||
dlist_add(&expect, "fi\0B");
|
||||
add = "fi\0B";
|
||||
}
|
||||
} else break;
|
||||
|
||||
dlist_add(&expect, ex);
|
||||
}
|
||||
}
|
||||
// Record how the previous stanza ended
|
||||
// Record how the previous stanza ended: ; | & ;; || && ;& ;;& |& NULL
|
||||
end = arg->v[arg->c];
|
||||
}
|
||||
|
||||
// If we need more lines to finish flow control...
|
||||
// TODO: functions
|
||||
if (expect) {
|
||||
// Do we need more lines to finish a flow control statement?
|
||||
if (expect || paren) {
|
||||
llist_traverse(expect, free);
|
||||
return start;
|
||||
}
|
||||
|
||||
// iterate through the commands running each one
|
||||
for (pl = *pipeline; pl ; pl = (pl->next == *pipeline) ? 0 : pl->next) {
|
||||
struct sh_process *pp = xzalloc(sizeof(struct sh_process));
|
||||
|
||||
@ -445,7 +484,12 @@ void sh_main(void)
|
||||
size_t linelen = 0;
|
||||
|
||||
// Prompt and read line
|
||||
if (!f) do_prompt(getenv(command ? "PS2" : "PS1"));
|
||||
if (!f) {
|
||||
char *s = getenv(command ? "PS2" : "PS1");
|
||||
|
||||
if (!s) s = command ? "> " : (getpid() ? "\\$ " : "# ");
|
||||
do_prompt(s);
|
||||
}
|
||||
if (1 > getline(&new, &linelen, f ? f : stdin)) break;
|
||||
if (f) TT.lineno++;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user