henesyinit from lsubb0c8bdb6 years agoHistory
645 lines · 11.1 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <thread.h>#include <omero.h>#include <error.h>#include <b.h>#include "ox.h" static Xcmd**	xcmds;static int	nxcmds;static Channel*	cmdc; Xcmd*allocxcmd(char* name, char* dir, char* cmd, char* ox){	Xcmd*	x; 	x = emalloc(sizeof(Xcmd));	memset(x, 0, sizeof(Xcmd));	if (name == nil)		name = "/dev/null";	x->name= estrdup(name);	x->dir = estrdup(dir);	x->cmd = estrdup(cmd);	if (ox)		x->ox = estrdup(ox);	x->infd[0]= x->outfd[1] = -1;	x->infd[1]= x->outfd[0] = -1;	x->errfd = -1;	x->when = time(nil);	return x;} static Xcmd*newxcmd(char* name, char* dir, char* cmd, char* ox){	Xcmd*	x; 	x = allocxcmd(name, dir, cmd, ox);	if ((nxcmds%16) == 0)		xcmds = erealloc(xcmds, (nxcmds+16)*sizeof(Xcmd*));	xcmds[nxcmds++] = x;	return x;} voidfreexcmd(Xcmd* c){	if (c){		free(c->name);		free(c->dir);		free(c->cmd);		free(c->tag);		free(c->ox);		free(c);	}}  voidxcmdproc(void* a){	Xcmd*	x;	int	i; 	x = a;	if (x->outfd[0] >= 0)		close(x->outfd[0]);	if (x->infd[1] >= 0)		close(x->infd[1]);	dup(x->outfd[1], 1);	if (x->errfd >= 0){		dup(x->errfd, 2);		close(x->errfd);	} else		dup(x->outfd[1], 2);	close(x->outfd[1]);	dup(x->infd[0], 0);	close(x->infd[0]);	chdir(x->dir);	for (i = 3; i < 128; i++)		close(i);	if (x->name == nil)		putenv("file", "/dev/null");	else if (x->name[0] == '[')		putenv("file", x->dir);	else		putenv("file", x->name);	if (x->ox != nil)		putenv("panel", x->ox);	/* Ugly, but convenient to avoid '' around its arguments	 */	if (!strncmp(x->cmd, "Clean ", 5))		procexecl(x->pidc, "/bin/Clean", "Clean", x->cmd+5, nil); 	procexecl(x->pidc, "/bin/rc", "rc", "-c", x->cmd, nil);	threadexits(nil);} static voidgone(int pid, int ok){	int	i;	char	vmsg[50];	char*	s; 	for (i = 0; i < nxcmds; i++)		if (xcmds[i] && xcmds[i]->pid == pid){			dprint("ox: gone: %s\n", xcmds[i]->cmd);			if (!ok || (time(nil) - xcmds[i]->when > 2)) {				s = strchr(xcmds[i]->cmd, ' ');				if (s)					*s = 0;				seprint(vmsg, vmsg+sizeof(vmsg),					"%s %s\n", xcmds[i]->cmd,					ok ? "completed" : "failed");				writefstr("/devs/voice/output", vmsg);			}			freexcmd(xcmds[i]);			xcmds[i] = nil;			break;		}} static voidwaitthread(void*){	Channel*	c;	Waitmsg*	m; 	threadsetname("waitthread"); 	c = threadwaitchan();	for(;;){		m = recvp(c);		gone(m->pid, (m->msg == nil || m->msg[0] == 0));		free(m);	}} static longreadbuf(Ioproc* io, int fd, char* buf, int len){	int	n;	int	nr;	Dir*	d;	int	more; 	n = 0;	do {		nr = ioread(io, fd, buf+n, len - n);		if (nr <= 0)			break;		n += nr;		d = dirfstat(fd);		if (d){			more = d->length;			free(d);		} else			more = 0;	} while (more && n < len); 	return n;} static voidxcmdoutthread(void* a){	Xcmd*	x = a;	char*	buf;	int	fd;	char*	s;	Edit*	e;	int	nr,nw;	int	pid;	Ioproc*	io;	long	tot;	int	i; 	fd = x->outfd[0];	s = estrdup(x->tag);	assert(s[0] == '[');	pid = x->pid;	buf = emalloc(64*1024+1);	e = nil;	io = ioproc();	assert(io);	tot = nw = 0;	for(;;){		if (e != nil && e->gtext == nil){			e->pid = 0;			deledit(e);			e = nil;			break;		}		nr = readbuf(io, fd, buf, 64*1024);		if (nr <= 0)			break;		if (e == nil){			e = musthavemsgs(s);			assert(e);			assert(e->pid == 0);			e->pid = pid;			free(e->text);			e->text = nil;			if(openpanel(e->gtext, OWRITE|OTRUNC) < 0){				msgprint(nil, "%s: %r\n", e->name);				e->pid = 0;				break;			}		}		if (tot > 640 * 1024){			// BUG: If there is too much text loaded, truncate and			// restart again. Should preserve the last N bytes,			// but this is enough by now.			if (e->gtext){				closepanel(e->gtext);				openpanel(e->gtext, OWRITE|OTRUNC);				tot = 0;			}		}		for (i = 0; i < nr; i++)			if (buf[i] == 0)				buf[i] = '?'; // precaution		assert( ( ((ulong)e->gtext)&1 ) == 0);	// BUG hunting		if (e->gtext != nil)		if((nw = writepanel(e->gtext, buf, nr)) <= 0){			msgprint(nil, "%s: %r\n", e->name);			break;		} // we ignore other cases due to binary output...		tot += nw; 	}	closeioproc(io);	if (e != nil){		e->pid = 0;		if (e->gtext)			closepanel(e->gtext);	}	free(s);	free(buf);	close(fd);	threadexits(nil);} voidxcmd(char* name, char* dir, char* arg, char* in, char* out, char* ox){	Xcmd*	x;	char	cmd[40];	char*	p; 	x = newxcmd(name, dir, arg, ox); 	if (in)		x->infd[0] = open(in, OREAD);	if (0 && x->infd[0] < 0)		pipe(x->infd);	if (x->infd[0] < 0)		x->infd[0] = open("/dev/null", OREAD); 	if (out)		x->outfd[1] = open(out, OREAD);	if (x->outfd[1] < 0)		pipe(x->outfd);	if (x->outfd[1] < 0)		x->outfd[1] = open("/dev/null", OWRITE); 	x->pidc = chancreate(sizeof(ulong), 0);	procrfork(xcmdproc, x, 16*1024, RFFDG|RFNOTEG|RFENVG);	x->pid = recvul(x->pidc);	strecpy(cmd, cmd+sizeof(cmd), x->cmd);	p = strchr(cmd, ' ');	if (p)		*p = 0;	x->tag = smprint("[%s %s %d]", x->dir, cmd, x->pid);	chanfree(x->pidc);	x->pidc = nil; 	close(x->infd[0]);	close(x->outfd[1]);	x->infd[0] = x->outfd[1] = -1; 	if (x->outfd[0] >= 0){		threadcreate(xcmdoutthread, x, 32*1024);	}} static intcput(Edit* e, int argc, char *[], int force){	char*	to;	Dir*	d;	long	l; 	if (argc != 1){		msgprint(nil, "ox: Put does not take arguments\n");		return 0;	}	if (e->qid.type&QTDIR)		return 1;	to = gettagpath(e);	if (!strcmp(to, e->name) && e->sts == Stemp)		return 1;	d = dirstat(to);	if (d != nil){		if (!force)		if (d->qid.path != e->qid.path){			msgprint(nil, "%s: file exists\n", to);			goto fail;		} else if (d->qid.vers != e->qid.vers){			msgprint(nil, "%s: file changed by %s\n", e->name, d->muid);			goto fail;		}	} else		msgprint(nil, "%s: new file\n", to);	dprint("put %s\n", to);	free(e->text);	e->text = readallpanel(e->gtext, &l);	if (e->text == nil){		msgprint(nil, "%s: %r\n", e->gtext->name);		goto fail;	}	l = createf(to, e->text, strlen(e->text), 0664);	dprint("x: %s: put %ld bytes\n", e->name, l);	if (l < 0){		msgprint(nil, "%s: %r\n", to);		openpanelctl(e->gtext);		panelctl(e->gtext, "dirty");		closepanelctl(e->gtext);		goto fail;	}	assert(l == strlen(e->text));	free(e->text);	e->text = nil;	free(e->name);	e->name = cleanpath(to, nil);	free(e->dir);	e->dir = filedir(e->name);	cleanedit(e, nil);	openpanelctl(e->gtext);	panelctl(e->gtext, "clean");	closepanelctl(e->gtext);	e->sts = Sclean;	free(d);	free(to);	return 1;fail:	free(d);	free(to);	return 0;} intcdone(Edit* e, int , char* [], int force){	char*	s; 	if (e->sts != Stemp)	if (!(e->qid.type&QTDIR))		if (getsts(e->gtext, e) == Sdirty){			if (!force){				s = gettagpath(e);				msgprint(nil, "%s: unsaved changes\n", s);				free(s);				return 0;			}		}	if (e->gtext != nil)		removepanel(e->gtext);	if (e->gtag != nil)		removepanel(e->gtag);	if (e->gcol != nil)		removepanel(e->gcol);	e->gtext = nil;	e->gtag = nil;	e->gcol = nil;	if (e->pid == 0){		deledit(e);		musthaveedits();		if (debug)dumpedits();	}	return -1;	// !0 to say ok. <0 to say e is gone} intcexit(Edit* , int , char* [], int force){	int	i; 	for(i = 0; i < nedits; i++)		if(edits[i] && edits[i]->sts == Sdirty && !force){			msgprint(nil, "dirty buffers\n");			return 0;		}	threadexitsall(nil);	return 1;} static intcfont(Edit* e, int , char* [], int ){	openpanelctl(e->gtext);	if (e->font == FR){		e->font = FT;		panelctl(e->gtext, "font T");	} else {		e->font = FR;		panelctl(e->gtext, "font R");	}	closepanelctl(e->gtext);	return 1;} static intcget(Edit* e, int argc, char* argv[], int force){	char*	from;	int	r; 	if (argc == 2){		from =  cleanpath(argv[1], e->dir);		editfile(from, 0);		free(from);		return 1;	}	if (e->sts == Stemp)		return 1;	if (!force && !(e->qid.type&QTDIR) && e->sts == Sdirty){		msgprint(nil, "%s: put changes first\n", e->name);		return 0;	}	from = estrdup(e->name);	dprint("get %s\n", from);	r = loadfile(e, from);	if (r){		updatetag(e, 1);		updatetext(e);		openpanelctl(e->gtext);		panelctl(e->gtext, "clean");		closepanelctl(e->gtext); 	}	return r;} static intccmds(Edit*, int, char*[], int){	sendul(cmdc, 0);	return 1;} static Cmd cmds[] = {	{ "Exit",	cexit},	{ "Done",	cdone},	{ "Put",	cput },	{ "P",		cput },	{ "Get",	cget },	{ "G",		cget },	{ "Font",	cfont},	{ "Cmds",	ccmds},}; static char*readout(int fd){	char*	s;	int	len;	int	off;	int	nr; 	s = emalloc(64*1024);	len = 64*1024;	s[0] = 0;	off = 0;	for(;;){		nr = read(fd, s+off, len - off - 1);		if (nr >= 0){			s[off+nr] = 0;			off += nr;		}		if (nr <= 0)			break;		if (nr == len - off - 1){			s = erealloc(s, len + 64*1024);			assert(s);			len += 64*1024;		}	}	return s;} voidwctl(char* path, char* ctl){	char*	fn; 	fn = smprint("%s/ctl", path);	writefstr(fn, ctl);	free(fn);

Lines 1–500 of 645.