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