Bug Summary

File:dmake/sysintf.c
Location:line 824, column 4
Description:Access to field 'fl_next' results in a dereference of a null pointer (loaded from variable 'new')

Annotated Source Code

1/* RCS $Id: sysintf.c,v 1.13 2008-03-05 18:30:58 kz Exp $
2--
3-- SYNOPSIS
4-- System independent interface
5--
6-- DESCRIPTION
7-- These are the routines constituting the system interface.
8-- The system is taken to be essentially POSIX conformant.
9-- The original code was extensively revised by T J Thompson at MKS,
10-- and the library cacheing was added by Eric Gisin at MKS. I then
11-- revised the code yet again, to improve the lib cacheing, and to
12-- make it more portable.
13--
14-- The following is a list of routines that are required by this file
15-- in order to work. These routines are provided as functions by the
16-- standard C lib of the target system or as #defines in system/sysintf.h
17-- or via appropriate C code in the system/ directory for the given
18-- system.
19--
20-- The first group must be provided by a file in the system/ directory
21-- the second group is ideally provided by the C lib. However, there
22-- are instances where the C lib implementation of the specified routine
23-- does not exist, or is incorrect. In these instances the routine
24-- must be provided by the the user in the system/ directory of dmake.
25-- (For example, the bsd/ dir contains code for putenv(), and tempnam())
26--
27-- DMAKE SPECIFIC:
28-- seek_arch()
29-- touch_arch()
30-- void_lcache()
31-- runargv()
32-- DMSTAT()
33-- Remove_prq()
34--
35-- C-LIB SPECIFIC: (should be present in your C-lib)
36-- utime()
37-- time()
38-- getenv()
39-- putenv()
40-- getcwd()
41-- signal()
42-- chdir()
43-- tempnam()
44--
45-- AUTHOR
46-- Dennis Vadura, dvadura@dmake.wticorp.com
47--
48-- WWW
49-- http://dmake.wticorp.com/
50--
51-- COPYRIGHT
52-- Copyright (c) 1996,1997 by WTI Corp. All rights reserved.
53--
54-- This program is NOT free software; you can redistribute it and/or
55-- modify it under the terms of the Software License Agreement Provided
56-- in the file <distribution-root>/readme/license.txt.
57--
58-- LOG
59-- Use cvs log to obtain detailed change logs.
60*/
61
62#include "extern.h"
63
64/* The following definition controls the use of GetModuleFileName() */
65#if defined(_MSC_VER) || defined(__MINGW32__)
66# define HAVE_GETMODULEFILENAMEFUNC 1
67
68/* this is needed for the _ftime call below. Only needed here. */
69# include <sys/timeb.h>
70#endif
71
72/* for cygwin_conv_to_posix_path() in Prolog() and for cygdospath()*/
73#if __CYGWIN__
74# include <sys/cygwin.h>
75#endif
76
77#include "sysintf.h"
78#if HAVE_ERRNO_H1
79# include <errno(*__errno_location ()).h>
80#else
81 extern int errno(*__errno_location ());
82#endif
83
84/*
85** Tries to stat the file name. Returns 0 if the file
86** does not exist. Note that if lib is not null it tries to stat
87** the name found inside lib.
88**
89** If member is NOT nil then look for the library object which defines the
90** symbol given by name. If found DmStrDup the name and return make the
91** pointer pointed at by sym point at it. Not handled for now!
92*/
93static time_t
94really_dostat(name, buf)
95char *name;
96struct stat *buf;
97{
98 return( ( DMSTATstat(name,buf)==-1
99 || (STOBOOL(Augmake)(Augmake && ((*Augmake | 0x20) == 'y')) && (buf->st_mode & S_IFDIR0040000)))
100 ? (time_t)0L
101 : (time_t) buf->st_mtimest_mtim.tv_sec
102 );
103}
104
105
106PUBLIC time_t
107Do_stat(name, lib, member, force)
108char *name;
109char *lib;
110char **member;
111int force;
112{
113 struct stat buf;
114 time_t seek_arch();
115
116 if( member != NIL(char *)((char **)((void*)0)) )
117 Fatal("Library symbol names not supported");
118
119 buf.st_mtimest_mtim.tv_sec = (time_t)0L;
120 if( lib != NIL(char)((char*)((void*)0)) )
121 return( seek_arch(Basename(name), lib) );
122 else if( strlen(Basename(name)) > NameMax ) {
123 Warning( "Filename [%s] longer than value of NAMEMAX [%d].\n\
124 Assume unix time 0.\n", Basename(name), NameMax );
125 return((time_t)0L);
126 }
127 else if( STOBOOL(UseDirCache)(UseDirCache && ((*UseDirCache | 0x20) == 'y')) )
128 return(CacheStat(name,force));
129 else
130 return(really_dostat(name,&buf));
131}
132
133
134/* Touch existing file to force modify time to present.
135 */
136PUBLIC int
137Do_touch(name, lib, member)
138char *name;
139char *lib;
140char **member;
141{
142 if( member != NIL(char *)((char **)((void*)0)) )
143 Fatal("Library symbol names not supported");
144
145 if (lib != NIL(char)((char*)((void*)0)))
146 return( touch_arch(Basename(name), lib) );
147 else if( strlen(Basename(name)) > NameMax ) {
148 Warning( "Filename [%s] longer than value of NAMEMAX [%d].\n\
149 File timestamp not updated to present time.\n", Basename(name), NameMax );
150 return(-1);
151 }
152 else
153#ifdef HAVE_UTIME_NULL1
154 return( utime(name, NULL((void*)0)) );
155#else
156# error "Utime NULL not supported"
157#endif
158}
159
160
161
162PUBLIC void
163Void_lib_cache( lib_name, member_name )/*
164=========================================
165 Void the library cache for lib lib_name, and member member_name. */
166char *lib_name;
167char *member_name;
168{
169 VOID_LCACHE( lib_name, member_name )(void) void_lcache(lib_name,member_name);
170}
171
172
173
174/*
175** return the current time
176*/
177PUBLIC time_t
178Do_time()
179{
180 return (time( NIL(time_t)((time_t*)((void*)0)) ));
181}
182
183
184
185/*
186** Print profiling information
187*/
188PUBLIC void
189Do_profile_output( text, mtype, target )
190char *text;
191uint16 mtype;
192CELLPTR target;
193{
194
195 time_t time_sec;
196 uint32 time_msec;
197 char *tstrg;
198 char *tname;
199
200#ifdef HAVE_GETTIMEOFDAY1
201 struct timeval timebuffer;
202 gettimeofday(&timebuffer, NULL((void*)0));
203 time_sec = timebuffer.tv_sec;
204 time_msec = timebuffer.tv_usec/1000;
205#else
206#if defined(_MSC_VER) || defined(__MINGW32__)
207 struct _timeb timebuffer;
208 _ftime( &timebuffer );
209 time_sec = timebuffer.time;
210 time_msec = timebuffer.millitm;
211# else
212 time_sec = time( NIL(time_t)((time_t*)((void*)0)) );
213 time_msec = 0;
214# endif
215#endif
216
217 tname = target->CE_NAMEce_name->ht_name;
218 if( mtype & M_TARGET0x01 ) {
219 tstrg = "target";
220 /* Don't print special targets .TARGETS and .ROOT */
221 if( tname[0] == '.' && (strcmp(".TARGETS", tname) == 0 || \
222 strcmp(".ROOT", tname) == 0) ) {
223 return;
224 }
225 } else {
226 tstrg = "recipe";
227 }
228
229 /* Don't print shell escape targets if not especially requested. */
230 if( (target->ce_attr & A_SHELLESC0x40000000) && !(Measure & M_SHELLESC0x08) ) {
231 return;
232 }
233
234 /* Print absolute path if requested. */
235 if( !(target->ce_attr & A_SHELLESC0x40000000) && (Measure & M_ABSPATH0x04) ) {
236 printf("%s %s %lu.%.3u %s%s%s\n",text, tstrg, time_sec, time_msec, Pwd, DirSepStr, tname);
237 } else {
238 printf("%s %s %lu.%.3u %s\n",text, tstrg, time_sec, time_msec, tname);
239 }
240}
241
242
243
244PUBLIC int
245Do_cmnd(cmd, group, do_it, target, cmnd_attr, last)/*
246=====================================================
247 Execute the string passed in as a command and return
248 the return code. The command line arguments are
249 assumed to be separated by spaces or tabs. The first
250 such argument is assumed to be the command.
251
252 If group is true then this is a group of commands to be fed to the
253 the shell as a single unit. In this case cmd is of the form
254 "file" indicating the file that should be read by the shell
255 in order to execute the command group.
256
257 If Wait_for_completion is TRUE add the A_WFC attribute to the new
258 process.
259*/
260char **cmd; /* Simulate a reference to *cmd. */
261int group; /* if set cmd contains the filename of a (group-)shell
262 * script. */
263int do_it; /* Only execute cmd if not set to null. */
264CELLPTR target;
265t_attr cmnd_attr; /* Attributes for current cmnd. */
266int last; /* Last recipe line in target. */
267{
268 int i;
269
270 DB_ENTER( "Do_cmnd" );
271
272 if( !do_it ) {
273 if( last && !Doing_bang ) {
274 /* Don't execute, just update the target when using '-t'
275 * switch. */
276 Update_time_stamp( target );
277 }
278 DB_RETURN( 0 )return (0);
279 }
280
281 /* Stop making the rest of the recipies for this target if an error occurred
282 * but the Continue (-k) flag is set to build as much as possible. */
283 if ( target->ce_attr & A_ERROR0x10000000 ) {
284 if ( last ) {
285 Update_time_stamp( target );
286 }
287 DB_RETURN( 0 )return (0);
288 }
289
290 if( Max_proc == 1 ) Wait_for_completion = TRUE1;
291
292 /* Tell runargv() to wait if needed. */
293 if( Wait_for_completion ) cmnd_attr |= A_WFC0x00200;
294
295 /* remove leading whitespace - This should never trigger! */
296 if( iswhite(**cmd)((**cmd == ' ') || (**cmd == '\t')) ) {
297 char *p;
298 if( (p = DmStrSpn(*cmd," \t") ) != *cmd )
299 strcpy(*cmd,p);
300 }
301
302 /* set shell if shell metas are found */
303 if( (cmnd_attr & A_SHELL0x00800) || group || (*DmStrPbrk(*cmd, Shell_metas)!='\0') )
304 cmnd_attr |= A_SHELL0x00800; /* If group is TRUE this doesn't hurt. */
305
306 /* runargv() returns either 0 or 1, 0 ==> command executed, and
307 * we waited for it to return, 1 ==> command started and is still
308 * running. */
309 i = runargv(target, group, last, cmnd_attr, cmd);
310
311 DB_RETURN( i )return (i);
312}
313
314
315#define MINARGV64 64
316
317PUBLIC char **
318Pack_argv( group, shell, cmd )/*
319================================
320 Take a command and pack it into an argument vector to be executed.
321 If group is true cmd holds the group script file.
322*/
323int group;
324int shell;
325char **cmd; /* Simulate a reference to *cmd. */
326{
327 static char **av = NIL(char *)((char **)((void*)0));
328 static int avs = 0;
329 int i = 0;
330 char *s; /* Temporary string pointer. */
331
332 if( av == NIL(char *)((char **)((void*)0)) ) {
333 TALLOC(av, MINARGV, char*)if ((av = (char**) calloc((unsigned int)(64), (size_t)sizeof(
char*))) == (char**)0) {No_ram();}
;
334 avs = MINARGV64;
335 }
336 av[0] = NIL(char)((char*)((void*)0));
337
338 if (**cmd) {
339 if( shell||group ) {
340 char* sh = group ? GShell : Shell;
341
342 if( sh != NIL(char)((char*)((void*)0)) ) {
343 av[i++] = sh;
344 if( (av[i] = (group?GShell_flags:Shell_flags)) != NIL(char)((char*)((void*)0)) ) i++;
345
346 if( shell && Shell_quote && *Shell_quote ) {
347 /* Enclose the shell command with SHELLCMDQUOTE. */
348 s = DmStrJoin(Shell_quote, *cmd, -1, FALSE0);
349 FREE(*cmd)free((char*)(*cmd));
350 *cmd = DmStrJoin(s, Shell_quote, -1, TRUE1);
351 }
352 av[i++] = *cmd;
353
354#if defined(USE_CREATEPROCESS)
355 /* CreateProcess() needs one long command line. */
356 av[0] = DmStrAdd(av[0], av[1], FALSE0);
357 av[1] = NIL(char)((char*)((void*)0));
358 /* i == 3 means Shell_flags are given. */
359 if( i == 3 ) {
360 s = av[0];
361 av[0] = DmStrAdd(s, av[2], FALSE0);
362 FREE(s)free((char*)(s));
363 av[2] = NIL(char)((char*)((void*)0));
364 }
365 /* The final free of cmd will free the concated command line. */
366 FREE(*cmd)free((char*)(*cmd));
367 *cmd = av[0];
368#endif
369 av[i] = NIL(char)((char*)((void*)0));
370 }
371 else
372 Fatal("%sSHELL macro not defined", group?"GROUP":"");
373 }
374 else {
375 char *tcmd = *cmd;
376
377#if defined(USE_CREATEPROCESS)
378 /* CreateProcess() needs one long command line, fill *cmd
379 * into av[0]. */
380 while( iswhite(*tcmd)((*tcmd == ' ') || (*tcmd == '\t')) ) ++tcmd;
381 if( *tcmd ) av[i++] = tcmd;
382#else
383 /* All other exec/spawn functions need the parameters separated
384 * in the argument vector. */
385 do {
386 /* Fill *cmd into av[]. Whitespace is converted into '\0' to
387 * terminate each av[] member. */
388 while( iswhite(*tcmd)((*tcmd == ' ') || (*tcmd == '\t')) ) ++tcmd;
389 if( *tcmd ) av[i++] = tcmd;
390
391 while( *tcmd != '\0' && !iswhite(*tcmd)((*tcmd == ' ') || (*tcmd == '\t')) ) ++tcmd;
392 if( *tcmd ) *tcmd++ = '\0';
393
394 /* dynamically increase av size. */
395 if( i == avs ) {
396 avs += MINARGV64;
397 av = (char **) realloc( av, avs*sizeof(char *) );
398 }
399 } while( *tcmd );
400#endif
401
402 av[i] = NIL(char)((char*)((void*)0));
403 }
404 }
405
406 return(av);
407}
408
409
410/*
411** Return the value of ename from the environment
412** if ename is not defined in the environment then
413** NIL(char) should be returned
414*/
415PUBLIC char *
416Read_env_string(ename)
417char *ename;
418{
419 return( getenv(ename) );
420}
421
422
423/*
424** Set the value of the environment string ename to value.
425** Returns 0 if success, non-zero if failure
426*/
427PUBLIC int
428Write_env_string(ename, value)
429char *ename;
430char *value;
431{
432#if defined(HAVE_SETENV1)
433
434 return( setenv(ename, value, 1) );
435
436#else /* !HAVE_SETENV */
437
438 char* p;
439 char* envstr = DmStrAdd(ename, value, FALSE0);
440
441 p = envstr+strlen(ename); /* Don't change this code, DmStrAdd does not */
442 *p++ = '='; /* add the space if *value is 0, it does */
443 if( !*value ) *p = '\0'; /* allocate enough memory for one though. */
444
445 return( putenv(envstr) ); /* Possibly leaking 'envstr' */
446
447#endif /* !HAVE_SETENV */
448}
449
450
451PUBLIC void
452ReadEnvironment()
453{
454 extern char **Rule_tab;
455#if !defined(_MSC_VER)
456#if defined(__BORLANDC__) && __BORLANDC__ >= 0x500
457 extern char ** _RTLENTRY _EXPDATA environ;
458#else
459 extern char **environ;
460#endif
461#endif
462 char **rsave;
463
464#if !defined(__ZTC__) && !defined(_MPW)
465# define make_env()
466# define free_env()
467#else
468 void make_env();
469 void free_env();
470#endif
471
472 make_env();
473
474 rsave = Rule_tab;
475 Rule_tab = environ;
476 Readenv = TRUE1;
477
478 Parse( NIL(FILE)((FILE*)((void*)0)) );
479
480 Readenv = FALSE0;
481 Rule_tab = rsave;
482
483 free_env();
484}
485
486
487
488/*
489** All we have to catch is SIGINT
490*/
491PUBLIC void
492Catch_signals(fn)
493void (*fn)(int);
494{
495 /* FIXME: Check this and add error handling. */
496 if( (void (*)(int)) signal(SIGINT2, SIG_IGN((__sighandler_t) 1)) != (void (*)(int))SIG_IGN((__sighandler_t) 1) )
497 signal( SIGINT2, fn );
498 if( (void (*)(int)) signal(SIGQUIT3, SIG_IGN((__sighandler_t) 1)) != (void (*)(int))SIG_IGN((__sighandler_t) 1) )
499 signal( SIGQUIT3, fn );
500}
501
502
503
504/*
505** Clear any previously set signals
506*/
507PUBLIC void
508Clear_signals()
509{
510 if( (void (*)())signal(SIGINT2, SIG_IGN((__sighandler_t) 1)) != (void (*)())SIG_IGN((__sighandler_t) 1) )
511 signal( SIGINT2, SIG_DFL((__sighandler_t) 0) );
512 if( (void (*)())signal(SIGQUIT3, SIG_IGN((__sighandler_t) 1)) != (void (*)())SIG_IGN((__sighandler_t) 1) )
513 signal( SIGQUIT3, SIG_DFL((__sighandler_t) 0) );
514}
515
516
517
518/*
519** Set program name
520*/
521PUBLIC void
522Prolog(argc, argv)
523int argc;
524char* argv[];
525{
526 Pname = (argc == 0) ? DEF_MAKE_PNAME"dmake" : argv[0];
527
528 /* Only some native Windows compilers provide this functionality. */
529#ifdef HAVE_GETMODULEFILENAMEFUNC
530 if( (AbsPname = MALLOC( PATH_MAX, char)(char*) malloc((unsigned int)(4096)*(size_t)sizeof(char))) == NIL(char)((char*)((void*)0)) ) No_ram();
531 GetModuleFileName(NULL((void*)0), AbsPname, PATH_MAX4096*sizeof(char));
532#else
533 AbsPname = "";
534#endif
535
536#if __CYGWIN__
537 /* Get the drive letter prefix used by cygwin. */
538 if ( (CygDrvPre = MALLOC( PATH_MAX, char)(char*) malloc((unsigned int)(4096)*(size_t)sizeof(char))) == NIL(char)((char*)((void*)0)) )
539 No_ram();
540 else {
541 int err = cygwin_conv_to_posix_path("c:", CygDrvPre);
542 if (err)
543 Fatal( "error converting \"%s\" - %s\n",
544 CygDrvPre, strerror (errno(*__errno_location ())));
545 if( (CygDrvPreLen = strlen(CygDrvPre)) == 2 ) {
546 /* No prefix */
547 *CygDrvPre = '\0';
548 CygDrvPreLen = 0;
549 } else {
550 /* Cut away the directory letter. */
551 CygDrvPre[CygDrvPreLen-2] = '\0';
552 /* Cut away the leading '/'. We don't free the pointer, i.e. choose
553 * the easy way. */
554 CygDrvPre++;
555 CygDrvPreLen -= 3;
556 }
557 }
558#endif
559
560 /* DirSepStr is used from Clean_path() in Def_cell(). Set it preliminary
561 * here, it will be redefined later in Create_macro_vars() in imacs.c. */
562 DirSepStr = "/";
563
564 Root = Def_cell( ".ROOT" );
565 Targets = Def_cell( ".TARGETS" );
566 Add_prerequisite(Root, Targets, FALSE0, FALSE0);
567
568 Targets->ce_flag = Root->ce_flag = F_RULES0x0010|F_TARGET0x0008|F_STAT0x0040;
569 Targets->ce_attr = Root->ce_attr = A_NOSTATE0x08000|A_PHONY0x04000;
570
571 Root->ce_flag |= F_MAGIC0x2000;
572 Root->ce_attr |= A_SEQ0x00200;
573
574 tzset();
575}
576
577
578
579/*
580** Do any clean up for exit.
581*/
582PUBLIC void
583Epilog(ret_code)
584int ret_code;
585{
586 Write_state();
587 Unlink_temp_files(Root);
588 Hook_std_writes(NIL(char)); /* For MSDOS tee (-F option) */
589 exit( ret_code );
590}
591
592
593
594/*
595** Use the built-in functions of the operating system to get the current
596** working directory.
597*/
598PUBLIC char *
599Get_current_dir()
600{
601 static char buf[PATH_MAX4096+2];
602
603 if( !getcwd(buf, sizeof(buf)) )
604 Fatal("Internal Error: Error when calling getcwd()!");
605
606#ifdef __EMX__
607 char *slash;
608 slash = buf;
609 while( (slash=strchr(slash,'/')) )
610 *slash = '\\';
611#endif
612
613 return buf;
614}
615
616
617
618/*
619** change working directory
620*/
621PUBLIC int
622Set_dir(path)
623char* path;
624{
625 return( chdir(path) );
626}
627
628
629
630/*
631** return switch char
632*/
633PUBLIC char
634Get_switch_char()
635{
636 return( getswitchar()'-' );
637}
638
639
640int Create_temp(tmpdir, path)/*
641===============================
642 Create a temporary file and open with exclusive access
643 Path is updated with the filename and the file descriptor
644 is returned. Note that the new name should be freed when
645 the file is removed.
646*/
647char *tmpdir;
648char **path;
649{
650 int fd; /* file descriptor */
651
652#if defined(HAVE_MKSTEMP1)
653 mode_t mask;
654
655 *path = DmStrJoin( tmpdir, DirSepStr, -1, FALSE0);
656 *path = DmStrJoin( *path, "mkXXXXXX", -1, TRUE1 );
657
658 mask = umask(0066);
659 fd = mkstemp( *path );
660 umask(mask);
661
662#elif defined(HAVE_TEMPNAM1)
663 char pidbuff[32];
664#if _MSC_VER >= 1300
665 /* Create more unique filename for .NET2003 and newer. */
666 long npid;
667 long nticks;
668
669 npid = _getpid();
670 nticks = GetTickCount() & 0xfff;
671 sprintf(pidbuff,"mk%d_%d_",npid,nticks);
672#else
673 sprintf(pidbuff,"mk");
674#endif
675 *path = tempnam(tmpdir, pidbuff);
676 fd = open(*path, O_CREAT0100 | O_EXCL0200 | O_TRUNC01000 | O_RDWR02, 0600);
677#else
678
679#error mkstemp() or tempnam() is needed
680
681#endif
682
683 return fd;
684}
685
686
687PUBLIC FILE*
688Get_temp(path, mode)/*
689======================
690 Generate a temporary file name and open the file for writing.
691 If a name cannot be generated or the file cannot be opened
692 return -1, else return the fileno of the open file.
693 and update the source file pointer to point at the new file name.
694 Note that the new name should be freed when the file is removed.
695 The file stream is opened with the given mode.
696*/
697char **path;
698char *mode;
699{
700 int fd;
701 FILE *fp;
702 char *tmpdir;
703 int tries = 20;
704
705 tmpdir = Read_env_string( "TMPDIR" );
706 if( tmpdir == NIL(char)((char*)((void*)0)) )
707 tmpdir = "/tmp";
708
709 while( --tries )
710 {
711 /* This sets path to the name of the created temp file. */
712 if( (fd = Create_temp(tmpdir, path)) != -1)
713 break;
714
715 free(*path); /* free var if creating temp failed. */
716 }
717
718 if( fd != -1)
719 {
720 Def_macro( "TMPFILE", DO_WINPATH(*path)*path, M_MULTI0x0004|M_EXPANDED0x0008 );
721 /* associate stream with file descriptor */
722 fp = fdopen(fd, mode);
723 }
724 else
725 fp = NIL(FILE)((FILE*)((void*)0));
726
727 return fp;
728}
729
730
731PUBLIC FILE *
732Start_temp( suffix, cp, fname )/*
733=================================
734 Open a new temporary file and set it up for writing. The file is linked
735 to cp and will be removed if once the target is finished.
736 If a suffix for the temporary files is requested two temporary files are
737 created. This is done because the routines that create a save temporary
738 file do not provide a definable suffix. The first (provided by Get_temp())
739 is save and unique and the second file is generated by adding the desired
740 suffix the the first temporary file. The extra file is also linked to cp
741 so that it gets removed later.
742 The function returns the FILE pointer to the temporary file (with suffix
743 if specified) and leaves the file name in *fname.
744*/
745char *suffix;
746CELLPTR cp;
747char **fname;
748{
749 FILE *fp, *fp2;
750 char *tmpname;
751 char *name;
752 char *fname_suff;
753
754 name = (cp != NIL(CELL)((CELL*)((void*)0)))?cp->CE_NAMEce_name->ht_name:"makefile text";
755
756 /* This sets tmpname to the name that was used. */
757 if( (fp = Get_temp(&tmpname, "w")) == NIL(FILE)((FILE*)((void*)0)) )
758 Open_temp_error( tmpname, name );
759
760 /* Don't free tmpname, it's stored in a FILELIST member in Link_temp(). */
761 Link_temp( cp, fp, tmpname );
762 *fname = tmpname;
763
764 /* As Get_temp() doesn't provide a definable suffix (anymore) we create an
765 * additional temporary file with that suffix. */
766 if ( suffix && *suffix ) {
767
768#ifdef HAVE_MKSTEMP1
769 /* Only use umask if we are also using mkstemp - this basically
770 * avoids using the incompatible implementation from MSVC. */
771 mode_t mask;
772
773 mask = umask(0066);
774#endif
775
776 fname_suff = DmStrJoin( tmpname, suffix, -1, FALSE0 );
777
778 /* Overwrite macro, Get_temp didn't know of the suffix. */
779 Def_macro( "TMPFILE", DO_WINPATH(fname_suff)fname_suff, M_MULTI0x0004|M_EXPANDED0x0008 );
780
781 if( (fp2 = fopen(fname_suff, "w" )) == NIL(FILE)((FILE*)((void*)0)) )
782 Open_temp_error( fname_suff, name );
783#ifdef HAVE_MKSTEMP1
784 umask(mask);
785#endif
786
787 /* Don't free fname_suff. */
788 Link_temp( cp, fp2, fname_suff );
789 fp = fp2;
790 *fname = fname_suff;
791 }
792
793 return( fp );
794}
795
796
797/*
798** Issue an error on failing to open a temporary file
799*/
800PUBLIC void
801Open_temp_error( tmpname, name )
802char *tmpname;
803char *name;
804{
805 Fatal("Cannot open temp file `%s' while processing `%s'", tmpname, name );
806}
807
808
809/*
810** Link a temp file onto the list of files.
811*/
812PUBLIC void
813Link_temp( cp, fp, fname )
814CELLPTR cp;
815FILE *fp;
816char *fname;
817{
818 FILELISTPTR new;
819
820 if( cp == NIL(CELL)((CELL*)((void*)0)) ) cp = Root;
1
Assuming 'cp' is not equal to null
2
Taking false branch
821
822 TALLOC( new, 1, FILELIST )if ((new = (FILELIST*) calloc((unsigned int)(1), (size_t)sizeof
(FILELIST))) == (FILELIST*)0) {No_ram();}
;
3
Within the expansion of the macro 'TALLOC':
a
Value assigned to 'new'
b
Assuming pointer value is null
823
824 new->fl_next = cp->ce_files;
4
Access to field 'fl_next' results in a dereference of a null pointer (loaded from variable 'new')
825 new->fl_name = fname;
826 new->fl_file = fp; /* indicates temp file is open */
827
828 cp->ce_files = new;
829}
830
831
832/*
833** Close a previously used temporary file.
834*/
835PUBLIC void
836Close_temp(cp, file)
837CELLPTR cp;
838FILE *file;
839{
840 FILELISTPTR fl;
841 if( cp == NIL(CELL)((CELL*)((void*)0)) ) cp = Root;
842
843 for( fl=cp->ce_files; fl && fl->fl_file != file; fl=fl->fl_next );
844 if( fl ) {
845 fl->fl_file = NIL(FILE)((FILE*)((void*)0));
846 fclose(file);
847 }
848}
849
850
851/*
852** Clean-up, and close all temporary files associated with a target.
853*/
854PUBLIC void
855Unlink_temp_files( cp )/*
856==========================
857 Unlink the tempfiles if any exist. Make sure you close the files first
858 though. This ensures that under DOS there is no disk space lost. */
859CELLPTR cp;
860{
861 FILELISTPTR cur, next;
862
863 if( cp == NIL(CELL)((CELL*)((void*)0)) || cp->ce_files == NIL(FILELIST)((FILELIST*)((void*)0)) ) return;
864
865 for( cur=cp->ce_files; cur != NIL(FILELIST)((FILELIST*)((void*)0)); cur=next ) {
866 next = cur->fl_next;
867
868 if( cur->fl_file ) fclose( cur->fl_file );
869
870 if( Verbose & V_LEAVE_TMP0x01 )
871 fprintf( stderrstderr, "%s: Left temp file [%s]\n", Pname, cur->fl_name );
872 else
873 (void) Remove_file( cur->fl_name );
874
875 FREE(cur->fl_name)free((char*)(cur->fl_name));
876 FREE(cur)free((char*)(cur));
877 }
878
879 cp->ce_files = NIL(FILELIST)((FILELIST*)((void*)0));
880}
881
882
883PUBLIC void
884Handle_result(status, ignore, abort_flg, target)/*
885==================================================
886 Handle return value of recipe.
887*/
888int status;
889int ignore;
890int abort_flg;
891CELLPTR target;
892{
893 status = ((status&0xff)==0 ? status>>8 /* return from exit() */
894 : (status & 0xff)==SIGTERM15 ? -1 /* terminated from SIGTERM */
895 : (status & 0x7f)+128); /* terminated from signal
896 * ( =status-128 ) */
897
898 if( status ) {
899 if( !abort_flg ) {
900 char buf[512];
901
902 sprintf(buf, "%s: Error code %d, while making '%s'",
903 Pname, status, target->ce_fname );
904
905 if( ignore || Continue ) {
906 if (!(Glob_attr & A_SILENT0x00002)) {
907 strcat(buf, " (Ignored" );
908
909 if ( Continue ) {
910 /* Continue after error if '-k' was used. */
911 strcat(buf,",Continuing");
912 target->ce_attr |= A_ERROR0x10000000;
913 }
914 strcat(buf,")");
915 if (Verbose)
916 fprintf(stderrstderr, "%s\n", buf);
917 }
918
919 if( target->ce_attr & A_ERRREMOVE0x40000
920 && Remove_file( target->ce_fname ) == 0
921 && !(Glob_attr & A_SILENT0x00002))
922 fprintf(stderrstderr,"%s: '%s' removed.\n", Pname, target->ce_fname);
923 }
924 else {
925 fprintf(stderrstderr, "%s\n",buf);
926
927 if(!(target->ce_attr & A_PRECIOUS0x00001)||(target->ce_attr & A_ERRREMOVE0x40000))
928 if( Remove_file( target->ce_fname ) == 0 )
929 fprintf(stderrstderr,"%s: '%s' removed.\n", Pname,
930 target->ce_fname);
931
932 Quit(0);
933 }
934 }
935 else if(!(target->ce_attr & A_PRECIOUS0x00001)||(target->ce_attr & A_ERRREMOVE0x40000))
936 Remove_file( target->ce_fname );
937 }
938}
939
940
941PUBLIC void
942Update_time_stamp( cp )/*
943=========================
944 Update the time stamp of cp and scan the list of its prerequisites for
945 files being marked as removable (ie. an inferred intermediate node).
946 Remove them if there are any. */
947CELLPTR cp;
948{
949 HASHPTR hp;
950 LINKPTR dp;
951 CELLPTR tcp;
952 time_t mintime;
953 int phony = ((cp->ce_attr&A_PHONY0x04000) != 0);
954
955 for(dp=CeMeToo(cp)&((cp)->ce_all); dp; dp=dp->cl_next) {
956 tcp=dp->cl_prq;
957 /* When calling Make() on this target ce_time was set to the minimal
958 * required time the target should have after building, i.e. the time
959 * stamp of the newest prerequisite or 1L if there is no
960 * prerequisite. */
961 mintime = tcp->ce_time;
962
963 if( tcp->ce_attr & A_LIBRARY0x00004 )
964 Void_lib_cache( tcp->ce_fname, NIL(char)((char*)((void*)0)) );
965 else if( !Touch && (tcp->ce_attr & A_LIBRARYM0x80000) )
966 Void_lib_cache( tcp->ce_lib, tcp->ce_fname );
967
968 /* phony targets are treated as if they were recently made
969 * and get the current time assigned. */
970 if( phony ) {
971 tcp->ce_time = Do_time();
972 }
973 else if (Trace) {
974 tcp->ce_time = Do_time();
975 }
976 else {
977 Stat_target(tcp, -1, TRUE1);
978
979 if( tcp->ce_time == (time_t) 0L ) {
980 /* If the target does not exist after building set its
981 * time stamp depending if it has recipes or not. Virtual
982 * Targets (without recipes) get the newest time stamp of
983 * its prerequisites assigned. (This was conveniently stored
984 * in mintime.)
985 * Targets with recipes are treated as if they were recently
986 * made and get the current time assigned. */
987 if( cp->ce_recipe == NIL(STRING)((STRING*)((void*)0)) && mintime > 1 ) {
988 tcp->ce_time = mintime;
989 }
990 else {
991 tcp->ce_time = Do_time();
992 }
993 }
994 else {
995 /* The target exist. If the target does not have recipe
996 * lines use the newest time stamp of either the target or
997 * the newest time stamp of its prerequisites and issue
998 * a warning. */
999 if( cp->ce_recipe == NIL(STRING)((STRING*)((void*)0)) ) {
1000 time_t newtime = ( mintime > 1 ? mintime : Do_time() );
1001
1002 if( !(tcp->ce_attr & A_SILENT0x00002) )
1003 Warning( "Found file corresponding to virtual target [%s].",
1004 tcp->CE_NAMEce_name->ht_name );
1005
1006 if( newtime > tcp->ce_time )
1007 tcp->ce_time = mintime;
1008 }
1009 }
1010 }
1011
1012 if( Trace ) {
1013 tcp->ce_flag |= F_STAT0x0040; /* pretend we stated ok */
1014 }
1015
1016 if( Verbose & V_MAKE0x10 )
1017 printf( "%s: <<<< Set [%s] time stamp to %lu\n",
1018 Pname, tcp->CE_NAMEce_name->ht_name, tcp->ce_time );
1019
1020 if( Measure & M_TARGET0x01 )
1021 Do_profile_output( "e", M_TARGET0x01, tcp );
1022
1023 /* At this point cp->ce_time is updated to either the actual file
1024 * time or the current time. */
1025 DB_PRINT( "make", ("time stamp: %ld, required mintime: %ld",
1026 cp->ce_time, mintime) );
1027 if( tcp->ce_time < mintime && !(tcp->ce_attr & A_SILENT0x00002) ) {
1028 Warning( "Target [%s] was made but the time stamp has not been updated.",
1029 tcp->CE_NAMEce_name->ht_name );
1030 }
1031
1032 /* The target was made, remove the temp files now. */
1033 Unlink_temp_files( tcp );
1034 tcp->ce_flag |= F_MADE0x8000;
1035 tcp->ce_attr |= A_UPDATED0x800000;
1036 }
1037
1038 /* Scan the list of prerequisites and if we find one that is
1039 * marked as being removable, (ie. an inferred intermediate node)
1040 * then remove it. We remove a prerequisite by running the recipe
1041 * associated with the special target .REMOVE.
1042 * Typically .REMOVE is defined in the startup file as:
1043 * .REMOVE :; $(RM) $<
1044 * with $< being the list of prerequisites specified in the current
1045 * target. (Make() sets $< .) */
1046
1047 /* Make sure we don't try to remove prerequisites for the .REMOVE
1048 * target. */
1049 if( strcmp(cp->CE_NAMEce_name->ht_name,".REMOVE") != 0 &&
1050 (hp = Get_name(".REMOVE", Defs, FALSE0)) != NIL(HASH)((HASH*)((void*)0)) ) {
1051 register LINKPTR dp;
1052 int flag = FALSE0;
1053 int rem;
1054 t_attr attr;
1055
1056 tcp = hp->CP_OWNRvar.val.ht.ht_owner;
1057
1058 /* The .REMOVE target is re-used. Remove old prerequisites. */
1059 tcp->ce_flag |= F_TARGET0x0008;
1060 Clear_prerequisites( tcp );
1061
1062 for(dp=cp->ce_prq; dp != NIL(LINK)((LINK*)((void*)0)); dp=dp->cl_next) {
1063 register CELLPTR prq = dp->cl_prq;
1064
1065 attr = Glob_attr | prq->ce_attr;
1066 /* We seem to have problems here that F_MULTI subtargets get removed
1067 * that even though they are still needed because the A_PRECIOUS
1068 * was not propagated correctly. Solution: Don't remove subtargets, the
1069 * master target will be removed if is not needed. */
1070 rem = (prq->ce_flag & F_REMOVE0x1000) &&
1071 (prq->ce_flag & F_MADE0x8000 ) &&
1072 !(prq->ce_count ) && /* Don't remove F_MULTI subtargets. */
1073 !(prq->ce_attr & A_PHONY0x04000) &&
1074 !(attr & A_PRECIOUS0x00001);
1075
1076 /* remove if rem is != 0 */
1077 if(rem) {
1078 LINKPTR tdp;
1079
1080 /* Add the target plus all that are linked to it with the .UPDATEALL
1081 * attribute. */
1082 for(tdp=CeMeToo(prq)&((prq)->ce_all); tdp; tdp=tdp->cl_next) {
1083 CELLPTR tmpcell=tdp->cl_prq;
1084
1085 (Add_prerequisite(tcp,tmpcell,FALSE0,FALSE0))->cl_flag|=F_TARGET0x0008;
1086 tmpcell->ce_flag &= ~F_REMOVE0x1000;
1087 }
1088 flag = TRUE1;
1089 }
1090 }
1091
1092 if( flag ) {
1093 int sv_force = Force;
1094
1095 Force = FALSE0;
1096 Remove_prq( tcp );
1097 Force = sv_force;
1098
1099 for(dp=tcp->ce_prq; dp != NIL(LINK)((LINK*)((void*)0)); dp=dp->cl_next) {
1100 register CELLPTR prq = dp->cl_prq;
1101
1102 prq->ce_flag &= ~(F_MADE0x8000|F_VISITED0x0080|F_STAT0x0040);
1103 prq->ce_flag |= F_REMOVE0x1000;
1104 prq->ce_time = (time_t)0L;
1105 }
1106 }
1107 }
1108}
1109
1110
1111PUBLIC int
1112Remove_file( name )
1113char *name;
1114{
1115 struct stat buf;
1116
1117 if( stat(name, &buf) != 0 )
1118 return 1;
1119 if( (buf.st_mode & S_IFMT0170000) == S_IFDIR0040000 )
1120 return 1;
1121 return(unlink(name));
1122}
1123
1124
1125#if defined(__CYGWIN__)
1126char *
1127cygdospath(char *src, int winpath)/*
1128====================================
1129 Convert to DOS path if winpath is true. The returned pointer is
1130 either the original pointer or a pointer to a static buffer.
1131*/
1132{
1133 static char *buf = NIL(char)((char*)((void*)0));
1134
1135 if ( !buf && ( (buf = MALLOC( PATH_MAX, char)(char*) malloc((unsigned int)(4096)*(size_t)sizeof(char))) == NIL(char)((char*)((void*)0)) ) )
1136 No_ram();
1137
1138 DB_PRINT( "cygdospath", ("converting [%s] with winpath [%d]", src, winpath ) );
1139
1140 /* Return immediately on NULL pointer or when .WINPATH is
1141 * not set. */
1142 if( !src || !winpath )
1143 return src;
1144
1145 if( *src && src[0] == '/' ) {
1146 char *tmp;
1147 int err = cygwin_conv_to_win32_path(src, buf);
1148 if (err)
1149 Fatal( "error converting \"%s\" - %s\n",
1150 src, strerror (errno(*__errno_location ())));
1151
1152 tmp = buf;
1153 while ((tmp = strchr (tmp, '\\')) != NULL((void*)0)) {
1154 *tmp = '/';
1155 tmp++;
1156 }
1157
1158 return buf;
1159 }
1160 else
1161 return src;
1162}
1163#endif