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