diff options
43 files changed, 1816 insertions, 356 deletions
diff --git a/Makefile.in b/Makefile.in index 0c1f414ec..2f8370b0f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -185,6 +185,7 @@ $(top_builddir)include/bits/sysnum.h: $(top_srcdir)extra/scripts/gen_bits_syscal exit 1; \ fi +.PHONY: $(LOCAL_INSTALL_PATH) $(LOCAL_INSTALL_PATH): $(Q)$(MAKE) PREFIX=$(shell pwd)/$(LOCAL_INSTALL_PATH) RUNTIME_PREFIX=/ \ DEVEL_PREFIX=/usr/ \ @@ -239,6 +240,7 @@ HEADERS_RM-$(UCLIBC_HAS_FLOATS) += complex.h fpu_control.h ieee754. 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 @@ -531,7 +531,7 @@ ifdef LD_FLAG_NO_ASNEEDED 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 --git a/extra/Configs/Config.in b/extra/Configs/Config.in index 8cbe31847..843988959 100644 --- a/extra/Configs/Config.in +++ b/extra/Configs/Config.in @@ -1926,6 +1926,18 @@ config UCLIBC_HAS_FTW 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" @@ -2350,7 +2362,7 @@ config UCLIBC_MALLOC_DEBUGGING 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 --git a/include/fts.h b/include/fts.h new file mode 100644 index 000000000..0a070ba8d --- /dev/null +++ b/include/fts.h @@ -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 <features.h> +#include <sys/types.h> + +/* The fts interface is incompatible with the LFS interface which + transparently uses the 64-bit file access functions. */ +#ifdef __USE_FILE_OFFSET64 +# error "<fts.h> 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 --git a/ldso/include/dl-elf.h b/ldso/include/dl-elf.h index 908cb63ce..495bd2bca 100644 --- a/ldso/include/dl-elf.h +++ b/ldso/include/dl-elf.h @@ -222,7 +222,7 @@ unsigned int __dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info 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 --git a/ldso/include/ldso.h b/ldso/include/ldso.h index 9aa610e7b..3152b744a 100644 --- a/ldso/include/ldso.h +++ b/ldso/include/ldso.h @@ -35,6 +35,8 @@ #include <sys/types.h> /* Pull in the arch specific page size */ #include <bits/uClibc_page.h> +/* Pull in the MIN macro */ +#include <sys/param.h> /* Pull in the ldso syscalls and string functions */ #ifndef __ARCH_HAS_NO_SHARED__ #include <dl-syscall.h> diff --git a/ldso/ldso/bfin/dl-inlines.h b/ldso/ldso/bfin/dl-inlines.h index 6524f5edc..969986218 100644 --- a/ldso/ldso/bfin/dl-inlines.h +++ b/ldso/ldso/bfin/dl-inlines.h @@ -88,14 +88,39 @@ __dl_init_loadaddr_hdr (struct elf32_fdpic_loadaddr loadaddr, void *addr, 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 --git a/ldso/ldso/bfin/dl-sysdep.h b/ldso/ldso/bfin/dl-sysdep.h index 50c750990..168e5c89a 100644 --- a/ldso/ldso/bfin/dl-sysdep.h +++ b/ldso/ldso/bfin/dl-sysdep.h @@ -120,6 +120,8 @@ struct funcdesc_ht; #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 --git a/ldso/ldso/c6x/dl-inlines.h b/ldso/ldso/c6x/dl-inlines.h index d8fb42c55..62e1cc9ca 100644 --- a/ldso/ldso/c6x/dl-inlines.h +++ b/ldso/ldso/c6x/dl-inlines.h @@ -74,6 +74,35 @@ __dl_init_loadaddr_hdr (struct elf32_dsbt_loadaddr loadaddr, void *addr, #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 --git a/ldso/ldso/c6x/dl-sysdep.h b/ldso/ldso/c6x/dl-sysdep.h index 8f1b122d3..ff7accdf1 100644 --- a/ldso/ldso/c6x/dl-sysdep.h +++ b/ldso/ldso/c6x/dl-sysdep.h @@ -104,6 +104,9 @@ struct elf32_dsbt_loadaddr; (__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 --git a/ldso/ldso/c6x/elfinterp.c b/ldso/ldso/c6x/elfinterp.c index 7c79171ce..f5d3ad41e 100644 --- a/ldso/ldso/c6x/elfinterp.c +++ b/ldso/ldso/c6x/elfinterp.c @@ -198,6 +198,10 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope, 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 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope, (char *)symbol_addr, symtab[symtab_index].st_size); } - break; + return 0; default: return -1; /*call _dl_exit(1) */ } diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c index a881b7df7..9e1415b83 100644 --- a/ldso/ldso/dl-elf.c +++ b/ldso/ldso/dl-elf.c @@ -314,6 +314,121 @@ goof: 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 @@ -482,6 +597,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, 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); @@ -502,8 +618,11 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, 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++; @@ -518,141 +637,9 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, ssize_t size; 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 : lib_loadaddr) + - (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 : lib_loadaddr); - 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) @@ -665,11 +652,11 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, 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; @@ -678,7 +665,6 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, } ppnt++; } - _dl_close(infile); /* * The dynamic_addr must be take into acount lib_loadaddr value, to note @@ -700,6 +686,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, _dl_dprintf(2, "%s: '%s' is missing a dynamic section\n", _dl_progname, libname); _dl_munmap(header, _dl_pagesize); + _dl_close(infile); return NULL; } @@ -715,10 +702,23 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, 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 : lib_loadaddr) + (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 @@ -729,6 +729,8 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, #endif } + _dl_close(infile); + tpnt = _dl_add_elf_hash_table(libname, lib_loadaddr, dynamic_info, dynamic_addr, 0); tpnt->mapaddr = libaddr; @@ -829,20 +831,44 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, #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 --git a/ldso/ldso/dl-startup.c b/ldso/ldso/dl-startup.c index 4799846ee..fa7972d90 100644 --- a/ldso/ldso/dl-startup.c +++ b/ldso/ldso/dl-startup.c @@ -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 --git a/ldso/ldso/frv/dl-inlines.h b/ldso/ldso/frv/dl-inlines.h index 95233a7c0..0395a7e23 100644 --- a/ldso/ldso/frv/dl-inlines.h +++ b/ldso/ldso/frv/dl-inlines.h @@ -72,14 +72,39 @@ __dl_init_loadaddr_hdr (struct elf32_fdpic_loadaddr loadaddr, void *addr, 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 --git a/ldso/ldso/frv/dl-sysdep.h b/ldso/ldso/frv/dl-sysdep.h index e9c847a69..206a66247 100644 --- a/ldso/ldso/frv/dl-sysdep.h +++ b/ldso/ldso/frv/dl-sysdep.h @@ -95,6 +95,8 @@ struct funcdesc_ht; #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 --git a/ldso/ldso/mips/elfinterp.c b/ldso/ldso/mips/elfinterp.c index 3ca403609..159e59d33 100644 --- a/ldso/ldso/mips/elfinterp.c +++ b/ldso/ldso/mips/elfinterp.c @@ -381,8 +381,11 @@ void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt, int lazy) *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, &_dl_loaded_modules->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL); + sym->st_name, &_dl_loaded_modules->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, &sym_ref); } got_entry++; diff --git a/ldso/ldso/x86_64/elfinterp.c b/ldso/ldso/x86_64/elfinterp.c index 44e2c66d8..dd9479987 100644 --- a/ldso/ldso/x86_64/elfinterp.c +++ b/ldso/ldso/x86_64/elfinterp.c @@ -157,7 +157,9 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope, int reloc_type; int symtab_index; char *symname; - struct elf_resolve *tls_tpnt = NULL; +#if defined USE_TLS && USE_TLS + struct elf_resolve *tls_tpnt; +#endif struct symbol_ref sym_ref; ElfW(Addr) *reloc_addr; ElfW(Addr) symbol_addr; @@ -189,13 +191,17 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope, if (_dl_trace_prelink) _dl_debug_lookup (symname, tpnt, &symtab[symtab_index], &sym_ref, elf_machine_type_class(reloc_type)); +#if defined USE_TLS && USE_TLS tls_tpnt = sym_ref.tpnt; +#endif } else { /* Relocs against STN_UNDEF are usually treated as using a * symbol value of zero, and using the module containing the * reloc itself. */ symbol_addr = sym_ref.sym->st_value; +#if defined USE_TLS && USE_TLS tls_tpnt = tpnt; +#endif } #if defined (__SUPPORT_LD_DEBUG__) diff --git a/libc/inet/ether_addr.c b/libc/inet/ether_addr.c index 621c62989..9071d71de 100644 --- a/libc/inet/ether_addr.c +++ b/libc/inet/ether_addr.c @@ -38,10 +38,12 @@ struct ether_addr *ether_aton_r(const char *asc, struct ether_addr *addr) for (cnt = 0; cnt < 6; ++cnt) { unsigned char number; - char ch; + char ch = *asc++; + if (ch < 0x20) + return NULL; /* | 0x20 is cheap tolower(), valid for letters/numbers only */ - ch = (*asc++) | 0x20; + ch |= 0x20; if ((ch < '0' || ch > '9') && (ch < 'a' || ch > 'f')) return NULL; number = !(ch > '9') ? (ch - '0') : (ch - 'a' + 10); diff --git a/libc/inet/getaddrinfo.c b/libc/inet/getaddrinfo.c index b3435a8b2..1a77c5199 100644 --- a/libc/inet/getaddrinfo.c +++ b/libc/inet/getaddrinfo.c @@ -395,9 +395,9 @@ gaih_inet(const char *name, const struct gaih_service *service, { struct gaih_servtuple nullserv; - const struct gaih_typeproto *tp = gaih_inet_typeproto; - struct gaih_servtuple *st = &nullserv; - struct gaih_addrtuple *at = NULL; + const struct gaih_typeproto *tp; + struct gaih_servtuple *st; + struct gaih_addrtuple *at; int rc; int v4mapped = (req->ai_family == PF_UNSPEC || req->ai_family == PF_INET6) && (req->ai_flags & AI_V4MAPPED); @@ -405,22 +405,24 @@ gaih_inet(const char *name, const struct gaih_service *service, memset(&nullserv, 0, sizeof(nullserv)); + tp = gaih_inet_typeproto; if (req->ai_protocol || req->ai_socktype) { ++tp; - while (tp->name[0] - && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype) - || (req->ai_protocol != 0 && !(tp->protoflag & GAI_PROTO_PROTOANY) && req->ai_protocol != tp->protocol) - ) - ) { + while (tp->name[0]) { + if ((req->ai_socktype == 0 || req->ai_socktype == tp->socktype) + && (req->ai_protocol == 0 || req->ai_protocol == tp->protocol || (tp->protoflag & GAI_PROTO_PROTOANY)) + ) { + goto found; + } ++tp; } - if (! tp->name[0]) { - if (req->ai_socktype) - return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE); - return (GAIH_OKIFUNSPEC | -EAI_SERVICE); - } + if (req->ai_socktype) + return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE); + return (GAIH_OKIFUNSPEC | -EAI_SERVICE); + found: ; } + st = &nullserv; if (service != NULL) { if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0) return (GAIH_OKIFUNSPEC | -EAI_SERVICE); @@ -495,6 +497,7 @@ gaih_inet(const char *name, const struct gaih_service *service, } } + at = NULL; if (name != NULL) { at = alloca(sizeof(struct gaih_addrtuple)); at->family = AF_UNSPEC; @@ -502,10 +505,9 @@ gaih_inet(const char *name, const struct gaih_service *service, at->next = NULL; if (inet_pton(AF_INET, name, at->addr) > 0) { - if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET || v4mapped) - at->family = AF_INET; - else + if (req->ai_family != AF_UNSPEC && req->ai_family != AF_INET && !v4mapped) return -EAI_FAMILY; + at->family = AF_INET; } #if defined __UCLIBC_HAS_IPV6__ @@ -518,11 +520,9 @@ gaih_inet(const char *name, const struct gaih_service *service, *scope_delim = '\0'; if (inet_pton(AF_INET6, namebuf, at->addr) > 0) { - if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) - at->family = AF_INET6; - else + if (req->ai_family != AF_UNSPEC && req->ai_family != AF_INET6) return -EAI_FAMILY; - + at->family = AF_INET6; if (scope_delim != NULL) { int try_numericscope = 0; uint32_t *a32 = (uint32_t*)at->addr; @@ -545,7 +545,7 @@ gaih_inet(const char *name, const struct gaih_service *service, } #endif - if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0) { + if (at->family == AF_UNSPEC && !(req->ai_flags & AI_NUMERICHOST)) { struct hostent *h; struct gaih_addrtuple **pat = &at; int no_data = 0; @@ -649,7 +649,7 @@ gaih_inet(const char *name, const struct gaih_service *service, at2->family, &th, tmpbuf, tmpbuflen, &h, &herrno); - } while (rc == errno && herrno == NETDB_INTERNAL); + } while (rc == ERANGE && herrno == NETDB_INTERNAL); if (rc != 0 && herrno == NETDB_INTERNAL) { __set_h_errno(herrno); @@ -783,9 +783,9 @@ int getaddrinfo(const char *name, const char *service, const struct addrinfo *hints, struct addrinfo **pai) { - int i = 0, j, last_i = 0; - struct addrinfo *p = NULL, **end; - const struct gaih *g = gaih, *pg = NULL; + int i, j, last_i; + struct addrinfo *p, **end; + const struct gaih *g, *pg; struct gaih_service gaih_service, *pservice; struct addrinfo default_hints; @@ -800,7 +800,7 @@ getaddrinfo(const char *name, const char *service, if (hints == NULL) { memset(&default_hints, 0, sizeof(default_hints)); - if (AF_UNSPEC) + if (AF_UNSPEC != 0) default_hints.ai_family = AF_UNSPEC; hints = &default_hints; } @@ -832,10 +832,14 @@ getaddrinfo(const char *name, const char *service, } else pservice = NULL; + g = gaih; + pg = NULL; + p = NULL; end = NULL; if (pai) end = &p; - + i = 0; + last_i = 0; j = 0; while (g->gaih) { if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC) { @@ -851,7 +855,7 @@ getaddrinfo(const char *name, const char *service, last_i = i; if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC)) continue; - if (p) + /*if (p) - freeaddrinfo works ok on NULL too */ freeaddrinfo(p); return -(i & GAIH_EAI); } diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c index 47bab7519..021d5bf5d 100644 --- a/libc/inet/resolv.c +++ b/libc/inet/resolv.c @@ -3009,7 +3009,7 @@ void res_close(void) 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 --git a/libc/misc/Makefile.in b/libc/misc/Makefile.in index 6c09d3142..e01b3dcbd 100644 --- a/libc/misc/Makefile.in +++ b/libc/misc/Makefile.in @@ -16,6 +16,7 @@ include $(top_srcdir)libc/misc/elf/Makefile.in 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 --git a/libc/misc/fts/Makefile b/libc/misc/fts/Makefile new file mode 100644 index 000000000..1361db3e0 --- /dev/null +++ b/libc/misc/fts/Makefile @@ -0,0 +1,14 @@ +# Makefile for uClibc +# +# Copyright (C) 2009 STMicroelectronics Ltd. +# Author: Salvatore Cro <salvatore.cro at st.com> +# +# 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 --git a/libc/misc/fts/Makefile.in b/libc/misc/fts/Makefile.in new file mode 100644 index 000000000..a1d0efa32 --- /dev/null +++ b/libc/misc/fts/Makefile.in @@ -0,0 +1,23 @@ +# FTS Makefile for uClibc +# +# Copyright (C) 2009 STMicroelectronics Ltd. +# Author: Salvatore Cro <salvatore.cro at st.com> +# +# 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 --git a/libc/misc/fts/fts.c b/libc/misc/fts/fts.c new file mode 100644 index 000000000..ce5d1586b --- /dev/null +++ b/libc/misc/fts/fts.c @@ -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 <sys/param.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <dirent.h> +#include <errno.h> +#include <fts.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#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 --git a/libc/stdlib/malloc/heap.h b/libc/stdlib/malloc/heap.h index 30380791f..2f06ab17c 100644 --- a/libc/stdlib/malloc/heap.h +++ b/libc/stdlib/malloc/heap.h @@ -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 --git a/libc/stdlib/malloc/malloc.h b/libc/stdlib/malloc/malloc.h index 0a4b43b86..25f7409bf 100644 --- a/libc/stdlib/malloc/malloc.h +++ b/libc/stdlib/malloc/malloc.h @@ -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 --git a/libc/string/generic/strnlen.c b/libc/string/generic/strnlen.c index 85819aaa6..b9dc16148 100644 --- a/libc/string/generic/strnlen.c +++ b/libc/string/generic/strnlen.c @@ -32,7 +32,7 @@ size_t strnlen (const char *str, size_t maxlen) { const char *char_ptr, *end_ptr = str + maxlen; const unsigned long int *longword_ptr; - unsigned long int longword, magic_bits, himagic, lomagic; + unsigned long int longword, himagic, lomagic; if (maxlen == 0) return 0; @@ -66,14 +66,12 @@ size_t strnlen (const char *str, size_t maxlen) The 1-bits make sure that carries propagate to the next 0-bit. The 0-bits provide holes for carries to fall into. */ - magic_bits = 0x7efefeffL; himagic = 0x80808080L; lomagic = 0x01010101L; if (sizeof (longword) > 4) { /* 64-bit version of the magic. */ /* Do the shift in two steps to avoid a warning if long has 32 bits. */ - magic_bits = ((0x7efefefeL << 16) << 16) | 0xfefefeffL; himagic = ((himagic << 16) << 16) | himagic; lomagic = ((lomagic << 16) << 16) | lomagic; } diff --git a/libc/sysdeps/linux/Makefile.commonarch b/libc/sysdeps/linux/Makefile.commonarch index 4e4815949..c1bc5df30 100644 --- a/libc/sysdeps/linux/Makefile.commonarch +++ b/libc/sysdeps/linux/Makefile.commonarch @@ -36,6 +36,6 @@ $(ARCH_HEADERS_OUT): 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 --git a/libc/sysdeps/linux/c6x/Makefile.arch b/libc/sysdeps/linux/c6x/Makefile.arch index 3e8dace07..6bb44f203 100644 --- a/libc/sysdeps/linux/c6x/Makefile.arch +++ b/libc/sysdeps/linux/c6x/Makefile.arch @@ -6,10 +6,5 @@ # CSRC := brk.c pread_write.c syscall.c prctl.c -#CSRC := SSRC := __longjmp.S bsd-_setjmp.S bsd-setjmp.S clone.S setjmp.S _vfork.S -#SSRC := - -# libc-nonshared-y += $(ARCH_OUT)/_syscall.os - diff --git a/libc/sysdeps/linux/common/Makefile.in b/libc/sysdeps/linux/common/Makefile.in index 3f9791104..8811268d0 100644 --- a/libc/sysdeps/linux/common/Makefile.in +++ b/libc/sysdeps/linux/common/Makefile.in @@ -14,18 +14,19 @@ CSRC- := ssp-local.c CSRC_LFS := $(notdir $(wildcard $(COMMON_DIR)/*64.c)) 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 +CSRC-$(findstring y,$(UCLIBC_HAS_SSP)$(UCLIBC_HAS_FORTIFY)) += ssp.c CSRC-$(UCLIBC_LINUX_MODULE_24) += create_module.c query_module.c \ get_kernel_syms.c # we need these internally: fstatfs.c statfs.c CSRC-$(UCLIBC_LINUX_SPECIFIC) += capget.c capset.c inotify.c ioperm.c iopl.c \ - modify_ldt.c personality.c ppoll.c prctl.c readahead.c reboot.c \ + madvise.c modify_ldt.c personality.c ppoll.c prctl.c readahead.c reboot.c \ remap_file_pages.c sched_getaffinity.c sched_setaffinity.c \ 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) @@ -40,7 +41,7 @@ CSRC-$(UCLIBC_NTP_LEGACY) += ntp_gettime.c # aio_cancel|aio_error|aio_fsync|aio_read|aio_return|aio_suspend|aio_write|clock_getres|clock_gettime|clock_settime|clock_settime|fdatasync|lio_listio|mlockall|munlockall|mlock|munlock|mq_close|mq_getattr|mq_notify|mq_open|mq_receive|mq_timedreceive|mq_send|mq_timedsend|mq_setattr|mq_unlink|nanosleep|sched_getparam|sched_get_priority_max|sched_get_priority_min|sched_getscheduler|sched_rr_get_interval|sched_setparam|sched_setscheduler|sem_close|sem_destroy|sem_getvalue|sem_init|sem_open|sem_post|sem_trywait|sem_wait|sem_unlink|sem_wait|shm_open|shm_unlink|sigqueue|sigtimedwait|sigwaitinfo|sigwaitinfo|timer_create|timer_delete|timer_getoverrun|timer_gettime|timer_settime CSRC-$(UCLIBC_HAS_REALTIME) += clock_getres.c clock_gettime.c clock_settime.c \ fdatasync.c mlockall.c mlock.c munlockall.c munlock.c \ - nanosleep.c __rt_sigtimedwait.c sched_getparam.c \ + nanosleep.c __rt_sigtimedwait.c __rt_sigwaitinfo.c sched_getparam.c \ sched_get_priority_max.c sched_get_priority_min.c sched_getscheduler.c \ sched_rr_get_interval.c sched_setparam.c sched_setscheduler.c sigqueue.c # clock_getcpuclockid|clock_nanosleep|mq_timedreceive|mq_timedsend|posix_fadvise|posix_fallocate|posix_madvise|posix_memalign|posix_mem_offset|posix_spawnattr_destroy|posix_spawnattr_init|posix_spawnattr_getflags|posix_spawnattr_setflags|posix_spawnattr_getpgroup|posix_spawnattr_setpgroup|posix_spawnattr_getschedparam|posix_spawnattr_setschedparam|posix_spawnattr_getschedpolicy|posix_spawnattr_setschedpolicy|posix_spawnattr_getsigdefault|posix_spawnattr_setsigdefault|posix_spawnattr_getsigmask|posix_spawnattr_setsigmask|posix_spawnattr_init|posix_spawnattr_setflags|posix_spawnattr_setpgroup|posix_spawnattr_setschedparam|posix_spawnattr_setschedpolicy|posix_spawnattr_setsigdefault|posix_spawnattr_setsigmask|posix_spawn_file_actions_addclose|posix_spawn_file_actions_addopen|posix_spawn_file_actions_adddup2|posix_spawn_file_actions_addopen|posix_spawn_file_actions_destroy|posix_spawn_file_actions_init|posix_spawn_file_actions_init|posix_spawn|posix_spawnp|posix_spawnp|posix_typed_mem_get_info|pthread_mutex_timedlock|sem_timedwait diff --git a/libc/sysdeps/linux/microblaze/Makefile.arch b/libc/sysdeps/linux/microblaze/Makefile.arch index ecbd80141..c80c65085 100644 --- a/libc/sysdeps/linux/microblaze/Makefile.arch +++ b/libc/sysdeps/linux/microblaze/Makefile.arch @@ -10,5 +10,3 @@ CSRC := mmap.c clone.c fixdfsi.c SSRC := setjmp.S __longjmp.S vfork.S ARCH_HEADERS := floatlib.h - -include $(top_srcdir)libc/sysdeps/linux/Makefile.commonarch diff --git a/libc/sysdeps/linux/sparc/soft-fp/sfp-machine.h b/libc/sysdeps/linux/sparc/soft-fp/sfp-machine.h index f1211705e..ecf9506b6 100644 --- a/libc/sysdeps/linux/sparc/soft-fp/sfp-machine.h +++ b/libc/sysdeps/linux/sparc/soft-fp/sfp-machine.h @@ -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 @@ do { \ else \ ___Q_simulate_exceptions (_fex); \ } while (0) +#endif diff --git a/libc/unistd/sysconf.c b/libc/unistd/sysconf.c index be58f111f..c1b3c86db 100644 --- a/libc/unistd/sysconf.c +++ b/libc/unistd/sysconf.c @@ -993,13 +993,12 @@ long int sysconf(int name) r = INTERNAL_SYSCALL (clock_getres, err, 2, CLOCK_MONOTONIC, &ts); return INTERNAL_SYSCALL_ERROR_P (r, err) ? -1 : _POSIX_VERSION; } -# else +# elif defined __UCLIBC_HAS_REALTIME__ if (clock_getres(CLOCK_MONOTONIC, NULL) >= 0) return _POSIX_VERSION; - - RETURN_NEG_1; # endif #endif + RETURN_NEG_1; #ifdef __UCLIBC_HAS_THREADS_NATIVE__ case _SC_THREAD_CPUTIME: diff --git a/libubacktrace/Makefile.in b/libubacktrace/Makefile.in index c1dd5d7ab..f75f68b75 100644 --- a/libubacktrace/Makefile.in +++ b/libubacktrace/Makefile.in @@ -12,35 +12,26 @@ CFLAGS-libubacktrace := -DNOT_IN_libc -DIS_IN_libubacktrace $(SSP_ALL_CFLAGS) LDFLAGS-libubacktrace.so := $(LDFLAGS) $(top_builddir)lib/libdl-$(VERSION).so +ifeq ($(CONFIG_ARM_EABI),y) +LIBGCC += $(shell $(CC) -print-file-name=libgcc_eh.a) +endif + LIBS-libubacktrace.so := $(LIBS) libubacktrace_FULL_NAME := libubacktrace-$(VERSION).so 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 --git a/libubacktrace/backtrace.c b/libubacktrace/backtrace.c index 872180028..18b91b1bb 100644 --- a/libubacktrace/backtrace.c +++ b/libubacktrace/backtrace.c @@ -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 <peppe.cavallaro@st.com> + * - Initial implementation for glibc + * * Author(s): Carmelo Amoroso <carmelo.amoroso@st.com> + * - 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 <execinfo.h> +#include <dlfcn.h> +#include <stdlib.h> +#include <unwind.h> +#include <assert.h> +#include <stdio.h> + +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 --git a/libubacktrace/sysdeps/sh/Makefile.arch b/libubacktrace/sysdeps/sh/Makefile.arch deleted file mode 100644 index 9b0de385b..000000000 --- a/libubacktrace/sysdeps/sh/Makefile.arch +++ /dev/null @@ -1,12 +0,0 @@ -# Makefile for uClibc (sh/libubacktrace) -# -# Copyright (C) 2010 STMicroelectronics Ltd -# Author: Carmelo Amoroso <carmelo.amoroso@st.com> - -# 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 --git a/libubacktrace/sysdeps/sh/backtrace.c b/libubacktrace/sysdeps/sh/backtrace.c deleted file mode 100644 index 18b91b1bb..000000000 --- a/libubacktrace/sysdeps/sh/backtrace.c +++ /dev/null @@ -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 <peppe.cavallaro@st.com> - * - Initial implementation for glibc - * - * Author(s): Carmelo Amoroso <carmelo.amoroso@st.com> - * - 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 <execinfo.h> -#include <dlfcn.h> -#include <stdlib.h> -#include <unwind.h> -#include <assert.h> -#include <stdio.h> - -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 --git a/test/inet/Makefile.in b/test/inet/Makefile.in index 0c0b9dc3d..0710d3d71 100644 --- a/test/inet/Makefile.in +++ b/test/inet/Makefile.in @@ -3,5 +3,9 @@ # ifeq ($(UCLIBC_HAS_IPV4)$(UCLIBC_HAS_IPV6),) TESTS_DISABLED := bug-if1 gethost_r-align gethostid if_nameindex tst-aton \ - tst-network tst-ntoa + tst-network tst-ntoa +endif + +ifeq ($(UCLIBC_HAS_SOCKET)$(UCLIBC_HAS_IPV4)$(UCLIBC_HAS_IPV6),) +TESTS_DISABLED := tst-ether_aton tst-ethers tst-ethers-line endif diff --git a/test/inet/tst-ether_aton.c b/test/inet/tst-ether_aton.c new file mode 100644 index 000000000..67cb43540 --- /dev/null +++ b/test/inet/tst-ether_aton.c @@ -0,0 +1,46 @@ +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <netinet/ether.h> + +static struct tests +{ + const char *input; + int valid; + uint8_t result[6]; +} tests[] = +{ + { "", 0, {0, 0, 0, 0, 0, 0} }, + { "AB:CD:EF:01:23:45", 1, {171, 205, 239, 1, 35, 69} }, + { "\022B:BB:BB:BB:BB:BB", 0, {0, 0, 0, 0, 0, 0} } +}; + + +int +main (int argc, char *argv[]) +{ + int result = 0; + size_t cnt; + + for (cnt = 0; cnt < sizeof (tests) / sizeof (tests[0]); ++cnt) + { + struct ether_addr *addr; + + if (!!(addr = ether_aton (tests[cnt].input)) != tests[cnt].valid) + { + if (tests[cnt].valid) + printf ("\"%s\" not seen as valid MAC address\n", tests[cnt].input); + else + printf ("\"%s\" seen as valid MAC address\n", tests[cnt].input); + result = 1; + } + else if (tests[cnt].valid + && memcmp(addr, &tests[cnt].result, sizeof(struct ether_addr))) + { + printf ("\"%s\" not converted correctly\n", tests[cnt].input); + result = 1; + } + } + + return result; +} diff --git a/test/nptl/Makefile.in b/test/nptl/Makefile.in index b6a279ebf..b91480250 100644 --- a/test/nptl/Makefile.in +++ b/test/nptl/Makefile.in @@ -221,9 +221,4 @@ OPTS_tst-cancel7 = --command ./tst-cancel7 OPTS_tst-mqueue7 = -- ./tst-mqueue7 OPTS_tst-exec4 = ./tst-exec4 -RET_tst-clock2 := 1 -RET_tst-cputimer1 := 1 -RET_tst-cputimer2 := 1 -RET_tst-cputimer3 := 1 - WRAPPER := env LD_LIBRARY_PATH="$$PWD:.:$(LD_LIBRARY_PATH)" TIMEOUTFACTOR=100 diff --git a/test/nptl/tst-clock2.c b/test/nptl/tst-clock2.c index 49a769bf4..bca40956e 100644 --- a/test/nptl/tst-clock2.c +++ b/test/nptl/tst-clock2.c @@ -62,7 +62,7 @@ do_test (void) if (sysconf (_SC_THREAD_CPUTIME) < 0) { puts ("_POSIX_THREAD_CPUTIME option not available"); - return 1; + return 0; } # endif diff --git a/test/tls/Makefile.in b/test/tls/Makefile.in index d19d347f3..875c60779 100644 --- a/test/tls/Makefile.in +++ b/test/tls/Makefile.in @@ -140,7 +140,6 @@ tst-tlsmod18a%.so: tst-tlsmod18a.c $(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 --git a/test/tls/tst-tls13.c b/test/tls/tst-tls13.c index 55fb62e54..beee91bf4 100644 --- a/test/tls/tst-tls13.c +++ b/test/tls/tst-tls13.c @@ -26,5 +26,5 @@ do_test (void) } #define TEST_FUNCTION do_test () -#define TIMEOUT 3 +#define TIMEOUT 20 #include "../test-skeleton.c" |