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