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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <sys/stat.h> 30 #include <fcntl.h> 31 #include <stdio.h> 32 #include <string.h> 33 #include <unistd.h> 34 #include <locale.h> 35 #include <dlfcn.h> 36 #include <errno.h> 37 #include "_crle.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 int 113 main(int argc, char ** argv) 114 { 115 Crle_desc crle = { 0 }; 116 int c, error = 0; 117 char ** lib; 118 List objdirs = { 0, 0 }; 119 Objdir _lobjdir = { 0, 0 }, * lobjdir = &_lobjdir; 120 struct stat ostatus, nstatus; 121 122 if (list_append(&objdirs, lobjdir) == 0) 123 return (1); 124 125 /* 126 * Establish locale. 127 */ 128 (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 129 (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 130 131 /* 132 * Initialization configuration information. 133 */ 134 crle.c_name = argv[0]; 135 crle.c_strbkts = 503; 136 crle.c_inobkts = 251; 137 crle.c_class = ELFCLASS32; 138 crle.c_machine = M_MACH; 139 140 /* 141 * First argument pass. 142 */ 143 while ((c = getopt(argc, argv, MSG_ORIG(MSG_ARG_OPTIONS))) != -1) { 144 switch (c) { 145 146 case '6': /* operate on 64-bit objects */ 147 if (optarg[0] != '4') { 148 (void) fprintf(stderr, 149 MSG_INTL(MSG_ARG_ILLEGAL), crle.c_name, 150 MSG_ORIG(MSG_ARG_6), optarg); 151 error = 1; 152 } 153 crle.c_class = ELFCLASS64; 154 #if defined(sparc) 155 crle.c_machine = EM_SPARCV9; 156 #elif defined(i386) 157 crle.c_machine = EM_IA_64; 158 #endif 159 break; 160 161 case 'A': /* create optional */ 162 /* FALLTHROUGH */ /* alternative */ 163 case 'a': /* create alternative */ 164 crle.c_flags |= (CRLE_CREAT | CRLE_ALTER); 165 lobjdir->o_flags |= (CRLE_CREAT | CRLE_ALTER); 166 break; 167 168 case 'c': /* define the config file */ 169 if (crle.c_confil) { 170 (void) fprintf(stderr, MSG_INTL(MSG_ARG_MULT), 171 crle.c_name, MSG_ORIG(MSG_ARG_C)); 172 error = 1; 173 } 174 crle.c_confil = optarg; 175 break; 176 177 case 'e': /* replaceable env variable */ 178 crle.c_flags |= (CRLE_RPLENV | CRLE_CREAT); 179 break; 180 181 case 'E': /* permanent env variable */ 182 crle.c_flags |= (CRLE_PRMENV | CRLE_CREAT); 183 break; 184 185 case 'f': /* dldump(3dl) flags */ 186 if (crle.c_dlflags) { 187 (void) fprintf(stderr, MSG_INTL(MSG_ARG_MULT), 188 crle.c_name, MSG_ORIG(MSG_ARG_F)); 189 error = 1; 190 } 191 if ((crle.c_dlflags = dlflags(&crle, 192 (const char *)optarg)) == 0) 193 error = 1; 194 break; 195 196 case 'G': /* group object */ 197 crle.c_flags |= (CRLE_DUMP | CRLE_ALTER); 198 lobjdir->o_flags |= (CRLE_DUMP | CRLE_ALTER); 199 /* FALLTHROUGH */ 200 case 'g': 201 crle.c_flags |= CRLE_CREAT; 202 lobjdir->o_flags |= CRLE_CREAT; 203 break; 204 205 case 'I': /* individual object */ 206 crle.c_flags |= (CRLE_DUMP | CRLE_ALTER); 207 lobjdir->o_flags |= (CRLE_DUMP | CRLE_ALTER); 208 /* FALLTHROUGH */ 209 case 'i': 210 crle.c_flags |= CRLE_CREAT; 211 lobjdir->o_flags |= CRLE_CREAT; 212 break; 213 214 case 'l': /* library search path */ 215 if (crle.c_flags & CRLE_AOUT) 216 crle.c_flags |= CRLE_ADLIB; 217 else 218 crle.c_flags |= CRLE_EDLIB; 219 crle.c_flags |= CRLE_CREAT; 220 break; 221 222 case 'o': /* define an object directory */ 223 if (lobjdir->o_objdir) { 224 if ((lobjdir = calloc(sizeof (Objdir), 1)) == 0) 225 return (1); 226 if (list_append(&objdirs, lobjdir) == 0) 227 return (1); 228 } 229 lobjdir->o_objdir = optarg; 230 break; 231 232 case 's': /* trusted (secure) path */ 233 if (crle.c_flags & CRLE_AOUT) 234 crle.c_flags |= CRLE_ASLIB; 235 else 236 crle.c_flags |= CRLE_ESLIB; 237 crle.c_flags |= CRLE_CREAT; 238 break; 239 240 case 't': /* search path type */ 241 if (strcmp((const char *)optarg, 242 MSG_ORIG(MSG_STR_ELF)) == 0) 243 crle.c_flags &= ~CRLE_AOUT; 244 else if (strcmp((const char *)optarg, 245 MSG_ORIG(MSG_STR_AOUT)) == 0) 246 crle.c_flags |= CRLE_AOUT; 247 else { 248 (void) fprintf(stderr, MSG_INTL(MSG_ARG_TYPE), 249 crle.c_name, optarg); 250 error = 1; 251 } 252 break; 253 254 case 'u': /* update mode */ 255 crle.c_flags |= (CRLE_CREAT | CRLE_UPDATE); 256 break; 257 258 case 'v': /* verbose mode */ 259 crle.c_flags |= CRLE_VERBOSE; 260 break; 261 262 default: 263 error = 2; 264 } 265 } 266 267 if (optind != argc) 268 error = 2; 269 270 /* 271 * Determine the configuration file, which in the case of an existing 272 * error condition is required in the final error message. 273 */ 274 if (crle.c_confil == 0) { 275 crle.c_flags |= CRLE_CONFDEF; 276 277 if (crle.c_class == ELFCLASS32) 278 crle.c_confil = (char *)MSG_ORIG(MSG_PTH_CONFIG); 279 else 280 crle.c_confil = (char *)MSG_ORIG(MSG_PTH_CONFIG_64); 281 } 282 283 /* 284 * Now that we've generated as many file/directory processing errors 285 * as we can, return if any fatal error conditions occurred. 286 */ 287 if (error) { 288 if (error == 2) { 289 (void) fprintf(stderr, MSG_INTL(MSG_ARG_USAGE), 290 crle.c_name); 291 } else if (crle.c_flags & CRLE_CREAT) { 292 (void) fprintf(stderr, MSG_INTL(MSG_GEN_CREATE), 293 crle.c_name, crle.c_confil); 294 } 295 return (1); 296 } 297 298 /* 299 * Apply any additional defaults. 300 */ 301 if (crle.c_dlflags == 0) 302 crle.c_dlflags = RTLD_REL_RELATIVE; 303 304 crle.c_audit = (char *)MSG_ORIG(MSG_ENV_LD_AUDIT); 305 306 (void) elf_version(EV_CURRENT); 307 308 /* 309 * If we're updating an existing file or not creating a configuration 310 * file at all, investigate the original. 311 */ 312 if ((crle.c_flags & CRLE_UPDATE) || 313 ((crle.c_flags & CRLE_CREAT) == 0)) { 314 if (inspectconfig(&crle)) 315 return (1); 316 if ((crle.c_flags & CRLE_UPDATE) == 0) 317 return (0); 318 } 319 320 if (crle.c_flags & CRLE_VERBOSE) 321 (void) printf(MSG_INTL(MSG_DIA_CONFILE), crle.c_confil); 322 323 /* 324 * Make sure the configuration file is accessible. Stat the file to 325 * determine its dev number - this is used to determine whether the 326 * temporary configuration file we're about to build can be renamed or 327 * must be copied to its final destination. 328 */ 329 (void) umask(022); 330 if (access(crle.c_confil, (R_OK | W_OK)) == 0) { 331 crle.c_flags |= CRLE_EXISTS; 332 333 if (stat(crle.c_confil, &ostatus) != 0) { 334 int err = errno; 335 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), 336 crle.c_name, crle.c_confil, strerror(err)); 337 return (1); 338 } 339 } else if (errno != ENOENT) { 340 int err = errno; 341 (void) fprintf(stderr, MSG_INTL(MSG_SYS_ACCESS), crle.c_name, 342 crle.c_confil, strerror(err)); 343 return (1); 344 } else { 345 int fd; 346 347 /* 348 * Try opening the file now, if it works delete it, there may 349 * be a lot of processing ahead of us, so we'll come back and 350 * create the real thing later. 351 */ 352 if ((fd = open(crle.c_confil, (O_RDWR | O_CREAT | O_TRUNC), 353 0666)) == -1) { 354 int err = errno; 355 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), 356 crle.c_name, crle.c_confil, strerror(err)); 357 return (1); 358 } 359 if (fstat(fd, &ostatus) != 0) { 360 int err = errno; 361 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), 362 crle.c_name, crle.c_confil, strerror(err)); 363 return (1); 364 } 365 (void) close(fd); 366 (void) unlink(crle.c_confil); 367 } 368 369 /* 370 * If an object directory is required to hold dldump(3dl) output assign 371 * a default if necessary and insure we're able to write there. 372 */ 373 if (crle.c_flags & CRLE_ALTER) { 374 if (lobjdir->o_objdir == 0) { 375 char *str; 376 377 /* 378 * Use the configuration files directory. 379 */ 380 if ((str = strrchr(crle.c_confil, '/')) == NULL) 381 lobjdir->o_objdir = 382 (char *)MSG_ORIG(MSG_DIR_DOT); 383 else { 384 int len = str - crle.c_confil; 385 386 if ((lobjdir->o_objdir = 387 malloc(len + 1)) == 0) { 388 int err = errno; 389 (void) fprintf(stderr, 390 MSG_INTL(MSG_SYS_MALLOC), 391 crle.c_name, strerror(err)); 392 return (1); 393 } 394 (void) strncpy(lobjdir->o_objdir, 395 crle.c_confil, len); 396 lobjdir->o_objdir[len] = '\0'; 397 } 398 } 399 400 /* 401 * If we're going to dldump(3dl) images ourself make sure we 402 * can access any directories. 403 */ 404 if (crle.c_flags & CRLE_DUMP) { 405 Objdir * objdir; 406 Listnode * lnp; 407 int err = 0; 408 409 for (LIST_TRAVERSE(&objdirs, lnp, objdir)) { 410 if (crle.c_flags & CRLE_VERBOSE) 411 (void) printf(MSG_INTL(MSG_DIA_OBJDIR), 412 objdir->o_objdir); 413 414 if ((objdir->o_flags & CRLE_DUMP) == 0) 415 continue; 416 417 if (access(objdir->o_objdir, 418 (R_OK | W_OK)) != 0) { 419 err = errno; 420 (void) fprintf(stderr, 421 MSG_INTL(MSG_SYS_ACCESS), 422 crle.c_name, objdir->o_objdir, 423 strerror(err)); 424 } 425 } 426 if (err) 427 return (1); 428 } 429 } 430 431 /* 432 * Establish any initial object directory. 433 */ 434 crle.c_objdir = _lobjdir.o_objdir; 435 436 /* 437 * Create a temporary file name in which to build the configuration 438 * information. 439 */ 440 if ((crle.c_tempname = tempnam(MSG_ORIG(MSG_TMP_DIR), 441 MSG_ORIG(MSG_TMP_PFX))) == NULL) { 442 int err = errno; 443 (void) fprintf(stderr, MSG_INTL(MSG_SYS_TEMPNAME), 444 crle.c_name, strerror(err)); 445 return (1); 446 } 447 if ((crle.c_tempfd = open(crle.c_tempname, (O_RDWR | O_CREAT), 448 0666)) == -1) { 449 int err = errno; 450 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), 451 crle.c_name, crle.c_tempname, strerror(err)); 452 return (1); 453 } 454 if (stat(crle.c_tempname, &nstatus) != 0) { 455 int err = errno; 456 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), 457 crle.c_name, crle.c_tempname, strerror(err)); 458 return (1); 459 } 460 if (ostatus.st_dev != nstatus.st_dev) 461 crle.c_flags |= CRLE_DIFFDEV; 462 463 /* 464 * Second pass. 465 */ 466 error = 0; 467 optind = 1; 468 while ((c = getopt(argc, argv, MSG_ORIG(MSG_ARG_OPTIONS))) != -1) { 469 const char *str; 470 int flag = 0; 471 472 switch (c) { 473 474 case '6': 475 break; 476 477 case 'A': /* alternative is optional */ 478 flag = RTC_OBJ_OPTINAL; 479 /* FALLTHROUGH */ 480 case 'a': /* alternative required */ 481 flag |= (RTC_OBJ_ALTER | RTC_OBJ_CMDLINE); 482 if (inspect(&crle, (const char *)optarg, flag) != 0) 483 error = 1; 484 break; 485 486 case 'c': 487 break; 488 489 case 'e': 490 if ((flag = addenv(&crle, (const char *)optarg, 491 RTC_ENV_REPLACE)) == 0) 492 error = 1; 493 else if ((crle.c_flags & CRLE_VERBOSE) && (flag == 1)) 494 (void) printf(MSG_INTL(MSG_DIA_RPLENV), 495 (const char *)optarg); 496 break; 497 498 case 'E': 499 if ((flag = addenv(&crle, (const char *)optarg, 500 RTC_ENV_PERMANT)) == 0) 501 error = 1; 502 else if ((crle.c_flags & CRLE_VERBOSE) && (flag == 1)) 503 (void) printf(MSG_INTL(MSG_DIA_PRMENV), 504 (const char *)optarg); 505 break; 506 507 case 'f': 508 break; 509 510 case 'G': /* group object */ 511 flag = (RTC_OBJ_DUMP | RTC_OBJ_ALTER); 512 /* FALLTHROUGH */ 513 case 'g': 514 flag |= (RTC_OBJ_GROUP | RTC_OBJ_CMDLINE); 515 if (inspect(&crle, (const char *)optarg, flag) != 0) 516 error = 1; 517 break; 518 519 case 'I': /* individual object */ 520 flag = (RTC_OBJ_DUMP | RTC_OBJ_ALTER); 521 /* FALLTHROUGH */ 522 case 'i': 523 flag |= RTC_OBJ_CMDLINE; 524 if (inspect(&crle, (const char *)optarg, flag) != 0) 525 error = 1; 526 break; 527 528 case 'l': /* library search path */ 529 if (crle.c_flags & CRLE_AOUT) { 530 str = MSG_ORIG(MSG_STR_AOUT); 531 lib = &crle.c_adlibpath; 532 } else { 533 str = MSG_ORIG(MSG_STR_ELF); 534 lib = &crle.c_edlibpath; 535 } 536 if (addlib(&crle, lib, (const char *)optarg) != 0) 537 error = 1; 538 else if (crle.c_flags & CRLE_VERBOSE) 539 (void) printf(MSG_INTL(MSG_DIA_DLIBPTH), 540 str, (const char *)optarg); 541 break; 542 543 case 'o': 544 crle.c_objdir = optarg; 545 break; 546 547 case 's': /* trusted (secure) path */ 548 if (crle.c_flags & CRLE_AOUT) { 549 str = MSG_ORIG(MSG_STR_AOUT); 550 lib = &crle.c_aslibpath; 551 } else { 552 str = MSG_ORIG(MSG_STR_ELF); 553 lib = &crle.c_eslibpath; 554 } 555 if (addlib(&crle, lib, (const char *)optarg) != 0) 556 error = 1; 557 else if (crle.c_flags & CRLE_VERBOSE) 558 (void) printf(MSG_INTL(MSG_DIA_TLIBPTH), 559 str, (const char *)optarg); 560 break; 561 562 case 't': /* search path type */ 563 if (strcmp((const char *)optarg, 564 MSG_ORIG(MSG_STR_ELF)) == 0) 565 crle.c_flags &= ~CRLE_AOUT; 566 else 567 crle.c_flags |= CRLE_AOUT; 568 break; 569 570 case 'u': 571 break; 572 573 case 'v': 574 break; 575 } 576 } 577 578 /* 579 * Now that we've generated as many file/directory processing errors 580 * as we can, return if any fatal error conditions occurred. 581 */ 582 if (error) { 583 (void) unlink(crle.c_tempname); 584 if (crle.c_flags & CRLE_CREAT) { 585 (void) fprintf(stderr, MSG_INTL(MSG_GEN_CREATE), 586 crle.c_name, crle.c_confil); 587 } 588 return (1); 589 } 590 591 /* 592 * Create a temporary configuration file. 593 */ 594 if (genconfig(&crle) != 0) { 595 (void) unlink(crle.c_tempname); 596 return (1); 597 } 598 599 /* 600 * If dldump(3dl) images are required spawn a process to create them. 601 */ 602 if (crle.c_flags & CRLE_DUMP) { 603 if (dump(&crle) != 0) { 604 (void) unlink(crle.c_tempname); 605 return (1); 606 } 607 } 608 609 /* 610 * Copy the finished temporary configuration file to its final home. 611 */ 612 if (updateconfig(&crle) != 0) 613 return (1); 614 615 return (0); 616 } 617