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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
41 * crle(1) entry point and argument processing.
43 * Two passes of the arguments are carried out; the first collects any single
44 * instance options and establishes defaults that might be appropriate for
47 * -64 operate on, or apply, 64-bit objects (default is 32-bit).
49 * -c file defines the output configuration file.
51 * -f flag flags for dldump(3dl).
53 * -o dir defines the output directory for any dldump(3dl) objects
54 * that follow. For backward compatibility (RTC_VER_ONE only
55 * allowed one output directory) allow the first occurrence of this
56 * specification to catch any previous files. If not specified,
57 * the configuration files parent directory is used).
59 * -u update any existing configuration file. Any additional
60 * arguments supplied will be added to the new configuration
65 * The second pass collects all other options and constructs an internal
66 * string table which will be used to create the eventual configuration file.
68 * -a name add the individual name, with an alternative to the
69 * configuration cache. No alternative is created via dldump(3dl),
70 * it is the users responsibility to furnish the alternative.
72 * -A name add the individual name, with an optional alternative to the
73 * configuration cache. No alternative is created via dldump(3dl),
74 * it is the users responsibility to furnish the alternative.
76 * -e envar replaceable environment variable
78 * -E envar permanent environment variable
80 * -i name add the individual name to the configuration cache. If name
81 * is a directory each shared object within the directory is added
84 * -I name same as -i, but in addition any ELF objects are dldump(3dl)'ed.
86 * -g name add the group name to the configuration cache. Each object is
87 * expanded to determine its dependencies and these are added to
88 * the cache. If name is a directory each shared object within the
89 * directory and its dependencies are added to the cache.
91 * -G app same as -g, but in addition any ELF objects are dldump(3dl)'ed.
93 * -l dir library search directory
95 * -s dir trusted (secure) directory
97 * -t type search directory type (ELF or AOUT).
101 * Establish a structure for maintaining current object directory attributes.
102 * We wish to validate the access of any object directory that will be written
103 * to (dldump(3dl), and thus by maintaining a current object directory and its
104 * intended use we can perform this validation later.
113 main(int argc
, char **argv
, char **envp
)
115 Crle_desc crle
= { 0 };
118 Alist
*objdirs
= NULL
;
119 Objdir
*objdir
, *iobjdir
;
120 struct stat ostatus
, nstatus
;
123 if ((objdir
= iobjdir
= alist_append(&objdirs
, NULL
, sizeof (Objdir
),
124 AL_CNT_CRLE
)) == NULL
)
130 (void) setlocale(LC_MESSAGES
, MSG_ORIG(MSG_STR_EMPTY
));
131 (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS
));
134 * Initialization configuration information.
136 crle
.c_name
= argv
[0];
137 crle
.c_flags
|= CRLE_ADDID
;
138 crle
.c_strbkts
= 503;
139 crle
.c_inobkts
= 251;
143 * First argument pass.
145 while ((c
= getopt(argc
, argv
, MSG_ORIG(MSG_ARG_OPTIONS
))) != -1) {
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
);
156 c_class
= ELFCLASS64
;
159 case 'A': /* create optional */
160 /* FALLTHROUGH */ /* alternative */
161 case 'a': /* create alternative */
162 crle
.c_flags
|= (CRLE_CREAT
| CRLE_ALTER
);
163 objdir
->o_flags
|= (CRLE_CREAT
| CRLE_ALTER
);
166 case 'c': /* define the config file */
168 (void) fprintf(stderr
, MSG_INTL(MSG_ARG_MULT
),
169 crle
.c_name
, MSG_ORIG(MSG_ARG_C
));
172 crle
.c_confil
= optarg
;
175 case 'e': /* replaceable env variable */
176 crle
.c_flags
|= (CRLE_RPLENV
| CRLE_CREAT
);
179 case 'E': /* permanent env variable */
180 crle
.c_flags
|= (CRLE_PRMENV
| CRLE_CREAT
);
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
));
189 if ((crle
.c_dlflags
= dlflags(&crle
,
190 (const char *)optarg
)) == 0)
194 case 'G': /* group object */
195 crle
.c_flags
|= (CRLE_DUMP
| CRLE_ALTER
);
196 objdir
->o_flags
|= (CRLE_DUMP
| CRLE_ALTER
);
199 crle
.c_flags
|= CRLE_CREAT
;
200 objdir
->o_flags
|= CRLE_CREAT
;
203 case 'I': /* individual object */
204 crle
.c_flags
|= (CRLE_DUMP
| CRLE_ALTER
);
205 objdir
->o_flags
|= (CRLE_DUMP
| CRLE_ALTER
);
208 crle
.c_flags
|= CRLE_CREAT
;
209 objdir
->o_flags
|= CRLE_CREAT
;
212 case 'l': /* library search path */
213 if (crle
.c_flags
& CRLE_AOUT
)
214 crle
.c_flags
|= CRLE_ADLIB
;
216 crle
.c_flags
|= CRLE_EDLIB
;
217 crle
.c_flags
|= CRLE_CREAT
;
220 case 'o': /* define an object directory */
221 if (objdir
->o_objdir
) {
222 if ((objdir
= alist_append(&objdirs
, NULL
,
223 sizeof (Objdir
), AL_CNT_CRLE
)) == NULL
)
226 objdir
->o_objdir
= optarg
;
229 case 's': /* trusted (secure) path */
230 if (crle
.c_flags
& CRLE_AOUT
)
231 crle
.c_flags
|= CRLE_ASLIB
;
233 crle
.c_flags
|= CRLE_ESLIB
;
234 crle
.c_flags
|= CRLE_CREAT
;
237 case 't': /* search path type */
238 if (strcmp((const char *)optarg
,
239 MSG_ORIG(MSG_STR_ELF
)) == 0)
240 crle
.c_flags
&= ~CRLE_AOUT
;
241 else if (strcmp((const char *)optarg
,
242 MSG_ORIG(MSG_STR_AOUT
)) == 0)
243 crle
.c_flags
|= CRLE_AOUT
;
245 (void) fprintf(stderr
, MSG_INTL(MSG_ARG_TYPE
),
246 crle
.c_name
, optarg
);
251 case 'u': /* update mode */
252 crle
.c_flags
|= (CRLE_CREAT
| CRLE_UPDATE
);
255 case 'v': /* verbose mode */
256 crle
.c_flags
|= CRLE_VERBOSE
;
268 * Determine the configuration file, which in the case of an existing
269 * error condition is required in the final error message.
271 if (crle
.c_confil
== NULL
) {
272 crle
.c_flags
|= CRLE_CONFDEF
;
273 if (c_class
== ELFCLASS32
) {
274 crle
.c_confil
= (char *)MSG_ORIG(MSG_PTH_CONFIG
);
276 crle
.c_confil
= (char *)MSG_ORIG(MSG_PTH_CONFIG_64
);
281 * Now that we've generated as many file/directory processing errors
282 * as we can, return if any fatal error conditions occurred.
286 (void) fprintf(stderr
, MSG_INTL(MSG_ARG_USAGE
),
288 } else if (crle
.c_flags
& CRLE_CREAT
) {
289 (void) fprintf(stderr
, MSG_INTL(MSG_GEN_CREATE
),
290 crle
.c_name
, crle
.c_confil
);
296 * Apply any additional defaults.
298 if (crle
.c_dlflags
== 0)
299 crle
.c_dlflags
= RTLD_REL_RELATIVE
;
301 crle
.c_audit
= (char *)MSG_ORIG(MSG_ENV_LD_AUDIT
);
303 (void) elf_version(EV_CURRENT
);
306 * If we're updating an existing file or not creating a configuration
307 * file at all, investigate the original.
309 if ((crle
.c_flags
& CRLE_UPDATE
) ||
310 ((crle
.c_flags
& CRLE_CREAT
) == 0)) {
311 switch (inspectconfig(&crle
, c_class
)) {
313 if ((crle
.c_flags
& CRLE_UPDATE
) == 0)
316 case INSCFG_RET_FAIL
:
318 case INSCFG_RET_NEED64
:
319 c_class
= ELFCLASS64
;
325 * Ensure that the right version (32 or 64-bit) of this program
326 * is running. The 32 and 64-bit compilers may align fields within
327 * structures differently. Using the right version of crle for
328 * the config file ensures that all linker components will see
329 * the same layout, without the need for special code.
332 if (c_class
== ELFCLASS32
) {
333 (void) fprintf(stderr
, MSG_INTL(MSG_ARG_CLASS
),
334 crle
.c_name
, crle
.c_confil
);
338 if (c_class
== ELFCLASS64
) {
339 (void) conv_check_native(argv
, envp
);
342 * conv_check_native() should not return, as we expect
343 * the 64-bit version to have executed on top of us.
344 * If it does, it means there is no 64-bit support
345 * available on this system.
347 (void) fprintf(stderr
, MSG_INTL(MSG_ISA32_NO64SUP
),
353 if (crle
.c_flags
& CRLE_VERBOSE
)
354 (void) printf(MSG_INTL(MSG_DIA_CONFILE
), crle
.c_confil
);
357 * Make sure the configuration file is accessible. Stat the file to
358 * determine its dev number - this is used to determine whether the
359 * temporary configuration file we're about to build can be renamed or
360 * must be copied to its final destination.
363 if (access(crle
.c_confil
, (R_OK
| W_OK
)) == 0) {
364 crle
.c_flags
|= CRLE_EXISTS
;
366 if (stat(crle
.c_confil
, &ostatus
) != 0) {
368 (void) fprintf(stderr
, MSG_INTL(MSG_SYS_OPEN
),
369 crle
.c_name
, crle
.c_confil
, strerror(err
));
372 } else if (errno
!= ENOENT
) {
374 (void) fprintf(stderr
, MSG_INTL(MSG_SYS_ACCESS
), crle
.c_name
,
375 crle
.c_confil
, strerror(err
));
381 * Try opening the file now, if it works delete it, there may
382 * be a lot of processing ahead of us, so we'll come back and
383 * create the real thing later.
385 if ((fd
= open(crle
.c_confil
, (O_RDWR
| O_CREAT
| O_TRUNC
),
388 (void) fprintf(stderr
, MSG_INTL(MSG_SYS_OPEN
),
389 crle
.c_name
, crle
.c_confil
, strerror(err
));
392 if (fstat(fd
, &ostatus
) != 0) {
394 (void) fprintf(stderr
, MSG_INTL(MSG_SYS_OPEN
),
395 crle
.c_name
, crle
.c_confil
, strerror(err
));
399 (void) unlink(crle
.c_confil
);
403 * If an object directory is required to hold dldump(3dl) output assign
404 * a default if necessary and insure we're able to write there.
406 if (crle
.c_flags
& CRLE_ALTER
) {
407 if (objdir
->o_objdir
== NULL
) {
411 * Use the configuration files directory.
413 if ((str
= strrchr(crle
.c_confil
, '/')) == NULL
)
415 (char *)MSG_ORIG(MSG_DIR_DOT
);
417 int len
= str
- crle
.c_confil
;
419 if ((objdir
->o_objdir
=
420 malloc(len
+ 1)) == NULL
) {
422 (void) fprintf(stderr
,
423 MSG_INTL(MSG_SYS_MALLOC
),
424 crle
.c_name
, strerror(err
));
427 (void) strncpy(objdir
->o_objdir
,
429 objdir
->o_objdir
[len
] = '\0';
434 * If we're going to dldump(3dl) images ourself make sure we
435 * can access any directories.
437 if (crle
.c_flags
& CRLE_DUMP
) {
442 for (ALIST_TRAVERSE(objdirs
, idx
, objdir
)) {
443 if (crle
.c_flags
& CRLE_VERBOSE
)
444 (void) printf(MSG_INTL(MSG_DIA_OBJDIR
),
447 if ((objdir
->o_flags
& CRLE_DUMP
) == 0)
450 if (access(objdir
->o_objdir
,
451 (R_OK
| W_OK
)) != 0) {
453 (void) fprintf(stderr
,
454 MSG_INTL(MSG_SYS_ACCESS
),
455 crle
.c_name
, objdir
->o_objdir
,
465 * Establish any initial object directory.
467 crle
.c_objdir
= iobjdir
->o_objdir
;
470 * Create a temporary file name in which to build the configuration
473 if ((crle
.c_tempname
= tempnam(MSG_ORIG(MSG_TMP_DIR
),
474 MSG_ORIG(MSG_TMP_PFX
))) == NULL
) {
476 (void) fprintf(stderr
, MSG_INTL(MSG_SYS_TEMPNAME
),
477 crle
.c_name
, strerror(err
));
480 if ((crle
.c_tempfd
= open(crle
.c_tempname
, (O_RDWR
| O_CREAT
),
483 (void) fprintf(stderr
, MSG_INTL(MSG_SYS_OPEN
),
484 crle
.c_name
, crle
.c_tempname
, strerror(err
));
487 if (stat(crle
.c_tempname
, &nstatus
) != 0) {
489 (void) fprintf(stderr
, MSG_INTL(MSG_SYS_OPEN
),
490 crle
.c_name
, crle
.c_tempname
, strerror(err
));
493 if (ostatus
.st_dev
!= nstatus
.st_dev
)
494 crle
.c_flags
|= CRLE_DIFFDEV
;
501 while ((c
= getopt(argc
, argv
, MSG_ORIG(MSG_ARG_OPTIONS
))) != -1) {
510 case 'A': /* alternative is optional */
511 flag
= RTC_OBJ_OPTINAL
;
513 case 'a': /* alternative required */
514 flag
|= (RTC_OBJ_ALTER
| RTC_OBJ_CMDLINE
);
515 if (inspect(&crle
, (const char *)optarg
, flag
) != 0)
523 if ((flag
= addenv(&crle
, (const char *)optarg
,
524 RTC_ENV_REPLACE
)) == 0)
526 else if ((crle
.c_flags
& CRLE_VERBOSE
) && (flag
== 1))
527 (void) printf(MSG_INTL(MSG_DIA_RPLENV
),
528 (const char *)optarg
);
532 if ((flag
= addenv(&crle
, (const char *)optarg
,
533 RTC_ENV_PERMANT
)) == 0)
535 else if ((crle
.c_flags
& CRLE_VERBOSE
) && (flag
== 1))
536 (void) printf(MSG_INTL(MSG_DIA_PRMENV
),
537 (const char *)optarg
);
543 case 'G': /* group object */
544 flag
= (RTC_OBJ_DUMP
| RTC_OBJ_ALTER
);
547 flag
|= (RTC_OBJ_GROUP
| RTC_OBJ_CMDLINE
);
548 if (inspect(&crle
, (const char *)optarg
, flag
) != 0)
552 case 'I': /* individual object */
553 flag
= (RTC_OBJ_DUMP
| RTC_OBJ_ALTER
);
556 flag
|= RTC_OBJ_CMDLINE
;
557 if (inspect(&crle
, (const char *)optarg
, flag
) != 0)
561 case 'l': /* library search path */
562 if (crle
.c_flags
& CRLE_AOUT
) {
563 str
= MSG_ORIG(MSG_STR_AOUT
);
564 lib
= &crle
.c_adlibpath
;
566 str
= MSG_ORIG(MSG_STR_ELF
);
567 lib
= &crle
.c_edlibpath
;
569 if (addlib(&crle
, lib
, (const char *)optarg
) != 0)
571 else if (crle
.c_flags
& CRLE_VERBOSE
)
572 (void) printf(MSG_INTL(MSG_DIA_DLIBPTH
),
573 str
, (const char *)optarg
);
577 crle
.c_objdir
= optarg
;
580 case 's': /* trusted (secure) path */
581 if (crle
.c_flags
& CRLE_AOUT
) {
582 str
= MSG_ORIG(MSG_STR_AOUT
);
583 lib
= &crle
.c_aslibpath
;
585 str
= MSG_ORIG(MSG_STR_ELF
);
586 lib
= &crle
.c_eslibpath
;
588 if (addlib(&crle
, lib
, (const char *)optarg
) != 0)
590 else if (crle
.c_flags
& CRLE_VERBOSE
)
591 (void) printf(MSG_INTL(MSG_DIA_TLIBPTH
),
592 str
, (const char *)optarg
);
595 case 't': /* search path type */
596 if (strcmp((const char *)optarg
,
597 MSG_ORIG(MSG_STR_ELF
)) == 0)
598 crle
.c_flags
&= ~CRLE_AOUT
;
600 crle
.c_flags
|= CRLE_AOUT
;
612 * Now that we've generated as many file/directory processing errors
613 * as we can, return if any fatal error conditions occurred.
616 (void) unlink(crle
.c_tempname
);
617 if (crle
.c_flags
& CRLE_CREAT
) {
618 (void) fprintf(stderr
, MSG_INTL(MSG_GEN_CREATE
),
619 crle
.c_name
, crle
.c_confil
);
625 * Create a temporary configuration file.
627 if (genconfig(&crle
) != 0) {
628 (void) unlink(crle
.c_tempname
);
633 * If dldump(3dl) images are required spawn a process to create them.
635 if (crle
.c_flags
& CRLE_DUMP
) {
636 if (dump(&crle
) != 0) {
637 (void) unlink(crle
.c_tempname
);
643 * Copy the finished temporary configuration file to its final home.
645 if (updateconfig(&crle
) != 0)