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