diff -Nur uClibc-0.9.32-rc3/extra/Configs/Config.in uClibc/extra/Configs/Config.in --- uClibc-0.9.32-rc3/extra/Configs/Config.in 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/extra/Configs/Config.in 2011-04-26 16:18:21.707661578 +0200 @@ -1898,6 +1898,18 @@ This interface is rarely used, and adds around 4.5k. Unless you have a pressing need for ftw(), you should probably answer N. +config UCLIBC_HAS_FTS + bool "Support the fts() interface (bsd-compat)" + default n + help + The fts functions are provided for traversing UNIX file hierarchies. + + This interface is currently used by the elfutils and adds + around 7.5k. + You should port your application to use the POSIX nftw() + interface. + + Unless you need to build/use elfutils, you should prolly answer N. config UCLIBC_HAS_GLOB bool "Support the glob() interface" @@ -2322,7 +2334,7 @@ config UCLIBC_HAS_BACKTRACE bool "Add support for application self-debugging" - depends on HAVE_SHARED && TARGET_sh + depends on HAVE_SHARED default n help Answer Y here to compile support for application self-debugging, by adding diff -Nur uClibc-0.9.32-rc3/include/fts.h uClibc/include/fts.h --- uClibc-0.9.32-rc3/include/fts.h 1970-01-01 01:00:00.000000000 +0100 +++ uClibc/include/fts.h 2011-04-26 16:18:21.727663221 +0200 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)fts.h 8.3 (Berkeley) 8/14/94 + */ + +#ifndef _FTS_H +#define _FTS_H 1 + +#include +#include + +/* The fts interface is incompatible with the LFS interface which + transparently uses the 64-bit file access functions. */ +#ifdef __USE_FILE_OFFSET64 +# error " cannot be used with -D_FILE_OFFSET_BITS==64" +#endif + + +typedef struct { + struct _ftsent *fts_cur; /* current node */ + struct _ftsent *fts_child; /* linked list of children */ + struct _ftsent **fts_array; /* sort array */ + dev_t fts_dev; /* starting device # */ + char *fts_path; /* path for this descent */ + int fts_rfd; /* fd for root */ + int fts_pathlen; /* sizeof(path) */ + int fts_nitems; /* elements in the sort array */ + int (*fts_compar) (const void *, const void *); /* compare fn */ + +#define FTS_COMFOLLOW 0x0001 /* follow command line symlinks */ +#define FTS_LOGICAL 0x0002 /* logical walk */ +#define FTS_NOCHDIR 0x0004 /* don't change directories */ +#define FTS_NOSTAT 0x0008 /* don't get stat info */ +#define FTS_PHYSICAL 0x0010 /* physical walk */ +#define FTS_SEEDOT 0x0020 /* return dot and dot-dot */ +#define FTS_XDEV 0x0040 /* don't cross devices */ +#define FTS_WHITEOUT 0x0080 /* return whiteout information */ +#define FTS_OPTIONMASK 0x00ff /* valid user option mask */ + +#define FTS_NAMEONLY 0x0100 /* (private) child names only */ +#define FTS_STOP 0x0200 /* (private) unrecoverable error */ + int fts_options; /* fts_open options, global flags */ +} FTS; + +typedef struct _ftsent { + struct _ftsent *fts_cycle; /* cycle node */ + struct _ftsent *fts_parent; /* parent directory */ + struct _ftsent *fts_link; /* next file in directory */ + long fts_number; /* local numeric value */ + void *fts_pointer; /* local address value */ + char *fts_accpath; /* access path */ + char *fts_path; /* root path */ + int fts_errno; /* errno for this node */ + int fts_symfd; /* fd for symlink */ + u_short fts_pathlen; /* strlen(fts_path) */ + u_short fts_namelen; /* strlen(fts_name) */ + + ino_t fts_ino; /* inode */ + dev_t fts_dev; /* device */ + nlink_t fts_nlink; /* link count */ + +#define FTS_ROOTPARENTLEVEL -1 +#define FTS_ROOTLEVEL 0 + short fts_level; /* depth (-1 to N) */ + +#define FTS_D 1 /* preorder directory */ +#define FTS_DC 2 /* directory that causes cycles */ +#define FTS_DEFAULT 3 /* none of the above */ +#define FTS_DNR 4 /* unreadable directory */ +#define FTS_DOT 5 /* dot or dot-dot */ +#define FTS_DP 6 /* postorder directory */ +#define FTS_ERR 7 /* error; errno is set */ +#define FTS_F 8 /* regular file */ +#define FTS_INIT 9 /* initialized only */ +#define FTS_NS 10 /* stat(2) failed */ +#define FTS_NSOK 11 /* no stat(2) requested */ +#define FTS_SL 12 /* symbolic link */ +#define FTS_SLNONE 13 /* symbolic link without target */ +#define FTS_W 14 /* whiteout object */ + u_short fts_info; /* user flags for FTSENT structure */ + +#define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */ +#define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */ + u_short fts_flags; /* private flags for FTSENT structure */ + +#define FTS_AGAIN 1 /* read node again */ +#define FTS_FOLLOW 2 /* follow symbolic link */ +#define FTS_NOINSTR 3 /* no instructions */ +#define FTS_SKIP 4 /* discard node */ + u_short fts_instr; /* fts_set() instructions */ + + struct stat *fts_statp; /* stat(2) information */ + char fts_name[1]; /* file name */ +} FTSENT; + +__BEGIN_DECLS +FTSENT *fts_children (FTS *, int); +int fts_close (FTS *); +FTS *fts_open (char * const *, int, + int (*)(const FTSENT **, const FTSENT **)); +FTSENT *fts_read (FTS *); +int fts_set (FTS *, FTSENT *, int) __THROW; +__END_DECLS + +#endif /* fts.h */ diff -Nur uClibc-0.9.32-rc3/ldso/include/dl-elf.h uClibc/ldso/include/dl-elf.h --- uClibc-0.9.32-rc3/ldso/include/dl-elf.h 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/ldso/include/dl-elf.h 2011-04-26 16:18:21.747664948 +0200 @@ -184,7 +184,7 @@ ADJUST_DYN_INFO(DT_DSBT_BASE_IDX, load_off); /* Initialize loadmap dsbt info. */ - load_off.map->dsbt_table = dynamic_info[DT_DSBT_BASE_IDX]; + load_off.map->dsbt_table = (void *)dynamic_info[DT_DSBT_BASE_IDX]; load_off.map->dsbt_size = dynamic_info[DT_DSBT_SIZE_IDX]; load_off.map->dsbt_index = dynamic_info[DT_DSBT_INDEX_IDX]; #endif diff -Nur uClibc-0.9.32-rc3/ldso/include/ldso.h uClibc/ldso/include/ldso.h --- uClibc-0.9.32-rc3/ldso/include/ldso.h 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/ldso/include/ldso.h 2011-04-26 16:18:21.747664948 +0200 @@ -34,6 +34,8 @@ #include /* Pull in the arch specific page size */ #include +/* Pull in the MIN macro */ +#include /* Pull in the ldso syscalls and string functions */ #ifndef __ARCH_HAS_NO_SHARED__ #include diff -Nur uClibc-0.9.32-rc3/ldso/ldso/bfin/dl-inlines.h uClibc/ldso/ldso/bfin/dl-inlines.h --- uClibc-0.9.32-rc3/ldso/ldso/bfin/dl-inlines.h 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/ldso/ldso/bfin/dl-inlines.h 2011-04-26 16:18:21.747664948 +0200 @@ -88,14 +88,39 @@ segdata->p_memsz = phdr->p_memsz; #if defined (__SUPPORT_LD_DEBUG__) - { - extern char *_dl_debug; - extern int _dl_debug_file; - if (_dl_debug) - _dl_dprintf(_dl_debug_file, "%i: mapped %x at %x, size %x\n", - loadaddr.map->nsegs-1, - segdata->p_vaddr, segdata->addr, segdata->p_memsz); - } + if (_dl_debug) + _dl_dprintf(_dl_debug_file, "%i: mapped %x at %x, size %x\n", + loadaddr.map->nsegs-1, + segdata->p_vaddr, segdata->addr, segdata->p_memsz); +#endif +} + +/* Replace an existing entry in the load map. */ +static __always_inline void +__dl_update_loadaddr_hdr (struct elf32_fdpic_loadaddr loadaddr, void *addr, + Elf32_Phdr *phdr) +{ + struct elf32_fdpic_loadseg *segdata; + void *oldaddr; + int i; + + for (i = 0; i < loadaddr.map->nsegs; i++) + if (loadaddr.map->segs[i].p_vaddr == phdr->p_vaddr + && loadaddr.map->segs[i].p_memsz == phdr->p_memsz) + break; + if (i == loadaddr.map->nsegs) + _dl_exit (-1); + + segdata = loadaddr.map->segs + i; + oldaddr = (void *)segdata->addr; + _dl_munmap (oldaddr, segdata->p_memsz); + segdata->addr = (Elf32_Addr) addr; + +#if defined (__SUPPORT_LD_DEBUG__) + if (_dl_debug) + _dl_dprintf(_dl_debug_file, "%i: changed mapping %x at %x (old %x), size %x\n", + loadaddr.map->nsegs-1, + segdata->p_vaddr, segdata->addr, oldaddr, segdata->p_memsz); #endif } diff -Nur uClibc-0.9.32-rc3/ldso/ldso/bfin/dl-sysdep.h uClibc/ldso/ldso/bfin/dl-sysdep.h --- uClibc-0.9.32-rc3/ldso/ldso/bfin/dl-sysdep.h 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/ldso/ldso/bfin/dl-sysdep.h 2011-04-26 16:18:21.747664948 +0200 @@ -120,6 +120,8 @@ #define DL_INIT_LOADADDR_HDR(LOADADDR, ADDR, PHDR) \ (__dl_init_loadaddr_hdr ((LOADADDR), (ADDR), (PHDR), \ dl_init_loadaddr_load_count)) +#define DL_UPDATE_LOADADDR_HDR(LOADADDR, ADDR, PHDR) \ + (__dl_update_loadaddr_hdr ((LOADADDR), (ADDR), (PHDR))) #define DL_LOADADDR_UNMAP(LOADADDR, LEN) \ (__dl_loadaddr_unmap ((LOADADDR), (NULL))) #define DL_LIB_UNMAP(LIB, LEN) \ diff -Nur uClibc-0.9.32-rc3/ldso/ldso/c6x/dl-inlines.h uClibc/ldso/ldso/c6x/dl-inlines.h --- uClibc-0.9.32-rc3/ldso/ldso/c6x/dl-inlines.h 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/ldso/ldso/c6x/dl-inlines.h 2011-04-26 16:18:21.747664948 +0200 @@ -74,6 +74,35 @@ #endif } +/* Replace an existing entry in the load map. */ +static __always_inline void +__dl_update_loadaddr_hdr (struct elf32_dsbt_loadaddr loadaddr, void *addr, + Elf32_Phdr *phdr) +{ + struct elf32_dsbt_loadseg *segdata; + void *oldaddr; + int i; + + for (i = 0; i < loadaddr.map->nsegs; i++) + if (loadaddr.map->segs[i].p_vaddr == phdr->p_vaddr + && loadaddr.map->segs[i].p_memsz == phdr->p_memsz) + break; + if (i == loadaddr.map->nsegs) + _dl_exit (-1); + + segdata = loadaddr.map->segs + i; + oldaddr = (void *)segdata->addr; + _dl_munmap (oldaddr, segdata->p_memsz); + segdata->addr = (Elf32_Addr) addr; + +#if defined (__SUPPORT_LD_DEBUG__) + if (_dl_debug) + _dl_dprintf(_dl_debug_file, "%i: changed mapping %x at %x (old %x), size %x\n", + loadaddr.map->nsegs-1, + segdata->p_vaddr, segdata->addr, oldaddr, segdata->p_memsz); +#endif +} + static __always_inline void __dl_loadaddr_unmap (struct elf32_dsbt_loadaddr loadaddr) { diff -Nur uClibc-0.9.32-rc3/ldso/ldso/c6x/dl-sysdep.h uClibc/ldso/ldso/c6x/dl-sysdep.h --- uClibc-0.9.32-rc3/ldso/ldso/c6x/dl-sysdep.h 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/ldso/ldso/c6x/dl-sysdep.h 2011-04-26 16:18:21.747664948 +0200 @@ -104,6 +104,9 @@ (__dl_init_loadaddr_hdr ((LOADADDR), (ADDR), (PHDR), \ dl_init_loadaddr_load_count)) +#define DL_UPDATE_LOADADDR_HDR(LOADADDR, ADDR, PHDR) \ + (__dl_update_loadaddr_hdr ((LOADADDR), (ADDR), (PHDR))) + #define DL_LOADADDR_UNMAP(LOADADDR, LEN) \ (__dl_loadaddr_unmap ((LOADADDR))) diff -Nur uClibc-0.9.32-rc3/ldso/ldso/c6x/elfinterp.c uClibc/ldso/ldso/c6x/elfinterp.c --- uClibc-0.9.32-rc3/ldso/ldso/c6x/elfinterp.c 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/ldso/ldso/c6x/elfinterp.c 2011-04-26 16:18:21.747664948 +0200 @@ -198,6 +198,10 @@ new_val = sym_val; *reloc_addr = sym_val; break; + case R_C6000_DSBT_INDEX: + new_val = (old_val & ~0x007fff00) | ((tpnt->loadaddr.map->dsbt_index & 0x7fff) << 8); + *reloc_addr = new_val; + break; case R_C6000_ABS_L16: new_val = (old_val & ~0x007fff80) | ((sym_val & 0xffff) << 7); *reloc_addr = new_val; @@ -224,7 +228,7 @@ (char *)symbol_addr, symtab[symtab_index].st_size); } - break; + return 0; default: return -1; /*call _dl_exit(1) */ } diff -Nur uClibc-0.9.32-rc3/ldso/ldso/dl-elf.c uClibc/ldso/ldso/dl-elf.c --- uClibc-0.9.32-rc3/ldso/ldso/dl-elf.c 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/ldso/ldso/dl-elf.c 2011-04-26 16:18:21.747664948 +0200 @@ -314,6 +314,121 @@ return NULL; } +/* + * Make a writeable mapping of a segment, regardless of whether PF_W is + * set or not. + */ +static void * +map_writeable (int infile, ElfW(Phdr) *ppnt, int piclib, int flags, + unsigned long libaddr) +{ + int prot_flags = ppnt->p_flags | PF_W; + char *status, *retval; + char *tryaddr; + ssize_t size; + unsigned long map_size; + char *cpnt; + char *piclib2map = NULL; + + if (piclib == 2 && + /* We might be able to avoid this call if memsz doesn't + require an additional page, but this would require mmap + to always return page-aligned addresses and a whole + number of pages allocated. Unfortunately on uClinux + may return misaligned addresses and may allocate + partial pages, so we may end up doing unnecessary mmap + calls. + + This is what we could do if we knew mmap would always + return aligned pages: + + ((ppnt->p_vaddr + ppnt->p_filesz + ADDR_ALIGN) & + PAGE_ALIGN) < ppnt->p_vaddr + ppnt->p_memsz) + + Instead, we have to do this: */ + ppnt->p_filesz < ppnt->p_memsz) + { + piclib2map = (char *) + _dl_mmap(0, (ppnt->p_vaddr & ADDR_ALIGN) + ppnt->p_memsz, + LXFLAGS(prot_flags), flags | MAP_ANONYMOUS, -1, 0); + if (_dl_mmap_check_error(piclib2map)) + return 0; + } + + tryaddr = piclib == 2 ? piclib2map + : ((char*) (piclib ? libaddr : 0) + + (ppnt->p_vaddr & PAGE_ALIGN)); + + size = (ppnt->p_vaddr & ADDR_ALIGN) + ppnt->p_filesz; + + /* For !MMU, mmap to fixed address will fail. + So instead of desperately call mmap and fail, + we set status to MAP_FAILED to save a call + to mmap (). */ +#ifndef __ARCH_USE_MMU__ + if (piclib2map == 0) +#endif + status = (char *) _dl_mmap + (tryaddr, size, LXFLAGS(prot_flags), + flags | (piclib2map ? MAP_FIXED : 0), + infile, ppnt->p_offset & OFFS_ALIGN); +#ifndef __ARCH_USE_MMU__ + else + status = MAP_FAILED; +#endif +#ifdef _DL_PREAD + if (_dl_mmap_check_error(status) && piclib2map + && (_DL_PREAD (infile, tryaddr, size, + ppnt->p_offset & OFFS_ALIGN) == size)) + status = tryaddr; +#endif + if (_dl_mmap_check_error(status) || (tryaddr && tryaddr != status)) + return 0; + + if (piclib2map) + retval = piclib2map; + else + retval = status; + + /* Now we want to allocate and zero-out any data from the end + of the region we mapped in from the file (filesz) to the + end of the loadable segment (memsz). We may need + additional pages for memsz, that we map in below, and we + can count on the kernel to zero them out, but we have to + zero out stuff in the last page that we mapped in from the + file. However, we can't assume to have actually obtained + full pages from the kernel, since we didn't ask for them, + and uClibc may not give us full pages for small + allocations. So only zero out up to memsz or the end of + the page, whichever comes first. */ + + /* CPNT is the beginning of the memsz portion not backed by + filesz. */ + cpnt = (char *) (status + size); + + /* MAP_SIZE is the address of the + beginning of the next page. */ + map_size = (ppnt->p_vaddr + ppnt->p_filesz + + ADDR_ALIGN) & PAGE_ALIGN; + + _dl_memset (cpnt, 0, + MIN (map_size + - (ppnt->p_vaddr + + ppnt->p_filesz), + ppnt->p_memsz + - ppnt->p_filesz)); + + if (map_size < ppnt->p_vaddr + ppnt->p_memsz && !piclib2map) { + tryaddr = map_size + (char*)(piclib ? libaddr : 0); + status = (char *) _dl_mmap(tryaddr, + ppnt->p_vaddr + ppnt->p_memsz - map_size, + LXFLAGS(prot_flags), + flags | MAP_ANONYMOUS | MAP_FIXED, -1, 0); + if (_dl_mmap_check_error(status) || tryaddr != status) + return NULL; + } + return retval; +} /* * Read one ELF library into memory, mmap it into the correct locations and @@ -475,6 +590,7 @@ status = (char *) _dl_mmap((char *) (piclib ? 0 : minvma), maxvma - minvma, PROT_NONE, flags | MAP_ANONYMOUS, -1, 0); if (_dl_mmap_check_error(status)) { + cant_map: _dl_dprintf(2, "%s:%i: can't map '%s'\n", _dl_progname, __LINE__, libname); _dl_internal_error_number = LD_ERROR_MMAP_FAILED; _dl_close(infile); @@ -495,8 +611,11 @@ char *addr; addr = DL_MAP_SEGMENT (epnt, ppnt, infile, flags); - if (addr == NULL) + if (addr == NULL) { + cant_map1: + DL_LOADADDR_UNMAP (lib_loadaddr, maxvma - minvma); goto cant_map; + } DL_INIT_LOADADDR_HDR (lib_loadaddr, addr, ppnt); ppnt++; @@ -517,141 +636,9 @@ } if (ppnt->p_flags & PF_W) { - unsigned long map_size; - char *cpnt; - char *piclib2map = 0; - - if (piclib == 2 && - /* We might be able to avoid this - call if memsz doesn't require - an additional page, but this - would require mmap to always - return page-aligned addresses - and a whole number of pages - allocated. Unfortunately on - uClinux may return misaligned - addresses and may allocate - partial pages, so we may end up - doing unnecessary mmap calls. - - This is what we could do if we - knew mmap would always return - aligned pages: - - ((ppnt->p_vaddr + ppnt->p_filesz - + ADDR_ALIGN) - & PAGE_ALIGN) - < ppnt->p_vaddr + ppnt->p_memsz) - - Instead, we have to do this: */ - ppnt->p_filesz < ppnt->p_memsz) - { - piclib2map = (char *) - _dl_mmap(0, (ppnt->p_vaddr & ADDR_ALIGN) - + ppnt->p_memsz, - LXFLAGS(ppnt->p_flags), - flags | MAP_ANONYMOUS, -1, 0); - if (_dl_mmap_check_error(piclib2map)) - goto cant_map; - DL_INIT_LOADADDR_HDR - (lib_loadaddr, piclib2map - + (ppnt->p_vaddr & ADDR_ALIGN), ppnt); - } - - tryaddr = piclib == 2 ? piclib2map - : ((char*) (piclib ? libaddr : 0) + - (ppnt->p_vaddr & PAGE_ALIGN)); - - size = (ppnt->p_vaddr & ADDR_ALIGN) - + ppnt->p_filesz; - - /* For !MMU, mmap to fixed address will fail. - So instead of desperately call mmap and fail, - we set status to MAP_FAILED to save a call - to mmap (). */ -#ifndef __ARCH_USE_MMU__ - if (piclib2map == 0) -#endif - status = (char *) _dl_mmap - (tryaddr, size, LXFLAGS(ppnt->p_flags), - flags | (piclib2map ? MAP_FIXED : 0), - infile, ppnt->p_offset & OFFS_ALIGN); -#ifndef __ARCH_USE_MMU__ - else - status = MAP_FAILED; -#endif -#ifdef _DL_PREAD - if (_dl_mmap_check_error(status) && piclib2map - && (_DL_PREAD (infile, tryaddr, size, - ppnt->p_offset & OFFS_ALIGN) - == size)) - status = tryaddr; -#endif - if (_dl_mmap_check_error(status) - || (tryaddr && tryaddr != status)) { - cant_map: - _dl_dprintf(2, "%s:%i: can't map '%s'\n", - _dl_progname, __LINE__, libname); - _dl_internal_error_number = LD_ERROR_MMAP_FAILED; - DL_LOADADDR_UNMAP (lib_loadaddr, maxvma - minvma); - _dl_close(infile); - _dl_munmap(header, _dl_pagesize); - return NULL; - } - - if (! piclib2map) { - DL_INIT_LOADADDR_HDR - (lib_loadaddr, status - + (ppnt->p_vaddr & ADDR_ALIGN), ppnt); - } - /* Now we want to allocate and - zero-out any data from the end of - the region we mapped in from the - file (filesz) to the end of the - loadable segment (memsz). We may - need additional pages for memsz, - that we map in below, and we can - count on the kernel to zero them - out, but we have to zero out stuff - in the last page that we mapped in - from the file. However, we can't - assume to have actually obtained - full pages from the kernel, since - we didn't ask for them, and uClibc - may not give us full pages for - small allocations. So only zero - out up to memsz or the end of the - page, whichever comes first. */ - - /* CPNT is the beginning of the memsz - portion not backed by filesz. */ - cpnt = (char *) (status + size); - - /* MAP_SIZE is the address of the - beginning of the next page. */ - map_size = (ppnt->p_vaddr + ppnt->p_filesz - + ADDR_ALIGN) & PAGE_ALIGN; - -#ifndef MIN -# define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - _dl_memset (cpnt, 0, - MIN (map_size - - (ppnt->p_vaddr - + ppnt->p_filesz), - ppnt->p_memsz - - ppnt->p_filesz)); - - if (map_size < ppnt->p_vaddr + ppnt->p_memsz - && !piclib2map) { - tryaddr = map_size + (char*)(piclib ? libaddr : 0); - status = (char *) _dl_mmap(tryaddr, - ppnt->p_vaddr + ppnt->p_memsz - map_size, - LXFLAGS(ppnt->p_flags), flags | MAP_ANONYMOUS | MAP_FIXED, -1, 0); - if (_dl_mmap_check_error(status) - || tryaddr != status) - goto cant_map; - } + status = map_writeable (infile, ppnt, piclib, flags, libaddr); + if (status == NULL) + goto cant_map1; } else { tryaddr = (piclib == 2 ? 0 : (char *) (ppnt->p_vaddr & PAGE_ALIGN) @@ -664,11 +651,11 @@ infile, ppnt->p_offset & OFFS_ALIGN); if (_dl_mmap_check_error(status) || (tryaddr && tryaddr != status)) - goto cant_map; - DL_INIT_LOADADDR_HDR - (lib_loadaddr, status - + (ppnt->p_vaddr & ADDR_ALIGN), ppnt); + goto cant_map1; } + DL_INIT_LOADADDR_HDR(lib_loadaddr, + status + (ppnt->p_vaddr & ADDR_ALIGN), + ppnt); /* if (libaddr == 0 && piclib) { libaddr = (unsigned long) status; @@ -677,7 +664,6 @@ } ppnt++; } - _dl_close(infile); /* For a non-PIC library, the addresses are all absolute */ if (piclib) { @@ -696,6 +682,7 @@ _dl_dprintf(2, "%s: '%s' is missing a dynamic section\n", _dl_progname, libname); _dl_munmap(header, _dl_pagesize); + _dl_close(infile); return NULL; } @@ -711,10 +698,23 @@ ppnt = (ElfW(Phdr) *)(intptr_t) & header[epnt->e_phoff]; for (i = 0; i < epnt->e_phnum; i++, ppnt++) { if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) { +#ifdef __ARCH_USE_MMU__ _dl_mprotect((void *) ((piclib ? libaddr : 0) + (ppnt->p_vaddr & PAGE_ALIGN)), (ppnt->p_vaddr & ADDR_ALIGN) + (unsigned long) ppnt->p_filesz, PROT_READ | PROT_WRITE | PROT_EXEC); +#else + void *new_addr; + new_addr = map_writeable (infile, ppnt, piclib, flags, libaddr); + if (!new_addr) { + _dl_dprintf(_dl_debug_file, "Can't modify %s's text section.", + libname); + _dl_exit(1); + } + DL_UPDATE_LOADADDR_HDR(lib_loadaddr, + new_addr + (ppnt->p_vaddr & ADDR_ALIGN), + ppnt); +#endif } } #else @@ -725,6 +725,8 @@ #endif } + _dl_close(infile); + tpnt = _dl_add_elf_hash_table(libname, lib_loadaddr, dynamic_info, dynamic_addr, 0); tpnt->relro_addr = relro_addr; @@ -809,20 +811,44 @@ #ifdef __DSBT__ /* Handle DSBT initialization */ { - struct elf_resolve *t, *ref = NULL; + struct elf_resolve *t, *ref; int idx = tpnt->loadaddr.map->dsbt_index; unsigned *dsbt = tpnt->loadaddr.map->dsbt_table; if (idx == 0) { - /* This DSO has not been assigned an index */ - _dl_dprintf(2, "%s: '%s' is missing a dsbt index assignment!\n", - _dl_progname, libname); - _dl_exit(1); + if (!dynamic_info[DT_TEXTREL]) { + /* This DSO has not been assigned an index. */ + _dl_dprintf(2, "%s: '%s' is missing a dsbt index assignment!\n", + _dl_progname, libname); + _dl_exit(1); + } + /* Find a dsbt table from another module. */ + ref = NULL; + for (t = _dl_loaded_modules; t; t = t->next) { + if (ref == NULL && t != tpnt) { + ref = t; + break; + } + } + idx = tpnt->loadaddr.map->dsbt_size; + while (idx-- > 0) + if (!ref || ref->loadaddr.map->dsbt_table[idx] == NULL) + break; + if (idx <= 0) { + _dl_dprintf(2, "%s: '%s' caused DSBT table overflow!\n", + _dl_progname, libname); + _dl_exit(1); + } + _dl_if_debug_dprint("\n\tfile='%s'; assigned index %d\n", + libname, idx); + tpnt->loadaddr.map->dsbt_index = idx; + } /* * Setup dsbt slot for this module in dsbt of all modules. */ + ref = NULL; for (t = _dl_loaded_modules; t; t = t->next) { /* find a dsbt table from another module */ if (ref == NULL && t != tpnt) { diff -Nur uClibc-0.9.32-rc3/ldso/ldso/dl-startup.c uClibc/ldso/ldso/dl-startup.c --- uClibc-0.9.32-rc3/ldso/ldso/dl-startup.c 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/ldso/ldso/dl-startup.c 2011-04-26 16:18:21.747664948 +0200 @@ -32,8 +32,8 @@ /* * The main trick with this program is that initially, we ourselves are not - * dynamicly linked. This means that we cannot access any global variables or - * call any functions. No globals initially, since the Global Offset Table + * dynamically linked. This means that we cannot access any global variables + * or call any functions. No globals initially, since the Global Offset Table * (GOT) is initialized by the linker assuming a virtual address of 0, and no * function calls initially since the Procedure Linkage Table (PLT) is not yet * initialized. @@ -55,12 +55,12 @@ * * Fortunately, the linker itself leaves a few clues lying around, and when the * kernel starts the image, there are a few further clues. First of all, there - * is Auxiliary Vector Table information sitting on which is provided to us by - * the kernel, and which includes information about the load address that the - * program interpreter was loaded at, the number of sections, the address the - * application was loaded at and so forth. Here this information is stored in - * the array auxvt. For details see linux/fs/binfmt_elf.c where it calls - * NEW_AUX_ENT() a bunch of time.... + * is Auxiliary Vector Table information sitting on the stack which is provided + * to us by the kernel, and which includes information about the address + * that the program interpreter was loaded at, the number of sections, the + * address the application was loaded at, and so forth. Here this information + * is stored in the array auxvt. For details see linux/fs/binfmt_elf.c where + * it calls NEW_AUX_ENT() a bunch of times.... * * Next, we need to find the GOT. On most arches there is a register pointing * to the GOT, but just in case (and for new ports) I've added some (slow) C diff -Nur uClibc-0.9.32-rc3/ldso/ldso/frv/dl-inlines.h uClibc/ldso/ldso/frv/dl-inlines.h --- uClibc-0.9.32-rc3/ldso/ldso/frv/dl-inlines.h 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/ldso/ldso/frv/dl-inlines.h 2011-04-26 16:18:21.757661905 +0200 @@ -72,14 +72,39 @@ segdata->p_memsz = phdr->p_memsz; #if defined (__SUPPORT_LD_DEBUG__) - { - extern char *_dl_debug; - extern int _dl_debug_file; - if (_dl_debug) - _dl_dprintf(_dl_debug_file, "%i: mapped %x at %x, size %x\n", - loadaddr.map->nsegs-1, - segdata->p_vaddr, segdata->addr, segdata->p_memsz); - } + if (_dl_debug) + _dl_dprintf(_dl_debug_file, "%i: mapped %x at %x, size %x\n", + loadaddr.map->nsegs-1, + segdata->p_vaddr, segdata->addr, segdata->p_memsz); +#endif +} + +/* Replace an existing entry in the load map. */ +static __always_inline void +__dl_update_loadaddr_hdr (struct elf32_fdpic_loadaddr loadaddr, void *addr, + Elf32_Phdr *phdr) +{ + struct elf32_fdpic_loadseg *segdata; + void *oldaddr; + int i; + + for (i = 0; i < loadaddr.map->nsegs; i++) + if (loadaddr.map->segs[i].p_vaddr == phdr->p_vaddr + && loadaddr.map->segs[i].p_memsz == phdr->p_memsz) + break; + if (i == loadaddr.map->nsegs) + _dl_exit (-1); + + segdata = loadaddr.map->segs + i; + oldaddr = (void *)segdata->addr; + _dl_munmap (oldaddr, segdata->p_memsz); + segdata->addr = (Elf32_Addr) addr; + +#if defined (__SUPPORT_LD_DEBUG__) + if (_dl_debug) + _dl_dprintf(_dl_debug_file, "%i: changed mapping %x at %x (old %x), size %x\n", + loadaddr.map->nsegs-1, + segdata->p_vaddr, segdata->addr, oldaddr, segdata->p_memsz); #endif } diff -Nur uClibc-0.9.32-rc3/ldso/ldso/frv/dl-sysdep.h uClibc/ldso/ldso/frv/dl-sysdep.h --- uClibc-0.9.32-rc3/ldso/ldso/frv/dl-sysdep.h 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/ldso/ldso/frv/dl-sysdep.h 2011-04-26 16:18:21.757661905 +0200 @@ -95,6 +95,8 @@ #define DL_INIT_LOADADDR_HDR(LOADADDR, ADDR, PHDR) \ (__dl_init_loadaddr_hdr ((LOADADDR), (ADDR), (PHDR), \ dl_init_loadaddr_load_count)) +#define DL_UPDATE_LOADADDR_HDR(LOADADDR, ADDR, PHDR) \ + (__dl_update_loadaddr_hdr ((LOADADDR), (ADDR), (PHDR))) #define DL_LOADADDR_UNMAP(LOADADDR, LEN) \ (__dl_loadaddr_unmap ((LOADADDR), (NULL))) #define DL_LIB_UNMAP(LIB, LEN) \ diff -Nur uClibc-0.9.32-rc3/ldso/ldso/mips/elfinterp.c uClibc/ldso/ldso/mips/elfinterp.c --- uClibc-0.9.32-rc3/ldso/ldso/mips/elfinterp.c 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/ldso/ldso/mips/elfinterp.c 2011-04-26 16:18:21.757661905 +0200 @@ -378,8 +378,11 @@ *got_entry += (unsigned long) tpnt->loadaddr; } else { + struct symbol_ref sym_ref; + sym_ref.sym = sym; + sym_ref.tpnt = NULL; *got_entry = (unsigned long) _dl_find_hash(strtab + - sym->st_name, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL); + sym->st_name, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, &sym_ref); } got_entry++; diff -Nur uClibc-0.9.32-rc3/libc/inet/resolv.c uClibc/libc/inet/resolv.c --- uClibc-0.9.32-rc3/libc/inet/resolv.c 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/libc/inet/resolv.c 2011-04-26 16:18:21.767661585 +0200 @@ -3009,7 +3009,7 @@ int m = 0; /* free nsaddrs[m] if they do not point to nsaddr_list[x] */ while (m < ARRAY_SIZE(_res._u._ext.nsaddrs)) { - char *p2 = (char*)(_res._u._ext.nsaddrs[m]); + char *p2 = (char*)(_res._u._ext.nsaddrs[m++]); if (p2 < p1 || (p2 - p1) > sizeof(_res.nsaddr_list)) free(p2); } diff -Nur uClibc-0.9.32-rc3/libc/misc/fts/fts.c uClibc/libc/misc/fts/fts.c --- uClibc-0.9.32-rc3/libc/misc/fts/fts.c 1970-01-01 01:00:00.000000000 +0100 +++ uClibc/libc/misc/fts/fts.c 2011-04-26 16:18:21.777663244 +0200 @@ -0,0 +1,1145 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __UCLIBC_HAS_LFS__ +# include <_lfs_64.h> +#else +# define stat64 stat +# define fstat64 fstat +#endif + +/* Largest alignment size needed, minus one. + Usually long double is the worst case. */ +#ifndef ALIGNBYTES +#define ALIGNBYTES (__alignof__ (long double) - 1) +#endif +/* Align P to that size. */ +#ifndef ALIGN +#define ALIGN(p) (((unsigned long int) (p) + ALIGNBYTES) & ~ALIGNBYTES) +#endif + + +static FTSENT *fts_alloc (FTS *, const char *, size_t) internal_function; +static FTSENT *fts_build (FTS *, int) internal_function; +static void fts_lfree (FTSENT *) internal_function; +static void fts_load (FTS *, FTSENT *) internal_function; +static size_t fts_maxarglen (char * const *) internal_function; +static void fts_padjust (FTS *, FTSENT *) internal_function; +static int fts_palloc (FTS *, size_t) internal_function; +static FTSENT *fts_sort (FTS *, FTSENT *, int) internal_function; +static u_short fts_stat (FTS *, FTSENT *, int) internal_function; +static int fts_safe_changedir (FTS *, FTSENT *, int, const char *) + internal_function; + +#ifndef MAX +#define MAX(a, b) ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a > _b ? _a : _b; }) +#endif + +#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) + +#define CLR(opt) (sp->fts_options &= ~(opt)) +#define ISSET(opt) (sp->fts_options & (opt)) +#define SET(opt) (sp->fts_options |= (opt)) + +#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd)) + +/* fts_build flags */ +#define BCHILD 1 /* fts_children */ +#define BNAMES 2 /* fts_children, names only */ +#define BREAD 3 /* fts_read */ + +FTS * +fts_open(argv, options, compar) + char * const *argv; + register int options; + int (*compar) (const FTSENT **, const FTSENT **); +{ + register FTS *sp; + register FTSENT *p, *root; + register int nitems; + FTSENT *parent = NULL; + FTSENT *tmp = NULL; + + /* Options check. */ + if (options & ~FTS_OPTIONMASK) { + __set_errno (EINVAL); + return (NULL); + } + + /* Allocate/initialize the stream */ + if ((sp = malloc((u_int)sizeof(FTS))) == NULL) + return (NULL); + memset(sp, 0, sizeof(FTS)); + sp->fts_compar = (int (*) (const void *, const void *)) compar; + sp->fts_options = options; + + /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ + if (ISSET(FTS_LOGICAL)) + SET(FTS_NOCHDIR); + + /* + * Start out with 1K of path space, and enough, in any case, + * to hold the user's paths. + */ +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + size_t maxarglen = fts_maxarglen(argv); + if (fts_palloc(sp, MAX(maxarglen, MAXPATHLEN))) + goto mem1; + + /* Allocate/initialize root's parent. */ + if (*argv != NULL) { + if ((parent = fts_alloc(sp, "", 0)) == NULL) + goto mem2; + parent->fts_level = FTS_ROOTPARENTLEVEL; + } + + /* Allocate/initialize root(s). */ + for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) { + /* Don't allow zero-length paths. */ + size_t len = strlen(*argv); + if (len == 0) { + __set_errno (ENOENT); + goto mem3; + } + + p = fts_alloc(sp, *argv, len); + p->fts_level = FTS_ROOTLEVEL; + p->fts_parent = parent; + p->fts_accpath = p->fts_name; + p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW)); + + /* Command-line "." and ".." are real directories. */ + if (p->fts_info == FTS_DOT) + p->fts_info = FTS_D; + + /* + * If comparison routine supplied, traverse in sorted + * order; otherwise traverse in the order specified. + */ + if (compar) { + p->fts_link = root; + root = p; + } else { + p->fts_link = NULL; + if (root == NULL) + tmp = root = p; + else { + tmp->fts_link = p; + tmp = p; + } + } + } + if (compar && nitems > 1) + root = fts_sort(sp, root, nitems); + + /* + * Allocate a dummy pointer and make fts_read think that we've just + * finished the node before the root(s); set p->fts_info to FTS_INIT + * so that everything about the "current" node is ignored. + */ + if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL) + goto mem3; + sp->fts_cur->fts_link = root; + sp->fts_cur->fts_info = FTS_INIT; + + /* + * If using chdir(2), grab a file descriptor pointing to dot to ensure + * that we can get back here; this could be avoided for some paths, + * but almost certainly not worth the effort. Slashes, symbolic links, + * and ".." are all fairly nasty problems. Note, if we can't get the + * descriptor we run anyway, just more slowly. + */ + if (!ISSET(FTS_NOCHDIR) + && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0) + SET(FTS_NOCHDIR); + + return (sp); + +mem3: fts_lfree(root); + free(parent); +mem2: free(sp->fts_path); +mem1: free(sp); + return (NULL); +} + +static void +internal_function +fts_load(sp, p) + FTS *sp; + register FTSENT *p; +{ + register int len; + register char *cp; + + /* + * Load the stream structure for the next traversal. Since we don't + * actually enter the directory until after the preorder visit, set + * the fts_accpath field specially so the chdir gets done to the right + * place and the user can access the first node. From fts_open it's + * known that the path will fit. + */ + len = p->fts_pathlen = p->fts_namelen; + memmove(sp->fts_path, p->fts_name, len + 1); + if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) { + len = strlen(++cp); + memmove(p->fts_name, cp, len + 1); + p->fts_namelen = len; + } + p->fts_accpath = p->fts_path = sp->fts_path; + sp->fts_dev = p->fts_dev; +} + +int +fts_close(sp) + FTS *sp; +{ + register FTSENT *freep, *p; + int saved_errno; + + /* + * This still works if we haven't read anything -- the dummy structure + * points to the root list, so we step through to the end of the root + * list which has a valid parent pointer. + */ + if (sp->fts_cur) { + for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { + freep = p; + p = p->fts_link != NULL ? p->fts_link : p->fts_parent; + free(freep); + } + free(p); + } + + /* Free up child linked list, sort array, path buffer. */ + if (sp->fts_child) + fts_lfree(sp->fts_child); + free(sp->fts_array); + free(sp->fts_path); + + /* Return to original directory, save errno if necessary. */ + if (!ISSET(FTS_NOCHDIR)) { + saved_errno = fchdir(sp->fts_rfd) ? errno : 0; + (void)close(sp->fts_rfd); + + /* Set errno and return. */ + if (saved_errno != 0) { + /* Free up the stream pointer. */ + free(sp); + __set_errno (saved_errno); + return (-1); + } + } + + /* Free up the stream pointer. */ + free(sp); + return (0); +} + +/* + * Special case of "/" at the end of the path so that slashes aren't + * appended which would cause paths to be written as "....//foo". + */ +#define NAPPEND(p) \ + (p->fts_path[p->fts_pathlen - 1] == '/' \ + ? p->fts_pathlen - 1 : p->fts_pathlen) + +FTSENT * +fts_read(sp) + register FTS *sp; +{ + register FTSENT *p, *tmp; + register int instr; + register char *t; + int saved_errno; + + /* If finished or unrecoverable error, return NULL. */ + if (sp->fts_cur == NULL || ISSET(FTS_STOP)) + return (NULL); + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* Save and zero out user instructions. */ + instr = p->fts_instr; + p->fts_instr = FTS_NOINSTR; + + /* Any type of file may be re-visited; re-stat and re-turn. */ + if (instr == FTS_AGAIN) { + p->fts_info = fts_stat(sp, p, 0); + return (p); + } + + /* + * Following a symlink -- SLNONE test allows application to see + * SLNONE and recover. If indirecting through a symlink, have + * keep a pointer to current location. If unable to get that + * pointer, follow fails. + */ + if (instr == FTS_FOLLOW && + (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { + p->fts_info = fts_stat(sp, p, 1); + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { + if ((p->fts_symfd = open(".", O_RDONLY, 0)) < 0) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + } else + p->fts_flags |= FTS_SYMFOLLOW; + } + return (p); + } + + /* Directory in pre-order. */ + if (p->fts_info == FTS_D) { + /* If skipped or crossed mount point, do post-order visit. */ + if (instr == FTS_SKIP || + (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { + if (p->fts_flags & FTS_SYMFOLLOW) + (void)close(p->fts_symfd); + if (sp->fts_child) { + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + p->fts_info = FTS_DP; + return (p); + } + + /* Rebuild if only read the names and now traversing. */ + if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) { + CLR(FTS_NAMEONLY); + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + + /* + * Cd to the subdirectory. + * + * If have already read and now fail to chdir, whack the list + * to make the names come out right, and set the parent errno + * so the application will eventually get an error condition. + * Set the FTS_DONTCHDIR flag so that when we logically change + * directories back to the parent we don't do a chdir. + * + * If haven't read do so. If the read fails, fts_build sets + * FTS_STOP or the fts_info field of the node. + */ + if (sp->fts_child != NULL) { + if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) { + p->fts_errno = errno; + p->fts_flags |= FTS_DONTCHDIR; + for (p = sp->fts_child; p != NULL; + p = p->fts_link) + p->fts_accpath = + p->fts_parent->fts_accpath; + } + } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) { + if (ISSET(FTS_STOP)) + return (NULL); + return (p); + } + p = sp->fts_child; + sp->fts_child = NULL; + sp->fts_cur = p; + goto name; + } + + /* Move to the next node on this level. */ +next: tmp = p; + if ((p = p->fts_link) != NULL) { + sp->fts_cur = p; + free(tmp); + + /* + * If reached the top, return to the original directory (or + * the root of the tree), and load the paths for the next root. + */ + if (p->fts_level == FTS_ROOTLEVEL) { + if (FCHDIR(sp, sp->fts_rfd)) { + SET(FTS_STOP); + return (NULL); + } + fts_load(sp, p); + return p; + } + + /* + * User may have called fts_set on the node. If skipped, + * ignore. If followed, get a file descriptor so we can + * get back if necessary. + */ + if (p->fts_instr == FTS_SKIP) + goto next; + if (p->fts_instr == FTS_FOLLOW) { + p->fts_info = fts_stat(sp, p, 1); + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { + if ((p->fts_symfd = + open(".", O_RDONLY, 0)) < 0) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + } else + p->fts_flags |= FTS_SYMFOLLOW; + } + p->fts_instr = FTS_NOINSTR; + } + +name: t = sp->fts_path + NAPPEND(p->fts_parent); + *t++ = '/'; + memmove(t, p->fts_name, p->fts_namelen + 1); + return p; + } + + /* Move up to the parent node. */ + p = tmp->fts_parent; + sp->fts_cur = p; + free(tmp); + + if (p->fts_level == FTS_ROOTPARENTLEVEL) { + /* + * Done; free everything up and set errno to 0 so the user + * can distinguish between error and EOF. + */ + free(p); + __set_errno (0); + return (sp->fts_cur = NULL); + } + + /* NUL terminate the pathname. */ + sp->fts_path[p->fts_pathlen] = '\0'; + + /* + * Return to the parent directory. If at a root node or came through + * a symlink, go back through the file descriptor. Otherwise, cd up + * one directory. + */ + if (p->fts_level == FTS_ROOTLEVEL) { + if (FCHDIR(sp, sp->fts_rfd)) { + SET(FTS_STOP); + return (NULL); + } + } else if (p->fts_flags & FTS_SYMFOLLOW) { + if (FCHDIR(sp, p->fts_symfd)) { + saved_errno = errno; + (void)close(p->fts_symfd); + __set_errno (saved_errno); + SET(FTS_STOP); + return (NULL); + } + (void)close(p->fts_symfd); + } else if (!(p->fts_flags & FTS_DONTCHDIR) && + fts_safe_changedir(sp, p->fts_parent, -1, "..")) { + SET(FTS_STOP); + return (NULL); + } + p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; + return p; +} + +/* + * Fts_set takes the stream as an argument although it's not used in this + * implementation; it would be necessary if anyone wanted to add global + * semantics to fts using fts_set. An error return is allowed for similar + * reasons. + */ +/* ARGSUSED */ +int +fts_set(sp, p, instr) + FTS *sp; + FTSENT *p; + int instr; +{ + if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW && + instr != FTS_NOINSTR && instr != FTS_SKIP) { + __set_errno (EINVAL); + return (1); + } + p->fts_instr = instr; + return (0); +} + +FTSENT * +fts_children(sp, instr) + register FTS *sp; + int instr; +{ + register FTSENT *p; + int fd; + + if (instr != 0 && instr != FTS_NAMEONLY) { + __set_errno (EINVAL); + return (NULL); + } + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* + * Errno set to 0 so user can distinguish empty directory from + * an error. + */ + __set_errno (0); + + /* Fatal errors stop here. */ + if (ISSET(FTS_STOP)) + return (NULL); + + /* Return logical hierarchy of user's arguments. */ + if (p->fts_info == FTS_INIT) + return (p->fts_link); + + /* + * If not a directory being visited in pre-order, stop here. Could + * allow FTS_DNR, assuming the user has fixed the problem, but the + * same effect is available with FTS_AGAIN. + */ + if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */) + return (NULL); + + /* Free up any previous child list. */ + if (sp->fts_child != NULL) + fts_lfree(sp->fts_child); + + if (instr == FTS_NAMEONLY) { + SET(FTS_NAMEONLY); + instr = BNAMES; + } else + instr = BCHILD; + + /* + * If using chdir on a relative path and called BEFORE fts_read does + * its chdir to the root of a traversal, we can lose -- we need to + * chdir into the subdirectory, and we don't know where the current + * directory is, so we can't get back so that the upcoming chdir by + * fts_read will work. + */ + if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' || + ISSET(FTS_NOCHDIR)) + return (sp->fts_child = fts_build(sp, instr)); + + if ((fd = open(".", O_RDONLY, 0)) < 0) + return (NULL); + sp->fts_child = fts_build(sp, instr); + if (fchdir(fd)) + return (NULL); + (void)close(fd); + return (sp->fts_child); +} + +/* + * This is the tricky part -- do not casually change *anything* in here. The + * idea is to build the linked list of entries that are used by fts_children + * and fts_read. There are lots of special cases. + * + * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is + * set and it's a physical walk (so that symbolic links can't be directories), + * we can do things quickly. First, if it's a 4.4BSD file system, the type + * of the file is in the directory entry. Otherwise, we assume that the number + * of subdirectories in a node is equal to the number of links to the parent. + * The former skips all stat calls. The latter skips stat calls in any leaf + * directories and for any files after the subdirectories in the directory have + * been found, cutting the stat calls by about 2/3. + */ +static FTSENT * +internal_function +fts_build(sp, type) + register FTS *sp; + int type; +{ + register struct dirent *dp; + register FTSENT *p, *head; + register int nitems; + FTSENT *cur, *tail; + DIR *dirp; + void *oldaddr; + int cderrno, descend, len, level, nlinks, saved_errno, + nostat, doadjust; + size_t maxlen; + char *cp; + + /* Set current node pointer. */ + cur = sp->fts_cur; + + /* + * Open the directory for reading. If this fails, we're done. + * If being called from fts_read, set the fts_info field. + */ +#if defined FTS_WHITEOUT && 0 + if (ISSET(FTS_WHITEOUT)) + oflag = DTF_NODUP|DTF_REWIND; + else + oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND; +#else +# define opendir2(path, flag) opendir(path) +#endif + if ((dirp = opendir2(cur->fts_accpath, oflag)) == NULL) { + if (type == BREAD) { + cur->fts_info = FTS_DNR; + cur->fts_errno = errno; + } + return (NULL); + } + + /* + * Nlinks is the number of possible entries of type directory in the + * directory if we're cheating on stat calls, 0 if we're not doing + * any stat calls at all, -1 if we're doing stats on everything. + */ + if (type == BNAMES) { + nlinks = 0; + /* Be quiet about nostat, GCC. */ + nostat = 0; + } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) { + nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); + nostat = 1; + } else { + nlinks = -1; + nostat = 0; + } + +#ifdef notdef + (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink); + (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n", + ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT)); +#endif + /* + * If we're going to need to stat anything or we want to descend + * and stay in the directory, chdir. If this fails we keep going, + * but set a flag so we don't chdir after the post-order visit. + * We won't be able to stat anything, but we can still return the + * names themselves. Note, that since fts_read won't be able to + * chdir into the directory, it will have to return different path + * names than before, i.e. "a/b" instead of "b". Since the node + * has already been visited in pre-order, have to wait until the + * post-order visit to return the error. There is a special case + * here, if there was nothing to stat then it's not an error to + * not be able to stat. This is all fairly nasty. If a program + * needed sorted entries or stat information, they had better be + * checking FTS_NS on the returned nodes. + */ + cderrno = 0; + if (nlinks || type == BREAD) { + if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) { + if (nlinks && type == BREAD) + cur->fts_errno = errno; + cur->fts_flags |= FTS_DONTCHDIR; + descend = 0; + cderrno = errno; + (void)closedir(dirp); + dirp = NULL; + } else + descend = 1; + } else + descend = 0; + + /* + * Figure out the max file name length that can be stored in the + * current path -- the inner loop allocates more path as necessary. + * We really wouldn't have to do the maxlen calculations here, we + * could do them in fts_read before returning the path, but it's a + * lot easier here since the length is part of the dirent structure. + * + * If not changing directories set a pointer so that can just append + * each new name into the path. + */ + len = NAPPEND(cur); + if (ISSET(FTS_NOCHDIR)) { + cp = sp->fts_path + len; + *cp++ = '/'; + } else { + /* GCC, you're too verbose. */ + cp = NULL; + } + len++; + maxlen = sp->fts_pathlen - len; + + level = cur->fts_level + 1; + + /* Read the directory, attaching each entry to the `link' pointer. */ + doadjust = 0; + for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) { + if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) + continue; + + if ((p = fts_alloc(sp, dp->d_name, _D_EXACT_NAMLEN (dp))) == NULL) + goto mem1; + if (_D_EXACT_NAMLEN (dp) >= maxlen) {/* include space for NUL */ + oldaddr = sp->fts_path; + if (fts_palloc(sp, _D_EXACT_NAMLEN (dp) + len + 1)) { + /* + * No more memory for path or structures. Save + * errno, free up the current structure and the + * structures already allocated. + */ +mem1: saved_errno = errno; + free(p); + fts_lfree(head); + (void)closedir(dirp); + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + __set_errno (saved_errno); + return (NULL); + } + /* Did realloc() change the pointer? */ + if (oldaddr != sp->fts_path) { + doadjust = 1; + if (ISSET(FTS_NOCHDIR)) + cp = sp->fts_path + len; + } + maxlen = sp->fts_pathlen - len; + } + + if (len + _D_EXACT_NAMLEN (dp) >= USHRT_MAX) { + /* + * In an FTSENT, fts_pathlen is a u_short so it is + * possible to wraparound here. If we do, free up + * the current structure and the structures already + * allocated, then error out with ENAMETOOLONG. + */ + free(p); + fts_lfree(head); + (void)closedir(dirp); + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + __set_errno (ENAMETOOLONG); + return (NULL); + } + p->fts_level = level; + p->fts_parent = sp->fts_cur; + p->fts_pathlen = len + _D_EXACT_NAMLEN (dp); + +#if defined FTS_WHITEOUT && 0 + if (dp->d_type == DT_WHT) + p->fts_flags |= FTS_ISW; +#endif + +#if 0 + /* Unreachable code. cderrno is only ever set to a nonnull + value if dirp is closed at the same time. But then we + cannot enter this loop. */ + if (cderrno) { + if (nlinks) { + p->fts_info = FTS_NS; + p->fts_errno = cderrno; + } else + p->fts_info = FTS_NSOK; + p->fts_accpath = cur->fts_accpath; + } else +#endif + if (nlinks == 0 +#if defined DT_DIR && defined _DIRENT_HAVE_D_TYPE + || (nostat && + dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN) +#endif + ) { + p->fts_accpath = + ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name; + p->fts_info = FTS_NSOK; + } else { + /* Build a file name for fts_stat to stat. */ + if (ISSET(FTS_NOCHDIR)) { + p->fts_accpath = p->fts_path; + memmove(cp, p->fts_name, p->fts_namelen + 1); + } else + p->fts_accpath = p->fts_name; + /* Stat it. */ + p->fts_info = fts_stat(sp, p, 0); + + /* Decrement link count if applicable. */ + if (nlinks > 0 && (p->fts_info == FTS_D || + p->fts_info == FTS_DC || p->fts_info == FTS_DOT)) + --nlinks; + } + + /* We walk in directory order so "ls -f" doesn't get upset. */ + p->fts_link = NULL; + if (head == NULL) + head = tail = p; + else { + tail->fts_link = p; + tail = p; + } + ++nitems; + } + if (dirp) + (void)closedir(dirp); + + /* + * If realloc() changed the address of the path, adjust the + * addresses for the rest of the tree and the dir list. + */ + if (doadjust) + fts_padjust(sp, head); + + /* + * If not changing directories, reset the path back to original + * state. + */ + if (ISSET(FTS_NOCHDIR)) { + if (len == sp->fts_pathlen || nitems == 0) + --cp; + *cp = '\0'; + } + + /* + * If descended after called from fts_children or after called from + * fts_read and nothing found, get back. At the root level we use + * the saved fd; if one of fts_open()'s arguments is a relative path + * to an empty directory, we wind up here with no other way back. If + * can't get back, we're done. + */ + if (descend && (type == BCHILD || !nitems) && + (cur->fts_level == FTS_ROOTLEVEL ? + FCHDIR(sp, sp->fts_rfd) : + fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) { + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + fts_lfree(head); + return (NULL); + } + + /* If didn't find anything, return NULL. */ + if (!nitems) { + if (type == BREAD) + cur->fts_info = FTS_DP; + fts_lfree(head); + return (NULL); + } + + /* Sort the entries. */ + if (sp->fts_compar && nitems > 1) + head = fts_sort(sp, head, nitems); + return (head); +} + +static u_short +internal_function +fts_stat(sp, p, follow) + FTS *sp; + register FTSENT *p; + int follow; +{ + register FTSENT *t; + register dev_t dev; + register ino_t ino; + struct stat *sbp, sb; + int saved_errno; + + /* If user needs stat info, stat buffer already allocated. */ + sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp; + +#if defined FTS_WHITEOUT && 0 + /* check for whiteout */ + if (p->fts_flags & FTS_ISW) { + if (sbp != &sb) { + memset(sbp, '\0', sizeof (*sbp)); + sbp->st_mode = S_IFWHT; + } + return (FTS_W); + } +#endif + + /* + * If doing a logical walk, or application requested FTS_FOLLOW, do + * a stat(2). If that fails, check for a non-existent symlink. If + * fail, set the errno from the stat call. + */ + if (ISSET(FTS_LOGICAL) || follow) { + if (stat(p->fts_accpath, sbp)) { + saved_errno = errno; + if (!lstat(p->fts_accpath, sbp)) { + __set_errno (0); + return (FTS_SLNONE); + } + p->fts_errno = saved_errno; + goto err; + } + } else if (lstat(p->fts_accpath, sbp)) { + p->fts_errno = errno; +err: memset(sbp, 0, sizeof(struct stat)); + return (FTS_NS); + } + + if (S_ISDIR(sbp->st_mode)) { + /* + * Set the device/inode. Used to find cycles and check for + * crossing mount points. Also remember the link count, used + * in fts_build to limit the number of stat calls. It is + * understood that these fields are only referenced if fts_info + * is set to FTS_D. + */ + dev = p->fts_dev = sbp->st_dev; + ino = p->fts_ino = sbp->st_ino; + p->fts_nlink = sbp->st_nlink; + + if (ISDOT(p->fts_name)) + return (FTS_DOT); + + /* + * Cycle detection is done by brute force when the directory + * is first encountered. If the tree gets deep enough or the + * number of symbolic links to directories is high enough, + * something faster might be worthwhile. + */ + for (t = p->fts_parent; + t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) + if (ino == t->fts_ino && dev == t->fts_dev) { + p->fts_cycle = t; + return (FTS_DC); + } + return (FTS_D); + } + if (S_ISLNK(sbp->st_mode)) + return (FTS_SL); + if (S_ISREG(sbp->st_mode)) + return (FTS_F); + return (FTS_DEFAULT); +} + +static FTSENT * +internal_function +fts_sort(sp, head, nitems) + FTS *sp; + FTSENT *head; + register int nitems; +{ + register FTSENT **ap, *p; + + /* + * Construct an array of pointers to the structures and call qsort(3). + * Reassemble the array in the order returned by qsort. If unable to + * sort for memory reasons, return the directory entries in their + * current order. Allocate enough space for the current needs plus + * 40 so don't realloc one entry at a time. + */ + if (nitems > sp->fts_nitems) { + struct _ftsent **a; + + sp->fts_nitems = nitems + 40; + if ((a = realloc(sp->fts_array, + (size_t)(sp->fts_nitems * sizeof(FTSENT *)))) == NULL) { + free(sp->fts_array); + sp->fts_array = NULL; + sp->fts_nitems = 0; + return (head); + } + sp->fts_array = a; + } + for (ap = sp->fts_array, p = head; p; p = p->fts_link) + *ap++ = p; + qsort((void *)sp->fts_array, nitems, sizeof(FTSENT *), sp->fts_compar); + for (head = *(ap = sp->fts_array); --nitems; ++ap) + ap[0]->fts_link = ap[1]; + ap[0]->fts_link = NULL; + return (head); +} + +static FTSENT * +internal_function +fts_alloc(sp, name, namelen) + FTS *sp; + const char *name; + size_t namelen; +{ + register FTSENT *p; + size_t len; + + /* + * The file name is a variable length array and no stat structure is + * necessary if the user has set the nostat bit. Allocate the FTSENT + * structure, the file name and the stat structure in one chunk, but + * be careful that the stat structure is reasonably aligned. Since the + * fts_name field is declared to be of size 1, the fts_name pointer is + * namelen + 2 before the first possible address of the stat structure. + */ + len = sizeof(FTSENT) + namelen; + if (!ISSET(FTS_NOSTAT)) + len += sizeof(struct stat) + ALIGNBYTES; + if ((p = malloc(len)) == NULL) + return (NULL); + + /* Copy the name and guarantee NUL termination. */ + memmove(p->fts_name, name, namelen); + p->fts_name[namelen] = '\0'; + + if (!ISSET(FTS_NOSTAT)) + p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2); + p->fts_namelen = namelen; + p->fts_path = sp->fts_path; + p->fts_errno = 0; + p->fts_flags = 0; + p->fts_instr = FTS_NOINSTR; + p->fts_number = 0; + p->fts_pointer = NULL; + return (p); +} + +static void +internal_function +fts_lfree(head) + register FTSENT *head; +{ + register FTSENT *p; + + /* Free a linked list of structures. */ + while ((p = head)) { + head = head->fts_link; + free(p); + } +} + +/* + * Allow essentially unlimited paths; find, rm, ls should all work on any tree. + * Most systems will allow creation of paths much longer than MAXPATHLEN, even + * though the kernel won't resolve them. Add the size (not just what's needed) + * plus 256 bytes so don't realloc the path 2 bytes at a time. + */ +static int +internal_function +fts_palloc(sp, more) + FTS *sp; + size_t more; +{ + char *p; + + sp->fts_pathlen += more + 256; + /* + * Check for possible wraparound. In an FTS, fts_pathlen is + * a signed int but in an FTSENT it is an unsigned short. + * We limit fts_pathlen to USHRT_MAX to be safe in both cases. + */ + if (sp->fts_pathlen < 0 || sp->fts_pathlen >= USHRT_MAX) { + free(sp->fts_path); + sp->fts_path = NULL; + __set_errno (ENAMETOOLONG); + return (1); + } + p = realloc(sp->fts_path, sp->fts_pathlen); + if (p == NULL) { + free(sp->fts_path); + sp->fts_path = NULL; + return 1; + } + sp->fts_path = p; + return 0; +} + +/* + * When the path is realloc'd, have to fix all of the pointers in structures + * already returned. + */ +static void +internal_function +fts_padjust(sp, head) + FTS *sp; + FTSENT *head; +{ + FTSENT *p; + char *addr = sp->fts_path; + +#define ADJUST(p) do { \ + if ((p)->fts_accpath != (p)->fts_name) { \ + (p)->fts_accpath = \ + (char *)addr + ((p)->fts_accpath - (p)->fts_path); \ + } \ + (p)->fts_path = addr; \ +} while (0) + /* Adjust the current set of children. */ + for (p = sp->fts_child; p; p = p->fts_link) + ADJUST(p); + + /* Adjust the rest of the tree, including the current level. */ + for (p = head; p->fts_level >= FTS_ROOTLEVEL;) { + ADJUST(p); + p = p->fts_link ? p->fts_link : p->fts_parent; + } +} + +static size_t +internal_function +fts_maxarglen(argv) + char * const *argv; +{ + size_t len, max; + + for (max = 0; *argv; ++argv) + if ((len = strlen(*argv)) > max) + max = len; + return (max + 1); +} + +/* + * Change to dir specified by fd or p->fts_accpath without getting + * tricked by someone changing the world out from underneath us. + * Assumes p->fts_dev and p->fts_ino are filled in. + */ +static int +internal_function +fts_safe_changedir(sp, p, fd, path) + FTS *sp; + FTSENT *p; + int fd; + const char *path; +{ + int ret, oerrno, newfd; + struct stat64 sb; + + newfd = fd; + if (ISSET(FTS_NOCHDIR)) + return (0); + if (fd < 0 && (newfd = open(path, O_RDONLY, 0)) < 0) + return (-1); + if (fstat64(newfd, &sb)) { + ret = -1; + goto bail; + } + if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) { + __set_errno (ENOENT); /* disinformation */ + ret = -1; + goto bail; + } + ret = fchdir(newfd); +bail: + oerrno = errno; + if (fd < 0) + (void)close(newfd); + __set_errno (oerrno); + return (ret); +} diff -Nur uClibc-0.9.32-rc3/libc/misc/fts/Makefile uClibc/libc/misc/fts/Makefile --- uClibc-0.9.32-rc3/libc/misc/fts/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ uClibc/libc/misc/fts/Makefile 2011-04-26 16:18:21.777663244 +0200 @@ -0,0 +1,14 @@ +# Makefile for uClibc +# +# Copyright (C) 2009 STMicroelectronics Ltd. +# Author: Salvatore Cro +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +top_srcdir=../../../ +top_builddir=../../../ +all: objs +include $(top_builddir)Rules.mak +include Makefile.in +include $(top_srcdir)Makerules diff -Nur uClibc-0.9.32-rc3/libc/misc/fts/Makefile.in uClibc/libc/misc/fts/Makefile.in --- uClibc-0.9.32-rc3/libc/misc/fts/Makefile.in 1970-01-01 01:00:00.000000000 +0100 +++ uClibc/libc/misc/fts/Makefile.in 2011-04-26 16:18:21.777663244 +0200 @@ -0,0 +1,23 @@ +# FTS Makefile for uClibc +# +# Copyright (C) 2009 STMicroelectronics Ltd. +# Author: Salvatore Cro +# +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +# + +subdirs += libc/misc/fts +CSRC := fts.c + +MISC_FTS_DIR := $(top_srcdir)libc/misc/fts +MISC_FTS_OUT := $(top_builddir)libc/misc/fts + +MISC_FTS_SRC := $(patsubst %.c,$(MISC_FTS_DIR)/%.c,$(CSRC)) +MISC_FTS_OBJ := $(patsubst %.c,$(MISC_FTS_OUT)/%.o,$(CSRC)) + +libc-$(UCLIBC_HAS_FTS) += $(MISC_FTS_OBJ) + +objclean-y += CLEAN_libc/misc/fts + +CLEAN_libc/misc/fts: + $(do_rm) $(addprefix $(MISC_FTS_OUT)/*., o os) diff -Nur uClibc-0.9.32-rc3/libc/misc/Makefile.in uClibc/libc/misc/Makefile.in --- uClibc-0.9.32-rc3/libc/misc/Makefile.in 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/libc/misc/Makefile.in 2011-04-26 16:18:21.767661585 +0200 @@ -16,6 +16,7 @@ include $(top_srcdir)libc/misc/file/Makefile.in include $(top_srcdir)libc/misc/fnmatch/Makefile.in include $(top_srcdir)libc/misc/ftw/Makefile.in +include $(top_srcdir)libc/misc/fts/Makefile.in include $(top_srcdir)libc/misc/glob/Makefile.in include $(top_srcdir)libc/misc/gnu/Makefile.in include $(top_srcdir)libc/misc/internals/Makefile.in diff -Nur uClibc-0.9.32-rc3/libc/stdlib/malloc/heap.h uClibc/libc/stdlib/malloc/heap.h --- uClibc-0.9.32-rc3/libc/stdlib/malloc/heap.h 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/libc/stdlib/malloc/heap.h 2011-04-26 16:18:21.888707940 +0200 @@ -29,8 +29,10 @@ /* The heap allocates in multiples of, and aligned to, HEAP_GRANULARITY. HEAP_GRANULARITY must be a power of 2. Malloc depends on this being the same as MALLOC_ALIGNMENT. */ -#define HEAP_GRANULARITY_TYPE double __attribute_aligned__ (sizeof (size_t)) -#define HEAP_GRANULARITY (__alignof__ (HEAP_GRANULARITY_TYPE)) +#define HEAP_GRANULARITY_TYPE double __attribute_aligned__ (HEAP_GRANULARITY) +#define HEAP_GRANULARITY \ + (__alignof__ (double) > sizeof (size_t) ? __alignof__ (double) : sizeof (size_t)) + /* The HEAP_INIT macro can be used as a static initializer for a heap diff -Nur uClibc-0.9.32-rc3/libc/stdlib/malloc/malloc.h uClibc/libc/stdlib/malloc/malloc.h --- uClibc-0.9.32-rc3/libc/stdlib/malloc/malloc.h 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/libc/stdlib/malloc/malloc.h 2011-04-26 16:18:21.888707940 +0200 @@ -17,7 +17,7 @@ alignment can be a significant win on targets like m68k and Coldfire, where __alignof__(double) == 2. */ #define MALLOC_ALIGNMENT \ - __alignof__ (double __attribute_aligned__ (sizeof (size_t))) + (__alignof__ (double) > sizeof (size_t) ? __alignof__ (double) : sizeof (size_t)) /* The system pagesize... */ extern size_t __pagesize; diff -Nur uClibc-0.9.32-rc3/libc/sysdeps/linux/common/lutimes.c uClibc/libc/sysdeps/linux/common/lutimes.c --- uClibc-0.9.32-rc3/libc/sysdeps/linux/common/lutimes.c 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/libc/sysdeps/linux/common/lutimes.c 2011-04-26 16:18:22.008914246 +0200 @@ -12,7 +12,7 @@ #ifdef __NR_lutimes _syscall2(int, lutimes, const char *, file, const struct timeval *, tvp) -#else +#elif defined __NR_utimensat #include #include diff -Nur uClibc-0.9.32-rc3/libc/sysdeps/linux/common/Makefile.in uClibc/libc/sysdeps/linux/common/Makefile.in --- uClibc-0.9.32-rc3/libc/sysdeps/linux/common/Makefile.in 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/libc/sysdeps/linux/common/Makefile.in 2011-04-26 16:18:21.927829410 +0200 @@ -15,7 +15,9 @@ CSRC-y := $(filter-out llseek.c $(CSRC_LFS),$(CSRC-y)) CSRC-$(UCLIBC_HAS_LFS) += llseek.c $(CSRC_LFS) -CSRC-$(if $(or $(UCLIBC_HAS_SSP),$(UCLIBC_HAS_FORTIFY)),y) += ssp.c +ifneq ($(UCLIBC_HAS_SSP)$(UCLIBC_HAS_FORTIFY),) +CSRC-y += ssp.c +endif CSRC-$(UCLIBC_LINUX_MODULE_24) += create_module.c query_module.c \ get_kernel_syms.c # we need these internally: fstatfs.c statfs.c @@ -25,7 +27,9 @@ sendfile64.c sendfile.c setfsgid.c setfsuid.c setresuid.c \ splice.c vmsplice.c tee.c signalfd.c swapoff.c swapon.c \ sync_file_range.c sysctl.c sysinfo.c timerfd.c uselib.c vhangup.c -CSRC-$(if $(and $(UCLIBC_LINUX_SPECIFIC),$(UCLIBC_HAS_THREADS_NATIVE)),y) += madvise.c +ifeq ($(UCLIBC_LINUX_SPECIFIC)$(UCLIBC_HAS_THREADS_NATIVE),yy) +CSRC-y += madvise.c +endif ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y) CSRC- += fork.c getpid.c raise.c open.c close.c read.c write.c CSRC- += $(if $(findstring =arm=,=$(TARGET_ARCH)=),vfork.c) diff -Nur uClibc-0.9.32-rc3/libc/sysdeps/linux/common/stubs.c uClibc/libc/sysdeps/linux/common/stubs.c --- uClibc-0.9.32-rc3/libc/sysdeps/linux/common/stubs.c 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/libc/sysdeps/linux/common/stubs.c 2011-04-26 16:18:22.038918529 +0200 @@ -172,6 +172,14 @@ make_stub(umount2) #endif +#ifndef __NR_utimensat +make_stub(futimens) +make_stub(utimensat) +# ifndef __NR_lutimes +make_stub(lutimes) +# endif +#endif + #ifndef __NR_vmsplice make_stub(vmsplice) #endif diff -Nur uClibc-0.9.32-rc3/libc/sysdeps/linux/cris/Makefile.arch uClibc/libc/sysdeps/linux/cris/Makefile.arch --- uClibc-0.9.32-rc3/libc/sysdeps/linux/cris/Makefile.arch 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/libc/sysdeps/linux/cris/Makefile.arch 2011-04-26 16:18:22.048914220 +0200 @@ -7,7 +7,7 @@ CSRC := __init_brk.c brk.c sbrk.c -SSRC := setjmp.S __longjmp.S clone.S sysdep.S syscall.S +SSRC := setjmp.S __longjmp.S clone.S sysdep.S syscall.S vfork.S ifeq ($(UNIFIED_SYSCALL),y) SSRC += __uClibc_syscall.S endif diff -Nur uClibc-0.9.32-rc3/libc/sysdeps/linux/cris/vfork.S uClibc/libc/sysdeps/linux/cris/vfork.S --- uClibc-0.9.32-rc3/libc/sysdeps/linux/cris/vfork.S 1970-01-01 01:00:00.000000000 +0100 +++ uClibc/libc/sysdeps/linux/cris/vfork.S 2011-04-26 16:18:22.058385770 +0200 @@ -0,0 +1,30 @@ +/*- + * Copyright (c) 2011 + * Thorsten Glaser + * + * This file is available either under the terms and conditions of + * the MirOS Licence, or the same terms as klibc or uClibc. + */ + +#include "sysdep.h" + + .syntax no_register_prefix + +/* + * vfork is special, but PSEUDO() would probably work were it not broken; + * there must be nothing at all on the stack above the stack frame of the + * enclosing function + */ + +ENTRY(__vfork) + movu.w __NR_vfork,$r9 + break 13 + cmps.w -4096,$r10 + bhs 0f + nop + Ret + nop +PSEUDO_END(__vfork) + +weak_alias(__vfork,vfork) +libc_hidden_weak(vfork) diff -Nur uClibc-0.9.32-rc3/libc/sysdeps/linux/Makefile.commonarch uClibc/libc/sysdeps/linux/Makefile.commonarch --- uClibc-0.9.32-rc3/libc/sysdeps/linux/Makefile.commonarch 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/libc/sysdeps/linux/Makefile.commonarch 2011-04-26 16:18:21.917874257 +0200 @@ -36,6 +36,6 @@ headers-y += $(ARCH_HEADERS_OUT) headers_clean-y += HEADERCLEAN_$(subst $(top_builddir),,$(ARCH_OUT)) HEADERCLEAN_$(subst $(top_builddir),,$(ARCH_OUT)): - $(RM) $(ARCH_HEADERS_OUT) + $(do_rm) $(ARCH_HEADERS_OUT) endif diff -Nur uClibc-0.9.32-rc3/libc/sysdeps/linux/sparc/soft-fp/sfp-machine.h uClibc/libc/sysdeps/linux/sparc/soft-fp/sfp-machine.h --- uClibc-0.9.32-rc3/libc/sysdeps/linux/sparc/soft-fp/sfp-machine.h 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/libc/sysdeps/linux/sparc/soft-fp/sfp-machine.h 2011-04-26 16:18:22.198914568 +0200 @@ -187,6 +187,7 @@ #define _FP_DECL_EX fpu_control_t _fcw +#ifdef __UCLIBC_HAS_FPU__ #define FP_INIT_ROUNDMODE \ do { \ _FPU_GETCW(_fcw); \ @@ -211,3 +212,4 @@ else \ ___Q_simulate_exceptions (_fex); \ } while (0) +#endif diff -Nur uClibc-0.9.32-rc3/libubacktrace/backtrace.c uClibc/libubacktrace/backtrace.c --- uClibc-0.9.32-rc3/libubacktrace/backtrace.c 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/libubacktrace/backtrace.c 2011-04-26 16:18:22.608067667 +0200 @@ -4,16 +4,81 @@ * User application that wants to use backtrace needs to be * compiled with -fexceptions option and -rdynamic to get full * symbols printed. - - * Copyright (C) 2010 STMicroelectronics Ltd + * + * Copyright (C) 2009, 2010 STMicroelectronics Ltd. + * + * Author(s): Giuseppe Cavallaro + * - Initial implementation for glibc + * * Author(s): Carmelo Amoroso + * - Reworked for uClibc + * - use dlsym/dlopen from libdl + * - rewrite initialisation to not use libc_once + * - make it available in static link too * * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. * */ -#error "Arch specific implementation must be provided to properly work" -int backtrace (void **array, int size) + +#include +#include +#include +#include +#include +#include + +struct trace_arg { - return -1; + void **array; + int cnt, size; +}; + +static _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *); +static _Unwind_Ptr (*unwind_getip) (struct _Unwind_Context *); + +static void backtrace_init (void) +{ + void *handle = dlopen ("libgcc_s.so.1", RTLD_LAZY); + + if (handle == NULL + || ((unwind_backtrace = dlsym (handle, "_Unwind_Backtrace")) == NULL) + || ((unwind_getip = dlsym (handle, "_Unwind_GetIP")) == NULL)) { + printf("libgcc_s.so.1 must be installed for backtrace to work\n"); + abort(); + } } +static _Unwind_Reason_Code +backtrace_helper (struct _Unwind_Context *ctx, void *a) +{ + struct trace_arg *arg = a; + + assert (unwind_getip != NULL); + + /* We are first called with address in the __backtrace function. Skip it. */ + if (arg->cnt != -1) + arg->array[arg->cnt] = (void *) unwind_getip (ctx); + if (++arg->cnt == arg->size) + return _URC_END_OF_STACK; + return _URC_NO_REASON; +} + +/* + * Perform stack unwinding by using the _Unwind_Backtrace. + * + * User application that wants to use backtrace needs to be + * compiled with -fexceptions option and -rdynamic to get full + * symbols printed. + */ +int backtrace (void **array, int size) +{ + struct trace_arg arg = { .array = array, .size = size, .cnt = -1 }; + + if (unwind_backtrace == NULL) + backtrace_init(); + + if (size >= 1) + unwind_backtrace (backtrace_helper, &arg); + + return arg.cnt != -1 ? arg.cnt : 0; +} diff -Nur uClibc-0.9.32-rc3/libubacktrace/Makefile.in uClibc/libubacktrace/Makefile.in --- uClibc-0.9.32-rc3/libubacktrace/Makefile.in 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/libubacktrace/Makefile.in 2011-04-26 16:18:22.608067667 +0200 @@ -18,29 +18,16 @@ libubacktrace_DIR := $(top_srcdir)libubacktrace libubacktrace_OUT := $(top_builddir)libubacktrace -libubacktrace_ARCH_DIR := $(libubacktrace_DIR)/sysdeps/$(TARGET_ARCH) -libubacktrace_ARCH_OUT := $(libubacktrace_OUT)/sysdeps/$(TARGET_ARCH) - --include $(libubacktrace_ARCH_DIR)/Makefile.arch libubacktrace_SRC-y := libubacktrace_SRC-$(UCLIBC_HAS_BACKTRACE) := backtrace.c backtracesyms.c backtracesymsfd.c -CFLAGS-libubacktrace/sysdeps/$(TARGET_ARCH)/ := $(CFLAGS-libubacktrace) - -# remove generic sources, if arch specific version is present -ifneq ($(strip $(libubacktrace_ARCH_SRC-y)),) -libubacktrace_SRC-y := $(filter-out $(notdir $(libubacktrace_ARCH_SRC-y)),$(libubacktrace_SRC-y)) -libubacktrace_ARCH_SRC := $(addprefix $(libubacktrace_ARCH_DIR)/,$(libubacktrace_ARCH_SRC-y)) -libubacktrace_ARCH_OBJ := $(patsubst $(libubacktrace_ARCH_DIR)/%.c,$(libubacktrace_ARCH_OUT)/%.o,$(libubacktrace_ARCH_SRC)) -endif - +# -fexections is required for backtrace to work using dwarf2 +CFLAGS-backtrace.c := -fexceptions -libubacktrace_SRC := $(addprefix $(libubacktrace_DIR)/,$(libubacktrace_SRC-y)) -libubacktrace_OBJ := $(patsubst $(libubacktrace_DIR)/%.c,$(libubacktrace_OUT)/%.o,$(libubacktrace_SRC)) -libubacktrace_SRCS := $(libubacktrace_SRC) $(libubacktrace_ARCH_SRC) -libubacktrace_OBJS := $(libubacktrace_OBJ) $(libubacktrace_ARCH_OBJ) +libubacktrace_SRCS := $(addprefix $(libubacktrace_DIR)/,$(libubacktrace_SRC-y)) +libubacktrace_OBJS := $(patsubst $(libubacktrace_DIR)/%.c,$(libubacktrace_OUT)/%.o,$(libubacktrace_SRCS)) ifeq ($(DOPIC),y) libubacktrace-a-y := $(libubacktrace_OBJS:.o=.os) diff -Nur uClibc-0.9.32-rc3/libubacktrace/sysdeps/sh/backtrace.c uClibc/libubacktrace/sysdeps/sh/backtrace.c --- uClibc-0.9.32-rc3/libubacktrace/sysdeps/sh/backtrace.c 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/libubacktrace/sysdeps/sh/backtrace.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,84 +0,0 @@ -/* - * Perform stack unwinding by using the _Unwind_Backtrace. - * - * User application that wants to use backtrace needs to be - * compiled with -fexceptions option and -rdynamic to get full - * symbols printed. - * - * Copyright (C) 2009, 2010 STMicroelectronics Ltd. - * - * Author(s): Giuseppe Cavallaro - * - Initial implementation for glibc - * - * Author(s): Carmelo Amoroso - * - Reworked for uClibc - * - use dlsym/dlopen from libdl - * - rewrite initialisation to not use libc_once - * - make it available in static link too - * - * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. - * - */ - -#include -#include -#include -#include -#include -#include - -struct trace_arg -{ - void **array; - int cnt, size; -}; - -static _Unwind_Reason_Code (*unwind_backtrace) (_Unwind_Trace_Fn, void *); -static _Unwind_Ptr (*unwind_getip) (struct _Unwind_Context *); - -static void backtrace_init (void) -{ - void *handle = dlopen ("libgcc_s.so.1", RTLD_LAZY); - - if (handle == NULL - || ((unwind_backtrace = dlsym (handle, "_Unwind_Backtrace")) == NULL) - || ((unwind_getip = dlsym (handle, "_Unwind_GetIP")) == NULL)) { - printf("libgcc_s.so.1 must be installed for backtrace to work\n"); - abort(); - } -} - -static _Unwind_Reason_Code -backtrace_helper (struct _Unwind_Context *ctx, void *a) -{ - struct trace_arg *arg = a; - - assert (unwind_getip != NULL); - - /* We are first called with address in the __backtrace function. Skip it. */ - if (arg->cnt != -1) - arg->array[arg->cnt] = (void *) unwind_getip (ctx); - if (++arg->cnt == arg->size) - return _URC_END_OF_STACK; - return _URC_NO_REASON; -} - -/* - * Perform stack unwinding by using the _Unwind_Backtrace. - * - * User application that wants to use backtrace needs to be - * compiled with -fexceptions option and -rdynamic to get full - * symbols printed. - */ -int backtrace (void **array, int size) -{ - struct trace_arg arg = { .array = array, .size = size, .cnt = -1 }; - - if (unwind_backtrace == NULL) - backtrace_init(); - - if (size >= 1) - unwind_backtrace (backtrace_helper, &arg); - - return arg.cnt != -1 ? arg.cnt : 0; -} diff -Nur uClibc-0.9.32-rc3/libubacktrace/sysdeps/sh/Makefile.arch uClibc/libubacktrace/sysdeps/sh/Makefile.arch --- uClibc-0.9.32-rc3/libubacktrace/sysdeps/sh/Makefile.arch 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/libubacktrace/sysdeps/sh/Makefile.arch 1970-01-01 01:00:00.000000000 +0100 @@ -1,12 +0,0 @@ -# Makefile for uClibc (sh/libubacktrace) -# -# Copyright (C) 2010 STMicroelectronics Ltd -# Author: Carmelo Amoroso - -# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. -# - -libubacktrace_ARCH_SRC-y := backtrace.c - -# -fexections is required for backtrace to work using dwarf2 -CFLAGS-backtrace.c := -fexceptions diff -Nur uClibc-0.9.32-rc3/Makefile.in uClibc/Makefile.in --- uClibc-0.9.32-rc3/Makefile.in 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/Makefile.in 2011-04-26 16:18:21.697662740 +0200 @@ -239,6 +239,7 @@ tgmath.h \ bits/math*.h HEADERS_RM-$(findstring y,$(UCLIBC_HAS_FTW)$(UCLIBC_HAS_NFTW)) += ftw.h +HEADERS_RM-$(UCLIBC_HAS_FTS) += fts.h HEADERS_RM-$(UCLIBC_HAS_GETTEXT_AWARENESS) += libintl.h HEADERS_RM-$(UCLIBC_HAS_GLIBC_CUSTOM_PRINTF) += printf.h HEADERS_RM-$(UCLIBC_HAS_GLOB) += glob.h diff -Nur uClibc-0.9.32-rc3/Rules.mak uClibc/Rules.mak --- uClibc-0.9.32-rc3/Rules.mak 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/Rules.mak 2011-04-26 16:18:21.697662740 +0200 @@ -531,7 +531,7 @@ export CC_FLAG_NO_ASNEEDED:=-Wl,$(LD_FLAG_NO_ASNEEDED) endif endif -link.asneeded = $(if $(and $(CC_FLAG_ASNEEDED),$(CC_FLAG_NO_ASNEEDED)),$(CC_FLAG_ASNEEDED) $(1) $(CC_FLAG_NO_ASNEEDED)) +link.asneeded = $(if $(findstring yy,$(CC_FLAG_ASNEEDED)$(CC_FLAG_NO_ASNEEDED)),$(CC_FLAG_ASNEEDED) $(1) $(CC_FLAG_NO_ASNEEDED)) # Check for AS_NEEDED support in linker script (binutils>=2.16.1 has it) ifndef ASNEEDED diff -Nur uClibc-0.9.32-rc3/test/tls/Makefile.in uClibc/test/tls/Makefile.in --- uClibc-0.9.32-rc3/test/tls/Makefile.in 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/test/tls/Makefile.in 2011-04-26 16:18:22.827742938 +0200 @@ -140,7 +140,6 @@ $(LDFLAGS_tst-tlsmod18a.so) tst-tls-at-ctor: tst-tlsmod-at-ctor.so -RET_tst-tls13 := 1 ifeq ($(TARGET_ARCH),mips) RET_tst-tls15 := 1 endif diff -Nur uClibc-0.9.32-rc3/test/tls/tst-tls13.c uClibc/test/tls/tst-tls13.c --- uClibc-0.9.32-rc3/test/tls/tst-tls13.c 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/test/tls/tst-tls13.c 2011-04-26 16:18:22.837818558 +0200 @@ -26,5 +26,5 @@ } #define TEST_FUNCTION do_test () -#define TIMEOUT 3 +#define TIMEOUT 20 #include "../test-skeleton.c" diff -Nur uClibc-0.9.32-rc3/utils/ldd.c uClibc/utils/ldd.c --- uClibc-0.9.32-rc3/utils/ldd.c 2011-03-16 20:11:13.000000000 +0100 +++ uClibc/utils/ldd.c 2011-04-26 16:18:22.888166105 +0200 @@ -553,7 +553,7 @@ interp_name = strdup(s); interp_dir = strdup(s); tmp = strrchr(interp_dir, '/'); - if (*tmp) + if (tmp) *tmp = '\0'; else { free(interp_dir);