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