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