#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. Load more
#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; } void freexcmd(Xcmd* c) { if (c){ free(c->name); free(c->dir); free(c->cmd); free(c->tag); free(c->ox); free(c); } } void xcmdproc(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 void gone(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 void waitthread(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 long readbuf(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 void xcmdoutthread(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); } void xcmd(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 int cput(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; } int cdone(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 } int cexit(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 int cfont(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 int cget(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 int ccmds(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; } void wctl(char* path, char* ctl) { char* fn; fn = smprint("%s/ctl", path); writefstr(fn, ctl); free(fn);