1 This patch supports cross-development for embedded systems by allowing the
2 host version of ldconfig (ldconfig.host) to build ld.so.cache for the target.
4 1) LDSO_CACHE_SUPPORT is defined for the host build.
5 2) A little-endian host can create a big-endian ld.so.cache, and vice versa.
6 3) Can use -r option without chroot(), so no need to run as superuser.
8 Dan Howell <dahowell@directv.com>
10 diff -urN uClibc-orig/utils/chroot_realpath.c uClibc-20050502/utils/chroot_realpath.c
11 --- uClibc-orig/utils/chroot_realpath.c 1969-12-31 16:00:00.000000000 -0800
12 +++ uClibc-20050502/utils/chroot_realpath.c 2005-09-12 18:30:29.000000000 -0700
15 + * chroot_realpath.c -- reslove pathname as if inside chroot
16 + * Based on realpath.c Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
18 + * This program is free software; you can redistribute it and/or modify
19 + * it under the terms of the GNU Library Public License as published by
20 + * the Free Software Foundation; either version 2, or (at your option)
21 + * any later version.
23 + * This program is distributed in the hope that it will be useful,
24 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 + * GNU Library Public License for more details.
28 + * 2005/09/12: Dan Howell (modified from realpath.c to emulate chroot)
35 +#include <sys/types.h>
40 +#include <limits.h> /* for PATH_MAX */
41 +#include <sys/param.h> /* for MAXPATHLEN */
44 +#define __set_errno(val) ((errno) = (val))
47 +#include <sys/stat.h> /* for S_IFLNK */
50 +#define PATH_MAX _POSIX_PATH_MAX
53 +#define MAX_READLINKS 32
55 +char *chroot_realpath(const char *chroot, const char *path, char resolved_path[])
57 + char copy_path[PATH_MAX];
58 + char link_path[PATH_MAX];
59 + char got_path[PATH_MAX];
60 + char *got_path_root = got_path;
61 + char *new_path = got_path;
68 + if (chroot == NULL || *chroot == '\0' ||
69 + (*chroot == '/' && chroot[1] == '\0')) {
70 + strcpy(resolved_path, path);
71 + return resolved_path;
74 + chroot_len = strlen(chroot);
76 + if (chroot_len + strlen(path) >= PATH_MAX - 3) {
77 + __set_errno(ENAMETOOLONG);
81 + /* Make a copy of the source path since we may need to modify it. */
82 + strcpy(copy_path, path);
84 + max_path = copy_path + PATH_MAX - chroot_len - 3;
86 + /* Start with the chroot path. */
87 + strcpy(new_path, chroot);
88 + new_path += chroot_len;
89 + while (*new_path == '/' && new_path > got_path)
91 + got_path_root = new_path;
94 + /* Expand each slash-separated pathname component. */
95 + while (*path != '\0') {
96 + /* Ignore stray "/". */
101 + if (*path == '.') {
103 + if (path[1] == '\0' || path[1] == '/') {
107 + if (path[1] == '.') {
108 + if (path[2] == '\0' || path[2] == '/') {
110 + /* Ignore ".." at root. */
111 + if (new_path == got_path_root + 1)
113 + /* Handle ".." by backing up. */
114 + while ((--new_path)[-1] != '/');
119 + /* Safely copy the next pathname component. */
120 + while (*path != '\0' && *path != '/') {
121 + if (path > max_path) {
122 + __set_errno(ENAMETOOLONG);
125 + *new_path++ = *path++;
128 + /* Don't follow symlink for last pathname component. */
131 + /* Protect against infinite loops. */
132 + if (readlinks++ > MAX_READLINKS) {
133 + __set_errno(ELOOP);
136 + /* See if latest pathname component is a symlink. */
138 + n = readlink(got_path, link_path, PATH_MAX - 1);
140 + /* EINVAL means the file exists but isn't a symlink. */
141 + if (errno != EINVAL) {
142 + /* Make sure it's null terminated. */
144 + strcpy(resolved_path, got_path);
148 + /* Note: readlink doesn't add the null byte. */
149 + link_path[n] = '\0';
150 + if (*link_path == '/')
151 + /* Start over for an absolute symlink. */
152 + new_path = got_path_root;
154 + /* Otherwise back up over this component. */
155 + while (*(--new_path) != '/');
156 + /* Safe sex check. */
157 + if (strlen(path) + n >= PATH_MAX - 2) {
158 + __set_errno(ENAMETOOLONG);
161 + /* Insert symlink contents into path. */
162 + strcat(link_path, path);
163 + strcpy(copy_path, link_path);
166 +#endif /* S_IFLNK */
169 + /* Delete trailing slash but don't whomp a lone slash. */
170 + if (new_path != got_path + 1 && new_path[-1] == '/')
172 + /* Make sure it's null terminated. */
174 + strcpy(resolved_path, got_path);
175 + return resolved_path;
177 diff -urN uClibc-orig/utils/ldconfig.c uClibc-20050502/utils/ldconfig.c
178 --- uClibc-orig/utils/ldconfig.c 2005-05-01 23:10:12.000000000 -0700
179 +++ uClibc-20050502/utils/ldconfig.c 2005-09-16 19:26:33.000000000 -0700
182 * This program may be used for any purpose as long as this
183 * copyright notice is kept.
185 + * 2005/09/16: Dan Howell (modified for cross-development)
191 #include <sys/stat.h>
192 #include <sys/mman.h>
196 #define BUFFER_SIZE 4096
198 #if !defined (N_MAGIC)
199 #define N_MAGIC(exec) ((exec).a_info & 0xffff)
201 +#define N_MAGIC_SWAP(exec) (bswap_32((exec).a_info) & 0xffff)
202 /* Code indicating object file or impure executable. */
204 /* Code indicating pure executable. */
206 char *conffile = LDSO_CONF; /* default conf file */
207 char *cachefile = LDSO_CACHE; /* default cache file */
209 +char *chroot_dir = NULL;
218 +extern char *chroot_realpath(const char *chroot, const char *path, char resolved_path[]);
221 /* These two are used internally -- you shouldn't need to use them */
222 static void verror_msg(const char *s, va_list p)
226 char buff[BUFFER_SIZE];
227 + char real[BUFFER_SIZE];
228 + static int byteswapflag = -1; /* start with byte-order unknown */
230 /* see if name is of the form *.so* */
231 if (name[strlen(name)-1] != '~' && (cp = strstr(name, ".so")))
233 sprintf(buff, "%s%s%s", dir, (*dir && strcmp(dir, "/")) ?
236 + /* get real path in case of chroot */
237 + if (!chroot_realpath(chroot_dir, buff, real))
238 + warn("can't resolve %s in chroot %s", buff, chroot_dir);
240 /* first, make sure it's a regular file */
241 - if (lstat(buff, &statbuf))
242 + if (lstat(real, &statbuf))
243 warn("skipping %s", buff);
244 else if (!S_ISREG(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode))
245 warnx("%s is not a regular file or symlink, skipping", buff);
246 @@ -267,14 +281,15 @@
247 *islink = S_ISLNK(statbuf.st_mode);
249 /* then try opening it */
250 - if (!(file = fopen(buff, "rb")))
251 + if (!(file = fopen(real, "rb")))
252 warn("skipping %s", buff);
255 /* now make sure it's a shared library */
256 if (fread(&exec, sizeof exec, 1, file) < 1)
257 warnx("can't read header from %s, skipping", buff);
258 - else if (N_MAGIC(exec) != ZMAGIC && N_MAGIC(exec) != QMAGIC)
259 + else if (N_MAGIC(exec) != ZMAGIC && N_MAGIC(exec) != QMAGIC &&
260 + N_MAGIC_SWAP(exec) != ZMAGIC && N_MAGIC_SWAP(exec) != QMAGIC)
262 elf_hdr = (ElfW(Ehdr) *) &exec;
263 if (elf_hdr->e_ident[0] != 0x7f ||
266 good = readsoname(buff, file, expected_type, type,
267 elf_hdr->e_ident[EI_CLASS]);
268 + if (byteswapflag == -1)
269 + /* byte-order detected */
270 + byteswapflag = byteswap;
271 if (good == NULL || *islink)
278 + /* Determine byte-order */
279 + byteswap = (N_MAGIC(exec) == ZMAGIC || N_MAGIC(exec) == QMAGIC) ? 0 : 1;
280 + if (byteswapflag == -1)
281 + /* byte-order detected */
282 + byteswapflag = byteswap;
285 good = xstrdup(name);
292 + if (byteswapflag >= 0 && byteswap != byteswapflag)
295 + warnx("mixed byte-order detected, using host byte-order...");
297 + if (byteswapflag == -2)
302 @@ -343,18 +375,24 @@
304 char libname[BUFFER_SIZE];
305 char linkname[BUFFER_SIZE];
306 + char reallibname[BUFFER_SIZE];
307 + char reallinkname[BUFFER_SIZE];
309 struct stat linkstat;
311 /* construct the full path names */
312 sprintf(libname, "%s/%s", dir, file);
313 sprintf(linkname, "%s/%s", dir, so);
314 + if (!chroot_realpath(chroot_dir, libname, reallibname))
315 + warn("can't resolve %s in chroot %s", libname, chroot_dir);
316 + if (!chroot_realpath(chroot_dir, linkname, reallinkname))
317 + warn("can't resolve %s in chroot %s", linkname, chroot_dir);
319 /* see if a link already exists */
320 - if (!stat(linkname, &linkstat))
321 + if (!stat(reallinkname, &linkstat))
323 /* now see if it's the one we want */
324 - if (stat(libname, &libstat))
325 + if (stat(reallibname, &libstat))
326 warn("can't stat %s", libname);
327 else if (libstat.st_dev == linkstat.st_dev &&
328 libstat.st_ino == linkstat.st_ino)
329 @@ -364,14 +402,14 @@
330 /* then update the link, if required */
331 if (change > 0 && !nolinks)
333 - if (!lstat(linkname, &linkstat))
334 + if (!lstat(reallinkname, &linkstat))
336 if (!S_ISLNK(linkstat.st_mode))
338 warnx("%s is not a symlink", linkname);
341 - else if (remove(linkname))
342 + else if (remove(reallinkname))
344 warn("can't unlink %s", linkname);
350 - if (symlink(file, linkname))
351 + if (symlink(file, reallinkname))
353 warn("can't link %s to %s", linkname, file);
356 char *so, *path, *path_n;
357 struct lib *lp, *libs = NULL;
358 int i, libtype, islink, expected_type = LIB_ANY;
359 + char realname[BUFFER_SIZE];
361 /* We need a writable copy of this string */
362 path = strdup(rawname);
365 printf("%s:\n", name);
367 + /* get real path in case of chroot */
368 + if (!chroot_realpath(chroot_dir, name, realname))
369 + warn("can't resolve %s in chroot %s", name, chroot_dir);
371 /* if we can't open it, we can't do anything */
372 - if ((dir = opendir(name)) == NULL)
373 + if ((dir = opendir(realname)) == NULL)
375 warn("skipping %s", name);
378 char *res = NULL, *cp;
381 + char realconffile[BUFFER_SIZE];
383 + if (!chroot_realpath(chroot_dir, conffile, realconffile))
386 - if ((file = fopen(conffile, "r")) != NULL)
387 + if ((file = fopen(realconffile, "r")) != NULL)
389 fstat(fileno(file), &stat);
390 res = xmalloc(stat.st_size + 1);
391 @@ -678,22 +725,38 @@
395 + char realcachefile[BUFFER_SIZE];
396 char tempfile[BUFFER_SIZE];
397 + header_t swap_magic;
398 + header_t *magic_ptr;
399 + libentry_t swap_lib;
400 + libentry_t *lib_ptr;
406 - sprintf(tempfile, "%s~", cachefile);
407 + if (!chroot_realpath(chroot_dir, cachefile, realcachefile))
408 + err(EXIT_FATAL,"can't resolve %s in chroot %s (%s)",
409 + cachefile, chroot_dir, strerror(errno));
411 + sprintf(tempfile, "%s~", realcachefile);
413 if (unlink(tempfile) && errno != ENOENT)
414 - err(EXIT_FATAL,"can't unlink %s (%s)", tempfile, strerror(errno));
415 + err(EXIT_FATAL,"can't unlink %s~ (%s)", cachefile, strerror(errno));
417 if ((cachefd = creat(tempfile, 0644)) < 0)
418 - err(EXIT_FATAL,"can't create %s (%s)", tempfile, strerror(errno));
419 + err(EXIT_FATAL,"can't create %s~ (%s)", cachefile, strerror(errno));
421 - if (write(cachefd, &magic, sizeof (header_t)) != sizeof (header_t))
422 - err(EXIT_FATAL,"can't write %s (%s)", tempfile, strerror(errno));
424 + swap_magic = magic;
425 + swap_magic.nlibs = bswap_32(swap_magic.nlibs);
426 + magic_ptr = &swap_magic;
428 + magic_ptr = &magic;
430 + if (write(cachefd, magic_ptr, sizeof (header_t)) != sizeof (header_t))
431 + err(EXIT_FATAL,"can't write %s~ (%s)", cachefile, strerror(errno));
433 for (cur_lib = lib_head; cur_lib != NULL; cur_lib = cur_lib->next)
435 @@ -701,29 +764,37 @@
436 stroffset += strlen(cur_lib->soname) + 1;
437 cur_lib->liboffset = stroffset;
438 stroffset += strlen(cur_lib->libname) + 1;
439 - if (write(cachefd, cur_lib, sizeof (libentry_t)) !=
440 - sizeof (libentry_t))
441 - err(EXIT_FATAL,"can't write %s (%s)", tempfile, strerror(errno));
443 + swap_lib.flags = bswap_32(cur_lib->flags);
444 + swap_lib.sooffset = bswap_32(cur_lib->sooffset);
445 + swap_lib.liboffset = bswap_32(cur_lib->liboffset);
446 + lib_ptr = &swap_lib;
448 + lib_ptr = (libentry_t *)cur_lib;
450 + if (write(cachefd, lib_ptr, sizeof (libentry_t)) !=
451 + sizeof (libentry_t))
452 + err(EXIT_FATAL,"can't write %s~ (%s)", cachefile, strerror(errno));
455 for (cur_lib = lib_head; cur_lib != NULL; cur_lib = cur_lib->next)
457 if (write(cachefd, cur_lib->soname, strlen(cur_lib->soname) + 1)
458 != strlen(cur_lib->soname) + 1)
459 - err(EXIT_FATAL,"can't write %s (%s)", tempfile, strerror(errno));
460 + err(EXIT_FATAL,"can't write %s~ (%s)", cachefile, strerror(errno));
461 if (write(cachefd, cur_lib->libname, strlen(cur_lib->libname) + 1)
462 != strlen(cur_lib->libname) + 1)
463 - err(EXIT_FATAL,"can't write %s (%s)", tempfile, strerror(errno));
464 + err(EXIT_FATAL,"can't write %s~ (%s)", cachefile, strerror(errno));
468 - err(EXIT_FATAL,"can't close %s (%s)", tempfile, strerror(errno));
469 + err(EXIT_FATAL,"can't close %s~ (%s)", cachefile, strerror(errno));
471 if (chmod(tempfile, 0644))
472 - err(EXIT_FATAL,"can't chmod %s (%s)", tempfile, strerror(errno));
473 + err(EXIT_FATAL,"can't chmod %s~ (%s)", cachefile, strerror(errno));
475 - if (rename(tempfile, cachefile))
476 - err(EXIT_FATAL,"can't rename %s (%s)", tempfile, strerror(errno));
477 + if (rename(tempfile, realcachefile))
478 + err(EXIT_FATAL,"can't rename %s~ (%s)", cachefile, strerror(errno));
481 void cache_print(void)
486 + char realcachefile[BUFFER_SIZE];
488 + if (!chroot_realpath(chroot_dir, cachefile, realcachefile))
489 + err(EXIT_FATAL,"can't resolve %s in chroot %s (%s)",
490 + cachefile, chroot_dir, strerror(errno));
492 - if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY))<0)
493 + if (stat(realcachefile, &st) || (fd = open(realcachefile, O_RDONLY))<0)
494 err(EXIT_FATAL,"can't read %s (%s)", cachefile, strerror(errno));
495 if ((c = mmap(0,st.st_size, PROT_READ, MAP_SHARED ,fd, 0)) == (caddr_t)-1)
496 err(EXIT_FATAL,"can't map %s (%s)", cachefile, strerror(errno));
501 - char *chroot_dir = NULL;
503 #ifdef __LDSO_CACHE_SUPPORT__
505 @@ -891,10 +966,16 @@
508 if (chroot_dir && *chroot_dir) {
509 - if (chroot(chroot_dir) < 0)
510 - err(EXIT_FATAL,"couldn't chroot to %s (%s)", chroot_dir, strerror(errno));
511 - if (chdir("/") < 0)
512 - err(EXIT_FATAL,"couldn't chdir to / (%s)", strerror(errno));
513 + if (chroot(chroot_dir) < 0) {
514 + if (chdir(chroot_dir) < 0)
515 + err(EXIT_FATAL,"couldn't chroot to %s (%s)", chroot_dir, strerror(errno));
519 + if (chdir("/") < 0)
520 + err(EXIT_FATAL,"couldn't chdir to / (%s)", strerror(errno));
525 /* allow me to introduce myself, hi, my name is ... */
526 diff -urN uClibc-orig/utils/Makefile uClibc-20050502/utils/Makefile
527 --- uClibc-orig/utils/Makefile 2005-05-01 23:10:12.000000000 -0700
528 +++ uClibc-20050502/utils/Makefile 2005-09-16 19:28:55.000000000 -0700
533 +ifeq ($(strip $(LDSO_CACHE_SUPPORT)),y)
534 +HOST_LDSO_CACHE_FLAG = -D__LDSO_CACHE_SUPPORT__=1
536 +HOST_LDSO_CACHE_FLAG =
539 # NOTE: We build the utils AFTER we have a uClibc-targeted toolchain.
541 ifeq ($(strip $(HAVE_SHARED)),y)
544 LDCONFIG_CFLAGS := $(PIEFLAG) $(LDPIEFLAG)
546 -ldconfig: ldconfig.c
547 +ldconfig: ldconfig.c chroot_realpath.c
548 $(CC) $(CFLAGS) $(LDCONFIG_CFLAGS) \
549 -DUCLIBC_RUNTIME_PREFIX=\"$(RUNTIME_PREFIX)\" \
550 -DUCLIBC_LDSO=$(UCLIBC_LDSO) -I. -I../ldso/include \
554 $(HOSTCC) $(HOSTCFLAGS) -Wl,-s \
555 - -DUCLIBC_RUNTIME_PREFIX=\"$(RUNTIME_PREFIX)\" \
556 + -DUCLIBC_RUNTIME_PREFIX=\"$(RUNTIME_PREFIX)\" $(HOST_LDSO_CACHE_FLAG) \
557 -DUCLIBC_LDSO=$(UCLIBC_LDSO) -I. -I../ldso/include \
560 -ldconfig.host: ldconfig.c
561 +ldconfig.host: ldconfig.c chroot_realpath.c
562 $(HOSTCC) $(HOSTCFLAGS) -Wl,-s \
563 - -DUCLIBC_RUNTIME_PREFIX=\"$(RUNTIME_PREFIX)\" \
564 + -DUCLIBC_RUNTIME_PREFIX=\"$(RUNTIME_PREFIX)\" $(HOST_LDSO_CACHE_FLAG) \
565 -DUCLIBC_LDSO=$(UCLIBC_LDSO) -I. -I../ldso/include \
568 diff -urN uClibc-orig/utils/readsoname2.c uClibc-20050502/utils/readsoname2.c
569 --- uClibc-orig/utils/readsoname2.c 2005-05-01 23:10:12.000000000 -0700
570 +++ uClibc-20050502/utils/readsoname2.c 2005-09-16 17:48:59.000000000 -0700
573 if (fstat(fileno(infile), &st))
575 - header = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fileno(infile), 0);
576 + header = mmap(0, st.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fileno(infile), 0);
577 if (header == (caddr_t)-1)
581 if ((char *)(epnt+1) > (char *)(header + st.st_size))
584 +#if __BYTE_ORDER == __LITTLE_ENDIAN
585 + byteswap = (epnt->e_ident[5] == ELFDATA2MSB) ? 1 : 0;
586 +#elif __BYTE_ORDER == __BIG_ENDIAN
587 + byteswap = (epnt->e_ident[5] == ELFDATA2LSB) ? 1 : 0;
589 +#error Unknown host byte order!
591 + /* Be very lazy, and only byteswap the stuff we use */
593 + epnt->e_phoff=bswap_32(epnt->e_phoff);
594 + epnt->e_phnum=bswap_16(epnt->e_phnum);
597 ppnt = (ElfW(Phdr) *)&header[epnt->e_phoff];
598 if ((char *)ppnt < (char *)header ||
599 (char *)(ppnt+epnt->e_phnum) > (char *)(header + st.st_size))
602 for(i = 0; i < epnt->e_phnum; i++)
604 + /* Be very lazy, and only byteswap the stuff we use */
606 + ppnt->p_type=bswap_32(ppnt->p_type);
607 + ppnt->p_vaddr=bswap_32(ppnt->p_vaddr);
608 + ppnt->p_offset=bswap_32(ppnt->p_offset);
609 + ppnt->p_filesz=bswap_32(ppnt->p_filesz);
612 if (loadaddr == -1 && ppnt->p_type == PT_LOAD)
613 loadaddr = (ppnt->p_vaddr & ~(page_size-1)) -
614 (ppnt->p_offset & ~(page_size-1));
616 (char *)(dpnt+dynamic_size) > (char *)(header + st.st_size))
620 + dpnt->d_tag=bswap_32(dpnt->d_tag);
621 + dpnt->d_un.d_val=bswap_32(dpnt->d_un.d_val);
624 while (dpnt->d_tag != DT_NULL)
626 if (dpnt->d_tag == DT_STRTAB)
627 strtab_val = dpnt->d_un.d_val;
630 + dpnt->d_tag=bswap_32(dpnt->d_tag);
631 + dpnt->d_un.d_val=bswap_32(dpnt->d_un.d_val);