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