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