github.com/razvanm/vanadium-go-1.3@v0.0.0-20160721203343-4a65068e5915/src/cmd/dist/plan9.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  #ifdef PLAN9
    11  
    12  #include <u.h>
    13  #include <libc.h>
    14  #include <stdio.h>
    15  #undef nil
    16  #undef nelem
    17  #include "a.h"
    18  
    19  // bprintf replaces the buffer with the result of the printf formatting
    20  // and returns a pointer to the NUL-terminated buffer contents.
    21  char*
    22  bprintf(Buf *b, char *fmt, ...)
    23  {
    24  	va_list arg;
    25  	char buf[4096];
    26  
    27  	breset(b);
    28  	va_start(arg, fmt);
    29  	vsnprintf(buf, sizeof buf, fmt, arg);
    30  	va_end(arg);
    31  	bwritestr(b, buf);
    32  	return bstr(b);
    33  }
    34  
    35  // bpathf is the same as bprintf (on windows it turns / into \ after the printf).
    36  // It returns a pointer to the NUL-terminated buffer contents.
    37  char*
    38  bpathf(Buf *b, char *fmt, ...)
    39  {
    40  	va_list arg;
    41  	char buf[4096];
    42  	
    43  	breset(b);
    44  	va_start(arg, fmt);
    45  	vsnprintf(buf, sizeof buf, fmt, arg);
    46  	va_end(arg);
    47  	bwritestr(b, buf);
    48  	return bstr(b);
    49  }
    50  
    51  // bwritef is like bprintf but does not reset the buffer
    52  // and does not return the NUL-terminated string.
    53  void
    54  bwritef(Buf *b, char *fmt, ...)
    55  {
    56  	va_list arg;
    57  	char buf[4096];
    58  	
    59  	va_start(arg, fmt);
    60  	vsnprintf(buf, sizeof buf, fmt, arg);
    61  	va_end(arg);
    62  	bwritestr(b, buf);
    63  }
    64  
    65  // breadfrom appends to b all the data that can be read from fd.
    66  static void
    67  breadfrom(Buf *b, int fd)
    68  {
    69  	int n;
    70  
    71  	for(;;) {
    72  		bgrow(b, 4096);
    73  		n = read(fd, b->p+b->len, 4096);
    74  		if(n < 0)
    75  			fatal("read");
    76  		if(n == 0)
    77  			break;
    78  		b->len += n;
    79  	}
    80  }
    81  
    82  // xgetenv replaces b with the value of the named environment variable.
    83  void
    84  xgetenv(Buf *b, char *name)
    85  {
    86  	char *p;
    87  	
    88  	breset(b);
    89  	p = getenv(name);
    90  	if(p != nil)
    91  		bwritestr(b, p);
    92  }
    93  
    94  static void genrun(Buf *b, char *dir, int mode, Vec *argv, int bg);
    95  
    96  // run runs the command named by cmd.
    97  // If b is not nil, run replaces b with the output of the command.
    98  // If dir is not nil, run runs the command in that directory.
    99  // If mode is CheckExit, run calls fatal if the command is not successful.
   100  void
   101  run(Buf *b, char *dir, int mode, char *cmd, ...)
   102  {
   103  	va_list arg;
   104  	Vec argv;
   105  	char *p;
   106  	
   107  	vinit(&argv);
   108  	vadd(&argv, cmd);
   109  	va_start(arg, cmd);
   110  	while((p = va_arg(arg, char*)) != nil)
   111  		vadd(&argv, p);
   112  	va_end(arg);
   113  	
   114  	runv(b, dir, mode, &argv);
   115  	
   116  	vfree(&argv);
   117  }
   118  
   119  // runv is like run but takes a vector.
   120  void
   121  runv(Buf *b, char *dir, int mode, Vec *argv)
   122  {
   123  	genrun(b, dir, mode, argv, 1);
   124  }
   125  
   126  // bgrunv is like run but runs the command in the background.
   127  // bgwait waits for pending bgrunv to finish.
   128  void
   129  bgrunv(char *dir, int mode, Vec *argv)
   130  {
   131  	genrun(nil, dir, mode, argv, 0);
   132  }
   133  
   134  #define MAXBG 4 /* maximum number of jobs to run at once */
   135  
   136  static struct {
   137  	int pid;
   138  	int mode;
   139  	char *cmd;
   140  	Buf *b;
   141  } bg[MAXBG];
   142  static int nbg;
   143  static int maxnbg = nelem(bg);
   144  
   145  static void bgwait1(void);
   146  
   147  // genrun is the generic run implementation.
   148  static void
   149  genrun(Buf *b, char *dir, int mode, Vec *argv, int wait)
   150  {
   151  	int i, p[2], pid;
   152  	Buf b1, cmd;
   153  	char *q;
   154  
   155  	while(nbg >= maxnbg)
   156  		bgwait1();
   157  
   158  	binit(&b1);
   159  	binit(&cmd);
   160  
   161  	if(!isabs(argv->p[0])) {
   162  		bpathf(&b1, "/bin/%s", argv->p[0]);
   163  		free(argv->p[0]);
   164  		argv->p[0] = xstrdup(bstr(&b1));
   165  	}
   166  
   167  	// Generate a copy of the command to show in a log.
   168  	// Substitute $WORK for the work directory.
   169  	for(i=0; i<argv->len; i++) {
   170  		if(i > 0)
   171  			bwritestr(&cmd, " ");
   172  		q = argv->p[i];
   173  		if(workdir != nil && hasprefix(q, workdir)) {
   174  			bwritestr(&cmd, "$WORK");
   175  			q += strlen(workdir);
   176  		}
   177  		bwritestr(&cmd, q);
   178  	}
   179  	if(vflag > 1)
   180  		errprintf("%s\n", bstr(&cmd));
   181  
   182  	if(b != nil) {
   183  		breset(b);
   184  		if(pipe(p) < 0)
   185  			fatal("pipe");
   186  	}
   187  
   188  	switch(pid = fork()) {
   189  	case -1:
   190  		fatal("fork");
   191  	case 0:
   192  		if(b != nil) {
   193  			close(0);
   194  			close(p[0]);
   195  			dup(p[1], 1);
   196  			dup(p[1], 2);
   197  			if(p[1] > 2)
   198  				close(p[1]);
   199  		}
   200  		if(dir != nil) {
   201  			if(chdir(dir) < 0) {
   202  				fprint(2, "chdir: %r\n");
   203  				_exits("chdir");
   204  			}
   205  		}
   206  		vadd(argv, nil);
   207  		exec(argv->p[0], argv->p);
   208  		fprint(2, "%s\n", bstr(&cmd));
   209  		fprint(2, "exec: %r\n");
   210  		_exits("exec");
   211  	}
   212  	if(b != nil) {
   213  		close(p[1]);
   214  		breadfrom(b, p[0]);
   215  		close(p[0]);
   216  	}
   217  
   218  	if(nbg < 0)
   219  		fatal("bad bookkeeping");
   220  	bg[nbg].pid = pid;
   221  	bg[nbg].mode = mode;
   222  	bg[nbg].cmd = btake(&cmd);
   223  	bg[nbg].b = b;
   224  	nbg++;
   225  	
   226  	if(wait)
   227  		bgwait();
   228  
   229  	bfree(&cmd);
   230  	bfree(&b1);
   231  }
   232  
   233  // bgwait1 waits for a single background job.
   234  static void
   235  bgwait1(void)
   236  {
   237  	Waitmsg *w;
   238  	int i, mode;
   239  	char *cmd;
   240  	Buf *b;
   241  
   242  	w = wait();
   243  	if(w == nil)
   244  		fatal("wait");
   245  		
   246  	for(i=0; i<nbg; i++)
   247  		if(bg[i].pid == w->pid)
   248  			goto ok;
   249  	fatal("wait: 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 && w->msg[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[4096];
   280  	
   281  	breset(b);
   282  	if(getwd(buf, sizeof buf) == nil)
   283  		fatal("getwd");
   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  	char buf[4096];
   293  	int fd;
   294  
   295  	fd = open(path, OREAD);
   296  	if(fd2path(fd, buf, sizeof buf) < 0)
   297  		fatal("fd2path");
   298  	close(fd);
   299  	breset(b);
   300  	bwritestr(b, buf);
   301  }
   302  
   303  // isdir reports whether p names an existing directory.
   304  bool
   305  isdir(char *p)
   306  {
   307  	Dir *d;
   308  	ulong mode;
   309  
   310  	d = dirstat(p);
   311  	if(d == nil)
   312  		return 0;
   313  	mode = d->mode;
   314  	free(d);
   315  	return (mode & DMDIR) == DMDIR;
   316  }
   317  
   318  // isfile reports whether p names an existing file.
   319  bool
   320  isfile(char *p)
   321  {
   322  	Dir *d;
   323  	ulong mode;
   324  
   325  	d = dirstat(p);
   326  	if(d == nil)
   327  		return 0;
   328  	mode = d->mode;
   329  	free(d);
   330  	return (mode & DMDIR) == 0;
   331  }
   332  
   333  // mtime returns the modification time of the file p.
   334  Time
   335  mtime(char *p)
   336  {
   337  	Dir *d;
   338  	ulong t;
   339  
   340  	d = dirstat(p);
   341  	if(d == nil)
   342  		return 0;
   343  	t = d->mtime;
   344  	free(d);
   345  	return (Time)t;
   346  }
   347  
   348  // isabs reports whether p is an absolute path.
   349  bool
   350  isabs(char *p)
   351  {
   352  	return hasprefix(p, "/");
   353  }
   354  
   355  // readfile replaces b with the content of the named file.
   356  void
   357  readfile(Buf *b, char *file)
   358  {
   359  	int fd;
   360  
   361  	breset(b);
   362  	fd = open(file, OREAD);
   363  	if(fd < 0)
   364  		fatal("open %s", file);
   365  	breadfrom(b, fd);
   366  	close(fd);
   367  }
   368  
   369  // writefile writes b to the named file, creating it if needed.
   370  void
   371  writefile(Buf *b, char *file, int exec)
   372  {
   373  	int fd;
   374  	Dir d;
   375  	
   376  	fd = create(file, ORDWR, 0666);
   377  	if(fd < 0)
   378  		fatal("create %s", file);
   379  	if(write(fd, b->p, b->len) != b->len)
   380  		fatal("short write");
   381  	if(exec) {
   382  		nulldir(&d);
   383  		d.mode = 0755;
   384  		dirfwstat(fd, &d);
   385  	}
   386  	close(fd);
   387  }
   388  
   389  // xmkdir creates the directory p.
   390  void
   391  xmkdir(char *p)
   392  {
   393  	int fd;
   394  
   395  	if(isdir(p))
   396  		return;
   397  	fd = create(p, OREAD, 0777|DMDIR);
   398  	close(fd);
   399  	if(fd < 0)
   400  		fatal("mkdir %s", p);
   401  }
   402  
   403  // xmkdirall creates the directory p and its parents, as needed.
   404  void
   405  xmkdirall(char *p)
   406  {
   407  	char *q;
   408  
   409  	if(isdir(p))
   410  		return;
   411  	q = strrchr(p, '/');
   412  	if(q != nil) {
   413  		*q = '\0';
   414  		xmkdirall(p);
   415  		*q = '/';
   416  	}
   417  	xmkdir(p);
   418  }
   419  
   420  // xremove removes the file p.
   421  void
   422  xremove(char *p)
   423  {
   424  	if(vflag > 2)
   425  		errprintf("rm %s\n", p);
   426  	remove(p);
   427  }
   428  
   429  // xremoveall removes the file or directory tree rooted at p.
   430  void
   431  xremoveall(char *p)
   432  {
   433  	int i;
   434  	Buf b;
   435  	Vec dir;
   436  
   437  	binit(&b);
   438  	vinit(&dir);
   439  
   440  	if(isdir(p)) {
   441  		xreaddir(&dir, p);
   442  		for(i=0; i<dir.len; i++) {
   443  			bprintf(&b, "%s/%s", p, dir.p[i]);
   444  			xremoveall(bstr(&b));
   445  		}
   446  	}
   447  	if(vflag > 2)
   448  		errprintf("rm %s\n", p);
   449  	remove(p);
   450  	
   451  	bfree(&b);
   452  	vfree(&dir);	
   453  }
   454  
   455  // xreaddir replaces dst with a list of the names of the files in dir.
   456  // The names are relative to dir; they are not full paths.
   457  void
   458  xreaddir(Vec *dst, char *dir)
   459  {
   460  	Dir *d;
   461  	int fd, i, n;
   462  
   463  	vreset(dst);
   464  
   465  	fd = open(dir, OREAD);
   466  	if(fd < 0)
   467  		fatal("open %s", dir);
   468  	n = dirreadall(fd, &d);
   469  	for(i=0; i<n; i++)
   470  		vadd(dst, d[i].name);
   471  	free(d);
   472  	close(fd);
   473  }
   474  
   475  // xworkdir creates a new temporary directory to hold object files
   476  // and returns the name of that directory.
   477  char*
   478  xworkdir(void)
   479  {
   480  	Buf b;
   481  	char *p;
   482  	int fd, tries;
   483  
   484  	binit(&b);
   485  
   486  	fd = 0;
   487  	for(tries=0; tries<1000; tries++) {
   488  		bprintf(&b, "/tmp/go-cbuild-%06x", nrand((1<<24)-1));
   489  		fd = create(bstr(&b), OREAD|OEXCL, 0700|DMDIR);
   490  		if(fd >= 0)
   491  			goto done;
   492  	}
   493  	fatal("xworkdir create");
   494  
   495  done:
   496  	close(fd);
   497  	p = btake(&b);
   498  
   499  	bfree(&b);
   500  	return p;
   501  }
   502  
   503  // fatal prints an error message to standard error and exits.
   504  void
   505  fatal(char *msg, ...)
   506  {
   507  	char buf[ERRMAX];
   508  	va_list arg;
   509  	
   510  	rerrstr(buf, sizeof buf);
   511  
   512  	fflush(stdout);
   513  	fprintf(stderr, "go tool dist: ");
   514  	va_start(arg, msg);
   515  	vfprintf(stderr, msg, arg);
   516  	va_end(arg);
   517  
   518  	if(buf[0])
   519  		fprintf(stderr, ": %s", buf);
   520  	fprintf(stderr, "\n");
   521  
   522  	bgwait();
   523  	exits(msg);
   524  }
   525  
   526  // xmalloc returns a newly allocated zeroed block of n bytes of memory.
   527  // It calls fatal if it runs out of memory.
   528  void*
   529  xmalloc(int n)
   530  {
   531  	void *p;
   532  	
   533  	p = malloc(n);
   534  	if(p == nil)
   535  		fatal("out of memory");
   536  	memset(p, 0, n);
   537  	return p;
   538  }
   539  
   540  // xstrdup returns a newly allocated copy of p.
   541  // It calls fatal if it runs out of memory.
   542  char*
   543  xstrdup(char *p)
   544  {
   545  	p = strdup(p);
   546  	if(p == nil)
   547  		fatal("out of memory");
   548  	return p;
   549  }
   550  
   551  // xrealloc grows the allocation p to n bytes and
   552  // returns the new (possibly moved) pointer.
   553  // It calls fatal if it runs out of memory.
   554  void*
   555  xrealloc(void *p, int n)
   556  {
   557  	p = realloc(p, n);
   558  	if(p == nil)
   559  		fatal("out of memory");
   560  	return p;
   561  }
   562  
   563  // xfree frees the result returned by xmalloc, xstrdup, or xrealloc.
   564  void
   565  xfree(void *p)
   566  {
   567  	free(p);
   568  }
   569  
   570  // hassuffix reports whether p ends with suffix.
   571  bool
   572  hassuffix(char *p, char *suffix)
   573  {
   574  	int np, ns;
   575  
   576  	np = strlen(p);
   577  	ns = strlen(suffix);
   578  	return np >= ns && streq(p+np-ns, suffix);
   579  }
   580  
   581  // hasprefix reports whether p begins with prefix.
   582  bool
   583  hasprefix(char *p, char *prefix)
   584  {
   585  	return strncmp(p, prefix, strlen(prefix)) == 0;
   586  }
   587  
   588  // contains reports whether sep appears in p.
   589  bool
   590  contains(char *p, char *sep)
   591  {
   592  	return strstr(p, sep) != nil;
   593  }
   594  
   595  // streq reports whether p and q are the same string.
   596  bool
   597  streq(char *p, char *q)
   598  {
   599  	return strcmp(p, q) == 0;
   600  }
   601  
   602  // lastelem returns the final path element in p.
   603  char*
   604  lastelem(char *p)
   605  {
   606  	char *out;
   607  
   608  	out = p;
   609  	for(; *p; p++)
   610  		if(*p == '/')
   611  			out = p+1;
   612  	return out;
   613  }
   614  
   615  // xmemmove copies n bytes from src to dst.
   616  void
   617  xmemmove(void *dst, void *src, int n)
   618  {
   619  	memmove(dst, src, n);
   620  }
   621  
   622  // xmemcmp compares the n-byte regions starting at a and at b.
   623  int
   624  xmemcmp(void *a, void *b, int n)
   625  {
   626  	return memcmp(a, b, n);
   627  }
   628  
   629  // xstrlen returns the length of the NUL-terminated string at p.
   630  int
   631  xstrlen(char *p)
   632  {
   633  	return strlen(p);
   634  }
   635  
   636  // xexit exits the process with return code n.
   637  void
   638  xexit(int n)
   639  {
   640  	char buf[32];
   641  
   642  	snprintf(buf, sizeof buf, "%d", n);
   643  	exits(buf);
   644  }
   645  
   646  // xatexit schedules the exit-handler f to be run when the program exits.
   647  void
   648  xatexit(void (*f)(void))
   649  {
   650  	atexit(f);
   651  }
   652  
   653  // xprintf prints a message to standard output.
   654  void
   655  xprintf(char *fmt, ...)
   656  {
   657  	va_list arg;
   658  	
   659  	va_start(arg, fmt);
   660  	vprintf(fmt, arg);
   661  	va_end(arg);
   662  }
   663  
   664  // errprintf prints a message to standard output.
   665  void
   666  errprintf(char *fmt, ...)
   667  {
   668  	va_list arg;
   669  	
   670  	va_start(arg, fmt);
   671  	vfprintf(stderr, fmt, arg);
   672  	va_end(arg);
   673  }
   674  
   675  // xsetenv sets the environment variable $name to the given value.
   676  void
   677  xsetenv(char *name, char *value)
   678  {
   679  	putenv(name, value);
   680  }
   681  
   682  // main takes care of OS-specific startup and dispatches to xmain.
   683  void
   684  main(int argc, char **argv)
   685  {
   686  	Buf b;
   687  
   688  	setvbuf(stdout, nil, _IOLBF, BUFSIZ);
   689  	setvbuf(stderr, nil, _IOLBF, BUFSIZ);
   690  
   691  	binit(&b);
   692  
   693  	rfork(RFENVG);
   694  
   695  	slash = "/";
   696  	gohostos = "plan9";
   697  
   698  	xgetenv(&b, "objtype");
   699  	if(b.len == 0)
   700  		fatal("$objtype is unset");
   701  	gohostarch = btake(&b);
   702  
   703  	srand(time(0)+getpid());
   704  	init();
   705  	xmain(argc, argv);
   706  
   707  	bfree(&b);
   708  	exits(nil);
   709  }
   710  
   711  // xqsort is a wrapper for the C standard qsort.
   712  void
   713  xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*))
   714  {
   715  	qsort(data, n, elemsize, cmp);
   716  }
   717  
   718  // xstrcmp compares the NUL-terminated strings a and b.
   719  int
   720  xstrcmp(char *a, char *b)
   721  {
   722  	return strcmp(a, b);
   723  }
   724  
   725  // xstrstr returns a pointer to the first occurrence of b in a.
   726  char*
   727  xstrstr(char *a, char *b)
   728  {
   729  	return strstr(a, b);
   730  }
   731  
   732  // xstrrchr returns a pointer to the final occurrence of c in p.
   733  char*
   734  xstrrchr(char *p, int c)
   735  {
   736  	return strrchr(p, c);
   737  }
   738  
   739  // xsamefile reports whether f1 and f2 are the same file (or dir)
   740  int
   741  xsamefile(char *f1, char *f2)
   742  {
   743  	return streq(f1, f2); // suffice for now
   744  }
   745  
   746  // xtryexecfunc tries to execute function f, if any illegal instruction
   747  // signal received in the course of executing that function, it will
   748  // return 0, otherwise it will return 1.
   749  int
   750  xtryexecfunc(void (*f)(void))
   751  {
   752  	USED(f);
   753  	return 0; // suffice for now
   754  }
   755  
   756  bool
   757  cansse2(void)
   758  {
   759  	// if we had access to cpuid, could answer this question
   760  	// less conservatively.
   761  	return 0;
   762  }
   763  
   764  #endif // PLAN9