221 lines
4.8 KiB
C
221 lines
4.8 KiB
C
/* @(#)ldconfig.c 1.1 94/10/31 SMI */
|
|
|
|
/*
|
|
* ldconfig: build configuration information for ld.so.
|
|
*/
|
|
|
|
#include <stdio.h> /* I/O */
|
|
#include <sys/mman.h> /* memory management */
|
|
#include <sys/param.h> /* general system definitions */
|
|
#include <sys/file.h> /* file I/O bits */
|
|
#include <sys/exec.h>
|
|
#include <link.h> /* link editor public */
|
|
#include "cache.h" /* local caching information */
|
|
|
|
/*
|
|
* Global storage and definitions.
|
|
*/
|
|
#define MAX_DB (1024 * 1024) /* 1Mb database is the max */
|
|
|
|
int fd; /* descriptor on database */
|
|
caddr_t db_base; /* base address of last database */
|
|
caddr_t heap_ptr; /* current file allocation */
|
|
caddr_t heap_base; /* base address of file mapping */
|
|
caddr_t heap_max; /* maximum file to allocate */
|
|
void build_cache(); /* build a cache given directory */
|
|
int first = 1; /* true if no first entry yet */
|
|
struct dbf *dbfp; /* working cache file pointer */
|
|
|
|
/*
|
|
* "Environmental" variables exported to the cache routines.
|
|
*/
|
|
extern caddr_t malloc(); /* heap allocator */
|
|
caddr_t mmap_alloc(); /* database allocator */
|
|
int false(); /* says we're never secure */
|
|
int use_cache = 0; /* no previous database */
|
|
|
|
/*
|
|
* List of directories which are always in the cache. Note: these need
|
|
* not be (nor are they) identical to the directories searched by default
|
|
* by the loader.
|
|
*/
|
|
char *default_directories[] = {"/usr/lib", "/usr/5lib",
|
|
"/usr/lib/fsoft", "/usr/lib/f68881", "/usr/lib/ffpa",
|
|
"/usr/lib/fswitch", 0};
|
|
|
|
/*
|
|
* Build a database by building over all arguments.
|
|
*/
|
|
main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
int i; /* loop temporary */
|
|
char *fnp; /* temporary file name */
|
|
char **cpp; /* loop temporary */
|
|
|
|
/*
|
|
* Initialize exported functions.
|
|
*/
|
|
db_malloc = mmap_alloc;
|
|
heap_malloc = malloc;
|
|
is_secure = false;
|
|
|
|
/*
|
|
* Make a temporary file, map it in up to its maximum length.
|
|
*/
|
|
fnp = (char *)mktemp("/etc/ld.so.XXXXXX");
|
|
if ((fd = open(fnp, O_CREAT|O_RDWR, 0644)) == -1) {
|
|
perror("ldconfig: open temporary");
|
|
exit(1);
|
|
}
|
|
if ((heap_base = mmap(0, MAX_DB, PROT_READ|PROT_WRITE,
|
|
MAP_SHARED, fd, 0)) == (caddr_t)-1) {
|
|
perror("ldconfig: mmap");
|
|
exit(1);
|
|
}
|
|
db_base = heap_ptr = heap_max = heap_base;
|
|
dbfp = (struct dbf *)(*db_malloc)(sizeof (struct dbf));
|
|
dbfp->dbf_magic = LD_CACHE_MAGIC;
|
|
#if TARGET==SUN2
|
|
dbfp->dbf_machtype = M_68010;
|
|
#endif
|
|
#if TARGET==SUN3
|
|
dbfp->dbf_machtype = M_68020;
|
|
#endif
|
|
#if TARGET==SUN4
|
|
dbfp->dbf_machtype = M_SPARC;
|
|
#endif
|
|
dbfp->dbf_version = LD_CACHE_VERSION;
|
|
|
|
/*
|
|
* For each argument, create a database.
|
|
*/
|
|
for (i = 1; i < argc; i++)
|
|
build_cache(argv[i], 1);
|
|
|
|
/*
|
|
* Build a database for each of the default directories.
|
|
* Note that it is not an error for these directories to
|
|
* fail (they may not exist in all installations).
|
|
*/
|
|
for (cpp = default_directories; *cpp; cpp++)
|
|
build_cache(*cpp, 0);
|
|
|
|
/*
|
|
* Database built. Close file, and rename it to be the "real"
|
|
* database. However, if nothing every actually got cached,
|
|
* delete it instead.
|
|
*/
|
|
(void) close(fd);
|
|
if (first) {
|
|
(void) unlink(fnp);
|
|
exit(0);
|
|
}
|
|
if (rename(fnp, CACHE_FILE) == -1) {
|
|
perror("ldconfig: rename");
|
|
exit(1);
|
|
}
|
|
exit(0);
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
/*
|
|
* Allocator for mmap arena.
|
|
*/
|
|
caddr_t
|
|
mmap_alloc(n)
|
|
int n;
|
|
{
|
|
caddr_t a;
|
|
static u_int page_size = 0;
|
|
|
|
/*
|
|
* Get value -- simply next address to allocate.
|
|
*/
|
|
a = heap_ptr;
|
|
|
|
/*
|
|
* Architecture-dependent rounding.
|
|
*/
|
|
#ifdef sparc
|
|
n = round(n, sizeof (double));
|
|
#endif sparc
|
|
#ifdef mc68000
|
|
n = round(n, sizeof (int));
|
|
#endif mc68000
|
|
|
|
/*
|
|
* If block to be allocated requires file extension, do so.
|
|
*/
|
|
if ((heap_ptr + n) >= heap_max) {
|
|
if (page_size == 0)
|
|
page_size = getpagesize();
|
|
heap_max = (caddr_t)roundup((u_int)heap_ptr + n, page_size);
|
|
if ((heap_max - heap_base) > MAX_DB) {
|
|
perror("ldconfig: data base overflow");
|
|
exit(1);
|
|
}
|
|
if (ftruncate(fd, heap_max - heap_base) == -1) {
|
|
perror("ldconfig: ftruncate");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Allocate full block, return starting address.
|
|
*/
|
|
heap_ptr += n;
|
|
return (a);
|
|
}
|
|
|
|
/*
|
|
* Call support routines to build a cache for the given directory.
|
|
*/
|
|
void
|
|
build_cache(cp, flag_error)
|
|
char *cp; /* directory to cache */
|
|
int flag_error; /* true if errors to be flagged */
|
|
{
|
|
struct db *dbp; /* working data base file */
|
|
|
|
if ((dbp = lo_cache(cp)) == (struct db *)NULL) {
|
|
if (flag_error)
|
|
(void) fprintf(stderr,
|
|
"ldconfig: directory %s not cached\n", cp);
|
|
return;
|
|
}
|
|
if (first) {
|
|
dbfp->dbf_db = RELPTR(dbfp, dbp);
|
|
db_base = (caddr_t) dbp = &AP(dbfp)[(int)dbfp->dbf_db];
|
|
first = 0;
|
|
}
|
|
if (dbp->db_chain == 0) {
|
|
dbp->db_chain = (caddr_t)(heap_ptr - db_base);
|
|
db_base = heap_ptr;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Dummy test to say we're never using security checks.
|
|
*/
|
|
int
|
|
false()
|
|
{
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Rounding function.
|
|
*/
|
|
round(v, r)
|
|
int v; /* value to be rounded */
|
|
int r; /* rounding point */
|
|
{
|
|
|
|
v += --r;
|
|
v &= ~r;
|
|
return (v);
|
|
}
|