dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / sgs / crle / common / crle.c
blob7524cb0200041877d35616d8ca5bad4dfd2f9f10
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <locale.h>
33 #include <dlfcn.h>
34 #include <errno.h>
35 #include "_crle.h"
36 #include "conv.h"
37 #include "msg.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
45 * other arguments:
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
61 * information.
63 * -v verbose mode.
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
82 * to the cache.
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.
106 typedef struct {
107 char *o_objdir;
108 uint_t o_flags;
109 } Objdir;
111 /*ARGSUSED2*/
113 main(int argc, char **argv, char **envp)
115 Crle_desc crle = { 0 };
116 int c, error = 0;
117 char **lib;
118 Alist *objdirs = NULL;
119 Objdir *objdir, *iobjdir;
120 struct stat ostatus, nstatus;
121 int c_class;
123 if ((objdir = iobjdir = alist_append(&objdirs, NULL, sizeof (Objdir),
124 AL_CNT_CRLE)) == NULL)
125 return (1);
128 * Establish locale.
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;
140 c_class = M_CLASS;
143 * First argument pass.
145 while ((c = getopt(argc, argv, MSG_ORIG(MSG_ARG_OPTIONS))) != -1) {
146 switch (c) {
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;
156 c_class = ELFCLASS64;
157 break;
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);
164 break;
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;
172 crle.c_confil = optarg;
173 break;
175 case 'e': /* replaceable env variable */
176 crle.c_flags |= (CRLE_RPLENV | CRLE_CREAT);
177 break;
179 case 'E': /* permanent env variable */
180 crle.c_flags |= (CRLE_PRMENV | CRLE_CREAT);
181 break;
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;
189 if ((crle.c_dlflags = dlflags(&crle,
190 (const char *)optarg)) == 0)
191 error = 1;
192 break;
194 case 'G': /* group object */
195 crle.c_flags |= (CRLE_DUMP | CRLE_ALTER);
196 objdir->o_flags |= (CRLE_DUMP | CRLE_ALTER);
197 /* FALLTHROUGH */
198 case 'g':
199 crle.c_flags |= CRLE_CREAT;
200 objdir->o_flags |= CRLE_CREAT;
201 break;
203 case 'I': /* individual object */
204 crle.c_flags |= (CRLE_DUMP | CRLE_ALTER);
205 objdir->o_flags |= (CRLE_DUMP | CRLE_ALTER);
206 /* FALLTHROUGH */
207 case 'i':
208 crle.c_flags |= CRLE_CREAT;
209 objdir->o_flags |= CRLE_CREAT;
210 break;
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;
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)
224 return (1);
226 objdir->o_objdir = optarg;
227 break;
229 case 's': /* trusted (secure) path */
230 if (crle.c_flags & CRLE_AOUT)
231 crle.c_flags |= CRLE_ASLIB;
232 else
233 crle.c_flags |= CRLE_ESLIB;
234 crle.c_flags |= CRLE_CREAT;
235 break;
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;
244 else {
245 (void) fprintf(stderr, MSG_INTL(MSG_ARG_TYPE),
246 crle.c_name, optarg);
247 error = 1;
249 break;
251 case 'u': /* update mode */
252 crle.c_flags |= (CRLE_CREAT | CRLE_UPDATE);
253 break;
255 case 'v': /* verbose mode */
256 crle.c_flags |= CRLE_VERBOSE;
257 break;
259 default:
260 error = 2;
264 if (optind != argc)
265 error = 2;
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);
275 } else {
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.
284 if (error) {
285 if (error == 2) {
286 (void) fprintf(stderr, MSG_INTL(MSG_ARG_USAGE),
287 crle.c_name);
288 } else if (crle.c_flags & CRLE_CREAT) {
289 (void) fprintf(stderr, MSG_INTL(MSG_GEN_CREATE),
290 crle.c_name, crle.c_confil);
292 return (1);
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)) {
312 case INSCFG_RET_OK:
313 if ((crle.c_flags & CRLE_UPDATE) == 0)
314 return (0);
315 break;
316 case INSCFG_RET_FAIL:
317 return (1);
318 case INSCFG_RET_NEED64:
319 c_class = ELFCLASS64;
320 break;
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.
331 #ifdef _ELF64
332 if (c_class == ELFCLASS32) {
333 (void) fprintf(stderr, MSG_INTL(MSG_ARG_CLASS),
334 crle.c_name, crle.c_confil);
335 return (1);
337 #else
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),
348 crle.c_name);
349 return (1);
351 #endif
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.
362 (void) umask(022);
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) {
367 int err = errno;
368 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
369 crle.c_name, crle.c_confil, strerror(err));
370 return (1);
372 } else if (errno != ENOENT) {
373 int err = errno;
374 (void) fprintf(stderr, MSG_INTL(MSG_SYS_ACCESS), crle.c_name,
375 crle.c_confil, strerror(err));
376 return (1);
377 } else {
378 int fd;
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),
386 0666)) == -1) {
387 int err = errno;
388 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
389 crle.c_name, crle.c_confil, strerror(err));
390 return (1);
392 if (fstat(fd, &ostatus) != 0) {
393 int err = errno;
394 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
395 crle.c_name, crle.c_confil, strerror(err));
396 return (1);
398 (void) close(fd);
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) {
408 char *str;
411 * Use the configuration files directory.
413 if ((str = strrchr(crle.c_confil, '/')) == NULL)
414 objdir->o_objdir =
415 (char *)MSG_ORIG(MSG_DIR_DOT);
416 else {
417 int len = str - crle.c_confil;
419 if ((objdir->o_objdir =
420 malloc(len + 1)) == NULL) {
421 int err = errno;
422 (void) fprintf(stderr,
423 MSG_INTL(MSG_SYS_MALLOC),
424 crle.c_name, strerror(err));
425 return (1);
427 (void) strncpy(objdir->o_objdir,
428 crle.c_confil, len);
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) {
438 Objdir *objdir;
439 Aliste idx;
440 int err = 0;
442 for (ALIST_TRAVERSE(objdirs, idx, objdir)) {
443 if (crle.c_flags & CRLE_VERBOSE)
444 (void) printf(MSG_INTL(MSG_DIA_OBJDIR),
445 objdir->o_objdir);
447 if ((objdir->o_flags & CRLE_DUMP) == 0)
448 continue;
450 if (access(objdir->o_objdir,
451 (R_OK | W_OK)) != 0) {
452 err = errno;
453 (void) fprintf(stderr,
454 MSG_INTL(MSG_SYS_ACCESS),
455 crle.c_name, objdir->o_objdir,
456 strerror(err));
459 if (err)
460 return (1);
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
471 * information.
473 if ((crle.c_tempname = tempnam(MSG_ORIG(MSG_TMP_DIR),
474 MSG_ORIG(MSG_TMP_PFX))) == NULL) {
475 int err = errno;
476 (void) fprintf(stderr, MSG_INTL(MSG_SYS_TEMPNAME),
477 crle.c_name, strerror(err));
478 return (1);
480 if ((crle.c_tempfd = open(crle.c_tempname, (O_RDWR | O_CREAT),
481 0666)) == -1) {
482 int err = errno;
483 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
484 crle.c_name, crle.c_tempname, strerror(err));
485 return (1);
487 if (stat(crle.c_tempname, &nstatus) != 0) {
488 int err = errno;
489 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
490 crle.c_name, crle.c_tempname, strerror(err));
491 return (1);
493 if (ostatus.st_dev != nstatus.st_dev)
494 crle.c_flags |= CRLE_DIFFDEV;
497 * Second pass.
499 error = 0;
500 optind = 1;
501 while ((c = getopt(argc, argv, MSG_ORIG(MSG_ARG_OPTIONS))) != -1) {
502 const char *str;
503 int flag = 0;
505 switch (c) {
507 case '6':
508 break;
510 case 'A': /* alternative is optional */
511 flag = RTC_OBJ_OPTINAL;
512 /* FALLTHROUGH */
513 case 'a': /* alternative required */
514 flag |= (RTC_OBJ_ALTER | RTC_OBJ_CMDLINE);
515 if (inspect(&crle, (const char *)optarg, flag) != 0)
516 error = 1;
517 break;
519 case 'c':
520 break;
522 case 'e':
523 if ((flag = addenv(&crle, (const char *)optarg,
524 RTC_ENV_REPLACE)) == 0)
525 error = 1;
526 else if ((crle.c_flags & CRLE_VERBOSE) && (flag == 1))
527 (void) printf(MSG_INTL(MSG_DIA_RPLENV),
528 (const char *)optarg);
529 break;
531 case 'E':
532 if ((flag = addenv(&crle, (const char *)optarg,
533 RTC_ENV_PERMANT)) == 0)
534 error = 1;
535 else if ((crle.c_flags & CRLE_VERBOSE) && (flag == 1))
536 (void) printf(MSG_INTL(MSG_DIA_PRMENV),
537 (const char *)optarg);
538 break;
540 case 'f':
541 break;
543 case 'G': /* group object */
544 flag = (RTC_OBJ_DUMP | RTC_OBJ_ALTER);
545 /* FALLTHROUGH */
546 case 'g':
547 flag |= (RTC_OBJ_GROUP | RTC_OBJ_CMDLINE);
548 if (inspect(&crle, (const char *)optarg, flag) != 0)
549 error = 1;
550 break;
552 case 'I': /* individual object */
553 flag = (RTC_OBJ_DUMP | RTC_OBJ_ALTER);
554 /* FALLTHROUGH */
555 case 'i':
556 flag |= RTC_OBJ_CMDLINE;
557 if (inspect(&crle, (const char *)optarg, flag) != 0)
558 error = 1;
559 break;
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;
565 } else {
566 str = MSG_ORIG(MSG_STR_ELF);
567 lib = &crle.c_edlibpath;
569 if (addlib(&crle, lib, (const char *)optarg) != 0)
570 error = 1;
571 else if (crle.c_flags & CRLE_VERBOSE)
572 (void) printf(MSG_INTL(MSG_DIA_DLIBPTH),
573 str, (const char *)optarg);
574 break;
576 case 'o':
577 crle.c_objdir = optarg;
578 break;
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;
584 } else {
585 str = MSG_ORIG(MSG_STR_ELF);
586 lib = &crle.c_eslibpath;
588 if (addlib(&crle, lib, (const char *)optarg) != 0)
589 error = 1;
590 else if (crle.c_flags & CRLE_VERBOSE)
591 (void) printf(MSG_INTL(MSG_DIA_TLIBPTH),
592 str, (const char *)optarg);
593 break;
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;
599 else
600 crle.c_flags |= CRLE_AOUT;
601 break;
603 case 'u':
604 break;
606 case 'v':
607 break;
612 * Now that we've generated as many file/directory processing errors
613 * as we can, return if any fatal error conditions occurred.
615 if (error) {
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);
621 return (1);
625 * Create a temporary configuration file.
627 if (genconfig(&crle) != 0) {
628 (void) unlink(crle.c_tempname);
629 return (1);
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);
638 return (1);
643 * Copy the finished temporary configuration file to its final home.
645 if (updateconfig(&crle) != 0)
646 return (1);
648 return (0);