/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include <sys/mman.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <stdio.h> #include <string.h> #include "rtc.h" #include "_crle.h" #include "msg.h" #define MAXNBKTS 10007 static const int hashsize[] = { 3, 7, 13, 31, 53, 67, 83, 97, 101, 151, 211, 251, 307, 353, 401, 457, 503, 557, 601, 653, 701, 751, 809, 859, 907, 953, 1009, 1103, 1201, 1301, 1409, 1511, 1601, 1709, 1801, 1901, 2003, 2111, 2203, 2309, 2411, 2503, 2609, 2707, 2801, 2903, 3001, 3109, 3203, 3301, 3407, 3511, 3607, 3701, 3803, 3907, 4001, 5003, 6101, 7001, 8101, 9001, MAXNBKTS }; /* * Generate a configuration file from the internal configuration information. * (very link-editor like). */ int genconfig(Crle_desc *crle) { int ndx, bkt; size_t size, hashoff = 0, stroff = 0, objoff = 0; size_t diroff = 0, fileoff = 0, envoff = 0; size_t fltroff = 0, flteoff = 0; Addr addr; Rtc_id *id; Rtc_head *head; Word *hashtbl, *hashbkt, *hashchn, hashbkts = 0; char *strtbl, *_strtbl; Rtc_obj *objtbl; Rtc_dir *dirtbl; Rtc_file *filetbl; Rtc_env *envtbl; Rtc_fltr *fltrtbl; Rtc_flte *fltetbl, * _fltetbl; Hash_tbl *stbl = crle->c_strtbl; Hash_ent *ent; /* * Establish the size of the configuration file. */ size = S_ROUND(sizeof (Rtc_head), sizeof (Word)); if (crle->c_hashstrnum) { hashoff = size; /* * Increment the hash string number to account for an initial * null entry. Indexes start at 1 to simplify hash lookup. */ crle->c_hashstrnum++; /* * Determine the hash table size. Establish the number of * buckets from the number of strings, the number of chains is * equivalent to the number of objects, and two entries for the * nbucket and nchain entries. */ for (ndx = 0; ndx < (sizeof (hashsize) / sizeof (int)); ndx++) { if (crle->c_hashstrnum > hashsize[ndx]) continue; hashbkts = hashsize[ndx]; break; } if (hashbkts == 0) hashbkts = MAXNBKTS; size += ((2 + hashbkts + crle->c_hashstrnum) * sizeof (Word)); size = S_ROUND(size, sizeof (Lword)); objoff = size; /* * Add the object table size (account for an 8-byte alignment * requirement for each object). */ size += (crle->c_hashstrnum * S_ROUND(sizeof (Rtc_obj), sizeof (Lword))); /* * Add the file descriptor arrays. */ fileoff = size; size += S_ROUND((crle->c_filenum * sizeof (Rtc_file)), sizeof (Word)); /* * Add the directory descriptor array. */ diroff = size; size += S_ROUND((crle->c_dirnum * sizeof (Rtc_dir)), sizeof (Word)); } /* * Add any environment string array (insure zero last entry). */ if (crle->c_envnum) { envoff = size; size += S_ROUND(((crle->c_envnum + 1) * sizeof (Rtc_env)), sizeof (Word)); } /* * Add any filter/filtee association arrays (insure zero last entry for * the filter array, the filtee arrays are already accounted for). */ if (crle->c_fltrnum) { fltroff = size; size += S_ROUND(((crle->c_fltrnum + 1) * sizeof (Rtc_fltr)), sizeof (Word)); flteoff = size; size += S_ROUND((crle->c_fltenum * sizeof (Rtc_flte)), sizeof (Word)); } /* * Add the string table size (this may contain library and/or secure * path strings, in addition to any directory/file strings). */ if (crle->c_strsize) { stroff = size; size += S_ROUND(crle->c_strsize, sizeof (Word)); } /* Account for addition of Rtc_id block at the start */ if (crle->c_flags & CRLE_ADDID) size += sizeof (Rtc_id); /* * Truncate our temporary file now that we know its size and map it. */ if (ftruncate(crle->c_tempfd, size) == -1) { int err = errno; (void) fprintf(stderr, MSG_INTL(MSG_SYS_TRUNC), crle->c_name, crle->c_tempname, strerror(err)); (void) close(crle->c_tempfd); return (1); } if ((addr = (Addr)mmap(0, size, (PROT_READ | PROT_WRITE), MAP_SHARED, crle->c_tempfd, 0)) == (Addr)-1) { int err = errno; (void) fprintf(stderr, MSG_INTL(MSG_SYS_MMAP), crle->c_name, crle->c_tempname, strerror(err)); (void) close(crle->c_tempfd); return (1); } /* * Save the mapped files info for possible dldump(3dl) updates. */ crle->c_tempaddr = addr; crle->c_tempsize = size; /* * Rtc_id goes at the top, followed by the Rtc_head. We base * all offset calculations relative to Rtc_head, not from * the top of the file. This eases backwards compatability to * older versons that lacked the Rtc_id at the top. */ if (crle->c_flags & CRLE_ADDID) { /* The contents of the Rtc_id are all known at compile time */ static const Rtc_id id_template = { RTC_ID_MAG0, RTC_ID_MAG1, RTC_ID_MAG2, RTC_ID_MAG3, M_CLASS, M_DATA, M_MACH, { 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; id = (Rtc_id *) addr; *id = id_template; /* Fill in the Rtc_id data */ addr += sizeof (Rtc_id); } else { id = NULL; } crle->c_tempheadaddr = addr; head = (Rtc_head *)addr; /* * Establish the real address of each of the structures within the file. */ head->ch_hash = hashoff; /* LINTED */ hashtbl = (Word *)(CAST_PTRINT(char *, head->ch_hash) + addr); head->ch_obj = objoff; /* LINTED */ objtbl = (Rtc_obj *)(CAST_PTRINT(char *, head->ch_obj) + addr); objtbl = (Rtc_obj *)S_ROUND((uintptr_t)(objtbl + 1), sizeof (Lword)); head->ch_file = fileoff; /* LINTED */ filetbl = (Rtc_file *)(CAST_PTRINT(char *, head->ch_file) + addr); head->ch_dir = diroff; /* LINTED */ dirtbl = (Rtc_dir *)(CAST_PTRINT(char *, head->ch_dir) + addr); head->ch_env = envoff; /* LINTED */ envtbl = (Rtc_env *)(CAST_PTRINT(char *, head->ch_env) + addr); head->ch_fltr = fltroff; /* LINTED */ fltrtbl = (Rtc_fltr *)(CAST_PTRINT(char *, head->ch_fltr) + addr); head->ch_flte = flteoff; /* LINTED */ fltetbl = _fltetbl = (Rtc_flte *)(CAST_PTRINT(char *, head->ch_flte) + addr); head->ch_str = stroff; strtbl = _strtbl = (char *)(CAST_PTRINT(char *, head->ch_str) + addr); /* * Fill in additional basic header information. */ head->ch_version = RTC_VER_CURRENT; if (crle->c_flags & CRLE_ALTER) head->ch_cnflags |= RTC_HDR_ALTER; if (crle->c_flags & CRLE_DUMP) { head->ch_cnflags |= RTC_HDR_IGNORE; head->ch_dlflags = crle->c_dlflags; } #ifdef _ELF64 head->ch_cnflags |= RTC_HDR_64; #endif #ifndef SGS_PRE_UNIFIED_PROCESS head->ch_cnflags |= RTC_HDR_UPM; #endif /* * If we have a hash table then there are directory and file entries * to process. */ if (crle->c_hashstrnum) { hashtbl[0] = hashbkts; hashtbl[1] = crle->c_hashstrnum; hashbkt = &hashtbl[2]; hashchn = &hashtbl[2 + hashbkts]; /* * Insure all hash chain and directory/filename table entries * are cleared. */ (void) memset(hashchn, 0, (crle->c_hashstrnum * sizeof (Word))); (void) memset(dirtbl, 0, (strtbl - (char *)dirtbl)); /* * Loop through the current string table list inspecting only * directories. */ for (ndx = 1, bkt = 0; bkt < stbl->t_size; bkt++) { for (ent = stbl->t_entry[bkt]; ent; ent = ent->e_next) { Word hashval; Hash_obj *obj = ent->e_obj; char *dir = (char *)ent->e_key; Rtc_dir *_dirtbl; /* * Skip any empty and non-directory entries. */ if ((obj == NULL) || ((obj->o_flags & RTC_OBJ_DIRENT) == 0)) continue; /* * Assign basic object attributes. */ objtbl->co_hash = ent->e_hash; objtbl->co_id = ent->e_id; objtbl->co_flags = obj->o_flags | ent->e_flags; objtbl->co_info = obj->o_info; ent->e_cobj = objtbl; /* * Assign the directory name (from its key), * and copy its name to the string table. */ objtbl->co_name = (Addr)(_strtbl - strtbl); (void) strcpy(_strtbl, dir); _strtbl += strlen(dir) + 1; /* * Establish an entry in the directory table and * reserve space for its associated filename * entries (note, we add a trailing null file * entry to simplify later inspection of the * final configuration file. */ _dirtbl = &dirtbl[ent->e_id - 1]; _dirtbl->cd_file = CAST_PTRINT(Word, ((char *)filetbl- addr)); _dirtbl->cd_obj = CAST_PTRINT(Word, ((char *)objtbl - addr)); /* LINTED */ filetbl = (Rtc_file *)((char *)filetbl + ((ent->e_cnt + 1) * sizeof (Rtc_file))); /* * Add this object to the hash table. */ hashval = ent->e_hash % hashbkts; hashchn[ndx] = hashbkt[hashval]; hashbkt[hashval] = ndx++; /* * Increment Rt_obj pointer (make sure pointer * falls on an 8-byte boundary). */ objtbl = (Rtc_obj *)S_ROUND((uintptr_t)(objtbl + 1), sizeof (Lword)); } } /* * Now collect all pathnames. These are typically full * pathnames, but may also be relative. Simple filenames are * recorded as offsets into these pathnames, thus we need to * establish the new pathname first. */ for (bkt = 0; bkt < stbl->t_size; bkt++) { for (ent = stbl->t_entry[bkt]; ent; ent = ent->e_next) { Word hashval; Hash_obj *obj = ent->e_obj; char *file = (char *)ent->e_key; char *_str; Rtc_dir *_dirtbl; Rtc_file *_filetbl; int _id; /* * Skip empty and directory entries, and any * simple filename entries. */ if ((obj == NULL) || (obj->o_flags & RTC_OBJ_DIRENT) || (ent->e_off)) continue; /* * Assign basic object attributes. */ objtbl->co_hash = ent->e_hash; objtbl->co_id = ent->e_id; objtbl->co_flags = obj->o_flags | ent->e_flags; objtbl->co_info = obj->o_info; ent->e_cobj = objtbl; /* * Assign the file name (from its key), * and copy its name to the string table. */ objtbl->co_name = (Addr)(_strtbl - strtbl); (void) strcpy(_strtbl, file); _strtbl += strlen(file) + 1; /* * Add this file to its associated directory. */ _dirtbl = &dirtbl[ent->e_id - 1]; /* LINTED */ _filetbl = (Rtc_file *)(CAST_PTRINT(char *, _dirtbl->cd_file) + addr); _id = --ent->e_dir->e_cnt; _filetbl[_id].cf_obj = CAST_PTRINT(Word, ((char *)objtbl - addr)); /* * If object has an alternative, record it in * the string table and assign the alternate * pointer. The new alternative offset is * retained for reuse in other filename entries. */ if ((objtbl->co_flags & RTC_OBJ_ALTER) && (obj->o_calter == 0)) { _str = obj->o_alter; objtbl->co_alter = obj->o_calter = (Addr)(_strtbl - strtbl); (void) strcpy(_strtbl, _str); _strtbl += strlen(_str) + 1; } else objtbl->co_alter = obj->o_calter; /* * If object identifies the specific application * for which this cache is relevant, record it * in the header. */ if ((objtbl->co_flags & (RTC_OBJ_APP | RTC_OBJ_REALPTH)) == (RTC_OBJ_APP | RTC_OBJ_REALPTH)) head->ch_app = _filetbl[_id].cf_obj; /* * Add this object to the hash table. */ hashval = ent->e_hash % hashbkts; hashchn[ndx] = hashbkt[hashval]; hashbkt[hashval] = ndx++; /* * Increment Rt_obj pointer (make sure pointer * falls on an 8-byte boundary). */ objtbl = (Rtc_obj *) S_ROUND((uintptr_t)(objtbl + 1), sizeof (Lword)); } } /* * Finally pick off any simple filenames. */ for (bkt = 0; bkt < stbl->t_size; bkt++) { for (ent = stbl->t_entry[bkt]; ent; ent = ent->e_next) { Word hashval; Hash_obj * obj = ent->e_obj; Rtc_dir * _dirtbl; Rtc_file * _filetbl; int _id; /* * Skip everything except simple filenames. */ if (ent->e_off == 0) continue; /* * Assign basic object attributes. */ objtbl->co_hash = ent->e_hash; objtbl->co_id = ent->e_id; objtbl->co_flags = obj->o_flags | ent->e_flags; objtbl->co_info = obj->o_info; objtbl->co_alter = obj->o_calter; ent->e_cobj = objtbl; /* * Assign the file name from its full name. */ objtbl->co_name = (Addr)(CAST_PTRINT(char *, ent->e_path->e_cobj->co_name) + ent->e_off); /* * Add this file to its associated directory. */ _dirtbl = &dirtbl[ent->e_id - 1]; /* LINTED */ _filetbl = (Rtc_file *) (CAST_PTRINT(char *, _dirtbl->cd_file) + addr); _id = --ent->e_dir->e_cnt; _filetbl[_id].cf_obj = CAST_PTRINT(Word, ((char *)objtbl - addr)); /* * Add this object to the hash table. */ hashval = ent->e_hash % hashbkts; hashchn[ndx] = hashbkt[hashval]; hashbkt[hashval] = ndx++; /* * Increment Rt_obj pointer (make sure pointer * falls on an 8-byte boundary). */ objtbl = (Rtc_obj *) S_ROUND((uintptr_t)(objtbl + 1), sizeof (Lword)); } } } /* * Add any library, or secure path definitions. */ if (crle->c_edlibpath) { head->ch_edlibpath = head->ch_str + (_strtbl - strtbl); (void) strcpy(_strtbl, crle->c_edlibpath); _strtbl += strlen((char *)crle->c_edlibpath) + 1; } else head->ch_edlibpath = 0; if (crle->c_adlibpath) { head->ch_adlibpath = head->ch_str + (_strtbl - strtbl); (void) strcpy(_strtbl, crle->c_adlibpath); _strtbl += strlen((char *)crle->c_adlibpath) + 1; } else head->ch_adlibpath = 0; if (crle->c_eslibpath) { head->ch_eslibpath = head->ch_str + (_strtbl - strtbl); (void) strcpy(_strtbl, crle->c_eslibpath); _strtbl += strlen((char *)crle->c_eslibpath) + 1; } else head->ch_eslibpath = 0; if (crle->c_aslibpath) { head->ch_aslibpath = head->ch_str + (_strtbl - strtbl); (void) strcpy(_strtbl, crle->c_aslibpath); _strtbl += strlen((char *)crle->c_aslibpath) + 1; } else head->ch_aslibpath = 0; /* * Add any environment variable entries. */ if (crle->c_envnum) { Env_desc *env; Aliste idx; for (APLIST_TRAVERSE(crle->c_env, idx, env)) { envtbl->env_str = head->ch_str + (_strtbl - strtbl); envtbl->env_flags = env->e_flags; (void) strcpy(_strtbl, env->e_str); _strtbl += env->e_totsz; envtbl++; } envtbl->env_str = 0; envtbl->env_flags = 0; } /* * Add any filter/filtee association entries. */ if (crle->c_fltrnum) { Flt_desc *flt; Aliste idx1; for (APLIST_TRAVERSE(crle->c_flt, idx1, flt)) { Hash_ent *flte; Aliste idx2; /* * Establish the filter name, and filtee string, as * offsets into the configuration files string table. * Establish the filtee as the offset into the filtee * table. */ fltrtbl->fr_filter = flt->f_fent->e_cobj->co_name; fltrtbl->fr_string = _strtbl - strtbl; (void) strcpy(_strtbl, flt->f_str); _strtbl += flt->f_strsz; fltrtbl->fr_filtee = (Word) ((uintptr_t)_fltetbl - (uintptr_t)fltetbl); for (APLIST_TRAVERSE(flt->f_filtee, idx2, flte)) { /* * Establish the filtee name as the offset into * the configuration files string table. */ _fltetbl->fe_filtee = flte->e_cobj->co_name; _fltetbl++; } _fltetbl->fe_filtee = 0; _fltetbl++, fltrtbl++; } fltrtbl->fr_filter = 0; fltrtbl->fr_filtee = 0; } /* * Flush everything out. */ (void) close(crle->c_tempfd); if (msync((void *)crle->c_tempaddr, crle->c_tempsize, MS_ASYNC) == -1) { int err = errno; (void) fprintf(stderr, MSG_INTL(MSG_SYS_TRUNC), crle->c_name, crle->c_tempname, strerror(err)); return (1); } return (0); } /* * Update a configuration file. If dldump()'ed images have been created then * the memory reservation of those images is added to the configuration file. * The temporary file is then moved into its final resting place. */ int updateconfig(Crle_desc * crle) { Rtc_head *head = (Rtc_head *)crle->c_tempheadaddr; if (crle->c_flags & CRLE_DUMP) { head->ch_cnflags &= ~RTC_HDR_IGNORE; if (msync((void *)crle->c_tempaddr, crle->c_tempsize, MS_ASYNC) == -1) { int err = errno; (void) fprintf(stderr, MSG_INTL(MSG_SYS_TRUNC), crle->c_name, crle->c_tempname, strerror(err)); return (1); } } /* * If an original configuration file exists, remove it. */ if (crle->c_flags & CRLE_EXISTS) (void) unlink(crle->c_confil); /* * Move the config file to its final resting place. If the two files * exist on the same filesystem a rename is sufficient. */ if (crle->c_flags & CRLE_DIFFDEV) { int fd; if ((fd = open(crle->c_confil, (O_RDWR | O_CREAT | O_TRUNC), 0666)) == -1) { int err = errno; (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), crle->c_name, crle->c_confil, strerror(err)); return (1); } if (write(fd, (void *)crle->c_tempaddr, crle->c_tempsize) != crle->c_tempsize) { int err = errno; (void) fprintf(stderr, MSG_INTL(MSG_SYS_WRITE), crle->c_name, crle->c_confil, strerror(err)); return (1); } (void) close(fd); (void) unlink(crle->c_tempname); } else (void) rename(crle->c_tempname, crle->c_confil); return (0); }