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 /* 525 * a.out is no longer supported, but remains in the crle file 526 * format 527 */ 528 head->ch_adlibpath = 0; 529 530 if (crle->c_eslibpath) { 531 head->ch_eslibpath = head->ch_str + (_strtbl - strtbl); 532 533 (void) strcpy(_strtbl, crle->c_eslibpath); 534 _strtbl += strlen((char *)crle->c_eslibpath) + 1; 535 } else 536 head->ch_eslibpath = 0; 537 538 /* 539 * a.out is no longer supported, but remains in the crle file 540 * format 541 */ 542 head->ch_aslibpath = 0; 543 544 /* 545 * Add any environment variable entries. 546 */ 547 if (crle->c_envnum) { 548 Env_desc *env; 549 Aliste idx; 550 551 for (APLIST_TRAVERSE(crle->c_env, idx, env)) { 552 envtbl->env_str = head->ch_str + (_strtbl - strtbl); 553 envtbl->env_flags = env->e_flags; 554 555 (void) strcpy(_strtbl, env->e_str); 556 _strtbl += env->e_totsz; 557 558 envtbl++; 559 } 560 envtbl->env_str = 0; 561 envtbl->env_flags = 0; 562 } 563 564 /* 565 * Add any filter/filtee association entries. 566 */ 567 if (crle->c_fltrnum) { 568 Flt_desc *flt; 569 Aliste idx1; 570 571 for (APLIST_TRAVERSE(crle->c_flt, idx1, flt)) { 572 Hash_ent *flte; 573 Aliste idx2; 574 575 /* 576 * Establish the filter name, and filtee string, as 577 * offsets into the configuration files string table. 578 * Establish the filtee as the offset into the filtee 579 * table. 580 */ 581 fltrtbl->fr_filter = flt->f_fent->e_cobj->co_name; 582 fltrtbl->fr_string = _strtbl - strtbl; 583 (void) strcpy(_strtbl, flt->f_str); 584 _strtbl += flt->f_strsz; 585 fltrtbl->fr_filtee = (Word) 586 ((uintptr_t)_fltetbl - (uintptr_t)fltetbl); 587 588 for (APLIST_TRAVERSE(flt->f_filtee, idx2, flte)) { 589 /* 590 * Establish the filtee name as the offset into 591 * the configuration files string table. 592 */ 593 _fltetbl->fe_filtee = flte->e_cobj->co_name; 594 _fltetbl++; 595 } 596 _fltetbl->fe_filtee = 0; 597 _fltetbl++, fltrtbl++; 598 } 599 fltrtbl->fr_filter = 0; 600 fltrtbl->fr_filtee = 0; 601 } 602 603 /* 604 * Flush everything out. 605 */ 606 (void) close(crle->c_tempfd); 607 if (msync((void *)crle->c_tempaddr, crle->c_tempsize, MS_ASYNC) == -1) { 608 int err = errno; 609 (void) fprintf(stderr, MSG_INTL(MSG_SYS_TRUNC), 610 crle->c_name, crle->c_tempname, strerror(err)); 611 return (1); 612 } 613 614 return (0); 615 } 616 617 /* 618 * Update a configuration file. If dldump()'ed images have been created then 619 * the memory reservation of those images is added to the configuration file. 620 * The temporary file is then moved into its final resting place. 621 */ 622 int 623 updateconfig(Crle_desc * crle) 624 { 625 Rtc_head *head = (Rtc_head *)crle->c_tempheadaddr; 626 627 if (crle->c_flags & CRLE_DUMP) { 628 head->ch_cnflags &= ~RTC_HDR_IGNORE; 629 630 if (msync((void *)crle->c_tempaddr, crle->c_tempsize, 631 MS_ASYNC) == -1) { 632 int err = errno; 633 (void) fprintf(stderr, MSG_INTL(MSG_SYS_TRUNC), 634 crle->c_name, crle->c_tempname, strerror(err)); 635 return (1); 636 } 637 } 638 639 /* 640 * If an original configuration file exists, remove it. 641 */ 642 if (crle->c_flags & CRLE_EXISTS) 643 (void) unlink(crle->c_confil); 644 645 /* 646 * Move the config file to its final resting place. If the two files 647 * exist on the same filesystem a rename is sufficient. 648 */ 649 if (crle->c_flags & CRLE_DIFFDEV) { 650 int fd; 651 652 if ((fd = open(crle->c_confil, (O_RDWR | O_CREAT | O_TRUNC), 653 0666)) == -1) { 654 int err = errno; 655 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), 656 crle->c_name, crle->c_confil, strerror(err)); 657 return (1); 658 } 659 if (write(fd, (void *)crle->c_tempaddr, crle->c_tempsize) != 660 crle->c_tempsize) { 661 int err = errno; 662 (void) fprintf(stderr, MSG_INTL(MSG_SYS_WRITE), 663 crle->c_name, crle->c_confil, strerror(err)); 664 return (1); 665 } 666 (void) close(fd); 667 (void) unlink(crle->c_tempname); 668 } else 669 (void) rename(crle->c_tempname, crle->c_confil); 670 671 return (0); 672 } 673