the devcmd device (/mnt/term/cmd) allows execution of commands on the os, with access stdin/stdout/stderr of the executing command.
Unified · Split
| @@ -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\ |
| @@ -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 | }; | ||
| @@ -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 pread | 8 | #undef read |
| 9 | #undef pwrite | 9 | #undef write |
| 10 | 10 | ||
| 11 | Chan* | 11 | Chan* |
| 12 | lfdchan(int fd) | 12 | lfdchan(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 | ||
| 29 | int | ||
| 30 | lfdfd(int fd) | ||
| 31 | { | ||
| 32 | return newfd(lfdchan(fd)); | ||
| 33 | } | ||
| 34 | |||
| 35 | static Chan* | 29 | static Chan* |
| 36 | lfdattach(char *x) | 30 | lfdattach(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 | |||
| 83 | lfdread(Chan *c, void *buf, long n, vlong off) | 75 | lfdread(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 | ||
| @@ -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 | }; | ||
| @@ -17,6 +17,7 @@ extern Dev mntdevtab; · 16 unmodified lines | |||
| 17 | extern Dev lfddevtab; | 17 | extern Dev lfddevtab; |
| 18 | extern Dev audiodevtab; | 18 | extern Dev audiodevtab; |
| 19 | extern Dev kbddevtab; | 19 | extern Dev kbddevtab; |
| 20 | extern Dev cmddevtab; | ||
| 20 | 21 | ||
| 21 | Dev *devtab[] = { | 22 | Dev *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 | 0 | 37 | 0 |
| 36 | }; | 38 | }; |
| 37 | 39 | ||
| @@ -84,6 +84,7 @@ void ksetenv(char*, char*, int); · 83 unmodified lines | |||
| 84 | void kstrcpy(char*, char*, int); | 84 | void kstrcpy(char*, char*, int); |
| 85 | void kstrdup(char**, char*); | 85 | void kstrdup(char**, char*); |
| 86 | long latin1(Rune*, int); | 86 | long latin1(Rune*, int); |
| 87 | Chan* lfdchan(void *); | ||
| 87 | void lock(Lock*); | 88 | void lock(Lock*); |
| 88 | void lockinit(void); | 89 | void lockinit(void); |
| 89 | void logopen(Log*); | 90 | void logopen(Log*); |
| @@ -114,8 +115,13 @@ Proc* newproc(void); · 24 unmodified lines | |||
| 114 | char* nextelem(char*, char*); | 115 | char* nextelem(char*, char*); |
| 115 | void nexterror(void); | 116 | void nexterror(void); |
| 116 | int openmode(ulong); | 117 | int openmode(ulong); |
| 118 | void* oscmd(char**, int, char*, Chan**); | ||
| 119 | int oscmdwait(void*, char*, int); | ||
| 120 | int oscmdkill(void*); | ||
| 121 | void oscmdfree(void*); | ||
| 117 | void oserrstr(void); | 122 | void oserrstr(void); |
| 118 | void oserror(void); | 123 | void oserror(void); |
| 124 | void osexit(void); | ||
| 119 | Block* packblock(Block*); | 125 | Block* packblock(Block*); |
| 120 | Block* padblock(Block*, int); | 126 | Block* padblock(Block*, int); |
| 121 | void panic(char*, ...); | 127 | void panic(char*, ...); |
| @@ -106,7 +106,18 @@ oserror(void) · 105 unmodified lines | |||
| 106 | nexterror(); | 106 | nexterror(); |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 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 | } | ||
| 110 | 121 | ||
| 111 | void | 122 | void |
| 112 | osproc(Proc *p) | 123 | osproc(Proc *p) |
| @@ -120,19 +131,11 @@ osproc(Proc *p) · 7 unmodified lines | |||
| 120 | sched_yield(); | 131 | sched_yield(); |
| 121 | } | 132 | } |
| 122 | 133 | ||
| 123 | static void* | 134 | void |
| 124 | tramp(void *vp) | 135 | osexit(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 | ||
| 138 | void | 141 | void |
| @@ -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 | ||
| 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 | |||
| 166 | static int randfd; | 204 | static int randfd; |
| 167 | #undef open | 205 | #undef open |
| 168 | void | 206 | void |
| @@ -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 | ||
| 7 | Rgrp *thergrp; | ||
| 8 | |||
| 9 | void | 7 | void |
| 10 | procinit0(void) | 8 | procinit0(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 | ||
| 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 | } | ||
| @@ -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 | ||
| 110 | void | ||
| 111 | osexit(void) | ||
| 112 | { | ||
| 113 | ExitThread(0); | ||
| 114 | } | ||
| 115 | |||
| 110 | void | 116 | void |
| 111 | procsleep(void) | 117 | procsleep(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 | ||
| 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 | |||
| 269 | void | 423 | void |
| 270 | oserrstr(void) | 424 | oserrstr(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--; |
| @@ -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"); |