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 2004 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 genconfig(Crle_desc * crle) 59 { 60 int ndx, bkt; 61 size_t size, hashoff = 0, stroff = 0, objoff = 0; 62 size_t diroff = 0, fileoff = 0, envoff = 0; 63 size_t fltroff = 0, flteoff = 0; 64 Addr addr; 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 /* 163 * Truncate our temporary file now that we know its size and map it. 164 */ 165 if (ftruncate(crle->c_tempfd, size) == -1) { 166 int err = errno; 167 (void) fprintf(stderr, MSG_INTL(MSG_SYS_TRUNC), 168 crle->c_name, crle->c_tempname, strerror(err)); 169 (void) close(crle->c_tempfd); 170 return (1); 171 } 172 if ((addr = (Addr)mmap(0, size, (PROT_READ | PROT_WRITE), MAP_SHARED, 173 crle->c_tempfd, 0)) == (Addr)-1) { 174 int err = errno; 175 (void) fprintf(stderr, MSG_INTL(MSG_SYS_MMAP), 176 crle->c_name, crle->c_tempname, strerror(err)); 177 (void) close(crle->c_tempfd); 178 return (1); 179 } 180 181 /* 182 * Save the mapped files info for possible dldump(3dl) updates. 183 */ 184 crle->c_tempaddr = addr; 185 crle->c_tempsize = size; 186 187 /* 188 * Establish the real address of each of the structures within the file. 189 */ 190 head = (Rtc_head *)addr; 191 192 head->ch_hash = hashoff; 193 /* LINTED */ 194 hashtbl = (Word *)((char *)head->ch_hash + addr); 195 196 head->ch_obj = objoff; 197 /* LINTED */ 198 objtbl = (Rtc_obj *)((char *)head->ch_obj + addr); 199 objtbl = (Rtc_obj *)S_ROUND((int)(objtbl + 1), sizeof (Lword)); 200 201 head->ch_file = fileoff; 202 /* LINTED */ 203 filetbl = (Rtc_file *)((char *)head->ch_file + addr); 204 205 head->ch_dir = diroff; 206 /* LINTED */ 207 dirtbl = (Rtc_dir *)((char *)head->ch_dir + addr); 208 209 head->ch_env = envoff; 210 /* LINTED */ 211 envtbl = (Rtc_env *)((char *)head->ch_env + addr); 212 213 head->ch_fltr = fltroff; 214 /* LINTED */ 215 fltrtbl = (Rtc_fltr *)((char *)head->ch_fltr + addr); 216 head->ch_flte = flteoff; 217 /* LINTED */ 218 fltetbl = _fltetbl = (Rtc_flte *)((char *)head->ch_flte + addr); 219 220 head->ch_str = stroff; 221 strtbl = _strtbl = (char *)((char *)head->ch_str + addr); 222 223 /* 224 * Fill in additional basic header information. 225 */ 226 head->ch_version = RTC_VER_CURRENT; 227 228 if (crle->c_flags & CRLE_ALTER) 229 head->ch_cnflags |= RTC_HDR_ALTER; 230 if (crle->c_flags & CRLE_DUMP) { 231 head->ch_cnflags |= RTC_HDR_IGNORE; 232 head->ch_dlflags = crle->c_dlflags; 233 } 234 if (crle->c_class == ELFCLASS64) 235 head->ch_cnflags |= RTC_HDR_64; 236 237 #ifndef SGS_PRE_UNIFIED_PROCESS 238 head->ch_cnflags |= RTC_HDR_UPM; 239 #endif 240 /* 241 * If we have a hash table then there are directory and file entries 242 * to process. 243 */ 244 if (crle->c_hashstrnum) { 245 hashtbl[0] = hashbkts; 246 hashtbl[1] = crle->c_hashstrnum; 247 hashbkt = &hashtbl[2]; 248 hashchn = &hashtbl[2 + hashbkts]; 249 250 /* 251 * Insure all hash chain and directory/filename table entries 252 * are cleared. 253 */ 254 (void) memset(hashchn, 0, (crle->c_hashstrnum * sizeof (Word))); 255 (void) memset(dirtbl, 0, (strtbl - (char *)dirtbl)); 256 257 /* 258 * Loop through the current string table list inspecting only 259 * directories. 260 */ 261 for (ndx = 1, bkt = 0; bkt < stbl->t_size; bkt++) { 262 for (ent = stbl->t_entry[bkt]; ent; ent = ent->e_next) { 263 Word hashval; 264 Hash_obj *obj = ent->e_obj; 265 char *dir = (char *)ent->e_key; 266 Rtc_dir *_dirtbl; 267 268 /* 269 * Skip any empty and non-directory entries. 270 */ 271 if ((obj == 0) || 272 ((obj->o_flags & RTC_OBJ_DIRENT) == 0)) 273 continue; 274 275 /* 276 * Assign basic object attributes. 277 */ 278 objtbl->co_hash = ent->e_hash; 279 objtbl->co_id = ent->e_id; 280 objtbl->co_flags = obj->o_flags | ent->e_flags; 281 objtbl->co_info = obj->o_info; 282 283 ent->e_cobj = objtbl; 284 285 /* 286 * Assign the directory name (from its key), 287 * and copy its name to the string table. 288 */ 289 objtbl->co_name = (Addr)(_strtbl - strtbl); 290 (void) strcpy(_strtbl, dir); 291 _strtbl += strlen(dir) + 1; 292 293 /* 294 * Establish an entry in the directory table and 295 * reserve space for its associated filename 296 * entries (note, we add a trailing null file 297 * entry to simplify later inspection of the 298 * final configuration file. 299 */ 300 _dirtbl = &dirtbl[ent->e_id - 1]; 301 _dirtbl->cd_file = 302 (Word)((char *)filetbl - addr); 303 _dirtbl->cd_obj = 304 (Word)((char *)objtbl - addr); 305 306 /* LINTED */ 307 filetbl = (Rtc_file *)((char *)filetbl + 308 ((ent->e_cnt + 1) * sizeof (Rtc_file))); 309 310 /* 311 * Add this object to the hash table. 312 */ 313 hashval = ent->e_hash % hashbkts; 314 hashchn[ndx] = hashbkt[hashval]; 315 hashbkt[hashval] = ndx++; 316 317 /* 318 * Increment Rt_obj pointer (make sure pointer 319 * falls on an 8-byte boundary). 320 */ 321 objtbl = (Rtc_obj *)S_ROUND((int)(objtbl + 1), 322 sizeof (Lword)); 323 } 324 } 325 326 /* 327 * Now collect all pathnames. These are typically full 328 * pathnames, but may also be relative. Simple filenames are 329 * recorded as offsets into these pathnames, thus we need to 330 * establish the new pathname first. 331 */ 332 for (bkt = 0; bkt < stbl->t_size; bkt++) { 333 for (ent = stbl->t_entry[bkt]; ent; ent = ent->e_next) { 334 Word hashval; 335 Hash_obj *obj = ent->e_obj; 336 char *file = (char *)ent->e_key; 337 char *_str; 338 Rtc_dir *_dirtbl; 339 Rtc_file *_filetbl; 340 int _id; 341 342 /* 343 * Skip empty and directory entries, and any 344 * simple filename entries. 345 */ 346 if ((obj == 0) || 347 (obj->o_flags & RTC_OBJ_DIRENT) || 348 (ent->e_off)) 349 continue; 350 351 /* 352 * Assign basic object attributes. 353 */ 354 objtbl->co_hash = ent->e_hash; 355 objtbl->co_id = ent->e_id; 356 objtbl->co_flags = obj->o_flags | ent->e_flags; 357 objtbl->co_info = obj->o_info; 358 359 ent->e_cobj = objtbl; 360 361 /* 362 * Assign the file name (from its key), 363 * and copy its name to the string table. 364 */ 365 objtbl->co_name = (Addr)(_strtbl - strtbl); 366 (void) strcpy(_strtbl, file); 367 _strtbl += strlen(file) + 1; 368 369 /* 370 * Add this file to its associated directory. 371 */ 372 _dirtbl = &dirtbl[ent->e_id - 1]; 373 /* LINTED */ 374 _filetbl = (Rtc_file *) 375 ((char *)_dirtbl->cd_file + addr); 376 377 _id = --ent->e_dir->e_cnt; 378 _filetbl[_id].cf_obj = 379 (Word)((char *)objtbl - addr); 380 381 /* 382 * If object has an alternative, record it in 383 * the string table and assign the alternate 384 * pointer. The new alternative offset is 385 * retained for reuse in other filename entries. 386 */ 387 if ((objtbl->co_flags & RTC_OBJ_ALTER) && 388 (obj->o_calter == 0)) { 389 _str = obj->o_alter; 390 objtbl->co_alter = obj->o_calter = 391 (Addr)(_strtbl - strtbl); 392 (void) strcpy(_strtbl, _str); 393 _strtbl += strlen(_str) + 1; 394 } else 395 objtbl->co_alter = obj->o_calter; 396 397 /* 398 * If object identifies the specific application 399 * for which this cache is relevant, record it 400 * in the header. 401 */ 402 if ((objtbl->co_flags & 403 (RTC_OBJ_APP | RTC_OBJ_REALPTH)) == 404 (RTC_OBJ_APP | RTC_OBJ_REALPTH)) 405 head->ch_app = _filetbl[_id].cf_obj; 406 407 /* 408 * Add this object to the hash table. 409 */ 410 hashval = ent->e_hash % hashbkts; 411 hashchn[ndx] = hashbkt[hashval]; 412 hashbkt[hashval] = ndx++; 413 414 /* 415 * Increment Rt_obj pointer (make sure pointer 416 * falls on an 8-byte boundary). 417 */ 418 objtbl = (Rtc_obj *)S_ROUND((int)(objtbl + 1), 419 sizeof (Lword)); 420 } 421 } 422 423 /* 424 * Finally pick off any simple filenames. 425 */ 426 for (bkt = 0; bkt < stbl->t_size; bkt++) { 427 for (ent = stbl->t_entry[bkt]; ent; ent = ent->e_next) { 428 Word hashval; 429 Hash_obj * obj = ent->e_obj; 430 Rtc_dir * _dirtbl; 431 Rtc_file * _filetbl; 432 int _id; 433 434 /* 435 * Skip everything except simple filenames. 436 */ 437 if (ent->e_off == 0) 438 continue; 439 440 /* 441 * Assign basic object attributes. 442 */ 443 objtbl->co_hash = ent->e_hash; 444 objtbl->co_id = ent->e_id; 445 objtbl->co_flags = obj->o_flags | ent->e_flags; 446 objtbl->co_info = obj->o_info; 447 objtbl->co_alter = obj->o_calter; 448 449 ent->e_cobj = objtbl; 450 451 /* 452 * Assign the file name from its full name. 453 */ 454 objtbl->co_name = (Addr)((char *) 455 ent->e_path->e_cobj->co_name + ent->e_off); 456 457 /* 458 * Add this file to its associated directory. 459 */ 460 _dirtbl = &dirtbl[ent->e_id - 1]; 461 /* LINTED */ 462 _filetbl = (Rtc_file *) 463 ((char *)_dirtbl->cd_file + addr); 464 465 _id = --ent->e_dir->e_cnt; 466 _filetbl[_id].cf_obj = 467 (Word)((char *)objtbl - addr); 468 469 /* 470 * Add this object to the hash table. 471 */ 472 hashval = ent->e_hash % hashbkts; 473 hashchn[ndx] = hashbkt[hashval]; 474 hashbkt[hashval] = ndx++; 475 476 /* 477 * Increment Rt_obj pointer (make sure pointer 478 * falls on an 8-byte boundary). 479 */ 480 objtbl = (Rtc_obj *)S_ROUND((int)(objtbl + 1), 481 sizeof (Lword)); 482 } 483 } 484 } 485 486 /* 487 * Add any library, or secure path definitions. 488 */ 489 if (crle->c_edlibpath) { 490 head->ch_edlibpath = head->ch_str + (_strtbl - strtbl); 491 492 (void) strcpy(_strtbl, crle->c_edlibpath); 493 _strtbl += strlen((char *)crle->c_edlibpath) + 1; 494 } else 495 head->ch_edlibpath = 0; 496 497 if (crle->c_adlibpath) { 498 head->ch_adlibpath = head->ch_str + (_strtbl - strtbl); 499 500 (void) strcpy(_strtbl, crle->c_adlibpath); 501 _strtbl += strlen((char *)crle->c_adlibpath) + 1; 502 } else 503 head->ch_adlibpath = 0; 504 505 if (crle->c_eslibpath) { 506 head->ch_eslibpath = head->ch_str + (_strtbl - strtbl); 507 508 (void) strcpy(_strtbl, crle->c_eslibpath); 509 _strtbl += strlen((char *)crle->c_eslibpath) + 1; 510 } else 511 head->ch_eslibpath = 0; 512 513 if (crle->c_aslibpath) { 514 head->ch_aslibpath = head->ch_str + (_strtbl - strtbl); 515 516 (void) strcpy(_strtbl, crle->c_aslibpath); 517 _strtbl += strlen((char *)crle->c_aslibpath) + 1; 518 } else 519 head->ch_aslibpath = 0; 520 521 /* 522 * Add any environment variable entries. 523 */ 524 if (crle->c_envnum) { 525 Env_desc * env; 526 Listnode * lnp; 527 528 for (LIST_TRAVERSE(&(crle->c_env), lnp, env)) { 529 envtbl->env_str = head->ch_str + (_strtbl - strtbl); 530 envtbl->env_flags = env->e_flags; 531 532 (void) strcpy(_strtbl, env->e_str); 533 _strtbl += env->e_totsz; 534 535 envtbl++; 536 } 537 envtbl->env_str = 0; 538 envtbl->env_flags = 0; 539 } 540 541 /* 542 * Add any filter/filtee association entries. 543 */ 544 if (crle->c_fltrnum) { 545 Flt_desc * flt; 546 Listnode * lnp1; 547 548 for (LIST_TRAVERSE(&(crle->c_flt), lnp1, flt)) { 549 Hash_ent * flte; 550 Listnode * lnp2; 551 552 /* 553 * Establish the filter name, and filtee string, as 554 * offsets into the configuration files string table. 555 * Establish the filtee as the offset into the filtee 556 * table. 557 */ 558 fltrtbl->fr_filter = flt->f_fent->e_cobj->co_name; 559 fltrtbl->fr_string = _strtbl - strtbl; 560 (void) strcpy(_strtbl, flt->f_str); 561 _strtbl += flt->f_strsz; 562 fltrtbl->fr_filtee = ((Word)_fltetbl - (Word)fltetbl); 563 564 for (LIST_TRAVERSE(&(flt->f_filtee), lnp2, flte)) { 565 /* 566 * Establish the filtee name as the offset into 567 * the configuration files string table. 568 */ 569 _fltetbl->fe_filtee = flte->e_cobj->co_name; 570 _fltetbl++; 571 } 572 _fltetbl->fe_filtee = 0; 573 _fltetbl++, fltrtbl++; 574 } 575 fltrtbl->fr_filter = 0; 576 fltrtbl->fr_filtee = 0; 577 } 578 579 /* 580 * Flush everything out. 581 */ 582 (void) close(crle->c_tempfd); 583 if (msync((void *)addr, size, MS_ASYNC) == -1) { 584 int err = errno; 585 (void) fprintf(stderr, MSG_INTL(MSG_SYS_TRUNC), 586 crle->c_name, crle->c_tempname, strerror(err)); 587 return (1); 588 } 589 590 return (0); 591 } 592 593 /* 594 * Update a configuration file. If dldump()'ed images have been created then 595 * the memory reservation of those images is added to the configuration file. 596 * The temporary file is then moved into its final resting place. 597 */ 598 updateconfig(Crle_desc * crle) 599 { 600 Rtc_head * head = (Rtc_head *)crle->c_tempaddr; 601 602 if (crle->c_flags & CRLE_DUMP) { 603 head->ch_cnflags &= ~RTC_HDR_IGNORE; 604 605 if (msync((void *)crle->c_tempaddr, crle->c_tempsize, 606 MS_ASYNC) == -1) { 607 int err = errno; 608 (void) fprintf(stderr, MSG_INTL(MSG_SYS_TRUNC), 609 crle->c_name, crle->c_tempname, strerror(err)); 610 return (1); 611 } 612 } 613 614 /* 615 * If an original configuration file exists, remove it. 616 */ 617 if (crle->c_flags & CRLE_EXISTS) 618 (void) unlink(crle->c_confil); 619 620 /* 621 * Move the config file to its final resting place. If the two files 622 * exist on the same filesystem a rename is sufficient. 623 */ 624 if (crle->c_flags & CRLE_DIFFDEV) { 625 int fd; 626 627 if ((fd = open(crle->c_confil, (O_RDWR | O_CREAT | O_TRUNC), 628 0666)) == -1) { 629 int err = errno; 630 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), 631 crle->c_name, crle->c_confil, strerror(err)); 632 return (1); 633 } 634 if (write(fd, (void *)crle->c_tempaddr, crle->c_tempsize) != 635 crle->c_tempsize) { 636 int err = errno; 637 (void) fprintf(stderr, MSG_INTL(MSG_SYS_WRITE), 638 crle->c_name, crle->c_confil, strerror(err)); 639 return (1); 640 } 641 (void) close(fd); 642 (void) unlink(crle->c_tempname); 643 } else 644 (void) rename(crle->c_tempname, crle->c_confil); 645 646 return (0); 647 } 648