github.com/yanyiwu/go@v0.0.0-20150106053140-03d6637dbb7f/src/cmd/dist/plan9.c (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // These #ifdefs are being used as a substitute for 6 // build configuration, so that on any system, this 7 // tool can be built with the local equivalent of 8 // cc *.c 9 // 10 #ifdef PLAN9 11 12 #include <u.h> 13 #include <libc.h> 14 #include <stdio.h> 15 #undef nil 16 #undef nelem 17 #include "a.h" 18 19 // bprintf replaces the buffer with the result of the printf formatting 20 // and returns a pointer to the NUL-terminated buffer contents. 21 char* 22 bprintf(Buf *b, char *fmt, ...) 23 { 24 va_list arg; 25 char buf[4096]; 26 27 breset(b); 28 va_start(arg, fmt); 29 vsnprintf(buf, sizeof buf, fmt, arg); 30 va_end(arg); 31 bwritestr(b, buf); 32 return bstr(b); 33 } 34 35 // bpathf is the same as bprintf (on windows it turns / into \ after the printf). 36 // It returns a pointer to the NUL-terminated buffer contents. 37 char* 38 bpathf(Buf *b, char *fmt, ...) 39 { 40 va_list arg; 41 char buf[4096]; 42 43 breset(b); 44 va_start(arg, fmt); 45 vsnprintf(buf, sizeof buf, fmt, arg); 46 va_end(arg); 47 bwritestr(b, buf); 48 return bstr(b); 49 } 50 51 // bwritef is like bprintf but does not reset the buffer 52 // and does not return the NUL-terminated string. 53 void 54 bwritef(Buf *b, char *fmt, ...) 55 { 56 va_list arg; 57 char buf[4096]; 58 59 va_start(arg, fmt); 60 vsnprintf(buf, sizeof buf, fmt, arg); 61 va_end(arg); 62 bwritestr(b, buf); 63 } 64 65 // breadfrom appends to b all the data that can be read from fd. 66 static void 67 breadfrom(Buf *b, int fd) 68 { 69 int n; 70 71 for(;;) { 72 bgrow(b, 4096); 73 n = read(fd, b->p+b->len, 4096); 74 if(n < 0) 75 fatal("read"); 76 if(n == 0) 77 break; 78 b->len += n; 79 } 80 } 81 82 // xgetenv replaces b with the value of the named environment variable. 83 void 84 xgetenv(Buf *b, char *name) 85 { 86 char *p; 87 88 breset(b); 89 p = getenv(name); 90 if(p != nil) 91 bwritestr(b, p); 92 } 93 94 static void genrun(Buf *b, char *dir, int mode, Vec *argv, int bg); 95 96 // run runs the command named by cmd. 97 // If b is not nil, run replaces b with the output of the command. 98 // If dir is not nil, run runs the command in that directory. 99 // If mode is CheckExit, run calls fatal if the command is not successful. 100 void 101 run(Buf *b, char *dir, int mode, char *cmd, ...) 102 { 103 va_list arg; 104 Vec argv; 105 char *p; 106 107 vinit(&argv); 108 vadd(&argv, cmd); 109 va_start(arg, cmd); 110 while((p = va_arg(arg, char*)) != nil) 111 vadd(&argv, p); 112 va_end(arg); 113 114 runv(b, dir, mode, &argv); 115 116 vfree(&argv); 117 } 118 119 // runv is like run but takes a vector. 120 void 121 runv(Buf *b, char *dir, int mode, Vec *argv) 122 { 123 genrun(b, dir, mode, argv, 1); 124 } 125 126 // bgrunv is like run but runs the command in the background. 127 // bgwait waits for pending bgrunv to finish. 128 void 129 bgrunv(char *dir, int mode, Vec *argv) 130 { 131 genrun(nil, dir, mode, argv, 0); 132 } 133 134 #define MAXBG 4 /* maximum number of jobs to run at once */ 135 136 static struct { 137 int pid; 138 int mode; 139 char *cmd; 140 Buf *b; 141 } bg[MAXBG]; 142 static int nbg; 143 static int maxnbg = nelem(bg); 144 145 static void bgwait1(void); 146 147 // genrun is the generic run implementation. 148 static void 149 genrun(Buf *b, char *dir, int mode, Vec *argv, int wait) 150 { 151 int i, p[2], pid; 152 Buf b1, cmd; 153 char *q; 154 155 while(nbg >= maxnbg) 156 bgwait1(); 157 158 binit(&b1); 159 binit(&cmd); 160 161 if(!isabs(argv->p[0])) { 162 bpathf(&b1, "/bin/%s", argv->p[0]); 163 free(argv->p[0]); 164 argv->p[0] = xstrdup(bstr(&b1)); 165 } 166 167 // Generate a copy of the command to show in a log. 168 // Substitute $WORK for the work directory. 169 for(i=0; i<argv->len; i++) { 170 if(i > 0) 171 bwritestr(&cmd, " "); 172 q = argv->p[i]; 173 if(workdir != nil && hasprefix(q, workdir)) { 174 bwritestr(&cmd, "$WORK"); 175 q += strlen(workdir); 176 } 177 bwritestr(&cmd, q); 178 } 179 if(vflag > 1) 180 errprintf("%s\n", bstr(&cmd)); 181 182 if(b != nil) { 183 breset(b); 184 if(pipe(p) < 0) 185 fatal("pipe"); 186 } 187 188 switch(pid = fork()) { 189 case -1: 190 fatal("fork"); 191 case 0: 192 if(b != nil) { 193 close(0); 194 close(p[0]); 195 dup(p[1], 1); 196 dup(p[1], 2); 197 if(p[1] > 2) 198 close(p[1]); 199 } 200 if(dir != nil) { 201 if(chdir(dir) < 0) { 202 fprint(2, "chdir: %r\n"); 203 _exits("chdir"); 204 } 205 } 206 vadd(argv, nil); 207 exec(argv->p[0], argv->p); 208 fprint(2, "%s\n", bstr(&cmd)); 209 fprint(2, "exec: %r\n"); 210 _exits("exec"); 211 } 212 if(b != nil) { 213 close(p[1]); 214 breadfrom(b, p[0]); 215 close(p[0]); 216 } 217 218 if(nbg < 0) 219 fatal("bad bookkeeping"); 220 bg[nbg].pid = pid; 221 bg[nbg].mode = mode; 222 bg[nbg].cmd = btake(&cmd); 223 bg[nbg].b = b; 224 nbg++; 225 226 if(wait) 227 bgwait(); 228 229 bfree(&cmd); 230 bfree(&b1); 231 } 232 233 // bgwait1 waits for a single background job. 234 static void 235 bgwait1(void) 236 { 237 Waitmsg *w; 238 int i, mode; 239 char *cmd; 240 Buf *b; 241 242 w = wait(); 243 if(w == nil) 244 fatal("wait"); 245 246 for(i=0; i<nbg; i++) 247 if(bg[i].pid == w->pid) 248 goto ok; 249 fatal("wait: unexpected pid"); 250 251 ok: 252 cmd = bg[i].cmd; 253 mode = bg[i].mode; 254 bg[i].pid = 0; 255 b = bg[i].b; 256 bg[i].b = nil; 257 bg[i] = bg[--nbg]; 258 259 if(mode == CheckExit && w->msg[0]) { 260 if(b != nil) 261 xprintf("%s\n", bstr(b)); 262 fatal("FAILED: %s", cmd); 263 } 264 xfree(cmd); 265 } 266 267 // bgwait waits for all the background jobs. 268 void 269 bgwait(void) 270 { 271 while(nbg > 0) 272 bgwait1(); 273 } 274 275 // xgetwd replaces b with the current directory. 276 void 277 xgetwd(Buf *b) 278 { 279 char buf[4096]; 280 281 breset(b); 282 if(getwd(buf, sizeof buf) == nil) 283 fatal("getwd"); 284 bwritestr(b, buf); 285 } 286 287 // xrealwd replaces b with the 'real' name for the given path. 288 // real is defined as what getcwd returns in that directory. 289 void 290 xrealwd(Buf *b, char *path) 291 { 292 char buf[4096]; 293 int fd; 294 295 fd = open(path, OREAD); 296 if(fd2path(fd, buf, sizeof buf) < 0) 297 fatal("fd2path"); 298 close(fd); 299 breset(b); 300 bwritestr(b, buf); 301 } 302 303 // isdir reports whether p names an existing directory. 304 bool 305 isdir(char *p) 306 { 307 Dir *d; 308 ulong mode; 309 310 d = dirstat(p); 311 if(d == nil) 312 return 0; 313 mode = d->mode; 314 free(d); 315 return (mode & DMDIR) == DMDIR; 316 } 317 318 // isfile reports whether p names an existing file. 319 bool 320 isfile(char *p) 321 { 322 Dir *d; 323 ulong mode; 324 325 d = dirstat(p); 326 if(d == nil) 327 return 0; 328 mode = d->mode; 329 free(d); 330 return (mode & DMDIR) == 0; 331 } 332 333 // mtime returns the modification time of the file p. 334 Time 335 mtime(char *p) 336 { 337 Dir *d; 338 ulong t; 339 340 d = dirstat(p); 341 if(d == nil) 342 return 0; 343 t = d->mtime; 344 free(d); 345 return (Time)t; 346 } 347 348 // isabs reports whether p is an absolute path. 349 bool 350 isabs(char *p) 351 { 352 return hasprefix(p, "/"); 353 } 354 355 // readfile replaces b with the content of the named file. 356 void 357 readfile(Buf *b, char *file) 358 { 359 int fd; 360 361 breset(b); 362 fd = open(file, OREAD); 363 if(fd < 0) 364 fatal("open %s", file); 365 breadfrom(b, fd); 366 close(fd); 367 } 368 369 // writefile writes b to the named file, creating it if needed. 370 void 371 writefile(Buf *b, char *file, int exec) 372 { 373 int fd; 374 Dir d; 375 376 fd = create(file, ORDWR, 0666); 377 if(fd < 0) 378 fatal("create %s", file); 379 if(write(fd, b->p, b->len) != b->len) 380 fatal("short write"); 381 if(exec) { 382 nulldir(&d); 383 d.mode = 0755; 384 dirfwstat(fd, &d); 385 } 386 close(fd); 387 } 388 389 // xmkdir creates the directory p. 390 void 391 xmkdir(char *p) 392 { 393 int fd; 394 395 if(isdir(p)) 396 return; 397 fd = create(p, OREAD, 0777|DMDIR); 398 close(fd); 399 if(fd < 0) 400 fatal("mkdir %s", p); 401 } 402 403 // xmkdirall creates the directory p and its parents, as needed. 404 void 405 xmkdirall(char *p) 406 { 407 char *q; 408 409 if(isdir(p)) 410 return; 411 q = strrchr(p, '/'); 412 if(q != nil) { 413 *q = '\0'; 414 xmkdirall(p); 415 *q = '/'; 416 } 417 xmkdir(p); 418 } 419 420 // xremove removes the file p. 421 void 422 xremove(char *p) 423 { 424 if(vflag > 2) 425 errprintf("rm %s\n", p); 426 remove(p); 427 } 428 429 // xremoveall removes the file or directory tree rooted at p. 430 void 431 xremoveall(char *p) 432 { 433 int i; 434 Buf b; 435 Vec dir; 436 437 binit(&b); 438 vinit(&dir); 439 440 if(isdir(p)) { 441 xreaddir(&dir, p); 442 for(i=0; i<dir.len; i++) { 443 bprintf(&b, "%s/%s", p, dir.p[i]); 444 xremoveall(bstr(&b)); 445 } 446 } 447 if(vflag > 2) 448 errprintf("rm %s\n", p); 449 remove(p); 450 451 bfree(&b); 452 vfree(&dir); 453 } 454 455 // xreaddir replaces dst with a list of the names of the files in dir. 456 // The names are relative to dir; they are not full paths. 457 void 458 xreaddir(Vec *dst, char *dir) 459 { 460 Dir *d; 461 int fd, i, n; 462 463 vreset(dst); 464 465 fd = open(dir, OREAD); 466 if(fd < 0) 467 fatal("open %s", dir); 468 n = dirreadall(fd, &d); 469 for(i=0; i<n; i++) 470 vadd(dst, d[i].name); 471 free(d); 472 close(fd); 473 } 474 475 // xworkdir creates a new temporary directory to hold object files 476 // and returns the name of that directory. 477 char* 478 xworkdir(void) 479 { 480 Buf b; 481 char *p; 482 int fd, tries; 483 484 binit(&b); 485 486 fd = 0; 487 for(tries=0; tries<1000; tries++) { 488 bprintf(&b, "/tmp/go-cbuild-%06x", nrand((1<<24)-1)); 489 fd = create(bstr(&b), OREAD|OEXCL, 0700|DMDIR); 490 if(fd >= 0) 491 goto done; 492 } 493 fatal("xworkdir create"); 494 495 done: 496 close(fd); 497 p = btake(&b); 498 499 bfree(&b); 500 return p; 501 } 502 503 // fatal prints an error message to standard error and exits. 504 void 505 fatal(char *msg, ...) 506 { 507 va_list arg; 508 509 fflush(stdout); 510 fprintf(stderr, "go tool dist: "); 511 va_start(arg, msg); 512 vfprintf(stderr, msg, arg); 513 va_end(arg); 514 fprintf(stderr, "\n"); 515 516 bgwait(); 517 exits(msg); 518 } 519 520 // xmalloc returns a newly allocated zeroed block of n bytes of memory. 521 // It calls fatal if it runs out of memory. 522 void* 523 xmalloc(int n) 524 { 525 void *p; 526 527 p = malloc(n); 528 if(p == nil) 529 fatal("out of memory"); 530 memset(p, 0, n); 531 return p; 532 } 533 534 // xstrdup returns a newly allocated copy of p. 535 // It calls fatal if it runs out of memory. 536 char* 537 xstrdup(char *p) 538 { 539 p = strdup(p); 540 if(p == nil) 541 fatal("out of memory"); 542 return p; 543 } 544 545 // xrealloc grows the allocation p to n bytes and 546 // returns the new (possibly moved) pointer. 547 // It calls fatal if it runs out of memory. 548 void* 549 xrealloc(void *p, int n) 550 { 551 p = realloc(p, n); 552 if(p == nil) 553 fatal("out of memory"); 554 return p; 555 } 556 557 // xfree frees the result returned by xmalloc, xstrdup, or xrealloc. 558 void 559 xfree(void *p) 560 { 561 free(p); 562 } 563 564 // hassuffix reports whether p ends with suffix. 565 bool 566 hassuffix(char *p, char *suffix) 567 { 568 int np, ns; 569 570 np = strlen(p); 571 ns = strlen(suffix); 572 return np >= ns && streq(p+np-ns, suffix); 573 } 574 575 // hasprefix reports whether p begins with prefix. 576 bool 577 hasprefix(char *p, char *prefix) 578 { 579 return strncmp(p, prefix, strlen(prefix)) == 0; 580 } 581 582 // contains reports whether sep appears in p. 583 bool 584 contains(char *p, char *sep) 585 { 586 return strstr(p, sep) != nil; 587 } 588 589 // streq reports whether p and q are the same string. 590 bool 591 streq(char *p, char *q) 592 { 593 return strcmp(p, q) == 0; 594 } 595 596 // lastelem returns the final path element in p. 597 char* 598 lastelem(char *p) 599 { 600 char *out; 601 602 out = p; 603 for(; *p; p++) 604 if(*p == '/') 605 out = p+1; 606 return out; 607 } 608 609 // xmemmove copies n bytes from src to dst. 610 void 611 xmemmove(void *dst, void *src, int n) 612 { 613 memmove(dst, src, n); 614 } 615 616 // xmemcmp compares the n-byte regions starting at a and at b. 617 int 618 xmemcmp(void *a, void *b, int n) 619 { 620 return memcmp(a, b, n); 621 } 622 623 // xstrlen returns the length of the NUL-terminated string at p. 624 int 625 xstrlen(char *p) 626 { 627 return strlen(p); 628 } 629 630 // xexit exits the process with return code n. 631 void 632 xexit(int n) 633 { 634 char buf[32]; 635 636 snprintf(buf, sizeof buf, "%d", n); 637 exits(buf); 638 } 639 640 // xatexit schedules the exit-handler f to be run when the program exits. 641 void 642 xatexit(void (*f)(void)) 643 { 644 atexit(f); 645 } 646 647 // xprintf prints a message to standard output. 648 void 649 xprintf(char *fmt, ...) 650 { 651 va_list arg; 652 653 va_start(arg, fmt); 654 vprintf(fmt, arg); 655 va_end(arg); 656 } 657 658 // errprintf prints a message to standard output. 659 void 660 errprintf(char *fmt, ...) 661 { 662 va_list arg; 663 664 va_start(arg, fmt); 665 vfprintf(stderr, fmt, arg); 666 va_end(arg); 667 } 668 669 // xsetenv sets the environment variable $name to the given value. 670 void 671 xsetenv(char *name, char *value) 672 { 673 putenv(name, value); 674 } 675 676 // main takes care of OS-specific startup and dispatches to xmain. 677 void 678 main(int argc, char **argv) 679 { 680 Buf b; 681 682 setvbuf(stdout, nil, _IOLBF, BUFSIZ); 683 setvbuf(stderr, nil, _IOLBF, BUFSIZ); 684 685 binit(&b); 686 687 rfork(RFENVG); 688 689 slash = "/"; 690 gohostos = "plan9"; 691 692 xgetenv(&b, "objtype"); 693 if(b.len == 0) 694 fatal("$objtype is unset"); 695 gohostarch = btake(&b); 696 697 srand(time(0)+getpid()); 698 init(); 699 xmain(argc, argv); 700 701 bfree(&b); 702 exits(nil); 703 } 704 705 // xqsort is a wrapper for the C standard qsort. 706 void 707 xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*)) 708 { 709 qsort(data, n, elemsize, cmp); 710 } 711 712 // xstrcmp compares the NUL-terminated strings a and b. 713 int 714 xstrcmp(char *a, char *b) 715 { 716 return strcmp(a, b); 717 } 718 719 // xstrstr returns a pointer to the first occurrence of b in a. 720 char* 721 xstrstr(char *a, char *b) 722 { 723 return strstr(a, b); 724 } 725 726 // xstrrchr returns a pointer to the final occurrence of c in p. 727 char* 728 xstrrchr(char *p, int c) 729 { 730 return strrchr(p, c); 731 } 732 733 // xsamefile reports whether f1 and f2 are the same file (or dir) 734 int 735 xsamefile(char *f1, char *f2) 736 { 737 return streq(f1, f2); // suffice for now 738 } 739 740 // xtryexecfunc tries to execute function f, if any illegal instruction 741 // signal received in the course of executing that function, it will 742 // return 0, otherwise it will return 1. 743 int 744 xtryexecfunc(void (*f)(void)) 745 { 746 USED(f); 747 return 0; // suffice for now 748 } 749 750 bool 751 cansse2(void) 752 { 753 // if we had access to cpuid, could answer this question 754 // less conservatively. 755 return 0; 756 } 757 758 #endif // PLAN9