code: plan9front

Download patch

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);
+}