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 head->ch_cnflags |= RTC_HDR_UPM; 263 /* 264 * If we have a hash table then there are directory and file entries 265 * to process. 266 */ 267 if (crle->c_hashstrnum) { 268 hashtbl[0] = hashbkts; 269 hashtbl[1] = crle->c_hashstrnum; 270 hashbkt = &hashtbl[2]; 271 hashchn = &hashtbl[2 + hashbkts]; 272 273 /* 274 * Insure all hash chain and directory/filename table entries 275 * are cleared. 276 */ 277 (void) memset(hashchn, 0, (crle->c_hashstrnum * sizeof (Word))); 278 (void) memset(dirtbl, 0, (strtbl - (char *)dirtbl)); 279 280 /* 281 * Loop through the current string table list inspecting only 282 * directories. 283 */ 284 for (ndx = 1, bkt = 0; bkt < stbl->t_size; bkt++) { 285 for (ent = stbl->t_entry[bkt]; ent; ent = ent->e_next) { 286 Word hashval; 287 Hash_obj *obj = ent->e_obj; 288 char *dir = (char *)ent->e_key; 289 Rtc_dir *_dirtbl; 290 291 /* 292 * Skip any empty and non-directory entries. 293 */ 294 if ((obj == NULL) || 295 ((obj->o_flags & RTC_OBJ_DIRENT) == 0)) 296 continue; 297 298 /* 299 * Assign basic object attributes. 300 */ 301 objtbl->co_hash = ent->e_hash; 302 objtbl->co_id = ent->e_id; 303 objtbl->co_flags = obj->o_flags | ent->e_flags; 304 objtbl->co_info = obj->o_info; 305 306 ent->e_cobj = objtbl; 307 308 /* 309 * Assign the directory name (from its key), 310 * and copy its name to the string table. 311 */ 312 objtbl->co_name = (Addr)(_strtbl - strtbl); 313 (void) strcpy(_strtbl, dir); 314 _strtbl += strlen(dir) + 1; 315 316 /* 317 * Establish an entry in the directory table and 318 * reserve space for its associated filename 319 * entries (note, we add a trailing null file 320 * entry to simplify later inspection of the 321 * final configuration file. 322 */ 323 _dirtbl = &dirtbl[ent->e_id - 1]; 324 _dirtbl->cd_file = 325 CAST_PTRINT(Word, ((char *)filetbl- addr)); 326 _dirtbl->cd_obj = 327 CAST_PTRINT(Word, ((char *)objtbl - addr)); 328 329 /* LINTED */ 330 filetbl = (Rtc_file *)((char *)filetbl + 331 ((ent->e_cnt + 1) * sizeof (Rtc_file))); 332 333 /* 334 * Add this object to the hash table. 335 */ 336 hashval = ent->e_hash % hashbkts; 337 hashchn[ndx] = hashbkt[hashval]; 338 hashbkt[hashval] = ndx++; 339 340 /* 341 * Increment Rt_obj pointer (make sure pointer 342 * falls on an 8-byte boundary). 343 */ 344 objtbl = 345 (Rtc_obj *)S_ROUND((uintptr_t)(objtbl + 1), 346 sizeof (Lword)); 347 } 348 } 349 350 /* 351 * Now collect all pathnames. These are typically full 352 * pathnames, but may also be relative. Simple filenames are 353 * recorded as offsets into these pathnames, thus we need to 354 * establish the new pathname first. 355 */ 356 for (bkt = 0; bkt < stbl->t_size; bkt++) { 357 for (ent = stbl->t_entry[bkt]; ent; ent = ent->e_next) { 358 Word hashval; 359 Hash_obj *obj = ent->e_obj; 360 char *file = (char *)ent->e_key; 361 char *_str; 362 Rtc_dir *_dirtbl; 363 Rtc_file *_filetbl; 364 int _id; 365 366 /* 367 * Skip empty and directory entries, and any 368 * simple filename entries. 369 */ 370 if ((obj == NULL) || 371 (obj->o_flags & RTC_OBJ_DIRENT) || 372 (ent->e_off)) 373 continue; 374 375 /* 376 * Assign basic object attributes. 377 */ 378 objtbl->co_hash = ent->e_hash; 379 objtbl->co_id = ent->e_id; 380 objtbl->co_flags = obj->o_flags | ent->e_flags; 381 objtbl->co_info = obj->o_info; 382 383 ent->e_cobj = objtbl; 384 385 /* 386 * Assign the file name (from its key), 387 * and copy its name to the string table. 388 */ 389 objtbl->co_name = (Addr)(_strtbl - strtbl); 390 (void) strcpy(_strtbl, file); 391 _strtbl += strlen(file) + 1; 392 393 /* 394 * Add this file to its associated directory. 395 */ 396 _dirtbl = &dirtbl[ent->e_id - 1]; 397 /* LINTED */ 398 _filetbl = (Rtc_file *)(CAST_PTRINT(char *, 399 _dirtbl->cd_file) + addr); 400 401 _id = --ent->e_dir->e_cnt; 402 _filetbl[_id].cf_obj = 403 CAST_PTRINT(Word, ((char *)objtbl - addr)); 404 405 /* 406 * If object has an alternative, record it in 407 * the string table and assign the alternate 408 * pointer. The new alternative offset is 409 * retained for reuse in other filename entries. 410 */ 411 if ((objtbl->co_flags & RTC_OBJ_ALTER) && 412 (obj->o_calter == 0)) { 413 _str = obj->o_alter; 414 objtbl->co_alter = obj->o_calter = 415 (Addr)(_strtbl - strtbl); 416 (void) strcpy(_strtbl, _str); 417 _strtbl += strlen(_str) + 1; 418 } else 419 objtbl->co_alter = obj->o_calter; 420 421 /* 422 * If object identifies the specific application 423 * for which this cache is relevant, record it 424 * in the header. 425 */ 426 if ((objtbl->co_flags & 427 (RTC_OBJ_APP | RTC_OBJ_REALPTH)) == 428 (RTC_OBJ_APP | RTC_OBJ_REALPTH)) 429 head->ch_app = _filetbl[_id].cf_obj; 430 431 /* 432 * Add this object to the hash table. 433 */ 434 hashval = ent->e_hash % hashbkts; 435 hashchn[ndx] = hashbkt[hashval]; 436 hashbkt[hashval] = ndx++; 437 438 /* 439 * Increment Rt_obj pointer (make sure pointer 440 * falls on an 8-byte boundary). 441 */ 442 objtbl = (Rtc_obj *) 443 S_ROUND((uintptr_t)(objtbl + 1), 444 sizeof (Lword)); 445 } 446 } 447 448 /* 449 * Finally pick off any simple filenames. 450 */ 451 for (bkt = 0; bkt < stbl->t_size; bkt++) { 452 for (ent = stbl->t_entry[bkt]; ent; ent = ent->e_next) { 453 Word hashval; 454 Hash_obj * obj = ent->e_obj; 455 Rtc_dir * _dirtbl; 456 Rtc_file * _filetbl; 457 int _id; 458 459 /* 460 * Skip everything except simple filenames. 461 */ 462 if (ent->e_off == 0) 463 continue; 464 465 /* 466 * Assign basic object attributes. 467 */ 468 objtbl->co_hash = ent->e_hash; 469 objtbl->co_id = ent->e_id; 470 objtbl->co_flags = obj->o_flags | ent->e_flags; 471 objtbl->co_info = obj->o_info; 472 objtbl->co_alter = obj->o_calter; 473 474 ent->e_cobj = objtbl; 475 476 /* 477 * Assign the file name from its full name. 478 */ 479 objtbl->co_name = (Addr)(CAST_PTRINT(char *, 480 ent->e_path->e_cobj->co_name) + ent->e_off); 481 482 /* 483 * Add this file to its associated directory. 484 */ 485 _dirtbl = &dirtbl[ent->e_id - 1]; 486 /* LINTED */ 487 _filetbl = (Rtc_file *) 488 (CAST_PTRINT(char *, _dirtbl->cd_file) + 489 addr); 490 491 _id = --ent->e_dir->e_cnt; 492 _filetbl[_id].cf_obj = 493 CAST_PTRINT(Word, ((char *)objtbl - addr)); 494 495 /* 496 * Add this object to the hash table. 497 */ 498 hashval = ent->e_hash % hashbkts; 499 hashchn[ndx] = hashbkt[hashval]; 500 hashbkt[hashval] = ndx++; 501 502 /* 503 * Increment Rt_obj pointer (make sure pointer 504 * falls on an 8-byte boundary). 505 */ 506 objtbl = (Rtc_obj *) 507 S_ROUND((uintptr_t)(objtbl + 1), 508 sizeof (Lword)); 509 } 510 } 511 } 512 513 /* 514 * Add any library, or secure path definitions. 515 */ 516 if (crle->c_edlibpath) { 517 head->ch_edlibpath = head->ch_str + (_strtbl - strtbl); 518 519 (void) strcpy(_strtbl, crle->c_edlibpath); 520 _strtbl += strlen((char *)crle->c_edlibpath) + 1; 521 } else 522 head->ch_edlibpath = 0; 523 524 if (crle->c_adlibpath) { 525 head->ch_adlibpath = head->ch_str + (_strtbl - strtbl); 526 527 (void) strcpy(_strtbl, crle->c_adlibpath); 528 _strtbl += strlen((char *)crle->c_adlibpath) + 1; 529 } else 530 head->ch_adlibpath = 0; 531 532 if (crle->c_eslibpath) { 533 head->ch_eslibpath = head->ch_str + (_strtbl - strtbl); 534 535 (void) strcpy(_strtbl, crle->c_eslibpath); 536 _strtbl += strlen((char *)crle->c_eslibpath) + 1; 537 } else 538 head->ch_eslibpath = 0; 539 540 if (crle->c_aslibpath) { 541 head->ch_aslibpath = head->ch_str + (_strtbl - strtbl); 542 543 (void) strcpy(_strtbl, crle->c_aslibpath); 544 _strtbl += strlen((char *)crle->c_aslibpath) + 1; 545 } else 546 head->ch_aslibpath = 0; 547 548 /* 549 * Add any environment variable entries. 550 */ 551 if (crle->c_envnum) { 552 Env_desc *env; 553 Aliste idx; 554 555 for (APLIST_TRAVERSE(crle->c_env, idx, env)) { 556 envtbl->env_str = head->ch_str + (_strtbl - strtbl); 557 envtbl->env_flags = env->e_flags; 558 559 (void) strcpy(_strtbl, env->e_str); 560 _strtbl += env->e_totsz; 561 562 envtbl++; 563 } 564 envtbl->env_str = 0; 565 envtbl->env_flags = 0; 566 } 567 568 /* 569 * Add any filter/filtee association entries. 570 */ 571 if (crle->c_fltrnum) { 572 Flt_desc *flt; 573 Aliste idx1; 574 575 for (APLIST_TRAVERSE(crle->c_flt, idx1, flt)) { 576 Hash_ent *flte; 577 Aliste idx2; 578 579 /* 580 * Establish the filter name, and filtee string, as 581 * offsets into the configuration files string table. 582 * Establish the filtee as the offset into the filtee 583 * table. 584 */ 585 fltrtbl->fr_filter = flt->f_fent->e_cobj->co_name; 586 fltrtbl->fr_string = _strtbl - strtbl; 587 (void) strcpy(_strtbl, flt->f_str); 588 _strtbl += flt->f_strsz; 589 fltrtbl->fr_filtee = (Word) 590 ((uintptr_t)_fltetbl - (uintptr_t)fltetbl); 591 592 for (APLIST_TRAVERSE(flt->f_filtee, idx2, flte)) { 593 /* 594 * Establish the filtee name as the offset into 595 * the configuration files string table. 596 */ 597 _fltetbl->fe_filtee = flte->e_cobj->co_name; 598 _fltetbl++; 599 } 600 _fltetbl->fe_filtee = 0; 601 _fltetbl++, fltrtbl++; 602 } 603 fltrtbl->fr_filter = 0; 604 fltrtbl->fr_filtee = 0; 605 } 606 607 /* 608 * Flush everything out. 609 */ 610 (void) close(crle->c_tempfd); 611 if (msync((void *)crle->c_tempaddr, crle->c_tempsize, MS_ASYNC) == -1) { 612 int err = errno; 613 (void) fprintf(stderr, MSG_INTL(MSG_SYS_TRUNC), 614 crle->c_name, crle->c_tempname, strerror(err)); 615 return (1); 616 } 617 618 return (0); 619 } 620 621 /* 622 * Update a configuration file. If dldump()'ed images have been created then 623 * the memory reservation of those images is added to the configuration file. 624 * The temporary file is then moved into its final resting place. 625 */ 626 int 627 updateconfig(Crle_desc * crle) 628 { 629 Rtc_head *head = (Rtc_head *)crle->c_tempheadaddr; 630 631 if (crle->c_flags & CRLE_DUMP) { 632 head->ch_cnflags &= ~RTC_HDR_IGNORE; 633 634 if (msync((void *)crle->c_tempaddr, crle->c_tempsize, 635 MS_ASYNC) == -1) { 636 int err = errno; 637 (void) fprintf(stderr, MSG_INTL(MSG_SYS_TRUNC), 638 crle->c_name, crle->c_tempname, strerror(err)); 639 return (1); 640 } 641 } 642 643 /* 644 * If an original configuration file exists, remove it. 645 */ 646 if (crle->c_flags & CRLE_EXISTS) 647 (void) unlink(crle->c_confil); 648 649 /* 650 * Move the config file to its final resting place. If the two files 651 * exist on the same filesystem a rename is sufficient. 652 */ 653 if (crle->c_flags & CRLE_DIFFDEV) { 654 int fd; 655 656 if ((fd = open(crle->c_confil, (O_RDWR | O_CREAT | O_TRUNC), 657 0666)) == -1) { 658 int err = errno; 659 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), 660 crle->c_name, crle->c_confil, strerror(err)); 661 return (1); 662 } 663 if (write(fd, (void *)crle->c_tempaddr, crle->c_tempsize) != 664 crle->c_tempsize) { 665 int err = errno; 666 (void) fprintf(stderr, MSG_INTL(MSG_SYS_WRITE), 667 crle->c_name, crle->c_confil, strerror(err)); 668 return (1); 669 } 670 (void) close(fd); 671 (void) unlink(crle->c_tempname); 672 } else 673 (void) rename(crle->c_tempname, crle->c_confil); 674 675 return (0); 676 } 677