github.com/razvanm/vanadium-go-1.3@v0.0.0-20160721203343-4a65068e5915/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 char buf[ERRMAX]; 508 va_list arg; 509 510 rerrstr(buf, sizeof buf); 511 512 fflush(stdout); 513 fprintf(stderr, "go tool dist: "); 514 va_start(arg, msg); 515 vfprintf(stderr, msg, arg); 516 va_end(arg); 517 518 if(buf[0]) 519 fprintf(stderr, ": %s", buf); 520 fprintf(stderr, "\n"); 521 522 bgwait(); 523 exits(msg); 524 } 525 526 // xmalloc returns a newly allocated zeroed block of n bytes of memory. 527 // It calls fatal if it runs out of memory. 528 void* 529 xmalloc(int n) 530 { 531 void *p; 532 533 p = malloc(n); 534 if(p == nil) 535 fatal("out of memory"); 536 memset(p, 0, n); 537 return p; 538 } 539 540 // xstrdup returns a newly allocated copy of p. 541 // It calls fatal if it runs out of memory. 542 char* 543 xstrdup(char *p) 544 { 545 p = strdup(p); 546 if(p == nil) 547 fatal("out of memory"); 548 return p; 549 } 550 551 // xrealloc grows the allocation p to n bytes and 552 // returns the new (possibly moved) pointer. 553 // It calls fatal if it runs out of memory. 554 void* 555 xrealloc(void *p, int n) 556 { 557 p = realloc(p, n); 558 if(p == nil) 559 fatal("out of memory"); 560 return p; 561 } 562 563 // xfree frees the result returned by xmalloc, xstrdup, or xrealloc. 564 void 565 xfree(void *p) 566 { 567 free(p); 568 } 569 570 // hassuffix reports whether p ends with suffix. 571 bool 572 hassuffix(char *p, char *suffix) 573 { 574 int np, ns; 575 576 np = strlen(p); 577 ns = strlen(suffix); 578 return np >= ns && streq(p+np-ns, suffix); 579 } 580 581 // hasprefix reports whether p begins with prefix. 582 bool 583 hasprefix(char *p, char *prefix) 584 { 585 return strncmp(p, prefix, strlen(prefix)) == 0; 586 } 587 588 // contains reports whether sep appears in p. 589 bool 590 contains(char *p, char *sep) 591 { 592 return strstr(p, sep) != nil; 593 } 594 595 // streq reports whether p and q are the same string. 596 bool 597 streq(char *p, char *q) 598 { 599 return strcmp(p, q) == 0; 600 } 601 602 // lastelem returns the final path element in p. 603 char* 604 lastelem(char *p) 605 { 606 char *out; 607 608 out = p; 609 for(; *p; p++) 610 if(*p == '/') 611 out = p+1; 612 return out; 613 } 614 615 // xmemmove copies n bytes from src to dst. 616 void 617 xmemmove(void *dst, void *src, int n) 618 { 619 memmove(dst, src, n); 620 } 621 622 // xmemcmp compares the n-byte regions starting at a and at b. 623 int 624 xmemcmp(void *a, void *b, int n) 625 { 626 return memcmp(a, b, n); 627 } 628 629 // xstrlen returns the length of the NUL-terminated string at p. 630 int 631 xstrlen(char *p) 632 { 633 return strlen(p); 634 } 635 636 // xexit exits the process with return code n. 637 void 638 xexit(int n) 639 { 640 char buf[32]; 641 642 snprintf(buf, sizeof buf, "%d", n); 643 exits(buf); 644 } 645 646 // xatexit schedules the exit-handler f to be run when the program exits. 647 void 648 xatexit(void (*f)(void)) 649 { 650 atexit(f); 651 } 652 653 // xprintf prints a message to standard output. 654 void 655 xprintf(char *fmt, ...) 656 { 657 va_list arg; 658 659 va_start(arg, fmt); 660 vprintf(fmt, arg); 661 va_end(arg); 662 } 663 664 // errprintf prints a message to standard output. 665 void 666 errprintf(char *fmt, ...) 667 { 668 va_list arg; 669 670 va_start(arg, fmt); 671 vfprintf(stderr, fmt, arg); 672 va_end(arg); 673 } 674 675 // xsetenv sets the environment variable $name to the given value. 676 void 677 xsetenv(char *name, char *value) 678 { 679 putenv(name, value); 680 } 681 682 // main takes care of OS-specific startup and dispatches to xmain. 683 void 684 main(int argc, char **argv) 685 { 686 Buf b; 687 688 setvbuf(stdout, nil, _IOLBF, BUFSIZ); 689 setvbuf(stderr, nil, _IOLBF, BUFSIZ); 690 691 binit(&b); 692 693 rfork(RFENVG); 694 695 slash = "/"; 696 gohostos = "plan9"; 697 698 xgetenv(&b, "objtype"); 699 if(b.len == 0) 700 fatal("$objtype is unset"); 701 gohostarch = btake(&b); 702 703 srand(time(0)+getpid()); 704 init(); 705 xmain(argc, argv); 706 707 bfree(&b); 708 exits(nil); 709 } 710 711 // xqsort is a wrapper for the C standard qsort. 712 void 713 xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*)) 714 { 715 qsort(data, n, elemsize, cmp); 716 } 717 718 // xstrcmp compares the NUL-terminated strings a and b. 719 int 720 xstrcmp(char *a, char *b) 721 { 722 return strcmp(a, b); 723 } 724 725 // xstrstr returns a pointer to the first occurrence of b in a. 726 char* 727 xstrstr(char *a, char *b) 728 { 729 return strstr(a, b); 730 } 731 732 // xstrrchr returns a pointer to the final occurrence of c in p. 733 char* 734 xstrrchr(char *p, int c) 735 { 736 return strrchr(p, c); 737 } 738 739 // xsamefile reports whether f1 and f2 are the same file (or dir) 740 int 741 xsamefile(char *f1, char *f2) 742 { 743 return streq(f1, f2); // suffice for now 744 } 745 746 // xtryexecfunc tries to execute function f, if any illegal instruction 747 // signal received in the course of executing that function, it will 748 // return 0, otherwise it will return 1. 749 int 750 xtryexecfunc(void (*f)(void)) 751 { 752 USED(f); 753 return 0; // suffice for now 754 } 755 756 bool 757 cansse2(void) 758 { 759 // if we had access to cpuid, could answer this question 760 // less conservatively. 761 return 0; 762 } 763 764 #endif // PLAN9