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 41 static 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 */ 56 int 57 genconfig(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 */ 630 int 631 updateconfig(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