github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/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 if(b.p[b.len-1] != '/') 470 bwrite(&b, "/", 1); 471 bwritestr(&b, "go-cbuild-XXXXXX"); 472 p = bstr(&b); 473 if(mkdtemp(p) == nil) 474 fatal("mkdtemp(%s): %s", p, strerror(errno)); 475 p = btake(&b); 476 477 bfree(&b); 478 479 return p; 480 } 481 482 // fatal prints an error message to standard error and exits. 483 void 484 fatal(char *msg, ...) 485 { 486 va_list arg; 487 488 fflush(stdout); 489 fprintf(stderr, "go tool dist: "); 490 va_start(arg, msg); 491 vfprintf(stderr, msg, arg); 492 va_end(arg); 493 fprintf(stderr, "\n"); 494 495 bgwait(); 496 exit(1); 497 } 498 499 // xmalloc returns a newly allocated zeroed block of n bytes of memory. 500 // It calls fatal if it runs out of memory. 501 void* 502 xmalloc(int n) 503 { 504 void *p; 505 506 p = malloc(n); 507 if(p == nil) 508 fatal("out of memory"); 509 memset(p, 0, n); 510 return p; 511 } 512 513 // xstrdup returns a newly allocated copy of p. 514 // It calls fatal if it runs out of memory. 515 char* 516 xstrdup(char *p) 517 { 518 p = strdup(p); 519 if(p == nil) 520 fatal("out of memory"); 521 return p; 522 } 523 524 // xrealloc grows the allocation p to n bytes and 525 // returns the new (possibly moved) pointer. 526 // It calls fatal if it runs out of memory. 527 void* 528 xrealloc(void *p, int n) 529 { 530 p = realloc(p, n); 531 if(p == nil) 532 fatal("out of memory"); 533 return p; 534 } 535 536 // xfree frees the result returned by xmalloc, xstrdup, or xrealloc. 537 void 538 xfree(void *p) 539 { 540 free(p); 541 } 542 543 // hassuffix reports whether p ends with suffix. 544 bool 545 hassuffix(char *p, char *suffix) 546 { 547 int np, ns; 548 549 np = strlen(p); 550 ns = strlen(suffix); 551 return np >= ns && strcmp(p+np-ns, suffix) == 0; 552 } 553 554 // hasprefix reports whether p begins with prefix. 555 bool 556 hasprefix(char *p, char *prefix) 557 { 558 return strncmp(p, prefix, strlen(prefix)) == 0; 559 } 560 561 // contains reports whether sep appears in p. 562 bool 563 contains(char *p, char *sep) 564 { 565 return strstr(p, sep) != nil; 566 } 567 568 // streq reports whether p and q are the same string. 569 bool 570 streq(char *p, char *q) 571 { 572 return strcmp(p, q) == 0; 573 } 574 575 // lastelem returns the final path element in p. 576 char* 577 lastelem(char *p) 578 { 579 char *out; 580 581 out = p; 582 for(; *p; p++) 583 if(*p == '/') 584 out = p+1; 585 return out; 586 } 587 588 // xmemmove copies n bytes from src to dst. 589 void 590 xmemmove(void *dst, void *src, int n) 591 { 592 memmove(dst, src, n); 593 } 594 595 // xmemcmp compares the n-byte regions starting at a and at b. 596 int 597 xmemcmp(void *a, void *b, int n) 598 { 599 return memcmp(a, b, n); 600 } 601 602 // xstrlen returns the length of the NUL-terminated string at p. 603 int 604 xstrlen(char *p) 605 { 606 return strlen(p); 607 } 608 609 // xexit exits the process with return code n. 610 void 611 xexit(int n) 612 { 613 exit(n); 614 } 615 616 // xatexit schedules the exit-handler f to be run when the program exits. 617 void 618 xatexit(void (*f)(void)) 619 { 620 atexit(f); 621 } 622 623 // xprintf prints a message to standard output. 624 void 625 xprintf(char *fmt, ...) 626 { 627 va_list arg; 628 629 va_start(arg, fmt); 630 vprintf(fmt, arg); 631 va_end(arg); 632 } 633 634 // errprintf prints a message to standard output. 635 void 636 errprintf(char *fmt, ...) 637 { 638 va_list arg; 639 640 va_start(arg, fmt); 641 vfprintf(stderr, fmt, arg); 642 va_end(arg); 643 } 644 645 // xsetenv sets the environment variable $name to the given value. 646 void 647 xsetenv(char *name, char *value) 648 { 649 setenv(name, value, 1); 650 } 651 652 // main takes care of OS-specific startup and dispatches to xmain. 653 int 654 main(int argc, char **argv) 655 { 656 Buf b; 657 int osx; 658 struct utsname u; 659 660 setvbuf(stdout, nil, _IOLBF, 0); 661 setvbuf(stderr, nil, _IOLBF, 0); 662 663 setenv("TERM", "dumb", 1); // disable escape codes in clang errors 664 665 binit(&b); 666 667 slash = "/"; 668 669 #if defined(__APPLE__) 670 gohostos = "darwin"; 671 // Even on 64-bit platform, darwin uname -m prints i386. 672 run(&b, nil, 0, "sysctl", "machdep.cpu.extfeatures", nil); 673 if(contains(bstr(&b), "EM64T")) 674 gohostarch = "amd64"; 675 #elif defined(__linux__) 676 gohostos = "linux"; 677 #elif defined(__DragonFly__) 678 gohostos = "dragonfly"; 679 #elif defined(__FreeBSD__) 680 gohostos = "freebsd"; 681 #elif defined(__FreeBSD_kernel__) 682 // detect debian/kFreeBSD. 683 // http://wiki.debian.org/Debian_GNU/kFreeBSD_FAQ#Q._How_do_I_detect_kfreebsd_with_preprocessor_directives_in_a_C_program.3F 684 gohostos = "freebsd"; 685 #elif defined(__OpenBSD__) 686 gohostos = "openbsd"; 687 #elif defined(__NetBSD__) 688 gohostos = "netbsd"; 689 #else 690 fatal("unknown operating system"); 691 #endif 692 693 if(gohostarch == nil) { 694 if(uname(&u) < 0) 695 fatal("uname: %s", strerror(errno)); 696 if(contains(u.machine, "x86_64") || contains(u.machine, "amd64")) 697 gohostarch = "amd64"; 698 else if(hassuffix(u.machine, "86")) 699 gohostarch = "386"; 700 else if(contains(u.machine, "arm")) 701 gohostarch = "arm"; 702 else 703 fatal("unknown architecture: %s", u.machine); 704 } 705 706 if(strcmp(gohostarch, "arm") == 0) 707 maxnbg = 1; 708 709 // The OS X 10.6 linker does not support external linking mode. 710 // See golang.org/issue/5130. 711 // 712 // OS X 10.6 does not work with clang either, but OS X 10.9 requires it. 713 // It seems to work with OS X 10.8, so we default to clang for 10.8 and later. 714 // See golang.org/issue/5822. 715 // 716 // Roughly, OS X 10.N shows up as uname release (N+4), 717 // so OS X 10.6 is uname version 10 and OS X 10.8 is uname version 12. 718 if(strcmp(gohostos, "darwin") == 0) { 719 if(uname(&u) < 0) 720 fatal("uname: %s", strerror(errno)); 721 osx = atoi(u.release) - 4; 722 if(osx <= 6) 723 goextlinkenabled = "0"; 724 if(osx >= 8) 725 defaultclang = 1; 726 } 727 728 init(); 729 xmain(argc, argv); 730 bfree(&b); 731 return 0; 732 } 733 734 // xqsort is a wrapper for the C standard qsort. 735 void 736 xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*)) 737 { 738 qsort(data, n, elemsize, cmp); 739 } 740 741 // xstrcmp compares the NUL-terminated strings a and b. 742 int 743 xstrcmp(char *a, char *b) 744 { 745 return strcmp(a, b); 746 } 747 748 // xstrstr returns a pointer to the first occurrence of b in a. 749 char* 750 xstrstr(char *a, char *b) 751 { 752 return strstr(a, b); 753 } 754 755 // xstrrchr returns a pointer to the final occurrence of c in p. 756 char* 757 xstrrchr(char *p, int c) 758 { 759 return strrchr(p, c); 760 } 761 762 // xsamefile reports whether f1 and f2 are the same file (or dir) 763 int 764 xsamefile(char *f1, char *f2) 765 { 766 return streq(f1, f2); // suffice for now 767 } 768 769 sigjmp_buf sigill_jmpbuf; 770 static void sigillhand(int); 771 772 // xtryexecfunc tries to execute function f, if any illegal instruction 773 // signal received in the course of executing that function, it will 774 // return 0, otherwise it will return 1. 775 // Some systems (notably NetBSD) will spin and spin when executing VFPv3 776 // instructions on VFPv2 system (e.g. Raspberry Pi) without ever triggering 777 // SIGILL, so we set a 1-second alarm to catch that case. 778 int 779 xtryexecfunc(void (*f)(void)) 780 { 781 int r; 782 r = 0; 783 signal(SIGILL, sigillhand); 784 signal(SIGALRM, sigillhand); 785 alarm(1); 786 if(sigsetjmp(sigill_jmpbuf, 1) == 0) { 787 f(); 788 r = 1; 789 } 790 signal(SIGILL, SIG_DFL); 791 alarm(0); 792 signal(SIGALRM, SIG_DFL); 793 return r; 794 } 795 796 // SIGILL handler helper 797 static void 798 sigillhand(int signum) 799 { 800 USED(signum); 801 siglongjmp(sigill_jmpbuf, 1); 802 } 803 804 static void 805 __cpuid(int dst[4], int ax) 806 { 807 #ifdef __i386__ 808 // we need to avoid ebx on i386 (esp. when -fPIC). 809 asm volatile( 810 "mov %%ebx, %%edi\n\t" 811 "cpuid\n\t" 812 "xchgl %%ebx, %%edi" 813 : "=a" (dst[0]), "=D" (dst[1]), "=c" (dst[2]), "=d" (dst[3]) 814 : "0" (ax)); 815 #elif defined(__x86_64__) 816 asm volatile("cpuid" 817 : "=a" (dst[0]), "=b" (dst[1]), "=c" (dst[2]), "=d" (dst[3]) 818 : "0" (ax)); 819 #else 820 dst[0] = dst[1] = dst[2] = dst[3] = 0; 821 #endif 822 } 823 824 bool 825 cansse2(void) 826 { 827 int info[4]; 828 829 __cpuid(info, 1); 830 return (info[3] & (1<<26)) != 0; // SSE2 831 } 832 833 #endif // PLAN9 834 #endif // __WINDOWS__