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 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 #pragma ident "%Z%%M% %I% %E% SMI" 26 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <fcntl.h> 30 #include <stdio.h> 31 #include <string.h> 32 #include <unistd.h> 33 #include <locale.h> 34 #include <dlfcn.h> 35 #include <errno.h> 36 #include "_crle.h" 37 #include "conv.h" 38 #include "msg.h" 39 40 41 /* 42 * crle(1) entry point and argument processing. 43 * 44 * Two passes of the arguments are carried out; the first collects any single 45 * instance options and establishes defaults that might be appropriate for 46 * other arguments: 47 * 48 * -64 operate on, or apply, 64-bit objects (default is 32-bit). 49 * 50 * -c file defines the output configuration file. 51 * 52 * -f flag flags for dldump(3dl). 53 * 54 * -o dir defines the output directory for any dldump(3dl) objects 55 * that follow. For backward compatibility (RTC_VER_ONE only 56 * allowed one output directory) allow the first occurrence of this 57 * specification to catch any previous files. If not specified, 58 * the configuration files parent directory is used). 59 * 60 * -u update any existing configuration file. Any additional 61 * arguments supplied will be added to the new configuration 62 * information. 63 * 64 * -v verbose mode. 65 * 66 * The second pass collects all other options and constructs an internal 67 * string table which will be used to create the eventual configuration file. 68 * 69 * -a name add the individual name, with an alternative to the 70 * configuration cache. No alternative is created via dldump(3dl), 71 * it is the users responsibility to furnish the alternative. 72 * 73 * -A name add the individual name, with an optional alternative to the 74 * configuration cache. No alternative is created via dldump(3dl), 75 * it is the users responsibility to furnish the alternative. 76 * 77 * -e envar replaceable environment variable 78 * 79 * -E envar permanent environment variable 80 * 81 * -i name add the individual name to the configuration cache. If name 82 * is a directory each shared object within the directory is added 83 * to the cache. 84 * 85 * -I name same as -i, but in addition any ELF objects are dldump(3dl)'ed. 86 * 87 * -g name add the group name to the configuration cache. Each object is 88 * expanded to determine its dependencies and these are added to 89 * the cache. If name is a directory each shared object within the 90 * directory and its dependencies are added to the cache. 91 * 92 * -G app same as -g, but in addition any ELF objects are dldump(3dl)'ed. 93 * 94 * -l dir library search directory 95 * 96 * -s dir trusted (secure) directory 97 * 98 * -t type search directory type (ELF or AOUT). 99 */ 100 101 /* 102 * Establish a structure for maintaining current object directory attributes. 103 * We wish to validate the access of any object directory that will be written 104 * to (dldump(3dl), and thus by maintaining a current object directory and its 105 * intended use we can perform this validation later. 106 */ 107 typedef struct { 108 char *o_objdir; 109 unsigned int o_flags; 110 } Objdir; 111 112 /*ARGSUSED2*/ 113 int 114 main(int argc, char **argv, char **envp) 115 { 116 Crle_desc crle = { 0 }; 117 int c, error = 0; 118 char ** lib; 119 List objdirs = { 0, 0 }; 120 Objdir _lobjdir = { 0, 0 }, * lobjdir = &_lobjdir; 121 struct stat ostatus, nstatus; 122 int c_class; 123 124 if (list_append(&objdirs, lobjdir) == 0) 125 return (1); 126 127 /* 128 * Establish locale. 129 */ 130 (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 131 (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 132 133 /* 134 * Initialization configuration information. 135 */ 136 crle.c_name = argv[0]; 137 crle.c_flags |= CRLE_ADDID; 138 crle.c_strbkts = 503; 139 crle.c_inobkts = 251; 140 c_class = M_CLASS; 141 142 /* 143 * First argument pass. 144 */ 145 while ((c = getopt(argc, argv, MSG_ORIG(MSG_ARG_OPTIONS))) != -1) { 146 switch (c) { 147 148 case '6': /* operate on 64-bit objects */ 149 if (optarg[0] != '4') { 150 (void) fprintf(stderr, 151 MSG_INTL(MSG_ARG_ILLEGAL), crle.c_name, 152 MSG_ORIG(MSG_ARG_6), optarg); 153 error = 1; 154 } 155 156 c_class = ELFCLASS64; 157 break; 158 159 case 'A': /* create optional */ 160 /* FALLTHROUGH */ /* alternative */ 161 case 'a': /* create alternative */ 162 crle.c_flags |= (CRLE_CREAT | CRLE_ALTER); 163 lobjdir->o_flags |= (CRLE_CREAT | CRLE_ALTER); 164 break; 165 166 case 'c': /* define the config file */ 167 if (crle.c_confil) { 168 (void) fprintf(stderr, MSG_INTL(MSG_ARG_MULT), 169 crle.c_name, MSG_ORIG(MSG_ARG_C)); 170 error = 1; 171 } 172 crle.c_confil = optarg; 173 break; 174 175 case 'e': /* replaceable env variable */ 176 crle.c_flags |= (CRLE_RPLENV | CRLE_CREAT); 177 break; 178 179 case 'E': /* permanent env variable */ 180 crle.c_flags |= (CRLE_PRMENV | CRLE_CREAT); 181 break; 182 183 case 'f': /* dldump(3dl) flags */ 184 if (crle.c_dlflags) { 185 (void) fprintf(stderr, MSG_INTL(MSG_ARG_MULT), 186 crle.c_name, MSG_ORIG(MSG_ARG_F)); 187 error = 1; 188 } 189 if ((crle.c_dlflags = dlflags(&crle, 190 (const char *)optarg)) == 0) 191 error = 1; 192 break; 193 194 case 'G': /* group object */ 195 crle.c_flags |= (CRLE_DUMP | CRLE_ALTER); 196 lobjdir->o_flags |= (CRLE_DUMP | CRLE_ALTER); 197 /* FALLTHROUGH */ 198 case 'g': 199 crle.c_flags |= CRLE_CREAT; 200 lobjdir->o_flags |= CRLE_CREAT; 201 break; 202 203 case 'I': /* individual object */ 204 crle.c_flags |= (CRLE_DUMP | CRLE_ALTER); 205 lobjdir->o_flags |= (CRLE_DUMP | CRLE_ALTER); 206 /* FALLTHROUGH */ 207 case 'i': 208 crle.c_flags |= CRLE_CREAT; 209 lobjdir->o_flags |= CRLE_CREAT; 210 break; 211 212 case 'l': /* library search path */ 213 if (crle.c_flags & CRLE_AOUT) 214 crle.c_flags |= CRLE_ADLIB; 215 else 216 crle.c_flags |= CRLE_EDLIB; 217 crle.c_flags |= CRLE_CREAT; 218 break; 219 220 case 'o': /* define an object directory */ 221 if (lobjdir->o_objdir) { 222 if ((lobjdir = calloc(sizeof (Objdir), 1)) == 0) 223 return (1); 224 if (list_append(&objdirs, lobjdir) == 0) 225 return (1); 226 } 227 lobjdir->o_objdir = optarg; 228 break; 229 230 case 's': /* trusted (secure) path */ 231 if (crle.c_flags & CRLE_AOUT) 232 crle.c_flags |= CRLE_ASLIB; 233 else 234 crle.c_flags |= CRLE_ESLIB; 235 crle.c_flags |= CRLE_CREAT; 236 break; 237 238 case 't': /* search path type */ 239 if (strcmp((const char *)optarg, 240 MSG_ORIG(MSG_STR_ELF)) == 0) 241 crle.c_flags &= ~CRLE_AOUT; 242 else if (strcmp((const char *)optarg, 243 MSG_ORIG(MSG_STR_AOUT)) == 0) 244 crle.c_flags |= CRLE_AOUT; 245 else { 246 (void) fprintf(stderr, MSG_INTL(MSG_ARG_TYPE), 247 crle.c_name, optarg); 248 error = 1; 249 } 250 break; 251 252 case 'u': /* update mode */ 253 crle.c_flags |= (CRLE_CREAT | CRLE_UPDATE); 254 break; 255 256 case 'v': /* verbose mode */ 257 crle.c_flags |= CRLE_VERBOSE; 258 break; 259 260 default: 261 error = 2; 262 } 263 } 264 265 if (optind != argc) 266 error = 2; 267 268 /* 269 * Determine the configuration file, which in the case of an existing 270 * error condition is required in the final error message. 271 */ 272 if (crle.c_confil == 0) { 273 crle.c_flags |= CRLE_CONFDEF; 274 if (c_class == ELFCLASS32) { 275 crle.c_confil = (char *)MSG_ORIG(MSG_PTH_CONFIG); 276 } else { 277 crle.c_confil = (char *)MSG_ORIG(MSG_PTH_CONFIG_64); 278 } 279 } 280 281 /* 282 * Now that we've generated as many file/directory processing errors 283 * as we can, return if any fatal error conditions occurred. 284 */ 285 if (error) { 286 if (error == 2) { 287 (void) fprintf(stderr, MSG_INTL(MSG_ARG_USAGE), 288 crle.c_name); 289 } else if (crle.c_flags & CRLE_CREAT) { 290 (void) fprintf(stderr, MSG_INTL(MSG_GEN_CREATE), 291 crle.c_name, crle.c_confil); 292 } 293 return (1); 294 } 295 296 /* 297 * Apply any additional defaults. 298 */ 299 if (crle.c_dlflags == 0) 300 crle.c_dlflags = RTLD_REL_RELATIVE; 301 302 crle.c_audit = (char *)MSG_ORIG(MSG_ENV_LD_AUDIT); 303 304 (void) elf_version(EV_CURRENT); 305 306 /* 307 * If we're updating an existing file or not creating a configuration 308 * file at all, investigate the original. 309 */ 310 if ((crle.c_flags & CRLE_UPDATE) || 311 ((crle.c_flags & CRLE_CREAT) == 0)) { 312 switch (inspectconfig(&crle, c_class)) { 313 case INSCFG_RET_OK: 314 if ((crle.c_flags & CRLE_UPDATE) == 0) 315 return (0); 316 break; 317 case INSCFG_RET_FAIL: 318 return (1); 319 case INSCFG_RET_NEED64: 320 c_class = ELFCLASS64; 321 break; 322 } 323 } 324 325 /* 326 * Ensure that the right version (32 or 64-bit) of this program 327 * is running. The 32 and 64-bit compilers may align fields within 328 * structures differently. Using the right version of crle for 329 * the config file ensures that all linker components will see 330 * the same layout, without the need for special code. 331 */ 332 #ifdef _ELF64 333 if (c_class == ELFCLASS32) { 334 (void) fprintf(stderr, MSG_INTL(MSG_ARG_CLASS), 335 crle.c_name, crle.c_confil); 336 return (1); 337 } 338 #else 339 if (c_class == ELFCLASS64) { 340 (void) conv_check_native(argv, envp); 341 342 /* 343 * conv_check_native() should not return, as we expect 344 * the 64-bit version to have executed on top of us. 345 * If it does, it means there is no 64-bit support 346 * available on this system. 347 */ 348 (void) fprintf(stderr, MSG_INTL(MSG_ISA32_NO64SUP), 349 crle.c_name); 350 return (1); 351 } 352 #endif 353 354 if (crle.c_flags & CRLE_VERBOSE) 355 (void) printf(MSG_INTL(MSG_DIA_CONFILE), crle.c_confil); 356 357 /* 358 * Make sure the configuration file is accessible. Stat the file to 359 * determine its dev number - this is used to determine whether the 360 * temporary configuration file we're about to build can be renamed or 361 * must be copied to its final destination. 362 */ 363 (void) umask(022); 364 if (access(crle.c_confil, (R_OK | W_OK)) == 0) { 365 crle.c_flags |= CRLE_EXISTS; 366 367 if (stat(crle.c_confil, &ostatus) != 0) { 368 int err = errno; 369 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), 370 crle.c_name, crle.c_confil, strerror(err)); 371 return (1); 372 } 373 } else if (errno != ENOENT) { 374 int err = errno; 375 (void) fprintf(stderr, MSG_INTL(MSG_SYS_ACCESS), crle.c_name, 376 crle.c_confil, strerror(err)); 377 return (1); 378 } else { 379 int fd; 380 381 /* 382 * Try opening the file now, if it works delete it, there may 383 * be a lot of processing ahead of us, so we'll come back and 384 * create the real thing later. 385 */ 386 if ((fd = open(crle.c_confil, (O_RDWR | O_CREAT | O_TRUNC), 387 0666)) == -1) { 388 int err = errno; 389 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), 390 crle.c_name, crle.c_confil, strerror(err)); 391 return (1); 392 } 393 if (fstat(fd, &ostatus) != 0) { 394 int err = errno; 395 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), 396 crle.c_name, crle.c_confil, strerror(err)); 397 return (1); 398 } 399 (void) close(fd); 400 (void) unlink(crle.c_confil); 401 } 402 403 /* 404 * If an object directory is required to hold dldump(3dl) output assign 405 * a default if necessary and insure we're able to write there. 406 */ 407 if (crle.c_flags & CRLE_ALTER) { 408 if (lobjdir->o_objdir == 0) { 409 char *str; 410 411 /* 412 * Use the configuration files directory. 413 */ 414 if ((str = strrchr(crle.c_confil, '/')) == NULL) 415 lobjdir->o_objdir = 416 (char *)MSG_ORIG(MSG_DIR_DOT); 417 else { 418 int len = str - crle.c_confil; 419 420 if ((lobjdir->o_objdir = 421 malloc(len + 1)) == 0) { 422 int err = errno; 423 (void) fprintf(stderr, 424 MSG_INTL(MSG_SYS_MALLOC), 425 crle.c_name, strerror(err)); 426 return (1); 427 } 428 (void) strncpy(lobjdir->o_objdir, 429 crle.c_confil, len); 430 lobjdir->o_objdir[len] = '\0'; 431 } 432 } 433 434 /* 435 * If we're going to dldump(3dl) images ourself make sure we 436 * can access any directories. 437 */ 438 if (crle.c_flags & CRLE_DUMP) { 439 Objdir * objdir; 440 Listnode * lnp; 441 int err = 0; 442 443 for (LIST_TRAVERSE(&objdirs, lnp, objdir)) { 444 if (crle.c_flags & CRLE_VERBOSE) 445 (void) printf(MSG_INTL(MSG_DIA_OBJDIR), 446 objdir->o_objdir); 447 448 if ((objdir->o_flags & CRLE_DUMP) == 0) 449 continue; 450 451 if (access(objdir->o_objdir, 452 (R_OK | W_OK)) != 0) { 453 err = errno; 454 (void) fprintf(stderr, 455 MSG_INTL(MSG_SYS_ACCESS), 456 crle.c_name, objdir->o_objdir, 457 strerror(err)); 458 } 459 } 460 if (err) 461 return (1); 462 } 463 } 464 465 /* 466 * Establish any initial object directory. 467 */ 468 crle.c_objdir = _lobjdir.o_objdir; 469 470 /* 471 * Create a temporary file name in which to build the configuration 472 * information. 473 */ 474 if ((crle.c_tempname = tempnam(MSG_ORIG(MSG_TMP_DIR), 475 MSG_ORIG(MSG_TMP_PFX))) == NULL) { 476 int err = errno; 477 (void) fprintf(stderr, MSG_INTL(MSG_SYS_TEMPNAME), 478 crle.c_name, strerror(err)); 479 return (1); 480 } 481 if ((crle.c_tempfd = open(crle.c_tempname, (O_RDWR | O_CREAT), 482 0666)) == -1) { 483 int err = errno; 484 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), 485 crle.c_name, crle.c_tempname, strerror(err)); 486 return (1); 487 } 488 if (stat(crle.c_tempname, &nstatus) != 0) { 489 int err = errno; 490 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), 491 crle.c_name, crle.c_tempname, strerror(err)); 492 return (1); 493 } 494 if (ostatus.st_dev != nstatus.st_dev) 495 crle.c_flags |= CRLE_DIFFDEV; 496 497 /* 498 * Second pass. 499 */ 500 error = 0; 501 optind = 1; 502 while ((c = getopt(argc, argv, MSG_ORIG(MSG_ARG_OPTIONS))) != -1) { 503 const char *str; 504 int flag = 0; 505 506 switch (c) { 507 508 case '6': 509 break; 510 511 case 'A': /* alternative is optional */ 512 flag = RTC_OBJ_OPTINAL; 513 /* FALLTHROUGH */ 514 case 'a': /* alternative required */ 515 flag |= (RTC_OBJ_ALTER | RTC_OBJ_CMDLINE); 516 if (inspect(&crle, (const char *)optarg, flag) != 0) 517 error = 1; 518 break; 519 520 case 'c': 521 break; 522 523 case 'e': 524 if ((flag = addenv(&crle, (const char *)optarg, 525 RTC_ENV_REPLACE)) == 0) 526 error = 1; 527 else if ((crle.c_flags & CRLE_VERBOSE) && (flag == 1)) 528 (void) printf(MSG_INTL(MSG_DIA_RPLENV), 529 (const char *)optarg); 530 break; 531 532 case 'E': 533 if ((flag = addenv(&crle, (const char *)optarg, 534 RTC_ENV_PERMANT)) == 0) 535 error = 1; 536 else if ((crle.c_flags & CRLE_VERBOSE) && (flag == 1)) 537 (void) printf(MSG_INTL(MSG_DIA_PRMENV), 538 (const char *)optarg); 539 break; 540 541 case 'f': 542 break; 543 544 case 'G': /* group object */ 545 flag = (RTC_OBJ_DUMP | RTC_OBJ_ALTER); 546 /* FALLTHROUGH */ 547 case 'g': 548 flag |= (RTC_OBJ_GROUP | RTC_OBJ_CMDLINE); 549 if (inspect(&crle, (const char *)optarg, flag) != 0) 550 error = 1; 551 break; 552 553 case 'I': /* individual object */ 554 flag = (RTC_OBJ_DUMP | RTC_OBJ_ALTER); 555 /* FALLTHROUGH */ 556 case 'i': 557 flag |= RTC_OBJ_CMDLINE; 558 if (inspect(&crle, (const char *)optarg, flag) != 0) 559 error = 1; 560 break; 561 562 case 'l': /* library search path */ 563 if (crle.c_flags & CRLE_AOUT) { 564 str = MSG_ORIG(MSG_STR_AOUT); 565 lib = &crle.c_adlibpath; 566 } else { 567 str = MSG_ORIG(MSG_STR_ELF); 568 lib = &crle.c_edlibpath; 569 } 570 if (addlib(&crle, lib, (const char *)optarg) != 0) 571 error = 1; 572 else if (crle.c_flags & CRLE_VERBOSE) 573 (void) printf(MSG_INTL(MSG_DIA_DLIBPTH), 574 str, (const char *)optarg); 575 break; 576 577 case 'o': 578 crle.c_objdir = optarg; 579 break; 580 581 case 's': /* trusted (secure) path */ 582 if (crle.c_flags & CRLE_AOUT) { 583 str = MSG_ORIG(MSG_STR_AOUT); 584 lib = &crle.c_aslibpath; 585 } else { 586 str = MSG_ORIG(MSG_STR_ELF); 587 lib = &crle.c_eslibpath; 588 } 589 if (addlib(&crle, lib, (const char *)optarg) != 0) 590 error = 1; 591 else if (crle.c_flags & CRLE_VERBOSE) 592 (void) printf(MSG_INTL(MSG_DIA_TLIBPTH), 593 str, (const char *)optarg); 594 break; 595 596 case 't': /* search path type */ 597 if (strcmp((const char *)optarg, 598 MSG_ORIG(MSG_STR_ELF)) == 0) 599 crle.c_flags &= ~CRLE_AOUT; 600 else 601 crle.c_flags |= CRLE_AOUT; 602 break; 603 604 case 'u': 605 break; 606 607 case 'v': 608 break; 609 } 610 } 611 612 /* 613 * Now that we've generated as many file/directory processing errors 614 * as we can, return if any fatal error conditions occurred. 615 */ 616 if (error) { 617 (void) unlink(crle.c_tempname); 618 if (crle.c_flags & CRLE_CREAT) { 619 (void) fprintf(stderr, MSG_INTL(MSG_GEN_CREATE), 620 crle.c_name, crle.c_confil); 621 } 622 return (1); 623 } 624 625 /* 626 * Create a temporary configuration file. 627 */ 628 if (genconfig(&crle) != 0) { 629 (void) unlink(crle.c_tempname); 630 return (1); 631 } 632 633 /* 634 * If dldump(3dl) images are required spawn a process to create them. 635 */ 636 if (crle.c_flags & CRLE_DUMP) { 637 if (dump(&crle) != 0) { 638 (void) unlink(crle.c_tempname); 639 return (1); 640 } 641 } 642 643 /* 644 * Copy the finished temporary configuration file to its final home. 645 */ 646 if (updateconfig(&crle) != 0) 647 return (1); 648 649 return (0); 650 } 651