This source file includes following definitions.
- bprintf
- bpathf
- bwritef
- breadfrom
- xgetenv
- run
- runv
- bgrunv
- genrun
- bgwait1
- bgwait
- xgetwd
- xrealwd
- isdir
- isfile
- mtime
- isabs
- readfile
- writefile
- xmkdir
- xmkdirall
- xremove
- xremoveall
- xreaddir
- xworkdir
- fatal
- xmalloc
- xstrdup
- xrealloc
- xfree
- hassuffix
- hasprefix
- contains
- streq
- lastelem
- xmemmove
- xmemcmp
- xstrlen
- xexit
- xatexit
- xprintf
- errprintf
- xsetenv
- main
- xqsort
- xstrcmp
- xstrstr
- xstrrchr
- xsamefile
- xtryexecfunc
- sigillhand
- __cpuid
- cansse2
#ifndef WIN32
#ifndef PLAN9
#include "a.h"
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/param.h>
#include <sys/utsname.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
#include <setjmp.h>
#include <signal.h>
char*
bprintf(Buf *b, char *fmt, ...)
{
va_list arg;
char buf[4096];
breset(b);
va_start(arg, fmt);
vsnprintf(buf, sizeof buf, fmt, arg);
va_end(arg);
bwritestr(b, buf);
return bstr(b);
}
char*
bpathf(Buf *b, char *fmt, ...)
{
va_list arg;
char buf[4096];
breset(b);
va_start(arg, fmt);
vsnprintf(buf, sizeof buf, fmt, arg);
va_end(arg);
bwritestr(b, buf);
return bstr(b);
}
void
bwritef(Buf *b, char *fmt, ...)
{
va_list arg;
char buf[4096];
va_start(arg, fmt);
vsnprintf(buf, sizeof buf, fmt, arg);
va_end(arg);
bwritestr(b, buf);
}
static void
breadfrom(Buf *b, int fd)
{
int n;
for(;;) {
bgrow(b, 4096);
n = read(fd, b->p+b->len, 4096);
if(n < 0)
fatal("read: %s", strerror(errno));
if(n == 0)
break;
b->len += n;
}
}
void
xgetenv(Buf *b, char *name)
{
char *p;
breset(b);
p = getenv(name);
if(p != NULL)
bwritestr(b, p);
}
static void genrun(Buf *b, char *dir, int mode, Vec *argv, int bg);
void
run(Buf *b, char *dir, int mode, char *cmd, ...)
{
va_list arg;
Vec argv;
char *p;
vinit(&argv);
vadd(&argv, cmd);
va_start(arg, cmd);
while((p = va_arg(arg, char*)) != nil)
vadd(&argv, p);
va_end(arg);
runv(b, dir, mode, &argv);
vfree(&argv);
}
void
runv(Buf *b, char *dir, int mode, Vec *argv)
{
genrun(b, dir, mode, argv, 1);
}
void
bgrunv(char *dir, int mode, Vec *argv)
{
genrun(nil, dir, mode, argv, 0);
}
#define MAXBG 4
static struct {
int pid;
int mode;
char *cmd;
Buf *b;
} bg[MAXBG];
static int nbg;
static int maxnbg = nelem(bg);
static void bgwait1(void);
static void
genrun(Buf *b, char *dir, int mode, Vec *argv, int wait)
{
int i, p[2], pid;
Buf cmd;
char *q;
while(nbg >= maxnbg)
bgwait1();
binit(&cmd);
for(i=0; i<argv->len; i++) {
if(i > 0)
bwritestr(&cmd, " ");
q = argv->p[i];
if(workdir != nil && hasprefix(q, workdir)) {
bwritestr(&cmd, "$WORK");
q += strlen(workdir);
}
bwritestr(&cmd, q);
}
if(vflag > 1)
errprintf("%s\n", bstr(&cmd));
if(b != nil) {
breset(b);
if(pipe(p) < 0)
fatal("pipe: %s", strerror(errno));
}
switch(pid = fork()) {
case -1:
fatal("fork: %s", strerror(errno));
case 0:
if(b != nil) {
close(0);
close(p[0]);
dup2(p[1], 1);
dup2(p[1], 2);
if(p[1] > 2)
close(p[1]);
}
if(dir != nil) {
if(chdir(dir) < 0) {
fprintf(stderr, "chdir %s: %s\n", dir, strerror(errno));
_exit(1);
}
}
vadd(argv, nil);
execvp(argv->p[0], argv->p);
fprintf(stderr, "%s\n", bstr(&cmd));
fprintf(stderr, "exec %s: %s\n", argv->p[0], strerror(errno));
_exit(1);
}
if(b != nil) {
close(p[1]);
breadfrom(b, p[0]);
close(p[0]);
}
if(nbg < 0)
fatal("bad bookkeeping");
bg[nbg].pid = pid;
bg[nbg].mode = mode;
bg[nbg].cmd = btake(&cmd);
bg[nbg].b = b;
nbg++;
if(wait)
bgwait();
bfree(&cmd);
}
static void
bgwait1(void)
{
int i, pid, status, mode;
char *cmd;
Buf *b;
errno = 0;
while((pid = wait(&status)) < 0) {
if(errno != EINTR)
fatal("waitpid: %s", strerror(errno));
}
for(i=0; i<nbg; i++)
if(bg[i].pid == pid)
goto ok;
fatal("waitpid: unexpected pid");
ok:
cmd = bg[i].cmd;
mode = bg[i].mode;
bg[i].pid = 0;
b = bg[i].b;
bg[i].b = nil;
bg[i] = bg[--nbg];
if(mode == CheckExit && (!WIFEXITED(status) || WEXITSTATUS(status) != 0)) {
if(b != nil)
xprintf("%s\n", bstr(b));
fatal("FAILED: %s", cmd);
}
xfree(cmd);
}
void
bgwait(void)
{
while(nbg > 0)
bgwait1();
}
void
xgetwd(Buf *b)
{
char buf[MAXPATHLEN];
breset(b);
if(getcwd(buf, MAXPATHLEN) == nil)
fatal("getcwd: %s", strerror(errno));
bwritestr(b, buf);
}
void
xrealwd(Buf *b, char *path)
{
int fd;
fd = open(".", 0);
if(fd < 0)
fatal("open .: %s", strerror(errno));
if(chdir(path) < 0)
fatal("chdir %s: %s", path, strerror(errno));
xgetwd(b);
if(fchdir(fd) < 0)
fatal("fchdir: %s", strerror(errno));
close(fd);
}
bool
isdir(char *p)
{
struct stat st;
return stat(p, &st) >= 0 && S_ISDIR(st.st_mode);
}
bool
isfile(char *p)
{
struct stat st;
return stat(p, &st) >= 0 && S_ISREG(st.st_mode);
}
Time
mtime(char *p)
{
struct stat st;
if(stat(p, &st) < 0)
return 0;
return (Time)st.st_mtime*1000000000LL;
}
bool
isabs(char *p)
{
return hasprefix(p, "/");
}
void
readfile(Buf *b, char *file)
{
int fd;
breset(b);
fd = open(file, 0);
if(fd < 0)
fatal("open %s: %s", file, strerror(errno));
breadfrom(b, fd);
close(fd);
}
void
writefile(Buf *b, char *file, int exec)
{
int fd;
fd = creat(file, 0666);
if(fd < 0)
fatal("create %s: %s", file, strerror(errno));
if(write(fd, b->p, b->len) != b->len)
fatal("short write: %s", strerror(errno));
if(exec)
fchmod(fd, 0755);
close(fd);
}
void
xmkdir(char *p)
{
if(mkdir(p, 0777) < 0)
fatal("mkdir %s: %s", p, strerror(errno));
}
void
xmkdirall(char *p)
{
char *q;
if(isdir(p))
return;
q = strrchr(p, '/');
if(q != nil) {
*q = '\0';
xmkdirall(p);
*q = '/';
}
xmkdir(p);
}
void
xremove(char *p)
{
if(vflag > 2)
errprintf("rm %s\n", p);
unlink(p);
}
void
xremoveall(char *p)
{
int i;
Buf b;
Vec dir;
binit(&b);
vinit(&dir);
if(isdir(p)) {
xreaddir(&dir, p);
for(i=0; i<dir.len; i++) {
bprintf(&b, "%s/%s", p, dir.p[i]);
xremoveall(bstr(&b));
}
if(vflag > 2)
errprintf("rm %s\n", p);
rmdir(p);
} else {
if(vflag > 2)
errprintf("rm %s\n", p);
unlink(p);
}
bfree(&b);
vfree(&dir);
}
void
xreaddir(Vec *dst, char *dir)
{
DIR *d;
struct dirent *dp;
vreset(dst);
d = opendir(dir);
if(d == nil)
fatal("opendir %s: %s", dir, strerror(errno));
while((dp = readdir(d)) != nil) {
if(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
continue;
vadd(dst, dp->d_name);
}
closedir(d);
}
char*
xworkdir(void)
{
Buf b;
char *p;
binit(&b);
xgetenv(&b, "TMPDIR");
if(b.len == 0)
bwritestr(&b, "/var/tmp");
if(b.p[b.len-1] != '/')
bwrite(&b, "/", 1);
bwritestr(&b, "go-cbuild-XXXXXX");
p = bstr(&b);
if(mkdtemp(p) == nil)
fatal("mkdtemp(%s): %s", p, strerror(errno));
p = btake(&b);
bfree(&b);
return p;
}
void
fatal(char *msg, ...)
{
va_list arg;
fflush(stdout);
fprintf(stderr, "go tool dist: ");
va_start(arg, msg);
vfprintf(stderr, msg, arg);
va_end(arg);
fprintf(stderr, "\n");
bgwait();
exit(1);
}
void*
xmalloc(int n)
{
void *p;
p = malloc(n);
if(p == nil)
fatal("out of memory");
memset(p, 0, n);
return p;
}
char*
xstrdup(char *p)
{
p = strdup(p);
if(p == nil)
fatal("out of memory");
return p;
}
void*
xrealloc(void *p, int n)
{
p = realloc(p, n);
if(p == nil)
fatal("out of memory");
return p;
}
void
xfree(void *p)
{
free(p);
}
bool
hassuffix(char *p, char *suffix)
{
int np, ns;
np = strlen(p);
ns = strlen(suffix);
return np >= ns && strcmp(p+np-ns, suffix) == 0;
}
bool
hasprefix(char *p, char *prefix)
{
return strncmp(p, prefix, strlen(prefix)) == 0;
}
bool
contains(char *p, char *sep)
{
return strstr(p, sep) != nil;
}
bool
streq(char *p, char *q)
{
return strcmp(p, q) == 0;
}
char*
lastelem(char *p)
{
char *out;
out = p;
for(; *p; p++)
if(*p == '/')
out = p+1;
return out;
}
void
xmemmove(void *dst, void *src, int n)
{
memmove(dst, src, n);
}
int
xmemcmp(void *a, void *b, int n)
{
return memcmp(a, b, n);
}
int
xstrlen(char *p)
{
return strlen(p);
}
void
xexit(int n)
{
exit(n);
}
void
xatexit(void (*f)(void))
{
atexit(f);
}
void
xprintf(char *fmt, ...)
{
va_list arg;
va_start(arg, fmt);
vprintf(fmt, arg);
va_end(arg);
}
void
errprintf(char *fmt, ...)
{
va_list arg;
va_start(arg, fmt);
vfprintf(stderr, fmt, arg);
va_end(arg);
}
void
xsetenv(char *name, char *value)
{
setenv(name, value, 1);
}
int
main(int argc, char **argv)
{
Buf b;
int osx;
struct utsname u;
setvbuf(stdout, nil, _IOLBF, 0);
setvbuf(stderr, nil, _IOLBF, 0);
setenv("TERM", "dumb", 1);
binit(&b);
slash = "/";
#if defined(__APPLE__)
gohostos = "darwin";
run(&b, nil, 0, "sysctl", "machdep.cpu.extfeatures", nil);
if(contains(bstr(&b), "EM64T"))
gohostarch = "amd64";
#elif defined(__linux__)
gohostos = "linux";
#elif defined(__DragonFly__)
gohostos = "dragonfly";
#elif defined(__FreeBSD__)
gohostos = "freebsd";
#elif defined(__FreeBSD_kernel__)
gohostos = "freebsd";
#elif defined(__OpenBSD__)
gohostos = "openbsd";
#elif defined(__NetBSD__)
gohostos = "netbsd";
#elif defined(__sun) && defined(__SVR4)
gohostos = "solaris";
run(&b, nil, 0, "isainfo", "-n", nil);
if(contains(bstr(&b), "amd64"))
gohostarch = "amd64";
if(contains(bstr(&b), "i386"))
gohostarch = "386";
#else
fatal("unknown operating system");
#endif
if(gohostarch == nil) {
if(uname(&u) < 0)
fatal("uname: %s", strerror(errno));
if(contains(u.machine, "x86_64") || contains(u.machine, "amd64"))
gohostarch = "amd64";
else if(hassuffix(u.machine, "86"))
gohostarch = "386";
else if(contains(u.machine, "arm"))
gohostarch = "arm";
else
fatal("unknown architecture: %s", u.machine);
}
if(strcmp(gohostarch, "arm") == 0)
maxnbg = 1;
if(strcmp(gohostos, "darwin") == 0) {
if(uname(&u) < 0)
fatal("uname: %s", strerror(errno));
osx = atoi(u.release) - 4;
if(osx <= 6)
goextlinkenabled = "0";
if(osx >= 8)
defaultclang = 1;
}
init();
xmain(argc, argv);
bfree(&b);
return 0;
}
void
xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*))
{
qsort(data, n, elemsize, cmp);
}
int
xstrcmp(char *a, char *b)
{
return strcmp(a, b);
}
char*
xstrstr(char *a, char *b)
{
return strstr(a, b);
}
char*
xstrrchr(char *p, int c)
{
return strrchr(p, c);
}
int
xsamefile(char *f1, char *f2)
{
return streq(f1, f2);
}
sigjmp_buf sigill_jmpbuf;
static void sigillhand(int);
int
xtryexecfunc(void (*f)(void))
{
int r;
r = 0;
signal(SIGILL, sigillhand);
signal(SIGALRM, sigillhand);
alarm(1);
if(sigsetjmp(sigill_jmpbuf, 1) == 0) {
f();
r = 1;
}
signal(SIGILL, SIG_DFL);
alarm(0);
signal(SIGALRM, SIG_DFL);
return r;
}
static void
sigillhand(int signum)
{
USED(signum);
siglongjmp(sigill_jmpbuf, 1);
}
static void
__cpuid(int dst[4], int ax)
{
#ifdef __i386__
asm volatile(
"mov %%ebx, %%edi\n\t"
"cpuid\n\t"
"xchgl %%ebx, %%edi"
: "=a" (dst[0]), "=D" (dst[1]), "=c" (dst[2]), "=d" (dst[3])
: "0" (ax));
#elif defined(__x86_64__)
asm volatile("cpuid"
: "=a" (dst[0]), "=b" (dst[1]), "=c" (dst[2]), "=d" (dst[3])
: "0" (ax));
#else
dst[0] = dst[1] = dst[2] = dst[3] = 0;
#endif
}
bool
cansse2(void)
{
int info[4];
__cpuid(info, 1);
return (info[3] & (1<<26)) != 0;
}
#endif
#endif