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 | 10 | dev.$O\ |
| 11 | 11 | devaudio.$O\ |
| 12 | 12 | devaudio-$(AUDIO).$O\ |
| 13 | + devcmd.$O\ | |
| 13 | 14 | devcons.$O\ |
| 14 | 15 | devdraw.$O\ |
| 15 | 16 | devfs-$(OS).$O\ |
| 16 | 17 | devip.$O\ |
| 17 | 18 | devip-$(OS).$O\ |
| 18 | 19 | devkbd.$O\ |
| 19 | − devlfd.$O\ | |
| 20 | + devlfd-$(OS).$O\ | |
| 20 | 21 | devmnt.$O\ |
| 21 | 22 | devmouse.$O\ |
| 22 | 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 | 1 | #include "u.h" |
| 2 | −#include <errno.h> | |
| 2 | +#include <errno.h> | |
| 3 | 3 | #include "lib.h" |
| 4 | 4 | #include "dat.h" |
| 5 | 5 | #include "fns.h" |
| 6 | 6 | #include "error.h" |
| 7 | 7 | |
| 8 | −#undef pread | |
| 9 | −#undef pwrite | |
| 8 | +#undef read | |
| 9 | +#undef write | |
| 10 | 10 | |
| 11 | 11 | Chan* |
| 12 | −lfdchan(int fd) | |
| 12 | +lfdchan(void *fd) | |
| 13 | 13 | { |
| 14 | 14 | Chan *c; |
| 15 | 15 | |
| 16 | 16 | c = newchan(); |
| 17 | 17 | c->type = devno('L', 0); |
| 18 | − c->aux = (void*)(uintptr)fd; | |
| 18 | + c->aux = fd; | |
| 19 | 19 | c->path = newpath("fd"); |
| 20 | 20 | c->mode = ORDWR; |
| 21 | 21 | c->qid.type = 0; |
| @@ -26,12 +26,6 @@ lfdchan(int fd) · 4 unmodified lines | ||
| 26 | 26 | return c; |
| 27 | 27 | } |
| 28 | 28 | |
| 29 | −int | |
| 30 | −lfdfd(int fd) | |
| 31 | −{ | |
| 32 | − return newfd(lfdchan(fd)); | |
| 33 | −} | |
| 34 | − | |
| 35 | 29 | static Chan* |
| 36 | 30 | lfdattach(char *x) |
| 37 | 31 | { |
| @@ -48,7 +42,6 @@ lfdwalk(Chan *c, Chan *nc, char **name, int nname) · 10 unmodified lines | ||
| 48 | 42 | USED(nc); |
| 49 | 43 | USED(name); |
| 50 | 44 | USED(nname); |
| 51 | − | |
| 52 | 45 | error(Egreg); |
| 53 | 46 | return nil; |
| 54 | 47 | } |
| @@ -68,7 +61,6 @@ lfdopen(Chan *c, int omode) · 13 unmodified lines | ||
| 68 | 61 | { |
| 69 | 62 | USED(c); |
| 70 | 63 | USED(omode); |
| 71 | − | |
| 72 | 64 | error(Egreg); |
| 73 | 65 | return nil; |
| 74 | 66 | } |
| @@ -83,11 +75,10 @@ static long · 8 unmodified lines | ||
| 83 | 75 | lfdread(Chan *c, void *buf, long n, vlong off) |
| 84 | 76 | { |
| 85 | 77 | USED(off); /* can't pread on pipes */ |
| 78 | + | |
| 86 | 79 | n = read((int)(uintptr)c->aux, buf, n); |
| 87 | − if(n < 0){ | |
| 88 | − iprint("error %d\n", errno); | |
| 80 | + if(n < 0) | |
| 89 | 81 | oserror(); |
| 90 | − } | |
| 91 | 82 | return n; |
| 92 | 83 | } |
| 93 | 84 | |
| @@ -97,10 +88,8 @@ lfdwrite(Chan *c, void *buf, long n, vlong off) · 3 unmodified lines | ||
| 97 | 88 | USED(off); /* can't pread on pipes */ |
| 98 | 89 | |
| 99 | 90 | n = write((int)(uintptr)c->aux, buf, n); |
| 100 | − if(n < 0){ | |
| 101 | − iprint("error %d\n", errno); | |
| 91 | + if(n < 0) | |
| 102 | 92 | oserror(); |
| 103 | − } | |
| 104 | 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 | 17 | extern Dev lfddevtab; |
| 18 | 18 | extern Dev audiodevtab; |
| 19 | 19 | extern Dev kbddevtab; |
| 20 | +extern Dev cmddevtab; | |
| 20 | 21 | |
| 21 | 22 | Dev *devtab[] = { |
| 22 | 23 | &rootdevtab, |
| @@ -32,6 +33,7 @@ Dev *devtab[] = { · 9 unmodified lines | ||
| 32 | 33 | &lfddevtab, |
| 33 | 34 | &audiodevtab, |
| 34 | 35 | &kbddevtab, |
| 36 | + &cmddevtab, | |
| 35 | 37 | 0 |
| 36 | 38 | }; |
| 37 | 39 | |
| @@ -84,6 +84,7 @@ void ksetenv(char*, char*, int); · 83 unmodified lines | ||
| 84 | 84 | void kstrcpy(char*, char*, int); |
| 85 | 85 | void kstrdup(char**, char*); |
| 86 | 86 | long latin1(Rune*, int); |
| 87 | +Chan* lfdchan(void *); | |
| 87 | 88 | void lock(Lock*); |
| 88 | 89 | void lockinit(void); |
| 89 | 90 | void logopen(Log*); |
| @@ -114,8 +115,13 @@ Proc* newproc(void); · 24 unmodified lines | ||
| 114 | 115 | char* nextelem(char*, char*); |
| 115 | 116 | void nexterror(void); |
| 116 | 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 | 122 | void oserrstr(void); |
| 118 | 123 | void oserror(void); |
| 124 | +void osexit(void); | |
| 119 | 125 | Block* packblock(Block*); |
| 120 | 126 | Block* padblock(Block*, int); |
| 121 | 127 | void panic(char*, ...); |
| @@ -106,7 +106,18 @@ oserror(void) · 105 unmodified lines | ||
| 106 | 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 | 122 | void |
| 112 | 123 | osproc(Proc *p) |
| @@ -120,19 +131,11 @@ osproc(Proc *p) · 7 unmodified lines | ||
| 120 | 131 | sched_yield(); |
| 121 | 132 | } |
| 122 | 133 | |
| 123 | −static void* | |
| 124 | −tramp(void *vp) | |
| 134 | +void | |
| 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 | 137 | pthread_setspecific(prdakey, 0); |
| 134 | 138 | pthread_exit(0); |
| 135 | − return 0; | |
| 136 | 139 | } |
| 137 | 140 | |
| 138 | 141 | void |
| @@ -163,6 +166,41 @@ procwakeup(Proc *p) · 24 unmodified lines | ||
| 163 | 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 | 204 | static int randfd; |
| 167 | 205 | #undef open |
| 168 | 206 | void |
| @@ -4,8 +4,6 @@ · 3 unmodified lines | ||
| 4 | 4 | #include "fns.h" |
| 5 | 5 | #include "error.h" |
| 6 | 6 | |
| 7 | −Rgrp *thergrp; | |
| 8 | − | |
| 9 | 7 | void |
| 10 | 8 | procinit0(void) |
| 11 | 9 | { |
| @@ -51,13 +49,13 @@ kproc(char *name, void (*fn)(void*), void *arg) · 39 unmodified lines | ||
| 51 | 49 | p->slash = cclone(up->slash); |
| 52 | 50 | p->dot = cclone(up->dot); |
| 53 | 51 | p->rgrp = up->rgrp; |
| 54 | − if(p->rgrp) | |
| 52 | + if(p->rgrp != nil) | |
| 55 | 53 | incref(&p->rgrp->ref); |
| 56 | 54 | p->pgrp = up->pgrp; |
| 57 | − if(up->pgrp) | |
| 55 | + if(up->pgrp != nil) | |
| 58 | 56 | incref(&up->pgrp->ref); |
| 59 | 57 | p->fgrp = up->fgrp; |
| 60 | − if(p->fgrp) | |
| 58 | + if(p->fgrp != nil) | |
| 61 | 59 | incref(&p->fgrp->ref); |
| 62 | 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 | 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 | 92 | _setproc(p); |
| 93 | 93 | op->tid = GetCurrentThreadId(); |
| 94 | 94 | (*p->fn)(p->arg); |
| 95 | − ExitThread(0); | |
| 95 | + pexit("", 0); | |
| 96 | 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 | 116 | void |
| 111 | 117 | procsleep(void) |
| 112 | 118 | { |
| @@ -251,14 +257,14 @@ WinMain(HINSTANCE x, HINSTANCE y, LPSTR z, int w) · 138 unmodified lines | ||
| 251 | 257 | |
| 252 | 258 | warg = GetCommandLineW(); |
| 253 | 259 | 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); | |
| 256 | 262 | |
| 257 | 263 | /* conservative guess at the number of args */ |
| 258 | 264 | for(argc=4,p=arg; *p; p++) |
| 259 | 265 | if(*p == ' ' || *p == '\t') |
| 260 | 266 | argc++; |
| 261 | − argv = malloc(argc*sizeof(char*)); | |
| 267 | + argv = smalloc(argc*sizeof(char*)); | |
| 262 | 268 | argc = args(argv, argc, arg); |
| 263 | 269 | |
| 264 | 270 | main(argc, argv); |
| @@ -266,6 +272,154 @@ WinMain(HINSTANCE x, HINSTANCE y, LPSTR z, int w) · 1 unmodified line | ||
| 266 | 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 | 423 | void |
| 270 | 424 | oserrstr(void) |
| 271 | 425 | { |
| @@ -296,9 +450,7 @@ showfilewrite(char *a, int n) · 24 unmodified lines | ||
| 296 | 450 | wchar_t *action, *arg, *cmd, *p; |
| 297 | 451 | int m; |
| 298 | 452 | |
| 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)); | |
| 302 | 454 | m = MultiByteToWideChar(CP_UTF8,0,a,n,cmd,n); |
| 303 | 455 | while(m > 0 && cmd[m-1] == '\n') |
| 304 | 456 | m--; |
| @@ -52,6 +52,7 @@ main(int argc, char **argv) · 51 unmodified lines | ||
| 52 | 52 | if(bind("#U", "/root", MREPL) < 0) |
| 53 | 53 | panic("bind #U: %r"); |
| 54 | 54 | bind("#A", "/dev", MAFTER); |
| 55 | + bind("#C", "/", MAFTER); | |
| 55 | 56 | |
| 56 | 57 | if(open("/dev/cons", OREAD) != 0) |
| 57 | 58 | panic("open0: %r"); |