ref: 68c88ddf3d41bc310e307663ac95ff1ec0353a38
parent: 916c7f0bd9295c649ce8f6f8245475d083f4b7bd
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Tue Jan 3 14:18:48 EST 2023
dial(1): add dial command similar to plan9port This is similar to plan9port dial(1), but names aux/dial because we already have the expect(1) commands in /bin/dial. One difference is that our dial allows specifying a command, similar to aux/listen1 that will get connected it standard input and output to the network connection.
--- /dev/null
+++ b/sys/man/1/dial
@@ -1,0 +1,41 @@
+.TH DIAL 1
+.SH NAME
+dial - connect to a remote service
+.SH SYNOPSIS
+.B aux/dial
+.RB [ -e ]
+.I addr
+[
+.I cmd
+[
+.I args
+]...
+]
+.SH DESCRIPTION
+Dial connects to the remote network address
+.I addr
+(see
+.IR dial (2))
+and if no
+.I cmd
+is specified, copies data from the connection to standard output,
+and from standard input to the connection.
+.PP
+By default, dial exists when end of file is reached on
+standard input or on the network connection.
+The
+.B -e
+flag cuses dial to exit only in response to end of file on
+the network connection.
+.PP
+If
+.I cmd
+is given, then
+.I cmd
+is executed with standard input and output connected to
+the network connection.
+.SH SOURCE
+.B /sys/src/cmd/aux/dial.c
+.SH SEE ALSO
+.IR dial (2),
+.IR listen (8)
--- /dev/null
+++ b/sys/src/cmd/aux/dial.c
@@ -1,0 +1,87 @@
+#include <u.h>
+#include <libc.h>
+
+int eflag;
+int nopts;
+char *opts[16];
+
+void
+xfer(int from, int to)
+{
+ char buf[8192];
+ int n;
+
+ while((n = read(from, buf, sizeof buf)) > 0)
+ if(write(to, buf, n) < 0)
+ break;
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s [-e] [-o msg]... addr [cmd [args]...]\n", argv0);
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ int i, fd, cfd, pid;
+
+ ARGBEGIN {
+ case 'e':
+ eflag = 1;
+ break;
+ case 'o':
+ if(nopts >= nelem(opts)){
+ fprint(2, "%s: too many -o options\n", argv0);
+ exits("opts");
+ }
+ opts[nopts++] = EARGF(usage());
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if(--argc < 0)
+ usage();
+ fd = dial(*argv++, nil, nil, &cfd);
+ if(fd < 0){
+ fprint(2, "%s: dial: %r\n", argv0);
+ exits("dial");
+ }
+ for(i = 0; i < nopts; i++)
+ write(cfd, opts[i], strlen(opts[i]));
+ close(cfd);
+
+ if(argc > 0){
+ dup(fd, 0);
+ dup(fd, 1);
+ /* dup(fd, 2); keep stderr */
+ if(fd > 2) close(fd);
+
+ exec(argv[0], argv);
+ if(argv[0][0] != '/')
+ exec(smprint("/bin/%s", argv[0]), argv);
+ fprint(2, "%s: exec: %r\n", argv0);
+ exits("exec");
+ }
+
+ pid = fork();
+ switch(pid){
+ case -1:
+ fprint(2, "%s: fork: %r", argv0);
+ exits("fork");
+ case 0:
+ xfer(0, fd);
+ if(eflag) exits(nil);
+ pid = getppid();
+ break;
+ default:
+ xfer(fd, 1);
+ break;
+ }
+ postnote(PNPROC, pid, "kill");
+ waitpid();
+ exits(nil);
+}