source: trunk/minix/commands/make/make.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 18.5 KB
Line 
1/*************************************************************************
2 *
3 * m a k e : m a k e . c
4 *
5 * Do the actual making for make plus system dependent stuff
6 *========================================================================
7 * Edition history
8 *
9 * # Date Comments By
10 * --- -------- ---------------------------------------------------- ---
11 * 1 ?? ??
12 * 2 01.07.89 $<,$* bugs fixed RAL
13 * 3 23.08.89 (time_t)time((time_t*)0) bug fixed, N_EXISTS added RAL
14 * 4 30.08.89 leading sp. in cmd. output eliminated, indention ch. PSH,RAL
15 * 5 03.09.89 :: time fixed, error output -> stderr, N_ERROR intr.
16 * fixed LZ elimintaed RAL
17 * 6 07.09.89 implmacro, DF macros,debug stuff added RAL
18 * 7 09.09.89 tos support added PHH,RAL
19 * 8 17.09.89 make1 arg. fixed, N_EXEC introduced RAL
20 * ------------ Version 2.0 released ------------------------------- RAL
21 * 18.05.90 fixed -n bug with silent rules. (Now echos them.) PAN
22 *
23 *************************************************************************/
24
25#include "h.h"
26#include <sys/wait.h>
27#include <unistd.h>
28
29_PROTOTYPE(static void tellstatus, (FILE *out, char *name, int status));
30
31static bool execflag;
32
33/*
34 * Exec a shell that returns exit status correctly (/bin/esh).
35 * The standard EON shell returns the process number of the last
36 * async command, used by the debugger (ugg).
37 * [exec on eon is like a fork+exec on unix]
38 */
39int dosh(string, shell)
40char *string;
41char *shell;
42{
43 int number;
44
45#ifdef unix
46 return system(string);
47#endif
48#ifdef tos
49 return Tosexec(string);
50#endif
51#ifdef eon
52 return ((number = execl(shell, shell,"-c", string, 0)) == -1) ?
53 -1: /* couldn't start the shell */
54 wait(number); /* return its exit status */
55#endif
56#ifdef os9
57 int status, pid;
58
59 strcat(string, "\n");
60 if ((number = os9fork(shell, strlen(string), string, 0, 0, 0)) == -1)
61 return -1; /* Couldn't start a shell */
62 do {
63 if ((pid = wait(&status)) == -1)
64 return -1; /* child already died!?!? */
65 } while (pid != number);
66
67 return status;
68#endif
69}
70
71
72#ifdef unix
73/*
74 * Make a file look very outdated after an error trying to make it.
75 * Don't remove, this keeps hard links intact. (kjb)
76 */
77int makeold(name) char *name;
78{
79 struct utimbuf a;
80
81 a.actime = a.modtime = 0; /* The epoch */
82
83 return utime(name, &a);
84}
85#endif
86
87
88static void tellstatus(out, name, status)
89FILE *out;
90char *name;
91int status;
92{
93 char cwd[PATH_MAX];
94
95 fprintf(out, "%s in %s: ",
96 name, getcwd(cwd, sizeof(cwd)) == NULL ? "?" : cwd);
97
98 if (WIFEXITED(status)) {
99 fprintf(out, "Exit code %d", WEXITSTATUS(status));
100 } else {
101 fprintf(out, "Signal %d%s",
102 WTERMSIG(status), status & 0x80 ? " - core dumped" : "");
103 }
104}
105
106
107/*
108 * Do commands to make a target
109 */
110void docmds1(np, lp)
111struct name *np;
112struct line *lp;
113{
114 register char *q;
115 register char *p;
116 register struct cmd *cp;
117 bool ssilent;
118 bool signore;
119 int estat;
120 char *shell;
121
122
123 if (*(shell = getmacro("SHELL")) == '\0')
124#ifdef eon
125 shell = ":bin/esh";
126#endif
127#ifdef unix
128 shell = "/bin/sh";
129#endif
130#ifdef os9
131 shell = "shell";
132#endif
133#ifdef tos
134 shell = "DESKTOP"; /* TOS has no shell */
135#endif
136
137 for (cp = lp->l_cmd; cp; cp = cp->c_next) {
138 execflag = TRUE;
139 strcpy(str1, cp->c_cmd);
140 expmake = FALSE;
141 expand(&str1s);
142 q = str1;
143 ssilent = silent;
144 signore = ignore;
145 while ((*q == '@') || (*q == '-')) {
146 if (*q == '@') /* Specific silent */
147 ssilent = TRUE;
148 else /* Specific ignore */
149 signore = TRUE;
150 if (!domake) putchar(*q); /* Show all characters. */
151 q++; /* Not part of the command */
152 }
153
154 for (p=q; *p; p++) {
155 if (*p == '\n' && p[1] != '\0') {
156 *p = ' ';
157 if (!ssilent || !domake)
158 fputs("\\\n", stdout);
159 }
160 else if (!ssilent || !domake)
161 putchar(*p);
162 }
163 if (!ssilent || !domake)
164 putchar('\n');
165
166 if (domake || expmake) { /* Get the shell to execute it */
167 fflush(stdout);
168 if ((estat = dosh(q, shell)) != 0) {
169 if (estat == -1)
170 fatal("Couldn't execute %s", shell,0);
171 else if (signore) {
172 tellstatus(stdout, myname, estat);
173 printf(" (Ignored)\n");
174 } else {
175 tellstatus(stderr, myname, estat);
176 fprintf(stderr, "\n");
177 if (!(np->n_flag & N_PREC))
178#ifdef unix
179 if (makeold(np->n_name) == 0)
180 fprintf(stderr,"%s: made '%s' look old.\n", myname, np->n_name);
181#else
182 if (unlink(np->n_name) == 0)
183 fprintf(stderr,"%s: '%s' removed.\n", myname, np->n_name);
184#endif
185 if (!conterr) exit(estat != 0);
186 np->n_flag |= N_ERROR;
187 return;
188 }
189 }
190 }
191 }
192}
193
194
195void docmds(np)
196struct name *np;
197{
198 register struct line *lp;
199
200 for (lp = np->n_line; lp; lp = lp->l_next)
201 docmds1(np, lp);
202}
203
204#ifdef tos
205/*
206 * execute the command submitted by make,
207 * needed because TOS has no internal shell,
208 * so we use Pexec to do the job
209 * v 1.1 of 10/sep/89 by yeti
210 */
211
212#define DELM1 ';'
213#define DELM2 ' '
214#define DELM3 ','
215
216int Tosexec(string)
217char *string;
218{
219 register char *help, *help2, c;
220 register unsigned char l=1;
221 char progname[80], command[255], plain[15];
222 static char **envp,*env;
223 register int error,i;
224
225 /* generate strange TOS environment (RAL) */
226 for ( i = 0, envp = environ; *envp; envp++) i += strlen(*envp) +1;
227 if ((env = malloc(i+1)) == (char *)0)
228 fatal("No memory for TOS environment",(char *)0,0);
229 for ( envp = environ, help = env; *envp; envp++) {
230 strcpy ( help, *envp);
231 while ( *(help++)) ;
232 }
233 *help = '\0';
234
235 help = progname;
236 while((*help++=*string++) != ' '); /* progname is command name */
237 *--help = '\0';
238
239 l = strlen(string); /* build option list */
240 command[0] = l; /* TOS likes it complicated */
241 strcpy(&command[1],string);
242 if ((error = (int) Pexec(0,progname,command,env)) != -33) {
243 free(env);
244 return(error);
245 }
246
247 /* could'nt find program, try to search the PATH */
248 if((help=strrchr(progname,'\\')) != (char *) 0) /* just the */
249 strcpy(plain,++help); /* name */
250 else if((help=strrchr(progname,'/')) != (char *) 0)
251 strcpy(plain,++help);
252 else if((help=strrchr(progname,':')) != (char *) 0)
253 strcpy(plain,++help);
254 else
255 strcpy(plain,progname);
256
257 if(*(help=getmacro("PATH")) == '\0') {
258 free(env);
259 return(-33);
260 }
261 c = 1;
262 while(c)
263 { help2 = &progname[-1];
264 i = 0;
265 while((c=*help++) != '\0' && i<80 && c != DELM1
266 && c != DELM2 && c != DELM3)
267 *++help2 = c, i++;
268 *++help2 = '\\';
269 strcpy(++help2,plain);
270 if((error=(int) Pexec(0,progname,command,env))!=-33) {
271 free(env);
272 return(error);
273 }
274 }
275 free(env);
276 return(-33);
277}
278
279
280/* (stolen from ZOO -- thanks to Rahul Dehsi)
281Function mstonix() accepts an MSDOS format date and time and returns
282a **IX format time. No adjustment is done for timezone.
283*/
284
285time_t mstonix (date, time)
286unsigned int date, time;
287{
288 int year, month, day, hour, min, sec, daycount;
289 time_t longtime;
290 /* no. of days to beginning of month for each month */
291 static int dsboy[12] = { 0, 31, 59, 90, 120, 151, 181, 212,
292 243, 273, 304, 334};
293
294 if (date == 0 && time == 0) /* special case! */
295 return (0L);
296
297 /* part of following code is common to zoolist.c */
298 year = (((unsigned int) date >> 9) & 0x7f) + 1980;
299 month = ((unsigned int) date >> 5) & 0x0f;
300 day = date & 0x1f;
301
302 hour = ((unsigned int) time >> 11)& 0x1f;
303 min = ((unsigned int) time >> 5) & 0x3f;
304 sec = ((unsigned int) time & 0x1f) * 2;
305
306/* DEBUG and leap year fixes thanks to Mark Alexander <uunet!amdahl!drivax!alexande>*/
307#ifdef DEBUG
308 printf ("mstonix: year=%d month=%d day=%d hour=%d min=%d sec=%d\n",
309 year, month, day, hour, min, sec);
310#endif
311 /* Calculate days since 1970/01/01 */
312 daycount = 365 * (year - 1970) + /* days due to whole years */
313 (year - 1969) / 4 + /* days due to leap years */
314 dsboy[month-1] + /* days since beginning of this year */
315 day-1; /* days since beginning of month */
316
317 if (year % 4 == 0 &&
318 year % 400 != 0 && month >= 3) /* if this is a leap year and month */
319 daycount++; /* is March or later, add a day */
320
321 /* Knowing the days, we can find seconds */
322 longtime = daycount * 24L * 60L * 60L +
323 hour * 60L * 60L + min * 60 + sec;
324 return (longtime);
325}
326#endif /* tos */
327
328#ifdef os9
329/*
330 * Some stuffing around to get the modified time of a file
331 * in an os9 file system
332 */
333void getmdate(fd, tbp)
334int fd;
335struct sgtbuf *tbp;
336{
337 struct registers regs;
338 static struct fildes fdbuf;
339
340
341 regs.rg_a = fd;
342 regs.rg_b = SS_FD;
343 regs.rg_x = &fdbuf;
344 regs.rg_y = sizeof (fdbuf);
345
346 if (_os9(I_GETSTT, &regs) == -1) {
347 errno = regs.rg_b & 0xff;
348 return -1;
349 }
350 if (tbp)
351 {
352 _strass(tbp, fdbuf.fd_date, sizeof (fdbuf.fd_date));
353 tbp->t_second = 0; /* Files are only acurate to mins */
354 }
355 return 0;
356}
357
358
359/*
360 * Kludge routine to return an aproximation of how many
361 * seconds since 1980. Dates will be in order, but will not
362 * be lineer
363 */
364time_t cnvtime(tbp)
365struct sgtbuf *tbp;
366{
367 long acc;
368
369 acc = tbp->t_year - 80; /* Baseyear is 1980 */
370 acc = acc * 12 + tbp->t_month;
371 acc = acc * 31 + tbp->t_day;
372 acc = acc * 24 + tbp->t_hour;
373 acc = acc * 60 + tbp->t_minute;
374 acc = acc * 60 + tbp->t_second;
375
376 return acc;
377}
378
379
380/*
381 * Get the current time in the internal format
382 */
383void time(tp)
384time_t *tp;
385{
386 struct sgtbuf tbuf;
387
388
389 if (getime(&tbuf) < 0)
390 return -1;
391
392 if (tp)
393 *tp = cnvtime(&tbuf);
394
395 return 0;
396}
397#endif
398
399
400/*
401 * Get the modification time of a file. If the first
402 * doesn't exist, it's modtime is set to 0.
403 */
404void modtime(np)
405struct name *np;
406{
407#ifdef unix
408 struct stat info;
409 int r;
410
411 if (is_archive_ref(np->n_name)) {
412 r = archive_stat(np->n_name, &info);
413 } else {
414 r = stat(np->n_name, &info);
415 }
416 if (r < 0) {
417 if (errno != ENOENT)
418 fatal("Can't open %s: %s", np->n_name, errno);
419
420 np->n_time = 0L;
421 np->n_flag &= ~N_EXISTS;
422 } else {
423 np->n_time = info.st_mtime;
424 np->n_flag |= N_EXISTS;
425 }
426#endif
427#ifdef tos
428 struct DOSTIME fm;
429 int fd;
430
431 if((fd=Fopen(np->n_name,0)) < 0) {
432 np->n_time = 0L;
433 np->n_flag &= ~N_EXISTS;
434 }
435 else {
436 Fdatime(&fm,fd,0);
437 Fclose(fd);
438 np->n_time = mstonix((unsigned int)fm.date,(unsigned int)fm.time);
439 np->n_flag |= N_EXISTS;
440 }
441#endif
442#ifdef eon
443 struct stat info;
444 int fd;
445
446 if ((fd = open(np->n_name, 0)) < 0) {
447 if (errno != ER_NOTF)
448 fatal("Can't open %s: %s", np->n_name, errno);
449
450 np->n_time = 0L;
451 np->n_flag &= ~N_EXISTS;
452 }
453 else if (getstat(fd, &info) < 0)
454 fatal("Can't getstat %s: %s", np->n_name, errno);
455 else {
456 np->n_time = info.st_mod;
457 np->n_flag |= N_EXISTS;
458 }
459
460 close(fd);
461#endif
462#ifdef os9
463 struct sgtbuf info;
464 int fd;
465
466 if ((fd = open(np->n_name, 0)) < 0) {
467 if (errno != E_PNNF)
468 fatal("Can't open %s: %s", np->n_name, errno);
469
470 np->n_time = 0L;
471 np->n_flag &= ~N_EXISTS;
472 }
473 else if (getmdate(fd, &info) < 0)
474 fatal("Can't getstat %s: %s", np->n_name, errno);
475 else {
476 np->n_time = cnvtime(&info);
477 np->n_flag |= N_EXISTS;
478 }
479
480 close(fd);
481#endif
482}
483
484
485/*
486 * Update the mod time of a file to now.
487 */
488void touch(np)
489struct name *np;
490{
491 char c;
492 int fd;
493
494 if (!domake || !silent) printf("touch(%s)\n", np->n_name);
495
496 if (domake) {
497#ifdef unix
498 struct utimbuf a;
499
500 a.actime = a.modtime = time((time_t *)NULL);
501 if (utime(np->n_name, &a) < 0)
502 printf("%s: '%s' not touched - non-existant\n",
503 myname, np->n_name);
504#endif
505#ifdef tos
506 struct DOSTIME fm;
507 int fd;
508
509 if((fd=Fopen(np->n_name,0)) < 0) {
510 printf("%s: '%s' not touched - non-existant\n",
511 myname, np->n_name);
512 }
513 else {
514 fm.date = Tgetdate();
515 fm.time = Tgettime();
516 Fdatime(&fm,fd,1);
517 Fclose(fd);
518 }
519#endif
520#ifdef eon
521 if ((fd = open(np->n_name, 0)) < 0)
522 printf("%s: '%s' not touched - non-existant\n",
523 myname, np->n_name);
524 else
525 {
526 uread(fd, &c, 1, 0);
527 uwrite(fd, &c, 1);
528 }
529 close(fd);
530#endif
531#ifdef os9
532 /*
533 * Strange that something almost as totally useless
534 * as this is easy to do in os9!
535 */
536 if ((fd = open(np->n_name, S_IWRITE)) < 0)
537 printf("%s: '%s' not touched - non-existant\n",
538 myname, np->n_name);
539 close(fd);
540#endif
541 }
542}
543
544
545/*
546 * Recursive routine to make a target.
547 */
548int make(np, level)
549struct name *np;
550int level;
551{
552 register struct depend *dp;
553 register struct line *lp;
554 register struct depend *qdp;
555 time_t now, t, dtime = 0;
556 bool dbgfirst = TRUE;
557 char *basename = (char *) 0;
558 char *inputname = (char *) 0;
559
560 if (np->n_flag & N_DONE) {
561 if(dbginfo) dbgprint(level,np,"already done");
562 return 0;
563 }
564
565 modtime(np); /* Gets modtime of this file */
566
567 while (time(&now) == np->n_time) {
568 /* Time of target is equal to the current time. This bothers us, because
569 * we can't tell if it needs to be updated if we update a file it depends
570 * on within a second. So wait until the second is over.
571 */
572 usleep(10000);
573 }
574
575 if (rules) {
576 for (lp = np->n_line; lp; lp = lp->l_next)
577 if (lp->l_cmd)
578 break;
579 if (!lp)
580 dyndep(np,&basename,&inputname);
581 }
582
583 if (!(np->n_flag & (N_TARG | N_EXISTS))) {
584 fprintf(stderr,"%s: Don't know how to make %s\n", myname, np->n_name);
585 if (conterr) {
586 np->n_flag |= N_ERROR;
587 if (dbginfo) dbgprint(level,np,"don't know how to make");
588 return 0;
589 }
590 else exit(1);
591 }
592
593 for (qdp = (struct depend *)0, lp = np->n_line; lp; lp = lp->l_next) {
594 for (dp = lp->l_dep; dp; dp = dp->d_next) {
595 if(dbginfo && dbgfirst) {
596 dbgprint(level,np," {");
597 dbgfirst = FALSE;
598 }
599 make(dp->d_name, level+1);
600 if (np->n_time < dp->d_name->n_time)
601 qdp = newdep(dp->d_name, qdp);
602 dtime = max(dtime, dp->d_name->n_time);
603 if (dp->d_name->n_flag & N_ERROR) np->n_flag |= N_ERROR;
604 if (dp->d_name->n_flag & N_EXEC ) np->n_flag |= N_EXEC;
605 }
606 if (!quest && (np->n_flag & N_DOUBLE) &&
607 (np->n_time < dtime || !( np->n_flag & N_EXISTS))) {
608 execflag = FALSE;
609 make1(np, lp, qdp, basename, inputname); /* free()'s qdp */
610 dtime = 0;
611 qdp = (struct depend *)0;
612 if(execflag) np->n_flag |= N_EXEC;
613 }
614 }
615
616 np->n_flag |= N_DONE;
617
618 if (quest) {
619 t = np->n_time;
620 np->n_time = now;
621 return (t < dtime);
622 }
623 else if ((np->n_time < dtime || !( np->n_flag & N_EXISTS))
624 && !(np->n_flag & N_DOUBLE)) {
625 execflag = FALSE;
626 make1(np, (struct line *)0, qdp, basename, inputname); /* free()'s qdp */
627 np->n_time = now;
628 if ( execflag) np->n_flag |= N_EXEC;
629 }
630 else if ( np->n_flag & N_EXEC ) {
631 np->n_time = now;
632 }
633
634 if (dbginfo) {
635 if(dbgfirst) {
636 if(np->n_flag & N_ERROR)
637 dbgprint(level,np,"skipped because of error");
638 else if(np->n_flag & N_EXEC)
639 dbgprint(level,np,"successfully made");
640 else dbgprint(level,np,"is up to date");
641 }
642 else {
643 if(np->n_flag & N_ERROR)
644 dbgprint(level,(struct name *)0,"} skipped because of error");
645 else if(np->n_flag & N_EXEC)
646 dbgprint(level,(struct name *)0,"} successfully made");
647 else dbgprint(level,(struct name *)0,"} is up to date");
648 }
649 }
650 if (level == 0 && !(np->n_flag & N_EXEC))
651 printf("%s: '%s' is up to date\n", myname, np->n_name);
652
653 if(basename)
654 free(basename);
655 return 0;
656}
657
658
659void make1(np, lp, qdp, basename, inputname)
660struct name *np;
661struct line *lp;
662register struct depend *qdp;
663char *basename;
664char *inputname;
665{
666 register struct depend *dp;
667 size_t l1, l2;
668
669 if (dotouch)
670 touch(np);
671 else if (!(np->n_flag & N_ERROR)) {
672 strcpy(str1, "");
673
674 if(!inputname) {
675 inputname = str1; /* default */
676 if (ambigmac) implmacros(np,lp,&basename,&inputname);
677 }
678 setDFmacro("<",inputname);
679
680 if(!basename)
681 basename = str1;
682 setDFmacro("*",basename);
683
684 for (dp = qdp; dp; dp = qdp) {
685 l1= strlen(str1);
686 l2= strlen(dp->d_name->n_name);
687 while (l1 + 1 + l2 +1 > str1s.len)
688 strrealloc(&str1s);
689 if (strlen(str1))
690 strcat(str1, " ");
691 strcat(str1, dp->d_name->n_name);
692 qdp = dp->d_next;
693 free(dp);
694 }
695 setmacro("?", str1);
696 setDFmacro("@", np->n_name);
697
698 if (lp) /* lp set if doing a :: rule */
699 docmds1(np, lp);
700 else
701 docmds(np);
702 }
703}
704
705void implmacros(np,lp, pbasename,pinputname)
706struct name *np;
707struct line *lp;
708char **pbasename; /* Name without suffix */
709char **pinputname;
710{
711 struct line *llp;
712 register char *p;
713 register char *q;
714 register char *suff; /* Old suffix */
715 int baselen;
716 struct depend *dp;
717 bool dpflag = FALSE;
718
719 /* get basename out of target name */
720 p = str2;
721 q = np->n_name;
722 suff = suffix(q);
723 while ( *q && (q < suff || !suff)) *p++ = *q++;
724 *p = '\0';
725 if ((*pbasename = (char *) malloc(strlen(str2)+1)) == (char *)0 )
726 fatal("No memory for basename",(char *)0,0);
727 strcpy(*pbasename,str2);
728 baselen = strlen(str2);
729
730 if ( lp)
731 llp = lp;
732 else
733 llp = np->n_line;
734
735 while (llp) {
736 for (dp = llp->l_dep; dp; dp = dp->d_next) {
737 if( strncmp(*pbasename,dp->d_name->n_name,baselen) == 0) {
738 *pinputname = dp->d_name->n_name;
739 return;
740 }
741 if( !dpflag) {
742 *pinputname = dp->d_name->n_name;
743 dpflag = TRUE;
744 }
745 }
746 if (lp) break;
747 llp = llp->l_next;
748 }
749
750#if NO_WE_DO_WANT_THIS_BASENAME
751 free(*pbasename); /* basename ambiguous or no dependency file */
752 *pbasename = (char *)0;
753#endif
754 return;
755}
756
757void dbgprint(level,np,comment)
758int level;
759struct name *np;
760char *comment;
761{
762 char *timep;
763
764 if(np) {
765 timep = ctime(&np->n_time);
766 timep[24] = '\0';
767 fputs(&timep[4],stdout);
768 }
769 else fputs(" ",stdout);
770 fputs(" ",stdout);
771 while(level--) fputs(" ",stdout);
772 if (np) {
773 fputs(np->n_name,stdout);
774 if (np->n_flag & N_DOUBLE) fputs(" :: ",stdout);
775 else fputs(" : ",stdout);
776 }
777 fputs(comment,stdout);
778 putchar((int)'\n');
779 fflush(stdout);
780 return;
781}
782
Note: See TracBrowser for help on using the repository browser.