3315e8b3 |
1 | /* -*-c-*- |
2 | * |
bdba26c6 |
3 | * $Id: sw_build.c,v 1.4 1999/09/16 12:53:46 mdw Exp $ |
3315e8b3 |
4 | * |
5 | * Management of build processes |
6 | * |
7 | * (c) 1999 EBI |
8 | */ |
9 | |
10 | /*----- Licensing notice --------------------------------------------------* |
11 | * |
12 | * This file is part of sw-tools. |
13 | * |
14 | * sw-tools is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by |
16 | * the Free Software Foundation; either version 2 of the License, or |
17 | * (at your option) any later version. |
18 | * |
19 | * sw-tools is distributed in the hope that it will be useful, |
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22 | * GNU General Public License for more details. |
23 | * |
24 | * You should have received a copy of the GNU General Public License |
25 | * along with sw-tools; if not, write to the Free Software Foundation, |
26 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
27 | */ |
28 | |
29 | /*----- Revision history --------------------------------------------------* |
30 | * |
31 | * $Log: sw_build.c,v $ |
bdba26c6 |
32 | * Revision 1.4 1999/09/16 12:53:46 mdw |
33 | * Some systems have uname(2) return > 0. |
34 | * |
1efab4fe |
35 | * Revision 1.3 1999/09/10 15:27:33 mdw |
36 | * Include `%'-escape substitution. |
37 | * |
5636c0ce |
38 | * Revision 1.2 1999/07/16 12:50:24 mdw |
39 | * Improve exit status display. New interface from `doto' project. |
40 | * |
41 | * Revision 1.1.1.1 1999/06/02 16:53:34 mdw |
42 | * Initial import. |
3315e8b3 |
43 | * |
44 | */ |
45 | |
46 | /*----- Header files ------------------------------------------------------*/ |
47 | |
48 | #include "config.h" |
49 | |
50 | #include <ctype.h> |
51 | #include <errno.h> |
52 | #include <signal.h> |
53 | #include <stdarg.h> |
54 | #include <stdio.h> |
55 | #include <stdlib.h> |
56 | #include <string.h> |
57 | |
58 | #include <sys/types.h> |
59 | #include <sys/time.h> |
60 | #include <sys/select.h> |
61 | #include <sys/stat.h> |
62 | #include <unistd.h> |
63 | #include <fcntl.h> |
64 | #include <sys/wait.h> |
1efab4fe |
65 | #include <sys/utsname.h> |
3315e8b3 |
66 | |
67 | #ifndef DECL_ENVIRON |
68 | extern char **environ; |
69 | #endif |
70 | |
71 | #include <mLib/alloc.h> |
72 | #include <mLib/dstr.h> |
73 | #include <mLib/exc.h> |
74 | #include <mLib/quis.h> |
75 | #include <mLib/report.h> |
76 | |
77 | #include "sw.h" |
78 | #include "sw_arch.h" |
79 | #include "sw_build.h" |
80 | #include "sw_info.h" |
81 | #include "sw_rsh.h" |
82 | |
83 | #define PRES_LINK 0 |
84 | #define PRES_DEFAULT 0 |
85 | #define PRES_PREFERENCE 0 |
86 | #include "pres_plain.h" |
87 | #include "pres_curses.h" |
88 | |
89 | /*----- Data structures ---------------------------------------------------*/ |
90 | |
91 | /*----- Static variables --------------------------------------------------*/ |
92 | |
93 | static pres *preslist = PRES_LINK; |
94 | |
95 | /*----- Main code ---------------------------------------------------------*/ |
96 | |
97 | /* --- @swbuild_archlist@ --- * |
98 | * |
99 | * Arguments: @swinfo *sw@ = pointer to the build information block |
100 | * |
101 | * Returns: A list of architectures which are to be built. |
102 | * |
103 | * Use: Decides which architectures need building, and returns them |
104 | * in a list. |
105 | */ |
106 | |
107 | archcons *swbuild_archlist(swinfo *sw) |
108 | { |
109 | archcons *a = arch_readtab(); |
110 | const char *only = 0; |
111 | unsigned and = 0, xor = 0; |
112 | |
113 | /* --- Restrict the architecture list appropriately --- */ |
114 | |
115 | only = opt_arch ? opt_arch : sw->only_arch; |
116 | |
117 | /* --- Apply the built flags --- */ |
118 | |
119 | if (!(opt_flags & optFlag_force) && sw->arch) { |
120 | archcons *aa = arch_filter(a, sw->arch, 0, 0); |
121 | archcons *c; |
122 | for (c = aa; c; c = c->cdr) |
123 | c->car->flags |= archFlag_built; |
124 | arch_free(aa); |
125 | and |= archFlag_built; |
126 | } |
127 | |
128 | return (arch_filter(a, only, and, xor)); |
129 | } |
130 | |
131 | /*----- Main build command ------------------------------------------------*/ |
132 | |
133 | /* --- @sw_run@ --- * |
134 | * |
135 | * Arguments: @int argc@ = number of command line arguments |
136 | * @char *argv[]@ = array of command line arguments |
137 | * |
138 | * Returns: Zero on success (all builds OK) or nonzero for failure. |
139 | * |
140 | * Use: Runs a multi-architecture build. |
141 | */ |
142 | |
143 | int sw_run(int argc, char *argv[]) |
144 | { |
145 | swinfo sw; |
146 | archcons *a; |
147 | pres *p = PRES_DEFAULT; |
148 | fd_set fdin; |
149 | int active = 0; |
150 | int maxfd = 0; |
151 | int rc = 0; |
152 | |
153 | /* --- Handle help on output styles --- */ |
154 | |
155 | if (opt_output && strcmp(opt_output, "help") == 0) { |
156 | printf("Presentation styles supported:"); |
157 | for (p = preslist; p; p = p->next) |
158 | printf(" %s", p->name); |
159 | putc('\n', stdout); |
160 | printf("The default presentation style is %s\n", (PRES_DEFAULT)->name); |
161 | exit(0); |
162 | } |
163 | |
164 | /* --- Validate arguments --- */ |
165 | |
166 | if (!argv[1]) |
167 | die(1, "Usage: run COMMAND [ARG...]"); |
168 | |
169 | /* --- Choose an output presentation style --- */ |
170 | |
171 | if (opt_output) { |
172 | pres *q; |
173 | size_t sz = strlen(opt_output); |
174 | p = 0; |
175 | |
176 | for (q = preslist; q; q = q->next) { |
177 | if (strncmp(opt_output, q->name, sz) == 0) { |
178 | if (q->name[sz] == 0) { |
179 | p = q; |
180 | break; |
181 | } else if (p) |
182 | die(1, "ambiguous output style `%s'", opt_output); |
183 | else |
184 | p = q; |
185 | } |
186 | } |
187 | |
188 | if (!p) |
189 | die(1, "unknown output style `%s'", opt_output); |
190 | } |
191 | |
192 | if (p->ok && !p->ok()) { |
193 | moan("output style `%s' can't run; using `plain' instead", p->name); |
194 | p = &pres_plain; |
195 | } |
196 | |
197 | /* --- Decide on an architecture --- */ |
198 | |
199 | if (swinfo_fetch(&sw)) { |
200 | die(1, "couldn't read build status: %s (try running setup)", |
201 | strerror(errno)); |
202 | } |
203 | swinfo_sanity(&sw); |
204 | a = swbuild_archlist(&sw); |
205 | |
206 | if (!a) { |
207 | moan("All desired architectures already built OK."); |
208 | moan("(Perhaps you forgot `--force', or want to say `%s reset'.)", QUIS); |
209 | return (0); |
210 | } |
211 | |
212 | /* --- Tie on remote context blocks, and crank up the presentation --- */ |
213 | |
214 | { |
215 | archcons *aa; |
216 | |
217 | for (aa = a; aa; aa = aa->cdr) |
218 | aa->car->r = xmalloc(sizeof(sw_remote)); |
219 | if (p->init && p->init(a)) |
220 | die(1, "presentation style refused to start: %s", strerror(errno)); |
221 | } |
222 | |
223 | signal(SIGINT, SIG_IGN); |
224 | signal(SIGQUIT, SIG_IGN); |
225 | |
226 | /* --- Trap any exceptions coming this way --- * |
227 | * |
228 | * It's important, for example, that a curses-based presentation system |
229 | * reset the terminal flags appropriately. |
230 | */ |
231 | |
232 | TRY { |
233 | /* --- Run remote build processes on the remote hosts --- */ |
234 | |
235 | { |
236 | archcons *aa; |
1efab4fe |
237 | dstr d = DSTR_INIT; |
238 | char **av; |
239 | struct utsname u; |
240 | |
241 | /* --- Fill in the hostname --- */ |
242 | |
bdba26c6 |
243 | if (uname(&u) < 0) |
1efab4fe |
244 | strcpy(u.nodename, "<unknown>"); |
245 | |
246 | /* --- If necessary, set up the output @argv@ array --- */ |
247 | |
248 | if (opt_flags & optFlag_percent) |
249 | av = xmalloc(argc * sizeof(char *)); |
250 | else |
251 | av = argv + 1; |
252 | |
253 | /* --- Run through the target build hosts --- */ |
3315e8b3 |
254 | |
255 | FD_ZERO(&fdin); |
256 | for (aa = a; aa; aa = aa->cdr) { |
257 | archent *e = aa->car; |
258 | sw_remote *r = e->r; |
1efab4fe |
259 | |
260 | /* --- If necessary, translate `%'-escapes --- */ |
261 | |
262 | if (opt_flags & optFlag_percent) { |
263 | char **pp, **qq; |
264 | |
265 | for (pp = argv + 1, qq = av; *pp; pp++, qq++) { |
266 | if (strchr(*pp, '%') == 0) |
267 | *qq = *pp; |
268 | else { |
269 | char *p; |
270 | char *q = *pp; |
271 | for (p = *pp; *p; p++) { |
272 | if (*p == '%') { |
273 | DPUTM(&d, q, p - q); |
274 | p++; |
275 | switch (*p) { |
276 | case 0: |
277 | DPUTC(&d, '%'); |
278 | goto done_arg; |
279 | case '%': |
280 | DPUTC(&d, '%'); |
281 | break; |
282 | case 'a': |
283 | dstr_puts(&d, e->arch); |
284 | break; |
285 | case 'h': |
286 | dstr_puts(&d, e->flags & archFlag_home ? |
287 | u.nodename : e->host); |
288 | break; |
289 | case 'P': |
290 | dstr_puts(&d, PREFIX); |
291 | break; |
292 | case 'p': |
293 | dstr_puts(&d, sw.package); |
294 | break; |
295 | case 'v': |
296 | dstr_puts(&d, sw.version); |
297 | break; |
298 | case 'u': |
299 | dstr_puts(&d, sw.maintainer); |
300 | break; |
301 | default: |
302 | DPUTC(&d, '%'); |
303 | DPUTC(&d, *p); |
304 | break; |
305 | } |
306 | q = p + 1; |
307 | } |
308 | } |
309 | DPUTM(&d, q, p - q); |
310 | done_arg: |
311 | DPUTZ(&d); |
312 | *qq = xstrdup(d.buf); |
313 | DRESET(&d); |
314 | } |
315 | } |
316 | *qq++ = 0; |
317 | } |
318 | |
319 | /* --- Start a new process off --- */ |
320 | |
3315e8b3 |
321 | if (swrsh(r, e->flags & archFlag_home ? 0 : e->host, |
1efab4fe |
322 | "build", av)) { |
3315e8b3 |
323 | dstr d = DSTR_INIT; |
324 | dstr_putf(&d, "%s: couldn't start build for architecture `%s': %s", |
325 | QUIS, e->arch, strerror(errno)); |
326 | p->output(e, d.buf, d.len); |
327 | free(r); |
328 | e->r = 0; |
329 | dstr_destroy(&d); |
330 | } else { |
331 | int fd = r->fdin; |
332 | if (fd > maxfd) |
333 | maxfd = fd; |
334 | active++; |
335 | FD_SET(fd, &fdin); |
336 | } |
1efab4fe |
337 | |
338 | /* --- Free up the argument array --- */ |
339 | |
340 | if (opt_flags & optFlag_percent) { |
341 | char **pp, **qq; |
342 | |
343 | for (pp = argv + 1, qq = av; *pp; pp++, qq++) { |
344 | if (*pp != *qq) |
345 | free(*qq); |
346 | } |
347 | } |
3315e8b3 |
348 | } |
1efab4fe |
349 | |
350 | if (opt_flags & optFlag_percent) |
351 | free(av); |
3315e8b3 |
352 | } |
353 | |
354 | /* --- Watch the builds until they do something interesting --- */ |
355 | |
356 | maxfd++; |
357 | while (active) { |
358 | fd_set f; |
359 | int n; |
360 | archcons *aa; |
361 | |
362 | /* --- Find out what interesting things are happening --- */ |
363 | |
364 | memcpy(&f, &fdin, sizeof(f)); |
365 | n = select(maxfd, &f, 0, 0, 0); |
366 | if (n < 0) { |
367 | if (errno == EINTR || errno == EAGAIN) |
368 | continue; |
369 | else |
370 | THROW(EXC_ERRNO, errno); |
371 | } |
372 | |
373 | /* --- Scan through for jobs which need attention --- */ |
374 | |
375 | for (aa = a; aa; aa = aa->cdr) { |
376 | archent *e = aa->car; |
377 | sw_remote *r = e->r; |
378 | int t; |
379 | |
380 | if (!FD_ISSET(r->fdin, &f)) |
381 | continue; |
382 | |
383 | switch (t = pkrecv(r)) { |
384 | |
385 | case PKTYPE_DATA: |
386 | p->output(e, r->buf, r->sz); |
387 | break; |
388 | |
389 | case PKTYPE_STATUS: { |
390 | dstr d = DSTR_INIT; |
391 | int ok = 1; |
392 | if (r->sz != 1) { |
393 | r->buf[r->sz] = 0; |
5636c0ce |
394 | dstr_putf(&d, "failed (%s)", r->buf); |
3315e8b3 |
395 | ok = 0; |
396 | rc = 1; |
397 | } else if (r->buf[0]) { |
5636c0ce |
398 | dstr_putf(&d, "failed (status %u)", (unsigned char)r->buf[0]); |
3315e8b3 |
399 | ok = 0; |
400 | rc = 1; |
5636c0ce |
401 | } else { |
402 | dstr_puts(&d, "finished"); |
403 | if (opt_flags & optFlag_install) |
404 | e->flags |= archFlag_built; |
405 | } |
3315e8b3 |
406 | if (p->close) |
5636c0ce |
407 | p->close(e, ok, d.buf); |
408 | dstr_destroy(&d); |
3315e8b3 |
409 | FD_CLR(r->fdin, &fdin); |
410 | close(r->fdin); |
411 | active--; |
412 | } break; |
413 | |
414 | case PKTYPE_EOF: { |
3315e8b3 |
415 | if (p->close) |
5636c0ce |
416 | p->close(e, 0, "unexpected exit"); |
3315e8b3 |
417 | rc = 1; |
418 | FD_CLR(r->fdin, &fdin); |
419 | close(r->fdin); |
420 | active--; |
421 | } break; |
422 | |
423 | default: { |
424 | const static char msg[] = "\n[Unexpected packet, type %i]\n"; |
425 | p->output(e, msg, sizeof(msg) - 1); |
426 | } break; |
427 | } |
428 | } |
429 | } |
430 | } |
431 | |
432 | /* --- Handle any exceptions coming this way --- * |
433 | * |
434 | * I could do more cleanup here (freeing buffers and so) but it's not worth |
435 | * it. Nobody's bothering to catch exceptions anyway. |
436 | */ |
437 | |
438 | CATCH { |
439 | if (p->abort) |
440 | p->abort(a); |
441 | switch (exc_type) { |
442 | case EXC_ERRNO: |
5636c0ce |
443 | die(1, "unexpected error: %s", strerror(exc_i)); |
3315e8b3 |
444 | break; |
445 | default: |
446 | RETHROW; |
447 | break; |
448 | } |
449 | } END_TRY; |
450 | |
451 | /* --- Tell the presentation that everything's done --- */ |
452 | |
453 | if (p->done) |
454 | p->done(a); |
455 | else if (opt_flags & optFlag_beep) |
456 | putchar('\a'); |
457 | |
458 | /* --- Clean up the unwanted remote contexts --- */ |
459 | |
460 | { |
461 | archcons *aa; |
462 | for (aa = a; aa; aa = aa->cdr) |
463 | free(a->car->r); |
464 | } |
465 | |
466 | /* --- Tidy away the architecture list --- */ |
467 | |
468 | arch_free(a); |
469 | |
470 | /* --- Mark built architectures as having been completed now --- */ |
471 | |
472 | if (opt_flags & optFlag_install) { |
473 | swinfo skel; |
474 | dstr d = DSTR_INIT; |
475 | swinfo_clear(&skel); |
476 | arch_toText(&d, arch_readtab(), archFlag_built, archFlag_built); |
477 | skel.arch = d.buf; |
478 | swinfo_update(&sw, &skel); |
479 | dstr_destroy(&d); |
480 | if (swinfo_put(&sw)) |
481 | die(1, "error writing build status: %s", strerror(errno)); |
482 | } |
483 | return (rc); |
484 | } |
485 | |
486 | /*----- Main remote entry point -------------------------------------------*/ |
487 | |
488 | /* --- @putf@ --- * |
489 | * |
490 | * Arguments: @sw_remote *r@ = pointer to remote context |
491 | * @FILE *fp@ = log file handle |
492 | * @const char *fmt@ = format string |
493 | * @...@ = other arguments |
494 | * |
495 | * Returns: --- |
496 | * |
497 | * Use: Reports a string to the log file and the remote controller |
498 | * process. |
499 | */ |
500 | |
501 | static void putf(sw_remote *r, FILE *fp, const char *fmt, ...) |
502 | { |
503 | va_list ap; |
504 | dstr d = DSTR_INIT; |
505 | va_start(ap, fmt); |
506 | dstr_vputf(&d, fmt, ap); |
507 | va_end(ap); |
508 | if (r) |
509 | pksend(r, PKTYPE_DATA, d.buf, d.len); |
510 | if (fp) |
511 | fwrite(d.buf, 1, d.len, fp); |
512 | dstr_destroy(&d); |
513 | } |
514 | |
515 | /* --- @swrsh_build@ --- * |
516 | * |
517 | * Arguments: @sw_remote *r@ = pointer to remote context |
518 | * @char *argv[]@ = pointer to argument list |
519 | * @char *env[]@ = pointer to environment list |
520 | * |
521 | * Returns: Doesn't. |
522 | * |
523 | * Use: Runs a remote build command. |
524 | */ |
525 | |
526 | void swrsh_build(sw_remote *r, char *argv[], char *env[]) |
527 | { |
528 | FILE *logfp; |
529 | int fd[2]; |
530 | pid_t kid; |
531 | |
1efab4fe |
532 | /* --- Validate the arguments --- */ |
3315e8b3 |
533 | |
534 | if (!argv[0]) |
535 | swdie(r, 1, "Usage: build COMMAND [ARG...]"); |
536 | |
537 | /* --- Change into architecture directory --- */ |
538 | |
539 | if (mkdir(ARCH, 0775) && errno != EEXIST) |
540 | swdie(r, 1, "mkdir(`%s') failed: %s", ARCH, strerror(errno)); |
541 | if (chdir(ARCH)) { |
542 | swdie(r, 1, "couldn't change directory to `%s': %s", |
543 | ARCH, strerror(errno)); |
544 | } |
545 | if (pipe(fd)) |
546 | swdie(r, 1, "couldn't create pipe: %s", strerror(errno)); |
547 | |
548 | /* --- Open the log file --- */ |
549 | |
550 | { |
551 | int logfd = open(".build-log", O_WRONLY | O_APPEND | O_CREAT, 0664); |
552 | time_t t; |
553 | struct tm *tm; |
554 | char buf[64]; |
555 | char **p; |
1efab4fe |
556 | struct utsname u; |
3315e8b3 |
557 | |
bdba26c6 |
558 | if (uname(&u) < 0) |
1efab4fe |
559 | swdie(r, 1, "couldn't get hostname: %s", strerror(errno)); |
3315e8b3 |
560 | if (logfd < 0) |
561 | swdie(r, 1, "couldn't open `.build-log' file: %s", strerror(errno)); |
562 | if ((logfp = fdopen(logfd, "a")) == 0) { |
563 | swdie(r, 1, "couldn't open stream on `.build-log' file: %s", |
564 | strerror(errno)); |
565 | } |
566 | t = time(0); |
567 | tm = localtime(&t); |
568 | strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm); |
1efab4fe |
569 | fprintf(logfp, "\n\n*** %s: %s started build: %s", |
570 | buf, u.nodename, argv[0]); |
3315e8b3 |
571 | for (p = argv + 1; *p; p++) |
572 | fprintf(logfp, " %s", *p); |
573 | fputs("\n\n", logfp); |
574 | } |
575 | |
576 | /* --- Start off the child process --- */ |
577 | |
578 | kid = fork(); |
579 | if (kid == 0) { |
580 | int nullfd; |
581 | close(fd[0]); |
582 | dup2(fd[1], 1); |
583 | dup2(fd[1], 2); |
584 | if (fd[1] > 2) |
585 | close(fd[1]); |
586 | close(0); |
587 | nullfd = open("/dev/null", O_RDONLY); |
588 | if (nullfd > 0) { |
589 | dup2(nullfd, 0); |
590 | close(nullfd); |
591 | } |
592 | environ = env; |
593 | execvp(argv[0], argv); |
594 | fprintf(stderr, "failed to start `%s': %s\n", argv[0], strerror(errno)); |
595 | _exit(127); |
596 | } |
597 | |
598 | /* --- Read from the pipe, and write to the socket and logfile --- */ |
599 | |
600 | close(fd[1]); |
601 | for (;;) { |
602 | ssize_t n = read(fd[0], r->buf, PKMAX); |
603 | if (!n) |
604 | break; |
605 | if (n < 0) { |
1efab4fe |
606 | putf(r, logfp, "\n*** error reading from pipe: %s\n", strerror(errno)); |
3315e8b3 |
607 | kill(kid, SIGTERM); |
608 | break; |
609 | } |
610 | fwrite(r->buf, 1, n, logfp); |
611 | pksend(r, PKTYPE_DATA, r->buf, n); |
612 | } |
613 | close(fd[0]); |
614 | |
615 | /* --- Reap exit status and produce final report --- */ |
616 | |
617 | { |
618 | int status; |
1efab4fe |
619 | if (waitpid(kid, &status, 0) < 0) { |
620 | putf(r, logfp, "\n*** error reading exit status: %s\n", |
621 | strerror(errno)); |
622 | } else { |
3315e8b3 |
623 | if (WIFSIGNALED(status)) |
1efab4fe |
624 | fprintf(logfp, "\n*** exited on signal %i\n", WTERMSIG(status)); |
3315e8b3 |
625 | else if (WIFEXITED(status)) |
1efab4fe |
626 | fprintf(logfp, "\n*** exited with status %i\n", WEXITSTATUS(status)); |
3315e8b3 |
627 | else |
1efab4fe |
628 | fprintf(logfp, "\n*** reaped, but didn't exit. Strange\n"); |
3315e8b3 |
629 | } |
630 | fclose(logfp); |
631 | swwait(r, status); |
632 | } |
633 | } |
634 | |
635 | /*----- Syntactic sugar ---------------------------------------------------*/ |
636 | |
637 | /* |
638 | * `Syntactic sugar causes cancer of the semicolon.' |
639 | * -- Alan Perlis, `Epigrams in Programming' |
640 | */ |
641 | |
642 | /* --- @build@ --- * |
643 | * |
644 | * Arguments: @char **u@ = first segment |
645 | * @char **v@ = second segment |
646 | * |
647 | * Returns: Return code from the build. |
648 | * |
649 | * Use: Combines two @argv@-style arrays and then runs a build on the |
650 | * result. |
651 | */ |
652 | |
653 | static int build(char **u, char **v) |
654 | { |
655 | size_t i, j; |
656 | char **p; |
657 | |
658 | for (i = 0, p = u; *p; p++, i++) ; |
659 | for (j = 0, p = v; *p; p++, j++) ; |
660 | p = xmalloc((i + j + 2) * sizeof(char **)); |
661 | memcpy(p + 1, u, i * sizeof(char **)); |
662 | memcpy(p + i + 1, v, j * sizeof(char **)); |
663 | p[0] = p[i + j + 1] = 0; |
664 | return (sw_run(i + j + 1, p)); |
665 | } |
666 | |
667 | /* --- @sw_make@ --- */ |
668 | |
669 | int sw_make(int argc, char *argv[]) |
670 | { |
671 | static char *mk[] = { 0, 0 }; |
672 | if (!mk[0]) { |
673 | char *m; |
674 | if ((m = getenv("SW_MAKE")) == 0 && |
675 | (m = getenv("MAKE")) == 0) |
676 | m = "make"; |
677 | mk[0] = m; |
678 | } |
679 | return (build(mk, argv + 1)); |
680 | } |
681 | |
682 | /* --- @sw_conf@ --- */ |
683 | |
684 | int sw_conf(int argc, char *argv[]) |
685 | { |
686 | static char *cf[] = { "../configure", "--prefix=" PREFIX, 0 }; |
687 | return (build(cf, argv + 1)); |
688 | } |
689 | |
690 | /*----- Other subcommands -------------------------------------------------*/ |
691 | |
692 | /* --- @sw_reset@ --- */ |
693 | |
694 | int sw_reset(int argc, char *argv[]) |
695 | { |
696 | swinfo sw, skel; |
697 | if (argc != 1) |
698 | die(1, "Usage: reset"); |
699 | if (swinfo_fetch(&sw)) { |
700 | die(1, "couldn't read build status: %s (try running setup)", |
701 | strerror(errno)); |
702 | } |
703 | swinfo_sanity(&sw); |
704 | swinfo_clear(&skel); |
705 | skel.arch = ""; |
706 | swinfo_update(&sw, &skel); |
707 | if (swinfo_put(&sw)) |
708 | die(1, "couldn't write build status: %s", strerror(errno)); |
709 | return (0); |
710 | } |
711 | |
712 | /*----- That's all, folks -------------------------------------------------*/ |