ref: ccc26ffb4b6a6de6373d57c537adae626511c4b2
dir: /livedoc.c/
#include <u.h> #include <libc.h> #include <bio.h> #include <plumb.h> void usage(void) { fprint(2, "usage: %s [-hqp] [-t sleep] [-m mark]\n", argv0); exits("usage"); } char Enoacme[] = "not in acme"; char Enofile[] = "no file"; typedef struct Winpos Winpos; struct Winpos { long m; long n; }; int winid; int ctlfd, addrfd, datafd; int sctlfd, stagfd; char *stag = nil; char *file, *filedir, *targetfile; char *ldpath = "/mnt/livedoc"; char *mark = "·"; int noplumb = 0; void runcmd(char *cmd, char **args) { int p[2]; if (pipe(p) < 0) sysfatal("runcmd: %r"); switch (fork()) { case -1: /* error */ sysfatal("unable to fork for %s: %r", cmd); case 0: /* child */ chdir(ldpath); /* ramfs call can silently fail */ dup(p[1], 1); close(p[1]); close(p[0]); exec(cmd, args); sysfatal("unable to exec: %r"); default: /* parent */ close(p[1]); break; } wait(); } Winpos finddot(void) { int n; Winpos pos; char data[25]; /* m[11] space[1] n[11] */ char *e; pos.m = pos.n = -1; fprint(ctlfd, "addr=dot"); n = pread(addrfd, data, 24, 0); if (n != 24) { werrstr("error reading addr file"); return pos; } data[24] = 0; pos.m = strtol(data, &e, 10); pos.n = strtol(e, nil, 10); return pos; } char *dircpargs[] = { "dircp", nil, "/mnt/livedoc", nil, }; char *cleanargs[] = { "rm", "-rf", "/mnt/livedoc/*", nil, }; void copydata(void) { dircpargs[1] = filedir; // runcmd("/bin/rm", cleanargs); runcmd("/bin/dircp", dircpargs); } void dumpfile(Winpos pos) { int fd; Biobuf *bin, *bout; char *s; fprint(addrfd, "#0,#%ld", pos.m); fd = open(targetfile, OWRITE); if (fd < 0) sysfatal("error opening file: %r"); bin = Bfdopen(datafd, OREAD); bout = Bfdopen(fd, OWRITE); while (s = Brdstr(bin, '\n', 0)) if (Bprint(bout, "%s", s) == -1) break; Bprint(bout, "%s", mark); fprint(addrfd, "#%ld,$", pos.m); while (s = Brdstr(bin, '\n', 0)) { if (Bprint(bout, "%s", s) == -1) break; } Bterm(bout); } char *mkpdargs[] = { "mk", "tout", nil, }; int pagedot(void) { int p[2]; Biobuf *bin; char *s; int page, ignore; if (pipe(p) < 0) sysfatal("unable to pipe: %r"); switch (fork()) { case -1: /* error */ sysfatal("unable to fork for pagedot: %r"); case 0: /* child */ chdir(ldpath); dup(p[1], 1); close(p[1]); close(p[0]); exec("/bin/mk", mkpdargs); sysfatal("error: %r"); default: /* parent */ close(p[1]); } page = 1; ignore = 0; bin = Bfdopen(p[0], OREAD); while (s = Brdstr(bin, '\n', 1)) { if (ignore) continue; if (s[0] == 'p') { page = atoi(&s[1]); } if (strstr(s, mark)) { ignore = 1; } free(s); } Bterm(bin); waitpid(); return ignore ? page : 1; } char *mkargs[] = { "mk", nil, }; void compile(void) { runcmd("/bin/mk", mkargs); } int round = 0; char *pdffile = nil; void copyfile(void) { char *s; int to, from, dirfd; int n, l; long r; Dir *dirs; char buf[8192]; dirfd = open(ldpath, OREAD); if (dirfd < 0) sysfatal("unable to open dir: %r"); s = nil; while ((n = dirread(dirfd, &dirs)) > 0) { for (int i = 0; i < n; i++) { l = strlen(dirs[i].name); if (strcmp(&dirs[i].name[l-4], ".pdf") == 0) { s = strdup(dirs[i].name); free(dirs); goto Found; } } free(dirs); } Found: /* s is pdf filename or nil */ close(dirfd); if (!s) { fprint(2, "no pdf file found!\n"); return; } from = open(s, OREAD); if (from < 0) sysfatal("cannot open source pdf file: %r"); free(s); if (pdffile) { remove(pdffile); free(pdffile); pdffile = nil; } round++; pdffile = smprint("/tmp/livedoc.%d.pdf", round); to = create(pdffile, OWRITE, 0666); if (to < 0) sysfatal("unable to create file: %r"); seek(from, 0, 0); while (r = read(from, buf, sizeof(buf))) { if (write(to, buf, r) != r) sysfatal("write error"); } close(from); close(to); } void plumbpage(int page) { char *s; int fd; if (!pdffile) return; if (noplumb) { print("%s!%d\n", pdffile, page); return; } fd = plumbopen("send", OWRITE|OCEXEC); if (fd < 0) { fprint(2, "unable to open plumber: %r\n"); return; } s = smprint("%s!%d", pdffile, page); plumbsendtext(fd, "Livedoc", "image", "/tmp", s); free(s); close(fd); } int singlerun = 0; int tick(void) { Winpos pos; int p; int tfd; /* access(2) doesn't work in this case for some reason */ tfd = open(stag, OREAD); if (tfd < 0) { return 0; } close(tfd); fprint(sctlfd, "dirty"); copydata(); pos = finddot(); dumpfile(pos); p = pagedot(); compile(); copyfile(); plumbpage(p); fprint(sctlfd, "clean"); return !singlerun; } char *ramfsargs[] = { "ramfs", "-m", "/mnt/livedoc", nil }; void main(int argc, char **argv) { char *s, sidstr[13]; char *winctl, *winaddr, *windata; int sleeptimer = 5000; int n, sid; ARGBEGIN{ case 'h': usage(); return; case 't': sleeptimer = abs(atoi(EARGF(usage()))); break; case 'm': mark = EARGF(usage()); break; case 'p': noplumb++; break; case 'q': singlerun++; break; }ARGEND; s = getenv("winid"); if (!s) { fprint(2, Enoacme); exits(Enoacme); } winid = atoi(s); file = getenv("%"); if (!file) { fprint(2, Enofile); exits(Enofile); } filedir = strdup(file); *strrchr(filedir, '/') = 0; targetfile = strrchr(file, '/') + 1; targetfile = smprint("%s/%s", ldpath, targetfile); winctl = smprint("/mnt/acme/%d/ctl", winid); winaddr = smprint("/mnt/acme/%d/addr", winid); windata = smprint("/mnt/acme/%d/xdata", winid); ctlfd = open(winctl, ORDWR); addrfd = open(winaddr, ORDWR); datafd = open(windata, OREAD); free(winctl); free(winaddr); free(windata); sctlfd = open("/mnt/acme/new/ctl", ORDWR); if (sctlfd < 0) sysfatal("unable to open file: %r"); read(sctlfd, sidstr, sizeof(sidstr)); sid = atoi(sidstr); stag = smprint("/mnt/acme/%d/tag", sid); stagfd = open(stag, ORDWR); fprint(sctlfd, "scratch\n"); fprint(sctlfd, "name %s/-Livedoc\n", filedir); if (ctlfd < 0 || addrfd < 0 || datafd < 0) { sysfatal("unable to open file: %r"); } runcmd("/bin/ramfs", ramfsargs); n = 0; while (tick() && n != -1) n = sleep(sleeptimer); if (pdffile) { remove(pdffile); free(pdffile); } close(ctlfd); close(addrfd); close(datafd); free(filedir); free(targetfile); free(stag); exits(nil); }