config.c revision b3fbe5e6c0ab1f506cd04f8dd39bf9656909f535
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#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"
#pragma ident "%Z%%M% %I% %E% SMI"
#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_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));
}
/*
* 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;
/*
* Establish the real address of each of the structures within the file.
*/
head = (Rtc_head *)addr;
head->ch_hash = hashoff;
/* LINTED */
hashtbl = (Word *)((char *)head->ch_hash + addr);
head->ch_obj = objoff;
/* LINTED */
objtbl = (Rtc_obj *)((char *)head->ch_obj + addr);
objtbl = (Rtc_obj *)S_ROUND((int)(objtbl + 1), sizeof (Lword));
head->ch_file = fileoff;
/* LINTED */
filetbl = (Rtc_file *)((char *)head->ch_file + addr);
head->ch_dir = diroff;
/* LINTED */
dirtbl = (Rtc_dir *)((char *)head->ch_dir + addr);
head->ch_env = envoff;
/* LINTED */
envtbl = (Rtc_env *)((char *)head->ch_env + addr);
head->ch_fltr = fltroff;
/* LINTED */
fltrtbl = (Rtc_fltr *)((char *)head->ch_fltr + addr);
head->ch_flte = flteoff;
/* LINTED */
fltetbl = _fltetbl = (Rtc_flte *)((char *)head->ch_flte + addr);
head->ch_str = stroff;
strtbl = _strtbl = (char *)((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;
}
if (crle->c_class == ELFCLASS64)
head->ch_cnflags |= RTC_HDR_64;
#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 == 0) ||
((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 =
(Word)((char *)filetbl - addr);
_dirtbl->cd_obj =
(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((int)(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 == 0) ||
(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 *)
((char *)_dirtbl->cd_file + addr);
_id = --ent->e_dir->e_cnt;
_filetbl[_id].cf_obj =
(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((int)(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)((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 *)
((char *)_dirtbl->cd_file + addr);
_id = --ent->e_dir->e_cnt;
_filetbl[_id].cf_obj =
(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((int)(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;
Listnode * lnp;
for (LIST_TRAVERSE(&(crle->c_env), lnp, 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;
Listnode * lnp1;
for (LIST_TRAVERSE(&(crle->c_flt), lnp1, flt)) {
Hash_ent * flte;
Listnode * lnp2;
/*
* 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)_fltetbl - (Word)fltetbl);
for (LIST_TRAVERSE(&(flt->f_filtee), lnp2, 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 *)addr, size, 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_tempaddr;
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);
}