github.com/golang-haiku/go-1.4.3@v0.0.0-20190609233734-1f5ae41cc308/src/cmd/dist/unix.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 #ifndef WIN32 11 #ifndef PLAN9 12 13 #include "a.h" 14 #include <unistd.h> 15 #include <dirent.h> 16 #include <sys/stat.h> 17 #include <sys/wait.h> 18 #include <sys/param.h> 19 #include <sys/utsname.h> 20 #include <fcntl.h> 21 #include <string.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <errno.h> 25 #include <stdarg.h> 26 #include <setjmp.h> 27 #include <signal.h> 28 29 // bprintf replaces the buffer with the result of the printf formatting 30 // and returns a pointer to the NUL-terminated buffer contents. 31 char* 32 bprintf(Buf *b, char *fmt, ...) 33 { 34 va_list arg; 35 char buf[4096]; 36 37 breset(b); 38 va_start(arg, fmt); 39 vsnprintf(buf, sizeof buf, fmt, arg); 40 va_end(arg); 41 bwritestr(b, buf); 42 return bstr(b); 43 } 44 45 // bpathf is the same as bprintf (on windows it turns / into \ after the printf). 46 // It returns a pointer to the NUL-terminated buffer contents. 47 char* 48 bpathf(Buf *b, char *fmt, ...) 49 { 50 va_list arg; 51 char buf[4096]; 52 53 breset(b); 54 va_start(arg, fmt); 55 vsnprintf(buf, sizeof buf, fmt, arg); 56 va_end(arg); 57 bwritestr(b, buf); 58 return bstr(b); 59 } 60 61 // bwritef is like bprintf but does not reset the buffer 62 // and does not return the NUL-terminated string. 63 void 64 bwritef(Buf *b, char *fmt, ...) 65 { 66 va_list arg; 67 char buf[4096]; 68 69 va_start(arg, fmt); 70 vsnprintf(buf, sizeof buf, fmt, arg); 71 va_end(arg); 72 bwritestr(b, buf); 73 } 74 75 // breadfrom appends to b all the data that can be read from fd. 76 static void 77 breadfrom(Buf *b, int fd) 78 { 79 int n; 80 81 for(;;) { 82 bgrow(b, 4096); 83 n = read(fd, b->p+b->len, 4096); 84 if(n < 0) 85 fatal("read: %s", strerror(errno)); 86 if(n == 0) 87 break; 88 b->len += n; 89 } 90 } 91 92 // xgetenv replaces b with the value of the named environment variable. 93 void 94 xgetenv(Buf *b, char *name) 95 { 96 char *p; 97 98 breset(b); 99 p = getenv(name); 100 if(p != NULL) 101 bwritestr(b, p); 102 } 103 104 static void genrun(Buf *b, char *dir, int mode, Vec *argv, int bg); 105 106 // run runs the command named by cmd. 107 // If b is not nil, run replaces b with the output of the command. 108 // If dir is not nil, run runs the command in that directory. 109 // If mode is CheckExit, run calls fatal if the command is not successful. 110 void 111 run(Buf *b, char *dir, int mode, char *cmd, ...) 112 { 113 va_list arg; 114 Vec argv; 115 char *p; 116 117 vinit(&argv); 118 vadd(&argv, cmd); 119 va_start(arg, cmd); 120 while((p = va_arg(arg, char*)) != nil) 121 vadd(&argv, p); 122 va_end(arg); 123 124 runv(b, dir, mode, &argv); 125 126 vfree(&argv); 127 } 128 129 // runv is like run but takes a vector. 130 void 131 runv(Buf *b, char *dir, int mode, Vec *argv) 132 { 133 genrun(b, dir, mode, argv, 1); 134 } 135 136 // bgrunv is like run but runs the command in the background. 137 // bgwait waits for pending bgrunv to finish. 138 void 139 bgrunv(char *dir, int mode, Vec *argv) 140 { 141 genrun(nil, dir, mode, argv, 0); 142 } 143 144 #define MAXBG 4 /* maximum number of jobs to run at once */ 145 146 static struct { 147 int pid; 148 int mode; 149 char *cmd; 150 Buf *b; 151 } bg[MAXBG]; 152 static int nbg; 153 static int maxnbg = nelem(bg); 154 155 static void bgwait1(void); 156 157 // genrun is the generic run implementation. 158 static void 159 genrun(Buf *b, char *dir, int mode, Vec *argv, int wait) 160 { 161 int i, p[2], pid; 162 Buf cmd; 163 char *q; 164 165 while(nbg >= maxnbg) 166 bgwait1(); 167 168 // Generate a copy of the command to show in a log. 169 // Substitute $WORK for the work directory. 170 binit(&cmd); 171 for(i=0; i<argv->len; i++) { 172 if(i > 0) 173 bwritestr(&cmd, " "); 174 q = argv->p[i]; 175 if(workdir != nil && hasprefix(q, workdir)) { 176 bwritestr(&cmd, "$WORK"); 177 q += strlen(workdir); 178 } 179 bwritestr(&cmd, q); 180 } 181 if(vflag > 1) 182 errprintf("%s\n", bstr(&cmd)); 183 184 if(b != nil) { 185 breset(b); 186 if(pipe(p) < 0) 187 fatal("pipe: %s", strerror(errno)); 188 } 189 190 switch(pid = fork()) { 191 case -1: 192 fatal("fork: %s", strerror(errno)); 193 case 0: 194 if(b != nil) { 195 close(0); 196 close(p[0]); 197 dup2(p[1], 1); 198 dup2(p[1], 2); 199 if(p[1] > 2) 200 close(p[1]); 201 } 202 if(dir != nil) { 203 if(chdir(dir) < 0) { 204 fprintf(stderr, "chdir %s: %s\n", dir, strerror(errno)); 205 _exit(1); 206 } 207 } 208 vadd(argv, nil); 209 execvp(argv->p[0], argv->p); 210 fprintf(stderr, "%s\n", bstr(&cmd)); 211 fprintf(stderr, "exec %s: %s\n", argv->p[0], strerror(errno)); 212 _exit(1); 213 } 214 if(b != nil) { 215 close(p[1]); 216 breadfrom(b, p[0]); 217 close(p[0]); 218 } 219 220 if(nbg < 0) 221 fatal("bad bookkeeping"); 222 bg[nbg].pid = pid; 223 bg[nbg].mode = mode; 224 bg[nbg].cmd = btake(&cmd); 225 bg[nbg].b = b; 226 nbg++; 227 228 if(wait) 229 bgwait(); 230 231 bfree(&cmd); 232 } 233 234 // bgwait1 waits for a single background job. 235 static void 236 bgwait1(void) 237 { 238 int i, pid, status, mode; 239 char *cmd; 240 Buf *b; 241 242 errno = 0; 243 while((pid = wait(&status)) < 0) { 244 if(errno != EINTR) 245 fatal("waitpid: %s", strerror(errno)); 246 } 247 for(i=0; i<nbg; i++) 248 if(bg[i].pid == pid) 249 goto ok; 250 fatal("waitpid: unexpected pid"); 251 252 ok: 253 cmd = bg[i].cmd; 254 mode = bg[i].mode; 255 bg[i].pid = 0; 256 b = bg[i].b; 257 bg[i].b = nil; 258 bg[i] = bg[--nbg]; 259 260 if(mode == CheckExit && (!WIFEXITED(status) || WEXITSTATUS(status) != 0)) { 261 if(b != nil) 262 xprintf("%s\n", bstr(b)); 263 fatal("FAILED: %s", cmd); 264 } 265 xfree(cmd); 266 } 267 268 // bgwait waits for all the background jobs. 269 void 270 bgwait(void) 271 { 272 while(nbg > 0) 273 bgwait1(); 274 } 275 276 // xgetwd replaces b with the current directory. 277 void 278 xgetwd(Buf *b) 279 { 280 char buf[MAXPATHLEN]; 281 282 breset(b); 283 if(getcwd(buf, MAXPATHLEN) == nil) 284 fatal("getcwd: %s", strerror(errno)); 285 bwritestr(b, buf); 286 } 287 288 // xrealwd replaces b with the 'real' name for the given path. 289 // real is defined as what getcwd returns in that directory. 290 void 291 xrealwd(Buf *b, char *path) 292 { 293 int fd; 294 295 fd = open(".", 0); 296 if(fd < 0) 297 fatal("open .: %s", strerror(errno)); 298 if(chdir(path) < 0) 299 fatal("chdir %s: %s", path, strerror(errno)); 300 xgetwd(b); 301 if(fchdir(fd) < 0) 302 fatal("fchdir: %s", strerror(errno)); 303 close(fd); 304 } 305 306 // isdir reports whether p names an existing directory. 307 bool 308 isdir(char *p) 309 { 310 struct stat st; 311 312 return stat(p, &st) >= 0 && S_ISDIR(st.st_mode); 313 } 314 315 // isfile reports whether p names an existing file. 316 bool 317 isfile(char *p) 318 { 319 struct stat st; 320 321 return stat(p, &st) >= 0 && S_ISREG(st.st_mode); 322 } 323 324 // mtime returns the modification time of the file p. 325 Time 326 mtime(char *p) 327 { 328 struct stat st; 329 330 if(stat(p, &st) < 0) 331 return 0; 332 return (Time)st.st_mtime*1000000000LL; 333 } 334 335 // isabs reports whether p is an absolute path. 336 bool 337 isabs(char *p) 338 { 339 return hasprefix(p, "/"); 340 } 341 342 // readfile replaces b with the content of the named file. 343 void 344 readfile(Buf *b, char *file) 345 { 346 int fd; 347 348 breset(b); 349 fd = open(file, 0); 350 if(fd < 0) 351 fatal("open %s: %s", file, strerror(errno)); 352 breadfrom(b, fd); 353 close(fd); 354 } 355 356 // writefile writes b to the named file, creating it if needed. if 357 // exec is non-zero, marks the file as executable. 358 void 359 writefile(Buf *b, char *file, int exec) 360 { 361 int fd; 362 363 fd = creat(file, 0666); 364 if(fd < 0) 365 fatal("create %s: %s", file, strerror(errno)); 366 if(write(fd, b->p, b->len) != b->len) 367 fatal("short write: %s", strerror(errno)); 368 if(exec) 369 fchmod(fd, 0755); 370 close(fd); 371 } 372 373 // xmkdir creates the directory p. 374 void 375 xmkdir(char *p) 376 { 377 if(mkdir(p, 0777) < 0) 378 fatal("mkdir %s: %s", p, strerror(errno)); 379 } 380 381 // xmkdirall creates the directory p and its parents, as needed. 382 void 383 xmkdirall(char *p) 384 { 385 char *q; 386 387 if(isdir(p)) 388 return; 389 q = strrchr(p, '/'); 390 if(q != nil) { 391 *q = '\0'; 392 xmkdirall(p); 393 *q = '/'; 394 } 395 xmkdir(p); 396 } 397 398 // xremove removes the file p. 399 void 400 xremove(char *p) 401 { 402 if(vflag > 2) 403 errprintf("rm %s\n", p); 404 unlink(p); 405 } 406 407 // xremoveall removes the file or directory tree rooted at p. 408 void 409 xremoveall(char *p) 410 { 411 int i; 412 Buf b; 413 Vec dir; 414 415 binit(&b); 416 vinit(&dir); 417 418 if(isdir(p)) { 419 xreaddir(&dir, p); 420 for(i=0; i<dir.len; i++) { 421 bprintf(&b, "%s/%s", p, dir.p[i]); 422 xremoveall(bstr(&b)); 423 } 424 if(vflag > 2) 425 errprintf("rm %s\n", p); 426 rmdir(p); 427 } else { 428 if(vflag > 2) 429 errprintf("rm %s\n", p); 430 unlink(p); 431 } 432 433 bfree(&b); 434 vfree(&dir); 435 } 436 437 // xreaddir replaces dst with a list of the names of the files in dir. 438 // The names are relative to dir; they are not full paths. 439 void 440 xreaddir(Vec *dst, char *dir) 441 { 442 DIR *d; 443 struct dirent *dp; 444 445 vreset(dst); 446 d = opendir(dir); 447 if(d == nil) 448 fatal("opendir %s: %s", dir, strerror(errno)); 449 while((dp = readdir(d)) != nil) { 450 if(streq(dp->d_name, ".") || streq(dp->d_name, "..")) 451 continue; 452 vadd(dst, dp->d_name); 453 } 454 closedir(d); 455 } 456 457 // xworkdir creates a new temporary directory to hold object files 458 // and returns the name of that directory. 459 char* 460 xworkdir(void) 461 { 462 Buf b; 463 char *p; 464 465 binit(&b); 466 467 xgetenv(&b, "TMPDIR"); 468 if(b.len == 0) 469 #if defined(__HAIKU__) 470 bwritestr(&b, "/tmp"); 471 #else 472 bwritestr(&b, "/var/tmp"); 473 #endif 474 if(b.p[b.len-1] != '/') 475 bwrite(&b, "/", 1); 476 bwritestr(&b, "go-cbuild-XXXXXX"); 477 p = bstr(&b); 478 if(mkdtemp(p) == nil) 479 fatal("mkdtemp(%s): %s", p, strerror(errno)); 480 p = btake(&b); 481 482 bfree(&b); 483 484 return p; 485 } 486 487 // fatal prints an error message to standard error and exits. 488 void 489 fatal(char *msg, ...) 490 { 491 va_list arg; 492 493 fflush(stdout); 494 fprintf(stderr, "go tool dist: "); 495 va_start(arg, msg); 496 vfprintf(stderr, msg, arg); 497 va_end(arg); 498 fprintf(stderr, "\n"); 499 500 bgwait(); 501 exit(1); 502 } 503 504 // xmalloc returns a newly allocated zeroed block of n bytes of memory. 505 // It calls fatal if it runs out of memory. 506 void* 507 xmalloc(int n) 508 { 509 void *p; 510 511 p = malloc(n); 512 if(p == nil) 513 fatal("out of memory"); 514 memset(p, 0, n); 515 return p; 516 } 517 518 // xstrdup returns a newly allocated copy of p. 519 // It calls fatal if it runs out of memory. 520 char* 521 xstrdup(char *p) 522 { 523 p = strdup(p); 524 if(p == nil) 525 fatal("out of memory"); 526 return p; 527 } 528 529 // xrealloc grows the allocation p to n bytes and 530 // returns the new (possibly moved) pointer. 531 // It calls fatal if it runs out of memory. 532 void* 533 xrealloc(void *p, int n) 534 { 535 p = realloc(p, n); 536 if(p == nil) 537 fatal("out of memory"); 538 return p; 539 } 540 541 // xfree frees the result returned by xmalloc, xstrdup, or xrealloc. 542 void 543 xfree(void *p) 544 { 545 free(p); 546 } 547 548 // hassuffix reports whether p ends with suffix. 549 bool 550 hassuffix(char *p, char *suffix) 551 { 552 int np, ns; 553 554 np = strlen(p); 555 ns = strlen(suffix); 556 return np >= ns && streq(p+np-ns, suffix); 557 } 558 559 // hasprefix reports whether p begins with prefix. 560 bool 561 hasprefix(char *p, char *prefix) 562 { 563 return strncmp(p, prefix, strlen(prefix)) == 0; 564 } 565 566 // contains reports whether sep appears in p. 567 bool 568 contains(char *p, char *sep) 569 { 570 return strstr(p, sep) != nil; 571 } 572 573 // streq reports whether p and q are the same string. 574 bool 575 streq(char *p, char *q) 576 { 577 return strcmp(p, q) == 0; 578 } 579 580 // lastelem returns the final path element in p. 581 char* 582 lastelem(char *p) 583 { 584 char *out; 585 586 out = p; 587 for(; *p; p++) 588 if(*p == '/') 589 out = p+1; 590 return out; 591 } 592 593 // xmemmove copies n bytes from src to dst. 594 void 595 xmemmove(void *dst, void *src, int n) 596 { 597 memmove(dst, src, n); 598 } 599 600 // xmemcmp compares the n-byte regions starting at a and at b. 601 int 602 xmemcmp(void *a, void *b, int n) 603 { 604 return memcmp(a, b, n); 605 } 606 607 // xstrlen returns the length of the NUL-terminated string at p. 608 int 609 xstrlen(char *p) 610 { 611 return strlen(p); 612 } 613 614 // xexit exits the process with return code n. 615 void 616 xexit(int n) 617 { 618 exit(n); 619 } 620 621 // xatexit schedules the exit-handler f to be run when the program exits. 622 void 623 xatexit(void (*f)(void)) 624 { 625 atexit(f); 626 } 627 628 // xprintf prints a message to standard output. 629 void 630 xprintf(char *fmt, ...) 631 { 632 va_list arg; 633 634 va_start(arg, fmt); 635 vprintf(fmt, arg); 636 va_end(arg); 637 } 638 639 // errprintf prints a message to standard output. 640 void 641 errprintf(char *fmt, ...) 642 { 643 va_list arg; 644 645 va_start(arg, fmt); 646 vfprintf(stderr, fmt, arg); 647 va_end(arg); 648 } 649 650 // xsetenv sets the environment variable $name to the given value. 651 void 652 xsetenv(char *name, char *value) 653 { 654 setenv(name, value, 1); 655 } 656 657 // main takes care of OS-specific startup and dispatches to xmain. 658 int 659 main(int argc, char **argv) 660 { 661 Buf b; 662 int osx; 663 struct utsname u; 664 665 setvbuf(stdout, nil, _IOLBF, 0); 666 setvbuf(stderr, nil, _IOLBF, 0); 667 668 setenv("TERM", "dumb", 1); // disable escape codes in clang errors 669 670 binit(&b); 671 672 slash = "/"; 673 674 #if defined(__APPLE__) 675 gohostos = "darwin"; 676 // Even on 64-bit platform, darwin uname -m prints i386. 677 run(&b, nil, 0, "sysctl", "machdep.cpu.extfeatures", nil); 678 if(contains(bstr(&b), "EM64T")) 679 gohostarch = "amd64"; 680 #elif defined(__linux__) 681 gohostos = "linux"; 682 #elif defined(__DragonFly__) 683 gohostos = "dragonfly"; 684 #elif defined(__FreeBSD__) 685 gohostos = "freebsd"; 686 #elif defined(__FreeBSD_kernel__) 687 // detect debian/kFreeBSD. 688 // http://wiki.debian.org/Debian_GNU/kFreeBSD_FAQ#Q._How_do_I_detect_kfreebsd_with_preprocessor_directives_in_a_C_program.3F 689 gohostos = "freebsd"; 690 #elif defined(__OpenBSD__) 691 gohostos = "openbsd"; 692 #elif defined(__NetBSD__) 693 gohostos = "netbsd"; 694 #elif defined(__sun) && defined(__SVR4) 695 gohostos = "solaris"; 696 // Even on 64-bit platform, solaris uname -m prints i86pc. 697 run(&b, nil, 0, "isainfo", "-n", nil); 698 if(contains(bstr(&b), "amd64")) 699 gohostarch = "amd64"; 700 if(contains(bstr(&b), "i386")) 701 gohostarch = "386"; 702 #elif defined(__HAIKU__) 703 gohostos = "haiku"; 704 // Under a Haiku PC, uname -m will always print BePC. 705 run(&b, nil, 0, "uname", "-p", nil); 706 if(contains(bstr(&b), "x86_64")) 707 gohostarch = "amd64"; 708 else if(contains(bstr(&b), "x86")) 709 gohostarch = "386"; 710 #else 711 fatal("unknown operating system"); 712 #endif 713 714 if(gohostarch == nil) { 715 if(uname(&u) < 0) 716 fatal("uname: %s", strerror(errno)); 717 if(contains(u.machine, "x86_64") || contains(u.machine, "amd64")) 718 gohostarch = "amd64"; 719 else if(hassuffix(u.machine, "86")) 720 gohostarch = "386"; 721 else if(contains(u.machine, "arm")) 722 gohostarch = "arm"; 723 else 724 fatal("unknown architecture: %s", u.machine); 725 } 726 727 if(streq(gohostarch, "arm")) 728 maxnbg = 1; 729 730 // The OS X 10.6 linker does not support external linking mode. 731 // See golang.org/issue/5130. 732 // 733 // OS X 10.6 does not work with clang either, but OS X 10.9 requires it. 734 // It seems to work with OS X 10.8, so we default to clang for 10.8 and later. 735 // See golang.org/issue/5822. 736 // 737 // Roughly, OS X 10.N shows up as uname release (N+4), 738 // so OS X 10.6 is uname version 10 and OS X 10.8 is uname version 12. 739 if(streq(gohostos, "darwin")) { 740 if(uname(&u) < 0) 741 fatal("uname: %s", strerror(errno)); 742 osx = atoi(u.release) - 4; 743 if(osx <= 6) 744 goextlinkenabled = "0"; 745 if(osx >= 8) 746 defaultclang = 1; 747 } 748 749 init(); 750 xmain(argc, argv); 751 bfree(&b); 752 return 0; 753 } 754 755 // xqsort is a wrapper for the C standard qsort. 756 void 757 xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*)) 758 { 759 qsort(data, n, elemsize, cmp); 760 } 761 762 // xstrcmp compares the NUL-terminated strings a and b. 763 int 764 xstrcmp(char *a, char *b) 765 { 766 return strcmp(a, b); 767 } 768 769 // xstrstr returns a pointer to the first occurrence of b in a. 770 char* 771 xstrstr(char *a, char *b) 772 { 773 return strstr(a, b); 774 } 775 776 // xstrrchr returns a pointer to the final occurrence of c in p. 777 char* 778 xstrrchr(char *p, int c) 779 { 780 return strrchr(p, c); 781 } 782 783 // xsamefile reports whether f1 and f2 are the same file (or dir) 784 int 785 xsamefile(char *f1, char *f2) 786 { 787 return streq(f1, f2); // suffice for now 788 } 789 790 sigjmp_buf sigill_jmpbuf; 791 static void sigillhand(int); 792 793 // xtryexecfunc tries to execute function f, if any illegal instruction 794 // signal received in the course of executing that function, it will 795 // return 0, otherwise it will return 1. 796 // Some systems (notably NetBSD) will spin and spin when executing VFPv3 797 // instructions on VFPv2 system (e.g. Raspberry Pi) without ever triggering 798 // SIGILL, so we set a 1-second alarm to catch that case. 799 int 800 xtryexecfunc(void (*f)(void)) 801 { 802 int r; 803 r = 0; 804 signal(SIGILL, sigillhand); 805 signal(SIGALRM, sigillhand); 806 alarm(1); 807 if(sigsetjmp(sigill_jmpbuf, 1) == 0) { 808 f(); 809 r = 1; 810 } 811 signal(SIGILL, SIG_DFL); 812 alarm(0); 813 signal(SIGALRM, SIG_DFL); 814 return r; 815 } 816 817 // SIGILL handler helper 818 static void 819 sigillhand(int signum) 820 { 821 USED(signum); 822 siglongjmp(sigill_jmpbuf, 1); 823 } 824 825 static void 826 __cpuid(int dst[4], int ax) 827 { 828 #ifdef __i386__ 829 // we need to avoid ebx on i386 (esp. when -fPIC). 830 asm volatile( 831 "mov %%ebx, %%edi\n\t" 832 "cpuid\n\t" 833 "xchgl %%ebx, %%edi" 834 : "=a" (dst[0]), "=D" (dst[1]), "=c" (dst[2]), "=d" (dst[3]) 835 : "0" (ax)); 836 #elif defined(__x86_64__) 837 asm volatile("cpuid" 838 : "=a" (dst[0]), "=b" (dst[1]), "=c" (dst[2]), "=d" (dst[3]) 839 : "0" (ax)); 840 #else 841 dst[0] = dst[1] = dst[2] = dst[3] = 0; 842 #endif 843 } 844 845 bool 846 cansse2(void) 847 { 848 int info[4]; 849 850 __cpuid(info, 1); 851 return (info[3] & (1<<26)) != 0; // SSE2 852 } 853 854 #endif // PLAN9 855 #endif // __WINDOWS__