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 /* 23 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/stat.h> 28 #include <sys/mman.h> 29 #include <fcntl.h> 30 #include <stdio.h> 31 #include <string.h> 32 #include <unistd.h> 33 #include <errno.h> 34 #include <limits.h> 35 #include "sgs.h" 36 #include "rtc.h" 37 #include "conv.h" 38 #include "_crle.h" 39 #include "msg.h" 40 41 42 /* 43 * Display the command line required to regenerate the configuration file. 44 * 45 * Under normal mode the command is printed on one line to make it more 46 * available for grep(1) use. Under verbose mode the command is separated 47 * into each argument (a little more readable perhaps when the arguments are 48 * numerous of have long pathnames). 49 * 50 * Note that for version 1 configuration files we never used to generate any 51 * command-line information, and as the attempt to do so is only a best effort 52 * don't bother printing anything. 53 */ 54 static void 55 printcmd(Crle_desc *crle, Rtc_head * head, APlist *cmdline) 56 { 57 Aliste idx, lidx; 58 const char *fmto, *fmtb, *fmtm, *fmte; 59 char *cmd; 60 int output = 0; 61 62 if (crle->c_flags & CRLE_VERBOSE) { 63 fmto = MSG_INTL(MSG_DMP_CMD_ONE_V); 64 fmtb = MSG_INTL(MSG_DMP_CMD_BGN_V); 65 fmtm = MSG_INTL(MSG_DMP_CMD_MID_V); 66 fmte = MSG_INTL(MSG_DMP_CMD_END_V); 67 68 } else if (head->ch_version > RTC_VER_ONE) { 69 fmto = MSG_INTL(MSG_DMP_CMD_ONE); 70 fmtb = MSG_INTL(MSG_DMP_CMD_BGN); 71 fmtm = MSG_INTL(MSG_DMP_CMD_MID); 72 fmte = MSG_INTL(MSG_DMP_CMD_END); 73 74 } else { 75 (void) printf(MSG_ORIG(MSG_STR_NL)); 76 return; 77 } 78 79 (void) printf(MSG_INTL(MSG_DMP_CMD_TITLE)); 80 81 lidx = aplist_nitems(cmdline) - 1; 82 for (APLIST_TRAVERSE(cmdline, idx, cmd)) { 83 if (output++ == 0) { 84 if (idx < lidx) 85 (void) printf(fmtb, cmd); 86 else 87 (void) printf(fmto, cmd); 88 } else { 89 if (idx < lidx) 90 (void) printf(fmtm, cmd); 91 else 92 (void) printf(fmte, cmd); 93 } 94 } 95 } 96 97 /* 98 * Establish the argument required to generate the associated object. 99 */ 100 static const char * 101 getformat(Half flags) 102 { 103 if (flags & RTC_OBJ_ALTER) { 104 if (flags & RTC_OBJ_DUMP) { 105 if (flags & RTC_OBJ_GROUP) 106 return (MSG_ORIG(MSG_CMD_DUMPGRP)); 107 else 108 return (MSG_ORIG(MSG_CMD_DUMPIND)); 109 } else { 110 if (flags & RTC_OBJ_OPTINAL) 111 return (MSG_ORIG(MSG_CMD_OPTIONAL)); 112 else 113 return (MSG_ORIG(MSG_CMD_ALTER)); 114 } 115 } else { 116 if (flags & RTC_OBJ_GROUP) 117 return (MSG_ORIG(MSG_CMD_GRP)); 118 else 119 return (MSG_ORIG(MSG_CMD_IND)); 120 } 121 } 122 123 /* 124 * Fabricate a system default search path. If an update is requested, and 125 * new search paths are specified while no configuration file exists, or if a 126 * configuration file does exist but doesn't specify this particular search 127 * path, create any system defaults. The intent is to allow 128 * "crle -u -l/usr/local/lib" and have this append the search path to the 129 * system default, rather than have the user have to determine and specify 130 * this default themselves. 131 */ 132 static int 133 fablib(Crle_desc * crle, int flag) 134 { 135 const char *path; 136 char **list; 137 138 switch (flag) { 139 case CRLE_EDLIB: 140 #if M_CLASS == ELFCLASS64 141 path = MSG_ORIG(MSG_PTH_NEWDLP_64); 142 #else 143 path = MSG_ORIG(MSG_PTH_NEWDLP); 144 #endif 145 list = &crle->c_edlibpath; 146 break; 147 148 case CRLE_ESLIB: 149 #if M_CLASS == ELFCLASS64 150 path = MSG_ORIG(MSG_PTH_NEWTD_64); 151 #else 152 path = MSG_ORIG(MSG_PTH_NEWTD); 153 #endif 154 list = &crle->c_eslibpath; 155 break; 156 157 default: 158 return (1); 159 } 160 161 return (addlib(crle, list, path)); 162 } 163 164 /* 165 * Establish the flags required to generate the associated object. Actually 166 * the flags are already part of the object being inspected from the present 167 * configuration file, but instead of using them all, which can cause some 168 * unsuspected propagation down the inspect() family, only use those flags that 169 * would have been contributed from crle()'s calls to inspect. 170 */ 171 static Half 172 getflags(Half flags) 173 { 174 flags &= 175 (RTC_OBJ_ALTER | RTC_OBJ_DUMP | RTC_OBJ_GROUP | RTC_OBJ_OPTINAL); 176 return (flags | RTC_OBJ_CMDLINE); 177 } 178 179 /* 180 * Dump a configuration files information. This routine is very close to the 181 * scanconfig() in libcrle. 182 */ 183 /*ARGSUSED2*/ 184 static INSCFG_RET 185 scanconfig(Crle_desc * crle, Addr addr, int c_class) 186 { 187 Conv_inv_buf_t inv_buf1, inv_buf2, inv_buf3, inv_buf4; 188 Conv_dl_flag_buf_t dl_flag_buf; 189 Rtc_id *id; 190 Rtc_head *head; 191 Rtc_dir *dirtbl; 192 Rtc_file *filetbl; 193 Rtc_obj *objtbl, *obj; 194 Word *hash, *chain; 195 const char *strtbl; 196 int ndx, bkts; 197 APlist *cmdline = NULL; 198 boolean_t cmdset = B_FALSE; 199 char _cmd[PATH_MAX], *cmd; 200 char _objdir[PATH_MAX], *objdir = NULL; 201 202 /* 203 * If there is an Rtc_id present, the Rtc_head follows it. 204 * Otherwise, it is at the top. 205 */ 206 if (RTC_ID_TEST(addr)) { 207 id = (Rtc_id *) addr; 208 addr += sizeof (*id); /* Rtc_head follows */ 209 } else { 210 id = NULL; 211 /* 212 * When updating an existing config file that is lacking 213 * the Rtc_id block, don't put one into the resulting file. 214 */ 215 crle->c_flags &= ~CRLE_ADDID; 216 } 217 head = (Rtc_head *) addr; 218 219 220 /* 221 * The rest of the configuration file can only be examined by 222 * a program of the same ELFCLASS, byte order, and hardware 223 * architecture as the one that created it. 224 */ 225 #ifdef _ELF64 226 /* 64-bit program with an existing 32-bit file? Abort. */ 227 if (!(head->ch_cnflags & RTC_HDR_64)) { 228 (void) fprintf(stderr, MSG_INTL(MSG_ARG_CLASS), 229 crle->c_name, crle->c_confil); 230 return (INSCFG_RET_FAIL); 231 } 232 #else 233 /* 32-bit program with an existing 64-bit file? Restart. */ 234 if (head->ch_cnflags & RTC_HDR_64) 235 return (INSCFG_RET_NEED64); 236 237 /* 238 * 32-bit program with an existing 32-bit file, but the 239 * user specified the -64 option? Abort 240 */ 241 if (c_class != ELFCLASS32) { 242 (void) fprintf(stderr, MSG_INTL(MSG_ARG_CLASS), 243 crle->c_name, crle->c_confil); 244 return (INSCFG_RET_FAIL); 245 } 246 #endif 247 /* 248 * Now that the ELFCLASS has been settled, ensure that the 249 * byte order and hardware match. Unlike ELFCLASS, where restarting 250 * the other version is an option, we cannot work around a mismatch 251 * of these attributes. 252 */ 253 if (id) { /* Rtc_id is present */ 254 /* 255 * Was the file produced by compatible hardware? 256 * ELFCLASS doesn't matter here, because we can 257 * adjust for that, but byte order and machine type do. 258 */ 259 if ((id->id_data != M_DATA) || (id->id_machine != M_MACH)) { 260 (void) fprintf(stderr, MSG_INTL(MSG_ARG_WRONGARCH), 261 crle->c_name, crle->c_confil, 262 conv_ehdr_data(id->id_data, CONV_FMT_ALT_FILE, 263 &inv_buf1), 264 conv_ehdr_mach(id->id_machine, CONV_FMT_ALT_FILE, 265 &inv_buf2), 266 conv_ehdr_data(M_DATA, CONV_FMT_ALT_FILE, 267 &inv_buf3), 268 conv_ehdr_mach(M_MACH, CONV_FMT_ALT_FILE, 269 &inv_buf4)); 270 return (INSCFG_RET_FAIL); 271 } 272 } 273 274 275 /* LINTED */ 276 objtbl = (Rtc_obj *)(CAST_PTRINT(char *, head->ch_obj) + addr); 277 strtbl = (const char *)(CAST_PTRINT(char *, head->ch_str) + addr); 278 279 /* 280 * If the configuration file has a version higher than we 281 * recognise, we face two issues: 282 * (1) Updates are not possible because we have no 283 * way to recognise or propagate the new features. 284 * This has to be a fatal error. 285 * (2) Printing has the risk that we may have been 286 * handed something other than a real config file, as 287 * well as the fact that we can't display the information 288 * for the new features. So, we print a warning, but 289 * continue on to do the best we can with it. 290 */ 291 if (head->ch_version > RTC_VER_CURRENT) { 292 if (crle->c_flags & CRLE_UPDATE) { 293 (void) fprintf(stderr, MSG_INTL(MSG_ARG_UPDATEVER), 294 crle->c_name, crle->c_confil, 295 (int)head->ch_version, RTC_VER_CURRENT); 296 return (INSCFG_RET_FAIL); 297 } else { 298 (void) fprintf(stderr, MSG_INTL(MSG_ARG_PRINTVER), 299 crle->c_name, crle->c_confil, 300 (int)head->ch_version, RTC_VER_CURRENT); 301 } 302 } 303 304 /* 305 * If this is a version 1 configuration file we can't generate accurate 306 * update information, or the command-line used to create the file. 307 */ 308 if (head->ch_version == RTC_VER_ONE) { 309 (void) printf(MSG_INTL(MSG_ARG_UPDATE), crle->c_name, 310 crle->c_confil, (int)head->ch_version); 311 } 312 313 314 if (!(crle->c_flags & CRLE_UPDATE) && (head->ch_cnflags & RTC_HDR_64)) { 315 /* 316 * Construct the original command line argument. 317 */ 318 cmd = strdupa(MSG_ORIG(MSG_CMD_64)); 319 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL) 320 return (INSCFG_RET_FAIL); 321 } 322 323 324 /* 325 * Start analyzing the configuration files header information. 326 */ 327 if ((crle->c_flags & CRLE_UPDATE) == 0) { 328 const char *fmt; 329 330 if (head->ch_dlflags) 331 fmt = conv_dl_flag(head->ch_dlflags, 0, &dl_flag_buf); 332 else 333 fmt = MSG_ORIG(MSG_STR_EMPTY); 334 335 (void) printf(MSG_INTL(MSG_DMP_HEAD), (int)head->ch_version, 336 crle->c_confil, fmt); 337 338 /* 339 * If the file has an id block, show the information 340 */ 341 if (id) 342 (void) printf(MSG_INTL(MSG_DMP_PLATFORM), 343 conv_ehdr_class(id->id_class, CONV_FMT_ALT_FILE, 344 &inv_buf1), 345 conv_ehdr_data(id->id_data, CONV_FMT_ALT_FILE, 346 &inv_buf2), 347 conv_ehdr_mach(id->id_machine, CONV_FMT_ALT_FILE, 348 &inv_buf3)); 349 350 /* 351 * Construct the original command line argument. 352 */ 353 (void) snprintf(_cmd, PATH_MAX, MSG_ORIG(MSG_CMD_CONF), 354 crle->c_confil); 355 cmd = strdupa(_cmd); 356 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL) 357 return (INSCFG_RET_FAIL); 358 359 /* 360 * Construct any -f usage. 361 */ 362 if (head->ch_dlflags && 363 (head->ch_dlflags != RTLD_REL_RELATIVE)) { 364 (void) snprintf(_cmd, PATH_MAX, MSG_ORIG(MSG_CMD_FLAGS), 365 conv_dl_flag(head->ch_dlflags, CONV_FMT_ALT_CRLE, 366 &dl_flag_buf)); 367 cmd = strdupa(_cmd); 368 cmdset = B_TRUE; 369 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL) 370 return (INSCFG_RET_FAIL); 371 } 372 } else { 373 /* 374 * Establish any -f usage. 375 */ 376 if (head->ch_dlflags && 377 (head->ch_dlflags != RTLD_REL_RELATIVE)) 378 crle->c_dlflags = head->ch_dlflags; 379 } 380 381 382 /* 383 * Determine if this configuration file is only applicable to a specific 384 * application. 385 */ 386 if (head->ch_app) { 387 char *alter; 388 389 obj = (Rtc_obj *)(head->ch_app + addr); 390 391 /* 392 * Determine the output directory for the files 393 * alternative name. 394 */ 395 alter = (char *)(strtbl + obj->co_alter); 396 (void) strcpy(_objdir, alter); 397 alter = strrchr(_objdir, '/'); 398 *alter = '\0'; 399 400 crle->c_objdir = objdir = _objdir; 401 402 if (crle->c_flags & CRLE_UPDATE) { 403 if (inspect(crle, (strtbl + obj->co_name), 404 (RTC_OBJ_DUMP | RTC_OBJ_ALTER | 405 RTC_OBJ_GROUP | RTC_OBJ_CMDLINE)) != 0) 406 return (INSCFG_RET_FAIL); 407 } else { 408 (void) printf(MSG_INTL(MSG_DMP_APP), 409 (strtbl + obj->co_alter), (strtbl + obj->co_name)); 410 411 /* 412 * Construct the original command line arguments. 413 */ 414 cmdset = B_TRUE; 415 (void) snprintf(_cmd, PATH_MAX, 416 MSG_ORIG(MSG_CMD_OUTPUT), crle->c_objdir); 417 cmd = strdupa(_cmd); 418 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL) 419 return (INSCFG_RET_FAIL); 420 421 (void) snprintf(_cmd, PATH_MAX, 422 MSG_ORIG(MSG_CMD_DUMPGRP), (strtbl + obj->co_name)); 423 cmd = strdupa(_cmd); 424 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL) 425 return (INSCFG_RET_FAIL); 426 } 427 } 428 429 /* 430 * Analyze any alternative library path and trusted directory entries. 431 */ 432 if (head->ch_edlibpath) { 433 const char *str; 434 435 str = (const char *)(head->ch_edlibpath + addr); 436 437 if (crle->c_flags & CRLE_UPDATE) { 438 439 if ((head->ch_cnflags & RTC_HDR_UPM) == 0) { 440 if (head->ch_cnflags & RTC_HDR_64) 441 str = conv_config_upm(str, 442 MSG_ORIG(MSG_PTH_OLDDLP_64), 443 MSG_ORIG(MSG_PTH_UPDLP_64), 444 MSG_PTH_UPDLP_64_SIZE); 445 else 446 str = conv_config_upm(str, 447 MSG_ORIG(MSG_PTH_OLDDLP), 448 MSG_ORIG(MSG_PTH_UPDLP), 449 MSG_PTH_UPDLP_SIZE); 450 } 451 if (addlib(crle, &crle->c_edlibpath, str) != 0) 452 return (INSCFG_RET_FAIL); 453 } else { 454 (void) printf(MSG_INTL(MSG_DMP_DLIBPTH), 455 MSG_ORIG(MSG_STR_ELF), str); 456 457 (void) snprintf(_cmd, PATH_MAX, 458 MSG_ORIG(MSG_CMD_EDLIB), str); 459 cmd = strdupa(_cmd); 460 cmdset = B_TRUE; 461 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL) 462 return (INSCFG_RET_FAIL); 463 } 464 } else { 465 if (crle->c_flags & CRLE_UPDATE) { 466 if (crle->c_flags & CRLE_EDLIB) { 467 /* 468 * If we've been asked to update a configuration 469 * file, and no existing default ELF search 470 * path exists, but the user is going to add new 471 * entries, fabricate the system defaults so 472 * that the users get added to them. 473 */ 474 if (fablib(crle, CRLE_EDLIB) != 0) 475 return (INSCFG_RET_FAIL); 476 } 477 } else { 478 /* 479 * Indicate any system default. 480 */ 481 #if M_CLASS == ELFCLASS64 482 (void) printf(MSG_INTL(MSG_DEF_NEWDLP_64)); 483 #else 484 (void) printf(MSG_INTL(MSG_DEF_NEWDLP)); 485 #endif 486 } 487 } 488 489 if (head->ch_eslibpath) { 490 const char *str; 491 492 str = (const char *)(head->ch_eslibpath + addr); 493 494 if (crle->c_flags & CRLE_UPDATE) { 495 496 if ((head->ch_cnflags & RTC_HDR_UPM) == 0) { 497 if (head->ch_cnflags & RTC_HDR_64) 498 str = conv_config_upm(str, 499 MSG_ORIG(MSG_PTH_OLDTD_64), 500 MSG_ORIG(MSG_PTH_UPTD_64), 501 MSG_PTH_UPTD_64_SIZE); 502 else 503 str = conv_config_upm(str, 504 MSG_ORIG(MSG_PTH_OLDTD), 505 MSG_ORIG(MSG_PTH_UPTD), 506 MSG_PTH_UPTD_SIZE); 507 } 508 if (addlib(crle, &crle->c_eslibpath, str) != 0) 509 return (INSCFG_RET_FAIL); 510 } else { 511 (void) printf(MSG_INTL(MSG_DMP_TLIBPTH), 512 MSG_ORIG(MSG_STR_ELF), str); 513 514 (void) snprintf(_cmd, PATH_MAX, 515 MSG_ORIG(MSG_CMD_ESLIB), str); 516 cmd = strdupa(_cmd); 517 cmdset = B_TRUE; 518 if (aplist_append(&cmdline, cmd, AL_CNT_CRLE) == NULL) 519 return (INSCFG_RET_FAIL); 520 } 521 } else { 522 if (crle->c_flags & CRLE_UPDATE) { 523 if (crle->c_flags & CRLE_ESLIB) { 524 /* 525 * If we've been asked to update a configuration 526 * file, and no existing default ELF secure 527 * path exists, but the user is going to add new 528 * entries, fabricate the system defaults so 529 * that the users get added to them. 530 */ 531 if (fablib(crle, CRLE_ESLIB) != 0) 532 return (INSCFG_RET_FAIL); 533 } 534 } else { 535 /* 536 * Indicate any system default. 537 */ 538 #if M_CLASS == ELFCLASS64 539 (void) printf(MSG_INTL(MSG_DEF_NEWTD_64)); 540 #else 541 (void) printf(MSG_INTL(MSG_DEF_NEWTD)); 542 #endif 543 } 544 } 545 546 /* 547 * Display any environment variables. 548 */ 549 if ((head->ch_version >= RTC_VER_THREE) && head->ch_env) { 550 Rtc_env *envtbl; 551 552 if ((crle->c_flags & CRLE_UPDATE) == 0) 553 (void) printf(MSG_INTL(MSG_ENV_TITLE)); 554 555 for (envtbl = (Rtc_env *)(head->ch_env + addr); 556 envtbl->env_str; envtbl++) { 557 const char *str; 558 559 str = (const char *)(envtbl->env_str + addr); 560 561 if (crle->c_flags & CRLE_UPDATE) { 562 if (addenv(crle, str, 563 (envtbl->env_flags | RTC_ENV_CONFIG)) == 0) 564 return (INSCFG_RET_FAIL); 565 } else { 566 const char *pfmt, *sfmt; 567 568 if (envtbl->env_flags & RTC_ENV_PERMANT) { 569 pfmt = MSG_INTL(MSG_ENV_PRM); 570 sfmt = MSG_ORIG(MSG_CMD_PRMENV); 571 } else { 572 pfmt = MSG_INTL(MSG_ENV_RPL); 573 sfmt = MSG_ORIG(MSG_CMD_RPLENV); 574 } 575 (void) printf(pfmt, str); 576 (void) snprintf(_cmd, PATH_MAX, sfmt, str); 577 cmd = strdupa(_cmd); 578 cmdset = B_TRUE; 579 if (aplist_append(&cmdline, cmd, 580 AL_CNT_CRLE) == NULL) 581 return (INSCFG_RET_FAIL); 582 } 583 } 584 } 585 586 /* 587 * Display any filter/filtee associations. 588 */ 589 if ((head->ch_version >= RTC_VER_FOUR) && head->ch_fltr) { 590 if ((crle->c_flags & CRLE_UPDATE) == 0) { 591 Rtc_fltr *fltrtbl; 592 Rtc_flte *fltetbl; 593 594 /* LINTED */ 595 fltrtbl = (Rtc_fltr *) 596 (CAST_PTRINT(char *, head->ch_fltr) + addr); 597 /* LINTED */ 598 fltetbl = (Rtc_flte *) 599 (CAST_PTRINT(char *, head->ch_flte) + addr); 600 601 (void) printf(MSG_INTL(MSG_FLT_TITLE)); 602 603 while (fltrtbl->fr_filter) { 604 Rtc_flte *_fltetbl; 605 606 /* 607 * Print the filter and filtee string pair. 608 */ 609 (void) printf(MSG_INTL(MSG_FLT_FILTER), 610 (strtbl + fltrtbl->fr_filter), 611 (strtbl + fltrtbl->fr_string)); 612 613 /* 614 * Print each filtee. 615 */ 616 /* LINTED */ 617 for (_fltetbl = (Rtc_flte *)((char *)fltetbl + 618 fltrtbl->fr_filtee); _fltetbl->fe_filtee; 619 _fltetbl++) { 620 (void) printf(MSG_INTL(MSG_FLT_FILTEE), 621 (strtbl + _fltetbl->fe_filtee)); 622 } 623 fltrtbl++; 624 } 625 } 626 } 627 628 /* 629 * Display any memory reservations required for any alternative 630 * objects. 631 */ 632 if (head->ch_resbgn && ((crle->c_flags & CRLE_UPDATE) == 0)) 633 (void) printf(MSG_INTL(MSG_DMP_RESV), 634 (u_longlong_t)head->ch_resbgn, 635 (u_longlong_t)head->ch_resend, 636 (u_longlong_t)(head->ch_resend - head->ch_resbgn)); 637 638 /* 639 * If there's no hash table there's nothing else to process. 640 */ 641 if (head->ch_hash == 0) { 642 if (((crle->c_flags & CRLE_UPDATE) == 0) && cmdset) 643 printcmd(crle, head, cmdline); 644 return (INSCFG_RET_OK); 645 } 646 647 /* 648 * Traverse the directory and filename arrays. 649 */ 650 for (dirtbl = (Rtc_dir *)(head->ch_dir + addr); 651 dirtbl->cd_obj; dirtbl++) { 652 struct stat status; 653 Rtc_obj *dobj; 654 const char *str; 655 656 dobj = (Rtc_obj *)(dirtbl->cd_obj + addr); 657 filetbl = (Rtc_file *)(dirtbl->cd_file + addr); 658 str = strtbl + dobj->co_name; 659 660 /* 661 * Simplify recreation by using any command-line directories. 662 * If we're dealing with a version 1 configuration file use 663 * every directory. 664 */ 665 if ((dobj->co_flags & RTC_OBJ_CMDLINE) || 666 (head->ch_version == RTC_VER_ONE)) { 667 if (crle->c_flags & CRLE_UPDATE) { 668 if (inspect(crle, str, 669 getflags(dobj->co_flags)) != 0) 670 return (INSCFG_RET_FAIL); 671 if ((dobj->co_flags & 672 (RTC_OBJ_NOEXIST | RTC_OBJ_ALTER)) == 673 RTC_OBJ_NOEXIST) 674 continue; 675 } else { 676 /* LINTED */ 677 (void) snprintf(_cmd, PATH_MAX, 678 getformat(dobj->co_flags), str); 679 cmd = strdupa(_cmd); 680 cmdset = B_TRUE; 681 if (aplist_append(&cmdline, cmd, 682 AL_CNT_CRLE) == NULL) 683 return (INSCFG_RET_FAIL); 684 } 685 } 686 687 /* 688 * If this isn't an update print the directory name. If the 689 * directory has no entries (possible if the directory is a 690 * symlink to another directory, in which case we record the 691 * real path also), don't bother printing it unless we're in 692 * verbose mode. 693 */ 694 if ((crle->c_flags & CRLE_UPDATE) == 0) { 695 if ((dobj->co_flags & 696 (RTC_OBJ_NOEXIST | RTC_OBJ_ALTER)) == 697 RTC_OBJ_NOEXIST) { 698 (void) printf(MSG_INTL(MSG_DMP_DIR_2), str); 699 continue; 700 } else if (filetbl->cf_obj || 701 (crle->c_flags & CRLE_VERBOSE)) 702 (void) printf(MSG_INTL(MSG_DMP_DIR_1), str); 703 } 704 705 /* 706 * Under verbose mode validate any real directory entry - the 707 * same test will be carried out by ld.so.1. 708 */ 709 if (((crle->c_flags & CRLE_UPDATE) == 0) && 710 (crle->c_flags & CRLE_VERBOSE) && 711 (dobj->co_flags & RTC_OBJ_REALPTH)) { 712 if (stat(str, &status) != 0) { 713 int err = errno; 714 (void) printf(MSG_INTL(MSG_DMP_STAT), str, 715 strerror(err)); 716 } else if (status.st_mtime != dobj->co_info) { 717 (void) printf(MSG_INTL(MSG_DMP_DCMP), str); 718 } 719 } 720 721 for (; filetbl->cf_obj; filetbl++) { 722 Rtc_obj *fobj; 723 Half flags; 724 725 fobj = (Rtc_obj *)(filetbl->cf_obj + addr); 726 str = strtbl + fobj->co_name; 727 flags = fobj->co_flags; 728 729 /* 730 * Only update individual files that were originally 731 * specified on the command-line. Or, if this is a 732 * version 1 configuration file use every file that 733 * isn't part of an all-entries directory. 734 */ 735 if (((flags & RTC_OBJ_CMDLINE) && 736 ((fobj->co_flags & RTC_OBJ_APP) == 0)) || 737 ((head->ch_version == RTC_VER_ONE) && 738 ((dobj->co_flags & RTC_OBJ_ALLENTS) == 0))) { 739 char *alter = NULL, altdir[PATH_MAX]; 740 741 /* 742 * Determine whether this file requires an 743 * alternative, and if so, and we haven't 744 * already an alternative in affect, create one. 745 */ 746 if (fobj->co_flags & RTC_OBJ_ALTER) { 747 alter = (char *)(strtbl + 748 fobj->co_alter); 749 (void) strcpy(altdir, alter); 750 alter = strrchr(altdir, '/'); 751 *alter = '\0'; 752 753 if ((objdir == NULL) || 754 (strcmp(objdir, altdir) != 0)) { 755 (void) strcpy(_objdir, altdir); 756 crle->c_objdir = alter = 757 objdir = _objdir; 758 } else 759 alter = NULL; 760 } 761 762 if (crle->c_flags & CRLE_UPDATE) { 763 if (inspect(crle, str, 764 getflags(flags)) != 0) 765 return (INSCFG_RET_FAIL); 766 continue; 767 } 768 769 if (alter) { 770 (void) snprintf(_cmd, PATH_MAX, 771 MSG_ORIG(MSG_CMD_OUTPUT), 772 crle->c_objdir); 773 cmd = strdupa(_cmd); 774 cmdset = B_TRUE; 775 if (aplist_append(&cmdline, cmd, 776 AL_CNT_CRLE) == NULL) 777 return (INSCFG_RET_FAIL); 778 } 779 780 /* LINTED */ 781 (void) snprintf(_cmd, PATH_MAX, 782 getformat(flags), str); 783 cmd = strdupa(_cmd); 784 cmdset = B_TRUE; 785 if (aplist_append(&cmdline, cmd, 786 AL_CNT_CRLE) == NULL) 787 return (INSCFG_RET_FAIL); 788 } 789 790 if (crle->c_flags & CRLE_UPDATE) 791 continue; 792 793 /* 794 * Although we record both full pathnames and their 795 * simple filenames (basename), only print the simple 796 * names unless we're under verbose mode. 797 */ 798 if ((strchr(str, '/') == 0) || 799 (crle->c_flags & CRLE_VERBOSE)) { 800 if (fobj->co_flags & RTC_OBJ_ALTER) 801 (void) printf(MSG_INTL(MSG_DMP_FILE_2), 802 str, (strtbl + fobj->co_alter)); 803 else 804 (void) printf(MSG_INTL(MSG_DMP_FILE_1), 805 str); 806 } 807 808 /* 809 * Under verbose mode validate any real file entry - the 810 * same test will be carried out by ld.so.1. 811 */ 812 if ((crle->c_flags & CRLE_VERBOSE) && 813 (fobj->co_flags & RTC_OBJ_REALPTH)) { 814 if (stat(str, &status) != 0) { 815 int err = errno; 816 (void) printf(MSG_INTL(MSG_DMP_STAT), 817 str, strerror(err)); 818 } else if (status.st_size != fobj->co_info) { 819 (void) printf(MSG_INTL(MSG_DMP_FCMP), 820 str); 821 } 822 } 823 } 824 } 825 826 if (((crle->c_flags & CRLE_UPDATE) == 0) && cmdset) 827 printcmd(crle, head, cmdline); 828 829 if ((crle->c_flags & CRLE_VERBOSE) == 0) 830 return (INSCFG_RET_OK); 831 832 /* 833 * If we've in verbose mode scan the hash list. 834 */ 835 /* LINTED */ 836 hash = (Word *)(CAST_PTRINT(char *, head->ch_hash) + addr); 837 bkts = hash[0]; 838 chain = &hash[2 + bkts]; 839 hash += 2; 840 841 (void) printf(MSG_INTL(MSG_DMP_HASH)); 842 843 /* 844 * Scan the hash buckets looking for valid entries. 845 */ 846 for (ndx = 0; ndx < bkts; ndx++, hash++) { 847 Conv_config_obj_buf_t config_obj_buf; 848 Rtc_obj *obj; 849 const char *str; 850 Word _ndx; 851 852 if (*hash == 0) 853 continue; 854 855 obj = objtbl + *hash; 856 str = strtbl + obj->co_name; 857 858 (void) printf(MSG_INTL(MSG_DMP_HASHENT_1), obj->co_id, ndx, 859 str, conv_config_obj(obj->co_flags, &config_obj_buf)); 860 861 /* 862 * Determine whether there are other objects chained to this 863 * bucket. 864 */ 865 for (_ndx = chain[*hash]; _ndx; _ndx = chain[_ndx]) { 866 obj = objtbl + _ndx; 867 str = strtbl + obj->co_name; 868 869 (void) printf(MSG_INTL(MSG_DMP_HASHENT_2), obj->co_id, 870 str, conv_config_obj(obj->co_flags, 871 &config_obj_buf)); 872 } 873 } 874 (void) printf(MSG_ORIG(MSG_STR_NL)); 875 876 return (INSCFG_RET_OK); 877 } 878 879 880 INSCFG_RET 881 inspectconfig(Crle_desc * crle, int c_class) 882 { 883 INSCFG_RET error; 884 int fd; 885 Addr addr; 886 struct stat status; 887 const char *caller = crle->c_name, *file = crle->c_confil; 888 Conv_inv_buf_t inv_buf1, inv_buf2, inv_buf3; 889 890 /* 891 * Open the configuration file, determine its size and map it in. 892 */ 893 if ((fd = open(file, O_RDONLY, 0)) == -1) { 894 int err = errno; 895 896 if (err == ENOENT) { 897 #ifndef _ELF64 898 /* Must restart if user requested a 64-bit file */ 899 if (c_class == ELFCLASS64) 900 return (INSCFG_RET_NEED64); 901 #endif 902 903 /* 904 * To allow an update (-u) from scratch, fabricate any 905 * default search and secure paths that the user 906 * intends to add to. 907 */ 908 if (crle->c_flags & CRLE_UPDATE) { 909 if (crle->c_flags & CRLE_EDLIB) { 910 if (fablib(crle, CRLE_EDLIB)) 911 return (INSCFG_RET_FAIL); 912 } 913 if (crle->c_flags & CRLE_ESLIB) { 914 if (fablib(crle, CRLE_ESLIB)) 915 return (INSCFG_RET_FAIL); 916 } 917 return (INSCFG_RET_OK); 918 919 } else if (crle->c_flags & CRLE_CONFDEF) { 920 const char *fmt1, *fmt2; 921 922 /* 923 * Otherwise if the user is inspecting a default 924 * configuration file that doesn't exist inform 925 * them and display the ELF defaults. 926 */ 927 (void) printf(MSG_INTL(MSG_DEF_NOCONF), file); 928 (void) printf(MSG_INTL(MSG_DMP_PLATFORM), 929 conv_ehdr_class(M_CLASS, 930 CONV_FMT_ALT_FILE, &inv_buf1), 931 conv_ehdr_data(M_DATA, 932 CONV_FMT_ALT_FILE, &inv_buf2), 933 conv_ehdr_mach(M_MACH, 934 CONV_FMT_ALT_FILE, &inv_buf3)); 935 936 937 #if M_CLASS == ELFCLASS64 938 fmt1 = MSG_INTL(MSG_DEF_NEWDLP_64); 939 fmt2 = MSG_INTL(MSG_DEF_NEWTD_64); 940 #else 941 fmt1 = MSG_INTL(MSG_DEF_NEWDLP); 942 fmt2 = MSG_INTL(MSG_DEF_NEWTD); 943 #endif 944 (void) printf(fmt1); 945 (void) printf(fmt2); 946 947 return (INSCFG_RET_OK); 948 } 949 } 950 951 /* 952 * Otherwise there's an error condition in accessing the file. 953 */ 954 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), caller, file, 955 strerror(err)); 956 957 return (INSCFG_RET_FAIL); 958 } 959 960 (void) fstat(fd, &status); 961 if (status.st_size < sizeof (Rtc_head)) { 962 (void) close(fd); 963 (void) fprintf(stderr, MSG_INTL(MSG_COR_TRUNC), caller, file); 964 return (INSCFG_RET_FAIL); 965 } 966 if ((addr = (Addr)mmap(0, status.st_size, PROT_READ, MAP_SHARED, 967 fd, 0)) == (Addr)MAP_FAILED) { 968 int err = errno; 969 (void) fprintf(stderr, MSG_INTL(MSG_SYS_MMAP), caller, file, 970 strerror(err)); 971 (void) close(fd); 972 return (INSCFG_RET_FAIL); 973 } 974 (void) close(fd); 975 976 /* 977 * Print the contents of the configuration file. 978 */ 979 error = scanconfig(crle, addr, c_class); 980 981 (void) munmap((void *)addr, status.st_size); 982 return (error); 983 } 984