Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(732)

Side by Side Diff: src/cmd/dist/unix.c

Issue 5620045: code review 5620045: cmd/dist: new command (Closed)
Patch Set: diff -r f79343c8a479 https://go.googlecode.com/hg/ Created 13 years, 2 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 <fcntl.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <errno.h>
24 #include <stdarg.h>
25
26 // breadfrom appends to b all the data that can be read from fd.
27 static void
28 breadfrom(Buf *b, int fd)
29 {
30 int n;
31
32 for(;;) {
33 bgrow(b, 4096);
34 n = read(fd, b->p+b->len, 4096);
35 if(n <= 0)
bradfitz 2012/02/02 00:53:11 be fatal on non-EOF errors?
36 break;
37 b->len += n;
38 }
39 }
40
41 // xgetenv replaces b with the value of the named environment variable.
42 void
43 xgetenv(Buf *b, char *name)
44 {
45 char *p;
46 ········
47 breset(b);
48 p = getenv(name);
49 if(p != NULL)
50 bwritestr(b, p);
51 }
52
53 // run runs the command named by cmd.
54 // If b is not nil, run replaces b with the output of the command.
55 // If dir is not nil, run runs the command in that directory.
56 // If mode is CheckExit, run calls fatal if the command is not successful.
57 void
58 run(Buf *b, char *dir, int mode, char *cmd, ...)
59 {
60 va_list arg;
61 Vec argv;
62 char *p;
63 ········
64 vinit(&argv);
65 vadd(&argv, cmd);
66 va_start(arg, cmd);
67 while((p = va_arg(arg, char*)) != nil)
68 vadd(&argv, p);
69 va_end(arg);
70 ········
71 runv(b, dir, mode, &argv);
72 ········
73 vfree(&argv);
74 }
75
76
77 // runv is like run but takes a vector.
78 void
79 runv(Buf *b, char *dir, int mode, Vec *argv)
80 {
81 int i, p[2], pid, status;
82 Buf cmd;
83 char *q;
84
85 binit(&cmd);
86 for(i=0; i<argv->len; i++) {
87 if(i > 0)
88 bwritestr(&cmd, " ");
89 q = argv->p[i];
90 if(workdir != nil && hasprefix(q, workdir)) {
91 bwritestr(&cmd, "$WORK");
iant 2012/02/02 01:53:26 What is this about?
92 q += strlen(workdir);
93 }
94 bwritestr(&cmd, q);
95 }
96 printf("%s\n", bstr(&cmd));
97 bfree(&cmd);
98
99 if(b != nil) {
100 breset(b);
101 if(pipe(p) < 0)
102 fatal("pipe: %s", strerror(errno));
103 }
104
105 switch(pid = fork()) {
106 case -1:
107 fatal("fork: %s", strerror(errno));
108 case 0:
109 if(b != nil) {
110 close(0);
111 close(p[0]);
112 dup2(p[1], 1);
113 dup2(p[1], 2);
114 if(p[1] > 2)
115 close(p[1]);
116 }
117 if(dir != nil) {
118 if(chdir(dir) < 0) {
119 fprintf(stderr, "chdir %s: %s\n", dir, strerror( errno));
120 _exit(1);
121 }
122 }
123 vadd(argv, nil);
124 execvp(argv->p[0], argv->p);
125 fprintf(stderr, "exec %s: %s\n", argv->p[0], strerror(errno));
126 _exit(1);
127 }
128 if(b != nil) {
129 close(p[1]);
130 breadfrom(b, p[0]);
131 close(p[0]);
132 }
133 wait:
134 errno = 0;
135 if(waitpid(pid, &status, 0) != pid) {
136 if(errno == EINTR)
137 goto wait;
138 fatal("waitpid: %s", strerror(errno));
139 }
140 if(mode==CheckExit && (!WIFEXITED(status) || WEXITSTATUS(status) != 0)) {
141 if(b != nil)
142 fwrite(b->p, b->len, 1, stderr);
143 fatal("%s failed", argv->p[0]);
144 }
145 }
146
147 // xgetwd replaces b with the current directory.
148 void
149 xgetwd(Buf *b)
150 {
151 char buf[MAXPATHLEN];
ality 2012/02/02 17:43:21 Should this be PATH_MAX? I never know which to use
152 ········
153 breset(b);
154 if(getcwd(buf, MAXPATHLEN) == nil)
ality 2012/02/02 17:43:21 s/MAXPATHLEN/sizeof buf/
155 fatal("getcwd: %s", strerror(errno));
156 bwritestr(b, buf);······
157 }
158
159 // xrealwd replaces b with the 'real' name for the given path.
160 // real is defined as what getcwd returns in that directory.
161 void
162 xrealwd(Buf *b, char *path)
ality 2012/02/02 17:43:21 This appears to be unused.
163 {
164 int fd;
165 ········
166 fd = open(".", 0);
167 if(fd < 0)
168 fatal("open .: %s", strerror(errno));
169 if(chdir(path) < 0)
170 fatal("chdir %s: %s", path, strerror(errno));
171 xgetwd(b);
172 if(fchdir(fd) < 0)
173 fatal("fchdir: %s", strerror(errno));
174 close(fd);
175 }
176
177 // isdir reports whether p names an existing directory.
178 bool
179 isdir(char *p)
180 {
181 struct stat st;
182 ········
183 return stat(p, &st) >= 0 && S_ISDIR(st.st_mode);
184 }
185
186 // isfile reports whether p names an existing file.
187 bool
188 isfile(char *p)
189 {
190 struct stat st;
191 ········
192 return stat(p, &st) >= 0 && S_ISREG(st.st_mode);
193 }
194
195 // mtime returns the modification time of the file p.
196 Time
197 mtime(char *p)
198 {
199 struct stat st;
200 ········
201 if(stat(p, &st) < 0)
202 return 0;
203 return (Time)st.st_mtime*1000000000LL;
204 }
205
206 // isabs reports whether p is an absolute path.
207 bool
208 isabs(char *p)
209 {
210 return hasprefix(p, "/");
211 }
212
213 // readfile replaces b with the content of the named file.
214 void
215 readfile(Buf *b, char *file)
216 {
217 int fd;
218 ········
219 breset(b);
220 fd = open(file, 0);
221 if(fd < 0)
222 fatal("open %s: %s", file, strerror(errno));
223 breadfrom(b, fd);
224 close(fd);
225 }
226
227 // writefile writes b to the named file, creating it if needed.
228 void
229 writefile(Buf *b, char *file)
230 {
231 int fd;
232 ········
233 fd = creat(file, 0666);
234 if(fd < 0)
235 fatal("create %s: %s", file, strerror(errno));
236 if(write(fd, b->p, b->len) != b->len)
237 fatal("short write: %s", strerror(errno));
238 close(fd);
239 }
240 ········
241 // xmkdir creates the directory p.
242 void
243 xmkdir(char *p)
244 {
245 if(mkdir(p, 0777) < 0)
246 fatal("mkdir %s: %s", p, strerror(errno));
247 }
248
249 // xmkdirall creates the directory p and its parents, as needed.
250 void
251 xmkdirall(char *p)
252 {
253 char *q;
254
255 if(isdir(p))
256 return;
257 q = strrchr(p, '/');
258 if(q != nil) {
259 *q = '\0';
260 xmkdirall(p);
261 *q = '/';
262 }
263 xmkdir(p);
264 }
265
266 // xremove removes the file p.
267 void
268 xremove(char *p)
269 {
270 unlink(p);
271 }
272
273 // xremoveall removes the file or directory tree rooted at p.
274 void
275 xremoveall(char *p)
276 {
277 int i;
278 Buf b;
279 Vec dir;
280
281 binit(&b);
282 vinit(&dir);
283
284 if(isdir(p)) {
285 xreaddir(&dir, p);
286 for(i=0; i<dir.len; i++) {
287 bprintf(&b, "%s/%s", p, dir.p[i]);
288 xremoveall(bstr(&b));
289 }
290 rmdir(p);
291 } else {
292 unlink(p);
293 }
294 ········
295 bfree(&b);
296 vfree(&dir);····
297 }
298
299 // xreaddir replaces dst with a list of the names of the files in dir.
300 // The names are relative to dir; they are not full paths.
301 void
302 xreaddir(Vec *dst, char *dir)
303 {
304 DIR *d;
305 struct dirent *dp;
306 ········
307 vreset(dst);
308 d = opendir(dir);
309 if(d == nil)
310 fatal("opendir %s: %s", dir, strerror(errno));
311 while((dp = readdir(d)) != nil) {
312 if(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0 )
313 continue;
314 vadd(dst, dp->d_name);
315 }
316 closedir(d);
317 }
318
319 // xworkdir creates a new temporary directory to hold object files
320 // and returns the name of that directory.
321 char*
322 xworkdir(void)
323 {
324 Buf b;
325 char *p;
326 ········
327 binit(&b);
328
329 xgetenv(&b, "TMPDIR");
330 if(b.len == 0)
331 bwritestr(&b, "/var/tmp");
332 bwritestr(&b, "/go-cbuild-XXXXXX");
333 if(mkdtemp(bstr(&b)) == nil)
334 fatal("mkdtemp: %s", strerror(errno));
335 p = btake(&b);
336
337 bfree(&b);
338
339 return p;
340 }
341
342 // fatal prints an error message to standard error and exits.
343 void
344 fatal(char *msg, ...)
345 {
346 va_list arg;
347 ········
348 fprintf(stderr, "go tool dist: ");
349 va_start(arg, msg);
350 vfprintf(stderr, msg, arg);
351 va_end(arg);
352 fprintf(stderr, "\n");
353 exit(1);
354 }
355
356 // xmalloc returns a newly allocated zeroed block of n bytes of memory.
357 // It calls fatal if it runs out of memory.
358 void*
359 xmalloc(int n)
360 {
361 void *p;
362 ········
363 p = malloc(n);
364 if(p == nil)
365 fatal("out of memory");
366 memset(p, 0, n);
367 return p;
368 }
369
370 // xstrdup returns a newly allocated copy of p.
371 // It calls fatal if it runs out of memory.
372 char*
373 xstrdup(char *p)
374 {
375 p = strdup(p);
376 if(p == nil)
377 fatal("out of memory");
378 return p;
379 }
380
381 // xrealloc grows the allocation p to n bytes and
382 // returns the new (possibly moved) pointer.
383 // It calls fatal if it runs out of memory.
384 void*
385 xrealloc(void *p, int n)
386 {
387 p = realloc(p, n);
388 if(p == nil)
389 fatal("out of memory");
390 return p;
391 }
392
393 // xfree frees the result returned by xmalloc, xstrdup, or xrealloc.
394 void
395 xfree(void *p)
396 {
397 free(p);
398 }
399
400 // hassuffix reports whether p ends with suffix.
401 bool
402 hassuffix(char *p, char *suffix)
403 {
404 int np, ns;
405 ········
406 np = strlen(p);
407 ns = strlen(suffix);
408 return np >= ns && strcmp(p+np-ns, suffix) == 0;
409 }
410
411 // hasprefix reports whether p begins wtih prefix.
412 bool
413 hasprefix(char *p, char *prefix)
414 {
415 return strncmp(p, prefix, strlen(prefix)) == 0;
416 }
417
418 // contains reports whether sep appears in p.
419 bool
420 contains(char *p, char *sep)
421 {
422 return strstr(p, sep) != nil;
423 }
424
425 // streq reports whether p and q are the same string.
426 bool
427 streq(char *p, char *q)
428 {
429 return strcmp(p, q) == 0;
430 }
431
432 // lastelem returns the final path element in p.
433 char*
434 lastelem(char *p)
435 {
436 char *out;
437
438 out = p;
439 for(; *p; p++)
440 if(*p == '/')
441 out = p+1;
442 return out;
443 }
444
445 // xmemmove copies n bytes from src to dst.
446 void
447 xmemmove(void *dst, void *src, int n)
448 {
449 memmove(dst, src, n);
450 }
451
452 // xmemcmp compares the n-byte regions starting at a and at b.
453 int
454 xmemcmp(void *a, void *b, int n)
455 {
456 return memcmp(a, b, n);
457 }
458
459 // xstrlen returns the length of the NUL-terminated string at p.
460 int
461 xstrlen(char *p)
462 {
463 return strlen(p);
464 }
465
466 // xexit exits the process with return code n.
467 void
468 xexit(int n)
469 {
470 exit(n);
471 }
472
473 // xatexit schedules the exit-handler f to be run when the program exits.
474 void
475 xatexit(void (*f)(void))
476 {
477 atexit(f);
478 }
479
480 // xprintf prints a message to standard output.
481 void
482 xprintf(char *fmt, ...)
483 {
484 va_list arg;
485 ········
486 va_start(arg, fmt);
487 vprintf(fmt, arg);
488 va_end(arg);
489 }
490
491 // xsetenv sets the environment variable $name to the given value.
492 void
493 xsetenv(char *name, char *value)
494 {
495 setenv(name, value, 1);
ality 2012/02/02 17:43:21 I'm not sure if setenv is available everywhere. Yo
496 }
497
498 // main takes care of OS-specific startup and dispatches to xmain.
499 int
500 main(int argc, char **argv)
501 {
502 char *p;
503
504 p = argv[0];
505 if(hassuffix(p, "bin/go-tool/dist")) {
506 default_goroot = xstrdup(p);
507 default_goroot[strlen(p)-strlen("bin/go-tool/dist")] = '\0';
508 }
509 ········
510 slash = "/";
511
512 #if defined(__APPLE__)
513 gohostos = "darwin";
514 #elif defined(__linux__)
515 gohostos = "linux";
516 #else
ality 2012/02/02 13:07:43 This will fail on Plan 9 since the #else correspon
517 fatal("unknown operating system");
518 #endif
519 xprintf("hostos %s\n", gohostos);
iant 2012/02/02 01:53:26 Remove debug print.
520
521 init();
522 xmain(argc, argv);
523 return 0;
524 }
525
526 // xqsort is a wrapper for the C standard qsort.
527 void
528 xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*))
529 {
530 qsort(data, n, elemsize, cmp);
531 }
532
533 // xstrcmp compares the NUL-terminated strings a and b.
534 int
535 xstrcmp(char *a, char *b)
536 {
537 return strcmp(a, b);
538 }
539
540 // xstrstr returns a pointer to the first occurrence of b in a.
541 char*
542 xstrstr(char *a, char *b)
543 {
544 return strstr(a, b);
545 }
546
547 // xstrrchr returns a pointer to the FINAL occurrence of c in p.
548 char*
549 xstrrchr(char *p, int c)
550 {
551 char *ep;
552 ········
553 ep = p+strlen(p);
ality 2012/02/02 17:43:21 Duplicated initialization of ep.
554 for(ep=p+strlen(p); ep >= p; ep--)
555 if(*ep == c)
556 return ep;
557 return nil;
558 }
559
560 #endif // PLAN9
561 #endif // __WINDOWS__
OLDNEW

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b