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