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
10 dev.$O\10 dev.$O\
11 devaudio.$O\11 devaudio.$O\
12 devaudio-$(AUDIO).$O\12 devaudio-$(AUDIO).$O\
13 devcmd.$O\
13 devcons.$O\14 devcons.$O\
14 devdraw.$O\15 devdraw.$O\
15 devfs-$(OS).$O\16 devfs-$(OS).$O\
16 devip.$O\17 devip.$O\
17 devip-$(OS).$O\18 devip-$(OS).$O\
18 devkbd.$O\19 devkbd.$O\
19 devlfd.$O\20 devlfd-$(OS).$O\
20 devmnt.$O\21 devmnt.$O\
21 devmouse.$O\22 devmouse.$O\
22 devpipe.$O\23 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
7enum
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
26typedef struct Conv Conv;
27struct 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
48static struct
49{
50 QLock l;
51 int nc;
52 int maxconv;
53 Conv** conv;
54} cmd;
55
56static Conv* cmdclone(char*);
57static void cmdproc(void*);
58
59static int
60cmd3gen(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
92static int
93cmdgen(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
160static void
161cmdinit(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
168static Chan *
169cmdattach(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
180static Walkqid*
181cmdwalk(Chan *c, Chan *nc, char **name, int nname)
182{
183 return devwalk(c, nc, name, nname, 0, 0, cmdgen);
184}
185
186static int
187cmdstat(Chan *c, uchar *db, int n)
188{
189 return devstat(c, db, n, 0, 0, cmdgen);
190}
191
192static Chan *
193cmdopen(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
289static void
290closeconv(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
309static void
310cmdfdclose(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
318static void
319cmdclose(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
358static long
359cmdread(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
416static int
417cmdstarted(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
425enum
426{
427 CMdir,
428 CMexec,
429 CMkill,
430 CMnice,
431 CMkillonclose
432};
433
434static
435Cmdtab cmdtab[] = {
436 CMdir, "dir", 2,
437 CMexec, "exec", 0,
438 CMkill, "kill", 1,
439 CMnice, "nice", 0,
440 CMkillonclose, "killonclose", 0,
441};
442
443static long
444cmdwrite(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
547static int
548cmdwstat(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
583static Conv*
584cmdclone(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
625static void
626cmdproc(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
681Dev 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 @@
1#include "u.h"1#include "u.h"
2#include <errno.h>2#include <errno.h>
3#include "lib.h"3#include "lib.h"
4#include "dat.h"4#include "dat.h"
5#include "fns.h"5#include "fns.h"
6#include "error.h"6#include "error.h"
7 7
8#undef pread8#undef read
9#undef pwrite9#undef write
10 10
11Chan*11Chan*
12lfdchan(int fd)12lfdchan(void *fd)
13{13{
14 Chan *c;14 Chan *c;
15 15
16 c = newchan();16 c = newchan();
17 c->type = devno('L', 0);17 c->type = devno('L', 0);
18 c->aux = (void*)(uintptr)fd;18 c->aux = fd;
19 c->path = newpath("fd");19 c->path = newpath("fd");
20 c->mode = ORDWR;20 c->mode = ORDWR;
21 c->qid.type = 0;21 c->qid.type = 0;
@@ -26,12 +26,6 @@ lfdchan(int fd) · 4 unmodified lines
26 return c;26 return c;
27}27}
28 28
29int
30lfdfd(int fd)
31{
32 return newfd(lfdchan(fd));
33}
34
35static Chan*29static Chan*
36lfdattach(char *x)30lfdattach(char *x)
37{31{
@@ -48,7 +42,6 @@ lfdwalk(Chan *c, Chan *nc, char **name, int nname) · 10 unmodified lines
48 USED(nc);42 USED(nc);
49 USED(name);43 USED(name);
50 USED(nname);44 USED(nname);
51
52 error(Egreg);45 error(Egreg);
53 return nil;46 return nil;
54}47}
@@ -68,7 +61,6 @@ lfdopen(Chan *c, int omode) · 13 unmodified lines
68{61{
69 USED(c);62 USED(c);
70 USED(omode);63 USED(omode);
71
72 error(Egreg);64 error(Egreg);
73 return nil;65 return nil;
74}66}
@@ -83,11 +75,10 @@ static long · 8 unmodified lines
83lfdread(Chan *c, void *buf, long n, vlong off)75lfdread(Chan *c, void *buf, long n, vlong off)
84{76{
85 USED(off); /* can't pread on pipes */77 USED(off); /* can't pread on pipes */
78
86 n = read((int)(uintptr)c->aux, buf, n);79 n = read((int)(uintptr)c->aux, buf, n);
87 if(n < 0){80 if(n < 0)
88 iprint("error %d\n", errno);
89 oserror();81 oserror();
90 }
91 return n;82 return n;
92}83}
93 84
@@ -97,10 +88,8 @@ lfdwrite(Chan *c, void *buf, long n, vlong off) · 3 unmodified lines
97 USED(off); /* can't pread on pipes */88 USED(off); /* can't pread on pipes */
98 89
99 n = write((int)(uintptr)c->aux, buf, n);90 n = write((int)(uintptr)c->aux, buf, n);
100 if(n < 0){91 if(n < 0)
101 iprint("error %d\n", errno);
102 oserror();92 oserror();
103 }
104 return n;93 return n;
105}94}
106 95
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
8Chan*
9lfdchan(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
26static Chan*
27lfdattach(char *x)
28{
29 USED(x);
30
31 error(Egreg);
32 return nil;
33}
34
35static Walkqid*
36lfdwalk(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
47static int
48lfdstat(Chan *c, uchar *dp, int n)
49{
50 USED(c);
51 USED(dp);
52 USED(n);
53 error(Egreg);
54 return -1;
55}
56
57static Chan*
58lfdopen(Chan *c, int omode)
59{
60 USED(c);
61 USED(omode);
62 error(Egreg);
63 return nil;
64}
65
66static void
67lfdclose(Chan *c)
68{
69 CloseHandle((HANDLE)c->aux);
70}
71
72static long
73lfdread(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
83static long
84lfdwrite(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
94Dev 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
17extern Dev lfddevtab;17extern Dev lfddevtab;
18extern Dev audiodevtab;18extern Dev audiodevtab;
19extern Dev kbddevtab;19extern Dev kbddevtab;
20extern Dev cmddevtab;
20 21
21Dev *devtab[] = {22Dev *devtab[] = {
22 &rootdevtab,23 &rootdevtab,
@@ -32,6 +33,7 @@ Dev *devtab[] = { · 9 unmodified lines
32 &lfddevtab,33 &lfddevtab,
33 &audiodevtab,34 &audiodevtab,
34 &kbddevtab,35 &kbddevtab,
36 &cmddevtab,
35 037 0
36};38};
37 39
kern/fns.h+6−0
@@ -84,6 +84,7 @@ void ksetenv(char*, char*, int); · 83 unmodified lines
84void kstrcpy(char*, char*, int);84void kstrcpy(char*, char*, int);
85void kstrdup(char**, char*);85void kstrdup(char**, char*);
86long latin1(Rune*, int);86long latin1(Rune*, int);
87Chan* lfdchan(void *);
87void lock(Lock*);88void lock(Lock*);
88void lockinit(void);89void lockinit(void);
89void logopen(Log*);90void logopen(Log*);
@@ -114,8 +115,13 @@ Proc* newproc(void); · 24 unmodified lines
114char* nextelem(char*, char*);115char* nextelem(char*, char*);
115void nexterror(void);116void nexterror(void);
116int openmode(ulong);117int openmode(ulong);
118void* oscmd(char**, int, char*, Chan**);
119int oscmdwait(void*, char*, int);
120int oscmdkill(void*);
121void oscmdfree(void*);
117void oserrstr(void);122void oserrstr(void);
118void oserror(void);123void oserror(void);
124void osexit(void);
119Block* packblock(Block*);125Block* packblock(Block*);
120Block* padblock(Block*, int);126Block* padblock(Block*, int);
121void panic(char*, ...);127void panic(char*, ...);
kern/posix.c+49−11
@@ -106,7 +106,18 @@ oserror(void) · 105 unmodified lines
106 nexterror();106 nexterror();
107}107}
108 108
109static void* tramp(void*);109static void*
110tramp(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}
110 121
111void122void
112osproc(Proc *p)123osproc(Proc *p)
@@ -120,19 +131,11 @@ osproc(Proc *p) · 7 unmodified lines
120 sched_yield();131 sched_yield();
121}132}
122 133
123static void*134void
124tramp(void *vp)135osexit(void)
125{136{
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 */
133 pthread_setspecific(prdakey, 0);137 pthread_setspecific(prdakey, 0);
134 pthread_exit(0);138 pthread_exit(0);
135 return 0;
136}139}
137 140
138void141void
@@ -163,6 +166,41 @@ procwakeup(Proc *p) · 24 unmodified lines
163 pthread_mutex_unlock(&op->mutex);166 pthread_mutex_unlock(&op->mutex);
164}167}
165 168
169void*
170oscmd(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
181int
182oscmdwait(void *c, char *status, int nstatus)
183{
184 USED(c);
185 USED(status);
186 USED(nstatus);
187
188 return -1;
189}
190
191int
192oscmdkill(void *c)
193{
194 USED(c);
195 return -1;
196}
197
198void
199oscmdfree(void *c)
200{
201 USED(c);
202}
203
166static int randfd;204static int randfd;
167#undef open205#undef open
168void206void
kern/procinit.c+30−5
@@ -4,8 +4,6 @@ · 3 unmodified lines
4#include "fns.h"4#include "fns.h"
5#include "error.h"5#include "error.h"
6 6
7Rgrp *thergrp;
8
9void7void
10procinit0(void)8procinit0(void)
11{9{
@@ -51,13 +49,13 @@ kproc(char *name, void (*fn)(void*), void *arg) · 39 unmodified lines
51 p->slash = cclone(up->slash);49 p->slash = cclone(up->slash);
52 p->dot = cclone(up->dot);50 p->dot = cclone(up->dot);
53 p->rgrp = up->rgrp;51 p->rgrp = up->rgrp;
54 if(p->rgrp)52 if(p->rgrp != nil)
55 incref(&p->rgrp->ref);53 incref(&p->rgrp->ref);
56 p->pgrp = up->pgrp;54 p->pgrp = up->pgrp;
57 if(up->pgrp)55 if(up->pgrp != nil)
58 incref(&up->pgrp->ref);56 incref(&up->pgrp->ref);
59 p->fgrp = up->fgrp;57 p->fgrp = up->fgrp;
60 if(p->fgrp)58 if(p->fgrp != nil)
61 incref(&p->fgrp->ref);59 incref(&p->fgrp->ref);
62 strecpy(p->text, p->text+sizeof p->text, name);60 strecpy(p->text, p->text+sizeof p->text, name);
63 61
@@ -65,3 +63,30 @@ kproc(char *name, void (*fn)(void*), void *arg) · 1 unmodified line
65 return p->pid;63 return p->pid;
66}64}
67 65
66void
67pexit(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
92 _setproc(p);92 _setproc(p);
93 op->tid = GetCurrentThreadId();93 op->tid = GetCurrentThreadId();
94 (*p->fn)(p->arg);94 (*p->fn)(p->arg);
95 ExitThread(0);95 pexit("", 0);
96 return 0;96 return 0;
97}97}
98 98
@@ -107,6 +107,12 @@ osproc(Proc *p) · 8 unmodified lines
107 }107 }
108}108}
109 109
110void
111osexit(void)
112{
113 ExitThread(0);
114}
115
110void116void
111procsleep(void)117procsleep(void)
112{118{
@@ -251,14 +257,14 @@ WinMain(HINSTANCE x, HINSTANCE y, LPSTR z, int w) · 138 unmodified lines
251 257
252 warg = GetCommandLineW();258 warg = GetCommandLineW();
253 n = wcslen(warg)*UTFmax+1;259 n = wcslen(warg)*UTFmax+1;
254 arg = malloc(n);260 arg = smalloc(n);
255 WideCharToMultiByte(CP_UTF8,0,warg,-1,arg,n,0,0);261 WideCharToMultiByte(CP_UTF8, 0, warg, -1, arg, n, 0, 0);
256 262
257 /* conservative guess at the number of args */263 /* conservative guess at the number of args */
258 for(argc=4,p=arg; *p; p++)264 for(argc=4,p=arg; *p; p++)
259 if(*p == ' ' || *p == '\t')265 if(*p == ' ' || *p == '\t')
260 argc++;266 argc++;
261 argv = malloc(argc*sizeof(char*));267 argv = smalloc(argc*sizeof(char*));
262 argc = args(argv, argc, arg);268 argc = args(argv, argc, arg);
263 269
264 main(argc, argv);270 main(argc, argv);
@@ -266,6 +272,154 @@ WinMain(HINSTANCE x, HINSTANCE y, LPSTR z, int w) · 1 unmodified line
266 return 0;272 return 0;
267}273}
268 274
275static char*
276qarg(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
298static wchar_t*
299wcmdline(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
325void*
326oscmd(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
396int
397oscmdwait(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
410int
411oscmdkill(void *c)
412{
413 TerminateProcess((HANDLE)c, 0);
414 return 0;
415}
416
417void
418oscmdfree(void *c)
419{
420 CloseHandle((HANDLE)c);
421}
422
269void423void
270oserrstr(void)424oserrstr(void)
271{425{
@@ -296,9 +450,7 @@ showfilewrite(char *a, int n) · 24 unmodified lines
296 wchar_t *action, *arg, *cmd, *p;450 wchar_t *action, *arg, *cmd, *p;
297 int m;451 int m;
298 452
299 cmd = malloc((n+1)*sizeof(wchar_t));453 cmd = smalloc((n+1)*sizeof(wchar_t));
300 if(cmd == nil)
301 error("out of memory");
302 m = MultiByteToWideChar(CP_UTF8,0,a,n,cmd,n);454 m = MultiByteToWideChar(CP_UTF8,0,a,n,cmd,n);
303 while(m > 0 && cmd[m-1] == '\n')455 while(m > 0 && cmd[m-1] == '\n')
304 m--;456 m--;
main.c+1−0
@@ -52,6 +52,7 @@ main(int argc, char **argv) · 51 unmodified lines
52 if(bind("#U", "/root", MREPL) < 0)52 if(bind("#U", "/root", MREPL) < 0)
53 panic("bind #U: %r");53 panic("bind #U: %r");
54 bind("#A", "/dev", MAFTER);54 bind("#A", "/dev", MAFTER);
55 bind("#C", "/", MAFTER);
55 56
56 if(open("/dev/cons", OREAD) != 0)57 if(open("/dev/cons", OREAD) != 0)
57 panic("open0: %r");58 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