1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25 /*
26 * @(#)rep.cc 1.25 06/12/12
27 */
28
29 #pragma ident "@(#)rep.cc 1.25 06/12/12"
30
31 /*
32 * rep.c
33 *
34 * This file handles the .nse_depinfo file
35 */
36
37 /*
38 * Included files
39 */
40 #include <mk/defs.h>
41 #include <mksh/misc.h> /* retmem() */
42 #include <vroot/report.h> /* NSE_DEPINFO */
43
44 /*
45 * Static variables
46 */
47 static Recursive_make recursive_list;
48 static Recursive_make *bpatch = &recursive_list;
49 static Boolean changed;
50
51 /*
52 * File table of contents
53 */
54
55
56 /*
57 * report_recursive_init()
58 *
59 * Read the .nse_depinfo file and make a list of all the
60 * .RECURSIVE entries.
61 *
62 * Parameters:
63 *
64 * Static variables used:
65 * bpatch Points to slot where next cell should be added
66 *
67 * Global variables used:
68 * recursive_name The Name ".RECURSIVE", compared against
69 */
70
71 void
72 report_recursive_init(void)
73 {
74 char *search_dir;
75 char nse_depinfo[MAXPATHLEN];
76 FILE *fp;
77 int line_size, line_index;
78 wchar_t *line;
79 wchar_t *bigger_line;
80 wchar_t *colon;
81 wchar_t *dollar;
82 Recursive_make rp;
83
84 /*
85 * This routine can be called more than once, don't do
86 * anything after the first time.
87 */
88 if (depinfo_already_read) {
89 return;
90 } else {
91 depinfo_already_read = true;
92 }
93
94 search_dir = getenv(NOCATGETS("NSE_DEP"));
95 if (search_dir == NULL) {
96 return;
97 }
98 (void) sprintf(nse_depinfo, "%s/%s", search_dir, NSE_DEPINFO);
99 fp = fopen(nse_depinfo, "r");
100 if (fp == NULL) {
101 return;
102 }
103 line_size = MAXPATHLEN;
104 line_index = line_size - 1;
105 line = ALLOC_WC(line_size);
106 Wstring rns(recursive_name);
107 wchar_t * wcb = rns.get_string();
108 while (fgetws(line, line_size, fp) != NULL) {
109 while (wslen(line) == line_index) {
110 if (line[wslen(line) - 1] == '\n') {
111 continue;
112 }
113 bigger_line = ALLOC_WC(2 * line_size);
114 wscpy(bigger_line, line);
115 retmem(line);
116 line = bigger_line;
117 if (fgetws(&line[line_index], line_size, fp) == NULL)
118 continue;
119 line_index = 2 * line_index;
120 line_size = 2 * line_size;
121 }
122
123 colon = (wchar_t *) wschr(line, (int) colon_char);
124 if (colon == NULL) {
125 continue;
126 }
127 dollar = (wchar_t *) wschr(line, (int) dollar_char);
128 line[wslen(line) - 1] = (int) nul_char;
129 if (IS_WEQUALN(&colon[2], wcb,
130 (int) recursive_name->hash.length)) {
131 /*
132 * If this entry is an old entry, ignore it
133 */
134 MBSTOWCS(wcs_buffer, DEPINFO_FMT_VERSION);
135 if (dollar == NULL ||
136 !IS_WEQUALN(wcs_buffer, (dollar+1) - VER_LEN, VER_LEN)){
137 continue;
138 }
139 rp = ALLOC(Recursive_make);
140 (void) memset((char *) rp, 0, sizeof (Recursive_make_rec));
141 /*
142 * set conditional_macro_string if string is present
143 */
144 rp->oldline = (wchar_t *) wsdup(line);
145 if ( dollar != NULL ){
146 rp->cond_macrostring =
147 (wchar_t *) wsdup(dollar - VER_LEN + 1);
148 }
149 /*
150 * get target name into recursive struct
151 */
152 *colon = (int) nul_char;
153 rp->target = (wchar_t *) wsdup(line);
154 *bpatch = rp;
155 bpatch = &rp->next;
156 }
157 }
158 (void) fclose(fp);
159 }
160
161 /*
162 * report_recursive_dep(target, line)
163 *
164 * Report a target as recursive.
165 *
166 * Parameters:
167 * line Dependency line reported
168 *
169 * Static variables used:
170 * bpatch Points to slot where next cell should be added
171 * changed Written if report set changed
172 */
173 void
174 report_recursive_dep(Name target, wchar_t *line)
175 {
176 Recursive_make rp;
177 wchar_t rec_buf[STRING_BUFFER_LENGTH];
178 String_rec string;
179
180 INIT_STRING_FROM_STACK(string, rec_buf);
181 cond_macros_into_string(target, &string);
182 /*
183 * find an applicable recursive entry, if there isn't one, create it
184 */
185 rp = find_recursive_target(target);
186 if (rp == NULL) {
187 rp = ALLOC(Recursive_make);
188 (void) memset((char *) rp, 0, sizeof (Recursive_make_rec));
189 wchar_t * wcb = get_wstring(target->string_mb); // XXX Tolik: needs retmem
190 rp->target = wcb;
191 rp->newline = (wchar_t *) wsdup(line);
192 rp->cond_macrostring = (wchar_t *) wsdup(rec_buf);
193 *bpatch = rp;
194 bpatch = &rp->next;
195 changed = true;
196 } else {
197 if ((rp->oldline != NULL) && !IS_WEQUAL(rp->oldline, line)) {
198 rp->newline = (wchar_t *) wsdup(line);
199 changed = true;
200 }
201 rp->removed = false;
202 }
203 }
204
205 /*
206 * find_recursive_target(target)
207 *
208 * Search the list for a given target.
209 *
210 * Return value:
211 * The target cell
212 *
213 * Parameters:
214 * target The target we need
215 * top_level_target more info used to determinde the
216 * target we need
217 *
218 * Static variables used:
219 * recursive_list The list of targets
220 */
221 Recursive_make
222 find_recursive_target(Name target)
223 {
224 Recursive_make rp;
225 String_rec string;
226 wchar_t rec_buf[STRING_BUFFER_LENGTH];
227
228 INIT_STRING_FROM_STACK(string, rec_buf);
229 cond_macros_into_string(target, &string);
230
231 Wstring tstr(target);
232 wchar_t * wcb = tstr.get_string();
233 for (rp = recursive_list; rp != NULL; rp = rp->next) {
234 /*
235 * If this entry has already been removed, ignore it.
236 */
237 if (rp->removed)
238 continue;
239 /*
240 * If this target, and the target on the list are the same
241 * and if one of them contains conditional macro info, while
242 * the other doesn't, remove this entry from the list of
243 * recursive entries. This can only happen if the Makefile
244 * has changed to no longer contain conditional macros.
245 */
246 if (IS_WEQUAL(rp->target, wcb)) {
247 if (rp->cond_macrostring[VER_LEN] == '\0' &&
248 string.buffer.start[VER_LEN] != '\0'){
249 rp->removed = true;
250 continue;
251 } else if (rp->cond_macrostring[VER_LEN] != '\0' &&
252 string.buffer.start[VER_LEN] == '\0'){
253 rp->removed = true;
254 continue;
255 }
256 }
257 /*
258 * If this is not a VERS2 entry, only need to match
259 * the target name. toptarg information from VERS1 entries
260 * are ignored.
261 */
262 MBSTOWCS(wcs_buffer, DEPINFO_FMT_VERSION);
263 if (IS_WEQUALN(wcs_buffer, string.buffer.start, VER_LEN)) {
264 if (IS_WEQUAL(rp->cond_macrostring,
265 string.buffer.start) &&
266 IS_WEQUAL(rp->target, wcb)) {
267 return rp;
268 }
269 } else {
270 if (IS_WEQUAL(rp->target, wcb)) {
271 return rp;
272 }
273 }
274 }
275 return NULL;
276 }
277
278 /*
279 * remove_recursive_dep(target, top_level_target)
280 *
281 * Mark a target as no longer recursive.
282 *
283 * Parameters:
284 * target The target we want to remove
285 * top_level_target target we want to remove must be built from
286 * the same top level target
287 *
288 * Static variables used:
289 * changed Written if report set changed
290 */
291 void
292 remove_recursive_dep(Name target)
293 {
294 Recursive_make rp;
295
296 rp = find_recursive_target(target);
297
298 if ( rp != NULL ) {
299 rp->removed = true;
300 changed = true;
301 if(rp->target) {
302 retmem(rp->target);
303 rp->target = NULL;
304 }
305 if(rp->newline) {
306 retmem(rp->newline);
307 rp->newline = NULL;
308 }
309 if(rp->oldline) {
310 retmem(rp->oldline);
311 rp->oldline = NULL;
312 }
313 if(rp->cond_macrostring) {
314 retmem(rp->cond_macrostring);
315 rp->cond_macrostring = NULL;
316 }
317 }
318 }
319
320 #ifdef NSE
321 /*
322 * report_recursive_done()
323 *
324 * Write the .nse_depinfo file.
325 *
326 * Parameters:
327 *
328 * Static variables used:
329 * recursive_list The list of targets
330 * changed Written if report set changed
331 *
332 * Global variables used:
333 * recursive_name The Name ".RECURSIVE", compared against
334 */
335 void
336 report_recursive_done(void)
337 {
338 char *search_dir;
339 char nse_depinfo[MAXPATHLEN];
340 char tmpfile[MAXPATHLEN];
341 FILE *ofp;
342 FILE *ifp;
343 wchar_t *space;
344 wchar_t *data;
345 wchar_t *line;
346 wchar_t *bigger_line;
347 int line_size, line_index;
348 int lock_err;
349 Recursive_make rp;
350
351 if (changed == false) {
352 return;
353 }
354
355 search_dir = getenv(NOCATGETS("NSE_DEP"));
356 if (search_dir == NULL) {
357 return;
358 }
359 (void) sprintf(nse_depinfo, "%s/%s", search_dir, NSE_DEPINFO);
360 (void) sprintf(tmpfile, "%s.%d", nse_depinfo, getpid());
361 ofp = fopen(tmpfile, "w");
362 if (ofp == NULL) {
363 (void) fprintf(stderr,
364 catgets(catd, 1, 116, "Cannot open `%s' for writing\n"),
365 tmpfile);
366 return;
367 }
368 (void) sprintf(nse_depinfo_lockfile,
369 "%s/%s", search_dir, NSE_DEPINFO_LOCK);
370 if (lock_err = file_lock(nse_depinfo,
371 nse_depinfo_lockfile,
372 (int *) &nse_depinfo_locked, 0)) {
373 (void) fprintf(stderr,
374 catgets(catd, 1, 117, "writing .RECURSIVE lines to %s\n"),
375 tmpfile);
376 (void) fprintf(stderr,
377 catgets(catd, 1, 118, "To recover, merge .nse_depinfo.%d with .nse_depinfo\n"),
378 getpid(),
379 catgets(catd, 1, 119, "with .nse_depinfo"));
380 }
381
382 if (nse_depinfo_locked) {
383 ifp = fopen(nse_depinfo, "r");
384 if (ifp != NULL) {
385 /*
386 * Copy all the non-.RECURSIVE lines from
387 * the old file to the new one.
388 */
389 line_size = MAXPATHLEN;
390 line_index = line_size - 1;
391 line = ALLOC_WC(line_size);
392 while (fgetws(line, line_size, ifp) != NULL) {
393 while (wslen(line) == line_index) {
394 if (line[wslen(line) - 1] == '\n') {
395 continue;
396 }
397 bigger_line = ALLOC_WC(2 * line_size);
398 wscpy(bigger_line, line);
399 retmem(line);
400 line = bigger_line;
401 if (fgetws(&line[line_index],
402 line_size, ifp) == NULL)
403 continue;
404 line_index = 2 * line_index;
405 line_size = 2 * line_size;
406 }
407
408 space = wschr(line, (int) space_char);
409 if (space != NULL &&
410 IS_WEQUALN(&space[1],
411 recursive_name->string,
412 (int) recursive_name->hash.length)) {
413 continue;
414 }
415 WCSTOMBS(mbs_buffer, line);
416 (void) fprintf(ofp, "%s", mbs_buffer);
417 }
418 (void) fclose(ifp);
419 }
420 }
421
422 /*
423 * Write out the .RECURSIVE lines.
424 */
425 for (rp = recursive_list; rp != NULL; rp = rp->next) {
426 if (rp->removed) {
427 continue;
428 }
429 if (rp->newline != NULL) {
430 data = rp->newline;
431 } else {
432 data = rp->oldline;
433 }
434 if (data != NULL) {
435 WCSTOMBS(mbs_buffer, data);
436 (void) fprintf(ofp, "%s\n", mbs_buffer);
437 }
438 }
439 (void) fclose(ofp);
440
441 if (nse_depinfo_locked) {
442 (void) rename(tmpfile, nse_depinfo);
443 (void) unlink(nse_depinfo_lockfile);
444 nse_depinfo_locked = false;
445 nse_depinfo_lockfile[0] = '\0';
446 (void) chmod(nse_depinfo, 0666);
447 }
448 }
449 #endif // NSE
450
451 /* gather_recursive_deps()
452 *
453 * Create or update list of recursive targets.
454 */
455 void
456 gather_recursive_deps(void)
457 {
458 Name_set::iterator np, e;
459 String_rec rec;
460 wchar_t rec_buf[STRING_BUFFER_LENGTH];
461 register Property lines;
462 Boolean has_recursive;
463 Dependency dp;
464
465 report_recursive_init();
466
467 /* Go thru all targets and dump recursive dependencies */
468 for (np = hashtab.begin(), e = hashtab.end(); np != e; np++) {
469 if (np->has_recursive_dependency){
470 has_recursive = false;
471 /*
472 * start .RECURSIVE line with target:
473 */
474 INIT_STRING_FROM_STACK(rec, rec_buf);
475 APPEND_NAME(np, &rec, FIND_LENGTH);
476 append_char((int) colon_char, &rec);
477 append_char((int) space_char, &rec);
478
479 for (lines = get_prop(np->prop,recursive_prop);
480 lines != NULL;
481 lines = get_prop(lines->next, recursive_prop)) {
482 /*
483 * if entry is already in depinfo
484 * file or entry was not built, ignore it
485 */
486 if (lines->body.recursive.in_depinfo)
487 continue;
488 if (!lines->body.recursive.has_built)
489 continue;
490 has_recursive = true;
491 lines->body.recursive.in_depinfo=true;
492
493 /*
494 * Write the remainder of the
495 * .RECURSIVE line
496 */
497 APPEND_NAME(recursive_name, &rec,
498 FIND_LENGTH);
499 append_char((int) space_char, &rec);
500 APPEND_NAME(lines->body.recursive.directory,
501 &rec, FIND_LENGTH);
502 append_char((int) space_char, &rec);
503 APPEND_NAME(lines->body.recursive.target,
504 &rec, FIND_LENGTH);
505 append_char((int) space_char, &rec);
506
507 /* Complete list of makefiles used */
508 for (dp = lines->body.recursive.makefiles;
509 dp != NULL;
510 dp = dp->next) {
511 APPEND_NAME(dp->name, &rec, FIND_LENGTH);
512 append_char((int) space_char, &rec);
513 }
514 }
515 /*
516 * dump list of conditional targets,
517 * and report recursive entry, if needed
518 */
519 cond_macros_into_string(np, &rec);
520 if (has_recursive){
521 report_recursive_dep(np, rec.buffer.start);
522 }
523
524 } else if ( np->has_built ) {
525 remove_recursive_dep(np);
526 }
527 }
528 }
529