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__