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