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