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