github.com/yanyiwu/go@v0.0.0-20150106053140-03d6637dbb7f/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  	va_list arg;
   508  	
   509  	fflush(stdout);
   510  	fprintf(stderr, "go tool dist: ");
   511  	va_start(arg, msg);
   512  	vfprintf(stderr, msg, arg);
   513  	va_end(arg);
   514  	fprintf(stderr, "\n");
   515  
   516  	bgwait();
   517  	exits(msg);
   518  }
   519  
   520  // xmalloc returns a newly allocated zeroed block of n bytes of memory.
   521  // It calls fatal if it runs out of memory.
   522  void*
   523  xmalloc(int n)
   524  {
   525  	void *p;
   526  	
   527  	p = malloc(n);
   528  	if(p == nil)
   529  		fatal("out of memory");
   530  	memset(p, 0, n);
   531  	return p;
   532  }
   533  
   534  // xstrdup returns a newly allocated copy of p.
   535  // It calls fatal if it runs out of memory.
   536  char*
   537  xstrdup(char *p)
   538  {
   539  	p = strdup(p);
   540  	if(p == nil)
   541  		fatal("out of memory");
   542  	return p;
   543  }
   544  
   545  // xrealloc grows the allocation p to n bytes and
   546  // returns the new (possibly moved) pointer.
   547  // It calls fatal if it runs out of memory.
   548  void*
   549  xrealloc(void *p, int n)
   550  {
   551  	p = realloc(p, n);
   552  	if(p == nil)
   553  		fatal("out of memory");
   554  	return p;
   555  }
   556  
   557  // xfree frees the result returned by xmalloc, xstrdup, or xrealloc.
   558  void
   559  xfree(void *p)
   560  {
   561  	free(p);
   562  }
   563  
   564  // hassuffix reports whether p ends with suffix.
   565  bool
   566  hassuffix(char *p, char *suffix)
   567  {
   568  	int np, ns;
   569  
   570  	np = strlen(p);
   571  	ns = strlen(suffix);
   572  	return np >= ns && streq(p+np-ns, suffix);
   573  }
   574  
   575  // hasprefix reports whether p begins with prefix.
   576  bool
   577  hasprefix(char *p, char *prefix)
   578  {
   579  	return strncmp(p, prefix, strlen(prefix)) == 0;
   580  }
   581  
   582  // contains reports whether sep appears in p.
   583  bool
   584  contains(char *p, char *sep)
   585  {
   586  	return strstr(p, sep) != nil;
   587  }
   588  
   589  // streq reports whether p and q are the same string.
   590  bool
   591  streq(char *p, char *q)
   592  {
   593  	return strcmp(p, q) == 0;
   594  }
   595  
   596  // lastelem returns the final path element in p.
   597  char*
   598  lastelem(char *p)
   599  {
   600  	char *out;
   601  
   602  	out = p;
   603  	for(; *p; p++)
   604  		if(*p == '/')
   605  			out = p+1;
   606  	return out;
   607  }
   608  
   609  // xmemmove copies n bytes from src to dst.
   610  void
   611  xmemmove(void *dst, void *src, int n)
   612  {
   613  	memmove(dst, src, n);
   614  }
   615  
   616  // xmemcmp compares the n-byte regions starting at a and at b.
   617  int
   618  xmemcmp(void *a, void *b, int n)
   619  {
   620  	return memcmp(a, b, n);
   621  }
   622  
   623  // xstrlen returns the length of the NUL-terminated string at p.
   624  int
   625  xstrlen(char *p)
   626  {
   627  	return strlen(p);
   628  }
   629  
   630  // xexit exits the process with return code n.
   631  void
   632  xexit(int n)
   633  {
   634  	char buf[32];
   635  
   636  	snprintf(buf, sizeof buf, "%d", n);
   637  	exits(buf);
   638  }
   639  
   640  // xatexit schedules the exit-handler f to be run when the program exits.
   641  void
   642  xatexit(void (*f)(void))
   643  {
   644  	atexit(f);
   645  }
   646  
   647  // xprintf prints a message to standard output.
   648  void
   649  xprintf(char *fmt, ...)
   650  {
   651  	va_list arg;
   652  	
   653  	va_start(arg, fmt);
   654  	vprintf(fmt, arg);
   655  	va_end(arg);
   656  }
   657  
   658  // errprintf prints a message to standard output.
   659  void
   660  errprintf(char *fmt, ...)
   661  {
   662  	va_list arg;
   663  	
   664  	va_start(arg, fmt);
   665  	vfprintf(stderr, fmt, arg);
   666  	va_end(arg);
   667  }
   668  
   669  // xsetenv sets the environment variable $name to the given value.
   670  void
   671  xsetenv(char *name, char *value)
   672  {
   673  	putenv(name, value);
   674  }
   675  
   676  // main takes care of OS-specific startup and dispatches to xmain.
   677  void
   678  main(int argc, char **argv)
   679  {
   680  	Buf b;
   681  
   682  	setvbuf(stdout, nil, _IOLBF, BUFSIZ);
   683  	setvbuf(stderr, nil, _IOLBF, BUFSIZ);
   684  
   685  	binit(&b);
   686  
   687  	rfork(RFENVG);
   688  
   689  	slash = "/";
   690  	gohostos = "plan9";
   691  
   692  	xgetenv(&b, "objtype");
   693  	if(b.len == 0)
   694  		fatal("$objtype is unset");
   695  	gohostarch = btake(&b);
   696  
   697  	srand(time(0)+getpid());
   698  	init();
   699  	xmain(argc, argv);
   700  
   701  	bfree(&b);
   702  	exits(nil);
   703  }
   704  
   705  // xqsort is a wrapper for the C standard qsort.
   706  void
   707  xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*))
   708  {
   709  	qsort(data, n, elemsize, cmp);
   710  }
   711  
   712  // xstrcmp compares the NUL-terminated strings a and b.
   713  int
   714  xstrcmp(char *a, char *b)
   715  {
   716  	return strcmp(a, b);
   717  }
   718  
   719  // xstrstr returns a pointer to the first occurrence of b in a.
   720  char*
   721  xstrstr(char *a, char *b)
   722  {
   723  	return strstr(a, b);
   724  }
   725  
   726  // xstrrchr returns a pointer to the final occurrence of c in p.
   727  char*
   728  xstrrchr(char *p, int c)
   729  {
   730  	return strrchr(p, c);
   731  }
   732  
   733  // xsamefile reports whether f1 and f2 are the same file (or dir)
   734  int
   735  xsamefile(char *f1, char *f2)
   736  {
   737  	return streq(f1, f2); // suffice for now
   738  }
   739  
   740  // xtryexecfunc tries to execute function f, if any illegal instruction
   741  // signal received in the course of executing that function, it will
   742  // return 0, otherwise it will return 1.
   743  int
   744  xtryexecfunc(void (*f)(void))
   745  {
   746  	USED(f);
   747  	return 0; // suffice for now
   748  }
   749  
   750  bool
   751  cansse2(void)
   752  {
   753  	// if we had access to cpuid, could answer this question
   754  	// less conservatively.
   755  	return 0;
   756  }
   757  
   758  #endif // PLAN9