540 lines · 14.0 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <ctype.h> /* hubshell is the client for hubfs, usually started by the hub wrapper script *//* it handles attaching and detaching from hub-connected rcs and creating new ones */ enum smallbuffer{	SMBUF = 777,}; typedef struct Shell	Shell; /* A Shell opens fds of 3 hubfiles and bucket-brigades data between the hubfs and std i/o fds*/struct Shell {	int fd[3];	int fdzerodelay;	int fdonedelay;	int fdtwodelay;	char basename[SMBUF];	char *fdname[3];	char shellctl;	char cmdresult;}; int notereceived; /* string storage for names of hubs and paths */char initname[SMBUF];char hubdir[SMBUF];char srvname[SMBUF];char ctlname[SMBUF];char basehub[SMBUF]; /* flags for rc commands to flush buffers */int fortunate;int echoes; Shell* setupshell(char *name);void startshell(Shell *s);void fdzerocat(int infd, int outfd, Shell *s);void fdonecat(int infd, int outfd, Shell *s);void fdtwocat(int infd, int outfd, Shell *s);int touch(char *name);void closefds(Shell *s);void parsebuf(Shell *s, char *buf, int outfd); /* set shellgroup variables and open file descriptors */Shell*setupshell(char *name){	Shell *s;	int i; 	s = (Shell*)malloc(sizeof(Shell));	if(s == nil)		sysfatal("Hubshell malloc failed!\n");	memset(s, 0, sizeof(Shell));	strncat(s->basename, name, SMBUF);	for(i = 1; i < 3; i++){		s->fdname[i] = (char*)malloc((strlen(s->basename)+1));		if(s->fdname[i] == nil)			sysfatal("Hubshell malloc failed!\n");		sprint(s->fdname[i], "%s%d", s->basename, i);		if((s->fd[i] = open(s->fdname[i], OREAD)) < 0){			fprint(2, "hubshell: giving up on task - cant open %s\n", s->fdname[i]);			return(nil);		};	}	s->fdname[0] =  (char*)malloc((strlen(s->basename)+1));	if(s->fdname[0] == nil)		sysfatal("Hubshell malloc failed!\n");	sprint(s->fdname[0], "%s%d", s->basename, 0);	if((s->fd[0] = open(s->fdname[0], OWRITE)) < 0){		fprint(2, "hubshell: giving up on task - cant open %s\n", s->fdname[0]);		return(nil);	}	sprint(basehub, s->fdname[0] + strlen(hubdir));	s->fdzerodelay = 0;	s->fdonedelay = 0;	s->fdtwodelay = 30;	s->cmdresult = 'a';	return s;} /* fork two reader procs for fd1 and 2, start writing to fd0 */voidstartshell(Shell *s){	/* fork cats for each file descriptor used by a shell */	if(rfork(RFPROC|RFMEM|RFNOWAIT|RFNOTEG)==0){		fdonecat(s->fd[1], 1, s);		exits(nil);	}	if(rfork(RFPROC|RFMEM|RFNOWAIT|RFNOTEG)==0){		fdtwocat(s->fd[2], 2, s);		exits(nil);	}	fdzerocat(0, s->fd[0], s);	exits(nil);} /* reader proc to transfer from hubfile to fd1 */voidfdonecat(int infd, int outfd, Shell *s){	char buf[8192];	long n; 	while((n=read(infd, buf, (long)sizeof(buf)))>0){		sleep(s->fdonedelay);		if(write(outfd, buf, n)!=n){			fprint(2, "hubshell: write error copying on fd %d\n", outfd);			exits(nil);		}		if(s->shellctl == 'q')			exits(nil);	}	if(n == 0)		fprint(2, "hubshell: zero length read on fd %d\n", infd);	if(n < 0)		fprint(2, "hubshell: error reading fd %d\n", infd);} /* reader proc to transfer from hubfile to fd2 */voidfdtwocat(int infd, int outfd, Shell *s){	char buf[8192];	long n; 	while((n=read(infd, buf, (long)sizeof(buf)))>0){		sleep(s->fdtwodelay);		if(write(outfd, buf, n)!=n){			fprint(2, "hubshell: write error copying on fd %d\n", outfd);			exits(nil);		}		if(s->shellctl == 'q')			exits(nil);	}	if(n == 0)		fprint(2, "hubshell: zero length read on fd %d\n", infd);	if(n < 0)		fprint(2, "hubshell: error reading fd %d\n", infd);} /* write user input from fd0 to hubfile */voidfdzerocat(int infd, int outfd, Shell *s){	char buf[8192];	long n;	char ctlbuf[8192];	int ctlfd; readloop:	while((n=read(infd, buf, (long)sizeof(buf)))>0){		/* check for user %command */		if((strncmp(buf, "%", 1)) == 0){			s->cmdresult = 'p';			parsebuf(s, buf + 1, outfd);			if(s->cmdresult != 'x'){				memset(buf, 0, 8192);				continue;			}		}		sleep(s->fdzerodelay);		if(write(outfd, buf, n)!=n)			fprint(2, "hubshell: write error copying on fd %d\n", outfd);		if(s->shellctl == 'q')			exits(nil);	}	/* eof input from user, send message to hubfs ctl file */	if(n == 0){		if((ctlfd = open(ctlname, OWRITE)) == - 1){			fprint(2, "hubshell: can't open ctl file\n");			goto readloop;		}		sprint(ctlbuf, "eof %s\n", basehub);		n=write(ctlfd, ctlbuf, strlen(ctlbuf) +1);			if(n != strlen(ctlbuf) + 1)				fprint(2, "hubshell: error writing to %s on fd %d\n", ctlname, ctlfd);		close(ctlfd);	}	/* hack to fix infinite loop bug with headless drawterm */	if(n < 0)		if(notereceived == 0)			exits(nil);	notereceived = 0;	goto readloop;		/* Use more gotos, they aren't harmful */} /* for creating new hubfiles */inttouch(char *name){	int fd; 	if((fd = create(name, OREAD|OEXCL, 0666)) < 0){		fprint(2, "hubshell: %s: cannot create: %r\n", name);		return 1;	}	close(fd);	return 0;} /* close fds when a shell moves to new hubfs */voidclosefds(Shell *s){	int i; 	for(i = 0; i < 3; i++)		close(s->fd[i]);} /* handles %commands */voidparsebuf(Shell *s, char *buf, int outfd){	char tmpstr[SMBUF];	char tmpname[SMBUF];	Shell *newshell;	memset(tmpstr, 0, SMBUF);	memset(tmpname, 0, SMBUF);	char ctlbuf[SMBUF];	int ctlfd;	int n; 	/* %detach closes hubshell fds and exits */	if(strncmp(buf, "detach", 6) == 0){		fprint(2, "hubshell: detaching\n");		s->shellctl = 'q';		if(fortunate)			write(outfd, "fortune\n", 8);		if(echoes)			write(outfd, "echo\n", 5);		sleep(1000);		closefds(s);		exits(nil);	} 	/* %remote command makes new shell on hubfs host by sending hub -b command */	if(strncmp(buf, "remote", 6) == 0){		if(isalpha(*(buf + 7)) == 0){			fprint(2, "hubshell: remote needs a name parameter to create new hubs\n:io ");			return;		}		strncat(tmpname, buf + 7, strcspn(buf + 7, "\n"));		fprint(2, "hubshell: creating new shell %s %s on remote host\n", srvname, tmpname);		snprint(tmpstr, SMBUF, "hub -b %s %s\n", srvname, tmpname);		write(outfd, tmpstr, strlen(tmpstr));		sleep(1000);		snprint(tmpstr, SMBUF, "/n/%s/%s", srvname, tmpname);		newshell = setupshell(tmpstr);		if(newshell == nil){			fprint(2, "hubshell: failed to setup up client shell, maybe problems on remote end\nio: ");			return;		}		s->shellctl = 'q';		if(fortunate)			write(outfd, "fortune\n", 8);		if(echoes)			write(outfd, "echo\n", 5);		sleep(700);		closefds(s);		startshell(newshell);		exits(nil);	} 	/* %local command makes new shell on local machine by executing the hub command and exiting */	if(strncmp(buf, "local", 5) == 0){		if(isalpha(*(buf + 6)) == 0){			fprint(2, "hubshell: local needs a name parameter to create new hubs\nio: ");			return;		}		strncpy(tmpstr, buf + 6, strcspn(buf + 6, "\n"));		fprint(2, "hubshell: creating new local shell using hub %s %s\n", srvname, tmpstr);		s->shellctl = 'q';		if(fortunate)			write(outfd, "fortune\n", 8);		if(echoes)			write(outfd, "echo\n", 5);		sleep(1000);		closefds(s);		execl("/bin/hub", "hub", srvname, tmpstr, 0);		exits(nil);	} 	/* %attach name starts new shell and exits the current one */	if(strncmp(buf, "attach", 6) == 0){		if(isalpha(*(buf + 7)) == 0){			fprint(2, "hubshell: attach needs a name parameter to know what hubs to use, try %%list\nio: ");			return;		}		strncat(tmpname, buf + 7, strcspn(buf + 7, "\n"));		fprint(2, "hubshell: attaching to  shell %s %s\n", srvname, tmpname);		snprint(tmpstr, SMBUF, "/n/%s/%s", srvname, tmpname);		newshell = setupshell(tmpstr);		if(newshell == nil){			fprint(2, "hubshell: failed to setup up client shell - do you need to create it with remote NAME?\nio: ");			return;		}		s->shellctl = 'q';		if(fortunate)			write(outfd, "fortune\n", 8);		if(echoes)			write(outfd, "echo\n", 5);		sleep(1000);		closefds(s);		startshell(newshell);		exits(nil);	} 	/* %err %in %out INT set the delay before reading/writing on that fd to INT milliseconds */	if(strncmp(buf, "err", 3) == 0){		if(isdigit(*(buf + 4)) == 0){			fprint(2, "hubshell: err hub delay setting requires numeric delay\nio: ");			return;		}		s->fdtwodelay = atoi(buf + 4);		fprint(2, "hubshell: err hub delay set to %d\nio: ", atoi(buf +4));		return;	}	if(strncmp(buf, "in", 2) == 0){		if(isdigit(*(buf + 3)) == 0){			fprint(2, "hubshell: in hub delay setting requires numeric delay\nio: ");			return;		}		s->fdzerodelay = atoi(buf + 3);		fprint(2, "hubshell: in hub delay set to %d\nio: ", atoi(buf +3));		return;	}	if(strncmp(buf, "out", 3) == 0){		if(isdigit(*(buf + 4)) == 0){			fprint(2, "hubshell: out hub delay setting requires numeric delay\nio: ");			return;		}		s->fdonedelay = atoi(buf + 4);		fprint(2, "hubshell: out hub delay set to %d\nio: ", atoi(buf +4));		return;	} 	/* %fortun and %echoes turn on buffer flush commands %unfort and %unecho deactivate */	if(strncmp(buf, "fortun", 6) == 0){		fprint(2, "hubshell: fortunes active\n");		fortunate = 1;		fprint(2, "io: ");		return;	}	if(strncmp(buf, "unfort", 6) == 0){		fprint(2, "hubshell: fortunes deactivated\n");		fortunate = 0;		fprint(2, "io: ");		return;	}	if(strncmp(buf, "echoes", 6) == 0){		fprint(2, "hubshell: echoes active\n");		echoes = 1;		fprint(2, "io: ");		return;	}	if(strncmp(buf, "unecho", 6) == 0){		fprint(2, "hubshell: echoes deactivated\n");		echoes = 0;		return;	} 	/* send eof or freeze/melt/fear/calm/trunc/notrunc messages to ctl file */	if(strncmp(buf, "eof", 3) == 0){		if((ctlfd = open(ctlname, OWRITE)) == - 1){			fprint(2, "hubshell: can't open ctl file\n");			return;		}		sprint(ctlbuf, "eof %s\n", basehub);		n=write(ctlfd, ctlbuf, strlen(ctlbuf) +1);			if(n != strlen(ctlbuf) + 1)				fprint(2, "hubshell: error writing to %s on fd %d\n", ctlname, ctlfd);		close(ctlfd);		return;	}	if(strncmp(buf, "freeze", 6) == 0){		if((ctlfd = open(ctlname, OWRITE)) == - 1){			fprint(2, "hubshell: can't open ctl file\n");			return;		}		sprint(ctlbuf, "freeze\n");		n=write(ctlfd, ctlbuf, strlen(ctlbuf) +1);			if(n != strlen(ctlbuf) + 1)				fprint(2, "hubshell: error writing to %s on fd %d\n", ctlname, ctlfd);		close(ctlfd);		return;	}	if(strncmp(buf, "melt", 4) == 0){		if((ctlfd = open(ctlname, OWRITE)) == - 1){			fprint(2, "hubshell: can't open ctl file\n");			return;		}		sprint(ctlbuf, "melt\n");		n=write(ctlfd, ctlbuf, strlen(ctlbuf) +1);			if(n != strlen(ctlbuf) + 1)				fprint(2, "hubshell: error writing to %s on fd %d\n", ctlname, ctlfd);		close(ctlfd);		fprint(2, "io: ");		return;	}	if(strncmp(buf, "fear", 4) == 0){		if((ctlfd = open(ctlname, OWRITE)) == - 1){			fprint(2, "hubshell: can't open ctl file\n");			return;		}		sprint(ctlbuf, "fear\n");		n=write(ctlfd, ctlbuf, strlen(ctlbuf) +1);			if(n != strlen(ctlbuf) + 1)				fprint(2, "hubshell: error writing to %s on fd %d\n", ctlname, ctlfd);		close(ctlfd);		fprint(2, "io: ");		return;	}	if(strncmp(buf, "calm", 4) == 0){		if((ctlfd = open(ctlname, OWRITE)) == - 1){			fprint(2, "hubshell: can't open ctl file\n");			return;		}		sprint(ctlbuf, "calm\n");		n=write(ctlfd, ctlbuf, strlen(ctlbuf) +1);			if(n != strlen(ctlbuf) + 1)				fprint(2, "hubshell: error writing to %s on fd %d\n", ctlname, ctlfd);		close(ctlfd);		fprint(2, "io: ");		return;	}	if(strncmp(buf, "trunc", 5) == 0){		if((ctlfd = open(ctlname, OWRITE)) == - 1){			fprint(2, "hubshell: can't open ctl file\n");			return;		}		sprint(ctlbuf, "trunc\n");		n=write(ctlfd, ctlbuf, strlen(ctlbuf) +1);			if(n != strlen(ctlbuf) + 1)				fprint(2, "hubshell: error writing to %s on fd %d\n", ctlname, ctlfd);		close(ctlfd);		fprint(2, "io: ");		return;	}	if(strncmp(buf, "notrunc", 7) == 0){		if((ctlfd = open(ctlname, OWRITE)) == - 1){			fprint(2, "hubshell: can't open ctl file\n");			return;		}		sprint(ctlbuf, "notrunc\n");		n=write(ctlfd, ctlbuf, strlen(ctlbuf) +1);			if(n != strlen(ctlbuf) + 1)				fprint(2, "hubshell: error writing to %s on fd %d\n", ctlname, ctlfd);		close(ctlfd);		fprint(2, "io: ");		return;	} 	/* %list displays attached hubs %status reports variable settings */	if(strncmp(buf, "list", 4) == 0){		sprint(tmpstr, "/n/%s", srvname);		print("listing mounted hubfs at /n/%s\n", srvname);		if(rfork(RFPROC|RFNOTEG|RFNOWAIT) == 0){			execl("/bin/lc", "lc", tmpstr, 0);			exits(nil);		}		sleep(1500);		fprint(2, "io: ");		return;	}	if(strncmp(buf, "status", 6) == 0){		print("\tHubshell status: attached to mounted %s of /srv/%s\n", s->basename, srvname);		print("\tfdzero delay: %d  fdone delay: %d  fdtwo delay: %d\n", s->fdzerodelay, s->fdonedelay, s->fdtwodelay);		if(fortunate)			print("\tfortune fd flush active\n");		if(echoes)			print("\techo fd flush active\n");		fprint(2, "io: ");		return;	} 	/* no matching command found, print list of commands as reminder */	fprint(2, "hubshell %% commands: \n\tdetach, remote NAME, local NAME, attach NAME \n\tstatus, list, err TIME, in TIME, out TIME\n\tfortun unfort echoes unecho trunc notrunc eof\n");	s->cmdresult = 'x';} /* receive interrupt messages (delete key) and pass them through to attached shells */intsendinterrupt(void *regs, char *notename){	char notehub[SMBUF];	int notefd; 	if(strcmp(notename, "interrupt") != 0)		return 0;	notereceived = 1;	if(regs == nil)		/* this is just to shut up a compiler warning */		fprint(2, "error in note registers\n");	sprint(notehub, "%s%s.note", hubdir, basehub);

Lines 1–500 of 540.