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