4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
29 * This file contains the routines that write the .make.state file
36 #include <mksh/misc.h> /* errmsg() */
37 #include <setjmp.h> /* setjmp() */
38 #include <unistd.h> /* getpid() */
39 #include <errno.h> /* errno */
40 #include <locale.h> /* MB_CUR_MAX */
45 #define LONGJUMP_VALUE 17
46 #define XFWRITE(string, length, fd) {if (fwrite(string, 1, length, fd) == 0) \
47 longjmp(long_jump, LONGJUMP_VALUE);}
48 #define XPUTC(ch, fd) { \
49 if (putc((int) ch, fd) == EOF) \
50 longjmp(long_jump, LONGJUMP_VALUE); \
52 #define XFPUTS(string, fd) fputs(string, fd)
63 * File table of contents
65 static char * escape_target_name(Name np
)
68 int len
= strlen(np
->string_mb
);
69 char * buff
= (char*)malloc(2 * len
);
74 int n
= mbtowc(&wc
, np
->string_mb
+ pos
, MB_CUR_MAX
);
75 if(n
< 0) { // error - this shouldn't happen
77 return strdup(np
->string_mb
);
79 if(wc
== dollar_char
) {
80 buff
[pp
] = '\\'; pp
++;
83 for(int j
=0;j
<n
;j
++) {
84 buff
[pp
] = np
->string_mb
[pos
+j
]; pp
++;
92 return strdup(np
->string_mb
);
96 static void print_auto_depes(register Dependency dependency
, register FILE *fd
, register Boolean built_this_run
, register int *line_length
, register char *target_name
, jmp_buf long_jump
);
99 * write_state_file(report_recursive, exiting)
101 * Write a new version of .make.state
104 * report_recursive Should only be done at end of run
105 * exiting true if called from the exit handler
107 * Global variables used:
108 * built_last_make_run The Name ".BUILT_LAST_MAKE_RUN", written
109 * command_changed If no command changed we do not need to write
110 * current_make_version The Name "<current version>", written
111 * do_not_exec_rule If -n is on we do not write statefile
112 * hashtab The hashtable that contains all names
113 * keep_state If .KEEP_STATE is no on we do not write file
114 * make_state The Name ".make.state", used for opening file
115 * make_version The Name ".MAKE_VERSION", written
116 * recursive_name The Name ".RECURSIVE", written
117 * rewrite_statefile Indicates that something changed
121 write_state_file(int, Boolean exiting
)
125 char buffer
[MAXPATHLEN
];
126 char make_state_tempfile
[MAXPATHLEN
];
128 register int attempts
= 0;
129 Name_set::iterator np
, e
;
130 register Property lines
;
132 Dependency dependency
;
133 register Boolean name_printed
;
134 Boolean built_this_run
= false;
137 register Cmd_line cp
;
140 if (!rewrite_statefile
||
144 (report_dependencies_level
> 0)) {
147 /* Lock the file for writing. */
148 make_state_lockfile
= getmem(strlen(make_state
->string_mb
) + strlen(".lock") + 1);
149 (void) sprintf(make_state_lockfile
,
151 make_state
->string_mb
);
152 if (lock_err
= file_lock(make_state
->string_mb
,
154 (int *) &make_state_locked
, 0)) {
155 retmem_mb(make_state_lockfile
);
156 make_state_lockfile
= NULL
;
159 * We need to make sure that we are not being
160 * called by the exit handler so we don't call
165 (void) sprintf(buffer
, "%s/.make.state.%d.XXXXXX", tmpdir
, getpid());
167 warning(gettext("Writing to %s"), buffer
);
168 int fdes
= mkstemp(buffer
);
169 if ((fdes
< 0) || (fd
= fdopen(fdes
, "w")) == NULL
) {
171 gettext("Could not open statefile `%s': %s"),
178 fatal(gettext("Can't lock .make.state"));
182 (void) sprintf(make_state_tempfile
,
184 make_state
->string_mb
);
185 /* Delete old temporary statefile (in case it exists) */
186 (void) unlink(make_state_tempfile
);
187 if ((fd
= fopen(make_state_tempfile
, "w")) == NULL
) {
188 lock_err
= errno
; /* Save it! unlink() can change errno */
189 (void) unlink(make_state_lockfile
);
190 retmem_mb(make_state_lockfile
);
191 make_state_lockfile
= NULL
;
192 make_state_locked
= false;
193 fatal(gettext("Could not open temporary statefile `%s': %s"),
198 * Set a trap for failed writes. If a write fails, the routine
199 * will try saving the .make.state file under another name in /tmp.
201 if (setjmp(long_jump
)) {
203 if (attempts
++ > 5) {
204 if ((make_state_lockfile
!= NULL
) &&
206 (void) unlink(make_state_lockfile
);
207 retmem_mb(make_state_lockfile
);
208 make_state_lockfile
= NULL
;
209 make_state_locked
= false;
211 fatal(gettext("Giving up on writing statefile"));
214 (void) sprintf(buffer
, "%s/.make.state.%d.XXXXXX", tmpdir
, getpid());
215 int fdes
= mkstemp(buffer
);
216 if ((fdes
< 0) || (fd
= fdopen(fdes
, "w")) == NULL
) {
217 fatal(gettext("Could not open statefile `%s': %s"),
221 warning(gettext("Initial write of statefile failed. Trying again on %s"),
225 /* Write the version stamp. */
226 XFWRITE(make_version
->string_mb
,
227 strlen(make_version
->string_mb
),
229 XPUTC(colon_char
, fd
);
231 XFWRITE(current_make_version
->string_mb
,
232 strlen(current_make_version
->string_mb
),
234 XPUTC(newline_char
, fd
);
237 * Go through all the targets, dump their dependencies and
240 for (np
= hashtab
.begin(), e
= hashtab
.end(); np
!= e
; np
++) {
242 * If the target has no command used nor dependencies,
243 * we can go to the next one.
245 if ((lines
= get_prop(np
->prop
, line_prop
)) == NULL
) {
248 /* If this target is a special target, don't print. */
249 if (np
->special_reader
!= no_special
) {
253 * Find out if any of the targets dependencies should
254 * be written to .make.state.
256 for (m
= 0, dependency
= lines
->body
.line
.dependencies
;
258 dependency
= dependency
->next
) {
259 if (m
= !dependency
->stale
260 && (dependency
->name
!= force
)
261 #ifndef PRINT_EXPLICIT_DEPEN
262 && dependency
->automatic
268 /* Only print if dependencies listed. */
269 if (m
|| (lines
->body
.line
.command_used
!= NULL
)) {
270 name_printed
= false;
272 * If this target was built during this make run,
275 built_this_run
= false;
277 built_this_run
= true;
278 XFWRITE(built_last_make_run
->string_mb
,
279 strlen(built_last_make_run
->string_mb
),
281 XPUTC(colon_char
, fd
);
282 XPUTC(newline_char
, fd
);
284 /* If the target has dependencies, we dump them. */
285 target_name
= escape_target_name(np
);
286 if (np
->has_long_member_name
) {
288 get_prop(np
->prop
, long_member_name_prop
)
289 ->body
.long_member_name
.member_name
->
293 XFPUTS(target_name
, fd
);
294 XPUTC(colon_char
, fd
);
299 lines
->body
.line
.dependencies
;
301 dependency
= dependency
->next
) {
302 print_auto_depes(dependency
,
311 /* If there is a command used, we dump it. */
312 if (lines
->body
.line
.command_used
!= NULL
) {
314 * Only write the target name if it
315 * wasn't done for the dependencies.
318 XFPUTS(target_name
, fd
);
319 XPUTC(colon_char
, fd
);
320 XPUTC(newline_char
, fd
);
323 * Write the command lines.
324 * Prefix each textual line with a tab.
326 for (cp
= lines
->body
.line
.command_used
;
333 if (cp
->command_line
!= NULL
) {
344 (int) newline_char
) {
350 XPUTC(newline_char
, fd
);
353 (void)free(target_name
);
356 if (fclose(fd
) == EOF
) {
357 longjmp(long_jump
, LONGJUMP_VALUE
);
360 if (unlink(make_state
->string_mb
) != 0 && errno
!= ENOENT
) {
361 lock_err
= errno
; /* Save it! unlink() can change errno */
362 /* Delete temporary statefile */
363 (void) unlink(make_state_tempfile
);
364 (void) unlink(make_state_lockfile
);
365 retmem_mb(make_state_lockfile
);
366 make_state_lockfile
= NULL
;
367 make_state_locked
= false;
368 fatal(gettext("Could not delete old statefile `%s': %s"),
369 make_state
->string_mb
,
372 if (rename(make_state_tempfile
, make_state
->string_mb
) != 0) {
373 lock_err
= errno
; /* Save it! unlink() can change errno */
374 /* Delete temporary statefile */
375 (void) unlink(make_state_tempfile
);
376 (void) unlink(make_state_lockfile
);
377 retmem_mb(make_state_lockfile
);
378 make_state_lockfile
= NULL
;
379 make_state_locked
= false;
380 fatal(gettext("Could not rename `%s' to `%s': %s"),
382 make_state
->string_mb
,
386 if ((make_state_lockfile
!= NULL
) && make_state_locked
) {
387 (void) unlink(make_state_lockfile
);
388 retmem_mb(make_state_lockfile
);
389 make_state_lockfile
= NULL
;
390 make_state_locked
= false;
395 * print_auto_depes(dependency, fd, built_this_run,
396 * line_length, target_name, long_jump)
398 * Will print a dependency list for automatic entries.
401 * dependency The dependency to print
402 * fd The file to print it to
403 * built_this_run If on we prefix each line with .BUILT_THIS...
404 * line_length Pointer to line length var that we update
405 * target_name We need this when we restart line
406 * long_jump setjmp/longjmp buffer used for IO error action
408 * Global variables used:
409 * built_last_make_run The Name ".BUILT_LAST_MAKE_RUN", written
410 * force The Name " FORCE", compared against
413 print_auto_depes(register Dependency dependency
, register FILE *fd
, register Boolean built_this_run
, register int *line_length
, register char *target_name
, jmp_buf long_jump
)
415 if (!dependency
->automatic
||
417 (dependency
->name
== force
)) {
420 XFWRITE(dependency
->name
->string_mb
,
421 strlen(dependency
->name
->string_mb
),
424 * Check if the dependency line is too long.
425 * If so, break it and start a new one.
427 if ((*line_length
+= (int) strlen(dependency
->name
->string_mb
) + 1) > 450) {
429 XPUTC(newline_char
, fd
);
430 if (built_this_run
) {
431 XFPUTS(built_last_make_run
->string_mb
, fd
);
432 XPUTC(colon_char
, fd
);
433 XPUTC(newline_char
, fd
);
435 XFPUTS(target_name
, fd
);
436 XPUTC(colon_char
, fd
);