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 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 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