xref: /illumos-gate/usr/src/cmd/sgs/crle/common/crle.c (revision e37d48e735b8e55f327dfa35a2d0006049ea5e58)
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