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