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