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 ... */ | 
