summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarmelo Amoroso <carmelo.amoroso@st.com>2011-05-04 08:31:16 +0200
committerCarmelo Amoroso <carmelo.amoroso@st.com>2011-05-04 08:31:16 +0200
commit3004ce0c9619f89bf8e64931edd696bf4df8d2e1 (patch)
treef03f898fa5c2506c4e30f5f89ce097acf01bc016
parent3b3285b1b7c02d36c74a6ae265fdb02ca991c96b (diff)
parent4916fd889ec1c60710faa528a3ccdb50973198e2 (diff)
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>
-rw-r--r--Makefile.in2
-rw-r--r--Rules.mak2
-rw-r--r--extra/Configs/Config.in14
-rw-r--r--include/fts.h131
-rw-r--r--ldso/include/dl-elf.h2
-rw-r--r--ldso/include/ldso.h2
-rw-r--r--ldso/ldso/bfin/dl-inlines.h41
-rw-r--r--ldso/ldso/bfin/dl-sysdep.h2
-rw-r--r--ldso/ldso/c6x/dl-inlines.h29
-rw-r--r--ldso/ldso/c6x/dl-sysdep.h3
-rw-r--r--ldso/ldso/c6x/elfinterp.c6
-rw-r--r--ldso/ldso/dl-elf.c318
-rw-r--r--ldso/ldso/dl-startup.c16
-rw-r--r--ldso/ldso/frv/dl-inlines.h41
-rw-r--r--ldso/ldso/frv/dl-sysdep.h2
-rw-r--r--ldso/ldso/mips/elfinterp.c5
-rw-r--r--ldso/ldso/x86_64/elfinterp.c8
-rw-r--r--libc/inet/ether_addr.c6
-rw-r--r--libc/inet/getaddrinfo.c60
-rw-r--r--libc/inet/resolv.c2
-rw-r--r--libc/misc/Makefile.in1
-rw-r--r--libc/misc/fts/Makefile14
-rw-r--r--libc/misc/fts/Makefile.in23
-rw-r--r--libc/misc/fts/fts.c1145
-rw-r--r--libc/stdlib/malloc/heap.h6
-rw-r--r--libc/stdlib/malloc/malloc.h2
-rw-r--r--libc/string/generic/strnlen.c4
-rw-r--r--libc/sysdeps/linux/Makefile.commonarch2
-rw-r--r--libc/sysdeps/linux/c6x/Makefile.arch5
-rw-r--r--libc/sysdeps/linux/common/Makefile.in11
-rw-r--r--libc/sysdeps/linux/microblaze/Makefile.arch2
-rw-r--r--libc/sysdeps/linux/sparc/soft-fp/sfp-machine.h2
-rw-r--r--libc/unistd/sysconf.c5
-rw-r--r--libubacktrace/Makefile.in25
-rw-r--r--libubacktrace/backtrace.c75
-rw-r--r--libubacktrace/sysdeps/sh/Makefile.arch12
-rw-r--r--libubacktrace/sysdeps/sh/backtrace.c84
-rw-r--r--test/inet/Makefile.in6
-rw-r--r--test/inet/tst-ether_aton.c46
-rw-r--r--test/nptl/Makefile.in5
-rw-r--r--test/nptl/tst-clock2.c2
-rw-r--r--test/tls/Makefile.in1
-rw-r--r--test/tls/tst-tls13.c2
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
diff --git a/Rules.mak b/Rules.mak
index 0aa684342..49ca2072a 100644
--- a/Rules.mak
+++ b/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
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"