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