Browse Source

Merge remote-tracking branch 'origin/master' into prelink

* origin/master: (32 commits)
  libubacktrace: fix backtrace support on arm-eabi, which needs libgcc_eh linked too
  getaddrinfo.c: fix incorrect check for ERANGE from gethostbyaddr_r
  getaddrinfo.c: improve code readability. No functional changes
  string: remove unused variable
  x86_64: silence warning if !TLS
  buildsys: prettify ssp.c handling
  madvise is LINUX_SPECIFIC
  test_nptl: fix expected result for tst-cputimer[123]
  test_nptl: fix expected result for tst-clock2 test
  buildsys: make $(LOCAL_INSTALL_PATH) phony
  ether_aton: reject invalid input
  tests: disable ether tests if !HAS_SOCKET
  inet: add ether_aton testcase
  sysconf: clock_getres depends on HAS_REALTIME
  __rt_sigwaitinfo: depends on HAS_REALTIME
  buildsys: minor fixes in Makefile.arch for C6X
  buildsys: minor fixes in Makefile.arch for microblaze
  libubacktrace: enabled for all archs indeed.
  sparc: don't access fp registers when configured for no fpu
  libubacktrace: generic implementation based dwarf
  ...

Conflicts:
	ldso/ldso/dl-elf.c
	ldso/ldso/mips/elfinterp.c
	ldso/ldso/x86_64/elfinterp.c

Signed-off-by: Carmelo Amoroso <carmelo.amoroso@st.com>
Carmelo Amoroso 13 years ago
parent
commit
3004ce0c96
43 changed files with 1816 additions and 356 deletions
  1. 2 0
      Makefile.in
  2. 1 1
      Rules.mak
  3. 13 1
      extra/Configs/Config.in
  4. 131 0
      include/fts.h
  5. 1 1
      ldso/include/dl-elf.h
  6. 2 0
      ldso/include/ldso.h
  7. 33 8
      ldso/ldso/bfin/dl-inlines.h
  8. 2 0
      ldso/ldso/bfin/dl-sysdep.h
  9. 29 0
      ldso/ldso/c6x/dl-inlines.h
  10. 3 0
      ldso/ldso/c6x/dl-sysdep.h
  11. 5 1
      ldso/ldso/c6x/elfinterp.c
  12. 172 146
      ldso/ldso/dl-elf.c
  13. 8 8
      ldso/ldso/dl-startup.c
  14. 33 8
      ldso/ldso/frv/dl-inlines.h
  15. 2 0
      ldso/ldso/frv/dl-sysdep.h
  16. 4 1
      ldso/ldso/mips/elfinterp.c
  17. 7 1
      ldso/ldso/x86_64/elfinterp.c
  18. 4 2
      libc/inet/ether_addr.c
  19. 32 28
      libc/inet/getaddrinfo.c
  20. 1 1
      libc/inet/resolv.c
  21. 1 0
      libc/misc/Makefile.in
  22. 14 0
      libc/misc/fts/Makefile
  23. 23 0
      libc/misc/fts/Makefile.in
  24. 1145 0
      libc/misc/fts/fts.c
  25. 4 2
      libc/stdlib/malloc/heap.h
  26. 1 1
      libc/stdlib/malloc/malloc.h
  27. 1 3
      libc/string/generic/strnlen.c
  28. 1 1
      libc/sysdeps/linux/Makefile.commonarch
  29. 0 5
      libc/sysdeps/linux/c6x/Makefile.arch
  30. 6 5
      libc/sysdeps/linux/common/Makefile.in
  31. 0 2
      libc/sysdeps/linux/microblaze/Makefile.arch
  32. 2 0
      libc/sysdeps/linux/sparc/soft-fp/sfp-machine.h
  33. 2 3
      libc/unistd/sysconf.c
  34. 8 17
      libubacktrace/Makefile.in
  35. 70 5
      libubacktrace/backtrace.c
  36. 0 12
      libubacktrace/sysdeps/sh/Makefile.arch
  37. 0 84
      libubacktrace/sysdeps/sh/backtrace.c
  38. 5 1
      test/inet/Makefile.in
  39. 46 0
      test/inet/tst-ether_aton.c
  40. 0 5
      test/nptl/Makefile.in
  41. 1 1
      test/nptl/tst-clock2.c
  42. 0 1
      test/tls/Makefile.in
  43. 1 1
      test/tls/tst-tls13.c

+ 2 - 0
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

+ 1 - 1
Rules.mak

@@ -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

+ 13 - 1
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

+ 131 - 0
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 */

+ 1 - 1
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

+ 2 - 0
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>

+ 33 - 8
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
 }
 

+ 2 - 0
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) \

+ 29 - 0
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)
 {

+ 3 - 0
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)))
 

+ 5 - 1
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) */
 	}

+ 172 - 146
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) {

+ 8 - 8
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

+ 33 - 8
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
 }
 

+ 2 - 0
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) \

+ 4 - 1
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++;

+ 7 - 1
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__)

+ 4 - 2
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);

+ 32 - 28
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);
 				}

+ 1 - 1
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);
 		}

+ 1 - 0
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

+ 14 - 0
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

+ 23 - 0
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)

+ 1145 - 0
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);
+}

+ 4 - 2
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

+ 1 - 1
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;

+ 1 - 3
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;
     }

+ 1 - 1
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

+ 0 - 5
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
-

+ 6 - 5
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

+ 0 - 2
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

+ 2 - 0
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

+ 2 - 3
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:

+ 8 - 17
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)

+ 70 - 5
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;
+}

+ 0 - 12
libubacktrace/sysdeps/sh/Makefile.arch

@@ -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

+ 0 - 84
libubacktrace/sysdeps/sh/backtrace.c

@@ -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;
-}

+ 5 - 1
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

+ 46 - 0
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;
+}

+ 0 - 5
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

+ 1 - 1
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
 

+ 0 - 1
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

+ 1 - 1
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"