config.c revision 1976:f0691a145b7e
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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25#pragma ident	"%Z%%M%	%I%	%E% SMI"
26
27#include	<sys/mman.h>
28#include	<sys/types.h>
29#include	<fcntl.h>
30#include	<unistd.h>
31#include	<errno.h>
32#include	<stdio.h>
33#include	<string.h>
34#include	"rtc.h"
35#include	"_crle.h"
36#include	"msg.h"
37
38
39#define	MAXNBKTS 10007
40
41static const int hashsize[] = {
42	3,	7,	13,	31,	53,	67,	83,	97,
43	101,	151,	211,	251,	307,	353,	401,	457,	503,
44	557,	601,	653,	701,	751,	809,	859,	907,	953,
45	1009,	1103,	1201,	1301,	1409,	1511,	1601,	1709,	1801,
46	1901,	2003,	2111,	2203,	2309,	2411,	2503,	2609,	2707,
47	2801,	2903,	3001,	3109,	3203,	3301,	3407,	3511,	3607,
48	3701,	3803,	3907,	4001,	5003,   6101,   7001,   8101,   9001,
49	MAXNBKTS
50};
51
52/*
53 * Generate a configuration file from the internal configuration information.
54 * (very link-editor like).
55 */
56int
57genconfig(Crle_desc * crle)
58{
59	int		ndx, bkt;
60	size_t		size, hashoff = 0, stroff = 0, objoff = 0;
61	size_t		diroff = 0, fileoff = 0, envoff = 0;
62	size_t		fltroff = 0, flteoff = 0;
63	Addr		addr;
64	Rtc_id		*id;
65	Rtc_head	*head;
66	Word		*hashtbl, * hashbkt, * hashchn, hashbkts = 0;
67	char		*strtbl, *_strtbl;
68	Rtc_obj		*objtbl;
69	Rtc_dir		*dirtbl;
70	Rtc_file	*filetbl;
71	Rtc_env		*envtbl;
72	Rtc_fltr	*fltrtbl;
73	Rtc_flte	*fltetbl, * _fltetbl;
74	Hash_tbl	*stbl = crle->c_strtbl;
75	Hash_ent	*ent;
76
77	/*
78	 * Establish the size of the configuration file.
79	 */
80	size = S_ROUND(sizeof (Rtc_head), sizeof (Word));
81
82	if (crle->c_hashstrnum) {
83		hashoff = size;
84
85		/*
86		 * Increment the hash string number to account for an initial
87		 * null entry.  Indexes start at 1 to simplify hash lookup.
88		 */
89		crle->c_hashstrnum++;
90
91		/*
92		 * Determine the hash table size.  Establish the number of
93		 * buckets from the number of strings, the number of chains is
94		 * equivalent to the number of objects, and two entries for the
95		 * nbucket and nchain entries.
96		 */
97		for (ndx = 0; ndx < (sizeof (hashsize) / sizeof (int)); ndx++) {
98			if (crle->c_hashstrnum > hashsize[ndx])
99				continue;
100			hashbkts = hashsize[ndx];
101			break;
102		}
103		if (hashbkts == 0)
104			hashbkts = MAXNBKTS;
105		size += ((2 + hashbkts + crle->c_hashstrnum) * sizeof (Word));
106		size = S_ROUND(size, sizeof (Lword));
107		objoff = size;
108
109		/*
110		 * Add the object table size (account for an 8-byte alignment
111		 * requirement for each object).
112		 */
113		size += (crle->c_hashstrnum *
114		    S_ROUND(sizeof (Rtc_obj), sizeof (Lword)));
115
116		/*
117		 * Add the file descriptor arrays.
118		 */
119		fileoff = size;
120		size += S_ROUND((crle->c_filenum * sizeof (Rtc_file)),
121		    sizeof (Word));
122
123		/*
124		 * Add the directory descriptor array.
125		 */
126		diroff = size;
127		size += S_ROUND((crle->c_dirnum * sizeof (Rtc_dir)),
128		    sizeof (Word));
129	}
130
131	/*
132	 * Add any environment string array (insure zero last entry).
133	 */
134	if (crle->c_envnum) {
135		envoff = size;
136		size += S_ROUND(((crle->c_envnum + 1) * sizeof (Rtc_env)),
137		    sizeof (Word));
138	}
139
140	/*
141	 * Add any filter/filtee association arrays (insure zero last entry for
142	 * the filter array, the filtee arrays are already accounted for).
143	 */
144	if (crle->c_fltrnum) {
145		fltroff = size;
146		size += S_ROUND(((crle->c_fltrnum + 1) * sizeof (Rtc_fltr)),
147		    sizeof (Word));
148		flteoff = size;
149		size += S_ROUND((crle->c_fltenum * sizeof (Rtc_flte)),
150		    sizeof (Word));
151	}
152
153	/*
154	 * Add the string table size (this may contain library and/or secure
155	 * path strings, in addition to any directory/file strings).
156	 */
157	if (crle->c_strsize) {
158		stroff = size;
159		size += S_ROUND(crle->c_strsize, sizeof (Word));
160	}
161
162	/* Account for addition of Rtc_id block at the start */
163	if (crle->c_flags & CRLE_ADDID)
164		size += sizeof (Rtc_id);
165
166	/*
167	 * Truncate our temporary file now that we know its size and map it.
168	 */
169	if (ftruncate(crle->c_tempfd, size) == -1) {
170		int err = errno;
171		(void) fprintf(stderr, MSG_INTL(MSG_SYS_TRUNC),
172		    crle->c_name, crle->c_tempname, strerror(err));
173		(void) close(crle->c_tempfd);
174		return (1);
175	}
176	if ((addr = (Addr)mmap(0, size, (PROT_READ | PROT_WRITE), MAP_SHARED,
177	    crle->c_tempfd, 0)) == (Addr)-1) {
178		int err = errno;
179		(void) fprintf(stderr, MSG_INTL(MSG_SYS_MMAP),
180		    crle->c_name, crle->c_tempname, strerror(err));
181		(void) close(crle->c_tempfd);
182		return (1);
183	}
184
185	/*
186	 * Save the mapped files info for possible dldump(3dl) updates.
187	 */
188	crle->c_tempaddr = addr;
189	crle->c_tempsize = size;
190
191	/*
192	 * Rtc_id goes at the top, followed by the Rtc_head. We base
193	 * all offset calculations relative to Rtc_head, not from
194	 * the top of the file. This eases backwards compatability to
195	 * older versons that lacked the Rtc_id at the top.
196	 */
197	if (crle->c_flags & CRLE_ADDID) {
198		/* The contents of the Rtc_id are all known at compile time */
199		static const Rtc_id id_template = {
200			RTC_ID_MAG0, RTC_ID_MAG1, RTC_ID_MAG2, RTC_ID_MAG3,
201			M_CLASS, M_DATA, M_MACH,
202			{ 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
203
204		id = (Rtc_id *) addr;
205		*id = id_template;	/* Fill in the Rtc_id data */
206		addr += sizeof (Rtc_id);
207	} else {
208		id = NULL;
209	}
210	crle->c_tempheadaddr = addr;
211	head = (Rtc_head *)addr;
212
213	/*
214	 * Establish the real address of each of the structures within the file.
215	 */
216	head->ch_hash = hashoff;
217	/* LINTED */
218	hashtbl = (Word *)(CAST_PTRINT(char *, head->ch_hash) + addr);
219
220	head->ch_obj = objoff;
221	/* LINTED */
222	objtbl = (Rtc_obj *)(CAST_PTRINT(char *, head->ch_obj) + addr);
223	objtbl = (Rtc_obj *)S_ROUND((uintptr_t)(objtbl + 1), sizeof (Lword));
224
225	head->ch_file = fileoff;
226	/* LINTED */
227	filetbl = (Rtc_file *)(CAST_PTRINT(char *, head->ch_file) + addr);
228
229	head->ch_dir = diroff;
230	/* LINTED */
231	dirtbl = (Rtc_dir *)(CAST_PTRINT(char *, head->ch_dir) + addr);
232
233	head->ch_env = envoff;
234	/* LINTED */
235	envtbl = (Rtc_env *)(CAST_PTRINT(char *, head->ch_env) + addr);
236
237	head->ch_fltr = fltroff;
238	/* LINTED */
239	fltrtbl = (Rtc_fltr *)(CAST_PTRINT(char *, head->ch_fltr) + addr);
240	head->ch_flte = flteoff;
241	/* LINTED */
242	fltetbl = _fltetbl =
243		(Rtc_flte *)(CAST_PTRINT(char *, head->ch_flte) + addr);
244
245	head->ch_str = stroff;
246	strtbl = _strtbl = (char *)(CAST_PTRINT(char *, head->ch_str) + addr);
247
248	/*
249	 * Fill in additional basic header information.
250	 */
251	head->ch_version = RTC_VER_CURRENT;
252
253	if (crle->c_flags & CRLE_ALTER)
254		head->ch_cnflags |= RTC_HDR_ALTER;
255	if (crle->c_flags & CRLE_DUMP) {
256		head->ch_cnflags |= RTC_HDR_IGNORE;
257		head->ch_dlflags = crle->c_dlflags;
258	}
259#ifdef _ELF64
260	head->ch_cnflags |= RTC_HDR_64;
261#endif
262
263#ifndef	SGS_PRE_UNIFIED_PROCESS
264	head->ch_cnflags |= RTC_HDR_UPM;
265#endif
266	/*
267	 * If we have a hash table then there are directory and file entries
268	 * to process.
269	 */
270	if (crle->c_hashstrnum) {
271		hashtbl[0] = hashbkts;
272		hashtbl[1] = crle->c_hashstrnum;
273		hashbkt = &hashtbl[2];
274		hashchn = &hashtbl[2 + hashbkts];
275
276		/*
277		 * Insure all hash chain and directory/filename table entries
278		 * are cleared.
279		 */
280		(void) memset(hashchn, 0, (crle->c_hashstrnum * sizeof (Word)));
281		(void) memset(dirtbl, 0, (strtbl - (char *)dirtbl));
282
283		/*
284		 * Loop through the current string table list inspecting only
285		 * directories.
286		 */
287		for (ndx = 1, bkt = 0; bkt < stbl->t_size; bkt++) {
288			for (ent = stbl->t_entry[bkt]; ent; ent = ent->e_next) {
289				Word		hashval;
290				Hash_obj	*obj = ent->e_obj;
291				char		*dir = (char *)ent->e_key;
292				Rtc_dir		*_dirtbl;
293
294				/*
295				 * Skip any empty and non-directory entries.
296				 */
297				if ((obj == 0) ||
298				    ((obj->o_flags & RTC_OBJ_DIRENT) == 0))
299					continue;
300
301				/*
302				 * Assign basic object attributes.
303				 */
304				objtbl->co_hash = ent->e_hash;
305				objtbl->co_id = ent->e_id;
306				objtbl->co_flags = obj->o_flags | ent->e_flags;
307				objtbl->co_info = obj->o_info;
308
309				ent->e_cobj = objtbl;
310
311				/*
312				 * Assign the directory name (from its key),
313				 * and copy its name to the string table.
314				 */
315				objtbl->co_name = (Addr)(_strtbl - strtbl);
316				(void) strcpy(_strtbl, dir);
317				_strtbl += strlen(dir) + 1;
318
319				/*
320				 * Establish an entry in the directory table and
321				 * reserve space for its associated filename
322				 * entries (note, we add a trailing null file
323				 * entry to simplify later inspection of the
324				 * final configuration file.
325				 */
326				_dirtbl = &dirtbl[ent->e_id - 1];
327				_dirtbl->cd_file =
328				    CAST_PTRINT(Word, ((char *)filetbl- addr));
329				_dirtbl->cd_obj =
330				    CAST_PTRINT(Word, ((char *)objtbl - addr));
331
332				/* LINTED */
333				filetbl = (Rtc_file *)((char *)filetbl +
334				    ((ent->e_cnt + 1) * sizeof (Rtc_file)));
335
336				/*
337				 * Add this object to the hash table.
338				 */
339				hashval = ent->e_hash % hashbkts;
340				hashchn[ndx] = hashbkt[hashval];
341				hashbkt[hashval] = ndx++;
342
343				/*
344				 * Increment Rt_obj pointer (make sure pointer
345				 * falls on an 8-byte boundary).
346				 */
347				objtbl = (Rtc_obj *)
348					S_ROUND((uintptr_t)(objtbl + 1),
349						sizeof (Lword));
350			}
351		}
352
353		/*
354		 * Now collect all pathnames.  These are typically full
355		 * pathnames, but may also be relative.  Simple filenames are
356		 * recorded as offsets into these pathnames, thus we need to
357		 * establish the new pathname first.
358		 */
359		for (bkt = 0; bkt < stbl->t_size; bkt++) {
360			for (ent = stbl->t_entry[bkt]; ent; ent = ent->e_next) {
361				Word		hashval;
362				Hash_obj	*obj = ent->e_obj;
363				char		*file = (char *)ent->e_key;
364				char		*_str;
365				Rtc_dir		*_dirtbl;
366				Rtc_file	*_filetbl;
367				int		_id;
368
369				/*
370				 * Skip empty and directory entries, and any
371				 * simple filename entries.
372				 */
373				if ((obj == 0) ||
374				    (obj->o_flags & RTC_OBJ_DIRENT) ||
375				    (ent->e_off))
376					continue;
377
378				/*
379				 * Assign basic object attributes.
380				 */
381				objtbl->co_hash = ent->e_hash;
382				objtbl->co_id = ent->e_id;
383				objtbl->co_flags = obj->o_flags | ent->e_flags;
384				objtbl->co_info = obj->o_info;
385
386				ent->e_cobj = objtbl;
387
388				/*
389				 * Assign the file name (from its key),
390				 * and copy its name to the string table.
391				 */
392				objtbl->co_name = (Addr)(_strtbl - strtbl);
393				(void) strcpy(_strtbl, file);
394				_strtbl += strlen(file) + 1;
395
396				/*
397				 * Add this file to its associated directory.
398				 */
399				_dirtbl = &dirtbl[ent->e_id - 1];
400				/* LINTED */
401				_filetbl = (Rtc_file *)
402				    (CAST_PTRINT(char *, _dirtbl->cd_file)
403					+ addr);
404
405				_id = --ent->e_dir->e_cnt;
406				_filetbl[_id].cf_obj =
407				    CAST_PTRINT(Word, ((char *)objtbl - addr));
408
409				/*
410				 * If object has an alternative, record it in
411				 * the string table and assign the alternate
412				 * pointer.  The new alternative offset is
413				 * retained for reuse in other filename entries.
414				 */
415				if ((objtbl->co_flags & RTC_OBJ_ALTER) &&
416				    (obj->o_calter == 0)) {
417					_str = obj->o_alter;
418					objtbl->co_alter = obj->o_calter =
419					    (Addr)(_strtbl - strtbl);
420					(void) strcpy(_strtbl, _str);
421					_strtbl += strlen(_str) + 1;
422				} else
423					objtbl->co_alter = obj->o_calter;
424
425				/*
426				 * If object identifies the specific application
427				 * for which this cache is relevant, record it
428				 * in the header.
429				 */
430				if ((objtbl->co_flags &
431				    (RTC_OBJ_APP | RTC_OBJ_REALPTH)) ==
432				    (RTC_OBJ_APP | RTC_OBJ_REALPTH))
433					head->ch_app = _filetbl[_id].cf_obj;
434
435				/*
436				 * Add this object to the hash table.
437				 */
438				hashval = ent->e_hash % hashbkts;
439				hashchn[ndx] = hashbkt[hashval];
440				hashbkt[hashval] = ndx++;
441
442				/*
443				 * Increment Rt_obj pointer (make sure pointer
444				 * falls on an 8-byte boundary).
445				 */
446				objtbl = (Rtc_obj *)
447				    S_ROUND((uintptr_t)(objtbl + 1),
448				    sizeof (Lword));
449			}
450		}
451
452		/*
453		 * Finally pick off any simple filenames.
454		 */
455		for (bkt = 0; bkt < stbl->t_size; bkt++) {
456			for (ent = stbl->t_entry[bkt]; ent; ent = ent->e_next) {
457				Word		hashval;
458				Hash_obj *	obj = ent->e_obj;
459				Rtc_dir *	_dirtbl;
460				Rtc_file *	_filetbl;
461				int		_id;
462
463				/*
464				 * Skip everything except simple filenames.
465				 */
466				if (ent->e_off == 0)
467					continue;
468
469				/*
470				 * Assign basic object attributes.
471				 */
472				objtbl->co_hash = ent->e_hash;
473				objtbl->co_id = ent->e_id;
474				objtbl->co_flags = obj->o_flags | ent->e_flags;
475				objtbl->co_info = obj->o_info;
476				objtbl->co_alter = obj->o_calter;
477
478				ent->e_cobj = objtbl;
479
480				/*
481				 * Assign the file name from its full name.
482				 */
483				objtbl->co_name = (Addr)(CAST_PTRINT(char *,
484				    ent->e_path->e_cobj->co_name) + ent->e_off);
485
486				/*
487				 * Add this file to its associated directory.
488				 */
489				_dirtbl = &dirtbl[ent->e_id - 1];
490				/* LINTED */
491				_filetbl = (Rtc_file *)
492				    (CAST_PTRINT(char *, _dirtbl->cd_file) +
493				    addr);
494
495				_id = --ent->e_dir->e_cnt;
496				_filetbl[_id].cf_obj =
497				    CAST_PTRINT(Word, ((char *)objtbl - addr));
498
499				/*
500				 * Add this object to the hash table.
501				 */
502				hashval = ent->e_hash % hashbkts;
503				hashchn[ndx] = hashbkt[hashval];
504				hashbkt[hashval] = ndx++;
505
506				/*
507				 * Increment Rt_obj pointer (make sure pointer
508				 * falls on an 8-byte boundary).
509				 */
510				objtbl = (Rtc_obj *)
511				    S_ROUND((uintptr_t)(objtbl + 1),
512				    sizeof (Lword));
513			}
514		}
515	}
516
517	/*
518	 * Add any library, or secure path definitions.
519	 */
520	if (crle->c_edlibpath) {
521		head->ch_edlibpath = head->ch_str + (_strtbl - strtbl);
522
523		(void) strcpy(_strtbl, crle->c_edlibpath);
524		_strtbl += strlen((char *)crle->c_edlibpath) + 1;
525	} else
526		head->ch_edlibpath = 0;
527
528	if (crle->c_adlibpath) {
529		head->ch_adlibpath = head->ch_str + (_strtbl - strtbl);
530
531		(void) strcpy(_strtbl, crle->c_adlibpath);
532		_strtbl += strlen((char *)crle->c_adlibpath) + 1;
533	} else
534		head->ch_adlibpath = 0;
535
536	if (crle->c_eslibpath) {
537		head->ch_eslibpath = head->ch_str + (_strtbl - strtbl);
538
539		(void) strcpy(_strtbl, crle->c_eslibpath);
540		_strtbl += strlen((char *)crle->c_eslibpath) + 1;
541	} else
542		head->ch_eslibpath = 0;
543
544	if (crle->c_aslibpath) {
545		head->ch_aslibpath = head->ch_str + (_strtbl - strtbl);
546
547		(void) strcpy(_strtbl, crle->c_aslibpath);
548		_strtbl += strlen((char *)crle->c_aslibpath) + 1;
549	} else
550		head->ch_aslibpath = 0;
551
552	/*
553	 * Add any environment variable entries.
554	 */
555	if (crle->c_envnum) {
556		Env_desc *	env;
557		Listnode *	lnp;
558
559		for (LIST_TRAVERSE(&(crle->c_env), lnp, env)) {
560			envtbl->env_str = head->ch_str + (_strtbl - strtbl);
561			envtbl->env_flags = env->e_flags;
562
563			(void) strcpy(_strtbl, env->e_str);
564			_strtbl += env->e_totsz;
565
566			envtbl++;
567		}
568		envtbl->env_str = 0;
569		envtbl->env_flags = 0;
570	}
571
572	/*
573	 * Add any filter/filtee association entries.
574	 */
575	if (crle->c_fltrnum) {
576		Flt_desc *	flt;
577		Listnode *	lnp1;
578
579		for (LIST_TRAVERSE(&(crle->c_flt), lnp1, flt)) {
580			Hash_ent *	flte;
581			Listnode *	lnp2;
582
583			/*
584			 * Establish the filter name, and filtee string, as
585			 * offsets into the configuration files string table.
586			 * Establish the filtee as the offset into the filtee
587			 * table.
588			 */
589			fltrtbl->fr_filter = flt->f_fent->e_cobj->co_name;
590			fltrtbl->fr_string = _strtbl - strtbl;
591			(void) strcpy(_strtbl, flt->f_str);
592			_strtbl += flt->f_strsz;
593			fltrtbl->fr_filtee = (Word)
594			    ((uintptr_t)_fltetbl - (uintptr_t)fltetbl);
595
596			for (LIST_TRAVERSE(&(flt->f_filtee), lnp2, flte)) {
597				/*
598				 * Establish the filtee name as the offset into
599				 * the configuration files string table.
600				 */
601				_fltetbl->fe_filtee = flte->e_cobj->co_name;
602				_fltetbl++;
603			}
604			_fltetbl->fe_filtee = 0;
605			_fltetbl++, fltrtbl++;
606		}
607		fltrtbl->fr_filter = 0;
608		fltrtbl->fr_filtee = 0;
609	}
610
611	/*
612	 * Flush everything out.
613	 */
614	(void) close(crle->c_tempfd);
615	if (msync((void *)crle->c_tempaddr, crle->c_tempsize, MS_ASYNC) == -1) {
616		int err = errno;
617		(void) fprintf(stderr, MSG_INTL(MSG_SYS_TRUNC),
618		    crle->c_name, crle->c_tempname, strerror(err));
619		return (1);
620	}
621
622	return (0);
623}
624
625/*
626 * Update a configuration file.  If dldump()'ed images have been created then
627 * the memory reservation of those images is added to the configuration file.
628 * The temporary file is then moved into its final resting place.
629 */
630int
631updateconfig(Crle_desc * crle)
632{
633	Rtc_head *head = (Rtc_head *)crle->c_tempheadaddr;
634
635	if (crle->c_flags & CRLE_DUMP) {
636		head->ch_cnflags &= ~RTC_HDR_IGNORE;
637
638		if (msync((void *)crle->c_tempaddr, crle->c_tempsize,
639		    MS_ASYNC) == -1) {
640			int err = errno;
641			(void) fprintf(stderr, MSG_INTL(MSG_SYS_TRUNC),
642			    crle->c_name, crle->c_tempname, strerror(err));
643			return (1);
644		}
645	}
646
647	/*
648	 * If an original configuration file exists, remove it.
649	 */
650	if (crle->c_flags & CRLE_EXISTS)
651		(void) unlink(crle->c_confil);
652
653	/*
654	 * Move the config file to its final resting place.  If the two files
655	 * exist on the same filesystem a rename is sufficient.
656	 */
657	if (crle->c_flags & CRLE_DIFFDEV) {
658		int	fd;
659
660		if ((fd = open(crle->c_confil, (O_RDWR | O_CREAT | O_TRUNC),
661		    0666)) == -1) {
662			int err = errno;
663			(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
664			    crle->c_name, crle->c_confil, strerror(err));
665			return (1);
666		}
667		if (write(fd, (void *)crle->c_tempaddr, crle->c_tempsize) !=
668		    crle->c_tempsize) {
669			int err = errno;
670			(void) fprintf(stderr, MSG_INTL(MSG_SYS_WRITE),
671			    crle->c_name, crle->c_confil, strerror(err));
672			return (1);
673		}
674		(void) close(fd);
675		(void) unlink(crle->c_tempname);
676	} else
677		(void) rename(crle->c_tempname, crle->c_confil);
678
679	return (0);
680}
681