History

cmd(3): port the os command execution device from inferno (win32 only so far)

the devcmd device (/mnt/term/cmd) allows execution of commands on the os, with access stdin/stdout/stderr of the executing command.

cinap_lenrek committed 6 years ago

Commit 7c69c6d1 parent 748142a10 files · +1070 −43Browse files

Unified · Split

10 files
  1. kern/Makefile +2 −1
  2. kern/devcmd.c +700 −0
  3. kern/devlfd-posix.c +8 −19
  4. kern/devlfd-win32.c +113 −0
  5. kern/devtab.c +2 −0
  6. kern/fns.h +6 −0
  7. kern/posix.c +49 −11
  8. kern/procinit.c +30 −5
  9. kern/win32.c +159 −7
  10. main.c +1 −0
kern/Makefile+2−1
@@ -10,13 +10,14 @@ OFILES=\ · 9 unmodified lines
1010 dev.$O\
1111 devaudio.$O\
1212 devaudio-$(AUDIO).$O\
13+ devcmd.$O\
1314 devcons.$O\
1415 devdraw.$O\
1516 devfs-$(OS).$O\
1617 devip.$O\
1718 devip-$(OS).$O\
1819 devkbd.$O\
19− devlfd.$O\
20+ devlfd-$(OS).$O\
2021 devmnt.$O\
2122 devmouse.$O\
2223 devpipe.$O\
kern/devcmd.c+700−0
@@ -0,0 +1,700 @@
1+#include "u.h"
2+#include "lib.h"
3+#include "dat.h"
4+#include "fns.h"
5+#include "error.h"
6+
7+enum
8+{
9+ Qtopdir, /* top level directory */
10+ Qcmd,
11+ Qclonus,
12+ Qconvdir,
13+ Qconvbase,
14+ Qdata = Qconvbase,
15+ Qstderr,
16+ Qctl,
17+ Qstatus,
18+ Qwait,
19+
20+ Debug=0 /* to help debug os.c */
21+};
22+#define TYPE(x) ((ulong)(x).path & 0xf)
23+#define CONV(x) (((ulong)(x).path >> 4)&0xfff)
24+#define QID(c, y) (((c)<<4) | (y))
25+
26+typedef struct Conv Conv;
27+struct Conv
28+{
29+ int x;
30+ int inuse;
31+ Chan* fd[3]; /* stdin, stdout, and stderr */
32+ int count[3]; /* number of readers on stdin/stdout/stderr */
33+ int perm;
34+ char* owner;
35+ char* state;
36+ Cmdbuf* cmd;
37+ char* dir;
38+ QLock l; /* protects state changes */
39+ Queue* waitq;
40+ void* child;
41+ char* error; /* on start up */
42+ int nice;
43+ short killonclose;
44+ short killed;
45+ Rendez startr;
46+};
47+
48+static struct
49+{
50+ QLock l;
51+ int nc;
52+ int maxconv;
53+ Conv** conv;
54+} cmd;
55+
56+static Conv* cmdclone(char*);
57+static void cmdproc(void*);
58+
59+static int
60+cmd3gen(Chan *c, int i, Dir *dp)
61+{
62+ Qid q;
63+ Conv *cv;
64+
65+ cv = cmd.conv[CONV(c->qid)];
66+ switch(i){
67+ default:
68+ return -1;
69+ case Qdata:
70+ mkqid(&q, QID(CONV(c->qid), Qdata), 0, QTFILE);
71+ devdir(c, q, "data", 0, cv->owner, cv->perm, dp);
72+ return 1;
73+ case Qstderr:
74+ mkqid(&q, QID(CONV(c->qid), Qstderr), 0, QTFILE);
75+ devdir(c, q, "stderr", 0, cv->owner, 0444, dp);
76+ return 1;
77+ case Qctl:
78+ mkqid(&q, QID(CONV(c->qid), Qctl), 0, QTFILE);
79+ devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp);
80+ return 1;
81+ case Qstatus:
82+ mkqid(&q, QID(CONV(c->qid), Qstatus), 0, QTFILE);
83+ devdir(c, q, "status", 0, cv->owner, 0444, dp);
84+ return 1;
85+ case Qwait:
86+ mkqid(&q, QID(CONV(c->qid), Qwait), 0, QTFILE);
87+ devdir(c, q, "wait", 0, cv->owner, 0444, dp);
88+ return 1;
89+ }
90+}
91+
92+static int
93+cmdgen(Chan *c, char *name, Dirtab *d, int nd, int s, Dir *dp)
94+{
95+ Qid q;
96+ Conv *cv;
97+
98+ USED(name);
99+ USED(nd);
100+ USED(d);
101+
102+ if(s == DEVDOTDOT){
103+ switch(TYPE(c->qid)){
104+ case Qtopdir:
105+ case Qcmd:
106+ mkqid(&q, QID(0, Qtopdir), 0, QTDIR);
107+ devdir(c, q, "#C", 0, eve, DMDIR|0555, dp);
108+ break;
109+ case Qconvdir:
110+ mkqid(&q, QID(0, Qcmd), 0, QTDIR);
111+ devdir(c, q, "cmd", 0, eve, DMDIR|0555, dp);
112+ break;
113+ default:
114+ panic("cmdgen %llux", c->qid.path);
115+ }
116+ return 1;
117+ }
118+
119+ switch(TYPE(c->qid)) {
120+ case Qtopdir:
121+ if(s >= 1)
122+ return -1;
123+ mkqid(&q, QID(0, Qcmd), 0, QTDIR);
124+ devdir(c, q, "cmd", 0, "cmd", DMDIR|0555, dp);
125+ return 1;
126+ case Qcmd:
127+ if(s < cmd.nc) {
128+ cv = cmd.conv[s];
129+ mkqid(&q, QID(s, Qconvdir), 0, QTDIR);
130+ sprint(up->genbuf, "%d", s);
131+ devdir(c, q, up->genbuf, 0, cv->owner, DMDIR|0555, dp);
132+ return 1;
133+ }
134+ s -= cmd.nc;
135+ if(s == 0){
136+ mkqid(&q, QID(0, Qclonus), 0, QTFILE);
137+ devdir(c, q, "clone", 0, "cmd", 0666, dp);
138+ return 1;
139+ }
140+ return -1;
141+ case Qclonus:
142+ if(s == 0){
143+ mkqid(&q, QID(0, Qclonus), 0, QTFILE);
144+ devdir(c, q, "clone", 0, "cmd", 0666, dp);
145+ return 1;
146+ }
147+ return -1;
148+ case Qconvdir:
149+ return cmd3gen(c, Qconvbase+s, dp);
150+ case Qdata:
151+ case Qstderr:
152+ case Qctl:
153+ case Qstatus:
154+ case Qwait:
155+ return cmd3gen(c, TYPE(c->qid), dp);
156+ }
157+ return -1;
158+}
159+
160+static void
161+cmdinit(void)
162+{
163+ cmd.maxconv = 1000;
164+ cmd.conv = mallocz(sizeof(Conv*)*(cmd.maxconv+1), 1);
165+ /* cmd.conv is checked by cmdattach, below */
166+}
167+
168+static Chan *
169+cmdattach(char *spec)
170+{
171+ Chan *c;
172+
173+ if(cmd.conv == nil)
174+ error(Enomem);
175+ c = devattach('C', spec);
176+ mkqid(&c->qid, QID(0, Qtopdir), 0, QTDIR);
177+ return c;
178+}
179+
180+static Walkqid*
181+cmdwalk(Chan *c, Chan *nc, char **name, int nname)
182+{
183+ return devwalk(c, nc, name, nname, 0, 0, cmdgen);
184+}
185+
186+static int
187+cmdstat(Chan *c, uchar *db, int n)
188+{
189+ return devstat(c, db, n, 0, 0, cmdgen);
190+}
191+
192+static Chan *
193+cmdopen(Chan *c, int omode)
194+{
195+ int perm;
196+ Conv *cv;
197+ char *user;
198+
199+ perm = 0;
200+ omode = openmode(omode);
201+ switch(omode) {
202+ case OREAD:
203+ perm = 4;
204+ break;
205+ case OWRITE:
206+ perm = 2;
207+ break;
208+ case ORDWR:
209+ perm = 6;
210+ break;
211+ }
212+
213+ switch(TYPE(c->qid)) {
214+ default:
215+ break;
216+ case Qtopdir:
217+ case Qcmd:
218+ case Qconvdir:
219+ case Qstatus:
220+ if(omode != OREAD)
221+ error(Eperm);
222+ break;
223+ case Qclonus:
224+ qlock(&cmd.l);
225+ if(waserror()){
226+ qunlock(&cmd.l);
227+ nexterror();
228+ }
229+ cv = cmdclone(up->user);
230+ poperror();
231+ qunlock(&cmd.l);
232+ if(cv == 0)
233+ error(Enodev);
234+ mkqid(&c->qid, QID(cv->x, Qctl), 0, QTFILE);
235+ break;
236+ case Qdata:
237+ case Qstderr:
238+ case Qctl:
239+ case Qwait:
240+ qlock(&cmd.l);
241+ cv = cmd.conv[CONV(c->qid)];
242+ qlock(&cv->l);
243+ if(waserror()){
244+ qunlock(&cv->l);
245+ qunlock(&cmd.l);
246+ nexterror();
247+ }
248+ user = up->user;
249+ if((perm & (cv->perm>>6)) != perm) {
250+ if(strcmp(user, cv->owner) != 0 ||
251+ (perm & cv->perm) != perm)
252+ error(Eperm);
253+ }
254+ switch(TYPE(c->qid)){
255+ case Qdata:
256+ if(omode == OWRITE || omode == ORDWR)
257+ cv->count[0]++;
258+ if(omode == OREAD || omode == ORDWR)
259+ cv->count[1]++;
260+ break;
261+ case Qstderr:
262+ if(omode != OREAD)
263+ error(Eperm);
264+ cv->count[2]++;
265+ break;
266+ case Qwait:
267+ if(cv->waitq == nil)
268+ cv->waitq = qopen(1024, Qmsg, nil, 0);
269+ break;
270+ }
271+ cv->inuse++;
272+ if(cv->inuse == 1) {
273+ cv->state = "Open";
274+ kstrdup(&cv->owner, user);
275+ cv->perm = 0660;
276+ cv->nice = 0;
277+ }
278+ poperror();
279+ qunlock(&cv->l);
280+ qunlock(&cmd.l);
281+ break;
282+ }
283+ c->mode = omode;
284+ c->flag |= COPEN;
285+ c->offset = 0;
286+ return c;
287+}
288+
289+static void
290+closeconv(Conv *c)
291+{
292+ kstrdup(&c->owner, "cmd");
293+ kstrdup(&c->dir, ".");
294+ c->perm = 0666;
295+ c->state = "Closed";
296+ c->killonclose = 0;
297+ c->killed = 0;
298+ c->nice = 0;
299+ free(c->cmd);
300+ c->cmd = nil;
301+ if(c->waitq != nil){
302+ qfree(c->waitq);
303+ c->waitq = nil;
304+ }
305+ free(c->error);
306+ c->error = nil;
307+}
308+
309+static void
310+cmdfdclose(Conv *c, int fd)
311+{
312+ if(--c->count[fd] == 0 && c->fd[fd] != nil){
313+ cclose(c->fd[fd]);
314+ c->fd[fd] = nil;
315+ }
316+}
317+
318+static void
319+cmdclose(Chan *c)
320+{
321+ Conv *cc;
322+ int r;
323+
324+ if((c->flag & COPEN) == 0)
325+ return;
326+
327+ switch(TYPE(c->qid)) {
328+ case Qctl:
329+ case Qdata:
330+ case Qstderr:
331+ case Qwait:
332+ cc = cmd.conv[CONV(c->qid)];
333+ qlock(&cc->l);
334+ if(TYPE(c->qid) == Qdata){
335+ if(c->mode == OWRITE || c->mode == ORDWR)
336+ cmdfdclose(cc, 0);
337+ if(c->mode == OREAD || c->mode == ORDWR)
338+ cmdfdclose(cc, 1);
339+ }else if(TYPE(c->qid) == Qstderr)
340+ cmdfdclose(cc, 2);
341+
342+ r = --cc->inuse;
343+ if(cc->child != nil){
344+ if(!cc->killed)
345+ if(r == 0 || (cc->killonclose && TYPE(c->qid) == Qctl)){
346+ iprint("cmdclose killing (killonclose %d)\n", cc->killonclose);
347+ oscmdkill(cc->child);
348+ cc->killed = 1;
349+ }
350+ }else if(r == 0)
351+ closeconv(cc);
352+
353+ qunlock(&cc->l);
354+ break;
355+ }
356+}
357+
358+static long
359+cmdread(Chan *ch, void *a, long n, vlong offset)
360+{
361+ Conv *c;
362+ char *p, *cmds;
363+ int fd;
364+
365+ USED(offset);
366+
367+ p = a;
368+ switch(TYPE(ch->qid)) {
369+ default:
370+ error(Eperm);
371+ case Qcmd:
372+ case Qtopdir:
373+ case Qconvdir:
374+ return devdirread(ch, a, n, 0, 0, cmdgen);
375+ case Qctl:
376+ sprint(up->genbuf, "%ld", CONV(ch->qid));
377+ return readstr(offset, p, n, up->genbuf);
378+ case Qstatus:
379+ c = cmd.conv[CONV(ch->qid)];
380+ cmds = "";
381+ if(c->cmd != nil)
382+ cmds = c->cmd->f[1];
383+ snprint(up->genbuf, sizeof(up->genbuf), "cmd/%d %d %s %q %q\n",
384+ c->x, c->inuse, c->state, c->dir, cmds);
385+ return readstr(offset, p, n, up->genbuf);
386+ case Qdata:
387+ case Qstderr:
388+ fd = 1;
389+ if(TYPE(ch->qid) == Qstderr)
390+ fd = 2;
391+ c = cmd.conv[CONV(ch->qid)];
392+ qlock(&c->l);
393+ ch = c->fd[fd];
394+ if(ch == nil){
395+ qunlock(&c->l);
396+ return 0;
397+ }
398+ incref(&ch->ref);
399+ qunlock(&c->l);
400+ if(waserror()){
401+ cclose(ch);
402+ nexterror();
403+ }
404+ n = devtab[ch->type]->read(ch, a, n, 0);
405+ if(n < 0)
406+ oserror();
407+ poperror();
408+ cclose(ch);
409+ return n;
410+ case Qwait:
411+ c = cmd.conv[CONV(ch->qid)];
412+ return qread(c->waitq, a, n);
413+ }
414+}
415+
416+static int
417+cmdstarted(void *a)
418+{
419+ Conv *c;
420+
421+ c = a;
422+ return c->child != nil || c->error != nil || strcmp(c->state, "Execute") != 0;
423+}
424+
425+enum
426+{
427+ CMdir,
428+ CMexec,
429+ CMkill,
430+ CMnice,
431+ CMkillonclose
432+};
433+
434+static
435+Cmdtab cmdtab[] = {
436+ CMdir, "dir", 2,
437+ CMexec, "exec", 0,
438+ CMkill, "kill", 1,
439+ CMnice, "nice", 0,
440+ CMkillonclose, "killonclose", 0,
441+};
442+
443+static long
444+cmdwrite(Chan *ch, void *a, long n, vlong offset)
445+{
446+ int i, r;
447+ Conv *c;
448+ Cmdbuf *cb;
449+ Cmdtab *ct;
450+
451+ USED(offset);
452+
453+ switch(TYPE(ch->qid)) {
454+ default:
455+ error(Eperm);
456+ case Qctl:
457+ c = cmd.conv[CONV(ch->qid)];
458+ cb = parsecmd(a, n);
459+ if(waserror()){
460+ free(cb);
461+ nexterror();
462+ }
463+ ct = lookupcmd(cb, cmdtab, nelem(cmdtab));
464+ switch(ct->index){
465+ case CMdir:
466+ kstrdup(&c->dir, cb->f[1]);
467+ break;
468+ case CMexec:
469+ poperror(); /* cb */
470+ qlock(&c->l);
471+ if(waserror()){
472+ qunlock(&c->l);
473+ free(cb);
474+ nexterror();
475+ }
476+ if(c->child != nil || c->cmd != nil)
477+ error(Einuse);
478+ for(i = 0; i < nelem(c->fd); i++)
479+ if(c->fd[i] != nil)
480+ error(Einuse);
481+ if(cb->nf < 1)
482+ error(Etoosmall);
483+ kproc("cmdproc", cmdproc, c); /* cmdproc held back until unlock below */
484+ free(c->cmd);
485+ c->cmd = cb; /* don't free cb */
486+ c->state = "Execute";
487+ poperror();
488+ qunlock(&c->l);
489+ while(waserror())
490+ ;
491+ sleep(&c->startr, cmdstarted, c);
492+ poperror();
493+ if(c->error)
494+ error(c->error);
495+ return n; /* avoid free(cb) below */
496+ case CMkill:
497+ qlock(&c->l);
498+ if(waserror()){
499+ qunlock(&c->l);
500+ nexterror();
501+ }
502+ if(c->child == nil)
503+ error("not started");
504+ if(oscmdkill(c->child) < 0)
505+ oserror();
506+ poperror();
507+ qunlock(&c->l);
508+ break;
509+ case CMnice:
510+ c->nice = cb->nf > 1? atoi(cb->f[1]): 1;
511+ break;
512+ case CMkillonclose:
513+ c->killonclose = 1;
514+ break;
515+ }
516+ poperror();
517+ free(cb);
518+ break;
519+ case Qdata:
520+ c = cmd.conv[CONV(ch->qid)];
521+ qlock(&c->l);
522+ ch = c->fd[0];
523+ if(ch == nil){
524+ qunlock(&c->l);
525+ error(Ehungup);
526+ }
527+ incref(&ch->ref);
528+ qunlock(&c->l);
529+ if(waserror()){
530+ cclose(ch);
531+ nexterror();
532+ }
533+ r = devtab[ch->type]->write(ch, a, n, 0);
534+ if(r == 0)
535+ error(Ehungup);
536+ if(r < 0) {
537+ /* XXX perhaps should kill writer "write on closed pipe" here, 2nd time around? */
538+ oserror();
539+ }
540+ poperror();
541+ cclose(ch);
542+ return r;
543+ }
544+ return n;
545+}
546+
547+static int
548+cmdwstat(Chan *c, uchar *dp, int n)
549+{
550+ Dir *d;
551+ Conv *cv;
552+
553+ switch(TYPE(c->qid)){
554+ default:
555+ error(Eperm);
556+ case Qctl:
557+ case Qdata:
558+ case Qstderr:
559+ d = malloc(sizeof(*d)+n);
560+ if(d == nil)
561+ error(Enomem);
562+ if(waserror()){
563+ free(d);
564+ nexterror();
565+ }
566+ n = convM2D(dp, n, d, (char*)&d[1]);
567+ if(n == 0)
568+ error(Eshortstat);
569+ cv = cmd.conv[CONV(c->qid)];
570+ if(!iseve() && strcmp(up->user, cv->owner) != 0)
571+ error(Eperm);
572+ if(!emptystr(d->uid))
573+ kstrdup(&cv->owner, d->uid);
574+ if(d->mode != ~0UL)
575+ cv->perm = d->mode & 0777;
576+ poperror();
577+ free(d);
578+ break;
579+ }
580+ return n;
581+}
582+
583+static Conv*
584+cmdclone(char *user)
585+{
586+ Conv *c, **pp, **ep;
587+ int i;
588+
589+ c = nil;
590+ ep = &cmd.conv[cmd.maxconv];
591+ for(pp = cmd.conv; pp < ep; pp++) {
592+ c = *pp;
593+ if(c == nil) {
594+ c = malloc(sizeof(Conv));
595+ if(c == nil)
596+ error(Enomem);
597+ qlock(&c->l);
598+ c->inuse = 1;
599+ c->x = pp - cmd.conv;
600+ cmd.nc++;
601+ *pp = c;
602+ break;
603+ }
604+ if(canqlock(&c->l)){
605+ if(c->inuse == 0 && c->child == nil)
606+ break;
607+ qunlock(&c->l);
608+ }
609+ }
610+ if(pp >= ep)
611+ return nil;
612+
613+ c->inuse = 1;
614+ kstrdup(&c->owner, user);
615+ kstrdup(&c->dir, ".");
616+ c->perm = 0660;
617+ c->state = "Closed";
618+ for(i=0; i<nelem(c->fd); i++)
619+ c->fd[i] = nil;
620+
621+ qunlock(&c->l);
622+ return c;
623+}
624+
625+static void
626+cmdproc(void *a)
627+{
628+ Conv *c;
629+ int n;
630+ char status[ERRMAX];
631+ void *t;
632+
633+ c = a;
634+ qlock(&c->l);
635+ if(Debug)
636+ print("f[0]=%q f[1]=%q\n", c->cmd->f[0], c->cmd->f[1]);
637+ if(waserror()){
638+ if(Debug)
639+ print("failed: %q\n", up->errstr);
640+ kstrdup(&c->error, up->errstr);
641+ c->state = "Done";
642+ wakeup(&c->startr);
643+ qunlock(&c->l);
644+ pexit("cmdproc", 0);
645+ }
646+ t = oscmd(c->cmd->f+1, c->nice, c->dir, c->fd);
647+ if(t == nil)
648+ oserror();
649+ c->child = t; /* to allow oscmdkill */
650+ poperror();
651+ qunlock(&c->l);
652+ wakeup(&c->startr);
653+ if(Debug)
654+ print("started\n");
655+ while(waserror()){
656+ iprint("XXX %s\n", up->errstr);
657+ oscmdkill(t);
658+ }
659+ n = oscmdwait(t, status, sizeof(status));
660+ if(n < 0){
661+ oserrstr();
662+ n = snprint(status, sizeof(status), "0 0 0 0 %q", up->errstr);
663+ }
664+ qlock(&c->l);
665+ c->child = nil;
666+ oscmdfree(t);
667+ if(Debug){
668+ status[n]=0;
669+ print("done %s %s %s: %q\n", chanpath(c->fd[0]), chanpath(c->fd[1]), chanpath(c->fd[2]), status);
670+ }
671+ if(c->inuse > 0){
672+ c->state = "Done";
673+ if(c->waitq != nil)
674+ qproduce(c->waitq, status, n);
675+ }else
676+ closeconv(c);
677+ qunlock(&c->l);
678+ pexit("", 0);
679+}
680+
681+Dev cmddevtab = {
682+ 'C',
683+ "cmd",
684+
685+ devreset,
686+ cmdinit,
687+ devshutdown,
688+ cmdattach,
689+ cmdwalk,
690+ cmdstat,
691+ cmdopen,
692+ devcreate,
693+ cmdclose,
694+ cmdread,
695+ devbread,
696+ cmdwrite,
697+ devbwrite,
698+ devremove,
699+ cmdwstat
700+};
kern/devlfd-posix.crenamed from kern/devlfd.c+8−19
@@ -1,21 +1,21 @@
11 #include "u.h"
2−#include <errno.h>
2+#include <errno.h>
33 #include "lib.h"
44 #include "dat.h"
55 #include "fns.h"
66 #include "error.h"
77
8−#undef pread
9−#undef pwrite
8+#undef read
9+#undef write
1010
1111 Chan*
12−lfdchan(int fd)
12+lfdchan(void *fd)
1313 {
1414 Chan *c;
1515
1616 c = newchan();
1717 c->type = devno('L', 0);
18− c->aux = (void*)(uintptr)fd;
18+ c->aux = fd;
1919 c->path = newpath("fd");
2020 c->mode = ORDWR;
2121 c->qid.type = 0;
@@ -26,12 +26,6 @@ lfdchan(int fd) · 4 unmodified lines
2626 return c;
2727 }
2828
29−int
30−lfdfd(int fd)
31−{
32− return newfd(lfdchan(fd));
33−}
34−
3529 static Chan*
3630 lfdattach(char *x)
3731 {
@@ -48,7 +42,6 @@ lfdwalk(Chan *c, Chan *nc, char **name, int nname) · 10 unmodified lines
4842 USED(nc);
4943 USED(name);
5044 USED(nname);
51−
5245 error(Egreg);
5346 return nil;
5447 }
@@ -68,7 +61,6 @@ lfdopen(Chan *c, int omode) · 13 unmodified lines
6861 {
6962 USED(c);
7063 USED(omode);
71−
7264 error(Egreg);
7365 return nil;
7466 }
@@ -83,11 +75,10 @@ static long · 8 unmodified lines
8375 lfdread(Chan *c, void *buf, long n, vlong off)
8476 {
8577 USED(off); /* can't pread on pipes */
78+
8679 n = read((int)(uintptr)c->aux, buf, n);
87− if(n < 0){
88− iprint("error %d\n", errno);
80+ if(n < 0)
8981 oserror();
90− }
9182 return n;
9283 }
9384
@@ -97,10 +88,8 @@ lfdwrite(Chan *c, void *buf, long n, vlong off) · 3 unmodified lines
9788 USED(off); /* can't pread on pipes */
9889
9990 n = write((int)(uintptr)c->aux, buf, n);
100− if(n < 0){
101− iprint("error %d\n", errno);
91+ if(n < 0)
10292 oserror();
103− }
10493 return n;
10594 }
10695
kern/devlfd-win32.c+113−0
@@ -0,0 +1,113 @@
1+#include <windows.h>
2+#include "u.h"
3+#include "lib.h"
4+#include "dat.h"
5+#include "fns.h"
6+#include "error.h"
7+
8+Chan*
9+lfdchan(void *fd)
10+{
11+ Chan *c;
12+
13+ c = newchan();
14+ c->type = devno('L', 0);
15+ c->aux = fd;
16+ c->path = newpath("fd");
17+ c->mode = ORDWR;
18+ c->qid.type = 0;
19+ c->qid.path = 0;
20+ c->qid.vers = 0;
21+ c->dev = 0;
22+ c->offset = 0;
23+ return c;
24+}
25+
26+static Chan*
27+lfdattach(char *x)
28+{
29+ USED(x);
30+
31+ error(Egreg);
32+ return nil;
33+}
34+
35+static Walkqid*
36+lfdwalk(Chan *c, Chan *nc, char **name, int nname)
37+{
38+ USED(c);
39+ USED(nc);
40+ USED(name);
41+ USED(nname);
42+
43+ error(Egreg);
44+ return nil;
45+}
46+
47+static int
48+lfdstat(Chan *c, uchar *dp, int n)
49+{
50+ USED(c);
51+ USED(dp);
52+ USED(n);
53+ error(Egreg);
54+ return -1;
55+}
56+
57+static Chan*
58+lfdopen(Chan *c, int omode)
59+{
60+ USED(c);
61+ USED(omode);
62+ error(Egreg);
63+ return nil;
64+}
65+
66+static void
67+lfdclose(Chan *c)
68+{
69+ CloseHandle((HANDLE)c->aux);
70+}
71+
72+static long
73+lfdread(Chan *c, void *buf, long n, vlong off)
74+{
75+ DWORD r;
76+
77+ USED(off); /* can't pread on pipes */
78+ if(!ReadFile((HANDLE)c->aux, buf, (DWORD)n, &r, NULL))
79+ oserror();
80+ return r;
81+}
82+
83+static long
84+lfdwrite(Chan *c, void *buf, long n, vlong off)
85+{
86+ DWORD r;
87+
88+ USED(off); /* can't pread on pipes */
89+ if(!WriteFile((HANDLE)c->aux, buf, (DWORD)n, &r, NULL))
90+ oserror();
91+ return r;
92+}
93+
94+Dev lfddevtab = {
95+ 'L',
96+ "lfd",
97+
98+ devreset,
99+ devinit,
100+ devshutdown,
101+ lfdattach,
102+ lfdwalk,
103+ lfdstat,
104+ lfdopen,
105+ devcreate,
106+ lfdclose,
107+ lfdread,
108+ devbread,
109+ lfdwrite,
110+ devbwrite,
111+ devremove,
112+ devwstat,
113+};
kern/devtab.c+2−0
@@ -17,6 +17,7 @@ extern Dev mntdevtab; · 16 unmodified lines
1717 extern Dev lfddevtab;
1818 extern Dev audiodevtab;
1919 extern Dev kbddevtab;
20+extern Dev cmddevtab;
2021
2122 Dev *devtab[] = {
2223 &rootdevtab,
@@ -32,6 +33,7 @@ Dev *devtab[] = { · 9 unmodified lines
3233 &lfddevtab,
3334 &audiodevtab,
3435 &kbddevtab,
36+ &cmddevtab,
3537 0
3638 };
3739
kern/fns.h+6−0
@@ -84,6 +84,7 @@ void ksetenv(char*, char*, int); · 83 unmodified lines
8484 void kstrcpy(char*, char*, int);
8585 void kstrdup(char**, char*);
8686 long latin1(Rune*, int);
87+Chan* lfdchan(void *);
8788 void lock(Lock*);
8889 void lockinit(void);
8990 void logopen(Log*);
@@ -114,8 +115,13 @@ Proc* newproc(void); · 24 unmodified lines
114115 char* nextelem(char*, char*);
115116 void nexterror(void);
116117 int openmode(ulong);
118+void* oscmd(char**, int, char*, Chan**);
119+int oscmdwait(void*, char*, int);
120+int oscmdkill(void*);
121+void oscmdfree(void*);
117122 void oserrstr(void);
118123 void oserror(void);
124+void osexit(void);
119125 Block* packblock(Block*);
120126 Block* padblock(Block*, int);
121127 void panic(char*, ...);
kern/posix.c+49−11
@@ -106,7 +106,18 @@ oserror(void) · 105 unmodified lines
106106 nexterror();
107107 }
108108
109−static void* tramp(void*);
109+static void*
110+tramp(void *vp)
111+{
112+ Proc *p;
113+
114+ p = vp;
115+ if(pthread_setspecific(prdakey, p))
116+ panic("cannot setspecific");
117+ (*p->fn)(p->arg);
118+ pexit("", 0);
119+ return 0;
120+}
110121
111122 void
112123 osproc(Proc *p)
@@ -120,19 +131,11 @@ osproc(Proc *p) · 7 unmodified lines
120131 sched_yield();
121132 }
122133
123−static void*
124−tramp(void *vp)
134+void
135+osexit(void)
125136 {
126− Proc *p;
127−
128− p = vp;
129− if(pthread_setspecific(prdakey, p))
130− panic("cannot setspecific");
131− (*p->fn)(p->arg);
132− /* BUG: leaks Proc */
133137 pthread_setspecific(prdakey, 0);
134138 pthread_exit(0);
135− return 0;
136139 }
137140
138141 void
@@ -163,6 +166,41 @@ procwakeup(Proc *p) · 24 unmodified lines
163166 pthread_mutex_unlock(&op->mutex);
164167 }
165168
169+void*
170+oscmd(char **argv, int nice, char *dir, Chan **fd)
171+{
172+ USED(argv);
173+ USED(nice);
174+ USED(dir);
175+ USED(fd);
176+
177+ error("not implemented");
178+ return nil;
179+}
180+
181+int
182+oscmdwait(void *c, char *status, int nstatus)
183+{
184+ USED(c);
185+ USED(status);
186+ USED(nstatus);
187+
188+ return -1;
189+}
190+
191+int
192+oscmdkill(void *c)
193+{
194+ USED(c);
195+ return -1;
196+}
197+
198+void
199+oscmdfree(void *c)
200+{
201+ USED(c);
202+}
203+
166204 static int randfd;
167205 #undef open
168206 void
kern/procinit.c+30−5
@@ -4,8 +4,6 @@ · 3 unmodified lines
44 #include "fns.h"
55 #include "error.h"
66
7−Rgrp *thergrp;
8−
97 void
108 procinit0(void)
119 {
@@ -51,13 +49,13 @@ kproc(char *name, void (*fn)(void*), void *arg) · 39 unmodified lines
5149 p->slash = cclone(up->slash);
5250 p->dot = cclone(up->dot);
5351 p->rgrp = up->rgrp;
54− if(p->rgrp)
52+ if(p->rgrp != nil)
5553 incref(&p->rgrp->ref);
5654 p->pgrp = up->pgrp;
57− if(up->pgrp)
55+ if(up->pgrp != nil)
5856 incref(&up->pgrp->ref);
5957 p->fgrp = up->fgrp;
60− if(p->fgrp)
58+ if(p->fgrp != nil)
6159 incref(&p->fgrp->ref);
6260 strecpy(p->text, p->text+sizeof p->text, name);
6361
@@ -65,3 +63,30 @@ kproc(char *name, void (*fn)(void*), void *arg) · 1 unmodified line
6563 return p->pid;
6664 }
6765
66+void
67+pexit(char *msg, int freemem)
68+{
69+ Proc *p = up;
70+
71+ USED(msg);
72+ USED(freemem);
73+
74+ if(p->pgrp != nil){
75+ closepgrp(p->pgrp);
76+ p->pgrp = nil;
77+ }
78+ if(p->rgrp != nil){
79+ closergrp(p->rgrp);
80+ p->rgrp = nil;
81+ }
82+ if(p->fgrp != nil){
83+ closefgrp(p->fgrp);
84+ p->fgrp = nil;
85+ }
86+
87+ cclose(p->dot);
88+ cclose(p->slash);
89+
90+ free(p);
91+ osexit();
92+}
kern/win32.c+159−7
@@ -92,7 +92,7 @@ tramp(LPVOID vp) · 91 unmodified lines
9292 _setproc(p);
9393 op->tid = GetCurrentThreadId();
9494 (*p->fn)(p->arg);
95− ExitThread(0);
95+ pexit("", 0);
9696 return 0;
9797 }
9898
@@ -107,6 +107,12 @@ osproc(Proc *p) · 8 unmodified lines
107107 }
108108 }
109109
110+void
111+osexit(void)
112+{
113+ ExitThread(0);
114+}
115+
110116 void
111117 procsleep(void)
112118 {
@@ -251,14 +257,14 @@ WinMain(HINSTANCE x, HINSTANCE y, LPSTR z, int w) · 138 unmodified lines
251257
252258 warg = GetCommandLineW();
253259 n = wcslen(warg)*UTFmax+1;
254− arg = malloc(n);
255− WideCharToMultiByte(CP_UTF8,0,warg,-1,arg,n,0,0);
260+ arg = smalloc(n);
261+ WideCharToMultiByte(CP_UTF8, 0, warg, -1, arg, n, 0, 0);
256262
257263 /* conservative guess at the number of args */
258264 for(argc=4,p=arg; *p; p++)
259265 if(*p == ' ' || *p == '\t')
260266 argc++;
261− argv = malloc(argc*sizeof(char*));
267+ argv = smalloc(argc*sizeof(char*));
262268 argc = args(argv, argc, arg);
263269
264270 main(argc, argv);
@@ -266,6 +272,154 @@ WinMain(HINSTANCE x, HINSTANCE y, LPSTR z, int w) · 1 unmodified line
266272 return 0;
267273 }
268274
275+static char*
276+qarg(char *s)
277+{
278+ char *d, *p;
279+ int n, c;
280+
281+ n = strlen(s);
282+ d = p = smalloc(3+2*n);
283+ if(s[0] == '"' || (strchr(s, ' ') == nil && strchr(s, '\t') == nil)){
284+ memmove(d, s, n+1);
285+ return d;
286+ }
287+ *p++ = '"';
288+ while((c = *s++) != 0){
289+ if(c == '\\' || c == '"')
290+ *p++ = '\\';
291+ *p++ = c;
292+ }
293+ *p++ = '"';
294+ *p = 0;
295+ return d;
296+}
297+
298+static wchar_t*
299+wcmdline(char **argv)
300+{
301+ wchar_t *s, *w, *e;
302+ int n, i;
303+ char *q;
304+
305+ n = 0;
306+ for(i = 0; argv[i] != nil; i++){
307+ q = qarg(argv[i]);
308+ n += strlen(q)+1;
309+ free(q);
310+ }
311+ s = smalloc((n+1)*sizeof(wchar_t));
312+ w = s;
313+ e = s + n;
314+ for(i = 0; argv[i] != nil; i++){
315+ if(i != 0)
316+ *w++ = L' ';
317+ q = qarg(argv[i]);
318+ w += MultiByteToWideChar(CP_UTF8, 0, q, strlen(argv[i]), w, e - w);
319+ free(q);
320+ }
321+ *w = 0;
322+ return s;
323+}
324+
325+void*
326+oscmd(char **argv, int nice, char *dir, Chan **fd)
327+{
328+ SECURITY_ATTRIBUTES sa;
329+ PROCESS_INFORMATION pi;
330+ STARTUPINFOW si;
331+ HANDLE p[3][2], tmp;
332+ wchar_t *wcmd, *wdir;
333+ int i;
334+
335+ memset(&sa, 0, sizeof(sa));
336+ sa.nLength = sizeof(sa);
337+ sa.lpSecurityDescriptor = NULL;
338+ sa.bInheritHandle = TRUE;
339+
340+ for(i = 0; i < 3; i++){
341+ if(!CreatePipe(&p[i][i==0], &p[i][i!=0], &sa, 0)
342+ || !DuplicateHandle(GetCurrentProcess(), p[i][0], GetCurrentProcess(), &tmp, 0, FALSE, DUPLICATE_SAME_ACCESS)){
343+ while(--i >= 0){
344+ CloseHandle(p[i][0]);
345+ CloseHandle(p[i][1]);
346+ }
347+ oserror();
348+ }
349+ CloseHandle(p[i][0]);
350+ p[i][0] = tmp;
351+ }
352+
353+ if(waserror()){
354+ for(i = 0; i < 3; i++){
355+ CloseHandle(p[i][0]);
356+ CloseHandle(p[i][1]);
357+ }
358+ nexterror();
359+ }
360+
361+ memset(&pi, 0, sizeof(pi));
362+ memset(&si, 0, sizeof(si));
363+ si.cb = sizeof(si);
364+ si.dwFlags = STARTF_USESTDHANDLES;
365+ si.hStdInput = p[0][1];
366+ si.hStdOutput = p[1][1];
367+ si.hStdError = p[2][1];
368+ si.lpDesktop = L"";
369+
370+ i = strlen(dir)+1;
371+ wdir = smalloc(i*sizeof(wchar_t));
372+ MultiByteToWideChar(CP_UTF8, 0, dir, i, wdir, i);
373+
374+ wcmd = wcmdline(argv);
375+ if(waserror()){
376+ free(wcmd);
377+ nexterror();
378+ }
379+
380+ if(!CreateProcessW(NULL, wcmd, NULL, NULL, TRUE, CREATE_NEW_PROCESS_GROUP|CREATE_NO_WINDOW, NULL, wdir, &si, &pi))
381+ oserror();
382+
383+ poperror();
384+ free(wcmd);
385+ free(wdir);
386+
387+ poperror();
388+ for(i = 0; i < 3; i++){
389+ fd[i] = lfdchan((void*)p[i][0]);
390+ CloseHandle(p[i][1]);
391+ }
392+ CloseHandle(pi.hThread);
393+ return (void*)pi.hProcess;
394+}
395+
396+int
397+oscmdwait(void *c, char *status, int nstatus)
398+{
399+ DWORD code = -1;
400+ for(;;){
401+ if(!GetExitCodeProcess((HANDLE)c, &code))
402+ return -1;
403+ if(code != STILL_ACTIVE)
404+ break;
405+ WaitForSingleObject((HANDLE)c, INFINITE);
406+ }
407+ return snprint(status, nstatus, "%d", (int)code);
408+}
409+
410+int
411+oscmdkill(void *c)
412+{
413+ TerminateProcess((HANDLE)c, 0);
414+ return 0;
415+}
416+
417+void
418+oscmdfree(void *c)
419+{
420+ CloseHandle((HANDLE)c);
421+}
422+
269423 void
270424 oserrstr(void)
271425 {
@@ -296,9 +450,7 @@ showfilewrite(char *a, int n) · 24 unmodified lines
296450 wchar_t *action, *arg, *cmd, *p;
297451 int m;
298452
299− cmd = malloc((n+1)*sizeof(wchar_t));
300− if(cmd == nil)
301− error("out of memory");
453+ cmd = smalloc((n+1)*sizeof(wchar_t));
302454 m = MultiByteToWideChar(CP_UTF8,0,a,n,cmd,n);
303455 while(m > 0 && cmd[m-1] == '\n')
304456 m--;
main.c+1−0
@@ -52,6 +52,7 @@ main(int argc, char **argv) · 51 unmodified lines
5252 if(bind("#U", "/root", MREPL) < 0)
5353 panic("bind #U: %r");
5454 bind("#A", "/dev", MAFTER);
55+ bind("#C", "/", MAFTER);
5556
5657 if(open("/dev/cons", OREAD) != 0)
5758 panic("open0: %r");

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t