diff options
Diffstat (limited to 'utils/ldconfig.c')
-rw-r--r-- | utils/ldconfig.c | 143 |
1 files changed, 112 insertions, 31 deletions
diff --git a/utils/ldconfig.c b/utils/ldconfig.c index 202a58dd6..85ce015d5 100644 --- a/utils/ldconfig.c +++ b/utils/ldconfig.c @@ -22,6 +22,8 @@ * * This program may be used for any purpose as long as this * copyright notice is kept. + * + * 2005/09/16: Dan Howell (modified for cross-development) */ #include <stdio.h> @@ -37,6 +39,7 @@ #include <errno.h> #include <sys/stat.h> #include <sys/mman.h> +#include "bswap.h" #include "dl-defs.h" #define BUFFER_SIZE 4096 @@ -56,6 +59,7 @@ struct exec #if !defined (N_MAGIC) #define N_MAGIC(exec) ((exec).a_info & 0xffff) #endif +#define N_MAGIC_SWAP(exec) (bswap_32((exec).a_info) & 0xffff) /* Code indicating object file or impure executable. */ #define OMAGIC 0407 /* Code indicating pure executable. */ @@ -97,6 +101,8 @@ void cache_dolib(const char *dir, const char *so, int libtype); char *conffile = LDSO_CONF; /* default conf file */ char *cachefile = LDSO_CACHE; /* default cache file */ #endif +char *chroot_dir = NULL; +int byteswap = 0; struct needed_tab { @@ -117,6 +123,8 @@ struct needed_tab needed_tab[] = { { NULL, LIB_ELF } }; +extern char *chroot_realpath(const char *chroot, const char *path, char resolved_path[]); + /* These two are used internally -- you shouldn't need to use them */ static void verror_msg(const char *s, va_list p) @@ -242,6 +250,8 @@ char *is_shlib(const char *dir, const char *name, int *type, ElfW(Ehdr) *elf_hdr; struct stat statbuf; char buff[BUFFER_SIZE]; + char real[BUFFER_SIZE]; + static int byteswapflag = -1; /* start with byte-order unknown */ /* see if name is of the form *.so* */ if (name[strlen(name)-1] != '~' && (cp = strstr(name, ".so"))) @@ -256,8 +266,12 @@ char *is_shlib(const char *dir, const char *name, int *type, sprintf(buff, "%s%s%s", dir, (*dir && strcmp(dir, "/")) ? "/" : "", name); + /* get real path in case of chroot */ + if (!chroot_realpath(chroot_dir, buff, real)) + warn("can't resolve %s in chroot %s", buff, chroot_dir); + /* first, make sure it's a regular file */ - if (lstat(buff, &statbuf)) + if (lstat(real, &statbuf)) warn("skipping %s", buff); else if (!S_ISREG(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) warnx("%s is not a regular file or symlink, skipping", buff); @@ -267,14 +281,15 @@ char *is_shlib(const char *dir, const char *name, int *type, *islink = S_ISLNK(statbuf.st_mode); /* then try opening it */ - if (!(file = fopen(buff, "rb"))) + if (!(file = fopen(real, "rb"))) warn("skipping %s", buff); else { /* now make sure it's a shared library */ if (fread(&exec, sizeof exec, 1, file) < 1) warnx("can't read header from %s, skipping", buff); - else if (N_MAGIC(exec) != ZMAGIC && N_MAGIC(exec) != QMAGIC) + else if (N_MAGIC(exec) != ZMAGIC && N_MAGIC(exec) != QMAGIC && + N_MAGIC_SWAP(exec) != ZMAGIC && N_MAGIC_SWAP(exec) != QMAGIC) { elf_hdr = (ElfW(Ehdr) *) &exec; if (elf_hdr->e_ident[0] != 0x7f || @@ -294,6 +309,9 @@ char *is_shlib(const char *dir, const char *name, int *type, *type = LIB_ELF; good = readsoname(buff, file, expected_type, type, elf_hdr->e_ident[EI_CLASS]); + if (byteswapflag == -1) + /* byte-order detected */ + byteswapflag = byteswap; if (good == NULL || *islink) { if (good != NULL) @@ -313,6 +331,12 @@ char *is_shlib(const char *dir, const char *name, int *type, } else { + /* Determine byte-order */ + byteswap = (N_MAGIC(exec) == ZMAGIC || N_MAGIC(exec) == QMAGIC) ? 0 : 1; + if (byteswapflag == -1) + /* byte-order detected */ + byteswapflag = byteswap; + if (*islink) good = xstrdup(name); else @@ -330,6 +354,14 @@ char *is_shlib(const char *dir, const char *name, int *type, *type = LIB_DLL; } fclose(file); + + if (byteswapflag >= 0 && byteswap != byteswapflag) + { + byteswapflag = -2; + warnx("mixed byte-order detected, using host byte-order..."); + } + if (byteswapflag == -2) + byteswap = 0; } } } @@ -343,18 +375,24 @@ void link_shlib(const char *dir, const char *file, const char *so) int change = 1; char libname[BUFFER_SIZE]; char linkname[BUFFER_SIZE]; + char reallibname[BUFFER_SIZE]; + char reallinkname[BUFFER_SIZE]; struct stat libstat; struct stat linkstat; /* construct the full path names */ sprintf(libname, "%s/%s", dir, file); sprintf(linkname, "%s/%s", dir, so); + if (!chroot_realpath(chroot_dir, libname, reallibname)) + warn("can't resolve %s in chroot %s", libname, chroot_dir); + if (!chroot_realpath(chroot_dir, linkname, reallinkname)) + warn("can't resolve %s in chroot %s", linkname, chroot_dir); /* see if a link already exists */ - if (!stat(linkname, &linkstat)) + if (!stat(reallinkname, &linkstat)) { /* now see if it's the one we want */ - if (stat(libname, &libstat)) + if (stat(reallibname, &libstat)) warn("can't stat %s", libname); else if (libstat.st_dev == linkstat.st_dev && libstat.st_ino == linkstat.st_ino) @@ -364,14 +402,14 @@ void link_shlib(const char *dir, const char *file, const char *so) /* then update the link, if required */ if (change > 0 && !nolinks) { - if (!lstat(linkname, &linkstat)) + if (!lstat(reallinkname, &linkstat)) { if (!S_ISLNK(linkstat.st_mode)) { warnx("%s is not a symlink", linkname); change = -1; } - else if (remove(linkname)) + else if (remove(reallinkname)) { warn("can't unlink %s", linkname); change = -1; @@ -379,7 +417,7 @@ void link_shlib(const char *dir, const char *file, const char *so) } if (change > 0) { - if (symlink(file, linkname)) + if (symlink(file, reallinkname)) { warn("can't link %s to %s", linkname, file); change = -1; @@ -441,6 +479,7 @@ void scan_dir(const char *rawname) char *so, *path, *path_n; struct lib *lp, *libs = NULL; int i, libtype, islink, expected_type = LIB_ANY; + char realname[BUFFER_SIZE]; /* We need a writable copy of this string */ path = strdup(rawname); @@ -500,8 +539,12 @@ void scan_dir(const char *rawname) if (verbose > 0) printf("%s:\n", name); + /* get real path in case of chroot */ + if (!chroot_realpath(chroot_dir, name, realname)) + warn("can't resolve %s in chroot %s", name, chroot_dir); + /* if we can't open it, we can't do anything */ - if ((dir = opendir(name)) == NULL) + if ((dir = opendir(realname)) == NULL) { warn("skipping %s", name); free(path); @@ -596,8 +639,12 @@ char *get_extpath(void) char *res = NULL, *cp; FILE *file; struct stat stat; + char realconffile[BUFFER_SIZE]; + + if (!chroot_realpath(chroot_dir, conffile, realconffile)) + return NULL; - if ((file = fopen(conffile, "r")) != NULL) + if ((file = fopen(realconffile, "r")) != NULL) { fstat(fileno(file), &stat); res = xmalloc(stat.st_size + 1); @@ -678,22 +725,38 @@ void cache_write(void) { int cachefd; int stroffset = 0; + char realcachefile[BUFFER_SIZE]; char tempfile[BUFFER_SIZE]; + header_t swap_magic; + header_t *magic_ptr; + libentry_t swap_lib; + libentry_t *lib_ptr; liblist_t *cur_lib; if (!magic.nlibs) return; - sprintf(tempfile, "%s~", cachefile); + if (!chroot_realpath(chroot_dir, cachefile, realcachefile)) + err(EXIT_FATAL,"can't resolve %s in chroot %s (%s)", + cachefile, chroot_dir, strerror(errno)); + + sprintf(tempfile, "%s~", realcachefile); if (unlink(tempfile) && errno != ENOENT) - err(EXIT_FATAL,"can't unlink %s (%s)", tempfile, strerror(errno)); + err(EXIT_FATAL,"can't unlink %s~ (%s)", cachefile, strerror(errno)); if ((cachefd = creat(tempfile, 0644)) < 0) - err(EXIT_FATAL,"can't create %s (%s)", tempfile, strerror(errno)); - - if (write(cachefd, &magic, sizeof (header_t)) != sizeof (header_t)) - err(EXIT_FATAL,"can't write %s (%s)", tempfile, strerror(errno)); + err(EXIT_FATAL,"can't create %s~ (%s)", cachefile, strerror(errno)); + + if (byteswap) { + swap_magic = magic; + swap_magic.nlibs = bswap_32(swap_magic.nlibs); + magic_ptr = &swap_magic; + } else { + magic_ptr = &magic; + } + if (write(cachefd, magic_ptr, sizeof (header_t)) != sizeof (header_t)) + err(EXIT_FATAL,"can't write %s~ (%s)", cachefile, strerror(errno)); for (cur_lib = lib_head; cur_lib != NULL; cur_lib = cur_lib->next) { @@ -701,29 +764,37 @@ void cache_write(void) stroffset += strlen(cur_lib->soname) + 1; cur_lib->liboffset = stroffset; stroffset += strlen(cur_lib->libname) + 1; - if (write(cachefd, cur_lib, sizeof (libentry_t)) != - sizeof (libentry_t)) - err(EXIT_FATAL,"can't write %s (%s)", tempfile, strerror(errno)); + if (byteswap) { + swap_lib.flags = bswap_32(cur_lib->flags); + swap_lib.sooffset = bswap_32(cur_lib->sooffset); + swap_lib.liboffset = bswap_32(cur_lib->liboffset); + lib_ptr = &swap_lib; + } else { + lib_ptr = (libentry_t *)cur_lib; + } + if (write(cachefd, lib_ptr, sizeof (libentry_t)) != + sizeof (libentry_t)) + err(EXIT_FATAL,"can't write %s~ (%s)", cachefile, strerror(errno)); } for (cur_lib = lib_head; cur_lib != NULL; cur_lib = cur_lib->next) { if (write(cachefd, cur_lib->soname, strlen(cur_lib->soname) + 1) != strlen(cur_lib->soname) + 1) - err(EXIT_FATAL,"can't write %s (%s)", tempfile, strerror(errno)); + err(EXIT_FATAL,"can't write %s~ (%s)", cachefile, strerror(errno)); if (write(cachefd, cur_lib->libname, strlen(cur_lib->libname) + 1) != strlen(cur_lib->libname) + 1) - err(EXIT_FATAL,"can't write %s (%s)", tempfile, strerror(errno)); + err(EXIT_FATAL,"can't write %s~ (%s)", cachefile, strerror(errno)); } if (close(cachefd)) - err(EXIT_FATAL,"can't close %s (%s)", tempfile, strerror(errno)); + err(EXIT_FATAL,"can't close %s~ (%s)", cachefile, strerror(errno)); if (chmod(tempfile, 0644)) - err(EXIT_FATAL,"can't chmod %s (%s)", tempfile, strerror(errno)); + err(EXIT_FATAL,"can't chmod %s~ (%s)", cachefile, strerror(errno)); - if (rename(tempfile, cachefile)) - err(EXIT_FATAL,"can't rename %s (%s)", tempfile, strerror(errno)); + if (rename(tempfile, realcachefile)) + err(EXIT_FATAL,"can't rename %s~ (%s)", cachefile, strerror(errno)); } void cache_print(void) @@ -734,8 +805,13 @@ void cache_print(void) char *strs; header_t *header; libentry_t *libent; + char realcachefile[BUFFER_SIZE]; + + if (!chroot_realpath(chroot_dir, cachefile, realcachefile)) + err(EXIT_FATAL,"can't resolve %s in chroot %s (%s)", + cachefile, chroot_dir, strerror(errno)); - if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY))<0) + if (stat(realcachefile, &st) || (fd = open(realcachefile, O_RDONLY))<0) err(EXIT_FATAL,"can't read %s (%s)", cachefile, strerror(errno)); if ((c = mmap(0,st.st_size, PROT_READ, MAP_SHARED ,fd, 0)) == (caddr_t)-1) err(EXIT_FATAL,"can't map %s (%s)", cachefile, strerror(errno)); @@ -828,7 +904,6 @@ int main(int argc, char **argv) int nodefault = 0; char *cp, *dir, *so; int libtype, islink; - char *chroot_dir = NULL; int printcache = 0; #ifdef __LDSO_CACHE_SUPPORT__ char *extpath; @@ -891,10 +966,16 @@ int main(int argc, char **argv) } if (chroot_dir && *chroot_dir) { - if (chroot(chroot_dir) < 0) - err(EXIT_FATAL,"couldn't chroot to %s (%s)", chroot_dir, strerror(errno)); - if (chdir("/") < 0) - err(EXIT_FATAL,"couldn't chdir to / (%s)", strerror(errno)); + if (chroot(chroot_dir) < 0) { + if (chdir(chroot_dir) < 0) + err(EXIT_FATAL,"couldn't chroot to %s (%s)", chroot_dir, strerror(errno)); + } + else + { + if (chdir("/") < 0) + err(EXIT_FATAL,"couldn't chdir to / (%s)", strerror(errno)); + chroot_dir = NULL; + } } /* allow me to introduce myself, hi, my name is ... */ |