Plan 9 from Bell Labs’s /usr/web/sources/contrib/mycroftiv/root/sys/src/cmd/iosrv/ioshell.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <u.h>
#include <libc.h>
#include <ctype.h>

#define HISTSIZE 131072
#define SMBUF 256

char cursrv[SMBUF];
char shortname[SMBUF];
char shellctl;
char hist[HISTSIZE];
int histlen;
int fd[4];
int hubfdmap[3];

void iocat(int infd, int outfd);
void fdzerocat(int infd, int outfd);

/* ioshell is a front end client for iosrv that spider-walks acrss available pipe files */
/* traps certain user input as commands to be implemented via messages to Hub ctl/data file */

/* basic cat-style data transfer between file descriptors */
void
iocat(int infd, int outfd)
{
	char buf[8192];
	long n;
	while((n=read(infd, buf, (long)sizeof(buf)))>0){
		if(write(outfd, buf, n)!=n){
			sysfatal("write error copying on fd %d\n", outfd);
		}
		sleep(0);
		if(shellctl == 'q'){
			exits(nil);
		}
	}
	if(n == 0){
		print("zero length read on fd %d\n", infd);
	}
	if(n < 0){
		sysfatal("error reading fd %d\n", infd);
	}
	return;
}

/* the process handling user input parses it and helps send commands to the iosrv ctl */
/* this function is a bit monstrous in appearance, but most of the time it simply bucket brigades information */
/* the complex actions are taken in response to control messages specifying changing or creating input/output sources */

void
fdzerocat(int infd, int outfd)
{
	char buf[8192];
	char fileinbuf[8192];
	char numname[SMBUF];
	int numfd;
	char tmpcmdname[SMBUF];
	int tmpcmdfd;
	long n;
	int swtarg;
	int targouttag;
	int tmpnum;
	char cmdstr[SMBUF];
	char newfd0[SMBUF];
	char newfd1[SMBUF];
	char newfd2[SMBUF];
	char ctlfdname[SMBUF];
	ulong datamode;
	ulong execmode;
	datamode = 0664L;
	execmode = 0777L;

	while(shellctl != 'q'){
		while((n=read(infd, buf, (long)sizeof(buf)))>0){

/* remote # command creates and connects to a new rc running on the remote iosrv host */

			if(strncmp(buf, "remote", 6) == 0){
				if(isdigit(*(buf + 7))){
					swtarg = atoi(buf +7);
				} else {
					print("ioshell err: new needs numeric argument\n");
					continue;
				}
				targouttag = 0;
				for(int i=swtarg; i < swtarg+3; i++){
					fprint(fd[3], "h%ds%d\n", i, targouttag);
					sleep(200);
					fprint(fd[3], "h%do%d\n", i, targouttag);
					sleep(200);
				}
				sprint(cmdstr, "rc -i <%s/H%dout%d/data1 >%s/H%din%d/data >[2]%s/H%din%d/data &\n", cursrv, swtarg, targouttag, cursrv, swtarg+1, targouttag, cursrv, swtarg+2, targouttag);
				if(rfork(RFPROC|RFMEM|RFNOWAIT|RFNOTEG) == 0){
					sleep(400);
					write(outfd, "rfork\n", 6);
					sleep(400);
					write(outfd, cmdstr, strlen(cmdstr));
					sleep(200);
					write(outfd, "rfork\n",6);
					exits(nil);
				}
				sleep(1500);
				sprint(numname, "%s/attach%d", cursrv, swtarg);
				numfd = create(numname, OWRITE, datamode);
				fprint(numfd, "%d", targouttag +1);
				close(numfd);
				sprint(numname, "%s/trihubs", cursrv);
				numfd = open(numname, OREAD);
				if(numfd < 0){
					print("didnt find a trihubs value\n");
				}
				read(numfd, fileinbuf, 8192);
				close(numfd);
				if(isdigit(*(fileinbuf))){
					tmpnum = atoi(fileinbuf);

					numfd=create(numname, OWRITE, datamode);
					fprint(numfd, "%d\n", tmpnum +1);
					close(numfd);
				} else {
					print("couldnt read trihub value, automatic client adds may fail\n");
				}
				sprint(newfd0, "%s/H%din%d/data", cursrv, swtarg, targouttag);
				sprint(newfd1, "%s/H%dout%d/data1", cursrv, swtarg+1, targouttag);
				sprint(newfd2, "%s/H%dout%d/data1", cursrv, swtarg+2, targouttag);
				sprint(ctlfdname, "%s/ctl/data", cursrv);
				shellctl = 'q';
				write(outfd, "fortune\n", 8);
				rfork(RFNOWAIT|RFNOTEG);
				execl("/bin/ioshell", "ioshell", newfd0, newfd1, newfd2, ctlfdname, 0);
				exits(nil);
			}

/* local # creates and connects to a new rc running on the local machine, and connects its file descriptors to pipes from iosrv */

			if(strncmp(buf, "local", 5) == 0){
				if(isdigit(*(buf + 6))){
					swtarg = atoi(buf +6);
				} else {
					print("ioshell err: new needs numeric argument\n");
					continue;
				}
				targouttag = 0;
				for(int i=swtarg; i < swtarg+3; i++){
					fprint(fd[3], "h%ds%d\n", i, targouttag);
					sleep(200);
					fprint(fd[3], "h%do%d\n", i, targouttag);
					sleep(200);
				}
				sprint(cmdstr, "rc -i <%s/H%dout%d/data1 >%s/H%din%d/data >[2]%s/H%din%d/data\n", cursrv, swtarg, targouttag, cursrv, swtarg+1, targouttag, cursrv, swtarg+2, targouttag);
				sprint(tmpcmdname, "%s/tmpcmd", cursrv);
				tmpcmdfd=create(tmpcmdname, OWRITE, execmode);
				if(tmpcmdfd < 0){
					print("couldnt create tmpcmd so rc will not be active\n");
				} else {
					fprint(tmpcmdfd, "#!/bin/rc\n");
					fprint(tmpcmdfd, cmdstr);
					close(tmpcmdfd);
					if(rfork(RFPROC|RFNAMEG|RFENVG|RFNOTEG) == 0){

						execl(tmpcmdname, "rcstart", nil);
						print("rc started exiting\n");
						exits(nil);
					}
				}
				sprint(numname, "%s/attach%d", cursrv, swtarg);
				numfd = create(numname, OWRITE, datamode);
				fprint(numfd, "%d", targouttag +1);
				close(numfd);
				sprint(numname, "%s/trihubs", cursrv);
				numfd = open(numname, ORDWR);
				if(numfd < 0){
					print("didnt find a trihubs value\n");
				}
				read(numfd, fileinbuf, 8192);
				close(numfd);
				if(isdigit(*(fileinbuf))){
					tmpnum = atoi(fileinbuf);
					numfd=create(numname, OWRITE, datamode);
					fprint(numfd, "%d\n", tmpnum +1);
					close(numfd);
				} else {
					print("couldnt read trihub value, automatic client adds may fail\n");
				}
				sprint(newfd0, "%s/H%din%d/data", cursrv, swtarg, targouttag);
				sprint(newfd1, "%s/H%dout%d/data1", cursrv, swtarg+1, targouttag);
				sprint(newfd2, "%s/H%dout%d/data1", cursrv, swtarg+2, targouttag);
				sprint(ctlfdname, "%s/ctl/data", cursrv);
				shellctl = 'q';
				write(outfd, "fortune\n", 8);
				rfork(RFNOWAIT|RFNOTEG);
				execl("/bin/ioshell", "ioshell", newfd0, newfd1, newfd2, ctlfdname, 0);
				print("stdout ioshell complete, exiting\n");
				exits(nil);
			}

/* attach # moves the ioshell between hubs - actually by exiting the current and starting a new ioshell with the correct paramaters */
/* this same technique is also used for 'remote' and 'local' connections */

			if(strncmp(buf, "attach", 6) == 0){
				if(isdigit(*(buf + 7))){
					swtarg = atoi(buf+7);
				} else {
					print("ioshell err: switch needs numeric argument\n");
					continue;
				}
				sprint(numname, "%s/attach%d", cursrv, swtarg);
				numfd=open(numname, OREAD);
				if(numfd < 0){
					print("couldnt find attach number, using arbitrary\n");
					targouttag=swtarg*5;
					goto readfailed;
				}
				read(numfd, fileinbuf, 8192);
				if(isdigit(*(fileinbuf))){
					targouttag = atoi(fileinbuf);
					close(numfd);
					numfd = create(numname, OWRITE, datamode);
					fprint(numfd, "%d", targouttag +1);
					close(numfd);
				} else {
					print("failed to read attach number using arbitrary \n");
					close(numfd);
					targouttag=swtarg*4;
				}
readfailed:
				fprint(fd[3], "h%di%d\n", swtarg, targouttag);
				sleep(200);
				for(int i=swtarg; i < swtarg+3; i++){
					fprint(fd[3], "h%do%d\n", i, targouttag);
					sleep(200);
				}
				sprint(newfd0, "%s/H%din%d/data", cursrv, swtarg, targouttag);
				sprint(newfd1, "%s/H%dout%d/data1", cursrv, swtarg+1, targouttag);
				sprint(newfd2, "%s/H%dout%d/data1", cursrv, swtarg+2, targouttag);
				sprint(ctlfdname, "%s/ctl/data", cursrv);
				shellctl = 'q';
				write(outfd, "fortune\n", 8);
				rfork(RFMEM|RFNOWAIT|RFNOTEG);
				execl("/bin/ioshell", "ioshell", newfd0, newfd1, newfd2, ctlfdname, 0);
				print("stdout ioshell complete, exiting\n");
				exits(nil);
			}			
			if(strncmp(buf, "clear", 5) == 0){
				fprint(fd[3], "h0c\n");
				sleep(200);
				fprint(fd[3], "h1c\n");
				sleep(200);
				fprint(fd[3], "h2c\n");
				print("server buffer cleared\n");
				print("ioshell: ");
				continue;
			}
/* hub cmdstr sends a message to the parsecmd routine in the iosrv ctlsrv - see control.c */
			if(strncmp(buf, "hub", 3) == 0){
				memset(cmdstr, 0, SMBUF);
				strncpy(cmdstr, buf+4, SMBUF);
				print("transmitting command to ctl\n");
				fprint(fd[3], "%s", cmdstr);
				print("ioshell: ");
				continue;
			}				
			if(strncmp(buf, "hist\n", 5) == 0){
				write(1, hist, histlen);
				print("ioshell: ");	
				continue;
			}
			if(strncmp(buf, "detach", 6) == 0){
				print("ioshell detaching\n");
				shellctl = 'q';
				write(outfd, "fortune\n", 8);
				exits(nil);
			}
			if(histlen > (HISTSIZE - 16385)){
				memset(hist, 0, HISTSIZE);
				histlen = 0;
			}
			strncat(hist, buf, n);
			histlen += n;
			if(write(outfd, buf, n)!=n){
				sysfatal("write error copying on fd %d", outfd);
			}
			sleep(0);
		}
		if(n == 0){
			print("zero length read on fd %d\n", infd);
		}
		if(n < 0){
			sysfatal("error reading on fd %d\n", infd);
		}
	}
	return;
}

/* fork off procs to transfer data between the given files and /fd/0,1,2 */
void
main(int argc, char *argv[])
{
	if(argc != 5){
		sysfatal("USAGE: ioshell filefromfd0 filetofd1 filetofd2 ctlfile");
	}
	strncat(cursrv, argv[4], (strlen(argv[4]) -9));
	strcat(shortname, cursrv+3);
	memset(hist, 0, HISTSIZE);
	fd[3] = open(argv[4], OWRITE);
	if(fd[4] < 0){
		sysfatal("cant open ctl file %s\n", argv[4]);
	}
	fd[0] = open(argv[1], OWRITE);
	if(fd[0] < 0){
		sysfatal("cant redirect stdout to %s\n", argv[1]);
	}
	for(int i=1; i < 3; i++){
		if(rfork(RFPROC|RFMEM|RFNOWAIT|RFNOTEG)==0){
			sleep(200);
			fd[i] = open(argv[i+1], OREAD);
			if(fd[i] < 0){
				sysfatal("cant open %s\n", argv[i+1]);
			}
			iocat(fd[i], i);
			print("iocat on fd %d ended\n", fd[i]);
			exits(nil);
		}
	}
	rfork(RFMEM|RFNOWAIT|RFNOTEG);
	print("attaching ioshell user input to %s fd %d\n", argv[1], fd[0]);
	fdzerocat(0, fd[0]);
	print("iocat of user input on fd %d ended\n", fd[0]);
	return;
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.