cd $(DIR_APP) && sed -i 's|libs -o|libs -L/usr/lib -Wl,-dynamic-linker=/lib/ld-linux.so.2 -o|' \
scripts/test-installation.pl
endif
+
+ cd $(DIR_APP) && for i in $(DIR_SRC)/src/patches/glibc/*; do \
+ patch -Np1 < $${i}; done
+
cd $(DIR_SRC)/glibc-build && $(DIR_APP)/configure $(EXTRA_CONFIG)
ifeq "$(ROOT)" ""
--- /dev/null
+--- glibc-2.3.6/ChangeLog.15 16 Feb 2005 07:35:41 -0000 1.1.2.1
++++ glibc-2.3.6-fedora/ChangeLog.15 18 Feb 2005 02:00:20 -0000 1.1.4.3
+@@ -512,6 +512,14 @@
+
+ 2004-11-26 Jakub Jelinek <jakub@redhat.com>
+
++ * posix/Makefile (generated: Add getconf.speclist.
++ ($(inst_libexecdir)/getconf): Use getconf.speclist instead of
++ getconf output.
++ ($(objpfx)getconf.speclist): New rule.
++ * posix/getconf.speclist.h: New file.
++
++2004-11-26 Jakub Jelinek <jakub@redhat.com>
++
+ * posix/Makefile (install-others): Add $(inst_libexecdir)/getconf.
+ (CFLAGS-sysconf.c): Add -D_GETCONF_DIR.
+ (CFLAGS-getconf.c): New.
+@@ -1103,6 +1111,16 @@
+ * sysdeps/generic/tempname.c (__path_search): Add missing argument
+ TRY_TMPDIR.
+
++2004-11-02 Jakub Jelinek <jakub@redhat.com>
++
++ * include/features.h (__USE_FORTIFY_LEVEL): Also set for Red Hat
++ GCC 3.4.x-RH >= 3.4.2-8.
++ * libio/bits/features.h (printf, fprintf, vprintf, vfprintf): For
++ GCC 3.4.x-RH use __builtin___{,v}{,f}printf_chk instead of
++ __{,v}{,f}printf_chk.
++ * debug/tst-chk1.c (do_test): Deal with GCC 3.4.x-RH not
++ being able to recognize subobjects.
++
+ 2004-10-31 Mariusz Mazur <mmazur@kernel.pl>
+
+ * sysdeps/unix/sysv/linux/alpha/setregid.c: New file.
+@@ -1398,6 +1416,11 @@
+ * posix/execvp.c (execvp): Also ignore ENODEV and ETIMEDOUT errno
+ values.
+
++2004-10-20 Jakub Jelinek <jakub@redhat.com>
++
++ * sysdeps/unix/sysv/linux/readonly-area.c (__readonly_area): If /proc
++ is not mounted, return 1.
++
+ 2004-10-20 Roland McGrath <roland@redhat.com>
+
+ * Makeconfig ($(common-objpfx)shlib-versions.v.i): Check also
+@@ -1470,6 +1493,11 @@
+ * debug/catchsegv.sh: Update copyright year.
+ Use mktemp to create segv_output file.
+
++2004-10-19 Jakub Jelinek <jakub@redhat.com>
++
++ * include/features.h (__USE_FORTIFY_LEVEL): Enable even with
++ Red Hat gcc4 4.0.0 and above.
++
+ 2004-10-18 Jakub Jelinek <jakub@redhat.com>
+
+ * elf/dl-libc.c (__libc_dlsym_private, __libc_register_dl_open_hook):
+@@ -3182,6 +3210,23 @@
+ before return type.
+ * locale/localename.c (__current_locale_name): Likewise.
+
++2004-08-31 Jakub Jelinek <jakub@redhat.com>
++
++ * elf/ldconfig.c (parse_conf): Add prefix argument, prepend it
++ before arguments to add_dir and pass to parse_conf_include.
++ (parse_conf_include): Add prefix argument, pass it down to
++ parse_conf.
++ (main): Call arch_startup. Adjust parse_conf caller.
++ Call add_arch_dirs.
++ * sysdeps/generic/dl-cache.h (arch_startup, add_arch_dirs): Define.
++ * sysdeps/unix/sysv/linux/i386/dl-cache.h: New file.
++ * sysdeps/unix/sysv/linux/ia64/dl-cache.h (EMUL_HACK, arch_startup,
++ add_arch_dirs): Define.
++ * sysdeps/unix/sysv/linux/ia64/ldd-rewrite.sed: Prepend
++ /emul/ia32-linux before the 32-bit ld.so pathname.
++ * sysdeps/unix/sysv/linux/ia64/dl-procinfo.c: New file.
++ * sysdeps/unix/sysv/linux/ia64/dl-procinfo.h: New file.
++
+ 2004-08-30 Roland McGrath <roland@frob.com>
+
+ * scripts/extract-abilist.awk: If `lastversion' variable defined, omit
+--- glibc-2.3.6/csu/elf-init.c 16 Aug 2004 04:51:00 -0000 1.3
++++ glibc-2.3.6-fedora/csu/elf-init.c 22 Sep 2004 21:20:47 -0000 1.3.2.1
+@@ -44,6 +44,24 @@ extern void (*__init_array_start []) (vo
+ extern void (*__init_array_end []) (void) attribute_hidden;
+ extern void (*__fini_array_start []) (void) attribute_hidden;
+ extern void (*__fini_array_end []) (void) attribute_hidden;
++
++# if defined HAVE_VISIBILITY_ATTRIBUTE \
++ && (defined SHARED || defined LIBC_NONSHARED)
++# define hidden_undef_2(x) #x
++# define hidden_undef_1(x) hidden_undef_2 (x)
++# define hidden_undef(x) \
++ __asm (hidden_undef_1 (ASM_GLOBAL_DIRECTIVE) " " #x); \
++ __asm (".hidden " #x);
++# else
++# define hidden_undef(x)
++# endif
++
++hidden_undef (__preinit_array_start)
++hidden_undef (__preinit_array_end)
++hidden_undef (__init_array_start)
++hidden_undef (__init_array_end)
++hidden_undef (__fini_array_start)
++hidden_undef (__fini_array_end)
+ #endif
+
+ /* These function symbols are provided for the .init/.fini section entry
+--- glibc-2.3.6/debug/tst-chk1.c 18 Nov 2004 23:23:17 -0000 1.5
++++ glibc-2.3.6-fedora/debug/tst-chk1.c 19 Nov 2004 00:18:08 -0000 1.1.2.7
+@@ -213,7 +213,7 @@ do_test (void)
+ if (memcmp (a.buf1, "aabcdabcjj", 10))
+ FAIL ();
+
+-#if __USE_FORTIFY_LEVEL < 2
++#if __USE_FORTIFY_LEVEL < 2 || !__GNUC_PREREQ (4, 0)
+ /* The following tests are supposed to crash with -D_FORTIFY_SOURCE=2
+ and sufficient GCC support, as the string operations overflow
+ from a.buf1 into a.buf2. */
+@@ -312,7 +312,7 @@ do_test (void)
+ memset (a.buf1 + 9, 'j', l0 + 2);
+ CHK_FAIL_END
+
+-#if __USE_FORTIFY_LEVEL >= 2
++#if __USE_FORTIFY_LEVEL >= 2 && __GNUC_PREREQ (4, 0)
+ # define O 0
+ #else
+ # define O 1
+--- glibc-2.3.6/elf/dl-support.c 6 Nov 2004 00:24:49 -0000 1.87
++++ glibc-2.3.6-fedora/elf/dl-support.c 10 Nov 2004 09:02:46 -0000 1.84.2.4
+@@ -281,6 +281,11 @@ _dl_non_dynamic_init (void)
+ if (_dl_platform != NULL)
+ _dl_platformlen = strlen (_dl_platform);
+
++#if defined (__i386__) && !defined (USE_TLS)
++ /* Load libs not using TLS. */
++ _dl_osversion = 0x20205;
++#endif
++
+ /* Scan for a program header telling us the stack is nonexecutable. */
+ if (_dl_phdr != NULL)
+ for (uint_fast16_t i = 0; i < _dl_phnum; ++i)
+--- glibc-2.3.6/elf/ldconfig.c 16 Feb 2005 10:29:34 -0000 1.47.4.1
++++ glibc-2.3.6-fedora/elf/ldconfig.c 16 Feb 2005 19:56:52 -0000 1.47.2.1.2.1
+@@ -944,17 +944,19 @@ search_dirs (void)
+
+
+ static void parse_conf_include (const char *config_file, unsigned int lineno,
+- bool do_chroot, const char *pattern);
++ const char *prefix, bool do_chroot,
++ const char *pattern);
+
+ /* Parse configuration file. */
+ static void
+-parse_conf (const char *filename, bool do_chroot)
++parse_conf (const char *filename, const char *prefix, bool do_chroot)
+ {
+ FILE *file = NULL;
+ char *line = NULL;
+ const char *canon;
+ size_t len = 0;
+ unsigned int lineno;
++ size_t prefix_len = prefix ? strlen (prefix) : 0;
+
+ if (do_chroot && opt_chroot)
+ {
+@@ -1015,7 +1017,14 @@ parse_conf (const char *filename, bool d
+ cp += 8;
+ while ((dir = strsep (&cp, " \t")) != NULL)
+ if (dir[0] != '\0')
+- parse_conf_include (filename, lineno, do_chroot, dir);
++ parse_conf_include (filename, lineno, prefix, do_chroot, dir);
++ }
++ else if (prefix != NULL)
++ {
++ size_t cp_len = strlen (cp);
++ char new_cp [prefix_len + cp_len + 1];
++ memcpy (mempcpy (new_cp, prefix, prefix_len), cp, cp_len + 1);
++ add_dir (new_cp);
+ }
+ else
+ add_dir (cp);
+@@ -1031,7 +1040,7 @@ parse_conf (const char *filename, bool d
+ config files to read. */
+ static void
+ parse_conf_include (const char *config_file, unsigned int lineno,
+- bool do_chroot, const char *pattern)
++ const char *prefix, bool do_chroot, const char *pattern)
+ {
+ if (opt_chroot && pattern[0] != '/')
+ error (EXIT_FAILURE, 0,
+@@ -1061,7 +1070,7 @@ parse_conf_include (const char *config_f
+ {
+ case 0:
+ for (size_t i = 0; i < gl.gl_pathc; ++i)
+- parse_conf (gl.gl_pathv[i], false);
++ parse_conf (gl.gl_pathv[i], prefix, false);
+ globfree64 (&gl);
+ break;
+
+@@ -1101,6 +1110,8 @@ main (int argc, char **argv)
+ {
+ int remaining;
+
++ arch_startup (argc, argv);
++
+ /* Parse and process arguments. */
+ argp_parse (&argp, argc, argv, 0, &remaining, NULL);
+
+@@ -1209,12 +1220,14 @@ main (int argc, char **argv)
+
+ if (!opt_only_cline)
+ {
+- parse_conf (config_file, true);
++ parse_conf (config_file, NULL, true);
+
+ /* Always add the standard search paths. */
+ add_system_dir (SLIBDIR);
+ if (strcmp (SLIBDIR, LIBDIR))
+ add_system_dir (LIBDIR);
++
++ add_arch_dirs (config_file);
+ }
+
+ search_dirs ();
+--- glibc-2.3.6/elf/rtld.c 6 Apr 2005 02:49:51 -0000 1.339.2.2
++++ glibc-2.3.6-fedora/elf/rtld.c 20 Mar 2005 18:56:00 -0000 1.330.2.10.2.2
+@@ -1116,6 +1116,53 @@ of this helper program; chances are you
+ ++GL(dl_ns)[LM_ID_BASE]._ns_nloaded;
+ ++GL(dl_load_adds);
+
++#if defined(__i386__)
++ /* Force non-TLS libraries for glibc 2.0 binaries
++ or if a buggy binary references non-TLS errno or h_errno. */
++ if (__builtin_expect (main_map->l_info[DT_NUM + DT_THISPROCNUM
++ + DT_VERSIONTAGIDX (DT_VERNEED)]
++ == NULL, 0)
++ && main_map->l_info[DT_DEBUG])
++ GLRO(dl_osversion) = 0x20205;
++ else if ((__builtin_expect (mode, normal) != normal
++ || main_map->l_info[ADDRIDX (DT_GNU_LIBLIST)] == NULL)
++ /* Only binaries have DT_DEBUG dynamic tags... */
++ && main_map->l_info[DT_DEBUG])
++ {
++ /* Workaround for buggy binaries. This doesn't handle buggy
++ libraries. */
++ bool buggy = false;
++ const ElfW(Sym) *symtab = (const void *) D_PTR (main_map,
++ l_info[DT_SYMTAB]);
++ const char *strtab = (const void *) D_PTR (main_map,
++ l_info[DT_STRTAB]);
++ Elf_Symndx symidx;
++ for (symidx = main_map->l_buckets[0x6c994f % main_map->l_nbuckets];
++ symidx != STN_UNDEF;
++ symidx = main_map->l_chain[symidx])
++ {
++ if (__builtin_expect (strcmp (strtab + symtab[symidx].st_name,
++ "errno") == 0, 0)
++ && ELFW(ST_TYPE) (symtab[symidx].st_info) != STT_TLS)
++ buggy = true;
++ }
++ for (symidx = main_map->l_buckets[0xe5c992f % main_map->l_nbuckets];
++ symidx != STN_UNDEF;
++ symidx = main_map->l_chain[symidx])
++ {
++ if (__builtin_expect (strcmp (strtab + symtab[symidx].st_name,
++ "h_errno") == 0, 0)
++ && ELFW(ST_TYPE) (symtab[symidx].st_info) != STT_TLS)
++ buggy = true;
++ }
++ if (__builtin_expect (buggy, false) && GLRO(dl_osversion) > 0x20401)
++ {
++ GLRO(dl_osversion) = 0x20401;
++ _dl_error_printf ("Incorrectly built binary which accesses errno or h_errno directly. Needs to be fixed.\n");
++ }
++ }
++#endif
++
+ /* If LD_USE_LOAD_BIAS env variable has not been seen, default
+ to not using bias for non-prelinked PIEs and libraries
+ and using it for executables or prelinked PIEs or libraries. */
+@@ -1255,6 +1302,58 @@ of this helper program; chances are you
+ }
+ }
+
++
++#if defined(__i386__) || defined(__alpha__) || (defined(__sparc__) && !defined(__arch64__))
++ /*
++ * Modifications by Red Hat Software
++ *
++ * Deal with the broken binaries from the non-versioned ages of glibc.
++ * If a binary does not have version information enabled, we assume that
++ * it is a glibc 2.0 binary and we load a compatibility library to try to
++ * overcome binary incompatibilities.
++ * Blame: gafton@redhat.com
++ */
++#define LIB_NOVERSION "/lib/libNoVersion.so.1"
++
++ if (__builtin_expect (main_map->l_info[DT_NUM + DT_THISPROCNUM
++ + DT_VERSIONTAGIDX (DT_VERNEED)]
++ == NULL, 0)
++ && (main_map->l_info[DT_DEBUG]
++ || !(GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)))
++ {
++ struct stat test_st;
++ int test_fd;
++ int can_load;
++
++ HP_TIMING_NOW (start);
++
++/* _dl_sysdep_message("Loading compatibility library... ", NULL); */
++
++ can_load = 1;
++ test_fd = __open (LIB_NOVERSION, O_RDONLY);
++ if (test_fd < 0) {
++ can_load = 0;
++/* _dl_sysdep_message(" Can't find " LIB_NOVERSION "\n", NULL); */
++ } else {
++ if (__fxstat (_STAT_VER, test_fd, &test_st) < 0 || test_st.st_size == 0) {
++ can_load = 0;
++/* _dl_sysdep_message(" Can't stat " LIB_NOVERSION "\n", NULL); */
++ }
++ }
++
++ if (test_fd >= 0) /* open did no fail.. */
++ __close(test_fd); /* avoid fd leaks */
++
++ if (can_load != 0)
++ npreloads += do_preload (LIB_NOVERSION, main_map,
++ "nonversioned binary");
++
++ HP_TIMING_NOW (stop);
++ HP_TIMING_DIFF (diff, start, stop);
++ HP_TIMING_ACCUM_NT (load_time, diff);
++ }
++#endif
++
+ if (__builtin_expect (GL(dl_rtld_map).l_next != NULL, 0))
+ {
+ /* Set up PRELOADS with a vector of the preloaded libraries. */
+--- glibc-2.3.6/elf/tst-tls10.h 17 Apr 2003 19:19:01 -0000 1.1
++++ glibc-2.3.6-fedora/elf/tst-tls10.h 22 Sep 2004 21:20:48 -0000 1.1.2.1
+@@ -1,8 +1,8 @@
+ #include <tls.h>
+ #include <stdlib.h>
+
+-#if defined USE_TLS && defined HAVE___THREAD \
+- && defined HAVE_TLS_MODEL_ATTRIBUTE
++#if defined USE_TLS \
++ && (0 || (defined HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE))
+ # define USE_TLS__THREAD
+
+ struct A
+--- glibc-2.3.6/iconv/iconvconfig.c 6 Apr 2005 00:37:52 -0000 1.21.2.2
++++ glibc-2.3.6-fedora/iconv/iconvconfig.c 3 Mar 2005 16:27:44 -0000 1.19.2.2.2.2
+@@ -1013,6 +1013,34 @@ next_prime (uint32_t seed)
+ module name offset
+ (following last entry with step count 0)
+ */
++
++static struct hash_entry *hash_table;
++static size_t hash_size;
++
++/* Function to insert the names. */
++static void name_insert (const void *nodep, VISIT value, int level)
++{
++ struct name *name;
++ unsigned int idx;
++ unsigned int hval2;
++
++ if (value != leaf && value != postorder)
++ return;
++
++ name = *(struct name **) nodep;
++ idx = name->hashval % hash_size;
++ hval2 = 1 + name->hashval % (hash_size - 2);
++
++ while (hash_table[idx].string_offset != 0)
++ if ((idx += hval2) >= hash_size)
++ idx -= hash_size;
++
++ hash_table[idx].string_offset = strtaboffset (name->strent);
++
++ assert (name->module_idx != -1);
++ hash_table[idx].module_idx = name->module_idx;
++}
++
+ static int
+ write_output (void)
+ {
+@@ -1020,8 +1048,6 @@ write_output (void)
+ char *string_table;
+ size_t string_table_size;
+ struct gconvcache_header header;
+- struct hash_entry *hash_table;
+- size_t hash_size;
+ struct module_entry *module_table;
+ char *extra_table;
+ char *cur_extra_table;
+@@ -1034,31 +1060,6 @@ write_output (void)
+ char tmpfname[(output_file == NULL ? sizeof finalname : output_file_len + 1)
+ + strlen (".XXXXXX")];
+
+- /* Function to insert the names. */
+- auto void
+- name_insert (const void *nodep, VISIT value, int level)
+- {
+- struct name *name;
+- unsigned int idx;
+- unsigned int hval2;
+-
+- if (value != leaf && value != postorder)
+- return;
+-
+- name = *(struct name **) nodep;
+- idx = name->hashval % hash_size;
+- hval2 = 1 + name->hashval % (hash_size - 2);
+-
+- while (hash_table[idx].string_offset != 0)
+- if ((idx += hval2) >= hash_size)
+- idx -= hash_size;
+-
+- hash_table[idx].string_offset = strtaboffset (name->strent);
+-
+- assert (name->module_idx != -1);
+- hash_table[idx].module_idx = name->module_idx;
+- }
+-
+ /* Open the output file. */
+ if (output_file == NULL)
+ {
+--- glibc-2.3.6/include/features.h 18 Feb 2005 00:08:56 -0000 1.36.2.1
++++ glibc-2.3.6-fedora/include/features.h 18 Feb 2005 02:00:22 -0000 1.35.2.4.2.1
+@@ -262,7 +262,13 @@
+ # define __USE_REENTRANT 1
+ #endif
+
+-#if _FORTIFY_SOURCE > 0 && __GNUC_PREREQ (4, 1) && __OPTIMIZE__ > 0
++#if _FORTIFY_SOURCE > 0 && __OPTIMIZE__ > 0 \
++ && (__GNUC_PREREQ (4, 1) \
++ || (defined __GNUC_RH_RELEASE__ && __GNUC_PREREQ (4, 0)) \
++ || (defined __GNUC_RH_RELEASE__ && __GNUC_PREREQ (3, 4) \
++ && __GNUC_MINOR__ == 4 \
++ && (__GNUC_PATCHLEVEL__ > 2 \
++ || (__GNUC_PATCHLEVEL__ == 2 && __GNUC_RH_RELEASE__ >= 8))))
+ # if _FORTIFY_SOURCE == 1
+ # define __USE_FORTIFY_LEVEL 1
+ # elif _FORTIFY_SOURCE > 1
+--- glibc-2.3.6/intl/locale.alias 4 Dec 2003 07:57:47 -0000 1.23
++++ glibc-2.3.6-fedora/intl/locale.alias 22 Sep 2004 21:20:53 -0000 1.23.2.1
+@@ -58,8 +58,6 @@ korean ko_KR.eucKR
+ korean.euc ko_KR.eucKR
+ ko_KR ko_KR.eucKR
+ lithuanian lt_LT.ISO-8859-13
+-no_NO nb_NO.ISO-8859-1
+-no_NO.ISO-8859-1 nb_NO.ISO-8859-1
+ norwegian nb_NO.ISO-8859-1
+ nynorsk nn_NO.ISO-8859-1
+ polish pl_PL.ISO-8859-2
+--- glibc-2.3.6/libio/stdio.h 18 Oct 2004 04:17:15 -0000 1.79
++++ glibc-2.3.6-fedora/libio/stdio.h 18 Oct 2004 09:58:44 -0000 1.78.2.2
+@@ -142,10 +142,12 @@ typedef _G_fpos64_t fpos64_t;
+ extern struct _IO_FILE *stdin; /* Standard input stream. */
+ extern struct _IO_FILE *stdout; /* Standard output stream. */
+ extern struct _IO_FILE *stderr; /* Standard error output stream. */
++#ifdef __STDC__
+ /* C89/C99 say they're macros. Make them happy. */
+ #define stdin stdin
+ #define stdout stdout
+ #define stderr stderr
++#endif
+
+ __BEGIN_NAMESPACE_STD
+ /* Remove file FILENAME. */
+--- glibc-2.3.6/libio/bits/stdio2.h 18 Oct 2004 04:17:14 -0000 1.1
++++ glibc-2.3.6-fedora/libio/bits/stdio2.h 2 Nov 2004 13:30:19 -0000 1.1.2.2
+@@ -61,14 +61,25 @@ extern int __vfprintf_chk (FILE *__restr
+ extern int __vprintf_chk (int __flag, __const char *__restrict __format,
+ _G_va_list __ap);
+
+-# define printf(...) \
++# if __GNUC_PREREQ (4, 0)
++# define printf(...) \
+ __printf_chk (__USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
+-# define fprintf(stream, ...) \
++# define fprintf(stream, ...) \
+ __fprintf_chk (stream, __USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
+-# define vprintf(format, ap) \
++# define vprintf(format, ap) \
+ __vprintf_chk (__USE_FORTIFY_LEVEL - 1, format, ap)
+-# define vfprintf(stream, format, ap) \
++# define vfprintf(stream, format, ap) \
+ __vfprintf_chk (stream, __USE_FORTIFY_LEVEL - 1, format, ap)
++# else
++# define printf(...) \
++ __builtin___printf_chk (__USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
++# define fprintf(stream, ...) \
++ __builtin___fprintf_chk (stream, __USE_FORTIFY_LEVEL - 1, __VA_ARGS__)
++# define vprintf(format, ap) \
++ __builtin___vprintf_chk (__USE_FORTIFY_LEVEL - 1, format, ap)
++# define vfprintf(stream, format, ap) \
++ __builtin___vfprintf_chk (stream, __USE_FORTIFY_LEVEL - 1, format, ap)
++# endif
+
+ #endif
+
+--- glibc-2.3.6/linuxthreads/ChangeLog 17 Oct 2005 04:57:37 -0000 1.833.2.4
++++ glibc-2.3.6-fedora/linuxthreads/ChangeLog 17 Oct 2005 05:22:00 -0000 1.817.2.14.2.3
+@@ -764,6 +764,12 @@
+ (pthread_barrierattr_setpshared): Return EINVAL if pshared
+ is neither PTHREAD_PROCESS_PRIVATE nor PTHREAD_PROCESS_SHARED.
+
++2003-09-02 Jakub Jelinek <jakub@redhat.com>
++
++ * sysdeps/sparc/tls.h (TLS_TCB_SIZE): If in ld.so and NPTL struct
++ pthread is bigger than struct _pthread_descr_struct, use NPTL struct
++ pthread size.
++
+ 2003-09-02 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/unix/sysv/linux/i386/dl-sysdep.h
+@@ -896,6 +902,34 @@
+
+ 2003-07-22 Jakub Jelinek <jakub@redhat.com>
+
++ * sysdeps/alpha/tls.h (TLS_INIT_TCB_SIZE, TLS_TCB_SIZE): Change to 0.
++ (TLS_INIT_TCB_ALIGN, TLS_TCB_ALIGN): Alignment of struct
++ _pthread_descr_struct.
++ (TLS_PRE_TCB_SIZE): Add sizeof (tcbhead_t) and pad to align.
++ If in ld.so and NPTL struct pthread is bigger than struct
++ _pthread_descr_struct, use NPTL struct pthread size.
++ (TLS_TCB_OFFSET): Define.
++ (INSTALL_DTV, INSTALL_NEW_DTV, GET_DTV, TLS_INIT_TP, THREAD_DTV,
++ THREAD_SELF, INIT_THREAD_SELF): Changed to match NPTL tls.h
++ definitions.
++ * sysdeps/i386/tls.h (TLS_TCB_SIZE): If in ld.so and NPTL struct
++ pthread is bigger than struct _pthread_descr_struct, use NPTL struct
++ pthread size.
++ * sysdeps/ia64/tls.h (TLS_PRE_TCB_SIZE): Likewise.
++ * sysdeps/powerpc/tls.h (TLS_PRE_TCB_SIZE): Likewise.
++ * sysdeps/s390/tls.h (TLS_TCB_SIZE): Likewise.
++ * sysdeps/sh/tls.h (TLS_PRE_TCB_SIZE): Likewise.
++ * sysdeps/x86_64/tls.h (TLS_TCB_SIZE): Likewise.
++ * sysdeps/pthread/Makefile (gen-as-const-headers): Add
++ nptl-struct-pthread.sym if nptl tree is present.
++ (before-compile): Add $(common-objpfx)nptl-struct-pthread.h
++ if nptl tree is not present.
++ (common-generated): Add nptl-struct-pthread.h.
++ ($(common-objpfx)nptl-struct-pthread.h): New rule.
++ * sysdeps/pthread/nptl-struct-pthread.sym: New file.
++
++2003-07-22 Jakub Jelinek <jakub@redhat.com>
++
+ * descr.h (struct _pthread_descr_struct): Provide p_res member
+ even if USE_TLS && HAVE___THREAD.
+ * sysdeps/pthread/res-state.c (__res_state): Return __resp
+--- glibc-2.3.6/linuxthreads/Makefile 16 Feb 2005 11:26:38 -0000 1.96.2.2
++++ glibc-2.3.6-fedora/linuxthreads/Makefile 16 Feb 2005 19:56:54 -0000 1.94.2.3.2.1
+@@ -245,15 +245,18 @@ $(addprefix $(objpfx), \
+ $(filter-out $(tests-static) $(tests-reverse) unload, \
+ $(tests) $(test-srcs))): $(objpfx)libpthread.so \
+ $(objpfx)libpthread_nonshared.a
+-# $(objpfx)../libc.so is used instead of $(common-objpfx)libc.so,
++# $(objpfx)linklibc.so is used instead of $(common-objpfx)libc.so,
+ # since otherwise libpthread.so comes before libc.so when linking.
+ $(addprefix $(objpfx), $(tests-reverse)): \
+- $(objpfx)../libc.so $(objpfx)libpthread.so \
++ $(objpfx)linklibc.so $(objpfx)libpthread.so \
+ $(objpfx)libpthread_nonshared.a
+ $(objpfx)../libc.so: $(common-objpfx)libc.so ;
+ $(addprefix $(objpfx),$(librt-tests)): $(common-objpfx)rt/librt.so
+ $(objpfx)unload: $(common-objpfx)dlfcn/libdl.so
+ $(objpfx)unload.out: $(objpfx)libpthread.so $(objpfx)libpthread_nonshared.a
++$(objpfx)linklibc.so: $(common-objpfx)libc.so
++ ln -s ../libc.so $@
++generated += libclink.so
+ else
+ $(addprefix $(objpfx),$(tests) $(test-srcs)): $(objpfx)libpthread.a
+ $(addprefix $(objpfx),$(librt-tests)): $(common-objpfx)rt/librt.a
+--- glibc-2.3.6/linuxthreads/cancel.c 22 Feb 2003 00:55:21 -0000 1.23
++++ glibc-2.3.6-fedora/linuxthreads/cancel.c 22 Sep 2004 21:20:55 -0000 1.23.2.1
+@@ -230,5 +230,6 @@ void __pthread_perform_cleanup(char *cur
+ }
+
+ /* And the TSD which needs special help. */
++ THREAD_SETMEM (self, p_cancelstate, PTHREAD_CANCEL_DISABLE);
+ __libc_thread_freeres ();
+ }
+--- glibc-2.3.6/linuxthreads/lockfile.c 18 Dec 2002 01:16:46 -0000 1.10
++++ glibc-2.3.6-fedora/linuxthreads/lockfile.c 22 Sep 2004 21:20:55 -0000 1.10.2.1
+@@ -74,7 +74,11 @@ __fresetlockfiles (void)
+ __pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE_NP);
+
+ for (i = _IO_iter_begin(); i != _IO_iter_end(); i = _IO_iter_next(i))
+- __pthread_mutex_init (_IO_iter_file(i)->_lock, &attr);
++ {
++ _IO_lock_t *_lock = _IO_iter_file(i)->_lock;
++ if (_lock)
++ __pthread_mutex_init (_lock, &attr);
++ }
+
+ __pthread_mutexattr_destroy (&attr);
+
+--- glibc-2.3.6/linuxthreads/semaphore.h 17 Apr 2004 23:01:39 -0000 1.13
++++ glibc-2.3.6-fedora/linuxthreads/semaphore.h 22 Sep 2004 21:20:55 -0000 1.13.2.1
+@@ -21,6 +21,7 @@
+ # define __need_timespec
+ # include <time.h>
+ #endif
++#include <bits/pthreadtypes.h>
+
+ #ifndef _PTHREAD_DESCR_DEFINED
+ /* Thread descriptors. Needed for `sem_t' definition. */
+--- glibc-2.3.6/linuxthreads/tst-tls1.h 2 Sep 2003 00:29:30 -0000 1.1
++++ glibc-2.3.6-fedora/linuxthreads/tst-tls1.h 22 Sep 2004 21:20:55 -0000 1.1.2.1
+@@ -2,7 +2,7 @@
+ #include <stdlib.h>
+ #include <tls.h>
+
+-#if USE_TLS && HAVE___THREAD
++#if USE_TLS && (0 || HAVE___THREAD)
+
+ struct tls_obj
+ {
+--- glibc-2.3.6/linuxthreads/sysdeps/alpha/tls.h 30 Jan 2003 21:03:40 -0000 1.5
++++ glibc-2.3.6-fedora/linuxthreads/sysdeps/alpha/tls.h 22 Sep 2004 21:20:55 -0000 1.5.2.1
+@@ -53,54 +53,76 @@ typedef struct
+ # include <sysdep.h>
+
+ /* This is the size of the initial TCB. */
+-# define TLS_INIT_TCB_SIZE sizeof (tcbhead_t)
++# define TLS_INIT_TCB_SIZE 0
+
+ /* Alignment requirements for the initial TCB. */
+-# define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t)
++# define TLS_INIT_TCB_ALIGN __alignof__ (struct _pthread_descr_struct)
+
+ /* This is the size of the TCB. */
+-# define TLS_TCB_SIZE sizeof (tcbhead_t)
++# define TLS_TCB_SIZE 0
+
+ /* Alignment requirements for the TCB. */
+-# define TLS_TCB_ALIGN __alignof__ (tcbhead_t)
++# define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct)
+
+ /* This is the size we need before TCB. */
+-# define TLS_PRE_TCB_SIZE sizeof (struct _pthread_descr_struct)
++# ifndef IS_IN_rtld
++# define TLS_PRE_TCB_SIZE \
++ (sizeof (struct _pthread_descr_struct) \
++ + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1)))
++# else
++# include <nptl-struct-pthread.h>
++# define TLS_PRE_TCB_SIZE \
++ ((sizeof (struct _pthread_descr_struct) > NPTL_STRUCT_PTHREAD_SIZE \
++ ? sizeof (struct _pthread_descr_struct) : NPTL_STRUCT_PTHREAD_SIZE) \
++ + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1)))
++# endif
+
+ /* The DTV is allocated at the TP; the TCB is placed elsewhere. */
+ # define TLS_DTV_AT_TP 1
+
++/* The following assumes that TP (R2 or R13) points to the end of the
++ TCB + 0x7000 (per the ABI). This implies that TCB address is
++ TP - 0x7000. As we define TLS_DTV_AT_TP we can
++ assume that the pthread struct is allocated immediately ahead of the
++ TCB. This implies that the pthread_descr address is
++ TP - (TLS_PRE_TCB_SIZE + 0x7000). */
++/* ??? PPC uses offset 0x7000; seems like a good idea for alpha too,
++ but binutils not yet changed to match. */
++# define TLS_TCB_OFFSET 0
++
+ /* Install the dtv pointer. The pointer passed is to the element with
+ index -1 which contain the length. */
+ # define INSTALL_DTV(TCBP, DTVP) \
+- (((tcbhead_t *) (TCBP))->dtv = (DTVP) + 1)
++ (((tcbhead_t *) (TCBP))[-1].dtv = (DTVP) + 1)
+
+ /* Install new dtv for current thread. */
+ # define INSTALL_NEW_DTV(DTV) \
+- (((tcbhead_t *)__builtin_thread_pointer ())->dtv = (DTV))
++ (THREAD_DTV() = (DTV))
+
+ /* Return dtv of given thread descriptor. */
+ # define GET_DTV(TCBP) \
+- (((tcbhead_t *) (TCBP))->dtv)
++ (((tcbhead_t *) (TCBP))[-1].dtv)
+
+ /* Code to initially initialize the thread pointer. This might need
+ special attention since 'errno' is not yet available and if the
+ operation can cause a failure 'errno' must not be touched. */
+ # define TLS_INIT_TP(TCBP, SECONDCALL) \
+- (__builtin_set_thread_pointer (TCBP), 0)
++ (__builtin_set_thread_pointer ((void *) (TCBP) + TLS_TCB_OFFSET), NULL)
+
+ /* Return the address of the dtv for the current thread. */
+ # define THREAD_DTV() \
+- (((tcbhead_t *)__builtin_thread_pointer ())->dtv)
++ (((tcbhead_t *) (__builtin_thread_pointer () - TLS_TCB_OFFSET))[-1].dtv)
+
+ /* Return the thread descriptor for the current thread. */
+ # undef THREAD_SELF
+ # define THREAD_SELF \
+- ((pthread_descr)__builtin_thread_pointer () - 1)
++ ((pthread_descr) (__builtin_thread_pointer () \
++ - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE))
+
+ # undef INIT_THREAD_SELF
+ # define INIT_THREAD_SELF(DESCR, NR) \
+- __builtin_set_thread_pointer ((struct _pthread_descr_struct *)(DESCR) + 1)
++ __builtin_set_thread_pointer ((char *)(DESCR) \
++ + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE)
+
+ /* Get the thread descriptor definition. */
+ # include <linuxthreads/descr.h>
+--- glibc-2.3.6/linuxthreads/sysdeps/i386/tls.h 19 Oct 2004 05:12:58 -0000 1.37
++++ glibc-2.3.6-fedora/linuxthreads/sysdeps/i386/tls.h 20 Oct 2004 10:47:17 -0000 1.35.2.4
+@@ -81,7 +81,14 @@ typedef struct
+ # define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t)
+
+ /* This is the size of the TCB. */
+-# define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct)
++# ifndef IS_IN_rtld
++# define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct)
++# else
++# include <nptl-struct-pthread.h>
++# define TLS_TCB_SIZE \
++ (sizeof (struct _pthread_descr_struct) > NPTL_STRUCT_PTHREAD_SIZE \
++ ? sizeof (struct _pthread_descr_struct) : NPTL_STRUCT_PTHREAD_SIZE)
++# endif
+
+ /* Alignment requirements for the TCB. */
+ # define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct)
+--- glibc-2.3.6/linuxthreads/sysdeps/ia64/tls.h 8 Jul 2004 21:20:57 -0000 1.9
++++ glibc-2.3.6-fedora/linuxthreads/sysdeps/ia64/tls.h 22 Sep 2004 21:20:55 -0000 1.9.2.1
+@@ -60,7 +60,14 @@ typedef struct
+ # define TLS_TCB_SIZE sizeof (tcbhead_t)
+
+ /* This is the size we need before TCB. */
+-# define TLS_PRE_TCB_SIZE sizeof (struct _pthread_descr_struct)
++# ifndef IS_IN_rtld
++# define TLS_PRE_TCB_SIZE sizeof (struct _pthread_descr_struct)
++# else
++# include <nptl-struct-pthread.h>
++# define TLS_PRE_TCB_SIZE \
++ (sizeof (struct _pthread_descr_struct) > NPTL_STRUCT_PTHREAD_SIZE \
++ ? sizeof (struct _pthread_descr_struct) : NPTL_STRUCT_PTHREAD_SIZE)
++# endif
+
+ /* Alignment requirements for the TCB. */
+ # define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct)
+--- glibc-2.3.6/linuxthreads/sysdeps/powerpc/tls.h 9 Apr 2004 19:09:42 -0000 1.8
++++ glibc-2.3.6-fedora/linuxthreads/sysdeps/powerpc/tls.h 22 Sep 2004 21:20:55 -0000 1.8.2.1
+@@ -64,11 +64,19 @@ typedef struct
+ # define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct)
+
+ /* This is the size we need before TCB. */
+-# define TLS_PRE_TCB_SIZE \
++# ifndef IS_IN_rtld
++# define TLS_PRE_TCB_SIZE \
+ (sizeof (struct _pthread_descr_struct) \
+ + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1)))
++# else
++# include <nptl-struct-pthread.h>
++# define TLS_PRE_TCB_SIZE \
++ ((sizeof (struct _pthread_descr_struct) > NPTL_STRUCT_PTHREAD_SIZE \
++ ? sizeof (struct _pthread_descr_struct) : NPTL_STRUCT_PTHREAD_SIZE) \
++ + ((sizeof (tcbhead_t) + TLS_TCB_ALIGN - 1) & ~(TLS_TCB_ALIGN - 1)))
++# endif
+
+-/* The following assumes that TP (R2 or R13) is points to the end of the
++/* The following assumes that TP (R2 or R13) points to the end of the
+ TCB + 0x7000 (per the ABI). This implies that TCB address is
+ TP - 0x7000. As we define TLS_DTV_AT_TP we can
+ assume that the pthread_descr is allocated immediately ahead of the
+--- glibc-2.3.6/linuxthreads/sysdeps/pthread/Makefile 14 Aug 2003 00:14:22 -0000 1.7
++++ glibc-2.3.6-fedora/linuxthreads/sysdeps/pthread/Makefile 22 Sep 2004 21:20:56 -0000 1.7.2.1
+@@ -12,3 +12,15 @@ endif
+ ifeq ($(subdir),posix)
+ CFLAGS-confstr.c += -DLIBPTHREAD_VERSION="\"$(shell sed 's/\(.*\) by .*/\1/' ../linuxthreads/Banner)\""
+ endif
++
++ifeq ($(subdir),csu)
++# Find out the size of NPTL struct pthread
++ifneq (,$(wildcard $(..)nptl/descr.h))
++gen-as-const-headers += nptl-struct-pthread.sym
++else
++before-compile += $(common-objpfx)nptl-struct-pthread.h
++common-generated += nptl-struct-pthread.h
++$(common-objpfx)nptl-struct-pthread.h:
++ @echo '#define NPTL_STRUCT_PTHREAD_SIZE 0' > $@
++endif
++endif
+--- glibc-2.3.6/linuxthreads/sysdeps/pthread/nptl-struct-pthread.sym 1 Jan 1970 00:00:00 -0000
++++ glibc-2.3.6-fedora/linuxthreads/sysdeps/pthread/nptl-struct-pthread.sym 22 Sep 2004 21:20:56 -0000 1.1.2.1
+@@ -0,0 +1,13 @@
++#ifdef HAVE_TLS_SUPPORT
++# ifndef HAVE_FORCED_UNWIND
++# define HAVE_FORCED_UNWIND 1
++# endif
++# define __need_struct_pthread_size
++# include <nptl/descr.h>
++#endif
++
++--
++
++#ifdef HAVE_TLS_SUPPORT
++NPTL_STRUCT_PTHREAD_SIZE sizeof (struct pthread)
++#endif
+--- glibc-2.3.6/linuxthreads/sysdeps/s390/tls.h 30 Jan 2003 18:34:11 -0000 1.3
++++ glibc-2.3.6-fedora/linuxthreads/sysdeps/s390/tls.h 22 Sep 2004 21:20:56 -0000 1.3.2.1
+@@ -72,7 +72,14 @@ typedef struct
+ # define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t)
+
+ /* This is the size of the TCB. */
+-# define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct)
++# ifndef IS_IN_rtld
++# define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct)
++# else
++# include <nptl-struct-pthread.h>
++# define TLS_TCB_SIZE \
++ (sizeof (struct _pthread_descr_struct) > NPTL_STRUCT_PTHREAD_SIZE \
++ ? sizeof (struct _pthread_descr_struct) : NPTL_STRUCT_PTHREAD_SIZE)
++# endif
+
+ /* Alignment requirements for the TCB. */
+ # define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct)
+--- glibc-2.3.6/linuxthreads/sysdeps/sh/tls.h 2 Mar 2003 11:44:20 -0000 1.9
++++ glibc-2.3.6-fedora/linuxthreads/sysdeps/sh/tls.h 22 Sep 2004 21:20:57 -0000 1.9.2.1
+@@ -64,7 +64,14 @@ typedef struct
+ # define TLS_TCB_SIZE sizeof (tcbhead_t)
+
+ /* This is the size we need before TCB. */
+-# define TLS_PRE_TCB_SIZE sizeof (struct _pthread_descr_struct)
++# ifndef IS_IN_rtld
++# define TLS_PRE_TCB_SIZE sizeof (struct _pthread_descr_struct)
++# else
++# include <nptl-struct-pthread.h>
++# define TLS_PRE_TCB_SIZE \
++ (sizeof (struct _pthread_descr_struct) > NPTL_STRUCT_PTHREAD_SIZE \
++ ? sizeof (struct _pthread_descr_struct) : NPTL_STRUCT_PTHREAD_SIZE)
++# endif
+
+ /* Alignment requirements for the TCB. */
+ # define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct)
+--- glibc-2.3.6/linuxthreads/sysdeps/sparc/tls.h 4 Feb 2003 20:41:02 -0000 1.3
++++ glibc-2.3.6-fedora/linuxthreads/sysdeps/sparc/tls.h 22 Sep 2004 21:20:57 -0000 1.3.2.1
+@@ -64,7 +64,14 @@ typedef struct
+ # define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t)
+
+ /* This is the size of the TCB. */
+-# define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct)
++# ifndef IS_IN_rtld
++# define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct)
++# else
++# include <nptl-struct-pthread.h>
++# define TLS_TCB_SIZE \
++ (sizeof (struct _pthread_descr_struct) > NPTL_STRUCT_PTHREAD_SIZE \
++ ? sizeof (struct _pthread_descr_struct) : NPTL_STRUCT_PTHREAD_SIZE)
++# endif
+
+ /* Alignment requirements for the TCB. */
+ # define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct)
+--- glibc-2.3.6/linuxthreads/sysdeps/x86_64/tls.h 18 Apr 2004 02:32:25 -0000 1.6
++++ glibc-2.3.6-fedora/linuxthreads/sysdeps/x86_64/tls.h 22 Sep 2004 21:20:57 -0000 1.6.2.1
+@@ -66,7 +66,14 @@ typedef struct
+ # define TLS_INIT_TCB_ALIGN __alignof__ (tcbhead_t)
+
+ /* This is the size of the TCB. */
+-# define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct)
++# ifndef IS_IN_rtld
++# define TLS_TCB_SIZE sizeof (struct _pthread_descr_struct)
++# else
++# include <nptl-struct-pthread.h>
++# define TLS_TCB_SIZE \
++ (sizeof (struct _pthread_descr_struct) > NPTL_STRUCT_PTHREAD_SIZE \
++ ? sizeof (struct _pthread_descr_struct) : NPTL_STRUCT_PTHREAD_SIZE)
++# endif
+
+ /* Alignment requirements for the TCB. */
+ # define TLS_TCB_ALIGN __alignof__ (struct _pthread_descr_struct)
+--- glibc-2.3.6/locale/iso-4217.def 18 Jul 2005 01:47:31 -0000 1.15.4.1
++++ glibc-2.3.6-fedora/locale/iso-4217.def 18 Jul 2005 04:40:54 -0000 1.15.2.1.2.1
+@@ -8,6 +8,7 @@
+ *
+ * !!! The list has to be sorted !!!
+ */
++DEFINE_INT_CURR("ADP") /* Andorran Peseta -> EUR */
+ DEFINE_INT_CURR("AED") /* United Arab Emirates Dirham */
+ DEFINE_INT_CURR("AFA") /* Afghanistan Afgani */
+ DEFINE_INT_CURR("ALL") /* Albanian Lek */
+@@ -15,12 +16,14 @@ DEFINE_INT_CURR("AMD") /* Armenia Dram
+ DEFINE_INT_CURR("ANG") /* Netherlands Antilles */
+ DEFINE_INT_CURR("AOA") /* Angolan Kwanza */
+ DEFINE_INT_CURR("ARS") /* Argentine Peso */
++DEFINE_INT_CURR("ATS") /* Austrian Schilling -> EUR */
+ DEFINE_INT_CURR("AUD") /* Australian Dollar */
+ DEFINE_INT_CURR("AWG") /* Aruba Guilder */
+ DEFINE_INT_CURR("AZM") /* Azerbaijan Manat */
+ DEFINE_INT_CURR("BAK") /* Bosnian and Herzegovina Convertible Mark */
+ DEFINE_INT_CURR("BBD") /* Barbados Dollar */
+ DEFINE_INT_CURR("BDT") /* Bangladesh Taka */
++DEFINE_INT_CURR("BEF") /* Belgian Franc -> EUR */
+ DEFINE_INT_CURR("BGL") /* Bulgarian Lev */
+ DEFINE_INT_CURR("BHD") /* Bahraini Dinar */
+ DEFINE_INT_CURR("BIF") /* Burundi Franc */
+@@ -45,6 +48,7 @@ DEFINE_INT_CURR("CUP") /* Cuban Peso *
+ DEFINE_INT_CURR("CVE") /* Cape Verde Escudo */
+ DEFINE_INT_CURR("CYP") /* Cypriot Pound */
+ DEFINE_INT_CURR("CZK") /* Czech Koruna */
++DEFINE_INT_CURR("DEM") /* German Mark -> EUR */
+ DEFINE_INT_CURR("DJF") /* Djibouti Franc */
+ DEFINE_INT_CURR("DKK") /* Danish Krone (Faroe Islands, Greenland) */
+ DEFINE_INT_CURR("DOP") /* Dominican Republic */
+@@ -52,16 +56,20 @@ DEFINE_INT_CURR("DZD") /* Algerian Dina
+ DEFINE_INT_CURR("EEK") /* Estonian Kroon */
+ DEFINE_INT_CURR("EGP") /* Egyptian Pound */
+ DEFINE_INT_CURR("ERN") /* Eritrean Nakfa */
++DEFINE_INT_CURR("ESP") /* Spanish Peseta -> EUR */
+ DEFINE_INT_CURR("ETB") /* Ethiopian Birr */
+ DEFINE_INT_CURR("EUR") /* European Union Euro */
++DEFINE_INT_CURR("FIM") /* Finnish Markka -> EUR */
+ DEFINE_INT_CURR("FJD") /* Fiji Dollar */
+ DEFINE_INT_CURR("FKP") /* Falkland Islands Pound (Malvinas) */
++DEFINE_INT_CURR("FRF") /* French Franc -> EUR */
+ DEFINE_INT_CURR("GBP") /* British Pound */
+ DEFINE_INT_CURR("GEL") /* Georgia Lari */
+ DEFINE_INT_CURR("GHC") /* Ghana Cedi */
+ DEFINE_INT_CURR("GIP") /* Gibraltar Pound */
+ DEFINE_INT_CURR("GMD") /* Gambian Dalasi */
+ DEFINE_INT_CURR("GNF") /* Guinea Franc */
++DEFINE_INT_CURR("GRD") /* Greek Drachma -> EUR */
+ DEFINE_INT_CURR("GTQ") /* Guatemala Quetzal */
+ DEFINE_INT_CURR("GYD") /* Guyana Dollar */
+ DEFINE_INT_CURR("HKD") /* Hong Kong Dollar */
+@@ -70,12 +78,14 @@ DEFINE_INT_CURR("HRK") /* Croatia Kuna
+ DEFINE_INT_CURR("HTG") /* Haiti Gourde */
+ DEFINE_INT_CURR("HUF") /* Hungarian Forint */
+ DEFINE_INT_CURR("IDR") /* Indonesia Rupiah */
++DEFINE_INT_CURR("IEP") /* Irish Pound -> EUR */
+ DEFINE_INT_CURR("ILS") /* Israeli Shekel */
+ DEFINE_INT_CURR("IMP") /* Isle of Man Pounds */
+ DEFINE_INT_CURR("INR") /* Indian Rupee (Bhutan) */
+ DEFINE_INT_CURR("IQD") /* Iraqi Dinar */
+ DEFINE_INT_CURR("IRR") /* Iranian Rial */
+ DEFINE_INT_CURR("ISK") /* Iceland Krona */
++DEFINE_INT_CURR("ITL") /* Italian Lira -> EUR */
+ DEFINE_INT_CURR("JMD") /* Jamaican Dollar */
+ DEFINE_INT_CURR("JOD") /* Jordanian Dinar */
+ DEFINE_INT_CURR("JPY") /* Japanese Yen */
+@@ -94,6 +104,7 @@ DEFINE_INT_CURR("LKR") /* Sri Lankan Ru
+ DEFINE_INT_CURR("LRD") /* Liberian Dollar */
+ DEFINE_INT_CURR("LSL") /* Lesotho Maloti */
+ DEFINE_INT_CURR("LTL") /* Lithuanian Litas */
++DEFINE_INT_CURR("LUF") /* Luxembourg Franc -> EUR */
+ DEFINE_INT_CURR("LVL") /* Latvia Lat */
+ DEFINE_INT_CURR("LYD") /* Libyan Arab Jamahiriya Dinar */
+ DEFINE_INT_CURR("MAD") /* Moroccan Dirham */
+@@ -114,6 +125,7 @@ DEFINE_INT_CURR("MZM") /* Mozambique Me
+ DEFINE_INT_CURR("NAD") /* Namibia Dollar */
+ DEFINE_INT_CURR("NGN") /* Nigeria Naira */
+ DEFINE_INT_CURR("NIO") /* Nicaragua Cordoba Oro */
++DEFINE_INT_CURR("NLG") /* Netherlands Guilder -> EUR */
+ DEFINE_INT_CURR("NOK") /* Norwegian Krone */
+ DEFINE_INT_CURR("NPR") /* Nepalese Rupee */
+ DEFINE_INT_CURR("NZD") /* New Zealand Dollar */
+@@ -124,6 +136,7 @@ DEFINE_INT_CURR("PGK") /* Papau New Gui
+ DEFINE_INT_CURR("PHP") /* Philippines Peso */
+ DEFINE_INT_CURR("PKR") /* Pakistan Rupee */
+ DEFINE_INT_CURR("PLN") /* Polish Zloty */
++DEFINE_INT_CURR("PTE") /* Portugese Escudo -> EUR */
+ DEFINE_INT_CURR("PYG") /* Paraguay Guarani */
+ DEFINE_INT_CURR("QAR") /* Qatar Rial */
+ DEFINE_INT_CURR("ROL") /* Romanian Leu */
+--- glibc-2.3.6/locale/programs/3level.h 13 Jun 2003 20:45:38 -0000 1.5
++++ glibc-2.3.6-fedora/locale/programs/3level.h 22 Sep 2004 21:20:58 -0000 1.5.2.1
+@@ -204,6 +204,42 @@ CONCAT(TABLE,_iterate) (struct TABLE *t,
+ }
+ }
+ }
++
++/* GCC ATM seems to do a poor job with pointers to nested functions passed
++ to inlined functions. Help it a little bit with this hack. */
++#define wchead_table_iterate(tp, fn) \
++do \
++ { \
++ struct wchead_table *t = (tp); \
++ uint32_t index1; \
++ for (index1 = 0; index1 < t->level1_size; index1++) \
++ { \
++ uint32_t lookup1 = t->level1[index1]; \
++ if (lookup1 != ((uint32_t) ~0)) \
++ { \
++ uint32_t lookup1_shifted = lookup1 << t->q; \
++ uint32_t index2; \
++ for (index2 = 0; index2 < (1 << t->q); index2++) \
++ { \
++ uint32_t lookup2 = t->level2[index2 + lookup1_shifted]; \
++ if (lookup2 != ((uint32_t) ~0)) \
++ { \
++ uint32_t lookup2_shifted = lookup2 << t->p; \
++ uint32_t index3; \
++ for (index3 = 0; index3 < (1 << t->p); index3++) \
++ { \
++ struct element_t *lookup3 \
++ = t->level3[index3 + lookup2_shifted]; \
++ if (lookup3 != NULL) \
++ fn ((((index1 << t->q) + index2) << t->p) + index3, \
++ lookup3); \
++ } \
++ } \
++ } \
++ } \
++ } \
++ } while (0)
++
+ #endif
+
+ #ifndef NO_FINALIZE
+--- glibc-2.3.6/localedata/Makefile 7 Aug 2004 23:38:13 -0000 1.101
++++ glibc-2.3.6-fedora/localedata/Makefile 22 Sep 2004 21:20:58 -0000 1.101.2.1
+@@ -222,6 +222,7 @@ $(INSTALL-SUPPORTED-LOCALES): install-lo
+ echo -n '...'; \
+ input=`echo $$locale | sed 's/\([^.]*\)[^@]*\(.*\)/\1\2/'`; \
+ $(LOCALEDEF) --alias-file=../intl/locale.alias \
++ --no-archive \
+ -i locales/$$input -c -f charmaps/$$charset \
+ $(addprefix --prefix=,$(install_root)) $$locale; \
+ echo ' done'; \
+--- glibc-2.3.6/localedata/SUPPORTED 18 Jul 2005 01:50:35 -0000 1.72.2.2
++++ glibc-2.3.6-fedora/localedata/SUPPORTED 18 Jul 2005 04:40:55 -0000 1.71.2.2.2.1
+@@ -68,6 +68,7 @@ cy_GB.UTF-8/UTF-8 \
+ cy_GB/ISO-8859-14 \
+ da_DK.UTF-8/UTF-8 \
+ da_DK/ISO-8859-1 \
++da_DK.ISO-8859-15/ISO-8859-15 \
+ de_AT.UTF-8/UTF-8 \
+ de_AT/ISO-8859-1 \
+ de_AT@euro/ISO-8859-15 \
+@@ -94,6 +95,7 @@ en_DK.UTF-8/UTF-8 \
+ en_DK/ISO-8859-1 \
+ en_GB.UTF-8/UTF-8 \
+ en_GB/ISO-8859-1 \
++en_GB.ISO-8859-15/ISO-8859-15 \
+ en_HK.UTF-8/UTF-8 \
+ en_HK/ISO-8859-1 \
+ en_IE.UTF-8/UTF-8 \
+@@ -108,6 +110,7 @@ en_SG.UTF-8/UTF-8 \
+ en_SG/ISO-8859-1 \
+ en_US.UTF-8/UTF-8 \
+ en_US/ISO-8859-1 \
++en_US.ISO-8859-15/ISO-8859-15 \
+ en_ZA.UTF-8/UTF-8 \
+ en_ZA/ISO-8859-1 \
+ en_ZW.UTF-8/UTF-8 \
+@@ -253,6 +256,8 @@ nl_NL/ISO-8859-1 \
+ nl_NL@euro/ISO-8859-15 \
+ nn_NO.UTF-8/UTF-8 \
+ nn_NO/ISO-8859-1 \
++no_NO.UTF-8/UTF-8 \
++no_NO/ISO-8859-1 \
+ oc_FR.UTF-8/UTF-8 \
+ oc_FR/ISO-8859-1 \
+ om_ET/UTF-8 \
+@@ -297,6 +302,7 @@ sv_FI/ISO-8859-1 \
+ sv_FI@euro/ISO-8859-15 \
+ sv_SE.UTF-8/UTF-8 \
+ sv_SE/ISO-8859-1 \
++sv_SE.ISO-8859-15/ISO-8859-15 \
+ ta_IN/UTF-8 \
+ te_IN/UTF-8 \
+ tg_TJ.UTF-8/UTF-8 \
+--- glibc-2.3.6/localedata/locales/cy_GB 28 Sep 2004 04:37:33 -0000 1.4
++++ glibc-2.3.6-fedora/localedata/locales/cy_GB 29 Sep 2004 08:48:23 -0000 1.3.2.2
+@@ -248,8 +248,11 @@ mon "<U0049><U006F><U006E><U0061
+ d_t_fmt "<U0044><U0079><U0064><U0064><U0020><U0025><U0041><U0020><U0025><U0064><U0020><U006d><U0069><U0073><U0020><U0025><U0042><U0020><U0025><U0059><U0020><U0025><U0054><U0020><U0025><U005A>"
+ d_fmt "<U0025><U0064><U002E><U0025><U006D><U002E><U0025><U0079>"
+ t_fmt "<U0025><U0054>"
+-am_pm "";""
+-t_fmt_ampm ""
++am_pm "<U0041><U004D>";"<U0050><U004D>"
++t_fmt_ampm "<U0025><U006C><U003A><U0025><U004D><U003A><U0025><U0053><U0020><U0025><U0050><U0020><U0025><U005A>"
++date_fmt "<U0025><U0061><U0020><U0025><U0062><U0020><U0025><U0065>/
++<U0020><U0025><U0048><U003A><U0025><U004D><U003A><U0025><U0053><U0020>/
++<U0025><U005A><U0020><U0025><U0059>"
+ END LC_TIME
+
+ LC_MESSAGES
+--- glibc-2.3.6/localedata/locales/en_GB 31 Oct 2004 23:42:26 -0000 1.12
++++ glibc-2.3.6-fedora/localedata/locales/en_GB 2 Nov 2004 12:25:47 -0000 1.10.2.2
+@@ -112,8 +112,8 @@ mon "<U004A><U0061><U006E><U0075
+ d_t_fmt "<U0025><U0061><U0020><U0025><U0064><U0020><U0025><U0062><U0020><U0025><U0059><U0020><U0025><U0054><U0020><U0025><U005A>"
+ d_fmt "<U0025><U0064><U002F><U0025><U006D><U002F><U0025><U0079>"
+ t_fmt "<U0025><U0054>"
+-am_pm "";""
+-t_fmt_ampm ""
++am_pm "<U0041><U004D>";"<U0050><U004D>"
++t_fmt_ampm "<U0025><U006C><U003A><U0025><U004D><U003A><U0025><U0053><U0020><U0025><U0050><U0020><U0025><U005A>"
+ date_fmt "<U0025><U0061><U0020><U0025><U0062><U0020><U0025><U0065>/
+ <U0020><U0025><U0048><U003A><U0025><U004D><U003A><U0025><U0053><U0020>/
+ <U0025><U005A><U0020><U0025><U0059>"
+--- glibc-2.3.6/localedata/locales/en_US 31 Oct 2004 23:42:26 -0000 1.9
++++ glibc-2.3.6-fedora/localedata/locales/en_US 2 Nov 2004 12:25:47 -0000 1.7.2.2
+@@ -100,7 +100,6 @@ mon "<U004A><U0061><U006E><U0075><U0061>
+ "<U004F><U0063><U0074><U006F><U0062><U0065><U0072>";/
+ "<U004E><U006F><U0076><U0065><U006D><U0062><U0065><U0072>";/
+ "<U0044><U0065><U0063><U0065><U006D><U0062><U0065><U0072>"
+-am_pm "";""
+ % Appropriate date and time representation (%c)
+ % "%a %d %b %Y %r %Z"
+ d_t_fmt "<U0025><U0061><U0020><U0025><U0064><U0020><U0025><U0062><U0020><U0025><U0059><U0020><U0025><U0072><U0020><U0025><U005A>"
+--- glibc-2.3.6/localedata/locales/no_NO 1 Jan 1970 00:00:00 -0000
++++ glibc-2.3.6-fedora/localedata/locales/no_NO 22 Sep 2004 21:21:01 -0000 1.11.2.1
+@@ -0,0 +1,69 @@
++escape_char /
++comment_char %
++
++% Norwegian language locale for Norway
++% Source: Norsk Standardiseringsforbund
++% Address: University Library,
++% Drammensveien 41, N-9242 Oslo, Norge
++% Contact: Kolbjoern Aamboe
++% Tel: +47 - 22859109
++% Fax: +47 - 22434497
++% Email: kolbjorn.aambo@usit.uio.no
++% Language: no
++% Territory: NO
++% Revision: 4.3
++% Date: 1996-10-15
++% Application: general
++% Users: general
++% Repertoiremap: mnemonic.ds
++% Charset: ISO-8859-1
++% Distribution and use is free, also
++% for commercial purposes.
++
++LC_IDENTIFICATION
++copy "nb_NO"
++END LC_IDENTIFICATION
++
++LC_COLLATE
++copy "nb_NO"
++END LC_COLLATE
++
++LC_CTYPE
++copy "nb_NO"
++END LC_CTYPE
++
++LC_MONETARY
++copy "nb_NO"
++END LC_MONETARY
++
++LC_NUMERIC
++copy "nb_NO"
++END LC_NUMERIC
++
++LC_TIME
++copy "nb_NO"
++END LC_TIME
++
++LC_MESSAGES
++copy "nb_NO"
++END LC_MESSAGES
++
++LC_PAPER
++copy "nb_NO"
++END LC_PAPER
++
++LC_TELEPHONE
++copy "nb_NO"
++END LC_TELEPHONE
++
++LC_MEASUREMENT
++copy "nb_NO"
++END LC_MEASUREMENT
++
++LC_NAME
++copy "nb_NO"
++END LC_NAME
++
++LC_ADDRESS
++copy "nb_NO"
++END LC_ADDRESS
+--- glibc-2.3.6/localedata/locales/zh_TW 31 Oct 2004 23:42:28 -0000 1.7
++++ glibc-2.3.6-fedora/localedata/locales/zh_TW 2 Nov 2004 12:25:57 -0000 1.5.2.2
+@@ -1,7 +1,7 @@
+ comment_char %
+ escape_char /
+ %
+-% Chinese language locale for Taiwan R.O.C.
++% Chinese language locale for Taiwan
+ % charmap: BIG5-CP950
+ %
+ % Original Author:
+@@ -17,7 +17,7 @@ escape_char /
+ % Reference: http://wwwold.dkuug.dk/JTC1/SC22/WG20/docs/n690.pdf
+
+ LC_IDENTIFICATION
+-title "Chinese locale for Taiwan R.O.C."
++title "Chinese locale for Taiwan"
+ source ""
+ address ""
+ contact ""
+@@ -25,7 +25,7 @@ email "bug-glibc-locales@gnu.org"
+ tel ""
+ fax ""
+ language "Chinese"
+-territory "Taiwan R.O.C."
++territory "Taiwan"
+ revision "0.2"
+ date "2000-08-02"
+ %
+--- glibc-2.3.6/nptl/ChangeLog 24 Oct 2005 20:50:59 -0000 1.756.2.11
++++ glibc-2.3.6-fedora/nptl/ChangeLog 4 Nov 2005 01:07:47 -0000 1.706.2.33.2.7
+@@ -561,6 +561,11 @@
+ Move definition inside libpthread, libc, librt check. Provide
+ definition for rtld.
+
++2004-09-02 Jakub Jelinek <jakub@redhat.com>
++
++ * pthread_cond_destroy.c (__pthread_cond_destroy): If there are
++ waiters, awake all waiters on the associated mutex.
++
+ 2004-09-02 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/alpha/jmpbuf-unwind.h: Define __libc_unwind_longjmp.
+@@ -2635,6 +2640,11 @@
+
+ * Makefile [$(build-shared) = yes] (tests): Depend on $(test-modules).
+
++2003-07-22 Jakub Jelinek <jakub@redhat.com>
++
++ * descr.h: Don't include lowlevellock.h, pthreaddef.h and dl-sysdep.h
++ if __need_struct_pthread_size, instead define lll_lock_t.
++
+ 2003-07-25 Jakub Jelinek <jakub@redhat.com>
+
+ * tst-cancel17.c (do_test): Check if aio_cancel failed.
+--- glibc-2.3.6/nptl/Makefile 18 Jul 2005 03:20:10 -0000 1.165.2.2
++++ glibc-2.3.6-fedora/nptl/Makefile 18 Jul 2005 04:41:02 -0000 1.157.2.8.2.2
+@@ -500,15 +500,19 @@ $(addprefix $(objpfx), \
+ $(tests) $(xtests) $(test-srcs))): $(objpfx)libpthread.so \
+ $(objpfx)libpthread_nonshared.a
+ $(objpfx)tst-unload: $(common-objpfx)dlfcn/libdl.so
+-# $(objpfx)../libc.so is used instead of $(common-objpfx)libc.so,
++# $(objpfx)linklibc.so is used instead of $(common-objpfx)libc.so,
+ # since otherwise libpthread.so comes before libc.so when linking.
+ $(addprefix $(objpfx), $(tests-reverse)): \
+- $(objpfx)../libc.so $(objpfx)libpthread.so \
++ $(objpfx)linklibc.so $(objpfx)libpthread.so \
+ $(objpfx)libpthread_nonshared.a
+ $(objpfx)../libc.so: $(common-objpfx)libc.so ;
+ $(addprefix $(objpfx),$(tests-static) $(xtests-static)): $(objpfx)libpthread.a
+
+ $(objpfx)tst-atfork2.out: $(objpfx)tst-atfork2mod.so
++
++$(objpfx)linklibc.so: $(common-objpfx)libc.so
++ ln -s ../libc.so $@
++generated += libclink.so
+ else
+ $(addprefix $(objpfx),$(tests) $(test-srcs)): $(objpfx)libpthread.a
+ endif
+--- glibc-2.3.6/nptl/descr.h 12 Nov 2004 01:24:24 -0000 1.25
++++ glibc-2.3.6-fedora/nptl/descr.h 12 Nov 2004 16:56:12 -0000 1.23.2.3
+@@ -27,9 +27,13 @@
+ #include <sys/types.h>
+ #include <hp-timing.h>
+ #include <list.h>
++#ifdef __need_struct_pthread_size
++#define lll_lock_t int
++#else
+ #include <lowlevellock.h>
+ #include <pthreaddef.h>
+ #include <dl-sysdep.h>
++#endif
+ #include "../nptl_db/thread_db.h"
+ #include <tls.h>
+ #ifdef HAVE_FORCED_UNWIND
+--- glibc-2.3.6/nptl/pthread_cond_destroy.c 2 Sep 2004 18:45:37 -0000 1.5
++++ glibc-2.3.6-fedora/nptl/pthread_cond_destroy.c 22 Sep 2004 21:21:01 -0000 1.5.2.1
+@@ -44,15 +44,35 @@ __pthread_cond_destroy (cond)
+ broadcasted, but still are using the pthread_cond_t structure,
+ pthread_cond_destroy needs to wait for them. */
+ unsigned int nwaiters = cond->__data.__nwaiters;
+- while (nwaiters >= (1 << COND_CLOCK_BITS))
++
++ if (nwaiters >= (1 << COND_CLOCK_BITS))
+ {
+- lll_mutex_unlock (cond->__data.__lock);
++ /* Wake everybody on the associated mutex in case there are
++ threads that have been requeued to it.
++ Without this, pthread_cond_destroy could block potentially
++ for a long time or forever, as it would depend on other
++ thread's using the mutex.
++ When all threads waiting on the mutex are woken up, pthread_cond_wait
++ only waits for threads to acquire and release the internal
++ condvar lock. */
++ if (cond->__data.__mutex != NULL
++ && cond->__data.__mutex != (void *) ~0l)
++ {
++ pthread_mutex_t *mut = (pthread_mutex_t *) cond->__data.__mutex;
++ lll_futex_wake (&mut->__data.__lock, INT_MAX);
++ }
++
++ do
++ {
++ lll_mutex_unlock (cond->__data.__lock);
+
+- lll_futex_wait (&cond->__data.__nwaiters, nwaiters);
++ lll_futex_wait (&cond->__data.__nwaiters, nwaiters);
+
+- lll_mutex_lock (cond->__data.__lock);
++ lll_mutex_lock (cond->__data.__lock);
+
+- nwaiters = cond->__data.__nwaiters;
++ nwaiters = cond->__data.__nwaiters;
++ }
++ while (nwaiters >= (1 << COND_CLOCK_BITS));
+ }
+
+ return 0;
+--- glibc-2.3.6/nptl/sysdeps/unix/sysv/linux/kernel-features.h 1 Jan 1970 00:00:00 -0000
++++ glibc-2.3.6-fedora/nptl/sysdeps/unix/sysv/linux/kernel-features.h 22 Sep 2004 21:21:02 -0000 1.1.2.1
+@@ -0,0 +1,6 @@
++#include_next <kernel-features.h>
++
++/* NPTL can always assume all clone thread flags work. */
++#ifndef __ASSUME_CLONE_THREAD_FLAGS
++# define __ASSUME_CLONE_THREAD_FLAGS 1
++#endif
+--- glibc-2.3.6/nscd/connections.c 18 Jul 2005 08:01:49 -0000 1.64.2.4
++++ glibc-2.3.6-fedora/nscd/connections.c 18 Jul 2005 08:11:00 -0000 1.55.2.5.2.3
+@@ -21,6 +21,7 @@
+ #include <alloca.h>
+ #include <assert.h>
+ #include <atomic.h>
++#include <dlfcn.h>
+ #include <error.h>
+ #include <errno.h>
+ #include <fcntl.h>
+@@ -42,6 +43,7 @@
+ #include <sys/socket.h>
+ #include <sys/stat.h>
+ #include <sys/un.h>
++#include <gnu/lib-names.h>
+
+ #include "nscd.h"
+ #include "dbg_log.h"
+@@ -1476,19 +1478,39 @@ start_threads (void)
+ pthread_condattr_t condattr;
+ pthread_condattr_init (&condattr);
+
+-#if defined _POSIX_CLOCK_SELECTION && _POSIX_CLOCK_SELECTION >= 0 \
+- && defined _POSIX_MONOTONIC_CLOCK && _POSIX_MONOTONIC_CLOCK >= 0
++#if defined _POSIX_MONOTONIC_CLOCK && _POSIX_MONOTONIC_CLOCK >= 0
+ /* Determine whether the monotonous clock is available. */
+ struct timespec dummy;
+ # if _POSIX_MONOTONIC_CLOCK == 0
+ if (sysconf (_SC_MONOTONIC_CLOCK) > 0)
+ # endif
+-# if _POSIX_CLOCK_SELECTION == 0
+- if (sysconf (_SC_CLOCK_SELECTION) > 0)
++ {
++# if defined _POSIX_CLOCK_SELECTION && _POSIX_CLOCK_SELECTION >= 0
++# if _POSIX_CLOCK_SELECTION == 0
++ if (sysconf (_SC_CLOCK_SELECTION) > 0)
++# endif
++ if (clock_getres (CLOCK_MONOTONIC, &dummy) == 0
++ && pthread_condattr_setclock (&condattr, CLOCK_MONOTONIC) == 0)
++ timeout_clock = CLOCK_MONOTONIC;
++# elif _POSIX_THREADS > 0
++ if (sysconf (_SC_CLOCK_SELECTION) > 0)
++ {
++ void *h = __libc_dlopen (LIBPTHREAD_SO);
++ int (*condattr_setclock) (pthread_condattr_t *, __clockid_t) = NULL;
++
++ if (h != NULL)
++ condattr_setclock = __libc_dlsym (h, "pthread_condattr_setclock");
++
++ if (condattr_setclock
++ && clock_getres (CLOCK_MONOTONIC, &dummy) == 0
++ && condattr_setclock (&condattr, CLOCK_MONOTONIC) == 0)
++ timeout_clock = CLOCK_MONOTONIC;
++
++ if (h != NULL)
++ __libc_dlclose (h);
++ }
+ # endif
+- if (clock_getres (CLOCK_MONOTONIC, &dummy) == 0
+- && pthread_condattr_setclock (&condattr, CLOCK_MONOTONIC) == 0)
+- timeout_clock = CLOCK_MONOTONIC;
++ }
+ #endif
+
+ pthread_cond_init (&readylist_cond, &condattr);
+@@ -1553,7 +1575,6 @@ start_threads (void)
+ main_loop_poll ();
+ }
+
+-
+ /* Look up the uid, gid, and supplementary groups to run nscd as. When
+ this function is called, we are not listening on the nscd socket yet so
+ we can just use the ordinary lookup functions without causing a lockup */
+@@ -1622,3 +1643,18 @@ finish_drop_privileges (void)
+ exit (1);
+ }
+ }
++
++/* Handle the HUP signal which will force a dump of the cache */
++void
++sighup_handler (int signum)
++{
++ /* Prune the password database */
++ prune_cache (&dbs[pwddb], LONG_MAX);
++
++ /* Prune the group database */
++ prune_cache (&dbs[grpdb], LONG_MAX);
++
++ /* Prune the host database */
++ prune_cache (&dbs[hstdb], LONG_MAX);
++}
++
+--- glibc-2.3.6/nscd/nscd.c 16 Feb 2005 11:29:42 -0000 1.42.2.2
++++ glibc-2.3.6-fedora/nscd/nscd.c 16 Feb 2005 19:56:58 -0000 1.38.2.4.2.1
+@@ -122,9 +122,16 @@ static struct argp argp =
+ options, parse_opt, NULL, doc,
+ };
+
++/* The SIGHUP handler is extern to this file */
++extern void sighup_handler(int signum);
++
+ /* True if only statistics are requested. */
+ static bool get_stats;
+
++#ifdef atomic_init_nscd
++atomic_init_nscd
++#endif
++
+ int
+ main (int argc, char **argv)
+ {
+@@ -266,6 +273,7 @@ main (int argc, char **argv)
+ signal (SIGINT, termination_handler);
+ signal (SIGQUIT, termination_handler);
+ signal (SIGTERM, termination_handler);
++ signal (SIGHUP, sighup_handler);
+ signal (SIGPIPE, SIG_IGN);
+
+ /* Cleanup files created by a previous 'bind'. */
+--- glibc-2.3.6/nscd/nscd.conf 3 Oct 2004 21:09:23 -0000 1.10
++++ glibc-2.3.6-fedora/nscd/nscd.conf 4 Oct 2004 08:56:17 -0000 1.8.2.2
+@@ -31,8 +31,8 @@
+ # logfile /var/log/nscd.log
+ # threads 6
+ # max-threads 128
+-# server-user nobody
+-# stat-user somebody
++ server-user nscd
++# stat-user nocpulse
+ debug-level 0
+ # reload-count 5
+ paranoia no
+--- glibc-2.3.6/nscd/nscd_conf.c 3 Oct 2004 21:10:35 -0000 1.16
++++ glibc-2.3.6-fedora/nscd/nscd_conf.c 4 Oct 2004 08:56:17 -0000 1.14.2.2
+@@ -230,7 +230,10 @@ nscd_parse_file (const char *fname, stru
+ if (strcmp (arg2, "no") == 0)
+ dbs[cnt].shared = 0;
+ else if (strcmp (arg2, "yes") == 0)
+- dbs[cnt].shared = 1;
++#ifndef atomic_supports_shared
++#define atomic_supports_shared 1
++#endif
++ dbs[cnt].shared = atomic_supports_shared;
+ break;
+ }
+ if (cnt == lastdb)
+--- glibc-2.3.6/posix/Makefile 17 Oct 2005 09:05:20 -0000 1.179.2.4
++++ glibc-2.3.6-fedora/posix/Makefile 23 Oct 2005 01:27:00 -0000 1.171.2.9.2.4
+@@ -106,7 +106,8 @@ generated := $(addprefix wordexp-test-re
+ bug-regex21-mem bug-regex21.mtrace \
+ tst-rxspencer-mem tst-rxspencer.mtrace tst-getconf.out \
+ tst-pcre-mem tst-pcre.mtrace tst-boost-mem tst-boost.mtrace \
+- bug-ga2.mtrace bug-ga2-mem bug-glob2.mtrace bug-glob2-mem
++ bug-ga2.mtrace bug-ga2-mem bug-glob2.mtrace bug-glob2-mem \
++ getconf.speclist
+
+ include ../Rules
+
+@@ -279,12 +280,16 @@ bug-glob2-ENV = MALLOC_TRACE=$(objpfx)bu
+ $(objpfx)bug-glob2-mem: $(objpfx)bug-glob2.out
+ $(common-objpfx)malloc/mtrace $(objpfx)bug-glob2.mtrace > $@
+
+-$(inst_libexecdir)/getconf: $(objpfx)getconf FORCE
++$(inst_libexecdir)/getconf: $(objpfx)getconf $(objpfx)getconf.speclist FORCE
+ $(addprefix $(..)./scripts/mkinstalldirs ,\
+ $(filter-out $(wildcard $@),$@))
+- for spec in `LC_ALL=C GETCONF_DIR=/dev/null \
+- $(run-program-prefix) $< \
+- _POSIX_V6_WIDTH_RESTRICTED_ENVS`; do \
+- $(INSTALL_PROGRAM) $< $@/$$spec.new; \
+- mv -f $@/$$spec.new $@/$$spec; \
++ for spec in `cat $(objpfx)getconf.speclist`; do \
++ $(INSTALL_PROGRAM) $< $@/$$spec.new; \
++ mv -f $@/$$spec.new $@/$$spec; \
+ done
++
++$(objpfx)getconf.speclist: getconf.speclist.h
++ $(CC) -E $(CFLAGS) $(CPPFLAGS) $< \
++ | sed -n -e '/START_OF_STRINGS/,$${/POSIX_V6_/{s/^[^"]*"//;s/".*$$//;p}}' \
++ > $@.new
++ mv -f $@.new $@
+--- glibc-2.3.6/posix/getconf.speclist.h 1 Jan 1970 00:00:00 -0000
++++ glibc-2.3.6-fedora/posix/getconf.speclist.h 13 Dec 2004 23:32:37 -0000 1.1.2.2
+@@ -0,0 +1,15 @@
++#include <unistd.h>
++const char *START_OF_STRINGS =
++#if _POSIX_V6_ILP32_OFF32 == 1
++"POSIX_V6_ILP32_OFF32"
++#endif
++#if _POSIX_V6_ILP32_OFFBIG == 1
++"POSIX_V6_ILP32_OFFBIG"
++#endif
++#if _POSIX_V6_LP64_OFF64 == 1
++"POSIX_V6_LP64_OFF64"
++#endif
++#if _POSIX_V6_LPBIG_OFFBIG == 1
++"POSIX_V6_LPBIG_OFFBIG"
++#endif
++"";
+--- glibc-2.3.6/sysdeps/generic/dl-cache.h 25 Jun 2003 08:01:22 -0000 1.13
++++ glibc-2.3.6-fedora/sysdeps/generic/dl-cache.h 22 Sep 2004 21:21:07 -0000 1.13.2.1
+@@ -36,6 +36,14 @@
+ # define add_system_dir(dir) add_dir (dir)
+ #endif
+
++#ifndef arch_startup
++# define arch_startup(argc, argv) do { } while (0)
++#endif
++
++#ifndef add_arch_dirs
++# define add_arch_dirs(config_file) do { } while (0)
++#endif
++
+ #define CACHEMAGIC "ld.so-1.7.0"
+
+ /* libc5 and glibc 2.0/2.1 use the same format. For glibc 2.2 another
+--- glibc-2.3.6/sysdeps/i386/bits/atomic.h 1 Jan 1970 00:00:00 -0000
++++ glibc-2.3.6-fedora/sysdeps/i386/bits/atomic.h 5 Oct 2004 12:09:44 -0000 1.1.2.3
+@@ -0,0 +1,410 @@
++/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <stdint.h>
++
++
++typedef int8_t atomic8_t;
++typedef uint8_t uatomic8_t;
++typedef int_fast8_t atomic_fast8_t;
++typedef uint_fast8_t uatomic_fast8_t;
++
++typedef int16_t atomic16_t;
++typedef uint16_t uatomic16_t;
++typedef int_fast16_t atomic_fast16_t;
++typedef uint_fast16_t uatomic_fast16_t;
++
++typedef int32_t atomic32_t;
++typedef uint32_t uatomic32_t;
++typedef int_fast32_t atomic_fast32_t;
++typedef uint_fast32_t uatomic_fast32_t;
++
++typedef int64_t atomic64_t;
++typedef uint64_t uatomic64_t;
++typedef int_fast64_t atomic_fast64_t;
++typedef uint_fast64_t uatomic_fast64_t;
++
++typedef intptr_t atomicptr_t;
++typedef uintptr_t uatomicptr_t;
++typedef intmax_t atomic_max_t;
++typedef uintmax_t uatomic_max_t;
++
++
++#ifndef LOCK_PREFIX
++# ifdef UP
++# define LOCK_PREFIX /* nothing */
++# else
++# define LOCK_PREFIX "lock;"
++# endif
++#endif
++
++/* i386 doesn't have cmpxchg* and xadd*. Instead of being completely
++ non-atomic, atomic_* macros that are using solely i386 instructions
++ are using those atomic instructions and the remaining ones are
++ non-atomic. When in nscd, use i486+ instructions if on i486+. */
++
++#ifdef IS_IN_nscd
++
++extern int has_cmpxchg attribute_hidden;
++
++#define atomic_supports_shared has_cmpxchg
++
++#define atomic_init_nscd \
++int has_cmpxchg attribute_hidden; \
++static void __attribute__((constructor)) \
++init_has_cmpxchg (void) \
++{ \
++ int fl1, fl2; \
++ __asm__ ("pushfl; pushfl; popl %0; movl %0,%1; xorl %2,%0;" \
++ "pushl %0; popfl; pushfl; popl %0; popfl" \
++ : "=&r" (fl1), "=&r" (fl2) : "i" (0x00040000)); \
++ if ((fl1 ^ fl2) & 0x00040000) \
++ has_cmpxchg = 1; \
++}
++
++# define __arch_compare_and_exchange_val_8_acq(mem, newval, oldval) \
++ ({ __typeof (*mem) ret; \
++ if (__builtin_expect (has_cmpxchg, 1)) \
++ __asm __volatile (LOCK_PREFIX "cmpxchgb %b2, %1" \
++ : "=a" (ret), "=m" (*mem) \
++ : "q" (newval), "m" (*mem), "0" (oldval)); \
++ else \
++ { \
++ ret = *mem; \
++ if (ret == oldval) \
++ *mem = (newval); \
++ } \
++ ret; })
++
++# define __arch_compare_and_exchange_val_16_acq(mem, newval, oldval) \
++ ({ __typeof (*mem) ret; \
++ if (__builtin_expect (has_cmpxchg, 1)) \
++ __asm __volatile (LOCK_PREFIX "cmpxchgw %w2, %1" \
++ : "=a" (ret), "=m" (*mem) \
++ : "r" (newval), "m" (*mem), "0" (oldval)); \
++ else \
++ { \
++ ret = *mem; \
++ if (ret == oldval) \
++ *mem = (newval); \
++ } \
++ ret; })
++
++# define __arch_compare_and_exchange_val_32_acq(mem, newval, oldval) \
++ ({ __typeof (*mem) ret; \
++ if (__builtin_expect (has_cmpxchg, 1)) \
++ __asm __volatile (LOCK_PREFIX "cmpxchgl %2, %1" \
++ : "=a" (ret), "=m" (*mem) \
++ : "r" (newval), "m" (*mem), "0" (oldval)); \
++ else \
++ { \
++ ret = *mem; \
++ if (ret == oldval) \
++ *mem = (newval); \
++ } \
++ ret; })
++
++/* XXX We do not really need 64-bit compare-and-exchange. At least
++ not in the moment. */
++# define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
++ ({ __typeof (*mem) ret = *(mem); abort (); ret = (newval); ret = (oldval); })
++
++
++# define atomic_exchange_and_add(mem, value) \
++ ({ __typeof (*mem) __result; \
++ __typeof (value) __addval = (value); \
++ if (__builtin_expect (! has_cmpxchg, 0)) \
++ { \
++ __typeof (mem) __memp = (mem); \
++ __result = *__memp; \
++ *__memp += __addval; \
++ } \
++ else if (sizeof (*mem) == 1) \
++ __asm __volatile (LOCK_PREFIX "xaddb %b0, %1" \
++ : "=r" (__result), "=m" (*mem) \
++ : "0" (__addval), "m" (*mem)); \
++ else if (sizeof (*mem) == 2) \
++ __asm __volatile (LOCK_PREFIX "xaddw %w0, %1" \
++ : "=r" (__result), "=m" (*mem) \
++ : "0" (__addval), "m" (*mem)); \
++ else if (sizeof (*mem) == 4) \
++ __asm __volatile (LOCK_PREFIX "xaddl %0, %1" \
++ : "=r" (__result), "=m" (*mem) \
++ : "0" (__addval), "m" (*mem)); \
++ else \
++ { \
++ __typeof (mem) __memp = (mem); \
++ __typeof (*mem) __tmpval; \
++ __result = *__memp; \
++ do \
++ __tmpval = __result; \
++ while ((__result = __arch_compare_and_exchange_val_64_acq \
++ (__memp, __result + __addval, __result)) == __tmpval); \
++ } \
++ __result; })
++
++#else
++
++/* We have by default no support for atomic operations. So define
++ them non-atomic. If this is a problem somebody will have to come
++ up with real definitions. */
++
++/* The only basic operation needed is compare and exchange. */
++#define atomic_compare_and_exchange_val_acq(mem, newval, oldval) \
++ ({ __typeof (mem) __gmemp = (mem); \
++ __typeof (*mem) __gret = *__gmemp; \
++ __typeof (*mem) __gnewval = (newval); \
++ \
++ if (__gret == (oldval)) \
++ *__gmemp = __gnewval; \
++ __gret; })
++
++#define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
++ ({ __typeof (mem) __gmemp = (mem); \
++ __typeof (*mem) __gnewval = (newval); \
++ \
++ *__gmemp == (oldval) ? (*__gmemp = __gnewval, 0) : 1; })
++
++/* XXX We do not really need 64-bit compare-and-exchange. At least
++ not in the moment. */
++# define __arch_compare_and_exchange_val_64_acq(mem, newval, oldval) \
++ ({ __typeof (*mem) ret = *(mem); abort (); ret = (newval); ret = (oldval); })
++
++#endif
++
++/* Note that we need no lock prefix. */
++#define atomic_exchange_acq(mem, newvalue) \
++ ({ __typeof (*mem) result; \
++ if (sizeof (*mem) == 1) \
++ __asm __volatile ("xchgb %b0, %1" \
++ : "=r" (result), "=m" (*mem) \
++ : "0" (newvalue), "m" (*mem)); \
++ else if (sizeof (*mem) == 2) \
++ __asm __volatile ("xchgw %w0, %1" \
++ : "=r" (result), "=m" (*mem) \
++ : "0" (newvalue), "m" (*mem)); \
++ else if (sizeof (*mem) == 4) \
++ __asm __volatile ("xchgl %0, %1" \
++ : "=r" (result), "=m" (*mem) \
++ : "0" (newvalue), "m" (*mem)); \
++ else \
++ { \
++ result = 0; \
++ abort (); \
++ } \
++ result; })
++
++
++#define atomic_add(mem, value) \
++ (void) ({ if (__builtin_constant_p (value) && (value) == 1) \
++ atomic_increment (mem); \
++ else if (__builtin_constant_p (value) && (value) == -1) \
++ atomic_decrement (mem); \
++ else if (sizeof (*mem) == 1) \
++ __asm __volatile (LOCK_PREFIX "addb %b1, %0" \
++ : "=m" (*mem) \
++ : "ir" (value), "m" (*mem)); \
++ else if (sizeof (*mem) == 2) \
++ __asm __volatile (LOCK_PREFIX "addw %w1, %0" \
++ : "=m" (*mem) \
++ : "ir" (value), "m" (*mem)); \
++ else if (sizeof (*mem) == 4) \
++ __asm __volatile (LOCK_PREFIX "addl %1, %0" \
++ : "=m" (*mem) \
++ : "ir" (value), "m" (*mem)); \
++ else \
++ { \
++ __typeof (value) __addval = (value); \
++ __typeof (mem) __memp = (mem); \
++ __typeof (*mem) __oldval = *__memp; \
++ __typeof (*mem) __tmpval; \
++ do \
++ __tmpval = __oldval; \
++ while ((__oldval = __arch_compare_and_exchange_val_64_acq \
++ (__memp, __oldval + __addval, __oldval)) == __tmpval); \
++ } \
++ })
++
++
++#define atomic_add_negative(mem, value) \
++ ({ unsigned char __result; \
++ if (sizeof (*mem) == 1) \
++ __asm __volatile (LOCK_PREFIX "addb %b2, %0; sets %1" \
++ : "=m" (*mem), "=qm" (__result) \
++ : "iq" (value), "m" (*mem)); \
++ else if (sizeof (*mem) == 2) \
++ __asm __volatile (LOCK_PREFIX "addw %w2, %0; sets %1" \
++ : "=m" (*mem), "=qm" (__result) \
++ : "ir" (value), "m" (*mem)); \
++ else if (sizeof (*mem) == 4) \
++ __asm __volatile (LOCK_PREFIX "addl %2, %0; sets %1" \
++ : "=m" (*mem), "=qm" (__result) \
++ : "ir" (value), "m" (*mem)); \
++ else \
++ abort (); \
++ __result; })
++
++
++#define atomic_add_zero(mem, value) \
++ ({ unsigned char __result; \
++ if (sizeof (*mem) == 1) \
++ __asm __volatile (LOCK_PREFIX "addb %b2, %0; setz %1" \
++ : "=m" (*mem), "=qm" (__result) \
++ : "ir" (value), "m" (*mem)); \
++ else if (sizeof (*mem) == 2) \
++ __asm __volatile (LOCK_PREFIX "addw %w2, %0; setz %1" \
++ : "=m" (*mem), "=qm" (__result) \
++ : "ir" (value), "m" (*mem)); \
++ else if (sizeof (*mem) == 4) \
++ __asm __volatile (LOCK_PREFIX "addl %2, %0; setz %1" \
++ : "=m" (*mem), "=qm" (__result) \
++ : "ir" (value), "m" (*mem)); \
++ else \
++ abort (); \
++ __result; })
++
++
++#define atomic_increment(mem) \
++ (void) ({ if (sizeof (*mem) == 1) \
++ __asm __volatile (LOCK_PREFIX "incb %b0" \
++ : "=m" (*mem) \
++ : "m" (*mem)); \
++ else if (sizeof (*mem) == 2) \
++ __asm __volatile (LOCK_PREFIX "incw %w0" \
++ : "=m" (*mem) \
++ : "m" (*mem)); \
++ else if (sizeof (*mem) == 4) \
++ __asm __volatile (LOCK_PREFIX "incl %0" \
++ : "=m" (*mem) \
++ : "m" (*mem)); \
++ else \
++ { \
++ __typeof (mem) __memp = (mem); \
++ __typeof (*mem) __oldval = *__memp; \
++ __typeof (*mem) __tmpval; \
++ do \
++ __tmpval = __oldval; \
++ while ((__oldval = __arch_compare_and_exchange_val_64_acq \
++ (__memp, __oldval + 1, __oldval)) == __tmpval); \
++ } \
++ })
++
++
++#define atomic_increment_and_test(mem) \
++ ({ unsigned char __result; \
++ if (sizeof (*mem) == 1) \
++ __asm __volatile (LOCK_PREFIX "incb %0; sete %b1" \
++ : "=m" (*mem), "=qm" (__result) \
++ : "m" (*mem)); \
++ else if (sizeof (*mem) == 2) \
++ __asm __volatile (LOCK_PREFIX "incw %0; sete %w1" \
++ : "=m" (*mem), "=qm" (__result) \
++ : "m" (*mem)); \
++ else if (sizeof (*mem) == 4) \
++ __asm __volatile (LOCK_PREFIX "incl %0; sete %1" \
++ : "=m" (*mem), "=qm" (__result) \
++ : "m" (*mem)); \
++ else \
++ abort (); \
++ __result; })
++
++
++#define atomic_decrement(mem) \
++ (void) ({ if (sizeof (*mem) == 1) \
++ __asm __volatile (LOCK_PREFIX "decb %b0" \
++ : "=m" (*mem) \
++ : "m" (*mem)); \
++ else if (sizeof (*mem) == 2) \
++ __asm __volatile (LOCK_PREFIX "decw %w0" \
++ : "=m" (*mem) \
++ : "m" (*mem)); \
++ else if (sizeof (*mem) == 4) \
++ __asm __volatile (LOCK_PREFIX "decl %0" \
++ : "=m" (*mem) \
++ : "m" (*mem)); \
++ else \
++ { \
++ __typeof (mem) __memp = (mem); \
++ __typeof (*mem) __oldval = *__memp; \
++ __typeof (*mem) __tmpval; \
++ do \
++ __tmpval = __oldval; \
++ while ((__oldval = __arch_compare_and_exchange_val_64_acq \
++ (__memp, __oldval - 1, __oldval)) == __tmpval); \
++ } \
++ })
++
++
++#define atomic_decrement_and_test(mem) \
++ ({ unsigned char __result; \
++ if (sizeof (*mem) == 1) \
++ __asm __volatile (LOCK_PREFIX "decb %b0; sete %1" \
++ : "=m" (*mem), "=qm" (__result) \
++ : "m" (*mem)); \
++ else if (sizeof (*mem) == 2) \
++ __asm __volatile (LOCK_PREFIX "decw %w0; sete %1" \
++ : "=m" (*mem), "=qm" (__result) \
++ : "m" (*mem)); \
++ else if (sizeof (*mem) == 4) \
++ __asm __volatile (LOCK_PREFIX "decl %0; sete %1" \
++ : "=m" (*mem), "=qm" (__result) \
++ : "m" (*mem)); \
++ else \
++ abort (); \
++ __result; })
++
++
++#define atomic_bit_set(mem, bit) \
++ (void) ({ if (sizeof (*mem) == 1) \
++ __asm __volatile (LOCK_PREFIX "orb %b2, %0" \
++ : "=m" (*mem) \
++ : "m" (*mem), "ir" (1 << (bit))); \
++ else if (sizeof (*mem) == 2) \
++ __asm __volatile (LOCK_PREFIX "orw %w2, %0" \
++ : "=m" (*mem) \
++ : "m" (*mem), "ir" (1 << (bit))); \
++ else if (sizeof (*mem) == 4) \
++ __asm __volatile (LOCK_PREFIX "orl %2, %0" \
++ : "=m" (*mem) \
++ : "m" (*mem), "ir" (1 << (bit))); \
++ else \
++ abort (); \
++ })
++
++
++#define atomic_bit_test_set(mem, bit) \
++ ({ unsigned char __result; \
++ if (sizeof (*mem) == 1) \
++ __asm __volatile (LOCK_PREFIX "btsb %3, %1; setc %0" \
++ : "=q" (__result), "=m" (*mem) \
++ : "m" (*mem), "ir" (bit)); \
++ else if (sizeof (*mem) == 2) \
++ __asm __volatile (LOCK_PREFIX "btsw %3, %1; setc %0" \
++ : "=q" (__result), "=m" (*mem) \
++ : "m" (*mem), "ir" (bit)); \
++ else if (sizeof (*mem) == 4) \
++ __asm __volatile (LOCK_PREFIX "btsl %3, %1; setc %0" \
++ : "=q" (__result), "=m" (*mem) \
++ : "m" (*mem), "ir" (bit)); \
++ else \
++ abort (); \
++ __result; })
++
++
++#define atomic_delay() asm ("rep; nop")
+--- glibc-2.3.6/sysdeps/ia64/Makefile 16 Aug 2004 06:46:14 -0000 1.10
++++ glibc-2.3.6-fedora/sysdeps/ia64/Makefile 22 Sep 2004 21:21:07 -0000 1.10.2.1
+@@ -12,8 +12,8 @@ elide-routines.os += hp-timing
+
+ ifeq (yes,$(build-shared))
+ # Compatibility
+-sysdep_routines += ia64libgcc
+-shared-only-routines += ia64libgcc
++sysdep_routines += libgcc-compat
++shared-only-routines += libgcc-compat
+ endif
+ endif
+
+--- glibc-2.3.6/sysdeps/ia64/ia64libgcc.S 11 May 2002 05:12:35 -0000 1.2
++++ glibc-2.3.6-fedora/sysdeps/ia64/ia64libgcc.S 22 Sep 2004 21:21:07 -0000 1.2.2.1
+@@ -1,350 +0,0 @@
+-/* From the Intel IA-64 Optimization Guide, choose the minimum latency
+- alternative. */
+-
+-#include <sysdep.h>
+-#undef ret
+-
+-#include <shlib-compat.h>
+-
+-#if SHLIB_COMPAT(libc, GLIBC_2_2, GLIBC_2_2_6)
+-
+-/* __divtf3
+- Compute a 80-bit IEEE double-extended quotient.
+- farg0 holds the dividend. farg1 holds the divisor. */
+-
+-ENTRY(___divtf3)
+- cmp.eq p7, p0 = r0, r0
+- frcpa.s0 f10, p6 = farg0, farg1
+- ;;
+-(p6) cmp.ne p7, p0 = r0, r0
+- .pred.rel.mutex p6, p7
+-(p6) fnma.s1 f11 = farg1, f10, f1
+-(p6) fma.s1 f12 = farg0, f10, f0
+- ;;
+-(p6) fma.s1 f13 = f11, f11, f0
+-(p6) fma.s1 f14 = f11, f11, f11
+- ;;
+-(p6) fma.s1 f11 = f13, f13, f11
+-(p6) fma.s1 f13 = f14, f10, f10
+- ;;
+-(p6) fma.s1 f10 = f13, f11, f10
+-(p6) fnma.s1 f11 = farg1, f12, farg0
+- ;;
+-(p6) fma.s1 f11 = f11, f10, f12
+-(p6) fnma.s1 f12 = farg1, f10, f1
+- ;;
+-(p6) fma.s1 f10 = f12, f10, f10
+-(p6) fnma.s1 f12 = farg1, f11, farg0
+- ;;
+-(p6) fma.s0 fret0 = f12, f10, f11
+-(p7) mov fret0 = f10
+- br.ret.sptk rp
+-END(___divtf3)
+- .symver ___divtf3, __divtf3@GLIBC_2.2
+-
+-/* __divdf3
+- Compute a 64-bit IEEE double quotient.
+- farg0 holds the dividend. farg1 holds the divisor. */
+-
+-ENTRY(___divdf3)
+- cmp.eq p7, p0 = r0, r0
+- frcpa.s0 f10, p6 = farg0, farg1
+- ;;
+-(p6) cmp.ne p7, p0 = r0, r0
+- .pred.rel.mutex p6, p7
+-(p6) fmpy.s1 f11 = farg0, f10
+-(p6) fnma.s1 f12 = farg1, f10, f1
+- ;;
+-(p6) fma.s1 f11 = f12, f11, f11
+-(p6) fmpy.s1 f13 = f12, f12
+- ;;
+-(p6) fma.s1 f10 = f12, f10, f10
+-(p6) fma.s1 f11 = f13, f11, f11
+- ;;
+-(p6) fmpy.s1 f12 = f13, f13
+-(p6) fma.s1 f10 = f13, f10, f10
+- ;;
+-(p6) fma.d.s1 f11 = f12, f11, f11
+-(p6) fma.s1 f10 = f12, f10, f10
+- ;;
+-(p6) fnma.d.s1 f8 = farg1, f11, farg0
+- ;;
+-(p6) fma.d fret0 = f8, f10, f11
+-(p7) mov fret0 = f10
+- br.ret.sptk rp
+- ;;
+-END(___divdf3)
+- .symver ___divdf3, __divdf3@GLIBC_2.2
+-
+-/* __divsf3
+- Compute a 32-bit IEEE float quotient.
+- farg0 holds the dividend. farg1 holds the divisor. */
+-
+-ENTRY(___divsf3)
+- cmp.eq p7, p0 = r0, r0
+- frcpa.s0 f10, p6 = farg0, farg1
+- ;;
+-(p6) cmp.ne p7, p0 = r0, r0
+- .pred.rel.mutex p6, p7
+-(p6) fmpy.s1 f8 = farg0, f10
+-(p6) fnma.s1 f9 = farg1, f10, f1
+- ;;
+-(p6) fma.s1 f8 = f9, f8, f8
+-(p6) fmpy.s1 f9 = f9, f9
+- ;;
+-(p6) fma.s1 f8 = f9, f8, f8
+-(p6) fmpy.s1 f9 = f9, f9
+- ;;
+-(p6) fma.d.s1 f10 = f9, f8, f8
+- ;;
+-(p6) fnorm.s.s0 fret0 = f10
+-(p7) mov fret0 = f10
+- br.ret.sptk rp
+- ;;
+-END(___divsf3)
+- .symver ___divsf3, __divsf3@GLIBC_2.2
+-
+-/* __divdi3
+- Compute a 64-bit integer quotient.
+- in0 holds the dividend. in1 holds the divisor. */
+-
+-ENTRY(___divdi3)
+- .regstk 2,0,0,0
+- /* Transfer inputs to FP registers. */
+- setf.sig f8 = in0
+- setf.sig f9 = in1
+- ;;
+- /* Convert the inputs to FP, so that they won't be treated as
+- unsigned. */
+- fcvt.xf f8 = f8
+- fcvt.xf f9 = f9
+- ;;
+- /* Compute the reciprocal approximation. */
+- frcpa.s1 f10, p6 = f8, f9
+- ;;
+- /* 3 Newton-Raphson iterations. */
+-(p6) fnma.s1 f11 = f9, f10, f1
+-(p6) fmpy.s1 f12 = f8, f10
+- ;;
+-(p6) fmpy.s1 f13 = f11, f11
+-(p6) fma.s1 f12 = f11, f12, f12
+- ;;
+-(p6) fma.s1 f10 = f11, f10, f10
+-(p6) fma.s1 f11 = f13, f12, f12
+- ;;
+-(p6) fma.s1 f10 = f13, f10, f10
+-(p6) fnma.s1 f12 = f9, f11, f8
+- ;;
+-(p6) fma.s1 f10 = f12, f10, f11
+- ;;
+- /* Round quotient to an integer. */
+- fcvt.fx.trunc.s1 f10 = f10
+- ;;
+- /* Transfer result to GP registers. */
+- getf.sig ret0 = f10
+- br.ret.sptk rp
+- ;;
+-END(___divdi3)
+- .symver ___divdi3, __divdi3@GLIBC_2.2
+-
+-/* __moddi3
+- Compute a 64-bit integer modulus.
+- in0 holds the dividend (a). in1 holds the divisor (b). */
+-
+-ENTRY(___moddi3)
+- .regstk 2,0,0,0
+- /* Transfer inputs to FP registers. */
+- setf.sig f14 = in0
+- setf.sig f9 = in1
+- ;;
+- /* Convert the inputs to FP, so that they won't be treated as
+- unsigned. */
+- fcvt.xf f8 = f14
+- fcvt.xf f9 = f9
+- ;;
+- /* Compute the reciprocal approximation. */
+- frcpa.s1 f10, p6 = f8, f9
+- ;;
+- /* 3 Newton-Raphson iterations. */
+-(p6) fmpy.s1 f12 = f8, f10
+-(p6) fnma.s1 f11 = f9, f10, f1
+- ;;
+-(p6) fma.s1 f12 = f11, f12, f12
+-(p6) fmpy.s1 f13 = f11, f11
+- ;;
+-(p6) fma.s1 f10 = f11, f10, f10
+-(p6) fma.s1 f11 = f13, f12, f12
+- ;;
+- sub in1 = r0, in1
+-(p6) fma.s1 f10 = f13, f10, f10
+-(p6) fnma.s1 f12 = f9, f11, f8
+- ;;
+- setf.sig f9 = in1
+-(p6) fma.s1 f10 = f12, f10, f11
+- ;;
+- fcvt.fx.trunc.s1 f10 = f10
+- ;;
+- /* r = q * (-b) + a */
+- xma.l f10 = f10, f9, f14
+- ;;
+- /* Transfer result to GP registers. */
+- getf.sig ret0 = f10
+- br.ret.sptk rp
+- ;;
+-END(___moddi3)
+- .symver ___moddi3, __moddi3@GLIBC_2.2
+-
+-/* __udivdi3
+- Compute a 64-bit unsigned integer quotient.
+- in0 holds the dividend. in1 holds the divisor. */
+-
+-ENTRY(___udivdi3)
+- .regstk 2,0,0,0
+- /* Transfer inputs to FP registers. */
+- setf.sig f8 = in0
+- setf.sig f9 = in1
+- ;;
+- /* Convert the inputs to FP, to avoid FP software-assist faults. */
+- fcvt.xuf.s1 f8 = f8
+- fcvt.xuf.s1 f9 = f9
+- ;;
+- /* Compute the reciprocal approximation. */
+- frcpa.s1 f10, p6 = f8, f9
+- ;;
+- /* 3 Newton-Raphson iterations. */
+-(p6) fnma.s1 f11 = f9, f10, f1
+-(p6) fmpy.s1 f12 = f8, f10
+- ;;
+-(p6) fmpy.s1 f13 = f11, f11
+-(p6) fma.s1 f12 = f11, f12, f12
+- ;;
+-(p6) fma.s1 f10 = f11, f10, f10
+-(p6) fma.s1 f11 = f13, f12, f12
+- ;;
+-(p6) fma.s1 f10 = f13, f10, f10
+-(p6) fnma.s1 f12 = f9, f11, f8
+- ;;
+-(p6) fma.s1 f10 = f12, f10, f11
+- ;;
+- /* Round quotient to an unsigned integer. */
+- fcvt.fxu.trunc.s1 f10 = f10
+- ;;
+- /* Transfer result to GP registers. */
+- getf.sig ret0 = f10
+- br.ret.sptk rp
+- ;;
+-END(___udivdi3)
+- .symver ___udivdi3, __udivdi3@GLIBC_2.2
+-
+-/* __umoddi3
+- Compute a 64-bit unsigned integer modulus.
+- in0 holds the dividend (a). in1 holds the divisor (b). */
+-
+-ENTRY(___umoddi3)
+- .regstk 2,0,0,0
+- /* Transfer inputs to FP registers. */
+- setf.sig f14 = in0
+- setf.sig f9 = in1
+- ;;
+- /* Convert the inputs to FP, to avoid FP software assist faults. */
+- fcvt.xuf.s1 f8 = f14
+- fcvt.xuf.s1 f9 = f9
+- ;;
+- /* Compute the reciprocal approximation. */
+- frcpa.s1 f10, p6 = f8, f9
+- ;;
+- /* 3 Newton-Raphson iterations. */
+-(p6) fmpy.s1 f12 = f8, f10
+-(p6) fnma.s1 f11 = f9, f10, f1
+- ;;
+-(p6) fma.s1 f12 = f11, f12, f12
+-(p6) fmpy.s1 f13 = f11, f11
+- ;;
+-(p6) fma.s1 f10 = f11, f10, f10
+-(p6) fma.s1 f11 = f13, f12, f12
+- ;;
+- sub in1 = r0, in1
+-(p6) fma.s1 f10 = f13, f10, f10
+-(p6) fnma.s1 f12 = f9, f11, f8
+- ;;
+- setf.sig f9 = in1
+-(p6) fma.s1 f10 = f12, f10, f11
+- ;;
+- /* Round quotient to an unsigned integer. */
+- fcvt.fxu.trunc.s1 f10 = f10
+- ;;
+- /* r = q * (-b) + a */
+- xma.l f10 = f10, f9, f14
+- ;;
+- /* Transfer result to GP registers. */
+- getf.sig ret0 = f10
+- br.ret.sptk rp
+- ;;
+-END(___umoddi3)
+- .symver ___umoddi3, __umoddi3@GLIBC_2.2
+-
+-/* __multi3
+- Compute a 128-bit multiply of 128-bit multiplicands.
+- in0/in1 holds one multiplicand (a), in2/in3 holds the other one (b). */
+-
+-ENTRY(___multi3)
+- .regstk 4,0,0,0
+- setf.sig f6 = in1
+- movl r19 = 0xffffffff
+- setf.sig f7 = in2
+- ;;
+- and r14 = r19, in0
+- ;;
+- setf.sig f10 = r14
+- and r14 = r19, in2
+- xmpy.l f9 = f6, f7
+- ;;
+- setf.sig f6 = r14
+- shr.u r14 = in0, 32
+- ;;
+- setf.sig f7 = r14
+- shr.u r14 = in2, 32
+- ;;
+- setf.sig f8 = r14
+- xmpy.l f11 = f10, f6
+- xmpy.l f6 = f7, f6
+- ;;
+- getf.sig r16 = f11
+- xmpy.l f7 = f7, f8
+- ;;
+- shr.u r14 = r16, 32
+- and r16 = r19, r16
+- getf.sig r17 = f6
+- setf.sig f6 = in0
+- ;;
+- setf.sig f11 = r14
+- getf.sig r21 = f7
+- setf.sig f7 = in3
+- ;;
+- xma.l f11 = f10, f8, f11
+- xma.l f6 = f6, f7, f9
+- ;;
+- getf.sig r18 = f11
+- ;;
+- add r18 = r18, r17
+- ;;
+- and r15 = r19, r18
+- cmp.ltu p7, p6 = r18, r17
+- ;;
+- getf.sig r22 = f6
+-(p7) adds r14 = 1, r19
+- ;;
+-(p7) add r21 = r21, r14
+- shr.u r14 = r18, 32
+- shl r15 = r15, 32
+- ;;
+- add r20 = r21, r14
+- ;;
+- add ret0 = r15, r16
+- add ret1 = r22, r20
+- br.ret.sptk rp
+- ;;
+-END(___multi3)
+- .symver ___multi3, __multi3@GLIBC_2.2
+-
+-#endif
+--- glibc-2.3.6/sysdeps/ia64/libgcc-compat.c 1 Jan 1970 00:00:00 -0000
++++ glibc-2.3.6-fedora/sysdeps/ia64/libgcc-compat.c 22 Sep 2004 21:21:08 -0000 1.1.2.1
+@@ -0,0 +1,84 @@
++/* pre-.hidden libgcc compatibility
++ Copyright (C) 2002 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++
++#include <stdint.h>
++#include <shlib-compat.h>
++
++#if SHLIB_COMPAT(libc, GLIBC_2_2, GLIBC_2_2_6)
++
++typedef int int128_t __attribute__((__mode__(TI)));
++
++extern long double __divtf3 (long double, long double) attribute_hidden;
++long double INTUSE (__divtf3) (long double x, long double y)
++{
++ return __divtf3 (x, y);
++}
++symbol_version (INTUSE (__divtf3), __divtf3, GLIBC_2.2);
++
++extern double __divdf3 (double, double) attribute_hidden;
++double INTUSE (__divdf3) (double x, double y)
++{
++ return __divdf3 (x, y);
++}
++symbol_version (INTUSE (__divdf3), __divdf3, GLIBC_2.2);
++
++extern float __divsf3 (float, float) attribute_hidden;
++float INTUSE (__divsf3) (float x, float y)
++{
++ return __divsf3 (x, y);
++}
++symbol_version (INTUSE (__divsf3), __divsf3, GLIBC_2.2);
++
++extern int64_t __divdi3 (int64_t, int64_t) attribute_hidden;
++int64_t INTUSE (__divdi3) (int64_t x, int64_t y)
++{
++ return __divdi3 (x, y);
++}
++symbol_version (INTUSE (__divdi3), __divdi3, GLIBC_2.2);
++
++extern int64_t __moddi3 (int64_t, int64_t) attribute_hidden;
++int64_t INTUSE (__moddi3) (int64_t x, int64_t y)
++{
++ return __moddi3 (x, y);
++}
++symbol_version (INTUSE (__moddi3), __moddi3, GLIBC_2.2);
++
++extern uint64_t __udivdi3 (uint64_t, uint64_t) attribute_hidden;
++uint64_t INTUSE (__udivdi3) (uint64_t x, uint64_t y)
++{
++ return __udivdi3 (x, y);
++}
++symbol_version (INTUSE (__udivdi3), __udivdi3, GLIBC_2.2);
++
++extern uint64_t __umoddi3 (uint64_t, uint64_t) attribute_hidden;
++uint64_t INTUSE (__umoddi3) (uint64_t x, uint64_t y)
++{
++ return __umoddi3 (x, y);
++}
++symbol_version (INTUSE (__umoddi3), __umoddi3, GLIBC_2.2);
++
++extern int128_t __multi3 (int128_t, int128_t) attribute_hidden;
++int128_t INTUSE (__multi3) (int128_t x, int128_t y)
++{
++ return __multi3 (x, y);
++}
++symbol_version (INTUSE (__multi3), __multi3, GLIBC_2.2);
++
++#endif
+--- glibc-2.3.6/sysdeps/unix/nice.c 28 Sep 2002 19:13:13 -0000 1.6
++++ glibc-2.3.6-fedora/sysdeps/unix/nice.c 22 Sep 2004 21:21:08 -0000 1.6.2.1
+@@ -41,7 +41,12 @@ nice (int incr)
+ __set_errno (save);
+ }
+
+- result = setpriority (PRIO_PROCESS, 0, prio + incr);
++ prio += incr;
++ if (prio < PRIO_MIN)
++ prio = PRIO_MIN;
++ else if (prio >= PRIO_MAX)
++ prio = PRIO_MAX - 1;
++ result = setpriority (PRIO_PROCESS, 0, prio);
+ if (result != -1)
+ return getpriority (PRIO_PROCESS, 0);
+ else
+--- glibc-2.3.6/sysdeps/unix/sysv/linux/paths.h 15 Nov 2000 23:06:47 -0000 1.11
++++ glibc-2.3.6-fedora/sysdeps/unix/sysv/linux/paths.h 22 Sep 2004 21:21:08 -0000 1.11.4.1
+@@ -61,7 +61,7 @@
+ #define _PATH_TTY "/dev/tty"
+ #define _PATH_UNIX "/boot/vmlinux"
+ #define _PATH_UTMP "/var/run/utmp"
+-#define _PATH_VI "/usr/bin/vi"
++#define _PATH_VI "/bin/vi"
+ #define _PATH_WTMP "/var/log/wtmp"
+
+ /* Provide trailing slash, since mostly used for building pathnames. */
+--- glibc-2.3.6/sysdeps/unix/sysv/linux/readonly-area.c 18 Oct 2004 04:17:11 -0000 1.1
++++ glibc-2.3.6-fedora/sysdeps/unix/sysv/linux/readonly-area.c 20 Oct 2004 11:04:51 -0000 1.1.2.2
+@@ -33,7 +33,10 @@ __readonly_area (const char *ptr, size_t
+
+ FILE *fp = fopen ("/proc/self/maps", "rc");
+ if (fp == NULL)
+- return -1;
++ /* We don't know. Returning 1 here means that programs using %n
++ and -D_FORTIFY_SOURCE=2 will work even when /proc is not mounted,
++ but will allow %n even in writable areas. */
++ return 1;
+
+ /* We need no locking. */
+ __fsetlocking (fp, FSETLOCKING_BYCALLER);
+--- glibc-2.3.6/sysdeps/unix/sysv/linux/tcsetattr.c 10 Sep 2003 19:16:07 -0000 1.16
++++ glibc-2.3.6-fedora/sysdeps/unix/sysv/linux/tcsetattr.c 22 Sep 2004 21:21:08 -0000 1.16.2.1
+@@ -49,6 +49,7 @@ tcsetattr (fd, optional_actions, termios
+ {
+ struct __kernel_termios k_termios;
+ unsigned long int cmd;
++ int retval;
+
+ switch (optional_actions)
+ {
+@@ -80,6 +81,35 @@ tcsetattr (fd, optional_actions, termios
+ memcpy (&k_termios.c_cc[0], &termios_p->c_cc[0],
+ __KERNEL_NCCS * sizeof (cc_t));
+
+- return INLINE_SYSCALL (ioctl, 3, fd, cmd, &k_termios);
++ retval = INLINE_SYSCALL (ioctl, 3, fd, cmd, &k_termios);
++
++ if (retval == 0 && cmd == TCSETS)
++ {
++ /* The Linux kernel has a bug which silently ignore the invalid
++ c_cflag on pty. We have to check it here. */
++ int save = errno;
++ retval = INLINE_SYSCALL (ioctl, 3, fd, TCGETS, &k_termios);
++ if (retval)
++ {
++ /* We cannot verify if the setting is ok. We don't return
++ an error (?). */
++ __set_errno (save);
++ retval = 0;
++ }
++ else if ((termios_p->c_cflag & (PARENB | CREAD))
++ != (k_termios.c_cflag & (PARENB | CREAD))
++ || ((termios_p->c_cflag & CSIZE)
++ && ((termios_p->c_cflag & CSIZE)
++ != (k_termios.c_cflag & CSIZE))))
++ {
++ /* It looks like the Linux kernel silently changed the
++ PARENB/CREAD/CSIZE bits in c_cflag. Report it as an
++ error. */
++ __set_errno (EINVAL);
++ retval = -1;
++ }
++ }
++
++ return retval;
+ }
+ libc_hidden_def (tcsetattr)
+--- glibc-2.3.6/sysdeps/unix/sysv/linux/i386/dl-cache.h 1 Jan 1970 00:00:00 -0000
++++ glibc-2.3.6-fedora/sysdeps/unix/sysv/linux/i386/dl-cache.h 22 Sep 2004 21:21:08 -0000 1.1.2.1
+@@ -0,0 +1,59 @@
++/* Support for reading /etc/ld.so.cache files written by Linux ldconfig.
++ Copyright (C) 2004 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++static inline int
++is_ia64 (void)
++{
++ unsigned int fl1, fl2;
++
++ /* See if we can use cpuid. */
++ __asm__ ("pushfl; pushfl; popl %0; movl %0,%1; xorl %2,%0;"
++ "pushl %0; popfl; pushfl; popl %0; popfl"
++ : "=&r" (fl1), "=&r" (fl2)
++ : "i" (0x00200000));
++ if (((fl1 ^ fl2) & 0x00200000) == 0)
++ return 0;
++
++ /* Host supports cpuid. See if cpuid gives capabilities, try
++ CPUID(0). Preserve %ebx and %ecx; cpuid insn clobbers these, we
++ don't need their CPUID values here, and %ebx may be the PIC
++ register. */
++ __asm__ ("pushl %%ecx; pushl %%ebx; cpuid; popl %%ebx; popl %%ecx"
++ : "=a" (fl1) : "0" (0) : "edx", "cc");
++ if (fl1 == 0)
++ return 0;
++
++ /* Invoke CPUID(1), return %edx; caller can examine bits to
++ determine what's supported. */
++ __asm__ ("pushl %%ecx; pushl %%ebx; cpuid; popl %%ebx; popl %%ecx"
++ : "=d" (fl2), "=a" (fl1) : "1" (1) : "cc");
++ return (fl2 & (1 << 30)) != 0;
++}
++
++#define arch_startup(argc, argv) \
++ do { \
++ /* On IA-64, try to execute 64-bit ldconfig if possible. \
++ This is because the badly designed /emul/ia32-linux hack \
++ will cause 32-bit ldconfig to do all sorts of weird things. */ \
++ if (is_ia64 ()) \
++ execv ("/emul/ia32-linux/../../sbin/ldconfig", \
++ (char *const *) argv); \
++ } while (0)
++
++#include_next <dl-cache.h>
+--- glibc-2.3.6/sysdeps/unix/sysv/linux/ia64/dl-cache.h 6 Jul 2001 04:56:17 -0000 1.2
++++ glibc-2.3.6-fedora/sysdeps/unix/sysv/linux/ia64/dl-cache.h 22 Sep 2004 21:21:09 -0000 1.2.4.1
+@@ -22,4 +22,31 @@
+ #define _dl_cache_check_flags(flags) \
+ ((flags) == _DL_CACHE_DEFAULT_ID)
+
++#define EMUL_HACK "/emul/ia32-linux"
++
++#define arch_startup(argc, argv) unlink (EMUL_HACK LD_SO_CACHE)
++
++#define add_arch_dirs(config_file) \
++ do { \
++ int save_verbose = opt_verbose; \
++ opt_verbose = 0; \
++ \
++ parse_conf (config_file, EMUL_HACK, true); \
++ \
++ /* Always add the standard search paths. */ \
++ add_system_dir (EMUL_HACK SLIBDIR); \
++ if (strcmp (SLIBDIR, LIBDIR)) \
++ add_system_dir (EMUL_HACK LIBDIR); \
++ \
++ char emul_config_file[strlen (config_file) \
++ + sizeof EMUL_HACK]; \
++ strcpy (mempcpy (emul_config_file, EMUL_HACK, \
++ strlen (EMUL_HACK)), config_file); \
++ \
++ if (! access (emul_config_file, R_OK)) \
++ parse_conf (emul_config_file, EMUL_HACK, true); \
++ \
++ opt_verbose = save_verbose; \
++ } while (0)
++
+ #include_next <dl-cache.h>
+--- glibc-2.3.6/sysdeps/unix/sysv/linux/ia64/dl-procinfo.c 1 Jan 1970 00:00:00 -0000
++++ glibc-2.3.6-fedora/sysdeps/unix/sysv/linux/ia64/dl-procinfo.c 22 Sep 2004 21:21:09 -0000 1.1.2.1
+@@ -0,0 +1,5 @@
++#ifdef IS_IN_ldconfig
++#include <sysdeps/i386/dl-procinfo.c>
++#else
++#include <sysdeps/generic/dl-procinfo.c>
++#endif
+--- glibc-2.3.6/sysdeps/unix/sysv/linux/ia64/dl-procinfo.h 1 Jan 1970 00:00:00 -0000
++++ glibc-2.3.6-fedora/sysdeps/unix/sysv/linux/ia64/dl-procinfo.h 22 Sep 2004 21:21:09 -0000 1.1.2.1
+@@ -0,0 +1,5 @@
++#ifdef IS_IN_ldconfig
++#include <sysdeps/unix/sysv/linux/i386/dl-procinfo.h>
++#else
++#include <sysdeps/generic/dl-procinfo.h>
++#endif
+--- glibc-2.3.6/sysdeps/unix/sysv/linux/ia64/ldd-rewrite.sed 17 Jan 2002 06:49:28 -0000 1.2
++++ glibc-2.3.6-fedora/sysdeps/unix/sysv/linux/ia64/ldd-rewrite.sed 22 Sep 2004 21:21:09 -0000 1.2.2.1
+@@ -1 +1 @@
+-s_^\(RTLDLIST=\)\([^ ]*\)-ia64\(\.so\.[0-9.]*\)[ ]*$_\1"\2-ia64\3 \2\3"_
++s_^\(RTLDLIST=\)\([^ ]*\)-ia64\(\.so\.[0-9.]*\)[ ]*$_\1"\2-ia64\3 /emul/ia32-linux\2\3"_
--- /dev/null
+--- libc/elf/dl-lookup.c.jj 2005-04-05 22:49:48.000000000 -0400
++++ libc/elf/dl-lookup.c 2008-03-28 12:23:44.000000000 -0400
+@@ -352,8 +352,29 @@ _dl_setup_hash (struct link_map *map)
+ Elf_Symndx *hash;
+ Elf_Symndx nchain;
+
+- if (!map->l_info[DT_HASH])
+- return;
++ if (__builtin_expect (!map->l_info[DT_HASH], 0))
++ {
++#ifdef SHARED
++# define DT_GNU_HASH 0x6ffffef5
++ ElfW(Dyn) *dyn = map->l_ld;
++ if (dyn == NULL)
++ return;
++ while (dyn->d_tag != DT_NULL)
++ if (dyn->d_tag == DT_GNU_HASH)
++ {
++ if (map->l_prev == NULL)
++ GL(dl_ns)[map->l_ns]._ns_loaded = NULL;
++ else
++ map->l_prev->l_next = NULL;
++ --GL(dl_ns)[map->l_ns]._ns_nloaded;
++ _dl_signal_error (0, map->l_name, NULL,
++ "requires glibc 2.5 or later dynamic linker");
++ }
++ else
++ dyn++;
++ return;
++#endif
++ }
+ hash = (void *) D_PTR (map, l_info[DT_HASH]);
+
+ map->l_nbuckets = *hash++;
--- /dev/null
+2006-04-24 Jakub Jelinek <jakub@redhat.com>
+
+ * malloc/arena.c (ptmalloc_init): Don't call __malloc_check_init
+ if MALLOC_CHECK_ env var contains an empty string.
+
+--- libc/malloc/arena.c 6 Mar 2006 06:18:35 -0000 1.20
++++ libc/malloc/arena.c 24 Apr 2006 17:23:50 -0000 1.21
+@@ -551,8 +551,8 @@ ptmalloc_init (void)
+ }
+ s = getenv("MALLOC_CHECK_");
+ #endif
+- if(s) {
+- if(s[0]) mALLOPt(M_CHECK_ACTION, (int)(s[0] - '0'));
++ if(s && s[0]) {
++ mALLOPt(M_CHECK_ACTION, (int)(s[0] - '0'));
+ if (check_action != 0)
+ __malloc_check_init();
+ }
--- /dev/null
+2005-10-07 Roland McGrath <roland@redhat.com>
+
+ [BZ #1438]
+ * include/features.h: Make tests on _FORTIFY_SOURCE and __OPTIMIZE__
+ friendly to -Wundef.
+ (__USE_FORTIFY_LEVEL): Always define it, to 0 if nothing else.
+
+--- libc/include/features.h 17 Feb 2005 01:10:58 -0000 1.38
++++ libc/include/features.h 8 Oct 2005 06:27:44 -0000 1.39
+@@ -262,18 +262,23 @@
+ # define __USE_REENTRANT 1
+ #endif
+
+-#if _FORTIFY_SOURCE > 0 && __OPTIMIZE__ > 0 \
++#if defined _FORTIFY_SOURCE && defined __OPTIMIZE__ \
++ && _FORTIFY_SOURCE > 0 && __OPTIMIZE__ > 0 \
+ && (__GNUC_PREREQ (4, 1) \
+ || (defined __GNUC_RH_RELEASE__ && __GNUC_PREREQ (4, 0)) \
+ || (defined __GNUC_RH_RELEASE__ && __GNUC_PREREQ (3, 4) \
+ && __GNUC_MINOR__ == 4 \
+ && (__GNUC_PATCHLEVEL__ > 2 \
+- || (__GNUC_PATCHLEVEL__ == 2 && __GNUC_RH_RELEASE__ >= 8))))
+-# if _FORTIFY_SOURCE == 1
+-# define __USE_FORTIFY_LEVEL 1
+-# elif _FORTIFY_SOURCE > 1
++ || (__GNUC_PATCHLEVEL__ == 2 \
++ && defined __GNUC_RH_RELEASE__ \
++ && __GNUC_RH_RELEASE__ >= 8))))
++# if _FORTIFY_SOURCE > 1
+ # define __USE_FORTIFY_LEVEL 2
++# else
++# define __USE_FORTIFY_LEVEL 1
+ # endif
++#else
++# define __USE_FORTIFY_LEVEL 0
+ #endif
+
+ /* We do support the IEC 559 math functionality, real and complex. */
--- /dev/null
+2006-09-05 Jakub Jelinek <jakub@redhat.com>
+ Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/pthread/aio_misc.h (AIO_MISC_NOTIFY): Don't decrement
+ counterp if it is already zero.
+
+2006-01-05 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/pthread/aio_misc.h [!DONT_USE_BOOTSTRAP_MAP]
+ (struct waitlist): Don't add cond.
+ * sysdeps/pthread/aio_notify.c [!DONT_USE_BOOTSTRAP_MAP]
+ (__aio_notify): Use AIO_MISC_NOTIFY instead of pthread_cond_signal.
+ * sysdeps/pthread/aio_suspend.c [!DONT_USE_BOOTSTRAP_MAP]: Don't
+ use condvar, use AIO_MISC_WAIT.
+ * sysdeps/pthread/lio_listio.c: Likewise.
+ * rt/Makefile (tests): Add tst-aio9 and tst-aio10.
+ * rt/tst-aio9.c: New file.
+ * rt/tst-aio10.c: New file.
+
+nptl/
+2006-01-07 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/pthread/aio_misc.h (AIO_MISC_WAIT): Work around gcc
+ being too clever and reloading the futex value where it shouldn't.
+
+2006-01-05 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/pthread/aio_misc.h: New file.
+
+--- libc/sysdeps/pthread/aio_misc.h.jj 2003-08-14 02:01:40.000000000 +0200
++++ libc/sysdeps/pthread/aio_misc.h 2006-02-22 19:05:18.000000000 +0100
+@@ -46,7 +46,9 @@ struct waitlist
+ {
+ struct waitlist *next;
+
++#ifndef DONT_NEED_AIO_MISC_COND
+ pthread_cond_t *cond;
++#endif
+ volatile int *counterp;
+ /* The next field is used in asynchronous `lio_listio' operations. */
+ struct sigevent *sigevp;
+--- libc/sysdeps/pthread/aio_notify.c.jj 2004-05-26 06:23:43.000000000 +0200
++++ libc/sysdeps/pthread/aio_notify.c 2006-02-22 19:10:15.000000000 +0100
+@@ -144,15 +144,21 @@ __aio_notify (struct requestlist *req)
+ {
+ struct waitlist *next = waitlist->next;
+
+- /* Decrement the counter. This is used in both cases. */
+- --*waitlist->counterp;
+-
+ if (waitlist->sigevp == NULL)
+- pthread_cond_signal (waitlist->cond);
++ {
++#ifdef DONT_NEED_AIO_MISC_COND
++ AIO_MISC_NOTIFY (waitlist);
++#else
++ /* Decrement the counter. */
++ --*waitlist->counterp;
++
++ pthread_cond_signal (waitlist->cond);
++#endif
++ }
+ else
+ /* This is part of a asynchronous `lio_listio' operation. If
+ this request is the last one, send the signal. */
+- if (*waitlist->counterp == 0)
++ if (--*waitlist->counterp == 0)
+ {
+ #ifdef BROKEN_THREAD_SIGNALS
+ __aio_notify_only (waitlist->sigevp, waitlist->caller_pid);
+--- libc/sysdeps/pthread/aio_suspend.c.jj 2003-08-14 02:04:38.000000000 +0200
++++ libc/sysdeps/pthread/aio_suspend.c 2006-02-22 19:11:54.000000000 +0100
+@@ -44,7 +44,9 @@ struct clparam
+ const struct aiocb *const *list;
+ struct waitlist *waitlist;
+ struct requestlist **requestlist;
++#ifndef DONT_NEED_AIO_MISC_COND
+ pthread_cond_t *cond;
++#endif
+ int nent;
+ };
+
+@@ -52,6 +54,12 @@ struct clparam
+ static void
+ cleanup (void *arg)
+ {
++#ifdef DONT_NEED_AIO_MISC_COND
++ /* Acquire the mutex. If pthread_cond_*wait is used this would
++ happen implicitly. */
++ pthread_mutex_lock (&__aio_requests_mutex);
++#endif
++
+ const struct clparam *param = (const struct clparam *) arg;
+
+ /* Now remove the entry in the waiting list for all requests
+@@ -75,8 +83,10 @@ cleanup (void *arg)
+ *listp = (*listp)->next;
+ }
+
++#ifndef DONT_NEED_AIO_MISC_COND
+ /* Release the conditional variable. */
+ (void) pthread_cond_destroy (param->cond);
++#endif
+
+ /* Release the mutex. */
+ pthread_mutex_unlock (&__aio_requests_mutex);
+@@ -89,13 +99,21 @@ aio_suspend (list, nent, timeout)
+ int nent;
+ const struct timespec *timeout;
+ {
++ if (__builtin_expect (nent < 0, 0))
++ {
++ __set_errno (EINVAL);
++ return -1;
++ }
++
+ struct waitlist waitlist[nent];
+ struct requestlist *requestlist[nent];
++#ifndef DONT_NEED_AIO_MISC_COND
+ pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
++#endif
+ int cnt;
+ bool any = false;
+ int result = 0;
+- int dummy;
++ int cntr = 1;
+
+ /* Request the mutex. */
+ pthread_mutex_lock (&__aio_requests_mutex);
+@@ -111,9 +129,11 @@ aio_suspend (list, nent, timeout)
+
+ if (requestlist[cnt] != NULL)
+ {
++#ifndef DONT_NEED_AIO_MISC_COND
+ waitlist[cnt].cond = &cond;
++#endif
+ waitlist[cnt].next = requestlist[cnt]->waiting;
+- waitlist[cnt].counterp = &dummy;
++ waitlist[cnt].counterp = &cntr;
+ waitlist[cnt].sigevp = NULL;
+ #ifdef BROKEN_THREAD_SIGNALS
+ waitlist[cnt].caller_pid = 0; /* Not needed. */
+@@ -139,12 +159,17 @@ aio_suspend (list, nent, timeout)
+ .list = list,
+ .waitlist = waitlist,
+ .requestlist = requestlist,
++#ifndef DONT_NEED_AIO_MISC_COND
+ .cond = &cond,
++#endif
+ .nent = nent
+ };
+
+ pthread_cleanup_push (cleanup, &clparam);
+
++#ifdef DONT_NEED_AIO_MISC_COND
++ AIO_MISC_WAIT (result, cntr, timeout, 1);
++#else
+ if (timeout == NULL)
+ result = pthread_cond_wait (&cond, &__aio_requests_mutex);
+ else
+@@ -166,6 +191,7 @@ aio_suspend (list, nent, timeout)
+ result = pthread_cond_timedwait (&cond, &__aio_requests_mutex,
+ &abstime);
+ }
++#endif
+
+ pthread_cleanup_pop (0);
+ }
+@@ -189,19 +215,23 @@ aio_suspend (list, nent, timeout)
+ *listp = (*listp)->next;
+ }
+
++#ifndef DONT_NEED_AIO_MISC_COND
+ /* Release the conditional variable. */
+ if (__builtin_expect (pthread_cond_destroy (&cond) != 0, 0))
+ /* This must never happen. */
+ abort ();
++#endif
+
+ if (result != 0)
+ {
+- /* An error occurred. Possibly it's EINTR. We have to translate
++#ifndef DONT_NEED_AIO_MISC_COND
++ /* An error occurred. Possibly it's ETIMEDOUT. We have to translate
+ the timeout error report of `pthread_cond_timedwait' to the
+ form expected from `aio_suspend'. */
+ if (result == ETIMEDOUT)
+ __set_errno (EAGAIN);
+ else
++#endif
+ __set_errno (result);
+
+ result = -1;
+--- libc/sysdeps/pthread/lio_listio.c.jj 2003-08-14 02:06:07.000000000 +0200
++++ libc/sysdeps/pthread/lio_listio.c 2006-02-22 19:29:04.000000000 +0100
+@@ -113,9 +113,11 @@ lio_listio (mode, list, nent, sig)
+ }
+ else if (mode == LIO_WAIT)
+ {
++#ifndef DONT_NEED_AIO_MISC_COND
+ pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+- struct waitlist waitlist[nent];
+ int oldstate;
++#endif
++ struct waitlist waitlist[nent];
+
+ total = 0;
+ for (cnt = 0; cnt < nent; ++cnt)
+@@ -124,7 +126,9 @@ lio_listio (mode, list, nent, sig)
+
+ if (requests[cnt] != NULL && list[cnt]->aio_lio_opcode != LIO_NOP)
+ {
++#ifndef DONT_NEED_AIO_MISC_COND
+ waitlist[cnt].cond = &cond;
++#endif
+ waitlist[cnt].next = requests[cnt]->waiting;
+ waitlist[cnt].counterp = &total;
+ waitlist[cnt].sigevp = NULL;
+@@ -136,6 +140,9 @@ lio_listio (mode, list, nent, sig)
+ }
+ }
+
++#ifdef DONT_NEED_AIO_MISC_COND
++ AIO_MISC_WAIT (result, total, NULL, 0);
++#else
+ /* Since `pthread_cond_wait'/`pthread_cond_timedwait' are cancelation
+ points we must be careful. We added entries to the waiting lists
+ which we must remove. So defer cancelation for now. */
+@@ -151,6 +158,7 @@ lio_listio (mode, list, nent, sig)
+ if (pthread_cond_destroy (&cond) != 0)
+ /* This must never happen. */
+ abort ();
++#endif
+ }
+ else
+ {
+@@ -179,7 +187,9 @@ lio_listio (mode, list, nent, sig)
+ if (requests[cnt] != NULL
+ && list[cnt]->aio_lio_opcode != LIO_NOP)
+ {
++#ifndef DONT_NEED_AIO_MISC_COND
+ waitlist->list[cnt].cond = NULL;
++#endif
+ waitlist->list[cnt].next = requests[cnt]->waiting;
+ waitlist->list[cnt].counterp = &waitlist->counter;
+ waitlist->list[cnt].sigevp = &waitlist->sigev;
+--- libc/rt/Makefile.jj 2005-04-27 10:01:44.000000000 +0200
++++ libc/rt/Makefile 2006-02-22 19:02:58.000000000 +0100
+@@ -43,7 +43,8 @@ librt-routines = $(aio-routines) \
+
+ tests := tst-shm tst-clock tst-clock_nanosleep tst-timer tst-timer2 \
+ tst-aio tst-aio64 tst-aio2 tst-aio3 tst-aio4 tst-aio5 tst-aio6 \
+- tst-aio7 tst-mqueue1 tst-mqueue2 tst-mqueue3 tst-mqueue4 \
++ tst-aio7 tst-aio9 tst-aio10 \
++ tst-mqueue1 tst-mqueue2 tst-mqueue3 tst-mqueue4 \
+ tst-mqueue5 tst-mqueue6 tst-mqueue7 tst-mqueue8 tst-mqueue9 \
+ tst-timer3 tst-timer4 tst-timer5 \
+ tst-cpuclock1 tst-cpuclock2 \
+--- libc/rt/tst-aio10.c.jj 2006-02-22 19:02:58.000000000 +0100
++++ libc/rt/tst-aio10.c 2006-02-22 19:02:58.000000000 +0100
+@@ -0,0 +1,119 @@
++#include <aio.h>
++#include <errno.h>
++#include <signal.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <pthread.h>
++#include <unistd.h>
++
++static pthread_barrier_t b;
++static pthread_t main_thread;
++static int flag;
++
++
++static void *
++tf (void *arg)
++{
++ int e = pthread_barrier_wait (&b);
++ if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
++ {
++ puts ("child: barrier_wait failed");
++ exit (1);
++ }
++
++ /* There is unfortunately no other way to try to make sure the other
++ thread reached the aio_suspend call. This test could fail on
++ highly loaded machines. */
++ sleep (2);
++
++ pthread_kill (main_thread, SIGUSR1);
++
++ while (1)
++ sleep (1000);
++
++ return NULL;
++}
++
++
++static void
++sh (int sig)
++{
++ flag = 1;
++}
++
++
++static int
++do_test (void)
++{
++ main_thread = pthread_self ();
++
++ struct sigaction sa;
++
++ sa.sa_handler = sh;
++ sa.sa_flags = 0;
++ sigemptyset (&sa.sa_mask);
++
++ if (sigaction (SIGUSR1, &sa, NULL) != 0)
++ {
++ puts ("sigaction failed");
++ return 1;
++ }
++
++ if (pthread_barrier_init (&b, NULL, 2) != 0)
++ {
++ puts ("barrier_init");
++ return 1;
++ }
++
++ int fds[2];
++ if (pipe (fds) != 0)
++ {
++ puts ("pipe failed");
++ return 1;
++ }
++
++ char buf[42];
++ struct aiocb req;
++ req.aio_fildes = fds[0];
++ req.aio_lio_opcode = LIO_READ;
++ req.aio_reqprio = 0;
++ req.aio_offset = 0;
++ req.aio_buf = buf;
++ req.aio_nbytes = sizeof (buf);
++ req.aio_sigevent.sigev_notify = SIGEV_NONE;
++
++ pthread_t th;
++ if (pthread_create (&th, NULL, tf, NULL) != 0)
++ {
++ puts ("create failed");
++ return 1;
++ }
++
++ int e = pthread_barrier_wait (&b);
++ if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
++ {
++ puts ("parent: barrier_wait failed");
++ exit (1);
++ }
++
++ struct aiocb *list[1];
++ list[0] = &req;
++
++ e = lio_listio (LIO_WAIT, list, 1, NULL);
++ if (e != -1)
++ {
++ puts ("lio_listio succeeded");
++ return 1;
++ }
++ if (errno != EINTR)
++ {
++ printf ("lio_listio did not return EINTR: %d (%d = %m)\n", e, errno);
++ return 1;
++ }
++
++ return 0;
++}
++
++#define TEST_FUNCTION do_test ()
++#define TIMEOUT 5
++#include "../test-skeleton.c"
+--- libc/rt/tst-aio9.c.jj 2006-02-22 19:02:58.000000000 +0100
++++ libc/rt/tst-aio9.c 2006-02-22 19:02:58.000000000 +0100
+@@ -0,0 +1,124 @@
++#include <aio.h>
++#include <errno.h>
++#include <signal.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <pthread.h>
++#include <unistd.h>
++
++static pthread_barrier_t b;
++static pthread_t main_thread;
++static int flag;
++
++
++static void *
++tf (void *arg)
++{
++ int e = pthread_barrier_wait (&b);
++ if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
++ {
++ puts ("child: barrier_wait failed");
++ exit (1);
++ }
++
++ /* There is unfortunately no other way to try to make sure the other
++ thread reached the aio_suspend call. This test could fail on
++ highly loaded machines. */
++ sleep (2);
++
++ pthread_kill (main_thread, SIGUSR1);
++
++ while (1)
++ sleep (1000);
++
++ return NULL;
++}
++
++
++static void
++sh (int sig)
++{
++ flag = 1;
++}
++
++
++static int
++do_test (void)
++{
++ main_thread = pthread_self ();
++
++ struct sigaction sa;
++
++ sa.sa_handler = sh;
++ sa.sa_flags = 0;
++ sigemptyset (&sa.sa_mask);
++
++ if (sigaction (SIGUSR1, &sa, NULL) != 0)
++ {
++ puts ("sigaction failed");
++ return 1;
++ }
++
++ if (pthread_barrier_init (&b, NULL, 2) != 0)
++ {
++ puts ("barrier_init");
++ return 1;
++ }
++
++ int fds[2];
++ if (pipe (fds) != 0)
++ {
++ puts ("pipe failed");
++ return 1;
++ }
++
++ char buf[42];
++ struct aiocb req;
++ req.aio_fildes = fds[0];
++ req.aio_reqprio = 0;
++ req.aio_offset = 0;
++ req.aio_buf = buf;
++ req.aio_nbytes = sizeof (buf);
++ req.aio_sigevent.sigev_notify = SIGEV_NONE;
++
++ if (aio_read (&req) != 0)
++ {
++ puts ("aio_read failed");
++ return 1;
++ }
++
++ pthread_t th;
++ if (pthread_create (&th, NULL, tf, NULL) != 0)
++ {
++ puts ("create failed");
++ return 1;
++ }
++
++ int e = pthread_barrier_wait (&b);
++ if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
++ {
++ puts ("parent: barrier_wait failed");
++ exit (1);
++ }
++
++ const struct aiocb *list[1];
++ list[0] = &req;
++
++ e = aio_suspend (list, 1, NULL);
++ if (e != -1)
++ {
++ puts ("aio_suspend succeeded");
++ return 1;
++ }
++ if (errno != EINTR)
++ {
++ puts ("aio_suspend did not return EINTR");
++ return 1;
++ }
++
++ return 0;
++}
++
++#define TEST_FUNCTION do_test ()
++#define TIMEOUT 5
++#include "../test-skeleton.c"
+--- libc/nptl/sysdeps/pthread/aio_misc.h.jj 2006-02-22 19:02:58.000000000 +0100
++++ libc/nptl/sysdeps/pthread/aio_misc.h 2006-02-22 19:02:58.000000000 +0100
+@@ -0,0 +1,74 @@
++/* Copyright (C) 2006 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++/* We define a special synchronization primitive for AIO. POSIX
++ conditional variables would be ideal but the pthread_cond_*wait
++ operations do not return on EINTR. This is a requirement for
++ correct aio_suspend and lio_listio implementations. */
++
++#include <assert.h>
++#include <pthreadP.h>
++#include <lowlevellock.h>
++
++#define DONT_NEED_AIO_MISC_COND 1
++
++#define AIO_MISC_NOTIFY(waitlist) \
++ do { \
++ if (*waitlist->counterp > 0 && --*waitlist->counterp == 0) \
++ lll_futex_wake (waitlist->counterp, 1); \
++ } while (0)
++
++#define AIO_MISC_WAIT(result, futex, timeout, cancel) \
++ do { \
++ volatile int *futexaddr = &futex; \
++ int oldval = futex; \
++ \
++ if (oldval != 0) \
++ { \
++ pthread_mutex_unlock (&__aio_requests_mutex); \
++ \
++ int oldtype; \
++ if (cancel) \
++ oldtype = LIBC_CANCEL_ASYNC (); \
++ \
++ int status; \
++ do \
++ { \
++ status = lll_futex_timed_wait (futexaddr, oldval, timeout); \
++ if (status != -EWOULDBLOCK) \
++ break; \
++ \
++ oldval = *futexaddr; \
++ } \
++ while (oldval != 0); \
++ \
++ if (cancel) \
++ LIBC_CANCEL_RESET (oldtype); \
++ \
++ if (status == -EINTR) \
++ result = EINTR; \
++ else if (status == -ETIMEDOUT) \
++ result = EAGAIN; \
++ else \
++ assert (status == 0 || status == -EWOULDBLOCK); \
++ \
++ pthread_mutex_lock (&__aio_requests_mutex); \
++ } \
++ } while (0)
++
++#include_next <aio_misc.h>
--- /dev/null
+2006-04-21 Jakub Jelinek <jakub@redhat.com>
+
+ * argp/argp.h (__option_is_short): Check upper limit of
+ __key. isprint() requires its argument to have the value
+ of an unsigned char or EOF.
+ Patch by Sergey Poznyakoff <gray@Mirddin.farlep.net>.
+
+--- libc/argp/argp.h 14 Oct 2005 05:53:47 -0000 1.31
++++ libc/argp/argp.h 22 Apr 2006 15:08:26 -0000 1.32
+@@ -24,6 +24,7 @@
+ #include <stdio.h>
+ #include <ctype.h>
+ #include <getopt.h>
++#include <limits.h>
+
+ #define __need_error_t
+ #include <errno.h>
+@@ -574,7 +575,7 @@ __NTH (__option_is_short (__const struct
+ else
+ {
+ int __key = __opt->key;
+- return __key > 0 && isprint (__key);
++ return __key > 0 && __key <= UCHAR_MAX && isprint (__key);
+ }
+ }
+
--- /dev/null
+2005-08-08 Ulrich Drepper <drepper@redhat.com>
+
+ * argp/argp-help.c: Use _IO_vasprintf instead of vasprintf.
+
+2005-08-08 Roland McGrath <roland@redhat.com>
+
+ * argp/argp-help.c (__argp_error): __asprintf -> vasprintf.
+ (__argp_failure): Likewise.
+
+--- libc/argp/argp-help.c 20 Jul 2005 17:50:29 -0000 1.45
++++ libc/argp/argp-help.c 9 Aug 2005 01:26:22 -0000 1.47
+@@ -48,7 +48,8 @@ char *alloca ();
+ #include <stdarg.h>
+ #include <ctype.h>
+ #include <limits.h>
+-#ifdef USE_IN_LIBIO
++#ifdef _LIBC
++# include <../libio/libioP.h>
+ # include <wchar.h>
+ #endif
+
+@@ -1768,7 +1769,7 @@ __argp_error (const struct argp_state *s
+ {
+ char *buf;
+
+- if (__asprintf (&buf, fmt, ap) < 0)
++ if (_IO_vasprintf (&buf, fmt, ap) < 0)
+ buf = NULL;
+
+ __fwprintf (stream, L"%s: %s\n",
+@@ -1847,7 +1848,7 @@ __argp_failure (const struct argp_state
+ {
+ char *buf;
+
+- if (__asprintf (&buf, fmt, ap) < 0)
++ if (_IO_vasprintf (&buf, fmt, ap) < 0)
+ buf = NULL;
+
+ __fwprintf (stream, L": %s", buf);
--- /dev/null
+2005-10-13 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #1373]
+ * argp/argp.h: Remove __NTH for __argp_usage inline function.
+
+--- libc/argp/argp.h 7 Sep 2004 22:23:45 -0000 1.30
++++ libc/argp/argp.h 14 Oct 2005 05:53:47 -0000 1.31
+@@ -561,7 +561,7 @@ extern void *__argp_input (__const struc
+ # endif
+
+ ARGP_EI void
+-__NTH (__argp_usage (__const struct argp_state *__state))
++__argp_usage (__const struct argp_state *__state)
+ {
+ __argp_state_help (__state, stderr, ARGP_HELP_STD_USAGE);
+ }
--- /dev/null
+2005-10-14 Ulrich Drepper <drepper@redhat.com>
+
+ * time/asctime.c (asctime_internal): Use __snprintf instead of
+ snprintf to avoid PLT entry.
+
+ [BZ #1460]
+ * time/asctime.c (asctime_internal): New function, derived from
+ asctime_r. Takes additional parameter which is the buffer length.
+ Use snprintf instead sprintf, if it overflows, fail.
+ (asctime_r): Call asctime_internal with 26 as buffer length.
+ (asctime): Call asctime_internal with length of internal buffer.
+ * time/Makefile (tests): Add bug-asctime_r.
+ * time/bug-asctime_r.c: New file.
+
+ [BZ #1459]
+ * time/asctime.c (__asctime_r): Check for tm_year computation to
+ overflow and fail in this case.
+ * time/Makefile (tests): Add bug-asctime.
+ * time/bug-asctime.c: New file.
+
+--- libc/time/asctime.c 3 Aug 2002 12:08:54 -0000 1.15
++++ libc/time/asctime.c 14 Oct 2005 21:15:47 -0000 1.18
+@@ -18,6 +19,7 @@
+
+ #include "../locale/localeinfo.h"
+ #include <errno.h>
++#include <limits.h>
+ #include <stdio.h>
+ #include <time.h>
+
+@@ -29,17 +31,9 @@ extern const struct locale_data _nl_C_LC
+ static const char format[] = "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n";
+ static char result[ 3+1+ 3+1+20+1+20+1+20+1+20+1+20+1 + 1];
+
+-/* Returns a string of the form "Day Mon dd hh:mm:ss yyyy\n"
+- which is the representation of TP in that form. */
+-char *
+-asctime (const struct tm *tp)
+-{
+- return __asctime_r (tp, result);
+-}
+-libc_hidden_def (asctime)
+
+-char *
+-__asctime_r (const struct tm *tp, char *buf)
++static char *
++asctime_internal (const struct tm *tp, char *buf, size_t buflen)
+ {
+ if (tp == NULL)
+ {
+@@ -47,15 +41,51 @@ __asctime_r (const struct tm *tp, char *
+ return NULL;
+ }
+
+- if (sprintf (buf, format,
+- (tp->tm_wday < 0 || tp->tm_wday >= 7 ?
+- "???" : ab_day_name (tp->tm_wday)),
+- (tp->tm_mon < 0 || tp->tm_mon >= 12 ?
+- "???" : ab_month_name (tp->tm_mon)),
+- tp->tm_mday, tp->tm_hour, tp->tm_min,
+- tp->tm_sec, 1900 + tp->tm_year) < 0)
++ /* We limit the size of the year which can be printed. Using the %d
++ format specifier used the addition of 1900 would overflow the
++ number and a negative vaue is printed. For some architectures we
++ could in theory use %ld or an evern larger integer format but
++ this would mean the output needs more space. This would not be a
++ problem if the 'asctime_r' interface would be defined sanely and
++ a buffer size would be passed. */
++ if (__builtin_expect (tp->tm_year > INT_MAX - 1900, 0))
++ {
++ eoverflow:
++ __set_errno (EOVERFLOW);
++ return NULL;
++ }
++
++ int n = __snprintf (buf, buflen, format,
++ (tp->tm_wday < 0 || tp->tm_wday >= 7 ?
++ "???" : ab_day_name (tp->tm_wday)),
++ (tp->tm_mon < 0 || tp->tm_mon >= 12 ?
++ "???" : ab_month_name (tp->tm_mon)),
++ tp->tm_mday, tp->tm_hour, tp->tm_min,
++ tp->tm_sec, 1900 + tp->tm_year);
++ if (n < 0)
+ return NULL;
++ if (n >= buflen)
++ goto eoverflow;
+
+ return buf;
+ }
++
++
++/* Like asctime, but write result to the user supplied buffer. The
++ buffer is only guaranteed to be 26 bytes in length. */
++char *
++__asctime_r (const struct tm *tp, char *buf)
++{
++ return asctime_internal (tp, buf, 26);
++}
+ weak_alias (__asctime_r, asctime_r)
++
++
++/* Returns a string of the form "Day Mon dd hh:mm:ss yyyy\n"
++ which is the representation of TP in that form. */
++char *
++asctime (const struct tm *tp)
++{
++ return asctime_internal (tp, result, sizeof (result));
++}
++libc_hidden_def (asctime)
+--- libc/time/bug-asctime_r.c 1 Jan 1970 00:00:00 -0000
++++ libc/time/bug-asctime_r.c 14 Oct 2005 15:19:22 -0000 1.2
+@@ -0,0 +1,32 @@
++#include <errno.h>
++#include <limits.h>
++#include <stdio.h>
++#include <time.h>
++
++
++static int
++do_test (void)
++{
++ int result = 0;
++ time_t t = time (NULL);
++ struct tm *tp = localtime (&t);
++ tp->tm_year = 10000 - 1900;
++ char buf[1000];
++ errno = 0;
++ buf[26] = '\xff';
++ char *s = asctime_r (tp, buf);
++ if (s != NULL || errno != EOVERFLOW)
++ {
++ puts ("asctime_r did not fail correctly");
++ result = 1;
++ }
++ if (buf[26] != '\xff')
++ {
++ puts ("asctime_r overwrote 27th byte in buffer");
++ result = 1;
++ }
++ return result;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- libc/time/bug-asctime.c 1 Jan 1970 00:00:00 -0000
++++ libc/time/bug-asctime.c 14 Oct 2005 14:54:27 -0000 1.2
+@@ -0,0 +1,33 @@
++#include <errno.h>
++#include <limits.h>
++#include <stdio.h>
++#include <time.h>
++
++
++static int
++do_test (void)
++{
++ int result = 0;
++ time_t t = time (NULL);
++ struct tm *tp = localtime (&t);
++ tp->tm_year = INT_MAX;
++ errno = 0;
++ char *s = asctime (tp);
++ if (s != NULL || errno != EOVERFLOW)
++ {
++ puts ("asctime did not fail correctly");
++ result = 1;
++ }
++ char buf[1000];
++ errno = 0;
++ s = asctime_r (tp, buf);
++ if (s != NULL || errno != EOVERFLOW)
++ {
++ puts ("asctime_r did not fail correctly");
++ result = 1;
++ }
++ return result;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- libc/time/Makefile 27 Apr 2005 04:31:51 -0000 1.107
++++ libc/time/Makefile 14 Oct 2005 15:16:17 -0000 1.109
+@@ -35,7 +35,7 @@ distribute := datemsk
+
+ tests := test_time clocktest tst-posixtz tst-strptime tst_wcsftime \
+ tst-getdate tst-mktime tst-mktime2 tst-ftime_l tst-strftime \
+- tst-mktime3 tst-strptime2
++ tst-mktime3 tst-strptime2 bug-asctime bug-asctime_r
+
+ include ../Rules
+
--- /dev/null
+2005-11-21 Jakub Jelinek <jakub@redhat.com>
+
+ * sunrpc/bindrsvprt.c (bindresvport): Wrap around to startport
+ in the loop if port is bigger than endport, initially set to
+ ENDPORT. When changing startport, set endport and port
+ appropriately.
+
+--- libc/sunrpc/bindrsvprt.c 23 May 2005 19:03:43 -0000 1.11
++++ libc/sunrpc/bindrsvprt.c 22 Nov 2005 04:39:05 -0000 1.12
+@@ -74,14 +74,13 @@ bindresvport (int sd, struct sockaddr_in
+ int res = -1;
+
+ int nports = ENDPORT - startport + 1;
++ int endport = ENDPORT;
+ again:
+ for (i = 0; i < nports; ++i)
+ {
+ sin->sin_port = htons (port++);
+- if (port > ENDPORT)
+- {
+- port = startport;
+- }
++ if (port > endport)
++ port = startport;
+ res = __bind (sd, sin, sizeof (struct sockaddr_in));
+ if (res >= 0 || errno != EADDRINUSE)
+ break;
+@@ -90,7 +89,9 @@ bindresvport (int sd, struct sockaddr_in
+ if (i == nports && startport != LOWPORT)
+ {
+ startport = LOWPORT;
++ endport = STARTPORT - 1;
+ nports = STARTPORT - LOWPORT;
++ port = LOWPORT + port % (STARTPORT - LOWPORT);
+ goto again;
+ }
+
--- /dev/null
+2007-02-12 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/i386/bits/byteswap.h (__bswap_32): Add __amdfam10__
+ to the list of i486+ CPUs.
+ * sysdeps/x86_64/bits/byteswap.h (__bswap_32): Likewise.
+
+2007-01-24 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/i386/bits/byteswap.h (__bswap_32): Add __nocona__, __core2__
+ and __geode__ to the list of i486+ CPUs.
+ * sysdeps/x86_64/bits/byteswap.h (__bswap_32): Likewise.
+
+2006-08-24 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2734]
+ * sysdeps/i386/bits/byteswap.h (__bswap_32): Use same conditions
+ as in the x86-64 code to use bswap.
+
+--- libc/sysdeps/i386/bits/byteswap.h 24 Aug 2006 07:02:16 -0000 1.14
++++ libc/sysdeps/i386/bits/byteswap.h 12 Feb 2007 21:21:03 -0000 1.16
+@@ -65,7 +65,9 @@ __bswap_16 (unsigned short int __bsx)
+ /* To swap the bytes in a word the i486 processors and up provide the
+ `bswap' opcode. On i386 we have to use three instructions. */
+ # if !defined __i486__ && !defined __pentium__ && !defined __pentiumpro__ \
+- && !defined __pentium4__
++ && !defined __pentium4__ && !defined __k8__ && !defined __athlon__ \
++ && !defined __k6__ && !defined __nocona__ && !defined __core2__ \
++ && !defined __geode__ && !defined __amdfam10__
+ # define __bswap_32(x) \
+ (__extension__ \
+ ({ register unsigned int __v, __x = (x); \
+--- libc/sysdeps/x86_64/bits/byteswap.h 17 Aug 2003 06:32:00 -0000 1.1
++++ libc/sysdeps/x86_64/bits/byteswap.h 12 Feb 2007 21:21:03 -0000 1.3
+@@ -59,7 +60,9 @@
+ # if __WORDSIZE == 64 || (defined __i486__ || defined __pentium__ \
+ || defined __pentiumpro__ || defined __pentium4__ \
+ || defined __k8__ || defined __athlon__ \
+- || defined __k6__)
++ || defined __k6__ || defined __nocona__ \
++ || defined __core2__ || defined __geode__ \
++ || defined __amdfam10__)
+ /* To swap the bytes in a word the i486 processors and up provide the
+ `bswap' opcode. On i386 we have to use three instructions. */
+ # define __bswap_32(x) \
--- /dev/null
+2005-09-22 Roland McGrath <roland@redhat.com>
+
+ * Makefile ($(objpfx)c++-types-check.out): Use $<, not $^, in command.
+ Reported by Alexandre Oliva <aoliva@redhat.com>.
+
+2005-09-17 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #1051]
+ * wctype/wctype.h: Remove stray __END_NAMESPACE_C99.
+ * stdlib/stdlib.h: Use __END_NAMESPACE_STD instead of
+ __END_NAMESPACE_C99 in one place.
+ * scripts/begin-end-check.pl: New file.
+ Patch by Ralph Loader <suckfish@ihug.co.nz>.
+ * Makefile: Add rules to run scripts/begin-end-check.pl.
+
+--- libc/wctype/wctype.h 1 Sep 2002 12:38:06 -0000 1.36
++++ libc/wctype/wctype.h 17 Sep 2005 15:45:42 -0000 1.37
+@@ -44,7 +44,6 @@ typedef unsigned int wint_t;
+ # ifdef __USE_ISOC99
+ __USING_NAMESPACE_C99(wint_t)
+ # endif
+-__END_NAMESPACE_C99
+ # endif
+
+ /* Constant expression of type `wint_t' whose value does not correspond
+--- libc/stdlib/stdlib.h 15 Jul 2005 10:47:20 -0000 1.112
++++ libc/stdlib/stdlib.h 17 Sep 2005 15:42:47 -0000 1.113
+@@ -187,7 +187,7 @@ extern long int strtol (__const char *__
+ extern unsigned long int strtoul (__const char *__restrict __nptr,
+ char **__restrict __endptr, int __base)
+ __THROW __nonnull ((1));
+-__END_NAMESPACE_C99
++__END_NAMESPACE_STD
+
+ #if defined __GLIBC_HAVE_LONG_LONG && defined __USE_BSD
+ /* Convert a string to a quadword integer. */
+--- libc/Makefile 6 Apr 2005 02:16:07 -0000 1.246
++++ libc/Makefile 17 Sep 2005 17:15:50 -0000 1.248
+@@ -241,7 +241,7 @@ check-data := $(firstword $(wildcard \
+ $(foreach M,$(config-machine) $(base-machine),\
+ scripts/data/c++-types-$M-$(config-os).data)))
+ ifneq (,$(check-data))
+-$(objpfx)c++-types-check.out: $(check-data)
+- scripts/check-c++-types.sh $^ $(CXX) $(filter-out -std=gnu99 -Wstrict-prototypes,$(CFLAGS)) $(CPPFLAGS) > $@
++$(objpfx)c++-types-check.out: $(check-data) scripts/check-c++-types.sh
++ scripts/check-c++-types.sh $< $(CXX) $(filter-out -std=gnu99 -Wstrict-prototypes,$(CFLAGS)) $(CPPFLAGS) > $@
+ else
+ $(objpfx)c++-types-check.out:
+@@ -250,6 +250,56 @@ $(objpfx)c++-types-check.out:
+ endif
+ endif
+
++ifneq ($(PERL),no)
++installed-headers = argp/argp.h assert/assert.h catgets/nl_types.h \
++ crypt/crypt.h ctype/ctype.h debug/execinfo.h \
++ dirent/dirent.h dlfcn/dlfcn.h elf/elf.h elf/link.h \
++ gmon/sys/gmon.h gmon/sys/gmon_out.h gmon/sys/profil.h \
++ grp/grp.h iconv/iconv.h iconv/gconv.h \
++ $(wildcard inet/netinet/*.h) \
++ $(wildcard inet/arpa/*.h inet/protocols/*.h) \
++ inet/aliases.h inet/ifaddrs.h inet/netinet/ip6.h \
++ inet/netinet/icmp6.h intl/libintl.h io/sys/stat.h \
++ io/sys/statfs.h io/sys/vfs.h io/sys/statvfs.h \
++ io/fcntl.h io/sys/fcntl.h io/poll.h io/sys/poll.h \
++ io/utime.h io/ftw.h io/fts.h io/sys/sendfile.h \
++ libio/stdio.h libio/libio.h locale/locale.h \
++ locale/langinfo.h locale/xlocale.h login/utmp.h \
++ login/lastlog.h login/pty.h malloc/malloc.h \
++ malloc/obstack.h malloc/mcheck.h math/math.h \
++ math/complex.h math/fenv.h math/tgmath.h misc/sys/uio.h \
++ $(wildcard nis/rpcsvc/*.h) nptl_db/thread_db.h \
++ nptl/sysdeps/pthread/pthread.h nptl/semaphore.h \
++ nss/nss.h posix/sys/utsname.h posix/sys/times.h \
++ posix/sys/wait.h posix/sys/types.h posix/unistd.h \
++ posix/glob.h posix/regex.h posix/wordexp.h posix/fnmatch.h\
++ posix/getopt.h posix/tar.h posix/sys/unistd.h \
++ posix/sched.h posix/re_comp.h posix/wait.h \
++ posix/cpio.h posix/spawn.h pwd/pwd.h resolv/resolv.h \
++ resolv/netdb.h $(wildcard resolv/arpa/*.h) \
++ resource/sys/resource.h resource/sys/vlimit.h \
++ resource/sys/vtimes.h resource/ulimit.h rt/aio.h \
++ rt/mqueue.h setjmp/setjmp.h shadow/shadow.h \
++ signal/signal.h signal/sys/signal.h socket/sys/socket.h \
++ socket/sys/un.h stdio-common/printf.h \
++ stdio-common/stdio_ext.h stdlib/stdlib.h stdlib/alloca.h \
++ stdlib/monetary.h stdlib/fmtmsg.h stdlib/ucontext.h \
++ sysdeps/generic/inttypes.h sysdeps/generic/stdint.h \
++ stdlib/errno.h stdlib/sys/errno.h string/string.h \
++ string/strings.h string/memory.h string/endian.h \
++ string/argz.h string/envz.h string/byteswap.h \
++ $(wildcard sunrpc/rpc/*.h sunrpc/rpcsvc/*.h) \
++ sysvipc/sys/ipc.h sysvipc/sys/msg.h sysvipc/sys/sem.h \
++ sysvipc/sys/shm.h termios/termios.h \
++ termios/sys/termios.h termios/sys/ttychars.h time/time.h \
++ time/sys/time.h time/sys/timeb.h wcsmbs/wchar.h \
++ wctype/wctype.h
++
++tests: $(objpfx)begin-end-check.out
++$(objpfx)begin-end-check.out: scripts/begin-end-check.pl
++ $(PERL) scripts/begin-end-check.pl $(installed-headers) > $@
++endif
++
+ # The realclean target is just like distclean for the parent, but we want
+ # the subdirs to know the difference in case they care.
+ realclean distclean: parent-clean
+--- libc/scripts/begin-end-check.pl 1 Jan 1970 00:00:00 -0000
++++ libc/scripts/begin-end-check.pl 17 Sep 2005 17:15:23 -0000 1.1
+@@ -0,0 +1,47 @@
++#!/usr/bin/perl
++
++use strict;
++use warnings;
++
++# Check __BEGIN_NAMESPACE ... __END_NAMESPACE pairing in an include file.
++
++my $code = 0;
++for my $path (@ARGV) {
++ my $localcode = 0;
++ my @stack;
++
++ open my $in, '<', $path
++ or die "open $path failed: $!";
++
++ while (<$in>) {
++ if ( /^\s*__BEGIN_(.*)\b/ ) {
++ push @stack, $1;
++ }
++ elsif ( /^\s*__END_(.*)\b/ ) {
++ if (@stack) {
++ my $tag = pop @stack;
++ if ($1 ne $tag) {
++ print "$path:$.: BEGIN $tag paired with END $1\n";
++ $localcode = 1;
++ }
++ }
++ else {
++ print "$path:$.: END $1 does not match a begin\n";
++ $localcode = 1;
++ }
++ }
++ }
++
++ if (@stack) {
++ print "$path: Unmatched begin tags " . join (' ', @stack) ."\n";
++ $localcode = 1;
++ }
++
++ if ($localcode == 0) {
++ print "$path: OK\n";
++ } else {
++ $code = $localcode;
++ }
++}
++
++exit $code;
--- /dev/null
+2005-09-27 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #1078]
+ * libio/fileops.c (_IO_new_file_xsputn): Determine amount of
+ available space in non-line-buffered buffer correctly.
+ * libio/oldfileops.c (_IO_old_file_xsputn): Likewise.
+ * stdio-common/Makefile (tests): Add tst-fwrite.
+ * stdio-common/tst-fwrite.c: New file.
+
+--- libc/libio/fileops.c 4 Sep 2005 20:07:40 -0000 1.108
++++ libc/libio/fileops.c 27 Sep 2005 18:49:43 -0000 1.109
+@@ -1281,7 +1281,7 @@ _IO_new_file_xsputn (f, data, n)
+ register const char *s = (const char *) data;
+ _IO_size_t to_do = n;
+ int must_flush = 0;
+- _IO_size_t count;
++ _IO_size_t count = 0;
+
+ if (n <= 0)
+ return 0;
+@@ -1290,7 +1290,6 @@ _IO_new_file_xsputn (f, data, n)
+ (or the filebuf is unbuffered), use sys_write directly. */
+
+ /* First figure out how much space is available in the buffer. */
+- count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */
+ if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
+ {
+ count = f->_IO_buf_end - f->_IO_write_ptr;
+@@ -1308,6 +1307,9 @@ _IO_new_file_xsputn (f, data, n)
+ }
+ }
+ }
++ else if (f->_IO_write_end > f->_IO_write_ptr)
++ count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */
++
+ /* Then fill the buffer. */
+ if (count > 0)
+ {
+--- libc/libio/oldfileops.c 4 Sep 2005 20:09:33 -0000 1.29
++++ libc/libio/oldfileops.c 27 Sep 2005 18:48:29 -0000 1.30
+@@ -695,7 +695,7 @@ _IO_old_file_xsputn (f, data, n)
+ register const char *s = (char *) data;
+ _IO_size_t to_do = n;
+ int must_flush = 0;
+- _IO_size_t count;
++ _IO_size_t count = 0;
+
+ if (n <= 0)
+ return 0;
+@@ -704,7 +704,6 @@ _IO_old_file_xsputn (f, data, n)
+ (or the filebuf is unbuffered), use sys_write directly. */
+
+ /* First figure out how much space is available in the buffer. */
+- count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */
+ if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
+ {
+ count = f->_IO_buf_end - f->_IO_write_ptr;
+@@ -722,6 +721,9 @@ _IO_old_file_xsputn (f, data, n)
+ }
+ }
+ }
++ else if (f->_IO_write_end > f->_IO_write_ptr)
++ count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */
++
+ /* Then fill the buffer. */
+ if (count > 0)
+ {
+--- libc/stdio-common/Makefile 26 Sep 2005 23:58:58 -0000 1.94
++++ libc/stdio-common/Makefile 27 Sep 2005 19:38:26 -0000 1.95
+@@ -53,7 +53,7 @@ tests := tstscanf test_rdwr test-popen t
+ scanf11 scanf12 tst-tmpnam tst-cookie tst-obprintf tst-sscanf \
+ tst-swprintf tst-fseek tst-fmemopen test-vfprintf tst-gets \
+ tst-perror tst-sprintf tst-rndseek tst-fdopen tst-fphex bug14 bug15 \
+- tst-popen tst-unlockedio tst-fmemopen2 tst-fgets
++ tst-popen tst-unlockedio tst-fmemopen2 tst-fgets tst-fwrite
+
+ test-srcs = tst-unbputc tst-printf
+
+--- libc/stdio-common/tst-fwrite.c 1 Jan 1970 00:00:00 -0000
++++ libc/stdio-common/tst-fwrite.c 27 Sep 2005 19:39:08 -0000 1.1
+@@ -0,0 +1,70 @@
++/* Derived from the test case in
++ http://sourceware.org/bugzilla/show_bug.cgi?id=1078. */
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++
++#define OUT_SIZE 10000
++
++
++static int fd;
++
++static void prepare (void);
++#define PREPARE(argc, argv) prepare ()
++
++static int do_test (void);
++#define TEST_FUNCTION do_test ()
++
++#include "../test-skeleton.c"
++
++
++static void
++prepare (void)
++{
++ fd = create_temp_file ("tst-fwrite.", NULL);
++ if (fd == -1)
++ {
++ puts ("cannot create temporary file");
++ exit (1);
++ }
++}
++
++
++static int
++do_test (void)
++{
++ FILE* f = fdopen (fd, "w+");
++ if (f == NULL) {
++ puts ("cannot create stream");
++ return 1;
++ }
++ puts ("Opened temp file");
++
++ if (fwrite ("a", 1, 1, f) != 1)
++ {
++ puts ("1st fwrite failed");
++ return 1;
++ }
++ puts ("Wrote a byte");
++ fflush (f);
++
++ char buffer[10000];
++ size_t i = fread (buffer, 1, sizeof (buffer), f);
++ printf ("Read %zu bytes\n", i);
++
++ for (i = 0; i < OUT_SIZE; i++)
++ {
++ if (fwrite ("n", 1, 1, f) != 1)
++ {
++ printf ("fwrite in loop round %zu failed\n", i);
++ return 1;
++ }
++
++ if ((i + 1) % 1000 == 0)
++ printf ("wrote %zu bytes ...\n", i + 1);
++ }
++
++ printf ("Wrote %i bytes [done]\n", OUT_SIZE);
++
++ return 0;
++}
--- /dev/null
+2006-05-02 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #1201]
+ * posix/regex.h: g++ still cannot handled [restrict].
+
+--- libc/posix/regex.h 21 Apr 2006 18:20:51 -0000 1.39
++++ libc/posix/regex.h 2 May 2006 21:37:34 -0000 1.40
+@@ -525,7 +525,8 @@ extern int re_exec (const char *);
+ #endif
+ /* gcc 3.1 and up support the [restrict] syntax. */
+ #ifndef __restrict_arr
+-# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
++# if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) \
++ && !defined __GNUG__
+ # define __restrict_arr __restrict
+ # else
+ # define __restrict_arr
--- /dev/null
+2005-09-13 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #1228]
+ * include/limits.h (LLONG_MIN, LLONG_MAX, ULLONG_MAX): Make sure these
+ are defined for -D_GNU_SOURCE or -D_ISOC99_SOURCE even when not
+ -std=c99.
+
+--- libc/include/limits.h 6 Jul 2001 04:54:52 -0000 1.11
++++ libc/include/limits.h 16 Oct 2005 15:32:33 -0000 1.12
+@@ -122,20 +123,20 @@
+ #if defined __GNUC__ && !defined _GCC_LIMITS_H_
+ /* `_GCC_LIMITS_H_' is what GCC's file defines. */
+ # include_next <limits.h>
++#endif
+
+ /* The <limits.h> files in some gcc versions don't define LLONG_MIN,
+ LLONG_MAX, and ULLONG_MAX. Instead only the values gcc defined for
+ ages are available. */
+-# ifdef __USE_ISOC99
+-# ifndef LLONG_MIN
+-# define LLONG_MIN LONG_LONG_MIN
+-# endif
+-# ifndef LLONG_MAX
+-# define LLONG_MAX LONG_LONG_MAX
+-# endif
+-# ifndef ULLONG_MAX
+-# define ULLONG_MAX ULONG_LONG_MAX
+-# endif
++#if defined __USE_ISOC99 && defined __GNUC__
++# ifndef LLONG_MIN
++# define LLONG_MIN (-LLONG_MAX-1)
++# endif
++# ifndef LLONG_MAX
++# define LLONG_MAX __LONG_LONG_MAX__
++# endif
++# ifndef ULLONG_MAX
++# define ULLONG_MAX (LLONG_MAX * 2ULL + 1)
+ # endif
+ #endif
+
--- /dev/null
+2005-09-27 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #1230]
+ * stdlib/strtod_l.c (STRNCASECMP): Always use C locale object.
+ (TOLOWER_C): Define. Use it when recognizing inf and nan.
+ * stdlib/Makefile (tests): Add bug-strtod2.
+ * stdlib/bug-strtod2.c: New file.
+
+--- libc/stdlib/strtod_l.c 10 Dec 2004 04:41:20 -0000 1.9
++++ libc/stdlib/strtod_l.c 28 Sep 2005 06:06:51 -0000 1.11
+@@ -100,7 +100,9 @@ extern unsigned long long int ____strtou
+ # define ISDIGIT(Ch) __iswdigit_l ((Ch), loc)
+ # define ISXDIGIT(Ch) __iswxdigit_l ((Ch), loc)
+ # define TOLOWER(Ch) __towlower_l ((Ch), loc)
+-# define STRNCASECMP(S1, S2, N) __wcsncasecmp_l ((S1), (S2), (N), loc)
++# define TOLOWER_C(Ch) __towlower_l ((Ch), &_nl_C_locobj)
++# define STRNCASECMP(S1, S2, N) \
++ __wcsncasecmp_l ((S1), (S2), (N), &_nl_C_locobj)
+ # define STRTOULL(S, E, B) ____wcstoull_l_internal ((S), (E), (B), 0, loc)
+ #else
+ # define STRING_TYPE char
+@@ -110,7 +112,9 @@ extern unsigned long long int ____strtou
+ # define ISDIGIT(Ch) __isdigit_l ((Ch), loc)
+ # define ISXDIGIT(Ch) __isxdigit_l ((Ch), loc)
+ # define TOLOWER(Ch) __tolower_l ((Ch), loc)
+-# define STRNCASECMP(S1, S2, N) __strncasecmp_l ((S1), (S2), (N), loc)
++# define TOLOWER_C(Ch) __tolower_l ((Ch), &_nl_C_locobj)
++# define STRNCASECMP(S1, S2, N) \
++ __strncasecmp_l ((S1), (S2), (N), &_nl_C_locobj)
+ # define STRTOULL(S, E, B) ____strtoull_l_internal ((S), (E), (B), 0, loc)
+ #endif
+
+@@ -554,7 +558,7 @@ INTERNAL (__STRTOF) (nptr, endptr, group
+ else if (c < L_('0') || c > L_('9'))
+ {
+ /* Check for `INF' or `INFINITY'. */
+- if (TOLOWER (c) == L_('i') && STRNCASECMP (cp, L_("inf"), 3) == 0)
++ if (TOLOWER_C (c) == L_('i') && STRNCASECMP (cp, L_("inf"), 3) == 0)
+ {
+ /* Return +/- infinity. */
+ if (endptr != NULL)
+@@ -565,7 +569,7 @@ INTERNAL (__STRTOF) (nptr, endptr, group
+ return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL;
+ }
+
+- if (TOLOWER (c) == L_('n') && STRNCASECMP (cp, L_("nan"), 3) == 0)
++ if (TOLOWER_C (c) == L_('n') && STRNCASECMP (cp, L_("nan"), 3) == 0)
+ {
+ /* Return NaN. */
+ FLOAT retval = NAN;
+--- libc/stdlib/Makefile 22 Jul 2005 04:25:44 -0000 1.101
++++ libc/stdlib/Makefile 28 Sep 2005 06:08:26 -0000 1.102
+@@ -63,7 +63,7 @@ tests := tst-strtol tst-strtod testmb t
+ test-canon test-canon2 tst-strtoll tst-environ \
+ tst-xpg-basename tst-random tst-random2 tst-bsearch \
+ tst-limits tst-rand48 bug-strtod tst-setcontext \
+- test-a64l tst-qsort tst-system testmb2
++ test-a64l tst-qsort tst-system testmb2 bug-strtod2
+
+ include ../Makeconfig
+
+--- libc/stdlib/bug-strtod2.c 1 Jan 1970 00:00:00 -0000
++++ libc/stdlib/bug-strtod2.c 28 Sep 2005 06:08:02 -0000 1.1
+@@ -0,0 +1,46 @@
++#include <locale.h>
++#include <math.h>
++#include <stdio.h>
++#include <stdlib.h>
++
++static const char *tests[] =
++ {
++ "inf", "Inf", "iNf", "inF", "INf", "iNF", "INF", "InF",
++ "infinity", "Infinity", "InfInity", "INFINITY"
++ };
++#define ntests (sizeof (tests) / sizeof (tests[0]))
++
++static int
++do_test (void)
++{
++ /* The Turkish locale is notorious because tolower() maps 'I' to the
++ dotless lowercase 'i' and toupper() maps 'i' to an 'I' with a dot
++ above. */
++ if (setlocale (LC_ALL, "tr_TR.UTF-8") == NULL)
++ {
++ puts ("cannot set locale");
++ return 0;
++ }
++
++ int res = 0;
++ for (int i = 0; i < ntests; ++i)
++ {
++ char *endp;
++ double d = strtod (tests[i], &endp);
++ if (*endp != '\0')
++ {
++ printf ("did not consume all of '%s'\n", tests[i]);
++ res = 1;
++ }
++ if (!isinf (d))
++ {
++ printf ("'%s' does not pass isinf\n", tests[i]);
++ res = 1;
++ }
++ }
++
++ return res;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- libc/stdlib/Depend 1 Jan 1970 00:00:00 -0000
++++ libc/stdlib/Depend 28 Sep 2005 05:51:29 -0000 1.1
+@@ -0,0 +1 @@
++localedata
--- /dev/null
+2005-09-20 Roland McGrath <roland@redhat.com>
+
+ [BZ #1346]
+ * elf/dl-load.c (_dl_map_object_from_fd) [HAVE_Z_RELRO]: Do relro
+ magic on __stack_prot only if [SHARED]. Skip mprotect if __stack_prot
+ lies outside the page-rounded-down relro region.
+
+--- libc/elf/dl-load.c 2 Sep 2005 07:33:58 -0000 1.270
++++ libc/elf/dl-load.c 20 Sep 2005 07:46:12 -0000 1.271
+@@ -1314,22 +1314,37 @@ cannot allocate TLS data structures for
+
+ if (__builtin_expect ((stack_flags &~ GL(dl_stack_flags)) & PF_X, 0))
+ {
++ if (__builtin_expect (__check_caller (RETURN_ADDRESS (0),
++ allow_ldso|allow_libc),
++ 0) != 0)
++ {
++ errstring = N_("invalid caller");
++ goto call_lose;
++ }
++
+ /* The stack is presently not executable, but this module
+ requires that it be executable. We must change the
+ protection of the variable which contains the flags used in
+ the mprotect calls. */
+-#ifdef HAVE_Z_RELRO
++#if defined HAVE_Z_RELRO && defined SHARED
+ if (mode & __RTLD_DLOPEN)
+ {
+- uintptr_t p = ((uintptr_t) &__stack_prot) & ~(GLRO(dl_pagesize) - 1);
+- size_t s = (uintptr_t) &__stack_prot - p + sizeof (int);
++ const uintptr_t p = (uintptr_t) &__stack_prot & -GLRO(dl_pagesize);
++ const size_t s = (uintptr_t) (&__stack_prot + 1) - p;
+
+- __mprotect ((void *) p, s, PROT_READ|PROT_WRITE);
+- if (__builtin_expect (__check_caller (RETURN_ADDRESS (0),
+- allow_ldso|allow_libc) == 0,
+- 0))
++ struct link_map *const m = &GL(dl_rtld_map);
++ const uintptr_t relro_end = ((m->l_addr + m->l_relro_addr
++ + m->l_relro_size)
++ & -GLRO(dl_pagesize));
++ if (__builtin_expect (p + s <= relro_end, 1))
++ {
++ /* The variable lies in the region protected by RELRO. */
++ __mprotect ((void *) p, s, PROT_READ|PROT_WRITE);
++ __stack_prot |= PROT_READ|PROT_WRITE|PROT_EXEC;
++ __mprotect ((void *) p, s, PROT_READ);
++ }
++ else
+ __stack_prot |= PROT_READ|PROT_WRITE|PROT_EXEC;
+- __mprotect ((void *) p, s, PROT_READ);
+ }
+ else
+ #endif
--- /dev/null
+2005-11-03 Roland McGrath <roland@redhat.com>
+
+ [BZ #1548]
+ * sunrpc/svc.c (svc_getreqset): Use ffsl instead of ffs on fd_mask,
+ make sure constant is long.
+ From Jay Lan <jlan@engr.sgi.com>.
+
+--- libc/sunrpc/svc.c 9 Feb 2004 10:47:53 -0000 1.18
++++ libc/sunrpc/svc.c 3 Nov 2005 23:30:45 -0000 1.20
+@@ -372,7 +372,7 @@ svc_getreqset (fd_set *readfds)
+ setsize = FD_SETSIZE;
+ maskp = readfds->fds_bits;
+ for (sock = 0; sock < setsize; sock += NFDBITS)
+- for (mask = *maskp++; (bit = ffs (mask)); mask ^= (1 << (bit - 1)))
++ for (mask = *maskp++; (bit = ffsl (mask)); mask ^= (1L << (bit - 1)))
+ INTUSE(svc_getreq_common) (sock + bit - 1);
+ }
+ INTDEF (svc_getreqset)
--- /dev/null
+2005-12-23 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #1566]
+ * sysdeps/i386/i586/memusage.h: New file.
+ * sysdeps/i386/memusage.h: Don't define GETTIME.
+
+--- libc/sysdeps/i386/memusage.h 6 Jul 2001 04:55:52 -0000 1.3
++++ libc/sysdeps/i386/memusage.h 23 Dec 2005 15:27:21 -0000 1.4
+@@ -17,6 +17,5 @@
+ 02111-1307 USA. */
+
+ #define GETSP() ({ register uintptr_t stack_ptr asm ("esp"); stack_ptr; })
+-#define GETTIME(low,high) asm ("rdtsc" : "=a" (low), "=d" (high))
+
+ #include <sysdeps/generic/memusage.h>
+--- libc/sysdeps/i386/i586/memusage.h 1 Jan 1970 00:00:00 -0000
++++ libc/sysdeps/i386/i586/memusage.h 23 Dec 2005 15:26:46 -0000 1.1
+@@ -0,0 +1 @@
++#include "../i686/memusage.h"
--- /dev/null
+2005-10-31 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #1579]
+ * debug/execinfo.h: Change backtrace_symbols_fd comment.
+
+--- libc/debug/execinfo.h 22 Oct 2004 21:07:57 -0000 1.8
++++ libc/debug/execinfo.h 31 Oct 2005 15:25:14 -0000 1.9
+@@ -35,8 +35,7 @@ extern char **backtrace_symbols (void *_
+
+
+ /* This function is similar to backtrace_symbols() but it writes the result
+- immediately to a file and can therefore also be used in situations where
+- malloc() is not usable anymore. */
++ immediately to a file. */
+ extern void backtrace_symbols_fd (void *__const *__array, int __size, int __fd)
+ __THROW __nonnull ((1));
+
--- /dev/null
+2005-11-03 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #1774]
+ * sysdeps/posix/getaddrinfo.c (gaih_inet): Don't use simple
+ gethostbyname2 lookup if AI_V4MAPPED|AI_ALL is set.
+
+ * sysdeps/posix/getaddrinfo.c (gaih_inet): Avoid alloca when possible
+ while looking for scope delimiter.
+
+--- libc/sysdeps/posix/getaddrinfo.c 26 Sep 2005 21:10:16 -0000 1.89
++++ libc/sysdeps/posix/getaddrinfo.c 3 Nov 2005 18:53:55 -0000 1.90
+@@ -568,12 +568,14 @@ gaih_inet (const char *name, const struc
+
+ if (at->family == AF_UNSPEC)
+ {
+- char *namebuf = strdupa (name);
+- char *scope_delim;
++ char *namebuf = (char *) name;
++ char *scope_delim = strchr (name, SCOPE_DELIMITER);
+
+- scope_delim = strchr (namebuf, SCOPE_DELIMITER);
+- if (scope_delim != NULL)
+- *scope_delim = '\0';
++ if (__builtin_expect (scope_delim != NULL, 0))
++ {
++ namebuf = alloca (scope_delim - name + 1);
++ *((char *) __mempcpy (namebuf, name, scope_delim - name)) = '\0';
++ }
+
+ if (inet_pton (AF_INET6, namebuf, at->addr) > 0)
+ {
+@@ -629,7 +631,10 @@ gaih_inet (const char *name, const struc
+
+ /* If we do not have to look for IPv4 and IPv6 together, use
+ the simple, old functions. */
+- if (req->ai_family == AF_INET || req->ai_family == AF_INET6)
++ if (req->ai_family == AF_INET
++ || (req->ai_family == AF_INET6
++ && ((req->ai_flags & AI_V4MAPPED) == 0
++ || (req->ai_flags & AI_ALL) == 0)))
+ {
+ int family = req->ai_family;
+ size_t tmpbuflen = 512;
--- /dev/null
+2005-12-22 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #1913]
+ * sysdeps/unix/sysv/linux/i386/i486/sem_wait.S (__new_sem_wait):
+ Fix unwind info. Remove useless branch prediction prefix.
+
+--- libc/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_wait.S 26 Jan 2005 19:57:25 -0000 1.6
++++ libc/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_wait.S 22 Dec 2005 17:58:29 -0000 1.7
+@@ -57,7 +57,7 @@ __new_sem_wait:
+ cfi_offset(6, -12) /* %esi */
+ 3: movl (%ebx), %eax
+ 2: testl %eax, %eax
+- je,pn 1f
++ je 1f
+
+ leal -1(%eax), %edx
+ LOCK
+@@ -73,7 +73,7 @@ __new_sem_wait:
+ cfi_adjust_cfa_offset(-12)
+ ret
+
+- cfi_adjust_cfa_offset(8)
++ cfi_adjust_cfa_offset(12)
+ cfi_offset(3, -8) /* %ebx */
+ cfi_offset(6, -12) /* %esi */
+ 1: call __pthread_enable_asynccancel
--- /dev/null
+2005-11-24 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
+ (__cleanup_fct_attribute): Use __regparm__ not regparm.
+
+ * sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h: When
+ compiling 32-bit code we must define __cleanup_fct_attribute.
+
+005-11-24 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #1920]
+ * sysdeps/pthread/pthread.h (__pthread_unwind_next): Use
+ __attribute__ instead of __attribute.
+ * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h
+ (__cleanup_fct_attribute): Likewise.
+
+--- libc/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h 28 Sep 2004 10:27:49 -0000 1.17
++++ libc/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h 24 Nov 2005 18:27:08 -0000 1.19
+@@ -155,6 +155,6 @@ typedef union
+
+
+ /* Extra attributes for the cleanup functions. */
+-#define __cleanup_fct_attribute __attribute ((regparm (1)))
++#define __cleanup_fct_attribute __attribute__ ((__regparm__ (1)))
+
+ #endif /* bits/pthreadtypes.h */
+--- libc/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h 6 Oct 2004 18:05:42 -0000 1.20
++++ libc/nptl/sysdeps/unix/sysv/linux/x86_64/bits/pthreadtypes.h 24 Nov 2005 18:25:32 -0000 1.21
+@@ -192,4 +192,9 @@ typedef union
+ #endif
+
+
++#if __WORDSIZE == 32
++/* Extra attributes for the cleanup functions. */
++# define __cleanup_fct_attribute __attribute__ ((__regparm__ (1)))
++#endif
++
+ #endif /* bits/pthreadtypes.h */
+--- libc/nptl/sysdeps/pthread/pthread.h 11 Jul 2005 16:38:01 -0000 1.34
++++ libc/nptl/sysdeps/pthread/pthread.h 24 Nov 2005 18:15:53 -0000 1.35
+@@ -657,9 +657,9 @@ extern void __pthread_unregister_cancel_
+
+ /* Internal interface to initiate cleanup. */
+ extern void __pthread_unwind_next (__pthread_unwind_buf_t *__buf)
+- __cleanup_fct_attribute __attribute ((__noreturn__))
++ __cleanup_fct_attribute __attribute__ ((__noreturn__))
+ # ifndef SHARED
+- __attribute ((__weak__))
++ __attribute__ ((__weak__))
+ # endif
+ ;
+ #endif
--- /dev/null
+2005-11-25 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #1925]
+ * nis/ypclnt.c (yp_order): Correct test for invalid parameter.
+
+--- libc/nis/ypclnt.c 24 Mar 2005 00:16:58 -0000 1.51
++++ libc/nis/ypclnt.c 25 Nov 2005 16:04:44 -0000 1.52
+@@ -593,7 +593,7 @@ yp_order (const char *indomain, const ch
+ enum clnt_stat result;
+
+ if (indomain == NULL || indomain[0] == '\0' ||
+- inmap == NULL || inmap == '\0')
++ inmap == NULL || inmap[0] == '\0')
+ return YPERR_BADARGS;
+
+ req.domain = (char *) indomain;
--- /dev/null
+2006-04-23 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #1951]
+ * sysdeps/posix/sigset.c (sigset): Return correct value reflecting
+ previous signal state.
+ * signal/Makefile (tests): Add tst-sigset2.
+ * signal/tst-sigset2.c: New file.
+
+--- libc/sysdeps/posix/sigset.c 17 Jun 2005 22:47:23 -0000 1.7
++++ libc/sysdeps/posix/sigset.c 23 Apr 2006 19:04:13 -0000 1.8
+@@ -29,8 +29,10 @@ sigset (sig, disp)
+ int sig;
+ __sighandler_t disp;
+ {
+- struct sigaction act, oact;
++ struct sigaction act;
++ struct sigaction oact;
+ sigset_t set;
++ sigset_t oset;
+
+ #ifdef SIG_HOLD
+ /* Handle SIG_HOLD first. */
+@@ -45,10 +47,18 @@ sigset (sig, disp)
+ return SIG_ERR;
+
+ /* Add the signal set to the current signal mask. */
+- if (__sigprocmask (SIG_BLOCK, &set, NULL) < 0)
++ if (__sigprocmask (SIG_BLOCK, &set, &oset) < 0)
+ return SIG_ERR;
+
+- return SIG_HOLD;
++ /* If the signal was already blocked signal this to the caller. */
++ if (__sigismember (&oset, sig))
++ return SIG_HOLD;
++
++ /* We need to determine whether a specific handler is installed. */
++ if (__sigaction (sig, NULL, &oact) < 0)
++ return SIG_ERR;
++
++ return oact.sa_handler;
+ }
+ #endif /* SIG_HOLD */
+
+@@ -75,8 +85,9 @@ sigset (sig, disp)
+ return SIG_ERR;
+
+ /* Remove the signal set from the current signal mask. */
+- if (__sigprocmask (SIG_UNBLOCK, &set, NULL) < 0)
++ if (__sigprocmask (SIG_UNBLOCK, &set, &oset) < 0)
+ return SIG_ERR;
+
+- return oact.sa_handler;
++ /* If the signal was already blocked return SIG_HOLD. */
++ return __sigismember (&oset, sig) ? SIG_HOLD : oact.sa_handler;
+ }
+--- libc/signal/Makefile 29 Dec 2003 17:49:12 -0000 1.24
++++ libc/signal/Makefile 23 Apr 2006 19:03:28 -0000 1.25
+@@ -38,7 +37,7 @@ routines := signal raise killpg \
+ allocrtsig sigtimedwait sigwaitinfo sigqueue \
+ sighold sigrelse sigignore sigset
+
+-tests := tst-signal tst-sigset tst-sigsimple tst-raise
++tests := tst-signal tst-sigset tst-sigsimple tst-raise tst-sigset2
+
+ distribute := sigsetops.h testrtsig.h sigset-cvt-mask.h
+
+--- libc/signal/tst-sigset2.c 1 Jan 1970 00:00:00 -0000
++++ libc/signal/tst-sigset2.c 23 Apr 2006 19:03:05 -0000 1.1
+@@ -0,0 +1,184 @@
++/* sigset_SIG_HOLD_bug.c [BZ #1951] */
++#include <errno.h>
++#include <error.h>
++#include <inttypes.h>
++#include <signal.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include <sys/types.h>
++#include <sys/wait.h>
++
++#define TEST_SIG SIGINT
++
++
++/* Print mask of blocked signals for this process */
++static void
++printSigMask (const char *msg)
++{
++ sigset_t currMask;
++ int sig;
++ int cnt;
++
++ if (msg != NULL)
++ printf ("%s", msg);
++
++ if (sigprocmask (SIG_BLOCK, NULL, &currMask) == -1)
++ error (1, errno, "sigaction");
++
++ cnt = 0;
++ for (sig = 1; sig < NSIG; sig++)
++ {
++ if (sigismember (&currMask, sig))
++ {
++ cnt++;
++ printf ("\t\t%d (%s)\n", sig, strsignal (sig));
++ }
++ }
++
++ if (cnt == 0)
++ printf ("\t\t<empty signal set>\n");
++} /* printSigMask */
++
++static void
++handler (int sig)
++{
++ printf ("Caught signal %d\n", sig);
++ printSigMask ("Signal mask in handler\n");
++ printf ("Handler returning\n");
++ _exit (1);
++} /* handler */
++
++static void
++printDisposition (sighandler_t disp)
++{
++ if (disp == SIG_HOLD)
++ printf ("SIG_HOLD");
++ else if (disp == SIG_DFL)
++ printf ("SIG_DFL");
++ else if (disp == SIG_IGN)
++ printf ("SIG_IGN");
++ else
++ printf ("handled at %" PRIxPTR, (uintptr_t) disp);
++} /* printDisposition */
++
++static int
++returnTest1 (void)
++{
++ sighandler_t prev;
++
++ printf ("===== TEST 1 =====\n");
++ printf ("Blocking signal with sighold()\n");
++ if (sighold (TEST_SIG) == -1)
++ error (1, errno, "sighold");
++ printSigMask ("Signal mask after sighold()\n");
++
++ printf ("About to use sigset() to establish handler\n");
++ prev = sigset (TEST_SIG, handler);
++ if (prev == SIG_ERR)
++ error(1, errno, "sigset");
++
++ printf ("Previous disposition: ");
++ printDisposition (prev);
++ printf (" (should be SIG_HOLD)\n");
++ if (prev != SIG_HOLD)
++ {
++ printf("TEST FAILED!!!\n");
++ return 1;
++ }
++ return 0;
++} /* returnTest1 */
++
++static int
++returnTest2 (void)
++{
++ sighandler_t prev;
++
++ printf ("\n===== TEST 2 =====\n");
++
++ printf ("About to use sigset() to set SIG_HOLD\n");
++ prev = sigset (TEST_SIG, SIG_HOLD);
++ if (prev == SIG_ERR)
++ error (1, errno, "sigset");
++
++ printf ("Previous disposition: ");
++ printDisposition (prev);
++ printf (" (should be SIG_DFL)\n");
++ if (prev != SIG_DFL)
++ {
++ printf("TEST FAILED!!!\n");
++ return 1;
++ }
++ return 0;
++} /* returnTest2 */
++
++static int
++returnTest3 (void)
++{
++ sighandler_t prev;
++
++ printf ("\n===== TEST 3 =====\n");
++
++ printf ("About to use sigset() to set SIG_HOLD\n");
++ prev = sigset (TEST_SIG, SIG_HOLD);
++ if (prev == SIG_ERR)
++ error (1, errno, "sigset");
++
++ printf ("About to use sigset() to set SIG_HOLD (again)\n");
++ prev = sigset (TEST_SIG, SIG_HOLD);
++ if (prev == SIG_ERR)
++ error (1, errno, "sigset");
++
++ printf ("Previous disposition: ");
++ printDisposition (prev);
++ printf (" (should be SIG_HOLD)\n");
++ if (prev != SIG_HOLD)
++ {
++ printf("TEST FAILED!!!\n");
++ return 1;
++ }
++ return 0;
++} /* returnTest3 */
++
++int
++main (int argc, char *argv[])
++{
++ pid_t childPid;
++
++ childPid = fork();
++ if (childPid == -1)
++ error (1, errno, "fork");
++
++ if (childPid == 0)
++ exit (returnTest1 ());
++
++ int status;
++ if (TEMP_FAILURE_RETRY (waitpid (childPid, &status, 0)) != childPid)
++ error (1, errno, "waitpid");
++ int result = !WIFEXITED (status) || WEXITSTATUS (status) != 0;
++
++ childPid = fork();
++ if (childPid == -1)
++ error (1, errno, "fork");
++
++ if (childPid == 0)
++ exit (returnTest2 ());
++
++ if (TEMP_FAILURE_RETRY (waitpid (childPid, &status, 0)) != childPid)
++ error (1, errno, "waitpid");
++ result |= !WIFEXITED (status) || WEXITSTATUS (status) != 0;
++
++ childPid = fork();
++ if (childPid == -1)
++ error (1, errno, "fork");
++
++ if (childPid == 0)
++ exit (returnTest3 ());
++
++ if (TEMP_FAILURE_RETRY (waitpid (childPid, &status, 0)) != childPid)
++ error (1, errno, "waitpid");
++ result |= !WIFEXITED (status) || WEXITSTATUS (status) != 0;
++
++ return result;
++} /* main */
--- /dev/null
+2005-12-20 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/unix/sysv/linux/time.c: If __NR_time is not defined,
+ use sysdeps/unix/time.c implementation.
+
+2005-12-19 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #1952]
+ * sysdeps/unix/sysv/linux/time.c: New file.
+ * sysdeps/unix/sysv/linux/i386/syscalls.list: Remove time entry.
+
+--- libc/sysdeps/unix/sysv/linux/time.c 1 Jan 1970 00:00:00 -0000
++++ libc/sysdeps/unix/sysv/linux/time.c 20 Dec 2005 14:57:37 -0000 1.2
+@@ -0,0 +1,43 @@
++/* Copyright (C) 2005 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <stddef.h>
++#include <time.h>
++
++#include <sysdep.h>
++
++#ifdef __NR_time
++
++time_t
++time (t)
++ time_t *t;
++{
++ INTERNAL_SYSCALL_DECL (err);
++ time_t res = INTERNAL_SYSCALL (time, err, 1, NULL);
++ /* There cannot be any error. */
++ if (t != NULL)
++ *t = res;
++ return res;
++}
++libc_hidden_def (time)
++
++#else
++
++# include <sysdeps/unix/time.c>
++
++#endif
+--- libc/sysdeps/unix/sysv/linux/i386/syscalls.list 10 Mar 2004 08:38:15 -0000 1.19
++++ libc/sysdeps/unix/sysv/linux/i386/syscalls.list 20 Dec 2005 07:52:13 -0000 1.20
+@@ -5,5 +5,4 @@ vm86old EXTRA vm86old i:p __vm86old vm
+ vm86 - vm86 i:ip __vm86 vm86@@GLIBC_2.3.4
+ oldgetrlimit EXTRA getrlimit i:ip __old_getrlimit getrlimit@GLIBC_2.0
+ oldsetrlimit EXTRA setrlimit i:ip __old_setrlimit setrlimit@GLIBC_2.0
+-time - time Ei:p time
+ waitpid - waitpid Ci:ipi __waitpid waitpid __libc_waitpid
--- /dev/null
+2005-12-19 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #1955]
+ * timezone/zic.c (tofile;): Fix typo in symlink creation.
+ Patch by Phil Estes <pestes@us.ibm.com>.
+
+--- libc/timezone/zic.c 6 Aug 2005 05:40:57 -0000 1.20
++++ libc/timezone/zic.c 20 Dec 2005 07:55:45 -0000 1.21
+@@ -650,7 +650,7 @@ const char * const tofile;
+ "../");
+ symlinkcontents =
+ ecatalloc(symlinkcontents,
+- fromfile);
++ fromname);
+ result = symlink(symlinkcontents,
+ toname);
+ if (result == 0)
--- /dev/null
+2005-12-21 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #1962]
+ * io/fts.c (fts_open): Change type of len to size_t.
+ (fts_build): Remove cast in call to fts_alloc.
+ (fts_alloc): Change third parameter's type to size_t.
+
+ [BZ #1960]
+ * io/fts.c (fts_open): Avoid function call in MAX macro use.
+
+--- libc/io/fts.c 14 Sep 2004 04:24:44 -0000 1.29
++++ libc/io/fts.c 21 Dec 2005 08:33:31 -0000 1.31
+@@ -53,7 +53,7 @@ static char sccsid[] = "@(#)fts.c 8.6 (B
+ #endif
+
+
+-static FTSENT *fts_alloc (FTS *, const char *, int) internal_function;
++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;
+@@ -94,7 +94,6 @@ fts_open(argv, options, compar)
+ register FTSENT *p, *root;
+ register int nitems;
+ FTSENT *parent, *tmp;
+- int len;
+
+ /* Options check. */
+ if (options & ~FTS_OPTIONMASK) {
+@@ -120,7 +119,8 @@ fts_open(argv, options, compar)
+ #ifndef MAXPATHLEN
+ #define MAXPATHLEN 1024
+ #endif
+- if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))
++ size_t maxarglen = fts_maxarglen(argv);
++ if (fts_palloc(sp, MAX(maxarglen, MAXPATHLEN)))
+ goto mem1;
+
+ /* Allocate/initialize root's parent. */
+@@ -131,7 +131,8 @@ fts_open(argv, options, compar)
+ /* Allocate/initialize root(s). */
+ for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
+ /* Don't allow zero-length paths. */
+- if ((len = strlen(*argv)) == 0) {
++ size_t len = strlen(*argv);
++ if (len == 0) {
+ __set_errno (ENOENT);
+ goto mem3;
+ }
+@@ -690,7 +691,7 @@ fts_build(sp, type)
+ if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
+ continue;
+
+- if ((p = fts_alloc(sp, dp->d_name, (int)_D_EXACT_NAMLEN (dp))) == NULL)
++ 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;
+@@ -961,7 +962,7 @@ internal_function
+ fts_alloc(sp, name, namelen)
+ FTS *sp;
+ const char *name;
+- register int namelen;
++ size_t namelen;
+ {
+ register FTSENT *p;
+ size_t len;
--- /dev/null
+2005-12-16 Thorsten Kukuk <kukuk@suse.de>
+
+ [BZ #1978]
+ * sysdeps/unix/sysv/linux/internal_statvfs.c (__statvfs_getflags):
+ Map more filesystem types to a string.
+ * sysdeps/unix/sysv/linux/linux_fsinfo.h: Add SYSFS_MAGIC.
+
+--- libc/sysdeps/unix/sysv/linux/internal_statvfs.c 3 Apr 2004 17:32:18 -0000 1.13
++++ libc/sysdeps/unix/sysv/linux/internal_statvfs.c 20 Dec 2005 07:20:16 -0000 1.14
+@@ -71,6 +71,33 @@ __statvfs_getflags (const char *name, in
+ case NFS_SUPER_MAGIC:
+ fsname = "nfs";
+ break;
++ case SYSFS_MAGIC:
++ fsname = "sysfs";
++ break;
++ case REISERFS_SUPER_MAGIC:
++ fsname = "reiserfs";
++ break;
++ case XFS_SUPER_MAGIC:
++ fsname = "xfs";
++ break;
++ case JFS_SUPER_MAGIC:
++ fsname = "jfs";
++ break;
++ case HPFS_SUPER_MAGIC:
++ fsname = "hpfs";
++ break;
++ case DEVFS_SUPER_MAGIC:
++ fsname = "devfs";
++ break;
++ case ISOFS_SUPER_MAGIC:
++ fsname = "iso9660";
++ break;
++ case MSDOS_SUPER_MAGIC:
++ fsname = "msdos";
++ break;
++ case NTFS_SUPER_MAGIC:
++ fsname = "ntfs";
++ break;
+ }
+
+ FILE *mtab = __setmntent ("/proc/mounts", "r");
+--- libc/sysdeps/unix/sysv/linux/linux_fsinfo.h 17 Sep 2003 00:48:25 -0000 1.14
++++ libc/sysdeps/unix/sysv/linux/linux_fsinfo.h 20 Dec 2005 07:21:14 -0000 1.15
+@@ -135,6 +135,9 @@
+ /* Constants that identify the `vxfs' filesystem. */
+ #define VXFS_SUPER_MAGIC 0xa501fcf5
+
++/* Constants that identify the `sysfs´ filesystem. */
++#define SYSFS_MAGIC 0x62656572
++
+ /* Maximum link counts. */
+ #define COH_LINK_MAX 10000
+ #define EXT2_LINK_MAX 32000
--- /dev/null
+2006-01-05 H.J. Lu <hongjiu.lu@intel.com>
+
+ [BZ #2013]
+ * sysdeps/ia64/memccpy.S: Properly handle recovery for
+ predicated speculative load.
+
+--- libc/sysdeps/ia64/memccpy.S 19 Nov 2003 06:11:26 -0000 1.7
++++ libc/sysdeps/ia64/memccpy.S 2 Mar 2006 04:49:27 -0000 1.8
+@@ -183,27 +183,64 @@ ENTRY(memccpy)
+ br.ret.sptk.many b0
+
+ .recovery1:
+- adds src = -(MEMLAT + 6 + 1) * 8, asrc
++#if MEMLAT != 6
++# error "MEMLAT must be 6!"
++#endif
++ adds src = -8, asrc
+ mov loopcnt = ar.lc
+- mov tmp = ar.ec ;;
++ mov tmp = ar.ec
++ ;;
++(p[0]) adds src = -8, src
++ ;;
++(p[1]) adds src = -8, src
+ sub sh1 = (MEMLAT + 6 + 1), tmp
+- shr.u sh2 = sh2, 3
+- ;;
++ ;;
++(p[2]) adds src = -8, src
++ ;;
++(p[3]) adds src = -8, src
+ shl loopcnt = loopcnt, 3
+- sub src = src, sh2
++ ;;
++(p[4]) adds src = -8, src
++ ;;
++(p[5]) adds src = -8, src
+ shl sh1 = sh1, 3
++ ;;
++(p[6]) adds src = -8, src
++ ;;
++(p[7]) adds src = -8, src
+ shl tmp = tmp, 3
+ ;;
++(p[8]) adds src = -8, src
++ ;;
++(p[9]) adds src = -8, src
++ shr.u sh2 = sh2, 3
++ ;;
++(p[10]) adds src = -8, src
++ ;;
++(p[11]) adds src = -8, src
+ add len = len, loopcnt
+- add src = sh1, src ;;
++ ;;
++ sub src = src, sh2
++ ;;
+ add len = tmp, len
+-.back1:
++ add src = sh1, src
+ br.cond.sptk .cpyfew
+
+ .recovery2:
+- add tmp = -(MEMLAT + 3) * 8, src
++#if MEMLAT != 6
++# error "MEMLAT must be 6!"
++#endif
++ add tmp = -8, src
+ (p7) br.cond.spnt .gotit
+ ;;
++(p[0]) add tmp = -8, tmp ;;
++(p[1]) add tmp = -8, tmp ;;
++(p[2]) add tmp = -8, tmp ;;
++(p[3]) add tmp = -8, tmp ;;
++(p[4]) add tmp = -8, tmp ;;
++(p[5]) add tmp = -8, tmp ;;
++(p[6]) add tmp = -8, tmp ;;
++(p[7]) add tmp = -8, tmp ;;
+ ld8 r[MEMLAT+2] = [tmp] ;;
+ xor pos0[1] = r[MEMLAT+2], charx8 ;;
+ czx1.r pos0[1] = pos0[1] ;;
--- /dev/null
+2005-12-21 Roland McGrath <roland@redhat.com>
+
+ [BZ #2066]
+ * intl/l10nflist.c (_nl_make_l10nflist): Free ABS_FILENAME when later
+ malloc fails.
+
+--- libc/intl/l10nflist.c 26 Sep 2004 05:06:25 -0000 1.32
++++ libc/intl/l10nflist.c 22 Dec 2005 01:03:27 -0000 1.33
+@@ -270,7 +270,10 @@ _nl_make_l10nflist (l10nfile_list, dirli
+ * (1 << pop (mask))
+ * sizeof (struct loaded_l10nfile *)));
+ if (retval == NULL)
+- return NULL;
++ {
++ free (abs_filename);
++ return NULL;
++ }
+
+ retval->filename = abs_filename;
+ /* If more than one directory is in the list this is a pseudo-entry
--- /dev/null
+2006-04-25 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2072]
+ * stdio-common/printf_fp.c: Fix potential memory leaks for
+ malloc'ed wbuffer which isn't freed in error conditions.
+
+--- libc/stdio-common/printf_fp.c 14 Jan 2006 12:09:45 -0000 1.57
++++ libc/stdio-common/printf_fp.c 25 Apr 2006 18:38:30 -0000 1.58
+@@ -72,7 +72,11 @@
+ { \
+ register const int outc = (ch); \
+ if (putc (outc, fp) == EOF) \
+- return -1; \
++ { \
++ if (buffer_malloced) \
++ free (wbuffer); \
++ return -1; \
++ } \
+ ++done; \
+ } while (0)
+
+@@ -83,7 +87,11 @@
+ if (len > 20) \
+ { \
+ if (PUT (fp, wide ? (const char *) wptr : ptr, outlen) != outlen) \
+- return -1; \
++ { \
++ if (buffer_malloced) \
++ free (wbuffer); \
++ return -1; \
++ } \
+ ptr += outlen; \
+ done += outlen; \
+ } \
+@@ -102,7 +110,11 @@
+ do \
+ { \
+ if (PAD (fp, ch, len) != len) \
+- return -1; \
++ { \
++ if (buffer_malloced) \
++ free (wbuffer); \
++ return -1; \
++ } \
+ done += len; \
+ } \
+ while (0)
+@@ -200,6 +212,11 @@ ___printf_fp (FILE *fp,
+ /* Nonzero if this is output on a wide character stream. */
+ int wide = info->wide;
+
++ /* Buffer in which we produce the output. */
++ wchar_t *wbuffer = NULL;
++ /* Flag whether wbuffer is malloc'ed or not. */
++ int buffer_malloced = 0;
++
+ auto wchar_t hack_digit (void);
+
+ wchar_t hack_digit (void)
+@@ -790,8 +807,7 @@ ___printf_fp (FILE *fp,
+
+ {
+ int width = info->width;
+- wchar_t *wbuffer, *wstartp, *wcp;
+- int buffer_malloced;
++ wchar_t *wstartp, *wcp;
+ int chars_needed;
+ int expscale;
+ int intdig_max, intdig_no = 0;
+@@ -1109,8 +1125,12 @@ ___printf_fp (FILE *fp,
+ buffer = (char *) malloc (2 + chars_needed + decimal_len
+ + ngroups * thousands_sep_len);
+ if (buffer == NULL)
+- /* Signal an error to the caller. */
+- return -1;
++ {
++ /* Signal an error to the caller. */
++ if (buffer_malloced)
++ free (wbuffer);
++ return -1;
++ }
+ }
+ else
+ buffer = (char *) alloca (2 + chars_needed + decimal_len
--- /dev/null
+2005-12-30 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2080]
+ * libio/iogetwline.c (_IO_getwline_info): Move return to correct
+ location.
+
+--- libc/libio/iogetwline.c 26 Feb 2002 01:43:50 -0000 1.7
++++ libc/libio/iogetwline.c 30 Dec 2005 18:06:43 -0000 1.8
+@@ -87,9 +87,9 @@ _IO_getwline_info (fp, buf, n, delim, ex
+ *ptr++ = wc;
+ else if (extract_delim < 0)
+ INTUSE(_IO_sputbackc) (fp, wc);
+- return ptr - buf;
+ if (extract_delim > 0)
+ ++len;
++ return ptr - buf;
+ }
+ *ptr++ = wc;
+ n--;
--- /dev/null
+2006-01-09 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2126]
+ * sysdeps/i386/i686/strtok.S: Store pointer to NUL byte if NULL is
+ returned.
+ * sysdeps/i386/strtok.S: Likewise.
+ * sysdeps/x86_64/strtok.S: Likewise.
+ * string/Makefile (tests): Add bug-strtok1.
+ * string/bug-strtok1.c: New file.
+
+--- libc/sysdeps/i386/strtok.S 4 May 2005 17:52:10 -0000 1.14
++++ libc/sysdeps/i386/strtok.S 10 Jan 2006 00:22:31 -0000 1.15
+@@ -385,6 +385,10 @@ L(epilogue):
+
+ L(returnNULL):
+ xorl %eax, %eax
++#ifdef USE_AS_STRTOK_R
++ movl SAVE(%esp), %ecx
++#endif
++ movl %edx, SAVE_PTR
+ RETURN_NULL_BOUNDED_POINTER
+ jmp L(epilogue)
+
+--- libc/sysdeps/i386/i686/strtok.S 4 May 2005 06:21:50 -0000 1.8
++++ libc/sysdeps/i386/i686/strtok.S 10 Jan 2006 00:23:13 -0000 1.9
+@@ -250,9 +250,9 @@ L(8): cmpl %eax, %edx
+ cmovne %ecx, %edx
+
+ /* Store the pointer to the next character. */
+-# ifdef USE_AS_STRTOK_R
++#ifdef USE_AS_STRTOK_R
+ movl SAVE(%esp), %ecx
+-# endif
++#endif
+ movl %edx, SAVE_PTR
+ CHECK_BOUNDS_HIGH (%edx, SAVE_PTR, jb)
+ RETURN_BOUNDED_POINTER (SAVE_PTR)
+@@ -271,6 +271,10 @@ L(epilogue):
+
+ L(returnNULL):
+ xorl %eax, %eax
++#ifdef USE_AS_STRTOK_R
++ movl SAVE(%esp), %ecx
++#endif
++ movl %edx, SAVE_PTR
+ RETURN_NULL_BOUNDED_POINTER
+ jmp L(epilogue)
+
+--- libc/sysdeps/x86_64/strtok.S 31 Mar 2005 10:00:13 -0000 1.3
++++ libc/sysdeps/x86_64/strtok.S 10 Jan 2006 00:12:59 -0000 1.4
+@@ -205,6 +205,8 @@ L(epilogue):
+
+ L(returnNULL):
+ xorq %rax, %rax
++ /* Store the pointer to the next character. */
++ movq %rdx, SAVE_PTR
+ jmp L(epilogue)
+
+ END (BP_SYM (FUNCTION))
+--- libc/string/bug-strtok1.c 1 Jan 1970 00:00:00 -0000
++++ libc/string/bug-strtok1.c 10 Jan 2006 00:12:13 -0000 1.1
+@@ -0,0 +1,45 @@
++/* See BZ #2126. */
++#include <string.h>
++#include <stdio.h>
++
++static int
++do_test (void)
++{
++ const char str[] = "axaaba";
++ char *token;
++ char *cp;
++ char *l;
++ int result = 0;
++
++ puts ("test strtok");
++ cp = strdupa (str);
++ printf ("cp = %p, len = %zu\n", cp, strlen (cp));
++ token = strtok (cp, "ab");
++ result |= token == NULL || strcmp (token, "x");
++ printf ("token: %s (%d)\n", token ? token : "NULL", result);
++ token = strtok(0, "ab");
++ result |= token != NULL;
++ printf ("token: %s (%d)\n", token ? token : "NULL", result);
++ token = strtok(0, "a");
++ result |= token != NULL;
++ printf ("token: %s (%d)\n", token ? token : "NULL", result);
++
++ puts ("test strtok_r");
++ cp = strdupa (str);
++ size_t len = strlen (cp);
++ printf ("cp = %p, len = %zu\n", cp, len);
++ token = strtok_r (cp, "ab", &l);
++ result |= token == NULL || strcmp (token, "x");
++ printf ("token: %s, next = %p (%d)\n", token ? token : "NULL", l, result);
++ token = strtok_r(0, "ab", &l);
++ result |= token != NULL || l != cp + len;
++ printf ("token: %s, next = %p (%d)\n", token ? token : "NULL", l, result);
++ token = strtok_r(0, "a", &l);
++ result |= token != NULL || l != cp + len;
++ printf ("token: %s, next = %p (%d)\n", token ? token : "NULL", l, result);
++
++ return result;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- libc/string/Makefile 12 Apr 2005 15:27:59 -0000 1.66
++++ libc/string/Makefile 10 Jan 2006 00:11:53 -0000 1.67
+@@ -53,7 +53,7 @@ tests := tester inl-tester noinl-tester
+ tst-strlen stratcliff tst-svc tst-inlcall \
+ bug-strncat1 bug-strspn1 bug-strpbrk1 tst-bswap \
+ tst-strtok tst-strxfrm bug-strcoll1 tst-strfry \
+- $(addprefix test-,$(strop-tests))
++ bug-strtok1 $(addprefix test-,$(strop-tests))
+ distribute := memcopy.h pagecopy.h tst-svc.expect test-string.h
+
+
--- /dev/null
+2006-01-15 Andreas Jaeger <aj@suse.de>
+
+ [BZ #2153]
+ * sysdeps/generic/s_cacosh.c (__cacosh): Do not return a negative
+ value. Patch by Wes Loewer <wjltemp-temp01@yahoo.com>.
+ * sysdeps/generic/s_cacoshl.c (__cacoshl): Likewise.
+ * sysdeps/generic/s_cacoshf.c (__cacoshf): Likewise.
+ * math/libm-test.inc (cacosh_test): Adjust for change.
+
+ * sysdeps/alpha/fpu/libm-test-ulps: Adopt for cacosh test change.
+ * sysdeps/hppa/fpu/libm-test-ulps: Likewise.
+ * sysdeps/i386/fpu/libm-test-ulps: Likewise.
+ * sysdeps/ia64/fpu/libm-test-ulps: Likewise.
+ * sysdeps/m68k/fpu/libm-test-ulps: Likewise.
+ * sysdeps/mips/fpu/libm-test-ulps: Likewise.
+ * sysdeps/powerpc/fpu/libm-test-ulps: Likewise.
+ * sysdeps/s390/fpu/libm-test-ulps: Likewise.
+ * sysdeps/x86_64/fpu/libm-test-ulps: Likewise.
+ * sysdeps/sh/sh4/fpu/libm-test-ulps: Likewise.
+ * sysdeps/sparc/sparc32/fpu/libm-test-ulps: Likewise.
+ * sysdeps/sparc/sparc64/fpu/libm-test-ulps: Likewise.
+
+--- libc/sysdeps/generic/s_cacosh.c 14 Dec 2005 10:12:27 -0000 1.1
++++ libc/sysdeps/generic/s_cacosh.c 15 Jan 2006 17:51:31 -0000 1.2
+@@ -73,6 +73,9 @@ __cacosh (__complex__ double x)
+
+ y = __csqrt (y);
+
++ if (__real__ x < 0.0)
++ y = -y;
++
+ __real__ y += __real__ x;
+ __imag__ y += __imag__ x;
+
+--- libc/sysdeps/generic/s_cacoshf.c 14 Dec 2005 10:12:45 -0000 1.1
++++ libc/sysdeps/generic/s_cacoshf.c 15 Jan 2006 17:51:31 -0000 1.2
+@@ -75,6 +75,9 @@ __cacoshf (__complex__ float x)
+
+ y = __csqrtf (y);
+
++ if (__real__ x < 0.0)
++ y = -y;
++
+ __real__ y += __real__ x;
+ __imag__ y += __imag__ x;
+
+--- libc/sysdeps/generic/s_cacoshl.c 14 Dec 2005 10:13:05 -0000 1.1
++++ libc/sysdeps/generic/s_cacoshl.c 15 Jan 2006 17:51:31 -0000 1.2
+@@ -73,6 +73,9 @@ __cacoshl (__complex__ long double x)
+
+ y = __csqrtl (y);
+
++ if (__real__ x < 0.0)
++ y = -y;
++
+ __real__ y += __real__ x;
+ __imag__ y += __imag__ x;
+
+--- libc/sysdeps/alpha/fpu/libm-test-ulps 17 Dec 2004 06:49:58 -0000 1.13
++++ libc/sysdeps/alpha/fpu/libm-test-ulps 15 Jan 2006 17:59:37 -0000 1.14
+@@ -20,12 +20,12 @@ float: 1
+ ifloat: 1
+
+ # cacosh
+-Test "Real part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Real part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 7
+ idouble: 1
+ ifloat: 7
+-Test "Imaginary part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Imaginary part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 3
+ idouble: 1
+--- libc/sysdeps/s390/fpu/libm-test-ulps 20 Jul 2005 18:18:56 -0000 1.13
++++ libc/sysdeps/s390/fpu/libm-test-ulps 15 Jan 2006 17:59:37 -0000 1.14
+@@ -17,12 +17,12 @@ float: 1
+ ifloat: 1
+
+ # cacosh
+-Test "Real part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Real part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 7
+ idouble: 1
+ ifloat: 7
+-Test "Imaginary part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Imaginary part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 3
+ idouble: 1
+--- libc/sysdeps/powerpc/fpu/libm-test-ulps 22 Dec 2005 00:56:05 -0000 1.15
++++ libc/sysdeps/powerpc/fpu/libm-test-ulps 15 Jan 2006 17:59:37 -0000 1.16
+@@ -17,12 +17,12 @@ float: 1
+ ifloat: 1
+
+ # cacosh
+-Test "Real part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Real part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 7
+ idouble: 1
+ ifloat: 7
+-Test "Imaginary part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Imaginary part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 3
+ idouble: 1
+--- libc/sysdeps/sparc/sparc32/fpu/libm-test-ulps 14 Jan 2006 12:09:02 -0000 1.13
++++ libc/sysdeps/sparc/sparc32/fpu/libm-test-ulps 15 Jan 2006 17:59:38 -0000 1.14
+@@ -33,10 +33,10 @@ ildouble: 1
+
+ # cacosh
+-Test "Real part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Real part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 7
+ idouble: 1
+ ifloat: 7
+-Test "Imaginary part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Imaginary part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 3
+--- libc/sysdeps/sparc/sparc64/fpu/libm-test-ulps 17 Dec 2004 07:40:44 -0000 1.16
++++ libc/sysdeps/sparc/sparc64/fpu/libm-test-ulps 15 Jan 2006 17:59:38 -0000 1.17
+@@ -33,14 +33,14 @@ ildouble: 1
+ ldouble: 1
+
+ # cacosh
+-Test "Real part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Real part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 7
+ idouble: 1
+ ifloat: 7
+ ildouble: 5
+ ldouble: 5
+-Test "Imaginary part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Imaginary part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 3
+ idouble: 1
+--- libc/sysdeps/mips/fpu/libm-test-ulps 23 Mar 2003 00:52:10 -0000 1.7
++++ libc/sysdeps/mips/fpu/libm-test-ulps 15 Jan 2006 17:59:37 -0000 1.8
+@@ -17,12 +17,12 @@ float: 1
+ ifloat: 1
+
+ # cacosh
+-Test "Real part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Real part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 7
+ idouble: 1
+ ifloat: 7
+-Test "Imaginary part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Imaginary part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 3
+ idouble: 1
+--- libc/sysdeps/sh/sh4/fpu/libm-test-ulps 23 Mar 2003 00:52:10 -0000 1.5
++++ libc/sysdeps/sh/sh4/fpu/libm-test-ulps 15 Jan 2006 17:59:38 -0000 1.6
+@@ -60,12 +60,12 @@ float: 1
+ ifloat: 1
+
+ # cacosh
+-Test "Real part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Real part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 7
+ idouble: 1
+ ifloat: 7
+-Test "Imaginary part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Imaginary part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 3
+ idouble: 1
+--- libc/sysdeps/i386/fpu/libm-test-ulps 30 Sep 2005 15:45:00 -0000 1.43
++++ libc/sysdeps/i386/fpu/libm-test-ulps 15 Jan 2006 17:59:37 -0000 1.44
+@@ -35,14 +35,14 @@ ildouble: 2
+ ldouble: 2
+
+ # cacosh
+-Test "Real part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Real part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 9
+ idouble: 1
+ ifloat: 9
+ ildouble: 6
+ ldouble: 6
+-Test "Imaginary part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Imaginary part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 4
+ idouble: 1
+--- libc/sysdeps/m68k/fpu/libm-test-ulps 24 Jun 2003 11:06:57 -0000 1.13
++++ libc/sysdeps/m68k/fpu/libm-test-ulps 15 Jan 2006 17:59:37 -0000 1.14
+@@ -36,14 +36,14 @@ ildouble: 2
+ ldouble: 2
+
+ # cacosh
+-Test "Real part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Real part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 7
+ idouble: 1
+ ifloat: 7
+ ildouble: 6
+ ldouble: 6
+-Test "Imaginary part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Imaginary part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ idouble: 1
+ ildouble: 2
+--- libc/sysdeps/ia64/fpu/libm-test-ulps 20 Dec 2005 15:17:24 -0000 1.18
++++ libc/sysdeps/ia64/fpu/libm-test-ulps 15 Jan 2006 17:59:37 -0000 1.19
+@@ -8,14 +8,14 @@ ildouble: 2
+ ldouble: 2
+
+ # cacosh
+-Test "Real part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Real part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 7
+ idouble: 1
+ ifloat: 7
+ ildouble: 7
+ ldouble: 7
+-Test "Imaginary part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Imaginary part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ idouble: 1
+ ildouble: 1
+--- libc/sysdeps/hppa/fpu/libm-test-ulps 23 Mar 2003 00:52:10 -0000 1.2
++++ libc/sysdeps/hppa/fpu/libm-test-ulps 15 Jan 2006 17:59:37 -0000 1.3
+@@ -17,12 +17,12 @@ float: 1
+ ifloat: 1
+
+ # cacosh
+-Test "Real part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Real part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 7
+ idouble: 1
+ ifloat: 7
+-Test "Imaginary part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Imaginary part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 3
+ idouble: 1
+--- libc/sysdeps/x86_64/fpu/libm-test-ulps 20 Jul 2005 18:15:21 -0000 1.10
++++ libc/sysdeps/x86_64/fpu/libm-test-ulps 15 Jan 2006 17:59:37 -0000 1.11
+@@ -48,14 +48,14 @@ ildouble: 2
+ ldouble: 2
+
+ # cacosh
+-Test "Real part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Real part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 7
+ idouble: 1
+ ifloat: 7
+ ildouble: 6
+ ldouble: 6
+-Test "Imaginary part of: cacosh (-2 - 3 i) == -1.9833870299165354323470769028940395 + 2.1414491111159960199416055713254211 i":
++Test "Imaginary part of: cacosh (-2 - 3 i) == 1.9833870299165354323470769028940395 - 2.1414491111159960199416055713254211 i":
+ double: 1
+ float: 3
+ idouble: 1
+--- libc/math/libm-test.inc 13 Oct 2005 19:07:12 -0000 1.66
++++ libc/math/libm-test.inc 15 Jan 2006 17:51:31 -0000 1.67
+@@ -1116,7 +1116,7 @@ cacosh_test (void)
+ TEST_c_c (cacosh, nan_value, nan_value, nan_value, nan_value);
+
+ TEST_c_c (cacosh, 0.75L, 1.25L, 1.13239363160530819522266333696834467L, 1.11752014915610270578240049553777969L);
+- TEST_c_c (cacosh, -2, -3, -1.9833870299165354323470769028940395L, 2.1414491111159960199416055713254211L);
++ TEST_c_c (cacosh, -2, -3, 1.9833870299165354323470769028940395L, -2.1414491111159960199416055713254211L);
+
+ END (cacosh, complex);
+ }
--- /dev/null
+2006-01-18 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2173]
+ * libio/fileops.c (_IO_new_file_fopen): If ,ccs= is given, also
+ set vtable to the wide vtable.
+ * libio/tst-fopenloc2.c: New file.
+ * libio/Makefile (tests): Add tst-fopenloc2.
+
+--- libc/libio/Makefile 16 Jan 2006 20:10:26 -0000 1.84
++++ libc/libio/Makefile 19 Jan 2006 01:22:48 -0000 1.85
+@@ -54,7 +54,7 @@ tests = tst_swprintf tst_wprintf tst_sws
+ tst-freopen bug-rewind bug-rewind2 bug-ungetc bug-fseek \
+ tst-mmap-eofsync tst-mmap-fflushsync bug-mmap-fflush \
+ tst-mmap2-eofsync tst-mmap-offend bug-fopena+ bug-wfflush \
+- bug-ungetc2 bug-ftell bug-ungetc3 bug-ungetc4
++ bug-ungetc2 bug-ftell bug-ungetc3 bug-ungetc4 tst-fopenloc2
+ test-srcs = test-freopen
+
+ all: # Make this the default target; it will be defined in Rules.
+--- libc/libio/fileops.c 27 Sep 2005 18:49:43 -0000 1.109
++++ libc/libio/fileops.c 19 Jan 2006 00:38:35 -0000 1.110
+@@ -399,6 +399,9 @@ _IO_new_file_fopen (fp, filename, mode,
+ /* And now the transliteration. */
+ cc->__cd_out.__cd.__data[0].__trans = &__libio_translit;
+
++ /* From now on use the wide character callback functions. */
++ ((struct _IO_FILE_plus *) fp)->vtable = fp->_wide_data->_wide_vtable;
++
+ /* Set the mode now. */
+ result->_mode = 1;
+ }
+--- libc/libio/tst-fopenloc2.c 1 Jan 1970 00:00:00 -0000
++++ libc/libio/tst-fopenloc2.c 19 Jan 2006 01:22:20 -0000 1.1
+@@ -0,0 +1,116 @@
++#include <errno.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <wchar.h>
++
++
++static const struct
++{
++ const char *enc;
++ const char *data;
++ size_t datalen;
++ const wchar_t *expected;
++ size_t expectedlen;
++} tests[] =
++ {
++ { "UCS-4LE", "a\0\0\0b\0\0\0", 8, L"ab", 2 },
++ { "UCS-4BE", "\0\0\0a\0\0\0b", 8, L"ab", 2 },
++ };
++#define ntests (sizeof (tests) / sizeof (tests[0]))
++
++
++static int do_test (void);
++#define TEST_FUNCTION do_test ()
++
++static void prepare (void);
++#define PREPARE(argc, argv) prepare ();
++
++#include "../test-skeleton.c"
++
++
++static int fd;
++static char *tmpname;
++
++
++static void
++prepare (void)
++{
++ fd = create_temp_file ("tst-fopenloc2", &tmpname);
++ if (fd == -1)
++ {
++ puts ("cannot open temp file");
++ exit (1);
++ }
++}
++
++
++static int
++do_test (void)
++{
++ for (int i = 0; i < ntests; ++i)
++ {
++ if (ftruncate (fd, 0) != 0)
++ {
++ printf ("ftruncate in round %d failed\n", i + 1);
++ return 1;
++ }
++
++ if (TEMP_FAILURE_RETRY (write (fd, tests[i].data, tests[i].datalen))
++ != tests[i].datalen)
++ {
++ printf ("write in round %d failed\n", i + 1);
++ return 1;
++ }
++
++ if (lseek (fd, 0, SEEK_SET) != 0)
++ {
++ printf ("lseek in round %d failed\n", i + 1);
++ return 1;
++ }
++
++ char *ccs;
++ if (asprintf (&ccs, "r,ccs=%s", tests[i].enc) == -1)
++ {
++ printf ("asprintf in round %d failed\n", i + 1);
++ return 1;
++ }
++
++ FILE *fp = fopen (tmpname, ccs);
++ if (fp == NULL)
++ {
++ printf ("fopen in round %d failed\n", i + 1);
++ return 1;
++ }
++
++#define LINELEN 100
++ wchar_t line[LINELEN];
++ if (fgetws (line, LINELEN, fp) != line)
++ {
++ printf ("fgetws in round %d failed\n", i + 1);
++ return 1;
++ }
++
++ if (wcslen (line) != tests[i].expectedlen)
++ {
++ printf ("round %d: expected length %zu, got length %zu\n",
++ i + 1, tests[i].expectedlen, wcslen (line));
++ return 1;
++ }
++
++ if (wcscmp (tests[i].expected, line) != 0)
++ {
++ printf ("round %d: expected L\"%ls\", got L\"%ls\"\n",
++ i + 1, tests[i].expected, line);
++ return 1;
++ }
++
++ fclose (fp);
++
++ free (ccs);
++ }
++
++ close (fd);
++
++ return 0;
++}
--- /dev/null
+2006-08-03 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2182]
+ * sysdeps/generic/s_cacosh.c: Return values from positive branch.
+ * sysdeps/generic/s_cacoshf.c: Likewise.
+ * sysdeps/generic/s_cacoshl.c: Likewise.
+
+--- libc/sysdeps/generic/s_cacosh.c 15 Jan 2006 17:51:31 -0000 1.2
++++ libc/sysdeps/generic/s_cacosh.c 3 Aug 2006 20:35:41 -0000 1.3
+@@ -80,6 +80,10 @@ __cacosh (__complex__ double x)
+ __imag__ y += __imag__ x;
+
+ res = __clog (y);
++
++ /* We have to use the positive branch. */
++ if (__real__ res < 0.0)
++ res = -res;
+ }
+
+ return res;
+--- libc/sysdeps/generic/s_cacoshf.c 15 Jan 2006 17:51:31 -0000 1.2
++++ libc/sysdeps/generic/s_cacoshf.c 3 Aug 2006 20:35:41 -0000 1.3
+@@ -95,6 +95,10 @@ __cacoshf (__complex__ float x)
+ + ro);
+ __imag__ res = __ieee754_atan2f (__imag__ x + b, __real__ x + a);
+ #endif
++
++ /* We have to use the positive branch. */
++ if (__real__ res < 0.0)
++ res = -res;
+ }
+
+ return res;
+--- libc/sysdeps/generic/s_cacoshl.c 15 Jan 2006 17:51:31 -0000 1.2
++++ libc/sysdeps/generic/s_cacoshl.c 3 Aug 2006 20:35:41 -0000 1.3
+@@ -80,6 +80,10 @@ __cacoshl (__complex__ long double x)
+ __imag__ y += __imag__ x;
+
+ res = __clogl (y);
++
++ /* We have to use the positive branch. */
++ if (__real__ res < 0.0)
++ res = -res;
+ }
+
+ return res;
--- /dev/null
+2006-02-12 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2226]
+ * libio/wgenops.c (_IO_wsetb): Use correct size of wide char
+ buffer in FREE_BUF call.
+
+--- libc/libio/wgenops.c 14 Sep 2004 04:24:45 -0000 1.13
++++ libc/libio/wgenops.c 12 Feb 2006 21:20:57 -0000 1.14
+@@ -116,7 +116,7 @@ _IO_wsetb (f, b, eb, a)
+ int a;
+ {
+ if (f->_wide_data->_IO_buf_base && !(f->_flags & _IO_USER_BUF))
+- FREE_BUF (f->_wide_data->_IO_buf_base, _IO_wblen (f));
++ FREE_BUF (f->_wide_data->_IO_buf_base, _IO_wblen (f) * sizeof (wchar_t));
+ f->_wide_data->_IO_buf_base = b;
+ f->_wide_data->_IO_buf_end = eb;
+ if (a)
--- /dev/null
+2006-02-03 Roland McGrath <roland@redhat.com>
+
+ [BZ #2268]
+ * sysdeps/posix/profil.c (__profil): Use __profile_frequency to choose
+ timer interval, don't assume smallest possible interval is it.
+
+--- libc/sysdeps/posix/profil.c 15 Dec 2005 21:10:10 -0000 1.13
++++ libc/sysdeps/posix/profil.c 3 Feb 2006 22:28:31 -0000 1.14
+@@ -22,6 +23,7 @@
+ #include <errno.h>
+ #include <signal.h>
+ #include <sys/time.h>
++#include <libc-internal.h>
+
+ #ifndef SIGPROF
+
+@@ -110,7 +112,7 @@ __profil (u_short *sample_buffer, size_t
+ return -1;
+
+ timer.it_value.tv_sec = 0;
+- timer.it_value.tv_usec = 1;
++ timer.it_value.tv_usec = 1000000 / __profile_frequency ();
+ timer.it_interval = timer.it_value;
+ return __setitimer (ITIMER_PROF, &timer, otimer_ptr);
+ }
--- /dev/null
+2006-04-01 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2415]
+ * elf/ldd.bash.in: Create better error messages for invalid input
+ files.
+
+--- libc/elf/ldd.bash.in 1 Jan 2006 19:15:56 -0000 1.35
++++ libc/elf/ldd.bash.in 1 Apr 2006 20:16:17 -0000 1.36
+@@ -144,9 +144,12 @@ for file do
+ *) file=./$file
+ ;;
+ esac
+- if test ! -f "$file"; then
++ if test ! -e "$file"; then
+ echo "ldd: ${file}:" $"No such file or directory" >&2
+ result=1
++ elif test ! -f "$file"; then
++ echo "ldd: ${file}:" $"not regular file" >&2
++ result=1
+ elif test -r "$file"; then
+ test -x "$file" || echo 'ldd:' $"\
+ warning: you do not have execution permission for" "\`$file'" >&2
--- /dev/null
+2006-04-02 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2418]
+ * sysdeps/unix/sysv/linux/getcwd.c (__getcwd): Use larger of PATH_MAX
+ and page size when allocating buffer.
+
+--- libc/sysdeps/unix/sysv/linux/getcwd.c 8 Jan 2006 08:21:15 -0000 1.23
++++ libc/sysdeps/unix/sysv/linux/getcwd.c 2 Apr 2006 17:58:28 -0000 1.24
+@@ -27,6 +27,7 @@
+ #include <sysdep.h>
+ #include <sys/syscall.h>
+ #include <bp-checks.h>
++#include <sys/param.h>
+
+ #include "kernel-features.h"
+
+@@ -86,7 +87,7 @@ __getcwd (char *buf, size_t size)
+ return NULL;
+ }
+
+- alloc_size = PATH_MAX;
++ alloc_size = MAX (PATH_MAX, __getpagesize ());
+ }
+
+ if (buf == NULL)
--- /dev/null
+2006-04-25 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2420]
+ * stdlib/strfmon_l.c (__vstrfmon_l): Fix handling of ! modifier.
+ * localedata/Makefile: Add rules to build and run tst-strfmon1.
+ * localedata/tst-strfmon1.c: New file.
+
+--- libc/stdlib/strfmon_l.c 14 Jan 2006 12:08:37 -0000 1.6
++++ libc/stdlib/strfmon_l.c 26 Apr 2006 05:14:49 -0000 1.7
+@@ -486,23 +486,21 @@ __vstrfmon_l (char *s, size_t maxsize, _
+ }
+
+ if (print_curr_symbol)
+- {
+- out_string (currency_symbol);
++ out_string (currency_symbol);
+
+- if (sign_posn == 4)
+- {
+- if (sep_by_space == 2)
+- out_char (space_char);
+- out_string (sign_string);
+- if (sep_by_space == 1)
+- /* POSIX.2 and SUS are not clear on this case, but C99
+- says a space follows the adjacent-symbol-and-sign */
+- out_char (' ');
+- }
+- else
+- if (sep_by_space == 1)
+- out_char (space_char);
++ if (sign_posn == 4)
++ {
++ if (print_curr_symbol && sep_by_space == 2)
++ out_char (space_char);
++ out_string (sign_string);
++ if (sep_by_space == 1)
++ /* POSIX.2 and SUS are not clear on this case, but C99
++ says a space follows the adjacent-symbol-and-sign */
++ out_char (' ');
+ }
++ else
++ if (print_curr_symbol && sep_by_space == 1)
++ out_char (space_char);
+ }
+ else
+ if (sign_posn != 0 && sign_posn != 2 && sign_posn != 3
+@@ -561,12 +559,13 @@ __vstrfmon_l (char *s, size_t maxsize, _
+ || (sign_posn == 0 && sep_by_space == 1))
+ out_char (space_char);
+ out_nstring (currency_symbol, currency_symbol_len);
+- if (sign_posn == 4)
+- {
+- if (sep_by_space == 2)
+- out_char (' ');
+- out_string (sign_string);
+- }
++ }
++
++ if (sign_posn == 4)
++ {
++ if (sep_by_space == 2)
++ out_char (' ');
++ out_string (sign_string);
+ }
+ }
+
+--- libc/localedata/Makefile 25 Sep 2005 17:01:12 -0000 1.102
++++ libc/localedata/Makefile 26 Apr 2006 05:14:03 -0000 1.103
+@@ -92,7 +92,8 @@ locale_test_suite := tst_iswalnum tst_is
+ tst_wctype tst_wcwidth
+
+ tests = $(locale_test_suite) tst-digits tst-setlocale bug-iconv-trans \
+- tst-leaks tst-mbswcs6 tst-xlocale1 tst-xlocale2 bug-usesetlocale
++ tst-leaks tst-mbswcs6 tst-xlocale1 tst-xlocale2 bug-usesetlocale \
++ tst-strfmon1
+ ifeq (yes,$(build-shared))
+ ifneq (no,$(PERL))
+ tests: $(objpfx)mtrace-tst-leaks
+@@ -282,6 +283,7 @@ tst-digits-ENV = $(TEST_MBWC_ENV)
+ tst-mbswcs6-ENV = $(TEST_MBWC_ENV)
+ tst-xlocale1-ENV = $(TEST_MBWC_ENV)
+ tst-xlocale2-ENV = $(TEST_MBWC_ENV)
++tst-strfmon1-ENV = $(TEST_MBWC_ENV)
+
+ tst-setlocale-ENV = LOCPATH=$(common-objpfx)localedata LC_ALL=ja_JP.EUC-JP
+
+--- libc/localedata/tst-strfmon1.c 1 Jan 1970 00:00:00 -0000
++++ libc/localedata/tst-strfmon1.c 26 Apr 2006 05:13:06 -0000 1.1
+@@ -0,0 +1,42 @@
++#include <monetary.h>
++#include <locale.h>
++#include <stdio.h>
++#include <string.h>
++
++static const struct
++{
++ const char *locale;
++ const char *expected;
++} tests[] =
++ {
++ { "de_DE.ISO-8859-1", "|-12,34 EUR|-12,34|" },
++ { "da_DK.ISO-8859-1", "|kr -12,34|-12,34|" },
++ { "zh_TW.EUC-TW", "|-NT$12.34|-12.34|" },
++ { "sv_SE.ISO-8859-1", "|-12,34 kr|-12,34|" }
++ };
++#define ntests (sizeof (tests) / sizeof (tests[0]))
++
++
++static int
++do_test (void)
++{
++ int res = 0;
++ for (int i = 0; i < ntests; ++i)
++ {
++ char buf[500];
++ if (setlocale (LC_ALL, tests[i].locale) == NULL)
++ {
++ printf ("failed to set locale %s\n", tests[i].locale);
++ res = 1;
++ continue;
++ }
++ strfmon (buf, sizeof (buf), "|%n|%!n|", -12.34, -12.34);
++ int fail = strcmp (buf, tests[i].expected) != 0;
++ printf ("%s%s\n", buf, fail ? " *** FAIL ***" : "");
++ res |= fail;
++ }
++ return res;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
--- /dev/null
+2006-03-17 Roland McGrath <roland@redhat.com>
+
+ * elf/tst-leaks1.c: Include <stdio.h>.
+
+2006-03-13 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #2451]
+ * elf/dl-load.c (open_verify): Add free_name argument, if true, free
+ name before calling lose.
+ (open_path): Adjust caller.
+ (_dl_map_object): Adjust callers. Free name_copy before calling
+ _dl_signal_error.
+ * elf/Makefile: Add rules to build and run tst-leaks1.
+ * elf/tst-leaks1.c: New test.
+
+--- libc/elf/Makefile 1 Mar 2006 06:18:26 -0000 1.310
++++ libc/elf/Makefile 19 Mar 2006 07:47:47 -0000 1.312
+@@ -87,7 +87,8 @@ distribute := rtld-Rules \
+ unload3mod1.c unload3mod2.c unload3mod3.c unload3mod4.c \
+ unload4mod1.c unload4mod2.c unload4mod3.c unload4mod4.c \
+ unload6mod1.c unload6mod2.c unload6mod3.c \
+- order2mod1.c order2mod2.c order2mod3.c order2mod4.c
++ order2mod1.c order2mod2.c order2mod3.c order2mod4.c \
++ tst-leaks1.c
+
+ CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables
+ CFLAGS-dl-lookup.c = -fexceptions -fasynchronous-unwind-tables
+@@ -135,7 +136,7 @@ vpath %.c ../locale/programs
+ endif
+ endif
+
+-tests = tst-tls1 tst-tls2 tst-tls9
++tests = tst-tls1 tst-tls2 tst-tls9 tst-leaks1
+ ifeq (yes,$(have-initfini-array))
+ tests += tst-array1 tst-array2 tst-array3 tst-array4
+ endif
+@@ -170,6 +171,7 @@ endif
+ ifeq (yesyes,$(have-fpie)$(build-shared))
+ tests: $(objpfx)tst-pie1.out
+ endif
++tests: $(objpfx)tst-leaks1-mem
+ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+ testobj1_1 failobj constload2 constload3 unloadmod \
+ dep1 dep2 dep3 dep4 $(modules-vis-$(have-protected)) \
+@@ -828,3 +830,9 @@ $(objpfx)order2mod1.so: $(objpfx)order2m
+ $(objpfx)order2mod4.so: $(objpfx)order2mod3.so
+ $(objpfx)order2mod2.so: $(objpfx)order2mod3.so
+ order2mod2.so-no-z-defs = yes
++
++$(objpfx)tst-leaks1: $(libdl)
++$(objpfx)tst-leaks1-mem: $(objpfx)tst-leaks1.out
++ $(common-objpfx)malloc/mtrace $(objpfx)tst-leaks1.mtrace > $@
++
++tst-leaks1-ENV = MALLOC_TRACE=$(objpfx)tst-leaks1.mtrace
+--- libc/elf/dl-load.c 17 Oct 2005 20:59:28 -0000 1.273
++++ libc/elf/dl-load.c 15 Mar 2006 19:20:04 -0000 1.274
+@@ -1491,7 +1491,7 @@ print_search_path (struct r_search_path_
+ this could mean there is something wrong in the installation and the
+ user might want to know about this. */
+ static int
+-open_verify (const char *name, struct filebuf *fbp)
++open_verify (const char *name, struct filebuf *fbp, bool free_name)
+ {
+ /* This is the expected ELF header. */
+ #define ELF32_CLASS ELFCLASS32
+@@ -1551,6 +1551,12 @@ open_verify (const char *name, struct fi
+ errstring = (errval == 0
+ ? N_("file too short") : N_("cannot read file data"));
+ call_lose:
++ if (free_name)
++ {
++ char *realname = (char *) name;
++ name = strdupa (realname);
++ free (realname);
++ }
+ lose (errval, fd, name, NULL, NULL, errstring);
+ }
+
+@@ -1728,7 +1734,7 @@ open_path (const char *name, size_t name
+ if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
+ _dl_debug_printf (" trying file=%s\n", buf);
+
+- fd = open_verify (buf, fbp);
++ fd = open_verify (buf, fbp, false);
+ if (this_dir->status[cnt] == unknown)
+ {
+ if (fd != -1)
+@@ -1965,7 +1971,7 @@ _dl_map_object (struct link_map *loader,
+
+ if (cached != NULL)
+ {
+- fd = open_verify (cached, &fb);
++ fd = open_verify (cached, &fb, false);
+ if (__builtin_expect (fd != -1, 1))
+ {
+ realname = local_strdup (cached);
+@@ -2001,7 +2007,7 @@ _dl_map_object (struct link_map *loader,
+ fd = -1;
+ else
+ {
+- fd = open_verify (realname, &fb);
++ fd = open_verify (realname, &fb, true);
+ if (__builtin_expect (fd, 0) == -1)
+ free (realname);
+ }
+@@ -2028,8 +2034,11 @@ _dl_map_object (struct link_map *loader,
+ if ((name_copy = local_strdup (name)) == NULL
+ || (l = _dl_new_object (name_copy, name, type, loader,
+ mode, nsid)) == NULL)
+- _dl_signal_error (ENOMEM, name, NULL,
+- N_("cannot create shared object descriptor"));
++ {
++ free (name_copy);
++ _dl_signal_error (ENOMEM, name, NULL,
++ N_("cannot create shared object descriptor"));
++ }
+ /* Signal that this is a faked entry. */
+ l->l_faked = 1;
+ /* Since the descriptor is initialized with zero we do not
+--- libc/elf/tst-leaks1.c 1 Jan 1970 00:00:00 -0000
++++ libc/elf/tst-leaks1.c 19 Mar 2006 07:47:56 -0000 1.2
+@@ -0,0 +1,25 @@
++#include <stdio.h>
++#include <dlfcn.h>
++#include <mcheck.h>
++#include <stdlib.h>
++
++int
++main (void)
++{
++ mtrace ();
++
++ int ret = 0;
++ for (int i = 0; i < 10; i++)
++ {
++ void *h = dlopen (i < 5 ? "./tst-leaks1.c"
++ : "$ORIGIN/tst-leaks1.o", RTLD_LAZY);
++ if (h != NULL)
++ {
++ puts ("dlopen unexpectedly succeeded");
++ ret = 1;
++ dlclose (h);
++ }
++ }
++
++ return ret;
++}
--- /dev/null
+2006-04-01 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2498]
+ * nscd/connections.c (main_loop_poll): If the connection cannot be
+ accepted because of user-imposed limits close the descriptor.
+
+--- libc/nscd/connections.c 3 Jan 2006 21:26:28 -0000 1.82
++++ libc/nscd/connections.c 1 Apr 2006 18:49:53 -0000 1.83
+@@ -1556,18 +1556,24 @@ main_loop_poll (void)
+ /* We have a new incoming connection. Accept the connection. */
+ int fd = TEMP_FAILURE_RETRY (accept (sock, NULL, NULL));
+
+- /* use the descriptor if we have not reached the limit. */
+- if (fd >= 0 && firstfree < nconns)
++ /* Use the descriptor if we have not reached the limit. */
++ if (fd >= 0)
+ {
+- conns[firstfree].fd = fd;
+- conns[firstfree].events = POLLRDNORM;
+- starttime[firstfree] = now;
+- if (firstfree >= nused)
+- nused = firstfree + 1;
+-
+- do
+- ++firstfree;
+- while (firstfree < nused && conns[firstfree].fd != -1);
++ if (firstfree < nconns)
++ {
++ conns[firstfree].fd = fd;
++ conns[firstfree].events = POLLRDNORM;
++ starttime[firstfree] = now;
++ if (firstfree >= nused)
++ nused = firstfree + 1;
++
++ do
++ ++firstfree;
++ while (firstfree < nused && conns[firstfree].fd != -1);
++ }
++ else
++ /* We cannot use the connection so close it. */
++ close (fd);
+ }
+
+ --n;
--- /dev/null
+2006-05-06 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2499]
+ * resolv/nss_dns/dns-canon.c (_nss_dns_getcanonname_r): Avoid
+ possibly unaligned memory accesses.
+
+ * resolv/res_mkquery.c: Correct buffer overflow check for
+ NS_NOTIFY_OP.
+
+ * resolv/res_send.c (send_dg): Rewrite error handling to be
+ more compact and avoid double recomputation of timeouts.
+ Pass MSG_NOSIGNAL to send.
+
+ [BZ #2499]
+ * resolv/res_query.c (__libc_res_nquery): If answerp != NULL,
+ __libc_res_nsend might reallocate the buffer for the answer. In
+ this case we have to reload the HP pointer.
+
+--- libc/resolv/res_mkquery.c 27 Oct 2004 21:27:29 -0000 1.15
++++ libc/resolv/res_mkquery.c 6 May 2006 18:04:12 -0000 1.16
+@@ -155,10 +155,14 @@ res_nmkquery(res_state statp,
+ * perform opcode specific processing
+ */
+ switch (op) {
+- case QUERY: /*FALLTHROUGH*/
+ case NS_NOTIFY_OP:
++ if ((buflen -= QFIXEDSZ + (data == NULL ? 0 : RRFIXEDSZ)) < 0)
++ return (-1);
++ goto compose;
++ case QUERY: /*FALLTHROUGH*/
+ if ((buflen -= QFIXEDSZ) < 0)
+ return (-1);
++ compose:
+ if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
+ return (-1);
+ cp += n;
+@@ -173,7 +177,6 @@ res_nmkquery(res_state statp,
+ /*
+ * Make an additional record for completion domain.
+ */
+- buflen -= RRFIXEDSZ;
+ n = dn_comp((char *)data, cp, buflen, dnptrs, lastdnptr);
+ if (n < 0)
+ return (-1);
+--- libc/resolv/res_query.c 18 Oct 2004 05:09:59 -0000 1.23
++++ libc/resolv/res_query.c 6 May 2006 07:15:53 -0000 1.24
+@@ -163,6 +165,10 @@ __libc_res_nquery(res_state statp,
+ return (n);
+ }
+
++ if (answerp != NULL)
++ /* __libc_res_nsend might have reallocated the buffer. */
++ hp = (HEADER *) *answerp;
++
+ if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
+ #ifdef DEBUG
+ if (statp->options & RES_DEBUG)
+--- libc/resolv/res_send.c 1 Nov 2005 00:07:49 -0000 1.45
++++ libc/resolv/res_send.c 6 May 2006 17:35:50 -0000 1.49
+@@ -914,7 +914,7 @@ send_dg(res_state statp,
+ }
+ __set_errno (0);
+ if (pfd[0].revents & POLLOUT) {
+- if (send(pfd[0].fd, (char*)buf, buflen, 0) != buflen) {
++ if (send(pfd[0].fd, (char*)buf, buflen, MSG_NOSIGNAL) != buflen) {
+ if (errno == EINTR || errno == EAGAIN)
+ goto recompute_resend;
+ Perror(statp, stderr, "send", errno);
+--- libc/resolv/nss_dns/dns-canon.c 19 Aug 2004 18:56:11 -0000 1.3
++++ libc/resolv/nss_dns/dns-canon.c 6 May 2006 19:17:41 -0000 1.4
+@@ -101,7 +103,7 @@ _nss_dns_getcanonname_r (const char *nam
+ ptr += s;
+
+ /* Check whether type and class match. */
+- unsigned int type = ntohs (*(uint16_t *) ptr);
++ unsigned int type = ns_get16 (ptr);
+ if (type == qtypes[i])
+ {
+ /* We found the record. */
+@@ -130,15 +133,15 @@ _nss_dns_getcanonname_r (const char *nam
+ if (type != ns_t_cname)
+ goto unavail;
+
+ ptr += sizeof (uint16_t);
+- if (*(uint16_t *) ptr != htons (ns_c_in))
++ if (ns_get16 (ptr) != ns_c_in)
+ goto unavail;
+
+ /* Also skip over the TTL. */
+ ptr += sizeof (uint16_t) + sizeof (uint32_t);
+
+ /* Skip over the data length and data. */
+- ptr += sizeof (uint16_t) + ntohs (*(uint16_t *) ptr);
++ ptr += sizeof (uint16_t) + ns_get16 (ptr);
+ }
+ }
+ }
--- /dev/null
+2006-04-02 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2501]
+ * nscd/nscd_helper.c (get_mapping): Rewrite code to send request
+ so it uses send and not writev.
+
+--- libc/nscd/nscd_helper.c 1 Mar 2006 05:39:03 -0000 1.14
++++ libc/nscd/nscd_helper.c 2 Apr 2006 18:22:23 -0000 1.15
+@@ -175,35 +175,40 @@ get_mapping (request_type type, const ch
+ struct mapped_database *result = NO_MAPPING;
+ #ifdef SCM_RIGHTS
+ const size_t keylen = strlen (key) + 1;
+- char resdata[keylen];
+ int saved_errno = errno;
+
+ int mapfd = -1;
+
+ /* Send the request. */
+- struct iovec iov[2];
+- request_header req;
++ struct
++ {
++ request_header req;
++ char key[keylen];
++ } reqdata;
+
+ int sock = open_socket ();
+ if (sock < 0)
+ goto out;
+
+- req.version = NSCD_VERSION;
+- req.type = type;
+- req.key_len = keylen;
+-
+- iov[0].iov_base = &req;
+- iov[0].iov_len = sizeof (req);
+- iov[1].iov_base = (void *) key;
+- iov[1].iov_len = keylen;
+-
+- if (__builtin_expect (TEMP_FAILURE_RETRY (__writev (sock, iov, 2))
+- != iov[0].iov_len + iov[1].iov_len, 0))
++ reqdata.req.version = NSCD_VERSION;
++ reqdata.req.type = type;
++ reqdata.req.key_len = keylen;
++ memcpy (reqdata.key, key, keylen);
++
++# ifndef MSG_NOSIGNAL
++# define MSG_NOSIGNAL 0
++# endif
++ if (__builtin_expect (TEMP_FAILURE_RETRY (__send (sock, &reqdata,
++ sizeof (reqdata),
++ MSG_NOSIGNAL))
++ != sizeof (reqdata), 0))
+ /* We cannot even write the request. */
+ goto out_close2;
+
+ /* Room for the data sent along with the file descriptor. We expect
+ the key name back. */
++# define resdata reqdata.key
++ struct iovec iov[1];
+ iov[0].iov_base = resdata;
+ iov[0].iov_len = keylen;
+
+@@ -230,11 +235,7 @@ get_mapping (request_type type, const ch
+ if (wait_on_socket (sock) <= 0)
+ goto out_close2;
+
+-#ifndef MSG_NOSIGNAL
+-# define MSG_NOSIGNAL 0
+-#endif
+- if (__builtin_expect (TEMP_FAILURE_RETRY (__recvmsg (sock, &msg,
+- MSG_NOSIGNAL))
++ if (__builtin_expect (TEMP_FAILURE_RETRY (__recvmsg (sock, &msg, 0))
+ != keylen, 0))
+ goto out_close2;
+
--- /dev/null
+2006-05-01 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2502]
+ * iconvdata/utf-7.c: Don't require more than one character after
+ the '+' sign starting Unicode shifted sequences.
+
+--- libc/iconvdata/utf-7.c 26 Mar 2004 06:41:46 -0000 1.6
++++ libc/iconvdata/utf-7.c 2 May 2006 05:17:29 -0000 1.7
+@@ -170,7 +170,7 @@ base64 (unsigned int i)
+ } \
+ else if (__builtin_expect (ch == '+', 1)) \
+ { \
+- if (__builtin_expect (inptr + 2 >= inend, 0)) \
++ if (__builtin_expect (inptr + 2 > inend, 0)) \
+ { \
+ /* Not enough input available. */ \
+ result = __GCONV_INCOMPLETE_INPUT; \
--- /dev/null
+2006-05-05 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #2509]
+ * stdio-common/tst-printf.sh: Adjust for tst-printf.c change even
+ on 32-bit arches.
+
+2006-05-02 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2509]
+ * stdio-common/vfprintf.c (process_arg): Fix reading of signed
+ short and byte values from parameter list.
+ * stdio-common/tst-printf.c (main): Add more tests.
+ * stdio-common/tst-printf.sh: Adjust for tst-printf.c change.
+
+--- libc/stdio-common/vfprintf.c 14 Jan 2006 12:09:45 -0000 1.133
++++ libc/stdio-common/vfprintf.c 2 May 2006 20:25:15 -0000 1.134
+@@ -530,14 +530,24 @@ vfprintf (FILE *s, const CHAR_T *format,
+ { \
+ if (is_long_num) \
+ signed_number = va_arg (ap, long int); \
+- else /* `char' and `short int' will be promoted to `int'. */ \
++ else if (is_char) \
++ signed_number = (signed char) va_arg (ap, unsigned int); \
++ else if (!is_short) \
+ signed_number = va_arg (ap, int); \
++ else \
++ signed_number = (short int) va_arg (ap, unsigned int); \
+ } \
+ else \
+ if (is_long_num) \
+ signed_number = args_value[fspec->data_arg].pa_long_int; \
+- else /* `char' and `short int' will be promoted to `int'. */ \
++ else if (is_char) \
++ signed_number = (signed char) \
++ args_value[fspec->data_arg].pa_u_int; \
++ else if (!is_short) \
+ signed_number = args_value[fspec->data_arg].pa_int; \
++ else \
++ signed_number = (short int) \
++ args_value[fspec->data_arg].pa_u_int; \
+ \
+ is_negative = signed_number < 0; \
+ number.word = is_negative ? (- signed_number) : signed_number; \
+--- libc/stdio-common/tst-printf.c 15 Mar 2002 22:05:52 -0000 1.16
++++ libc/stdio-common/tst-printf.c 2 May 2006 20:23:30 -0000 1.17
+@@ -273,6 +273,15 @@ I am ready for my first lesson today.";
+
+ printf ("printf (\"%%hhu\", %u) = %hhu\n", UCHAR_MAX + 2, UCHAR_MAX + 2);
+ printf ("printf (\"%%hu\", %u) = %hu\n", USHRT_MAX + 2, USHRT_MAX + 2);
++ printf ("printf (\"%%hhi\", %i) = %hhi\n", UCHAR_MAX + 2, UCHAR_MAX + 2);
++ printf ("printf (\"%%hi\", %i) = %hi\n", USHRT_MAX + 2, USHRT_MAX + 2);
++
++ printf ("printf (\"%%1$hhu\", %2$u) = %1$hhu\n",
++ UCHAR_MAX + 2, UCHAR_MAX + 2);
++ printf ("printf (\"%%1$hu\", %2$u) = %1$hu\n", USHRT_MAX + 2, USHRT_MAX + 2);
++ printf ("printf (\"%%1$hhi\", %2$i) = %1$hhi\n",
++ UCHAR_MAX + 2, UCHAR_MAX + 2);
++ printf ("printf (\"%%1$hi\", %2$i) = %1$hi\n", USHRT_MAX + 2, USHRT_MAX + 2);
+
+ puts ("--- Should be no further output. ---");
+ rfg1 ();
+--- libc/stdio-common/tst-printf.sh 15 Mar 2002 22:06:24 -0000 1.8
++++ libc/stdio-common/tst-printf.sh 2 May 2006 20:23:51 -0000 1.10
+@@ -136,6 +136,12 @@ Test ok.
+ sprintf (buf, "%07Lo", 040000000000ll) = 40000000000
+ printf ("%hhu", 257) = 1
+ printf ("%hu", 65537) = 1
++printf ("%hhi", 257) = 1
++printf ("%hi", 65537) = 1
++printf ("%1$hhu", 257) = 1
++printf ("%1$hu", 65537) = 1
++printf ("%1$hhi", 257) = 1
++printf ("%1$hi", 65537) = 1
+ --- Should be no further output. ---
+ EOF
+ cmp - ${common_objpfx}stdio-common/tst-printf.out > /dev/null 2>&1 ||
+@@ -246,6 +246,12 @@ Test ok.
+ sprintf (buf, "%07Lo", 040000000000ll) = 40000000000
+ printf ("%hhu", 257) = 1
+ printf ("%hu", 65537) = 1
++printf ("%hhi", 257) = 1
++printf ("%hi", 65537) = 1
++printf ("%1$hhu", 257) = 1
++printf ("%1$hu", 65537) = 1
++printf ("%1$hhi", 257) = 1
++printf ("%1$hi", 65537) = 1
+ --- Should be no further output. ---
+ EOF
+ cmp - ${common_objpfx}stdio-common/tst-printf.out > /dev/null 2>&1 ||
--- /dev/null
+2006-04-25 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2571]
+ * nscd/nscd_helper.c (__nscd_get_map_ref): Make mapptr argument a
+ volatile pointer so that the mapptr->mapped value is re-read after
+ the lock is retrieved.
+ * nscd/nscd-client.h: Update __nscd_get_map_ref prototype.
+
+--- libc/nscd/nscd-client.h 22 Nov 2005 19:03:50 -0000 1.21
++++ libc/nscd/nscd-client.h 25 Apr 2006 23:48:55 -0000 1.22
+@@ -277,7 +277,7 @@ extern int __nscd_open_socket (const cha
+ /* Get reference of mapping. */
+ extern struct mapped_database *__nscd_get_map_ref (request_type type,
+ const char *name,
+- struct locked_map_ptr *mapptr,
++ volatile struct locked_map_ptr *mapptr,
+ int *gc_cyclep);
+
+ /* Unmap database. */
+--- libc/nscd/nscd_helper.c 2 Apr 2006 18:22:23 -0000 1.15
++++ libc/nscd/nscd_helper.c 25 Apr 2006 23:47:53 -0000 1.16
+@@ -316,17 +316,18 @@ get_mapping (request_type type, const ch
+
+ struct mapped_database *
+ __nscd_get_map_ref (request_type type, const char *name,
+- struct locked_map_ptr *mapptr, int *gc_cyclep)
++ volatile struct locked_map_ptr *mapptr, int *gc_cyclep)
+ {
+ struct mapped_database *cur = mapptr->mapped;
+ if (cur == NO_MAPPING)
+ return cur;
+
+ int cnt = 0;
+- while (atomic_compare_and_exchange_val_acq (&mapptr->lock, 1, 0) != 0)
++ while (__builtin_expect (atomic_compare_and_exchange_val_acq (&mapptr->lock,
++ 1, 0) != 0, 0))
+ {
+ // XXX Best number of rounds?
+- if (++cnt > 5)
++ if (__builtin_expect (++cnt > 5, 0))
+ return NO_MAPPING;
+
+ atomic_delay ();
+@@ -340,7 +341,8 @@ __nscd_get_map_ref (request_type type, c
+ if (cur == NULL
+ || (cur->head->nscd_certainly_running == 0
+ && cur->head->timestamp + MAPPING_TIMEOUT < time (NULL)))
+- cur = get_mapping (type, name, &mapptr->mapped);
++ cur = get_mapping (type, name,
++ (struct mapped_database **) &mapptr->mapped);
+
+ if (__builtin_expect (cur != NO_MAPPING, 1))
+ {
--- /dev/null
+2006-09-24 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/ieee754/ldbl-128/s_lrintl.c (__lrintl): Fix 2 typos.
+
+2006-09-20 Andreas Jaeger <aj@suse.de>
+
+ * math/libm-test.inc (lrint_test_upward): Fix typo.
+
+2006-06-17 Joseph S. Myers <joseph@codesourcery.com>
+
+ [BZ #2592]
+ * math/libm-test.inc (lrint_test_tonearest): New function.
+ (lrint_test_towardzero): New function.
+ (lrint_test_downward): New function.
+ (lrint_test_upward): New function.
+ (main): Run these new tests.
+ * sysdeps/ieee754/dbl-64/s_llrint.c (__llrint): Correct rounding
+ of values near to 0.
+ (two52): Use double not long double.
+ * sysdeps/ieee754/dbl-64/s_lrint.c (__lrint): Likewise.
+ * sysdeps/ieee754/flt-32/s_llrintf.c (__llrintf): Likewise.
+ (two23): Use float not double.
+ * sysdeps/ieee754/flt-32/s_lrintf.c (__lrintf): Likewise.
+ (two23): Use float not double.
+ * sysdeps/ieee754/ldbl-128/s_llrintl.c (__llrintl): Likewise.
+ * sysdeps/ieee754/ldbl-128/s_lrintl.c (__lrintl): Likewise.
+ * sysdeps/ieee754/ldbl-96/s_llrintl.c (__llrintl): Likewise.
+ * sysdeps/ieee754/ldbl-96/s_lrintl.c (__lrintl): Likewise.
+
+--- libc/math/libm-test.inc 16 Mar 2006 23:16:56 -0000 1.71
++++ libc/math/libm-test.inc 20 Sep 2006 19:36:26 -0000 1.73
+@@ -3273,6 +3273,166 @@ lrint_test (void)
+
+
+ static void
++lrint_test_tonearest (void)
++{
++ int save_round_mode;
++ START (lrint_tonearest);
++
++ save_round_mode = fegetround ();
++
++ if (!fesetround (FE_TONEAREST))
++ {
++ TEST_f_l (lrint, 0.0, 0);
++ TEST_f_l (lrint, minus_zero, 0);
++ TEST_f_l (lrint, 0.2L, 0);
++ TEST_f_l (lrint, -0.2L, 0);
++ TEST_f_l (lrint, 0.5L, 0);
++ TEST_f_l (lrint, -0.5L, 0);
++ TEST_f_l (lrint, 0.8L, 1);
++ TEST_f_l (lrint, -0.8L, -1);
++
++ TEST_f_l (lrint, 1.4L, 1);
++ TEST_f_l (lrint, -1.4L, -1);
++
++ TEST_f_l (lrint, 8388600.3L, 8388600);
++ TEST_f_l (lrint, -8388600.3L, -8388600);
++
++ TEST_f_l (lrint, 1071930.0008, 1071930);
++#ifndef TEST_FLOAT
++ TEST_f_l (lrint, 1073741824.01, 1073741824);
++# if LONG_MAX > 281474976710656
++ TEST_f_l (lrint, 281474976710656.025, 281474976710656);
++# endif
++#endif
++ }
++
++ fesetround (save_round_mode);
++
++ END (lrint_tonearest);
++}
++
++
++static void
++lrint_test_towardzero (void)
++{
++ int save_round_mode;
++ START (lrint_towardzero);
++
++ save_round_mode = fegetround ();
++
++ if (!fesetround (FE_TOWARDZERO))
++ {
++ TEST_f_l (lrint, 0.0, 0);
++ TEST_f_l (lrint, minus_zero, 0);
++ TEST_f_l (lrint, 0.2L, 0);
++ TEST_f_l (lrint, -0.2L, 0);
++ TEST_f_l (lrint, 0.5L, 0);
++ TEST_f_l (lrint, -0.5L, 0);
++ TEST_f_l (lrint, 0.8L, 0);
++ TEST_f_l (lrint, -0.8L, 0);
++
++ TEST_f_l (lrint, 1.4L, 1);
++ TEST_f_l (lrint, -1.4L, -1);
++
++ TEST_f_l (lrint, 8388600.3L, 8388600);
++ TEST_f_l (lrint, -8388600.3L, -8388600);
++
++ TEST_f_l (lrint, 1071930.0008, 1071930);
++#ifndef TEST_FLOAT
++ TEST_f_l (lrint, 1073741824.01, 1073741824);
++# if LONG_MAX > 281474976710656
++ TEST_f_l (lrint, 281474976710656.025, 281474976710656);
++# endif
++#endif
++ }
++
++ fesetround (save_round_mode);
++
++ END (lrint_towardzero);
++}
++
++
++static void
++lrint_test_downward (void)
++{
++ int save_round_mode;
++ START (lrint_downward);
++
++ save_round_mode = fegetround ();
++
++ if (!fesetround (FE_DOWNWARD))
++ {
++ TEST_f_l (lrint, 0.0, 0);
++ TEST_f_l (lrint, minus_zero, 0);
++ TEST_f_l (lrint, 0.2L, 0);
++ TEST_f_l (lrint, -0.2L, -1);
++ TEST_f_l (lrint, 0.5L, 0);
++ TEST_f_l (lrint, -0.5L, -1);
++ TEST_f_l (lrint, 0.8L, 0);
++ TEST_f_l (lrint, -0.8L, -1);
++
++ TEST_f_l (lrint, 1.4L, 1);
++ TEST_f_l (lrint, -1.4L, -2);
++
++ TEST_f_l (lrint, 8388600.3L, 8388600);
++ TEST_f_l (lrint, -8388600.3L, -8388601);
++
++ TEST_f_l (lrint, 1071930.0008, 1071930);
++#ifndef TEST_FLOAT
++ TEST_f_l (lrint, 1073741824.01, 1073741824);
++# if LONG_MAX > 281474976710656
++ TEST_f_l (lrint, 281474976710656.025, 281474976710656);
++# endif
++#endif
++ }
++
++ fesetround (save_round_mode);
++
++ END (lrint_downward);
++}
++
++
++static void
++lrint_test_upward (void)
++{
++ int save_round_mode;
++ START (lrint_upward);
++
++ save_round_mode = fegetround ();
++
++ if (!fesetround (FE_UPWARD))
++ {
++ TEST_f_l (lrint, 0.0, 0);
++ TEST_f_l (lrint, minus_zero, 0);
++ TEST_f_l (lrint, 0.2L, 1);
++ TEST_f_l (lrint, -0.2L, 0);
++ TEST_f_l (lrint, 0.5L, 1);
++ TEST_f_l (lrint, -0.5L, 0);
++ TEST_f_l (lrint, 0.8L, 1);
++ TEST_f_l (lrint, -0.8L, 0);
++
++ TEST_f_l (lrint, 1.4L, 2);
++ TEST_f_l (lrint, -1.4L, -1);
++
++ TEST_f_l (lrint, 8388600.3L, 8388601);
++ TEST_f_l (lrint, -8388600.3L, -8388600);
++
++#ifndef TEST_FLOAT
++ TEST_f_l (lrint, 1071930.0008, 1071931);
++ TEST_f_l (lrint, 1073741824.01, 1073741825);
++# if LONG_MAX > 281474976710656 && defined (TEST_LDOUBLE)
++ TEST_f_l (lrint, 281474976710656.025, 281474976710656);
++# endif
++#endif
++ }
++
++ fesetround (save_round_mode);
++
++ END (lrint_upward);
++}
++
++
++static void
+ llrint_test (void)
+ {
+ /* XXX this test is incomplete. We need to have a way to specifiy
+@@ -5937,6 +6097,10 @@ main (int argc, char **argv)
+ rint_test_downward ();
+ rint_test_upward ();
+ lrint_test ();
++ lrint_test_tonearest ();
++ lrint_test_towardzero ();
++ lrint_test_downward ();
++ lrint_test_upward ();
+ llrint_test ();
+ llrint_test_tonearest ();
+ llrint_test_towardzero ();
+--- libc/sysdeps/ieee754/dbl-64/s_llrint.c 1 Feb 2004 19:20:22 -0000 1.3
++++ libc/sysdeps/ieee754/dbl-64/s_llrint.c 20 Sep 2006 17:14:24 -0000 1.4
+@@ -23,7 +23,7 @@
+
+ #include "math_private.h"
+
+-static const long double two52[2] =
++static const double two52[2] =
+ {
+ 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
+ -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
+@@ -48,19 +48,14 @@ __llrint (double x)
+
+ if (j0 < 20)
+ {
+- if (j0 < -1)
+- return 0;
+- else
+- {
+- w = two52[sx] + x;
+- t = w - two52[sx];
+- EXTRACT_WORDS (i0, i1, t);
+- j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
+- i0 &= 0xfffff;
+- i0 |= 0x100000;
++ w = two52[sx] + x;
++ t = w - two52[sx];
++ EXTRACT_WORDS (i0, i1, t);
++ j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
++ i0 &= 0xfffff;
++ i0 |= 0x100000;
+
+- result = i0 >> (20 - j0);
+- }
++ result = (j0 < 0 ? 0 : i0 >> (20 - j0));
+ }
+ else if (j0 < (int32_t) (8 * sizeof (long long int)) - 1)
+ {
+--- libc/sysdeps/ieee754/dbl-64/s_lrint.c 1 Feb 2004 19:01:03 -0000 1.3
++++ libc/sysdeps/ieee754/dbl-64/s_lrint.c 20 Sep 2006 17:14:24 -0000 1.4
+@@ -48,19 +48,14 @@ __lrint (double x)
+
+ if (j0 < 20)
+ {
+- if (j0 < -1)
+- return 0;
+- else
+- {
+- w = two52[sx] + x;
+- t = w - two52[sx];
+- EXTRACT_WORDS (i0, i1, t);
+- j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
+- i0 &= 0xfffff;
+- i0 |= 0x100000;
++ w = two52[sx] + x;
++ t = w - two52[sx];
++ EXTRACT_WORDS (i0, i1, t);
++ j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
++ i0 &= 0xfffff;
++ i0 |= 0x100000;
+
+- result = i0 >> (20 - j0);
+- }
++ result = (j0 < 0 ? 0 : i0 >> (20 - j0));
+ }
+ else if (j0 < (int32_t) (8 * sizeof (long int)) - 1)
+ {
+--- libc/sysdeps/ieee754/flt-32/s_llrintf.c 6 Jul 2001 04:55:55 -0000 1.2
++++ libc/sysdeps/ieee754/flt-32/s_llrintf.c 20 Sep 2006 17:14:24 -0000 1.3
+@@ -23,7 +23,7 @@
+
+ #include "math_private.h"
+
+-static const double two23[2] =
++static const float two23[2] =
+ {
+ 8.3886080000e+06, /* 0x4B000000 */
+ -8.3886080000e+06, /* 0xCB000000 */
+@@ -49,9 +49,7 @@ __llrintf (float x)
+
+ if (j0 < (int32_t) (sizeof (long long int) * 8) - 1)
+ {
+- if (j0 < -1)
+- return 0;
+- else if (j0 >= 23)
++ if (j0 >= 23)
+ result = (long long int) i0 << (j0 - 23);
+ else
+ {
+@@ -62,7 +60,7 @@ __llrintf (float x)
+ i0 &= 0x7fffff;
+ i0 |= 0x800000;
+
+- result = i0 >> (23 - j0);
++ result = (j0 < 0 ? 0 : i0 >> (23 - j0));
+ }
+ }
+ else
+--- libc/sysdeps/ieee754/flt-32/s_lrintf.c 6 Jul 2001 04:55:55 -0000 1.2
++++ libc/sysdeps/ieee754/flt-32/s_lrintf.c 20 Sep 2006 17:14:24 -0000 1.3
+@@ -23,7 +23,7 @@
+
+ #include "math_private.h"
+
+-static const double two23[2] =
++static const float two23[2] =
+ {
+ 8.3886080000e+06, /* 0x4B000000 */
+ -8.3886080000e+06, /* 0xCB000000 */
+@@ -49,9 +49,7 @@ __lrintf (float x)
+
+ if (j0 < (int32_t) (sizeof (long int) * 8) - 1)
+ {
+- if (j0 < -1)
+- return 0;
+- else if (j0 >= 23)
++ if (j0 >= 23)
+ result = (long int) i0 << (j0 - 23);
+ else
+ {
+@@ -62,7 +60,7 @@ __lrintf (float x)
+ i0 &= 0x7fffff;
+ i0 |= 0x800000;
+
+- result = i0 >> (23 - j0);
++ result = (j0 < 0 ? 0 : i0 >> (23 - j0));
+ }
+ }
+ else
+--- libc/sysdeps/ieee754/ldbl-128/s_llrintl.c 1 Feb 2006 19:42:43 -0000 1.3
++++ libc/sysdeps/ieee754/ldbl-128/s_llrintl.c 20 Sep 2006 17:14:24 -0000 1.4
+@@ -48,8 +48,6 @@ __llrintl (long double x)
+
+ if (j0 < (int32_t) (8 * sizeof (long long int)) - 1)
+ {
+- if (j0 < -1)
+- return 0;
+ w = two112[sx] + x;
+ t = w - two112[sx];
+ GET_LDOUBLE_WORDS64 (i0, i1, t);
+@@ -57,7 +55,9 @@ __llrintl (long double x)
+ i0 &= 0x0000ffffffffffffLL;
+ i0 |= 0x0001000000000000LL;
+
+- if (j0 <= 48)
++ if (j0 < 0)
++ result = 0;
++ else if (j0 <= 48)
+ result = i0 >> (48 - j0);
+ else
+ result = ((long long int) i0 << (j0 - 48)) | (i1 >> (112 - j0));
+--- libc/sysdeps/ieee754/ldbl-128/s_lrintl.c 12 Feb 2004 20:57:40 -0000 1.3
++++ libc/sysdeps/ieee754/ldbl-128/s_lrintl.c 25 Sep 2006 14:11:26 -0000 1.5
+@@ -48,19 +48,14 @@ __lrintl (long double x)
+
+ if (j0 < 48)
+ {
+- if (j0 < -1)
+- return 0;
+- else
+- {
+- w = two112[sx] + x;
+- t = w - two112[sx];
+- GET_LDOUBLE_WORDS64 (i0, i1, x);
+- j0 = ((i0 >> 48) & 0x7fff) - 0x3fff;
+- i0 &= 0x0000ffffffffffffLL;
+- i0 |= 0x0001000000000000LL;
++ w = two112[sx] + x;
++ t = w - two112[sx];
++ GET_LDOUBLE_WORDS64 (i0, i1, t);
++ j0 = ((i0 >> 48) & 0x7fff) - 0x3fff;
++ i0 &= 0x0000ffffffffffffLL;
++ i0 |= 0x0001000000000000LL;
+
+- result = i0 >> (48 - j0);
+- }
++ result = (j0 < 0 ? 0 : i0 >> (48 - j0));
+ }
+ else if (j0 < (int32_t) (8 * sizeof (long int)) - 1)
+ {
+@@ -70,7 +65,7 @@ __lrintl (long double x)
+ {
+ w = two112[sx] + x;
+ t = w - two112[sx];
+- GET_LDOUBLE_WORDS64 (i0, i1, x);
++ GET_LDOUBLE_WORDS64 (i0, i1, t);
+ j0 = ((i0 >> 48) & 0x7fff) - 0x3fff;
+ i0 &= 0x0000ffffffffffffLL;
+ i0 |= 0x0001000000000000LL;
+--- libc/sysdeps/ieee754/ldbl-96/s_llrintl.c 12 Feb 2004 20:57:52 -0000 1.3
++++ libc/sysdeps/ieee754/ldbl-96/s_llrintl.c 20 Sep 2006 17:14:24 -0000 1.4
+@@ -47,9 +47,7 @@ __llrintl (long double x)
+
+ if (j0 < (int32_t) (8 * sizeof (long long int)) - 1)
+ {
+- if (j0 < -1)
+- return 0;
+- else if (j0 >= 63)
++ if (j0 >= 63)
+ result = (((long long int) i0 << 32) | i1) << (j0 - 63);
+ else
+ {
+@@ -58,7 +56,9 @@ __llrintl (long double x)
+ GET_LDOUBLE_WORDS (se, i0, i1, t);
+ j0 = (se & 0x7fff) - 0x3fff;
+
+- if (j0 <= 31)
++ if (j0 < 0)
++ result = 0;
++ else if (j0 <= 31)
+ result = i0 >> (31 - j0);
+ else
+ result = ((long long int) i0 << (j0 - 31)) | (i1 >> (63 - j0));
+--- libc/sysdeps/ieee754/ldbl-96/s_lrintl.c 1 Feb 2004 19:11:52 -0000 1.3
++++ libc/sysdeps/ieee754/ldbl-96/s_lrintl.c 20 Sep 2006 17:14:24 -0000 1.4
+@@ -47,17 +47,12 @@ __lrintl (long double x)
+
+ if (j0 < 31)
+ {
+- if (j0 < -1)
+- return 0;
+- else
+- {
+- w = two63[sx] + x;
+- t = w - two63[sx];
+- GET_LDOUBLE_WORDS (se, i0, i1, t);
+- j0 = (se & 0x7fff) - 0x3fff;
++ w = two63[sx] + x;
++ t = w - two63[sx];
++ GET_LDOUBLE_WORDS (se, i0, i1, t);
++ j0 = (se & 0x7fff) - 0x3fff;
+
+- result = i0 >> (31 - j0);
+- }
++ result = (j0 < 0 ? 0 : i0 >> (31 - j0));
+ }
+ else if (j0 < (int32_t) (8 * sizeof (long int)) - 1)
+ {
--- /dev/null
+2006-05-02 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2632]
+ * nscd/connections.c (nscd_init): Correct initialization of
+ in-memory database structure.
+
+--- libc/nscd/connections.c 27 Apr 2006 20:33:32 -0000 1.87
++++ libc/nscd/connections.c 2 May 2006 16:42:58 -0000 1.88
+@@ -722,7 +722,7 @@ cannot set socket to close on exec: %s;
+ dbs[cnt].head = xmalloc (sizeof (struct database_pers_head)
+ + (dbs[cnt].suggested_module
+ * sizeof (ref_t)));
+- memset (dbs[cnt].head, '\0', sizeof (dbs[cnt].head));
++ memset (dbs[cnt].head, '\0', sizeof (struct database_pers_head));
+ assert (~ENDREF == 0);
+ memset (dbs[cnt].head->array, '\xff',
+ dbs[cnt].suggested_module * sizeof (ref_t));
--- /dev/null
+2006-05-09 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2644]
+ * sysdeps/pthread/unwind-forcedunwind.c: Different solution for
+ the reload problem. Change the one path in pthread_cancel_init
+ which causes the problem. Force gcc to reload. Simplify callers.
+
+2006-05-07 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2644]
+ * sysdeps/pthread/unwind-forcedunwind.c: Make sure functions
+ pointers are reloaded after pthread_cancel_init calls.
+
+--- libc/nptl/sysdeps/pthread/unwind-forcedunwind.c 16 Nov 2005 23:31:28 -0000 1.2
++++ libc/nptl/sysdeps/pthread/unwind-forcedunwind.c 9 May 2006 15:20:39 -0000 1.6
+@@ -31,13 +31,18 @@ static _Unwind_Reason_Code (*libgcc_s_fo
+ static _Unwind_Word (*libgcc_s_getcfa) (struct _Unwind_Context *);
+
+ void
++__attribute_noinline__
+ pthread_cancel_init (void)
+ {
+ void *resume, *personality, *forcedunwind, *getcfa;
+ void *handle;
+
+ if (__builtin_expect (libgcc_s_getcfa != NULL, 1))
+- return;
++ {
++ /* Force gcc to reload all values. */
++ asm volatile ("" ::: "memory");
++ return;
++ }
+
+ handle = __libc_dlopen ("libgcc_s.so.1");
+
--- /dev/null
+2006-05-21 Joseph S. Myers <joseph@codesourcery.com>
+
+ [BZ #2680]
+ * posix/unistd.h (getlogin_r): Condition on __USE_POSIX199506, not
+ __USE_UNIX98.
+
+--- libc/posix/unistd.h 1 Apr 2006 19:11:33 -0000 1.146
++++ libc/posix/unistd.h 24 Aug 2006 06:46:27 -0000 1.147
+@@ -811,7 +811,7 @@ extern int tcsetpgrp (int __fd, __pid_t
+ This function is a possible cancellation points and therefore not
+ marked with __THROW. */
+ extern char *getlogin (void);
+-#if defined __USE_REENTRANT || defined __USE_UNIX98
++#if defined __USE_REENTRANT || defined __USE_POSIX199506
+ /* Return at most NAME_LEN characters of the login name of the user in NAME.
+ If it cannot be determined or some other error occurred, return the error
+ code. Otherwise return 0.
--- /dev/null
+2006-08-27 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2684]
+ * malloc/malloc.c (public_rEALLOc): Try harder by using other
+ arenas if allocation failed.
+ Patch mostly by Jan Edler <jan.edler@indexengines.com>.
+
+--- libc/malloc/malloc.c 27 Aug 2006 04:37:30 -0000 1.165
++++ libc/malloc/malloc.c 28 Aug 2006 00:57:31 -0000 1.166
+@@ -3625,6 +3625,29 @@ public_rEALLOc(Void_t* oldmem, size_t by
+ (void)mutex_unlock(&ar_ptr->mutex);
+ assert(!newp || chunk_is_mmapped(mem2chunk(newp)) ||
+ ar_ptr == arena_for_chunk(mem2chunk(newp)));
++
++ if (newp == NULL)
++ {
++ /* Try harder to allocate memory in other arenas. */
++ newp = public_mALLOc(bytes);
++ if (newp != NULL)
++ {
++ MALLOC_COPY (newp, oldmem, oldsize - 2 * SIZE_SZ);
++#if THREAD_STATS
++ if(!mutex_trylock(&ar_ptr->mutex))
++ ++(ar_ptr->stat_lock_direct);
++ else {
++ (void)mutex_lock(&ar_ptr->mutex);
++ ++(ar_ptr->stat_lock_wait);
++ }
++#else
++ (void)mutex_lock(&ar_ptr->mutex);
++#endif
++ _int_free(ar_ptr, oldmem);
++ (void)mutex_unlock(&ar_ptr->mutex);
++ }
++ }
++
+ return newp;
+ }
+ #ifdef libc_hidden_def
--- /dev/null
+2006-06-04 Ulrich Drepper <drepper@redhat.com>
+
+ * string/Makefile (tests): Add bug-envz1.
+ * string/bug-enz1.c: New file.
+
+2006-06-02 Ryan S. Arnold <rsa@us.ibm.com>
+
+ [BZ #2703]
+ * string/envz.c (envz_strip): Correct erroneously reversed src
+ and dest parameters to memmove() invocation.
+
+--- libc/string/Makefile 4 Apr 2006 08:40:42 -0000 1.68
++++ libc/string/Makefile 4 Jun 2006 16:35:25 -0000 1.69
+@@ -53,7 +53,8 @@ tests := tester inl-tester noinl-tester
+ tst-strlen stratcliff tst-svc tst-inlcall \
+ bug-strncat1 bug-strspn1 bug-strpbrk1 tst-bswap \
+ tst-strtok tst-strxfrm bug-strcoll1 tst-strfry \
+- bug-strtok1 $(addprefix test-,$(strop-tests))
++ bug-strtok1 $(addprefix test-,$(strop-tests)) \
++ bug-envz1
+ distribute := memcopy.h pagecopy.h tst-svc.expect test-string.h
+
+
+--- libc/string/bug-envz1.c 1 Jan 1970 00:00:00 -0000
++++ libc/string/bug-envz1.c 4 Jun 2006 16:35:21 -0000 1.1
+@@ -0,0 +1,76 @@
++/* Test for bug BZ #2703. */
++#include <stdio.h>
++#include <envz.h>
++#include <stdlib.h>
++#include <string.h>
++
++static const struct
++{
++ const char *s;
++ int in_result;
++} strs[] =
++{
++ { "a=1", 1 },
++ { "b=2", 1 },
++ { "(*)", 0 },
++ { "(*)", 0 },
++ { "e=5", 1 },
++ { "f=", 1 },
++ { "(*)", 0 },
++ { "h=8", 1 },
++ { "i=9", 1 },
++ { "j", 0 }
++};
++
++#define nstrs (sizeof (strs) / sizeof (strs[0]))
++
++
++static int
++do_test (void)
++{
++
++ size_t size = 0;
++ char *str = malloc (100);
++ if (str == NULL)
++ {
++ puts ("out of memory");
++ return 1;
++ }
++
++ char **argz = &str;
++
++ for (int i = 0; i < nstrs; ++i)
++ argz_add_sep (argz, &size, strs[i].s, '\0');
++
++ printf ("calling envz_strip with size=%zu\n", size);
++ envz_strip (argz, &size);
++
++ int result = 0;
++ printf ("new size=%zu\n", size);
++ for (int i = 0; i < nstrs; ++i)
++ if (strs[i].in_result)
++ {
++ char name[2];
++ name[0] = strs[i].s[0];
++ name[1] = '\0';
++
++ char *e = envz_entry (*argz, size, name);
++ if (e == NULL)
++ {
++ printf ("entry '%s' not found\n", name);
++ result = 1;
++ }
++ else if (strcmp (e, strs[i].s) != 0)
++ {
++ printf ("entry '%s' does not match: is '%s', expected '%s'\n",
++ name, e, strs[i].s);
++ result = 1;
++ }
++ }
++
++ free (*argz);
++ return result;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- libc/string/envz.c 6 Aug 2002 06:08:16 -0000 1.13
++++ libc/string/envz.c 4 Jun 2006 04:34:14 -0000 1.14
+@@ -165,7 +165,7 @@ envz_strip (char **envz, size_t *envz_le
+ left -= entry_len;
+ if (! strchr (entry, SEP))
+ /* Null entry. */
+- memmove (entry + entry_len, entry, left);
++ memmove (entry, entry + entry_len, left);
+ else
+ entry += entry_len;
+ }
--- /dev/null
+2006-06-14 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #2766]
+ * misc/insremque.c (insque): Handle prev == NULL.
+ * misc/Makefile (tests): Add tst-insremque.
+ * misc/tst-insremque.c: New test.
+
+--- libc/misc/Makefile 23 Feb 2006 22:50:16 -0000 1.118
++++ libc/misc/Makefile 17 Jun 2006 17:00:58 -0000 1.119
+@@ -76,7 +76,7 @@ endif
+ gpl2lgpl := error.c error.h
+
+ tests := tst-dirname tst-tsearch tst-fdset tst-efgcvt tst-mntent tst-hsearch \
+- tst-error1
++ tst-error1 tst-insremque
+ ifeq (no,$(cross-compiling))
+ tests: $(objpfx)tst-error1-mem
+ endif
+--- libc/misc/insremque.c 6 Jul 2001 04:55:36 -0000 1.4
++++ libc/misc/insremque.c 17 Jun 2006 16:59:34 -0000 1.5
+@@ -24,12 +24,20 @@
+ void
+ insque (void *elem, void *prev)
+ {
+- struct qelem *next = ((struct qelem *) prev)->q_forw;
+- ((struct qelem *) prev)->q_forw = (struct qelem *) elem;
+- if (next != NULL)
+- next->q_back = (struct qelem *) elem;
+- ((struct qelem *) elem)->q_forw = next;
+- ((struct qelem *) elem)->q_back = (struct qelem *) prev;
++ if (prev == NULL)
++ {
++ ((struct qelem *) elem)->q_forw = NULL;
++ ((struct qelem *) elem)->q_back = NULL;
++ }
++ else
++ {
++ struct qelem *next = ((struct qelem *) prev)->q_forw;
++ ((struct qelem *) prev)->q_forw = (struct qelem *) elem;
++ if (next != NULL)
++ next->q_back = (struct qelem *) elem;
++ ((struct qelem *) elem)->q_forw = next;
++ ((struct qelem *) elem)->q_back = (struct qelem *) prev;
++ }
+ }
+
+ /* Unlink ELEM from the doubly-linked list that it is in. */
+--- libc/misc/tst-insremque.c 1 Jan 1970 00:00:00 -0000
++++ libc/misc/tst-insremque.c 17 Jun 2006 17:00:08 -0000 1.1
+@@ -0,0 +1,61 @@
++#include <search.h>
++#include <stdio.h>
++#include <string.h>
++
++#define CHECK(cond) \
++ do \
++ if (! (cond)) \
++ { \
++ printf ("Condition " #cond " not true on line %d\n", __LINE__); \
++ ret = 1; \
++ } \
++ while (0)
++
++static int
++do_test (void)
++{
++ struct qelem elements[4];
++ int ret = 0;
++
++ /* Linear list. */
++ memset (elements, 0xff, sizeof (elements));
++ insque (&elements[0], NULL);
++ remque (&elements[0]);
++ insque (&elements[0], NULL);
++ insque (&elements[2], &elements[0]);
++ insque (&elements[1], &elements[0]);
++ insque (&elements[3], &elements[2]);
++ remque (&elements[2]);
++ insque (&elements[2], &elements[0]);
++ CHECK (elements[0].q_back == NULL);
++ CHECK (elements[0].q_forw == &elements[2]);
++ CHECK (elements[1].q_back == &elements[2]);
++ CHECK (elements[1].q_forw == &elements[3]);
++ CHECK (elements[2].q_back == &elements[0]);
++ CHECK (elements[2].q_forw == &elements[1]);
++ CHECK (elements[3].q_back == &elements[1]);
++ CHECK (elements[3].q_forw == NULL);
++
++ /* Circular list. */
++ memset (elements, 0xff, sizeof (elements));
++ elements[0].q_back = &elements[0];
++ elements[0].q_forw = &elements[0];
++ insque (&elements[2], &elements[0]);
++ insque (&elements[1], &elements[0]);
++ insque (&elements[3], &elements[2]);
++ remque (&elements[2]);
++ insque (&elements[2], &elements[0]);
++ CHECK (elements[0].q_back == &elements[3]);
++ CHECK (elements[0].q_forw == &elements[2]);
++ CHECK (elements[1].q_back == &elements[2]);
++ CHECK (elements[1].q_forw == &elements[3]);
++ CHECK (elements[2].q_back == &elements[0]);
++ CHECK (elements[2].q_forw == &elements[1]);
++ CHECK (elements[3].q_back == &elements[1]);
++ CHECK (elements[3].q_forw == &elements[0]);
++
++ return ret;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
--- /dev/null
+2006-09-07 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #2775]
+ * malloc/malloc.c (sYSMALLOc): Only call grow_heap if
+ (long) (MINSIZE + nb - old_size) is positive.
+
+ * malloc/arena.c (grow_heap): When growing bail even if new_size
+ is negative.
+
+--- libc/malloc/arena.c 22 Aug 2006 06:39:51 -0000 1.23
++++ libc/malloc/arena.c 7 Sep 2006 16:04:22 -0000 1.24
+@@ -712,7 +712,7 @@ grow_heap(h, diff) heap_info *h; long di
+ if(diff >= 0) {
+ diff = (diff + page_mask) & ~page_mask;
+ new_size = (long)h->size + diff;
+- if(new_size > HEAP_MAX_SIZE)
++ if((unsigned long) new_size > (unsigned long) HEAP_MAX_SIZE)
+ return -1;
+ if(mprotect((char *)h + h->size, diff, PROT_READ|PROT_WRITE) != 0)
+ return -2;
+--- libc/malloc/malloc.c 28 Aug 2006 00:57:31 -0000 1.167
++++ libc/malloc/malloc.c 7 Sep 2006 16:06:02 -0000 1.168
+@@ -2970,7 +2970,8 @@ static Void_t* sYSMALLOc(nb, av) INTERNA
+ /* First try to extend the current heap. */
+ old_heap = heap_for_ptr(old_top);
+ old_heap_size = old_heap->size;
+- if (grow_heap(old_heap, MINSIZE + nb - old_size) == 0) {
++ if ((long) (MINSIZE + nb - old_size) > 0
++ && grow_heap(old_heap, MINSIZE + nb - old_size) == 0) {
+ av->system_mem += old_heap->size - old_heap_size;
+ arena_mem += old_heap->size - old_heap_size;
+ #if 0
--- /dev/null
+2006-06-17 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2792]
+ * elf/dl-deps.c (expand_dst): Rename __cnt variable to not
+ conflict with DL_DST_REQUIRED.
+
+--- libc/elf/dl-deps.c 18 Jan 2006 19:48:53 -0000 1.81
++++ libc/elf/dl-deps.c 17 Jun 2006 16:51:56 -0000 1.82
+@@ -101,9 +101,9 @@ struct list
+ ({ \
+ const char *__str = (str); \
+ const char *__result = __str; \
+- size_t __cnt = DL_DST_COUNT(__str, 0); \
++ size_t __dst_cnt = DL_DST_COUNT (__str, 0); \
+ \
+- if (__cnt != 0) \
++ if (__dst_cnt != 0) \
+ { \
+ char *__newp; \
+ \
+@@ -113,9 +113,9 @@ struct list
+ DST not allowed in SUID/SGID programs")); \
+ \
+ __newp = (char *) alloca (DL_DST_REQUIRED (l, __str, strlen (__str), \
+- __cnt)); \
++ __dst_cnt)); \
+ \
+- __result = _dl_dst_substitute (l, __str, __newp, 0); \
++ __result = _dl_dst_substitute (l, __str, __newp, 0); \
+ \
+ if (*__result == '\0') \
+ { \
--- /dev/null
+2006-09-09 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2821]
+ * time/mktime.c (guess_time_tm): Fix overflow detection.
+ * time/Makefile (tests): Add bug-mktime1.
+ * time/bug-mktime1.c: New file.
+
+--- libc/time/Makefile 14 Oct 2005 15:16:17 -0000 1.109
++++ libc/time/Makefile 9 Sep 2006 16:54:49 -0000 1.110
+@@ -35,7 +35,7 @@ distribute := datemsk
+
+ tests := test_time clocktest tst-posixtz tst-strptime tst_wcsftime \
+ tst-getdate tst-mktime tst-mktime2 tst-ftime_l tst-strftime \
+- tst-mktime3 tst-strptime2 bug-asctime bug-asctime_r
++ tst-mktime3 tst-strptime2 bug-asctime bug-asctime_r bug-mktime1
+
+ include ../Rules
+
+--- libc/time/bug-mktime1.c 1 Jan 1970 00:00:00 -0000
++++ libc/time/bug-mktime1.c 9 Sep 2006 16:54:23 -0000 1.1
+@@ -0,0 +1,17 @@
++#include <stdio.h>
++#include <time.h>
++
++
++static int
++do_test (void)
++{
++ struct tm t2 = { 0, 0, 0, 1, 1, 2050 - 1900, 1, 1, 1 };
++ time_t tt2 = mktime (&t2);
++ printf ("%ld\n", (long int) tt2);
++ if (sizeof (time_t) == 4 && tt2 != -1)
++ return 1;
++ return 0;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- libc/time/mktime.c 8 Sep 2005 08:09:07 -0000 1.66
++++ libc/time/mktime.c 9 Sep 2006 16:56:18 -0000 1.67
+@@ -216,10 +216,11 @@ guess_time_tm (long int year, long int y
+ /* Overflow occurred one way or another. Return the nearest result
+ that is actually in range, except don't report a zero difference
+ if the actual difference is nonzero, as that would cause a false
+- match. */
++ match; and don't oscillate between two values, as that would
++ confuse the spring-forward gap detector. */
+ return (*t < TIME_T_MIDPOINT
+- ? TIME_T_MIN + (*t == TIME_T_MIN)
+- : TIME_T_MAX - (*t == TIME_T_MAX));
++ ? (*t <= TIME_T_MIN + 1 ? *t + 1 : TIME_T_MIN)
++ : (TIME_T_MAX - 1 <= *t ? *t - 1 : TIME_T_MAX));
+ }
+
+ /* Use CONVERT to convert *T to a broken down time in *TP.
--- /dev/null
+2006-06-23 Paul Eggert <eggert@cs.ucla.edu>
+
+ [BZ #2841]
+ * sysdeps/generic/stdint.h (UINT8_C, UINT16_C): Don't append 'U',
+ since C99 requires the result to promote to 'int' when uint_least8_t
+ and uint_least16_t promote to 'int'.
+
+--- libc/sysdeps/generic/stdint.h 18 Aug 2001 22:15:39 -0000 1.10
++++ libc/sysdeps/generic/stdint.h 12 Aug 2006 21:22:51 -0000 1.11
+@@ -297,8 +297,8 @@ typedef unsigned long long int uintmax_t
+ # endif
+
+ /* Unsigned. */
+-# define UINT8_C(c) c ## U
+-# define UINT16_C(c) c ## U
++# define UINT8_C(c) c
++# define UINT16_C(c) c
+ # define UINT32_C(c) c ## U
+ # if __WORDSIZE == 64
+ # define UINT64_C(c) c ## UL
--- /dev/null
+2006-08-12 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2843]
+ * pthread_join.c (pthread_join): Account for self being canceled
+ when checking for deadlocks.
+ * tst-join5.c: Cleanups. Allow to be used in tst-join6.
+ (tf1): Don't print anything after pthread_join returns, this would be
+ another cancellation point.
+ (tf2): Likewise.
+ * tst-join6.c: New file.
+ * Makefile (tests): Add tst-join6.
+
+--- libc/nptl/Makefile 1 Aug 2006 06:05:02 -0000 1.183
++++ libc/nptl/Makefile 13 Aug 2006 01:53:28 -0000 1.184
+@@ -224,7 +224,7 @@ tests = tst-typesizes \
+ tst-basic1 tst-basic2 tst-basic3 tst-basic4 tst-basic5 tst-basic6 \
+ tst-kill1 tst-kill2 tst-kill3 tst-kill4 tst-kill5 tst-kill6 \
+ tst-raise1 \
+- tst-join1 tst-join2 tst-join3 tst-join4 tst-join5 \
++ tst-join1 tst-join2 tst-join3 tst-join4 tst-join5 tst-join6 \
+ tst-detach1 \
+ tst-eintr1 tst-eintr2 tst-eintr3 tst-eintr4 tst-eintr5 \
+ tst-tsd1 tst-tsd2 tst-tsd3 tst-tsd4 tst-tsd5 \
+--- libc/nptl/pthread_join.c 21 Dec 2005 22:17:21 -0000 1.9
++++ libc/nptl/pthread_join.c 13 Aug 2006 01:54:37 -0000 1.10
+@@ -27,7 +27,11 @@
+ static void
+ cleanup (void *arg)
+ {
+- *(void **) arg = NULL;
++ /* If we already changed the waiter ID, reset it. The call cannot
++ fail for any reason but the thread not having done that yet so
++ there is no reason for a loop. */
++ atomic_compare_and_exchange_bool_acq ((struct pthread **) arg, NULL,
++ THREAD_SELF);
+ }
+
+
+@@ -36,7 +40,6 @@ pthread_join (threadid, thread_return)
+ pthread_t threadid;
+ void **thread_return;
+ {
+- struct pthread *self;
+ struct pthread *pd = (struct pthread *) threadid;
+
+ /* Make sure the descriptor is valid. */
+@@ -49,12 +52,23 @@ pthread_join (threadid, thread_return)
+ /* We cannot wait for the thread. */
+ return EINVAL;
+
+- self = THREAD_SELF;
+- if (pd == self
+- || (self->joinid == pd
+- && (pd->cancelhandling
+- & (CANCELING_BITMASK | CANCELED_BITMASK | EXITING_BITMASK
+- | TERMINATED_BITMASK)) == 0))
++ struct pthread *self = THREAD_SELF;
++ int result = 0;
++
++ /* During the wait we change to asynchronous cancellation. If we
++ are canceled the thread we are waiting for must be marked as
++ un-wait-ed for again. */
++ pthread_cleanup_push (cleanup, &pd->joinid);
++
++ /* Switch to asynchronous cancellation. */
++ int oldtype = CANCEL_ASYNC ();
++
++ if ((pd == self
++ || (self->joinid == pd
++ && (pd->cancelhandling
++ & (CANCELING_BITMASK | CANCELED_BITMASK | EXITING_BITMASK
++ | TERMINATED_BITMASK)) == 0))
++ && !CANCEL_ENABLED_AND_CANCELED (self->cancelhandling))
+ /* This is a deadlock situation. The threads are waiting for each
+ other to finish. Note that this is a "may" error. To be 100%
+ sure we catch this error we would have to lock the data
+@@ -62,28 +76,17 @@ pthread_join (threadid, thread_return)
+ two threads are really caught in this situation they will
+ deadlock. It is the programmer's problem to figure this
+ out. */
+- return EDEADLK;
+-
++ result = EDEADLK;
+ /* Wait for the thread to finish. If it is already locked something
+ is wrong. There can only be one waiter. */
+- if (__builtin_expect (atomic_compare_and_exchange_bool_acq (&pd->joinid,
+- self,
+- NULL), 0))
++ else if (__builtin_expect (atomic_compare_and_exchange_bool_acq (&pd->joinid,
++ self,
++ NULL), 0))
+ /* There is already somebody waiting for the thread. */
+- return EINVAL;
+-
+-
+- /* During the wait we change to asynchronous cancellation. If we
+- are cancelled the thread we are waiting for must be marked as
+- un-wait-ed for again. */
+- pthread_cleanup_push (cleanup, &pd->joinid);
+-
+- /* Switch to asynchronous cancellation. */
+- int oldtype = CANCEL_ASYNC ();
+-
+-
+- /* Wait for the child. */
+- lll_wait_tid (pd->tid);
++ result = EINVAL;
++ else
++ /* Wait for the child. */
++ lll_wait_tid (pd->tid);
+
+
+ /* Restore cancellation mode. */
+@@ -93,16 +96,19 @@ pthread_join (threadid, thread_return)
+ pthread_cleanup_pop (0);
+
+
+- /* We mark the thread as terminated and as joined. */
+- pd->tid = -1;
++ if (__builtin_expect (result == 0, 1))
++ {
++ /* We mark the thread as terminated and as joined. */
++ pd->tid = -1;
+
+- /* Store the return value if the caller is interested. */
+- if (thread_return != NULL)
+- *thread_return = pd->result;
++ /* Store the return value if the caller is interested. */
++ if (thread_return != NULL)
++ *thread_return = pd->result;
+
+
+- /* Free the TCB. */
+- __free_tcb (pd);
++ /* Free the TCB. */
++ __free_tcb (pd);
++ }
+
+- return 0;
++ return result;
+ }
+--- libc/nptl/tst-join5.c 23 Mar 2003 10:01:40 -0000 1.2
++++ libc/nptl/tst-join5.c 13 Aug 2006 01:52:22 -0000 1.3
+@@ -21,120 +21,187 @@
+ #include <pthread.h>
+ #include <stdio.h>
+ #include <stdlib.h>
++#include <time.h>
++#include <unistd.h>
++#include <sys/syscall.h>
++
++
++#define wait_code() \
++ do { \
++ struct timespec ts = { .tv_sec = 0, .tv_nsec = 200000000 }; \
++ while (syscall (__NR_nanosleep, &ts, &ts) < 0) \
++ /* nothing */; \
++ } while (0)
++
++
++#ifdef WAIT_IN_CHILD
++static pthread_barrier_t b;
++#endif
+
+
+ static void *
+ tf1 (void *arg)
+ {
+- pthread_join ((pthread_t) arg, NULL);
++#ifdef WAIT_IN_CHILD
++ int e = pthread_barrier_wait (&b);
++ if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
++ {
++ printf ("%s: barrier_wait failed\n", __func__);
++ exit (1);
++ }
++
++ wait_code ();
++#endif
+
+- puts ("1st join returned");
++ pthread_join ((pthread_t) arg, NULL);
+
+- return (void *) 1l;
++ exit (42);
+ }
+
+
+ static void *
+ tf2 (void *arg)
+ {
+- pthread_join ((pthread_t) arg, NULL);
++#ifdef WAIT_IN_CHILD
++ int e = pthread_barrier_wait (&b);
++ if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
++ {
++ printf ("%s: barrier_wait failed\n", __func__);
++ exit (1);
++ }
+
+- puts ("2nd join returned");
++ wait_code ();
++#endif
++ pthread_join ((pthread_t) arg, NULL);
+
+- return (void *) 1l;
++ exit (43);
+ }
+
+
+ static int
+ do_test (void)
+ {
++#ifdef WAIT_IN_CHILD
++ if (pthread_barrier_init (&b, NULL, 2) != 0)
++ {
++ puts ("barrier_init failed");
++ return 1;
++ }
++#endif
++
+ pthread_t th;
+
+ int err = pthread_join (pthread_self (), NULL);
+ if (err == 0)
+ {
+ puts ("1st circular join succeeded");
+- exit (1);
++ return 1;
+ }
+ if (err != EDEADLK)
+ {
+ printf ("1st circular join %d, not EDEADLK\n", err);
+- exit (1);
++ return 1;
+ }
+
+ if (pthread_create (&th, NULL, tf1, (void *) pthread_self ()) != 0)
+ {
+ puts ("1st create failed");
+- exit (1);
++ return 1;
+ }
+
++#ifndef WAIT_IN_CHILD
++ wait_code ();
++#endif
++
+ if (pthread_cancel (th) != 0)
+ {
+ puts ("cannot cancel 1st thread");
+- exit (1);
++ return 1;
+ }
+
++#ifdef WAIT_IN_CHILD
++ int e = pthread_barrier_wait (&b);
++ if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
++ {
++ printf ("%s: barrier_wait failed\n", __func__);
++ return 1;
++ }
++#endif
++
+ void *r;
+ err = pthread_join (th, &r);
+ if (err != 0)
+ {
+ printf ("cannot join 1st thread: %d\n", err);
+- exit (1);
++ return 1;
+ }
+ if (r != PTHREAD_CANCELED)
+ {
+ puts ("1st thread not canceled");
+- exit (1);
++ return 1;
+ }
+
+ err = pthread_join (pthread_self (), NULL);
+ if (err == 0)
+ {
+ puts ("2nd circular join succeeded");
+- exit (1);
++ return 1;
+ }
+ if (err != EDEADLK)
+ {
+ printf ("2nd circular join %d, not EDEADLK\n", err);
+- exit (1);
++ return 1;
+ }
+
+ if (pthread_create (&th, NULL, tf2, (void *) pthread_self ()) != 0)
+ {
+ puts ("2nd create failed");
+- exit (1);
++ return 1;
+ }
+
++#ifndef WAIT_IN_CHILD
++ wait_code ();
++#endif
++
+ if (pthread_cancel (th) != 0)
+ {
+ puts ("cannot cancel 2nd thread");
+- exit (1);
++ return 1;
+ }
+
++#ifdef WAIT_IN_CHILD
++ e = pthread_barrier_wait (&b);
++ if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
++ {
++ printf ("%s: barrier_wait failed\n", __func__);
++ return 1;
++ }
++#endif
++
+ if (pthread_join (th, &r) != 0)
+ {
+ puts ("cannot join 2nd thread");
+- exit (1);
++ return 1;
+ }
+ if (r != PTHREAD_CANCELED)
+ {
+ puts ("2nd thread not canceled");
+- exit (1);
++ return 1;
+ }
+
+ err = pthread_join (pthread_self (), NULL);
+ if (err == 0)
+ {
+- puts ("2nd circular join succeeded");
+- exit (1);
++ puts ("3rd circular join succeeded");
++ return 1;
+ }
+ if (err != EDEADLK)
+ {
+- printf ("2nd circular join %d, not EDEADLK\n", err);
+- exit (1);
++ printf ("3rd circular join %d, not EDEADLK\n", err);
++ return 1;
+ }
+
+- exit (0);
++ return 0;
+ }
+
+ #define TEST_FUNCTION do_test ()
+--- libc/nptl/tst-join6.c 1 Jan 1970 00:00:00 -0000
++++ libc/nptl/tst-join6.c 13 Aug 2006 01:51:08 -0000 1.1
+@@ -0,0 +1,2 @@
++#define WAIT_IN_CHILD 1
++#include "tst-join5.c"
--- /dev/null
+2006-08-03 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2892]
+ * pthread_setspecific.c (__pthread_setspecific): Check
+ out-of-range index before checking for unused key.
+
+--- libc/nptl/pthread_setspecific.c 2 Apr 2003 03:41:41 -0000 1.4
++++ libc/nptl/pthread_setspecific.c 3 Aug 2006 09:34:57 -0000 1.5
+@@ -52,8 +52,8 @@ __pthread_setspecific (key, value)
+ }
+ else
+ {
+- if (KEY_UNUSED ((seq = __pthread_keys[key].seq))
+- || key >= PTHREAD_KEYS_MAX)
++ if (key >= PTHREAD_KEYS_MAX
++ || KEY_UNUSED ((seq = __pthread_keys[key].seq)))
+ /* Not valid. */
+ return EINVAL;
+
--- /dev/null
+2006-08-08 Jakub Jelinek <jakub@redhat.com>
+
+ * stdio-common/bug16.c (tests): New array.
+ (do_tests): Allow the first hexadecimal digit
+ to be 1, 2, 4 or 8. Do 3 additional tests.
+
+2006-08-03 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2908]
+ * sysdeps/generic/printf_fphex.c (__printf_fphex): When rounding up
+ 'f', use '1' as leading digit not '\1'.
+ * stdio-common/Makefile (tests): Add bug16.
+ * stdio-common/bug16.c: New file.
+
+--- libc/stdio-common/Makefile 14 Jan 2006 12:09:45 -0000 1.97
++++ libc/stdio-common/Makefile 3 Aug 2006 09:25:01 -0000 1.98
+@@ -54,7 +54,7 @@ tests := tstscanf test_rdwr test-popen t
+ tst-swprintf tst-fseek tst-fmemopen test-vfprintf tst-gets \
+ tst-perror tst-sprintf tst-rndseek tst-fdopen tst-fphex bug14 bug15 \
+ tst-popen tst-unlockedio tst-fmemopen2 tst-put-error tst-fgets \
+- tst-fwrite
++ tst-fwrite bug16
+
+ test-srcs = tst-unbputc tst-printf
+
+--- libc/sysdeps/generic/printf_fphex.c 14 Dec 2005 10:00:09 -0000 1.14
++++ libc/sysdeps/generic/printf_fphex.c 3 Aug 2006 09:37:36 -0000 1.17
+@@ -399,12 +399,15 @@ __printf_fphex (FILE *fp,
+ ++leading;
+ else
+ {
+- leading = 1;
++ leading = '1';
+ if (expnegative)
+ {
+- exponent += 4;
+- if (exponent >= 0)
+- expnegative = 0;
++ exponent -= 4;
++ if (exponent <= 0)
++ {
++ exponent = -exponent;
++ expnegative = 0;
++ }
+ }
+ else
+ exponent += 4;
+--- libc/stdio-common/bug16.c 1 Jan 1970 00:00:00 -0000
++++ libc/stdio-common/bug16.c 8 Aug 2006 15:44:33 -0000 1.2
+@@ -0,0 +1,43 @@
++#include <stdio.h>
++#include <string.h>
++
++struct
++{
++ long double val;
++ const char str[4][7];
++} tests[] =
++{
++ { 0x0.FFFFp+0L, { "0X1P+0", "0X2P-1", "0X4P-2", "0X8P-3" } },
++ { 0x0.FFFFp+1L, { "0X1P+1", "0X2P+0", "0X4P-1", "0X8P-2" } },
++ { 0x0.FFFFp+2L, { "0X1P+2", "0X2P+1", "0X4P+0", "0X8P-1" } },
++ { 0x0.FFFFp+3L, { "0X1P+3", "0X2P+2", "0X4P+1", "0X8P+0" } }
++};
++
++static int
++do_test (void)
++{
++ char buf[100];
++ int ret = 0;
++
++ for (size_t i = 0; i < sizeof (tests) / sizeof (tests[0]); ++i)
++ {
++ snprintf (buf, sizeof (buf), "%.0LA", tests[i].val);
++
++ size_t j;
++ for (j = 0; j < 4; ++j)
++ if (strcmp (buf, tests[i].str[j]) == 0)
++ break;
++
++ if (j == 4)
++ {
++ printf ("%zd: got \"%s\", expected \"%s\" or equivalent\n",
++ i, buf, tests[i].str[0]);
++ ret = 1;
++ }
++ }
++
++ return ret;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
--- /dev/null
+2006-08-03 Eric Blake <ebb9@byu.net>
+
+ [BZ #2998]
+ * misc/error.c (error_tail) [_LIBC]: Avoid invalid free.
+
+--- libc/misc/error.c 28 Jul 2005 21:42:37 -0000 1.38
++++ libc/misc/error.c 12 Aug 2006 17:57:29 -0000 1.39
+@@ -224,7 +224,10 @@ error_tail (int status, int errnum, cons
+ {
+ /* The string cannot be converted. */
+ if (use_malloc)
+- free (wmessage);
++ {
++ free (wmessage);
++ use_malloc = false;
++ }
+ wmessage = (wchar_t *) L"???";
+ }
+
--- /dev/null
+2006-09-12 Ulrich Drepper <drepper@redhat.com>
+
+ * tst-cond22.c (tf): Slight changes to the pthread_cond_wait use
+ to guarantee the thread is always canceled.
+
+2006-09-08 Jakub Jelinek <jakub@redhat.com>
+
+ * tst-cond22.c: Include pthread.h instead of pthreadP.h.
+ Include stdlib.h.
+ * sysdeps/pthread/pthread_cond_wait.c (__condvar_cleanup): Only
+ increase FUTEX if increasing WAKEUP_SEQ. Fix comment typo.
+ * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise.
+ * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+ * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise.
+
+2006-09-08 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #3123]
+ * sysdeps/pthread/pthread_cond_wait.c (__condvar_cleanup): Don't
+ increment WAKEUP_SEQ if this would increase the value beyond TOTAL_SEQ.
+ * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S: Likewise.
+ * sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S: Likewise.
+ * sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: Likewise.
+ * Makefile (tests): Add tst-cond22.
+ * tst-cond22.c: New file.
+
+--- libc/nptl/Makefile 21 Aug 2006 21:02:10 -0000 1.186
++++ libc/nptl/Makefile 8 Sep 2006 10:40:49 -0000 1.188
+@@ -196,7 +196,7 @@ tests = tst-attr1 tst-attr2 tst-attr3 \
+ tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 \
+ tst-cond8 tst-cond9 tst-cond10 tst-cond11 tst-cond12 tst-cond13 \
+ tst-cond14 tst-cond15 tst-cond16 tst-cond17 tst-cond18 tst-cond19 \
+- tst-cond20 tst-cond21 \
++ tst-cond20 tst-cond21 tst-cond22 \
+ tst-rwlock1 tst-rwlock2 tst-rwlock3 tst-rwlock4 tst-rwlock5 \
+ tst-rwlock6 tst-rwlock7 tst-rwlock8 tst-rwlock9 tst-rwlock10 \
+ tst-rwlock11 tst-rwlock12 tst-rwlock13 tst-rwlock14 \
+--- libc/nptl/tst-cond22.c 1 Jan 1970 00:00:00 -0000
++++ libc/nptl/tst-cond22.c 12 Sep 2006 12:24:28 -0000 1.5
+@@ -0,0 +1,160 @@
++#include <pthread.h>
++#include <stdio.h>
++#include <stdlib.h>
++
++
++static pthread_barrier_t b;
++static pthread_cond_t c = PTHREAD_COND_INITIALIZER;
++static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
++
++
++static void
++cl (void *arg)
++{
++ pthread_mutex_unlock (&m);
++}
++
++
++static void *
++tf (void *arg)
++{
++ if (pthread_mutex_lock (&m) != 0)
++ {
++ printf ("%s: mutex_lock failed\n", __func__);
++ exit (1);
++ }
++ int e = pthread_barrier_wait (&b);
++ if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
++ {
++ printf ("%s: barrier_wait failed\n", __func__);
++ exit (1);
++ }
++ pthread_cleanup_push (cl, NULL);
++ /* We have to loop here because the cancellation might come after
++ the cond_wait call left the cancelable area and is then waiting
++ on the mutex. In this case the beginning of the second cond_wait
++ call will cause the cancellation to happen. */
++ do
++ if (pthread_cond_wait (&c, &m) != 0)
++ {
++ printf ("%s: cond_wait failed\n", __func__);
++ exit (1);
++ }
++ while (arg == NULL);
++ pthread_cleanup_pop (0);
++ if (pthread_mutex_unlock (&m) != 0)
++ {
++ printf ("%s: mutex_unlock failed\n", __func__);
++ exit (1);
++ }
++ return NULL;
++}
++
++
++static int
++do_test (void)
++{
++ int status = 0;
++
++ if (pthread_barrier_init (&b, NULL, 2) != 0)
++ {
++ puts ("barrier_init failed");
++ return 1;
++ }
++
++ pthread_t th;
++ if (pthread_create (&th, NULL, tf, NULL) != 0)
++ {
++ puts ("1st create failed");
++ return 1;
++ }
++ int e = pthread_barrier_wait (&b);
++ if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
++ {
++ puts ("1st barrier_wait failed");
++ return 1;
++ }
++ if (pthread_mutex_lock (&m) != 0)
++ {
++ puts ("1st mutex_lock failed");
++ return 1;
++ }
++ if (pthread_cond_signal (&c) != 0)
++ {
++ puts ("1st cond_signal failed");
++ return 1;
++ }
++ if (pthread_cancel (th) != 0)
++ {
++ puts ("cancel failed");
++ return 1;
++ }
++ if (pthread_mutex_unlock (&m) != 0)
++ {
++ puts ("1st mutex_unlock failed");
++ return 1;
++ }
++ void *res;
++ if (pthread_join (th, &res) != 0)
++ {
++ puts ("1st join failed");
++ return 1;
++ }
++ if (res != PTHREAD_CANCELED)
++ {
++ puts ("first thread not canceled");
++ status = 1;
++ }
++
++ printf ("cond = { %d, %x, %lld, %lld, %lld, %p, %u, %u }\n",
++ c.__data.__lock, c.__data.__futex, c.__data.__total_seq,
++ c.__data.__wakeup_seq, c.__data.__woken_seq, c.__data.__mutex,
++ c.__data.__nwaiters, c.__data.__broadcast_seq);
++
++ if (pthread_create (&th, NULL, tf, (void *) 1l) != 0)
++ {
++ puts ("2nd create failed");
++ return 1;
++ }
++ e = pthread_barrier_wait (&b);
++ if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
++ {
++ puts ("2nd barrier_wait failed");
++ return 1;
++ }
++ if (pthread_mutex_lock (&m) != 0)
++ {
++ puts ("2nd mutex_lock failed");
++ return 1;
++ }
++ if (pthread_cond_signal (&c) != 0)
++ {
++ puts ("2nd cond_signal failed");
++ return 1;
++ }
++ if (pthread_mutex_unlock (&m) != 0)
++ {
++ puts ("2nd mutex_unlock failed");
++ return 1;
++ }
++ if (pthread_join (th, &res) != 0)
++ {
++ puts ("2nd join failed");
++ return 1;
++ }
++ if (res != NULL)
++ {
++ puts ("2nd thread canceled");
++ status = 1;
++ }
++
++ printf ("cond = { %d, %x, %lld, %lld, %lld, %p, %u, %u }\n",
++ c.__data.__lock, c.__data.__futex, c.__data.__total_seq,
++ c.__data.__wakeup_seq, c.__data.__woken_seq, c.__data.__mutex,
++ c.__data.__nwaiters, c.__data.__broadcast_seq);
++
++ return status;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- libc/nptl/sysdeps/pthread/pthread_cond_wait.c 2 Sep 2004 18:49:34 -0000 1.16
++++ libc/nptl/sysdeps/pthread/pthread_cond_wait.c 9 Sep 2006 11:21:23 -0000 1.18
+@@ -50,10 +50,16 @@ __condvar_cleanup (void *arg)
+ if (cbuffer->bc_seq == cbuffer->cond->__data.__broadcast_seq)
+ {
+ /* This thread is not waiting anymore. Adjust the sequence counters
+- appropriately. */
+- ++cbuffer->cond->__data.__wakeup_seq;
++ appropriately. We do not increment WAKEUP_SEQ if this would
++ bump it over the value of TOTAL_SEQ. This can happen if a thread
++ was woken and then canceled. */
++ if (cbuffer->cond->__data.__wakeup_seq
++ < cbuffer->cond->__data.__total_seq)
++ {
++ ++cbuffer->cond->__data.__wakeup_seq;
++ ++cbuffer->cond->__data.__futex;
++ }
+ ++cbuffer->cond->__data.__woken_seq;
+- ++cbuffer->cond->__data.__futex;
+ }
+
+ cbuffer->cond->__data.__nwaiters -= 1 << COND_CLOCK_BITS;
+--- libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S 2 Sep 2004 18:53:10 -0000 1.37
++++ libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_timedwait.S 9 Sep 2006 11:21:23 -0000 1.39
+@@ -406,12 +406,22 @@ __condvar_tw_cleanup:
+ cmpl 20(%esp), %eax
+ jne 3f
+
+- addl $1, wakeup_seq(%ebx)
+- adcl $0, wakeup_seq+4(%ebx)
++ /* We increment the wakeup_seq counter only if it is lower than
++ total_seq. If this is not the case the thread was woken and
++ then canceled. In this case we ignore the signal. */
++ movl total_seq(%ebx), %eax
++ movl total_seq+4(%ebx), %edi
++ cmpl wakeup_seq+4(%ebx), %edi
++ jb 6f
++ ja 7f
++ cmpl wakeup_seq(%ebx), %eax
++ jbe 7f
+
++6: addl $1, wakeup_seq(%ebx)
++ adcl $0, wakeup_seq+4(%ebx)
+ addl $1, cond_futex(%ebx)
+
+- addl $1, woken_seq(%ebx)
++7: addl $1, woken_seq(%ebx)
+ adcl $0, woken_seq+4(%ebx)
+
+ 3: subl $(1 << clock_bits), cond_nwaiters(%ebx)
+--- libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S 2 Sep 2004 18:52:38 -0000 1.32
++++ libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_cond_wait.S 9 Sep 2006 11:21:23 -0000 1.34
+@@ -297,12 +297,22 @@ __condvar_w_cleanup:
+ cmpl 12(%esp), %eax
+ jne 3f
+
+- addl $1, wakeup_seq(%ebx)
+- adcl $0, wakeup_seq+4(%ebx)
++ /* We increment the wakeup_seq counter only if it is lower than
++ total_seq. If this is not the case the thread was woken and
++ then canceled. In this case we ignore the signal. */
++ movl total_seq(%ebx), %eax
++ movl total_seq+4(%ebx), %edi
++ cmpl wakeup_seq+4(%ebx), %edi
++ jb 6f
++ ja 7f
++ cmpl wakeup_seq(%ebx), %eax
++ jbe 7f
+
++6: addl $1, wakeup_seq(%ebx)
++ adcl $0, wakeup_seq+4(%ebx)
+ addl $1, cond_futex(%ebx)
+
+- addl $1, woken_seq(%ebx)
++7: addl $1, woken_seq(%ebx)
+ adcl $0, woken_seq+4(%ebx)
+
+ 3: subl $(1 << clock_bits), cond_nwaiters(%ebx)
+--- libc/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S 31 Mar 2005 10:00:15 -0000 1.22
++++ libc/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S 9 Sep 2006 11:21:23 -0000 1.24
+@@ -67,9 +67,15 @@ __condvar_cleanup:
+ cmpl 4(%r8), %edx
+ jne 3f
+
++ /* We increment the wakeup_seq counter only if it is lower than
++ total_seq. If this is not the case the thread was woken and
++ then canceled. In this case we ignore the signal. */
++ movq total_seq(%rdi), %rax
++ cmpq wakeup_seq(%rdi), %rax
++ jbe 6f
+ incq wakeup_seq(%rdi)
+- incq woken_seq(%rdi)
+ incl cond_futex(%rdi)
++6: incq woken_seq(%rdi)
+
+ 3: subl $(1 << clock_bits), cond_nwaiters(%rdi)
+
--- /dev/null
+2006-09-05 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #3124]
+ * descr.h (struct pthread): Add parent_cancelhandling.
+ * sysdeps/pthread/createthread.c (create_thread): Pass parent
+ cancelhandling value to child.
+ * pthread_create.c (start_thread): If parent thread was canceled
+ reset the SIGCANCEL mask.
+ * Makefile (tests): Add tst-cancel25.
+ * tst-cancel25.c: New file.
+
+--- libc/nptl/Makefile 21 Aug 2006 21:02:10 -0000 1.186
++++ libc/nptl/Makefile 8 Sep 2006 10:40:49 -0000 1.188
+@@ -220,7 +220,7 @@ tests = tst-attr1 tst-attr2 tst-attr3 \
+ tst-cancel6 tst-cancel7 tst-cancel8 tst-cancel9 tst-cancel10 \
+ tst-cancel11 tst-cancel12 tst-cancel13 tst-cancel14 tst-cancel15 \
+ tst-cancel16 tst-cancel17 tst-cancel18 tst-cancel19 tst-cancel20 \
+- tst-cancel21 tst-cancel22 tst-cancel23 \
++ tst-cancel21 tst-cancel22 tst-cancel23 tst-cancel25 \
+ tst-cleanup0 tst-cleanup1 tst-cleanup2 tst-cleanup3 tst-cleanup4 \
+ tst-flock1 tst-flock2 \
+ tst-signal1 tst-signal2 tst-signal3 tst-signal4 tst-signal5 \
+--- libc/nptl/descr.h 14 Aug 2006 22:58:59 -0000 1.36
++++ libc/nptl/descr.h 5 Sep 2006 17:14:03 -0000 1.37
+@@ -296,6 +296,10 @@ struct pthread
+ /* True if thread must stop at startup time. */
+ bool stopped_start;
+
++ /* The parent's cancel handling at the time of the pthread_create
++ call. This might be needed to undo the effects of a cancellation. */
++ int parent_cancelhandling;
++
+ /* Lock to synchronize access to the descriptor. */
+ lll_lock_t lock;
+
+--- libc/nptl/pthread_create.c 14 Aug 2006 23:06:09 -0000 1.53
++++ libc/nptl/pthread_create.c 5 Sep 2006 17:12:15 -0000 1.54
+@@ -251,6 +251,19 @@ start_thread (void *arg)
+ }
+ #endif
+
++ /* If the parent was running cancellation handlers while creating
++ the thread the new thread inherited the signal mask. Reset the
++ cancellation signal mask. */
++ if (__builtin_expect (pd->parent_cancelhandling & CANCELING_BITMASK, 0))
++ {
++ INTERNAL_SYSCALL_DECL (err);
++ sigset_t mask;
++ __sigemptyset (&mask);
++ __sigaddset (&mask, SIGCANCEL);
++ (void) INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_UNBLOCK, &mask,
++ NULL, _NSIG / 8);
++ }
++
+ /* This is where the try/finally block should be created. For
+ compilers without that support we do use setjmp. */
+ struct pthread_unwind_buf unwind_buf;
+--- libc/nptl/tst-cancel25.c 1 Jan 1970 00:00:00 -0000
++++ libc/nptl/tst-cancel25.c 5 Sep 2006 17:11:13 -0000 1.1
+@@ -0,0 +1,171 @@
++#include <pthreadP.h>
++#include <signal.h>
++#include <stdio.h>
++#include <stdlib.h>
++
++
++static pthread_barrier_t b;
++static pthread_t th2;
++
++
++static void *
++tf2 (void *arg)
++{
++ sigset_t mask;
++ if (pthread_sigmask (SIG_SETMASK, NULL, &mask) != 0)
++ {
++ puts ("pthread_sigmask failed");
++ exit (1);
++ }
++ if (sigismember (&mask, SIGCANCEL))
++ {
++ puts ("SIGCANCEL blocked in new thread");
++ exit (1);
++ }
++
++ /* Sync with the main thread so that we do not test anything else. */
++ int e = pthread_barrier_wait (&b);
++ if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
++ {
++ puts ("barrier_wait failed");
++ exit (1);
++ }
++
++ while (1)
++ {
++ /* Just a cancelable call. */
++ struct timespec ts = { 10000, 0 };
++ nanosleep (&ts, 0);
++ }
++
++ return NULL;
++}
++
++
++static void
++unwhand (void *arg)
++{
++ if (pthread_create (&th2, NULL, tf2, NULL) != 0)
++ {
++ puts ("unwhand: create failed");
++ exit (1);
++ }
++}
++
++
++static void *
++tf (void *arg)
++{
++ pthread_cleanup_push (unwhand, NULL);
++
++ /* Sync with the main thread so that we do not test anything else. */
++ int e = pthread_barrier_wait (&b);
++ if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
++ {
++ puts ("barrier_wait failed");
++ exit (1);
++ }
++
++ while (1)
++ {
++ /* Just a cancelable call. */
++ struct timespec ts = { 10000, 0 };
++ nanosleep (&ts, 0);
++ }
++
++ pthread_cleanup_pop (0);
++
++ return NULL;
++}
++
++
++static int
++do_test (void)
++{
++ if (pthread_barrier_init (&b, NULL, 2) != 0)
++ {
++ puts ("barrier_init failed");
++ return 1;
++ }
++
++ pthread_t th1;
++ if (pthread_create (&th1, NULL, tf, NULL) != 0)
++ {
++ puts ("create failed");
++ return 1;
++ }
++
++ int e = pthread_barrier_wait (&b);
++ if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
++ {
++ puts ("barrier_wait failed");
++ return 1;
++ }
++
++ /* Make sure tf1 enters nanosleep. */
++ struct timespec ts = { 0, 500000000 };
++ while (nanosleep (&ts, &ts) != 0)
++ ;
++
++ if (pthread_cancel (th1) != 0)
++ {
++ puts ("1st cancel failed");
++ return 1;
++ }
++
++ void *res;
++ if (pthread_join (th1, &res) != 0)
++ {
++ puts ("1st join failed");
++ return 1;
++ }
++ if (res != PTHREAD_CANCELED)
++ {
++ puts ("1st thread not canceled");
++ return 1;
++ }
++
++ e = pthread_barrier_wait (&b);
++ if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
++ {
++ puts ("barrier_wait failed");
++ return 1;
++ }
++
++ /* Make sure tf2 enters nanosleep. */
++ ts.tv_sec = 0;
++ ts.tv_nsec = 500000000;
++ while (nanosleep (&ts, &ts) != 0)
++ ;
++
++ puts ("calling pthread_cancel the second time");
++ if (pthread_cancel (th2) != 0)
++ {
++ puts ("2nd cancel failed");
++ return 1;
++ }
++
++ puts ("calling pthread_join the second time");
++ if (pthread_join (th2, &res) != 0)
++ {
++ puts ("2nd join failed");
++ return 1;
++ }
++ if (res != PTHREAD_CANCELED)
++ {
++ puts ("2nd thread not canceled");
++ return 1;
++ }
++
++ if (pthread_barrier_destroy (&b) != 0)
++ {
++ puts ("barrier_destroy failed");
++ return 0;
++ }
++
++ return 0;
++}
++
++#define TEST_FUNCTION do_test ()
++#define TIMEOUT 4
++#include "../test-skeleton.c"
+--- libc/nptl/sysdeps/pthread/createthread.c 20 Nov 2004 07:12:45 -0000 1.27
++++ libc/nptl/sysdeps/pthread/createthread.c 5 Sep 2006 17:13:14 -0000 1.28
+@@ -242,6 +242,7 @@ create_thread (struct pthread *pd, const
+ || (attr->flags & ATTR_FLAG_NOTINHERITSCHED) != 0))
+ stopped = true;
+ pd->stopped_start = stopped;
++ pd->parent_cancelhandling = THREAD_GETMEM (THREAD_SELF, cancelhandling);
+
+ /* Actually create the thread. */
+ int res = do_clone (pd, attr, clone_flags, start_thread,
--- /dev/null
+2006-09-07 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #3155]
+ * sysdeps/powerpc/powerpc32/fpu/s_lrint.S (__lrint): Don't access
+ stack below r1.
+
+--- libc/sysdeps/powerpc/powerpc32/fpu/s_lrint.S 28 Jan 2006 00:07:39 -0000 1.2
++++ libc/sysdeps/powerpc/powerpc32/fpu/s_lrint.S 7 Sep 2006 13:46:45 -0000 1.3
+@@ -21,13 +21,15 @@
+ #include <math_ldbl_opt.h>
+
+ /* long int[r3] __lrint (double x[fp1]) */
+-ENTRY (__lrint)
++ENTRY (__lrint)
++ stwu r1,-16(r1)
+ fctiw fp13,fp1
+- stfd fp13,-8(r1)
++ stfd fp13,8(r1)
+ nop /* Insure the following load is in a different dispatch group */
+ nop /* to avoid pipe stall on POWER4&5. */
+ nop
+- lwz r3,-4(r1)
++ lwz r3,12(r1)
++ addi r1,r1,16
+ blr
+ END (__lrint)
+
--- /dev/null
+2006-09-30 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/generic/glob.c (glob_in_dir): Add some comments and asserts to
+ explain why there are no leaks.
+
+2006-09-25 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #3253]
+ * sysdeps/generic/glob.c (glob_in_dir): Don't alloca one struct globlink at a
+ time, rather allocate increasingly bigger arrays of pointers, if
+ possible with alloca, if too large with malloc.
+
+--- libc/sysdeps/generic/glob.c 11 Jan 2006 05:30:02 -0000 1.69
++++ libc/sysdeps/generic/glob.c 30 Sep 2006 15:08:44 -0000 1.72
+@@ -1316,16 +1316,25 @@ glob_in_dir (pattern, directory, flags,
+ {
+ size_t dirlen = strlen (directory);
+ __ptr_t stream = NULL;
+- struct globlink
++ struct globnames
+ {
+- struct globlink *next;
+- char *name;
++ struct globnames *next;
++ size_t count;
++ char *name[64];
+ };
+- struct globlink *names = NULL;
+- size_t nfound;
++#define INITIAL_COUNT sizeof (init_names.name) / sizeof (init_names.name[0])
++ struct globnames init_names;
++ struct globnames *names = &init_names;
++ struct globnames *names_alloca = &init_names;
++ size_t nfound = 0;
++ size_t allocasize = sizeof (init_names);
++ size_t cur = 0;
+ int meta;
+ int save;
+
++ init_names.next = NULL;
++ init_names.count = INITIAL_COUNT;
++
+ meta = __glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE));
+ if (meta == 0 && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
+ {
+@@ -1333,7 +1342,6 @@ glob_in_dir (pattern, directory, flags,
+ characters and we must not return an error therefore the
+ result will always contain exactly one name. */
+ flags |= GLOB_NOCHECK;
+- nfound = 0;
+ }
+ else if (meta == 0 &&
+ ((flags & GLOB_NOESCAPE) || strchr (pattern, '\\') == NULL))
+@@ -1362,8 +1370,6 @@ glob_in_dir (pattern, directory, flags,
+ /* We found this file to be existing. Now tell the rest
+ of the function to copy this name into the result. */
+ flags |= GLOB_NOCHECK;
+-
+- nfound = 0;
+ }
+ else
+ {
+@@ -1371,12 +1377,10 @@ glob_in_dir (pattern, directory, flags,
+ {
+ /* This is a special case for matching directories like in
+ "*a/". */
+- names = (struct globlink *) __alloca (sizeof (struct globlink));
+- names->name = (char *) malloc (1);
+- if (names->name == NULL)
++ names->name[cur] = (char *) malloc (1);
++ if (names->name[cur] == NULL)
+ goto memory_error;
+- names->name[0] = '\0';
+- names->next = NULL;
++ *names->name[cur++] = '\0';
+ nfound = 1;
+ meta = 0;
+ }
+@@ -1391,7 +1395,6 @@ glob_in_dir (pattern, directory, flags,
+ && ((errfunc != NULL && (*errfunc) (directory, errno))
+ || (flags & GLOB_ERR)))
+ return GLOB_ABORTED;
+- nfound = 0;
+ meta = 0;
+ }
+ else
+@@ -1402,7 +1405,6 @@ glob_in_dir (pattern, directory, flags,
+ | FNM_CASEFOLD
+ #endif
+ );
+- nfound = 0;
+ flags |= GLOB_MAGCHAR;
+
+ while (1)
+@@ -1466,21 +1468,35 @@ glob_in_dir (pattern, directory, flags,
+ link_exists_p (directory, dirlen, name, pglob,
+ flags))
+ {
+- struct globlink *new = (struct globlink *)
+- __alloca (sizeof (struct globlink));
++ if (cur == names->count)
++ {
++ struct globnames *newnames;
++ size_t count = names->count * 2;
++ size_t size = (sizeof (struct globnames)
++ + ((count - INITIAL_COUNT)
++ * sizeof (char *)));
++ allocasize += size;
++ if (__libc_use_alloca (allocasize))
++ newnames = names_alloca = __alloca (size);
++ else if ((newnames = malloc (size))
++ == NULL)
++ goto memory_error;
++ newnames->count = count;
++ newnames->next = names;
++ names = newnames;
++ cur = 0;
++ }
+ len = NAMLEN (d);
+- new->name = (char *) malloc (len + 1);
+- if (new->name == NULL)
++ names->name[cur] = (char *) malloc (len + 1);
++ if (names->name[cur] == NULL)
+ goto memory_error;
+ #ifdef HAVE_MEMPCPY
+- *((char *) mempcpy ((__ptr_t) new->name, name, len))
++ *((char *) mempcpy (names->name[cur++], name, len))
+ = '\0';
+ #else
+- memcpy ((__ptr_t) new->name, name, len);
+- new->name[len] = '\0';
++ memcpy ((__ptr_t) names->name[cur], name, len);
++ names->name[cur++][len] = '\0';
+ #endif
+- new->next = names;
+- names = new;
+ ++nfound;
+ }
+ }
+@@ -1493,66 +1509,97 @@ glob_in_dir (pattern, directory, flags,
+ {
+ size_t len = strlen (pattern);
+ nfound = 1;
+- names = (struct globlink *) __alloca (sizeof (struct globlink));
+- names->next = NULL;
+- names->name = (char *) malloc (len + 1);
+- if (names->name == NULL)
++ names->name[cur] = (char *) malloc (len + 1);
++ if (names->name[cur] == NULL)
+ goto memory_error;
+ #ifdef HAVE_MEMPCPY
+- *((char *) mempcpy (names->name, pattern, len)) = '\0';
++ *((char *) mempcpy (names->name[cur++], pattern, len)) = '\0';
+ #else
+- memcpy (names->name, pattern, len);
+- names->name[len] = '\0';
++ memcpy (names->name[cur], pattern, len);
++ names->name[cur++][len] = '\0';
+ #endif
+ }
+
++ int result = GLOB_NOMATCH;
+ if (nfound != 0)
+ {
+- char **new_gl_pathv;
++ result = 0;
+
++ char **new_gl_pathv;
+ new_gl_pathv
+ = (char **) realloc (pglob->gl_pathv,
+ (pglob->gl_pathc + pglob->gl_offs + nfound + 1)
+ * sizeof (char *));
+ if (new_gl_pathv == NULL)
+- goto memory_error;
+- pglob->gl_pathv = new_gl_pathv;
++ {
++ memory_error:
++ while (1)
++ {
++ struct globnames *old = names;
++ for (size_t i = 0; i < cur; ++i)
++ free (names->name[i]);
++ names = names->next;
++ /* NB: we will not leak memory here if we exit without
++ freeing the current block assigned to OLD. At least
++ the very first block is always allocated on the stack
++ and this is the block assigned to OLD here. */
++ if (names == NULL)
++ {
++ assert (old == &init_names);
++ break;
++ }
++ cur = names->count;
++ if (old == names_alloca)
++ names_alloca = names;
++ else
++ free (old);
++ }
++ result = GLOB_NOSPACE;
++ }
++ else
++ {
++ while (1)
++ {
++ struct globnames *old = names;
++ for (size_t i = 0; i < cur; ++i)
++ new_gl_pathv[pglob->gl_offs + pglob->gl_pathc++]
++ = names->name[i];
++ names = names->next;
++ /* NB: we will not leak memory here if we exit without
++ freeing the current block assigned to OLD. At least
++ the very first block is always allocated on the stack
++ and this is the block assigned to OLD here. */
++ if (names == NULL)
++ {
++ assert (old == &init_names);
++ break;
++ }
++ cur = names->count;
++ if (old == names_alloca)
++ names_alloca = names;
++ else
++ free (old);
++ }
+
+- for (; names != NULL; names = names->next)
+- pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc++] = names->name;
+- pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
++ pglob->gl_pathv = new_gl_pathv;
+
+- pglob->gl_flags = flags;
++ pglob->gl_pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
++
++ pglob->gl_flags = flags;
++ }
+ }
+
+- save = errno;
+ if (stream != NULL)
+ {
++ save = errno;
+ if (flags & GLOB_ALTDIRFUNC)
+ (*pglob->gl_closedir) (stream);
+ else
+ closedir ((DIR *) stream);
++ __set_errno (save);
+ }
+- __set_errno (save);
+
+- return nfound == 0 ? GLOB_NOMATCH : 0;
+-
+- memory_error:
+- {
+- int save = errno;
+- if (flags & GLOB_ALTDIRFUNC)
+- (*pglob->gl_closedir) (stream);
+- else
+- closedir ((DIR *) stream);
+- __set_errno (save);
+- }
+- while (names != NULL)
+- {
+- if (names->name != NULL)
+- free ((__ptr_t) names->name);
+- names = names->next;
+- }
+- return GLOB_NOSPACE;
++ return result;
+ }
+
+ #endif /* Not ELIDE_CODE. */
--- /dev/null
+2008-02-11 Joseph Myers <joseph@codesourcery.com>
+
+ [BZ #3406]
+ * sysdeps/ieee754/flt-32/w_expf.c (o_threshold): Correct value.
+ * math/libm-test.inc (exp_test): Test 88.72269439697265625.
+
+--- libc/math/libm-test.inc 11 Apr 2008 19:32:30 -0000 1.79
++++ libc/math/libm-test.inc 22 May 2008 19:59:10 -0000 1.81
+@@ -2510,6 +2510,7 @@ exp_test (void)
+ TEST_f_f (exp, 3, M_E3l);
+ TEST_f_f (exp, 0.75L, 2.11700001661267466854536981983709561L);
+ TEST_f_f (exp, 50.0L, 5184705528587072464087.45332293348538L);
++ TEST_f_f (exp, 88.72269439697265625L, 3.40233126623160774937554134772290447915e38L);
+ #ifdef TEST_LDOUBLE
+ /* The result can only be represented in long double. */
+ TEST_f_f (exp, 1000.0L, 0.197007111401704699388887935224332313e435L);
+--- libc/sysdeps/ieee754/flt-32/w_expf.c 14 Jul 1999 00:03:46 -0000 1.1
++++ libc/sysdeps/ieee754/flt-32/w_expf.c 11 May 2008 17:49:19 -0000 1.2
+@@ -29,7 +29,7 @@ static const float
+ #else
+ static float
+ #endif
+-o_threshold= 8.8721679688e+01, /* 0x42b17180 */
++o_threshold= 8.8722831726e+01, /* 0x42b17217 */
+ u_threshold= -1.0397208405e+02; /* 0xc2cff1b5 */
+
+ #ifdef __STDC__
--- /dev/null
+2006-11-10 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #3451]
+ * sysdeps/i386/fpu/bits/mathinline.h (floor): Make rounding mode
+ change atomic.
+ (ceil): Likewise.
+
+--- libc/sysdeps/i386/fpu/bits/mathinline.h 7 Sep 2004 22:23:42 -0000 1.58
++++ libc/sysdeps/i386/fpu/bits/mathinline.h 10 Nov 2006 20:42:00 -0000 1.60
+@@ -529,24 +529,38 @@ __inline_mathcodeNP (tanh, __x, \
+
+ __inline_mathcodeNP (floor, __x, \
+ register long double __value; \
+- __volatile unsigned short int __cw; \
+- __volatile unsigned short int __cwtmp; \
+- __asm __volatile ("fnstcw %0" : "=m" (__cw)); \
+- __cwtmp = (__cw & 0xf3ff) | 0x0400; /* rounding down */ \
+- __asm __volatile ("fldcw %0" : : "m" (__cwtmp)); \
+- __asm __volatile ("frndint" : "=t" (__value) : "0" (__x)); \
+- __asm __volatile ("fldcw %0" : : "m" (__cw)); \
++ register int __ignore; \
++ unsigned short int __cw; \
++ unsigned short int __cwtmp; \
++ __asm __volatile ("fnstcw %3\n\t" \
++ "movzwl %3, %1\n\t" \
++ "andl $0xf3ff, %1\n\t" \
++ "orl $0x0400, %1\n\t" /* rounding down */ \
++ "movw %w1, %2\n\t" \
++ "fldcw %2\n\t" \
++ "frndint\n\t" \
++ "fldcw %3" \
++ : "=t" (__value), "=&q" (__ignore), "=m" (__cwtmp), \
++ "=m" (__cw) \
++ : "0" (__x)); \
+ return __value)
+
+ __inline_mathcodeNP (ceil, __x, \
+ register long double __value; \
+- __volatile unsigned short int __cw; \
+- __volatile unsigned short int __cwtmp; \
+- __asm __volatile ("fnstcw %0" : "=m" (__cw)); \
+- __cwtmp = (__cw & 0xf3ff) | 0x0800; /* rounding up */ \
+- __asm __volatile ("fldcw %0" : : "m" (__cwtmp)); \
+- __asm __volatile ("frndint" : "=t" (__value) : "0" (__x)); \
+- __asm __volatile ("fldcw %0" : : "m" (__cw)); \
++ register int __ignore; \
++ unsigned short int __cw; \
++ unsigned short int __cwtmp; \
++ __asm __volatile ("fnstcw %3\n\t" \
++ "movzwl %3, %1\n\t" \
++ "andl $0xf3ff, %1\n\t" \
++ "orl $0x0800, %1\n\t" /* rounding up */ \
++ "movw %w1, %2\n\t" \
++ "fldcw %2\n\t" \
++ "frndint\n\t" \
++ "fldcw %3" \
++ : "=t" (__value), "=&q" (__ignore), "=m" (__cwtmp), \
++ "=m" (__cw) \
++ : "0" (__x)); \
+ return __value)
+
+ #ifdef __FAST_MATH__
--- /dev/null
+2007-02-21 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #3458]
+ * sysdeps/unix/sysv/linux/posix_madvise.c: New file.
+ * sysdeps/unix/sysv/linux/syscalls.list: Remove posix_madvise entry.
+
+--- libc/sysdeps/unix/sysv/linux/posix_madvise.c 1 Jan 1970 00:00:00 -0000
++++ libc/sysdeps/unix/sysv/linux/posix_madvise.c 21 Feb 2007 19:07:06 -0000 1.2
+@@ -0,0 +1,38 @@
++/* Copyright (C) 2007 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <sysdep.h>
++#include <sys/mman.h>
++
++
++int
++posix_madvise (void *addr, size_t len, int advice)
++{
++ /* We have one problem: the kernel's MADV_DONTNEED does not
++ correspond to POSIX's POSIX_MADV_DONTNEED. The former simply
++ discards changes made to the memory without writing it back to
++ disk, if this would be necessary. The POSIX behavior does not
++ allow this. There is no functionality mapping the POSIX behavior
++ so far so we ignore that advice for now. */
++ if (advice == POSIX_MADV_DONTNEED)
++ return 0;
++
++ INTERNAL_SYSCALL_DECL (err);
++ int result = INTERNAL_SYSCALL (madvise, err, 3, addr, len, advice);
++ return INTERNAL_SYSCALL_ERRNO (result, err);
++}
+--- libc/sysdeps/unix/sysv/linux/syscalls.list 11 Oct 2006 20:18:04 -0000 1.128
++++ libc/sysdeps/unix/sysv/linux/syscalls.list 21 Feb 2007 19:02:17 -0000 1.129
+@@ -32,7 +32,6 @@ ioperm - ioperm i:iii ioperm
+ iopl - iopl i:i iopl
+ klogctl EXTRA syslog i:isi klogctl
+ lchown - lchown i:sii __lchown lchown
+-posix_madvise - madvise Vi:pii posix_madvise
+ madvise - madvise i:pii madvise
+ mincore - mincore i:anV mincore
+ mlock - mlock i:bn mlock
--- /dev/null
+2007-02-17 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #3842]
+ * sysdeps/posix/euidaccess.c [_LIBC] (euidaccess): Remove shortcut
+ using __libc_enable_secure.
+
+--- libc/sysdeps/posix/euidaccess.c 6 Jan 2006 11:21:57 -0000 1.13
++++ libc/sysdeps/posix/euidaccess.c 17 Feb 2007 18:12:29 -0000 1.14
+@@ -128,10 +128,6 @@ euidaccess (path, mode)
+ #ifdef _LIBC
+ uid_t euid;
+ gid_t egid;
+-
+- if (! __libc_enable_secure)
+- /* If we are not set-uid or set-gid, access does the same. */
+- return __access (path, mode);
+ #else
+ if (have_ids == 0)
+ {
+@@ -162,6 +158,10 @@ euidaccess (path, mode)
+ /* Now we need the IDs. */
+ euid = __geteuid ();
+ egid = __getegid ();
++
++ if (__getuid () == euid && __getgid () == egid)
++ /* If we are not set-uid or set-gid, access does the same. */
++ return __access (path, mode);
+ #endif
+
+ /* The super-user can read and write any file, and execute any file
--- /dev/null
+2007-01-11 Jakub Jelinek <jakub@redhat.com>
+
+ * stdlib/strtod_l.c (____STRTOF_INTERNAL): Fix handling of multi-byte
+ thousands separators.
+ * stdlib/Makefile: Add rules to build and run tst-strtod4.
+ * stdlib/tst-strtod4.c: New test.
+
+ [BZ #3855]
+ * stdlib/strtod_l.c (____STRTOF_INTERNAL): 0x. not followed by
+ hexadecimal digit should accept just the initial 0.
+ * stdlib/tst-strtod2.c (tests): New variable.
+ (do_test): Run several tests rather than just one.
+
+2007-01-03 Ulrich Drepper <drepper@redhat.com>
+
+ * stdlib/Makefile (tst-strtod3-ENV): Define.
+
+--- libc/stdlib/Makefile 3 Jan 2007 22:42:33 -0000 1.116
++++ libc/stdlib/Makefile 11 Jan 2007 17:37:12 -0000 1.117
+@@ -64,7 +64,7 @@ tests := tst-strtol tst-strtod testmb t
+ tst-xpg-basename tst-random tst-random2 tst-bsearch \
+ tst-limits tst-rand48 bug-strtod tst-setcontext \
+ test-a64l tst-qsort tst-system testmb2 bug-strtod2 \
+- tst-atof1 tst-atof2 tst-strtod2 tst-strtod3
++ tst-atof1 tst-atof2 tst-strtod2 tst-strtod3 tst-strtod4
+
+ include ../Makeconfig
+
+@@ -114,6 +114,8 @@ include ../Rules
+ test-canon-ARGS = --test-dir=${common-objpfx}stdlib
+
+ tst-strtod-ENV = LOCPATH=$(common-objpfx)localedata
++tst-strtod3-ENV = LOCPATH=$(common-objpfx)localedata
++tst-strtod4-ENV = LOCPATH=$(common-objpfx)localedata
+ testmb2-ENV = LOCPATH=$(common-objpfx)localedata
+
+ # Run a test on the header files we use.
+--- libc/stdlib/strtod_l.c 11 Dec 2006 21:43:48 -0000 1.19
++++ libc/stdlib/strtod_l.c 11 Jan 2007 17:35:29 -0000 1.21
+@@ -650,10 +651,11 @@ ____STRTOF_INTERNAL (nptr, endptr, group
+ if (c != '0')
+ {
+ for (cnt = 0; thousands[cnt] != '\0'; ++cnt)
+- if (c != thousands[cnt])
++ if (thousands[cnt] != cp[cnt])
+ break;
+ if (thousands[cnt] != '\0')
+ break;
++ cp += cnt - 1;
+ }
+ c = *++cp;
+ }
+@@ -665,14 +667,23 @@ ____STRTOF_INTERNAL (nptr, endptr, group
+ if (!((c >= L_('0') && c <= L_('9'))
+ || (base == 16 && ((CHAR_TYPE) TOLOWER (c) >= L_('a')
+ && (CHAR_TYPE) TOLOWER (c) <= L_('f')))
++ || (
+ #ifdef USE_WIDE_CHAR
+- || c == (wint_t) decimal
++ c == (wint_t) decimal
+ #else
+- || ({ for (cnt = 0; decimal[cnt] != '\0'; ++cnt)
+- if (decimal[cnt] != cp[cnt])
+- break;
+- decimal[cnt] == '\0'; })
+-#endif
++ ({ for (cnt = 0; decimal[cnt] != '\0'; ++cnt)
++ if (decimal[cnt] != cp[cnt])
++ break;
++ decimal[cnt] == '\0'; })
++#endif
++ /* '0x.' alone is not a valid hexadecimal number.
++ '.' alone is not valid either, but that has been checked
++ already earlier. */
++ && (base != 16
++ || cp != start_of_digits
++ || (cp[decimal_len] >= L_('0') && cp[decimal_len] <= L_('9'))
++ || ((CHAR_TYPE) TOLOWER (cp[decimal_len]) >= L_('a')
++ && (CHAR_TYPE) TOLOWER (cp[decimal_len]) <= L_('f'))))
+ || (base == 16 && (cp != start_of_digits
+ && (CHAR_TYPE) TOLOWER (c) == L_('p')))
+ || (base != 16 && (CHAR_TYPE) TOLOWER (c) == L_('e'))))
+@@ -715,6 +726,7 @@ ____STRTOF_INTERNAL (nptr, endptr, group
+ break;
+ if (thousands[cnt] != '\0')
+ break;
++ cp += cnt - 1;
+ }
+ #endif
+ }
+--- libc/stdlib/tst-strtod2.c 11 Dec 2006 21:36:30 -0000 1.2
++++ libc/stdlib/tst-strtod2.c 11 Jan 2007 17:27:16 -0000 1.3
+@@ -1,22 +1,41 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+
++struct test
++{
++ const char *str;
++ double result;
++ size_t offset;
++} tests[] =
++{
++ { "0xy", 0.0, 1 },
++ { "0x.y", 0.0, 1 },
++ { "0x0.y", 0.0, 4 },
++ { "0x.0y", 0.0, 4 },
++ { ".y", 0.0, 0 },
++ { "0.y", 0.0, 2 },
++ { ".0y", 0.0, 2 }
++};
++
+ static int
+ do_test (void)
+ {
+ int status = 0;
+- const char s[] = "0x";
+- char *ep;
+- double r = strtod (s, &ep);
+- if (r != 0)
+- {
+- printf ("r = %g, expect 0\n", r);
+- status = 1;
+- }
+- if (ep != s + 1)
++ for (size_t i = 0; i < sizeof (tests) / sizeof (tests[0]); ++i)
+ {
+- printf ("strtod parsed %ju characters, expected 1\n", ep - s);
+- status = 1;
++ char *ep;
++ double r = strtod (tests[i].str, &ep);
++ if (r != tests[i].result)
++ {
++ printf ("test %zu r = %g, expect %g\n", i, r, tests[i].result);
++ status = 1;
++ }
++ if (ep != tests[i].str + tests[i].offset)
++ {
++ printf ("test %zu strtod parsed %ju characters, expected %zu\n",
++ i, ep - tests[i].str, tests[i].offset);
++ status = 1;
++ }
+ }
+ return status;
+ }
+--- libc/stdlib/tst-strtod4.c 1 Jan 1970 00:00:00 -0000
++++ libc/stdlib/tst-strtod4.c 11 Jan 2007 17:36:58 -0000 1.1
+@@ -0,0 +1,56 @@
++#include <locale.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++#define NBSP "\xc2\xa0"
++
++static const struct
++{
++ const char *in;
++ const char *out;
++ double expected;
++} tests[] =
++ {
++ { "000"NBSP"000"NBSP"000", "", 0.0 },
++ { "1"NBSP"000"NBSP"000,5x", "x", 1000000.5 }
++ };
++#define NTESTS (sizeof (tests) / sizeof (tests[0]))
++
++
++static int
++do_test (void)
++{
++ if (setlocale (LC_ALL, "cs_CZ.UTF-8") == NULL)
++ {
++ puts ("could not set locale");
++ return 1;
++ }
++
++ int status = 0;
++
++ for (int i = 0; i < NTESTS; ++i)
++ {
++ char *ep;
++ double r = __strtod_internal (tests[i].in, &ep, 1);
++
++ if (strcmp (ep, tests[i].out) != 0)
++ {
++ printf ("%d: got rest string \"%s\", expected \"%s\"\n",
++ i, ep, tests[i].out);
++ status = 1;
++ }
++
++ if (r != tests[i].expected)
++ {
++ printf ("%d: got wrong results %g, expected %g\n",
++ i, r, tests[i].expected);
++ status = 1;
++ }
++ }
++
++ return status;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
--- /dev/null
+2007-01-22 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #3902]
+ * stdio-common/_itoa.c (_itoa): Make sure at least a zero is emitted.
+ * stdio-common/Makefile (tests): Add bug17.
+ * stdio-common/bug17.c: New file.
+
+--- libc/stdio-common/_itoa.c 6 Jun 2004 06:02:14 -0000 1.21
++++ libc/stdio-common/_itoa.c 22 Jan 2007 16:16:08 -0000 1.22
+@@ -269,6 +269,7 @@ _itoa (value, buflim, base, upper_case)
+
+ default:
+ {
++ char *bufend = buflim;
+ #if BITS_PER_MP_LIMB == 64
+ mp_limb_t base_multiplier = brec->base_multiplier;
+ if (brec->flag)
+@@ -454,6 +455,8 @@ _itoa (value, buflim, base, upper_case)
+ }
+ while (n != 0);
+ #endif
++ if (buflim == bufend)
++ *--buflim = '0';
+ }
+ break;
+ }
+--- libc/stdio-common/Makefile 3 Aug 2006 09:25:01 -0000 1.98
++++ libc/stdio-common/Makefile 22 Jan 2007 16:17:13 -0000 1.99
+@@ -54,7 +54,7 @@ tests := tstscanf test_rdwr test-popen t
+ tst-swprintf tst-fseek tst-fmemopen test-vfprintf tst-gets \
+ tst-perror tst-sprintf tst-rndseek tst-fdopen tst-fphex bug14 bug15 \
+ tst-popen tst-unlockedio tst-fmemopen2 tst-put-error tst-fgets \
+- tst-fwrite bug16
++ tst-fwrite bug16 bug17
+
+ test-srcs = tst-unbputc tst-printf
+
+--- libc/stdio-common/bug17.c 1 Jan 1970 00:00:00 -0000
++++ libc/stdio-common/bug17.c 22 Jan 2007 16:17:04 -0000 1.1
+@@ -0,0 +1,31 @@
++#include <stdio.h>
++#include <string.h>
++
++static int
++do_test (void)
++{
++ static const char expect[] = "0, 0, 0";
++ char buf[100];
++ int status = 0;
++
++ static const char fmt1[] = "%0d, %0ld, %0lld";
++ snprintf (buf, sizeof (buf), fmt1, 0, 0L, 0LL);
++ if (strcmp (buf, expect) != 0)
++ {
++ printf ("\"%s\": got \"%s\", expected \"%s\"\n", fmt1, buf, expect);
++ status = 1;
++ }
++
++ static const char fmt2[] = "%0u, %0lu, %0llu";
++ snprintf (buf, sizeof (buf), fmt2, 0u, 0uL, 0uLL);
++ if (strcmp (buf, expect) != 0)
++ {
++ printf ("\"%s\": got \"%s\", expected \"%s\"\n", fmt2, buf, expect);
++ status = 1;
++ }
++
++ return status;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
--- /dev/null
+2005-09-23 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #394]
+ * libio/fmemopen.c (fmemopen_write): Return 0 instead of -1 if
+ nothing can be written.
+ * libio/iofopncook.c (_IO_cookie_write): If something went wrong,
+ set error bit.
+
+--- libc/libio/iofopncook.c 19 Jan 2005 19:25:42 -0000 1.23
++++ libc/libio/iofopncook.c 23 Sep 2005 16:35:17 -0000 1.24
+@@ -64,9 +64,16 @@ _IO_cookie_write (fp, buf, size)
+ struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
+
+ if (cfile->__io_functions.write == NULL)
+- return -1;
++ {
++ fp->_flags |= _IO_ERR_SEEN;
++ return 0;
++ }
++
++ _IO_ssize_t n = cfile->__io_functions.write (cfile->__cookie, buf, size);
++ if (n < size)
++ fp->_flags |= _IO_ERR_SEEN;
+
+- return cfile->__io_functions.write (cfile->__cookie, buf, size);
++ return n;
+ }
+
+ static _IO_off64_t
+--- libc/libio/fmemopen.c 2 Feb 2005 19:43:54 -0000 1.11
++++ libc/libio/fmemopen.c 23 Sep 2005 16:34:35 -0000 1.12
+@@ -127,7 +127,7 @@ fmemopen_write (void *cookie, const char
+ if ((size_t) (c->pos + addnullc) == c->size)
+ {
+ __set_errno (ENOSPC);
+- return -1;
++ return 0;
+ }
+ s = c->size - c->pos - addnullc;
+ }
--- /dev/null
+2007-02-08 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #3944]
+ * time/strptime_l.c (__strptime_internal): Set have_mon for
+ %b/%B/%h. Set have_mon and have_mday if tm_mon and tm_mday
+ have been computed from tm_yday and tm_year. Don't crash
+ in day_of_the_week or day_of_the_year if not have_mon
+ and tm_mon contains bogus value.
+ * time/Makefile (tests): Add tst-strptime3.
+ * time/tst-strptime3.c: New test.
+
+--- libc/time/strptime_l.c 27 Apr 2005 04:30:10 -0000 1.7
++++ libc/time/strptime_l.c 9 Feb 2007 01:32:17 -0000 1.8
+@@ -400,6 +400,7 @@ __strptime_internal (rp, fmt, tm, decide
+ /* Does not match a month name. */
+ return NULL;
+ tm->tm_mon = cnt;
++ have_mon = 1;
+ want_xday = 1;
+ break;
+ case 'c':
+@@ -1085,11 +1086,15 @@ __strptime_internal (rp, fmt, tm, decide
+ tm->tm_mday =
+ (tm->tm_yday
+ - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
++ have_mon = 1;
++ have_mday = 1;
+ }
+- day_of_the_week (tm);
++ /* Don't crash in day_of_the_week if tm_mon is uninitialized. */
++ if (have_mon || (unsigned) tm->tm_mon <= 11)
++ day_of_the_week (tm);
+ }
+
+- if (want_xday && !have_yday)
++ if (want_xday && !have_yday && (have_mon || (unsigned) tm->tm_mon <= 11))
+ day_of_the_year (tm);
+
+ if ((have_uweek || have_wweek) && have_wday)
+--- libc/time/Makefile 9 Sep 2006 16:54:49 -0000 1.110
++++ libc/time/Makefile 9 Feb 2007 01:33:54 -0000 1.111
+@@ -35,7 +35,8 @@ distribute := datemsk
+
+ tests := test_time clocktest tst-posixtz tst-strptime tst_wcsftime \
+ tst-getdate tst-mktime tst-mktime2 tst-ftime_l tst-strftime \
+- tst-mktime3 tst-strptime2 bug-asctime bug-asctime_r bug-mktime1
++ tst-mktime3 tst-strptime2 bug-asctime bug-asctime_r bug-mktime1 \
++ tst-strptime3
+
+ include ../Rules
+
+--- libc/time/tst-strptime3.c 1 Jan 1970 00:00:00 -0000
++++ libc/time/tst-strptime3.c 9 Feb 2007 01:33:40 -0000 1.1
+@@ -0,0 +1,55 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <time.h>
++
++
++int
++main (void)
++{
++ int result = 0;
++ struct tm tm;
++
++ memset (&tm, 0xaa, sizeof (tm));
++
++ /* Test we don't crash on uninitialized struct tm.
++ Some fields might contain bogus values until everything
++ needed is initialized, but we shouldn't crash. */
++ if (strptime ("2007", "%Y", &tm) == NULL
++ || strptime ("12", "%d", &tm) == NULL
++ || strptime ("Feb", "%b", &tm) == NULL
++ || strptime ("13", "%M", &tm) == NULL
++ || strptime ("21", "%S", &tm) == NULL
++ || strptime ("16", "%H", &tm) == NULL)
++ {
++ puts ("strptimes failed");
++ result = 1;
++ }
++
++ if (tm.tm_sec != 21 || tm.tm_min != 13 || tm.tm_hour != 16
++ || tm.tm_mday != 12 || tm.tm_mon != 1 || tm.tm_year != 107
++ || tm.tm_wday != 1 || tm.tm_yday != 42)
++ {
++ puts ("unexpected tm content");
++ result = 1;
++ }
++
++ if (strptime ("8", "%d", &tm) == NULL)
++ {
++ puts ("strptime failed");
++ result = 1;
++ }
++
++ if (tm.tm_sec != 21 || tm.tm_min != 13 || tm.tm_hour != 16
++ || tm.tm_mday != 8 || tm.tm_mon != 1 || tm.tm_year != 107
++ || tm.tm_wday != 4 || tm.tm_yday != 38)
++ {
++ puts ("unexpected tm content");
++ result = 1;
++ }
++
++ if (result == 0)
++ puts ("all OK");
++
++ return 0;
++}
--- /dev/null
+2007-02-05 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #3957]
+ * posix/regcomp.c (parse_bracket_exp): Set '\n' bit rather than '\0'
+ bit for RE_HAT_LISTS_NOT_NEWLINE.
+ (build_charclass_op): Remove bogus comment.
+ * posix/Makefile (tests): Add bug-regex27 and bug-regex28.
+ * posix/bug-regex27.c: New test.
+ * posix/bug-regex28.c: New test.
+
+--- libc/posix/regcomp.c 31 Jan 2006 19:17:14 -0000 1.112
++++ libc/posix/regcomp.c 5 Feb 2007 15:23:49 -0000 1.113
+@@ -3019,7 +3019,7 @@ parse_bracket_exp (re_string_t *regexp,
+ #endif /* not RE_ENABLE_I18N */
+ non_match = 1;
+ if (syntax & RE_HAT_LISTS_NOT_NEWLINE)
+- bitset_set (sbcset, '\0');
++ bitset_set (sbcset, '\n');
+ re_string_skip_bytes (regexp, token_len); /* Skip a token. */
+ token_len = peek_token_bracket (token, regexp, syntax);
+ if (BE (token->type == END_OF_RE, 0))
+@@ -3549,10 +3549,6 @@ build_charclass_op (re_dfa_t *dfa, RE_TR
+ if (non_match)
+ {
+ #ifdef RE_ENABLE_I18N
+- /*
+- if (syntax & RE_HAT_LISTS_NOT_NEWLINE)
+- bitset_set(cset->sbcset, '\0');
+- */
+ mbcset->non_match = 1;
+ #endif /* not RE_ENABLE_I18N */
+ }
+--- libc/posix/Makefile 3 Jan 2007 23:02:10 -0000 1.194
++++ libc/posix/Makefile 5 Feb 2007 15:22:40 -0000 1.195
+@@ -81,7 +81,8 @@ tests := tstgetopt testfnm runtests run
+ bug-regex13 bug-regex14 bug-regex15 bug-regex16 \
+ bug-regex17 bug-regex18 bug-regex19 bug-regex20 \
+ bug-regex21 bug-regex22 bug-regex23 bug-regex24 \
+- bug-regex25 bug-regex26 tst-nice tst-nanosleep tst-regex2 \
++ bug-regex25 bug-regex26 bug-regex27 bug-regex28 \
++ tst-nice tst-nanosleep tst-regex2 \
+ transbug tst-rxspencer tst-pcre tst-boost \
+ bug-ga1 tst-vfork1 tst-vfork2 tst-vfork3 tst-waitid \
+ tst-getaddrinfo2 bug-glob1 bug-glob2 tst-sysconf \
+--- libc/posix/bug-regex27.c 1 Jan 1970 00:00:00 -0000
++++ libc/posix/bug-regex27.c 5 Feb 2007 15:22:27 -0000 1.1
+@@ -0,0 +1,64 @@
++/* Test REG_NEWLINE.
++ Copyright (C) 2007 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Jakub Jelinek <jakub@redhat.com>, 2007.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <regex.h>
++#include <stdio.h>
++#include <string.h>
++
++struct tests
++{
++ const char *regex;
++ const char *string;
++ int cflags;
++ int retval;
++} tests[] = {
++ { "a.b", "a\nb", REG_EXTENDED | REG_NEWLINE, REG_NOMATCH },
++ { "a.b", "a\nb", REG_EXTENDED, 0 },
++ { "a[^x]b", "a\nb", REG_EXTENDED | REG_NEWLINE, REG_NOMATCH },
++ { "a[^x]b", "a\nb", REG_EXTENDED, 0 }
++};
++
++int
++main (void)
++{
++ regex_t r;
++ size_t i;
++ int ret = 0;
++
++ for (i = 0; i < sizeof (tests) / sizeof (tests[i]); ++i)
++ {
++ memset (&r, 0, sizeof (r));
++ if (regcomp (&r, tests[i].regex, tests[i].cflags))
++ {
++ printf ("regcomp %zd failed\n", i);
++ ret = 1;
++ continue;
++ }
++ int rv = regexec (&r, tests[i].string, 0, NULL, 0);
++ if (rv != tests[i].retval)
++ {
++ printf ("regexec %zd unexpected value %d != %d\n",
++ i, rv, tests[i].retval);
++ ret = 1;
++ }
++ regfree (&r);
++ }
++ return ret;
++}
+--- libc/posix/bug-regex28.c 1 Jan 1970 00:00:00 -0000
++++ libc/posix/bug-regex28.c 5 Feb 2007 15:22:27 -0000 1.1
+@@ -0,0 +1,75 @@
++/* Test RE_HAT_LISTS_NOT_NEWLINE and RE_DOT_NEWLINE.
++ Copyright (C) 2007 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Jakub Jelinek <jakub@redhat.com>, 2007.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <regex.h>
++#include <stdio.h>
++#include <string.h>
++
++struct tests
++{
++ const char *regex;
++ const char *string;
++ reg_syntax_t syntax;
++ int retval;
++} tests[] = {
++#define EGREP RE_SYNTAX_EGREP
++#define EGREP_NL (RE_SYNTAX_EGREP | RE_DOT_NEWLINE) & ~RE_HAT_LISTS_NOT_NEWLINE
++ { "a.b", "a\nb", EGREP, -1 },
++ { "a.b", "a\nb", EGREP_NL, 0 },
++ { "a[^x]b", "a\nb", EGREP, -1 },
++ { "a[^x]b", "a\nb", EGREP_NL, 0 },
++ /* While \S and \W are internally handled as [^[:space:]] and [^[:alnum:]_],
++ RE_HAT_LISTS_NOT_NEWLINE did not make any difference, so ensure
++ it doesn't change. */
++ { "a\\Sb", "a\nb", EGREP, -1 },
++ { "a\\Sb", "a\nb", EGREP_NL, -1 },
++ { "a\\Wb", "a\nb", EGREP, 0 },
++ { "a\\Wb", "a\nb", EGREP_NL, 0 }
++};
++
++int
++main (void)
++{
++ struct re_pattern_buffer r;
++ size_t i;
++ int ret = 0;
++
++ for (i = 0; i < sizeof (tests) / sizeof (tests[i]); ++i)
++ {
++ re_set_syntax (tests[i].syntax);
++ memset (&r, 0, sizeof (r));
++ if (re_compile_pattern (tests[i].regex, strlen (tests[i].regex), &r))
++ {
++ printf ("re_compile_pattern %zd failed\n", i);
++ ret = 1;
++ continue;
++ }
++ size_t len = strlen (tests[i].string);
++ int rv = re_search (&r, tests[i].string, len, 0, len, NULL);
++ if (rv != tests[i].retval)
++ {
++ printf ("re_search %zd unexpected value %d != %d\n",
++ i, rv, tests[i].retval);
++ ret = 1;
++ }
++ regfree (&r);
++ }
++ return ret;
++}
--- /dev/null
+2007-04-13 Jakub Jelinek <jakub@redhat.com>
+
+ * stdio-common/printf_fp.c (___printf_fp): Fix exponent -4
+ special case handling when wcp == wstartp + 1. Fix a comment typo.
+ * stdio-common/tfformat.c (sprint_doubles): Add a new testcase.
+
+2007-02-21 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #4070]
+ * stdio-common/printf_fp.c (___printf_fp): Handle a few more
+ special cases.
+ * stdio-common/tfformat.c (sprint_doubles): Some more tests.
+
+2007-02-19 Ulrich Drepper <drepper@redhat.com>
+
+ * stdio-common/printf_fp.c (___printf_fp): Cleanups and minor
+ optimization.
+
+--- libc/stdio-common/printf_fp.c 25 Apr 2006 18:38:30 -0000 1.58
++++ libc/stdio-common/printf_fp.c 16 Apr 2007 23:28:26 -0000 1.62
+@@ -811,12 +811,14 @@ ___printf_fp (FILE *fp,
+ int chars_needed;
+ int expscale;
+ int intdig_max, intdig_no = 0;
+- int fracdig_min, fracdig_max, fracdig_no = 0;
++ int fracdig_min;
++ int fracdig_max;
+ int dig_max;
+ int significant;
+ int ngroups = 0;
++ char spec = _tolower (info->spec);
+
+- if (_tolower (info->spec) == 'e')
++ if (spec == 'e')
+ {
+ type = info->spec;
+ intdig_max = 1;
+@@ -826,7 +828,7 @@ ___printf_fp (FILE *fp,
+ dig_max = INT_MAX; /* Unlimited. */
+ significant = 1; /* Does not matter here. */
+ }
+- else if (_tolower (info->spec) == 'f')
++ else if (spec == 'f')
+ {
+ type = 'f';
+ fracdig_min = fracdig_max = info->prec < 0 ? 6 : info->prec;
+@@ -923,7 +925,9 @@ ___printf_fp (FILE *fp,
+ }
+
+ /* Generate the needed number of fractional digits. */
+- while (fracdig_no < fracdig_min
++ int fracdig_no = 0;
++ int added_zeros = 0;
++ while (fracdig_no < fracdig_min + added_zeros
+ || (fracdig_no < fracdig_max && (fracsize > 1 || frac[0] != 0)))
+ {
+ ++fracdig_no;
+@@ -934,7 +938,7 @@ ___printf_fp (FILE *fp,
+ {
+ ++fracdig_max;
+ if (fracdig_min > 0)
+- ++fracdig_min;
++ ++added_zeros;
+ }
+ }
+
+@@ -971,11 +975,23 @@ ___printf_fp (FILE *fp,
+ {
+ /* Process fractional digits. Terminate if not rounded or
+ radix character is reached. */
++ int removed = 0;
+ while (*--wtp != decimalwc && *wtp == L'9')
+- *wtp = '0';
++ {
++ *wtp = L'0';
++ ++removed;
++ }
++ if (removed == fracdig_min && added_zeros > 0)
++ --added_zeros;
+ if (*wtp != decimalwc)
+ /* Round up. */
+ (*wtp)++;
++ else if (__builtin_expect (spec == 'g' && type == 'f' && info->alt,
++ 0))
++ /* This is a special case: the rounded number is 1.0,
++ the format is 'g' or 'G', and the alternative format
++ is selected. This means the result must be "1.". */
++ --added_zeros;
+ }
+
+ if (fracdig_no == 0 || *wtp == decimalwc)
+@@ -1042,7 +1058,7 @@ ___printf_fp (FILE *fp,
+
+ do_expo:
+ /* Now remove unnecessary '0' at the end of the string. */
+- while (fracdig_no > fracdig_min && *(wcp - 1) == L'0')
++ while (fracdig_no > fracdig_min + added_zeros && *(wcp - 1) == L'0')
+ {
+ --wcp;
+ --fracdig_no;
+@@ -1060,26 +1076,46 @@ ___printf_fp (FILE *fp,
+ /* Write the exponent if it is needed. */
+ if (type != 'f')
+ {
+- *wcp++ = (wchar_t) type;
+- *wcp++ = expsign ? L'-' : L'+';
+-
+- /* Find the magnitude of the exponent. */
+- expscale = 10;
+- while (expscale <= exponent)
+- expscale *= 10;
+-
+- if (exponent < 10)
+- /* Exponent always has at least two digits. */
+- *wcp++ = L'0';
++ if (__builtin_expect (expsign != 0 && exponent == 4 && spec == 'g', 0))
++ {
++ /* This is another special case. The exponent of the number is
++ really smaller than -4, which requires the 'e'/'E' format.
++ But after rounding the number has an exponent of -4. */
++ assert (wcp >= wstartp + 1);
++ assert (wstartp[0] == L'1');
++ __wmemcpy (wstartp, L"0.0001", 6);
++ wstartp[1] = decimalwc;
++ if (wcp >= wstartp + 2)
++ {
++ wmemset (wstartp + 6, L'0', wcp - (wstartp + 2));
++ wcp += 4;
++ }
++ else
++ wcp += 5;
++ }
+ else
+- do
+- {
+- expscale /= 10;
+- *wcp++ = L'0' + (exponent / expscale);
+- exponent %= expscale;
+- }
+- while (expscale > 10);
+- *wcp++ = L'0' + exponent;
++ {
++ *wcp++ = (wchar_t) type;
++ *wcp++ = expsign ? L'-' : L'+';
++
++ /* Find the magnitude of the exponent. */
++ expscale = 10;
++ while (expscale <= exponent)
++ expscale *= 10;
++
++ if (exponent < 10)
++ /* Exponent always has at least two digits. */
++ *wcp++ = L'0';
++ else
++ do
++ {
++ expscale /= 10;
++ *wcp++ = L'0' + (exponent / expscale);
++ exponent %= expscale;
++ }
++ while (expscale > 10);
++ *wcp++ = L'0' + exponent;
++ }
+ }
+
+ /* Compute number of characters which must be filled with the padding
+--- libc/stdio-common/tfformat.c 11 Mar 2002 21:46:37 -0000 1.7
++++ libc/stdio-common/tfformat.c 16 Apr 2007 23:28:37 -0000 1.9
+@@ -4012,6 +4012,15 @@ sprint_double_type sprint_doubles[] =
+ {__LINE__, 16, "0x1.0p+4", "%.1a"},
+ {__LINE__, 16, "0x1.00000000000000000000p+4", "%.20a"},
+ {__LINE__, 4444.88888888, "4445", "%2.F"},
++ {__LINE__, 0.956, "1", "%.0g"},
++ {__LINE__, 1.0956, "1.", "%#.0g"},
++ {__LINE__, 0.956, "1.", "%#.0g"},
++ {__LINE__, 0.0956, "0.1", "%#.0g"},
++ {__LINE__, 0.00956, "0.01", "%#.0g"},
++ {__LINE__, 0.000956, "0.001", "%#.0g"},
++ {__LINE__, 0.000098, "0.0001", "%#.0g"},
++ {__LINE__, 0.0000996, "0.00010", "%#.2g"},
++ {__LINE__, 9.999999999999999e-05, "0.0001", "%g"},
+
+ {0 }
+
+@@ -4023,13 +4032,8 @@ sprint_double_type sprint_doubles[] =
+
+ int required_precision = 13;
+
+-#if defined(__STDC__) || defined(__cplusplus)
+ static int
+ matches (register char *result, register const char *desired)
+-#else
+-int matches(result, desired)
+- register char *result; register const char *desired;
+-#endif
+ {
+ int digits_seen = 0;
+ for (;; result++, desired++) {
+@@ -4080,7 +4084,7 @@ int main(int argc, char *argv[])
+
+ /* And one special test. */
+ {
+- const char ref[] = "1.7763568394002504646778106689453125e-15";
++ static const char ref[] = "1.7763568394002504646778106689453125e-15";
+ int i;
+ d = 1.0;
+ for (i = 1; i < 50; ++i)
--- /dev/null
+2007-02-21 Ulrich Drepper <drepper@redhat.com>
+
+ * nscd/grpcache.c (cache_addgr): In case a record changed on
+ refresh, adjust key_copy.
+
+ [BZ #4074]
+ * nscd/pwdcache.c (cache_addpw): In case a record changed on
+ refresh, adjust key_copy.
+
+--- libc/nscd/grpcache.c 14 Jan 2007 05:09:52 -0000 1.47
++++ libc/nscd/grpcache.c 21 Feb 2007 09:07:54 -0000 1.48
+@@ -279,6 +279,7 @@ cache_addgr (struct database_dyn *db, in
+ /* Adjust pointers into the memory block. */
+ gr_name = (char *) newp + (gr_name - (char *) dataset);
+ cp = (char *) newp + (cp - (char *) dataset);
++ key_copy = (char *) newp + (key_copy - (char *) dataset);
+
+ dataset = memcpy (newp, dataset, total + n);
+ alloca_used = false;
+--- libc/nscd/pwdcache.c 14 Jan 2007 05:09:52 -0000 1.45
++++ libc/nscd/pwdcache.c 21 Feb 2007 09:05:19 -0000 1.46
+@@ -274,6 +274,7 @@ cache_addpw (struct database_dyn *db, in
+ {
+ /* Adjust pointer into the memory block. */
+ cp = (char *) newp + (cp - (char *) dataset);
++ key_copy = (char *) newp + (key_copy - (char *) dataset);
+
+ dataset = memcpy (newp, dataset, total + n);
+ alloca_used = false;
--- /dev/null
+2007-03-15 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #4101]
+ * argp/argp-help.c (hol_cluster_cmp): Fix comparisons used to find
+ ancestors with the same depths.
+ Patch by Niels Moeller <nisse@lysator.liu.se>.
+ (filter_doc): Don't crash if argp is NULL.
+ * argp/Makefile (tests): Add tst-argp2.
+ * argp/tst-argp2.c: New test.
+
+--- libc/argp/Makefile 9 May 2006 22:42:24 -0000 1.7
++++ libc/argp/Makefile 15 Mar 2007 20:08:57 -0000 1.8
+@@ -26,7 +26,7 @@ distribute = argp-fmtstream.h argp-namef
+ routines = $(addprefix argp-, ba fmtstream fs-xinl help parse pv \
+ pvh xinl eexst)
+
+-tests = argp-test tst-argp1 bug-argp1
++tests = argp-test tst-argp1 bug-argp1 tst-argp2
+
+ CFLAGS-argp-help.c = $(uses-callbacks) -fexceptions
+ CFLAGS-argp-parse.c = $(uses-callbacks)
+--- libc/argp/argp-help.c 10 May 2006 06:28:06 -0000 1.54
++++ libc/argp/argp-help.c 15 Mar 2007 20:08:18 -0000 1.55
+@@ -672,9 +673,9 @@ hol_cluster_cmp (const struct hol_cluste
+ {
+ /* If one cluster is deeper than the other, use its ancestor at the same
+ level, so that finding the common ancestor is straightforward. */
+- while (cl1->depth < cl2->depth)
++ while (cl1->depth > cl2->depth)
+ cl1 = cl1->parent;
+- while (cl2->depth < cl1->depth)
++ while (cl2->depth > cl1->depth)
+ cl2 = cl2->parent;
+
+ /* Now reduce both clusters to their ancestors at the point where both have
+@@ -987,7 +988,7 @@ static const char *
+ filter_doc (const char *doc, int key, const struct argp *argp,
+ const struct argp_state *state)
+ {
+- if (argp->help_filter)
++ if (argp && argp->help_filter)
+ /* We must apply a user filter to this output. */
+ {
+ void *input = __argp_input (argp, state);
+--- libc/argp/tst-argp2.c 1 Jan 1970 00:00:00 -0000
++++ libc/argp/tst-argp2.c 15 Mar 2007 20:08:46 -0000 1.1
+@@ -0,0 +1,101 @@
++/* Copyright (C) 2007 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Jakub Jelinek <jakub@redhat.com>, 2007.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <argp.h>
++
++static const struct argp_option opt1[] =
++ {
++ { "opt1", '1', "NUMBER", 0, "Option 1" },
++ { NULL, 0, NULL, 0, NULL }
++ };
++
++static const struct argp_option opt2[] =
++ {
++ { "opt2", '2', "NUMBER", 0, "Option 2" },
++ { NULL, 0, NULL, 0, NULL }
++ };
++
++static const struct argp_option opt3[] =
++ {
++ { "opt3", '3', "NUMBER", 0, "Option 3" },
++ { NULL, 0, NULL, 0, NULL }
++ };
++
++static const struct argp_option opt4[] =
++ {
++ { "opt4", '4', "NUMBER", 0, "Option 4" },
++ { NULL, 0, NULL, 0, NULL }
++ };
++
++static const struct argp_option opt5[] =
++ {
++ { "opt5", '5', "NUMBER", 0, "Option 5" },
++ { NULL, 0, NULL, 0, NULL }
++ };
++
++static struct argp argp5 =
++ {
++ opt5, NULL, "args doc5", "doc5", NULL, NULL, NULL
++ };
++
++static struct argp argp4 =
++ {
++ opt4, NULL, "args doc4", "doc4", NULL, NULL, NULL
++ };
++
++static struct argp argp3 =
++ {
++ opt3, NULL, "args doc3", "doc3", NULL, NULL, NULL
++ };
++
++static struct argp_child children2[] =
++ {
++ { &argp4, 0, "child3", 3 },
++ { &argp5, 0, "child4", 4 },
++ { NULL, 0, NULL, 0 }
++ };
++
++static struct argp argp2 =
++ {
++ opt2, NULL, "args doc2", "doc2", children2, NULL, NULL
++ };
++
++static struct argp_child children1[] =
++ {
++ { &argp2, 0, "child1", 1 },
++ { &argp3, 0, "child2", 2 },
++ { NULL, 0, NULL, 0 }
++ };
++
++static struct argp argp1 =
++ {
++ opt1, NULL, "args doc1", "doc1", children1, NULL, NULL
++ };
++
++
++static int
++do_test (void)
++{
++ argp_help (&argp1, stdout, ARGP_HELP_LONG, (char *) "tst-argp2");
++ return 0;
++}
++
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
--- /dev/null
+2007-03-15 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #4130]
+ * sysdeps/generic/utmp_file.c (setutent_file): Use O_LARGEFILE for
+ open_not_cancel_2.
+ (updwtmp_file): Likewise.
+
+--- libc/sysdeps/generic/utmp_file.c 14 Dec 2005 11:33:40 -0000 1.17
++++ libc/sysdeps/generic/utmp_file.c 15 Mar 2007 20:06:17 -0000 1.18
+@@ -140,11 +140,11 @@ setutent_file (void)
+
+ file_name = TRANSFORM_UTMP_FILE_NAME (__libc_utmp_file_name);
+
+- file_fd = open_not_cancel_2 (file_name, O_RDWR);
++ file_fd = open_not_cancel_2 (file_name, O_RDWR | O_LARGEFILE);
+ if (file_fd == -1)
+ {
+ /* Hhm, read-write access did not work. Try read-only. */
+- file_fd = open_not_cancel_2 (file_name, O_RDONLY);
++ file_fd = open_not_cancel_2 (file_name, O_RDONLY | O_LARGEFILE);
+ if (file_fd == -1)
+ return 0;
+ }
+@@ -459,7 +459,7 @@ updwtmp_file (const char *file, const st
+ int fd;
+
+ /* Open WTMP file. */
+- fd = open_not_cancel_2 (file, O_WRONLY);
++ fd = open_not_cancel_2 (file, O_WRONLY | O_LARGEFILE);
+ if (fd < 0)
+ return -1;
+
--- /dev/null
+2007-04-13 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #4344]
+ * elf/ldconfig.c (search_dir): Fix 2 off-by-2 errors.
+ Reported by David Anderson <davea42@earthlink.net>.
+
+--- libc/elf/ldconfig.c 3 Jan 2007 05:44:11 -0000 1.58
++++ libc/elf/ldconfig.c 13 Apr 2007 19:53:20 -0000 1.59
+@@ -707,10 +707,10 @@ search_dir (const struct dir_entry *entr
+ + 1, ".#prelink#.", sizeof (".#prelink#.") - 1) == 0)
+ continue;
+ }
+- len += strlen (entry->path);
++ len += strlen (entry->path) + 2;
+ if (len > file_name_len)
+ {
+- file_name_len = len + 1;
++ file_name_len = len;
+ file_name = alloca (file_name_len);
+ if (!opt_chroot)
+ real_file_name = file_name;
+@@ -718,10 +718,10 @@ search_dir (const struct dir_entry *entr
+ sprintf (file_name, "%s/%s", entry->path, direntry->d_name);
+ if (opt_chroot)
+ {
+- len = strlen (dir_name) + strlen (direntry->d_name);
++ len = strlen (dir_name) + strlen (direntry->d_name) + 2;
+ if (len > real_file_name_len)
+ {
+- real_file_name_len = len + 1;
++ real_file_name_len = len;
+ real_file_name = alloca (real_file_name_len);
+ }
+ sprintf (real_file_name, "%s/%s", dir_name, direntry->d_name);
--- /dev/null
+2007-05-21 Jakub Jelinek <jakub@redhat.com>
+
+ * malloc/hooks.c (public_sET_STATe): Put all chunks into
+ unsorted chunks and clear {fd,bk}_nextsize fields of largebin
+ chunks.
+
+2007-04-30 Ulrich Drepper <drepper@redhat.com>
+ Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #4349]
+ * malloc/malloc.c: Keep separate list for first blocks on the bin
+ lists with a given size. This helps skipping over list elements
+ we know won't fit in two places.
+ Inspired by a patch by Tomash Brechko <tomash.brechko@gmail.com>.
+
+--- libc/malloc/malloc.c 2008-05-09 03:52:41.000000000 -0400
++++ libc/malloc/malloc.c 2008-06-24 14:48:40.000000000 -0400
+@@ -1781,6 +1781,10 @@
+
+ struct malloc_chunk* fd; /* double links -- used only if free. */
+ struct malloc_chunk* bk;
++
++ /* Only used for large blocks: pointer to next larger size. */
++ struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
++ struct malloc_chunk* bk_nextsize;
+ };
+
+
+@@ -1881,7 +1885,7 @@
+ #define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
+
+ /* The smallest possible chunk */
+-#define MIN_CHUNK_SIZE (sizeof(struct malloc_chunk))
++#define MIN_CHUNK_SIZE (offsetof(struct malloc_chunk, fd_nextsize))
+
+ /* The smallest size we can malloc is an aligned minimal chunk */
+
+@@ -2081,6 +2085,24 @@
+ else { \
+ FD->bk = BK; \
+ BK->fd = FD; \
++ if (!in_smallbin_range (P->size) \
++ && __builtin_expect (P->fd_nextsize != NULL, 0)) { \
++ assert (P->fd_nextsize->bk_nextsize == P); \
++ assert (P->bk_nextsize->fd_nextsize == P); \
++ if (FD->fd_nextsize == NULL) { \
++ if (P->fd_nextsize == P) \
++ FD->fd_nextsize = FD->bk_nextsize = FD; \
++ else { \
++ FD->fd_nextsize = P->fd_nextsize; \
++ FD->bk_nextsize = P->bk_nextsize; \
++ P->fd_nextsize->bk_nextsize = FD; \
++ P->bk_nextsize->fd_nextsize = FD; \
++ } \
++ } else { \
++ P->fd_nextsize->bk_nextsize = P->bk_nextsize; \
++ P->bk_nextsize->fd_nextsize = P->fd_nextsize; \
++ } \
++ } \
+ } \
+ }
+
+@@ -2786,7 +2808,31 @@
+ /* lists are sorted */
+ assert(p->bk == b ||
+ (unsigned long)chunksize(p->bk) >= (unsigned long)chunksize(p));
+- }
++
++ if (!in_smallbin_range(size))
++ {
++ if (p->fd_nextsize != NULL)
++ {
++ if (p->fd_nextsize == p)
++ assert (p->bk_nextsize == p);
++ else
++ {
++ if (p->fd_nextsize == first (b))
++ assert (chunksize (p) < chunksize (p->fd_nextsize));
++ else
++ assert (chunksize (p) > chunksize (p->fd_nextsize));
++
++ if (p == first (b))
++ assert (chunksize (p) > chunksize (p->bk_nextsize));
++ else
++ assert (chunksize (p) < chunksize (p->bk_nextsize));
++ }
++ }
++ else
++ assert (p->bk_nextsize == NULL);
++ }
++ } else if (!in_smallbin_range(size))
++ assert (p->fd_nextsize == NULL && p->bk_nextsize == NULL);
+ /* chunk is followed by a legal chain of inuse chunks */
+ for (q = next_chunk(p);
+ (q != av->top && inuse(q) &&
+@@ -4135,6 +4181,11 @@
+ unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder;
+ av->last_remainder = remainder;
+ remainder->bk = remainder->fd = unsorted_chunks(av);
++ if (!in_smallbin_range(remainder_size))
++ {
++ remainder->fd_nextsize = NULL;
++ remainder->bk_nextsize = NULL;
++ }
+
+ set_head(victim, nb | PREV_INUSE |
+ (av != &main_arena ? NON_MAIN_ARENA : 0));
+@@ -4183,19 +4234,36 @@
+ size |= PREV_INUSE;
+ /* if smaller than smallest, bypass loop below */
+ assert((bck->bk->size & NON_MAIN_ARENA) == 0);
+- if ((unsigned long)(size) <= (unsigned long)(bck->bk->size)) {
++ if ((unsigned long)(size) < (unsigned long)(bck->bk->size)) {
+ fwd = bck;
+ bck = bck->bk;
++
++ victim->fd_nextsize = fwd->fd;
++ victim->bk_nextsize = fwd->fd->bk_nextsize;
++ fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim;
+ }
+ else {
+ assert((fwd->size & NON_MAIN_ARENA) == 0);
+- while ((unsigned long)(size) < (unsigned long)(fwd->size)) {
+- fwd = fwd->fd;
+- assert((fwd->size & NON_MAIN_ARENA) == 0);
+- }
+- bck = fwd->bk;
++ while ((unsigned long) size < fwd->size)
++ {
++ fwd = fwd->fd_nextsize;
++ assert((fwd->size & NON_MAIN_ARENA) == 0);
++ }
++
++ if ((unsigned long) size == (unsigned long) fwd->size)
++ /* Always insert in the second position. */
++ fwd = fwd->fd;
++ else
++ {
++ victim->fd_nextsize = fwd;
++ victim->bk_nextsize = fwd->bk_nextsize;
++ fwd->bk_nextsize = victim;
++ victim->bk_nextsize->fd_nextsize = victim;
++ }
++ bck = fwd->bk;
+ }
+- }
++ } else
++ victim->fd_nextsize = victim->bk_nextsize = victim;
+ }
+
+ mark_bin(av, victim_index);
+@@ -4213,21 +4281,25 @@
+
+ /*
+ If a large request, scan through the chunks of current bin in
+- sorted order to find smallest that fits. This is the only step
+- where an unbounded number of chunks might be scanned without doing
+- anything useful with them. However the lists tend to be short.
++ sorted order to find smallest that fits. Use the skip list for this.
+ */
+
+ if (!in_smallbin_range(nb)) {
+ bin = bin_at(av, idx);
+
+ /* skip scan if empty or largest chunk is too small */
+- if ((victim = last(bin)) != bin &&
+- (unsigned long)(first(bin)->size) >= (unsigned long)(nb)) {
++ if ((victim = first(bin)) != bin &&
++ (unsigned long)(victim->size) >= (unsigned long)(nb)) {
+
++ victim = victim->bk_nextsize;
+ while (((unsigned long)(size = chunksize(victim)) <
+ (unsigned long)(nb)))
+- victim = victim->bk;
++ victim = victim->bk_nextsize;
++
++ /* Avoid removing the first entry for a size so that the skip
++ list does not have to be rerouted. */
++ if (victim != last(bin) && victim->size == victim->fd->size)
++ victim = victim->fd;
+
+ remainder_size = size - nb;
+ unlink(victim, bck, fwd);
+@@ -4249,6 +4321,11 @@
+ remainder->fd = fwd;
+ bck->fd = remainder;
+ fwd->bk = remainder;
++ if (!in_smallbin_range(remainder_size))
++ {
++ remainder->fd_nextsize = NULL;
++ remainder->bk_nextsize = NULL;
++ }
+ set_head(victim, nb | PREV_INUSE |
+ (av != &main_arena ? NON_MAIN_ARENA : 0));
+ set_head(remainder, remainder_size | PREV_INUSE);
+@@ -4318,9 +4395,7 @@
+ remainder_size = size - nb;
+
+ /* unlink */
+- bck = victim->bk;
+- bin->bk = bck;
+- bck->fd = bin;
++ unlink(victim, bck, fwd);
+
+ /* Exhaust */
+ if (remainder_size < MINSIZE) {
+@@ -4345,7 +4420,11 @@
+ /* advertise as last remainder */
+ if (in_smallbin_range(nb))
+ av->last_remainder = remainder;
+-
++ if (!in_smallbin_range(remainder_size))
++ {
++ remainder->fd_nextsize = NULL;
++ remainder->bk_nextsize = NULL;
++ }
+ set_head(victim, nb | PREV_INUSE |
+ (av != &main_arena ? NON_MAIN_ARENA : 0));
+ set_head(remainder, remainder_size | PREV_INUSE);
+@@ -4568,8 +4647,13 @@
+
+ bck = unsorted_chunks(av);
+ fwd = bck->fd;
+- p->bk = bck;
+ p->fd = fwd;
++ p->bk = bck;
++ if (!in_smallbin_range(size))
++ {
++ p->fd_nextsize = NULL;
++ p->bk_nextsize = NULL;
++ }
+ bck->fd = p;
+ fwd->bk = p;
+
+@@ -4729,6 +4813,11 @@
+ unsorted_bin->fd = p;
+ first_unsorted->bk = p;
+
++ if (!in_smallbin_range (size)) {
++ p->fd_nextsize = NULL;
++ p->bk_nextsize = NULL;
++ }
++
+ set_head(p, size | PREV_INUSE);
+ p->bk = unsorted_bin;
+ p->fd = first_unsorted;
+--- libc/malloc/hooks.c.jj 2005-11-21 10:43:04.000000000 -0500
++++ libc/malloc/hooks.c 2008-05-09 03:54:00.000000000 -0400
+@@ -595,8 +595,9 @@ public_sET_STATe(Void_t* msptr)
+ assert(ms->av[2*i+3] == 0);
+ first(b) = last(b) = b;
+ } else {
+- if(i<NSMALLBINS || (largebin_index(chunksize(ms->av[2*i+2]))==i &&
+- largebin_index(chunksize(ms->av[2*i+3]))==i)) {
++ if(0 &&
++ (i<NSMALLBINS || (largebin_index(chunksize(ms->av[2*i+2]))==i &&
++ largebin_index(chunksize(ms->av[2*i+3]))==i))) {
+ first(b) = ms->av[2*i+2];
+ last(b) = ms->av[2*i+3];
+ /* Make sure the links to the bins within the heap are correct. */
+@@ -616,6 +617,17 @@ public_sET_STATe(Void_t* msptr)
+ }
+ }
+ }
++ if (1) {
++ /* Clear fd_nextsize and bk_nextsize fields. */
++ b = unsorted_chunks(&main_arena)->fd;
++ while (b != unsorted_chunks(&main_arena)) {
++ if (!in_smallbin_range(chunksize(b))) {
++ b->fd_nextsize = NULL;
++ b->bk_nextsize = NULL;
++ }
++ b = b->fd;
++ }
++ }
+ mp_.sbrk_base = ms->sbrk_base;
+ main_arena.system_mem = ms->sbrked_mem_bytes;
+ mp_.trim_threshold = ms->trim_threshold;
--- /dev/null
+2007-04-16 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #4364]
+ * posix/unistd.h (_XOPEN_VERSION): Define appropriately for SUSv3.
+
+--- libc/posix/unistd.h 9 Nov 2006 21:51:58 -0000 1.148
++++ libc/posix/unistd.h 16 Apr 2007 23:44:06 -0000 1.149
+@@ -56,7 +56,9 @@ __BEGIN_DECLS
+ #define _POSIX2_LOCALEDEF 200112L
+
+ /* X/Open version number to which the library conforms. It is selectable. */
+-#ifdef __USE_UNIX98
++#ifdef __USE_XOPEN2K
++# define _XOPEN_VERSION 600
++#elif defined __USE_UNIX98
+ # define _XOPEN_VERSION 500
+ #else
+ # define _XOPEN_VERSION 4
--- /dev/null
+2007-04-23 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #4405]
+ * iconvdata/gconv-modules (E13B): Add a missing slash to the alias
+ name. Patch by Aurelien Jarno <aurelien@aurel32.net>.
+
+--- libc/iconvdata/gconv-modules 20 Jan 2007 00:22:40 -0000 1.90
++++ libc/iconvdata/gconv-modules 23 Apr 2007 09:22:10 -0000 1.91
+@@ -1376,7 +1376,7 @@ module INTERNAL INIS-CYRILLIC// INIS-C
+ # from to module cost
+ alias ISO-IR-98// ISO_2033//
+ alias ISO_2033-1983// ISO_2033//
+-alias E13B/ ISO_2033//
++alias E13B// ISO_2033//
+ alias CSISO2033// ISO_2033//
+ module ISO_2033// INTERNAL ISO_2033 1
+ module INTERNAL ISO_2033// ISO_2033 1
--- /dev/null
+2007-05-04 Ulrich Drepper <drepper@redhat.com>
+
+ * stdio-common/vfprintf.c (process_string_arg): Adjust call to
+ __mbsnrtowcs after last change.
+
+2007-05-02 Jakub Jelinek <jakub@redhat.com>
+
+ * stdio-common/vfprintf.c (process_string_arg): Use a VLA rather than
+ fixed length array for ignore.
+
+2007-04-30 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #4438]
+ * stdio-common/vfprintf.c (process_string_arg): Don't overflow the
+ stack for large precisions.
+ * stdio-common/test-vfprintf.c (main): Add test for large
+ precision.
+
+--- libc/stdio-common/vfprintf.c 17 Mar 2007 17:08:56 -0000 1.135
++++ libc/stdio-common/vfprintf.c 5 May 2007 04:41:35 -0000 1.138
+@@ -1160,19 +1160,26 @@ vfprintf (FILE *s, const CHAR_T *format,
+ else \
+ { \
+ /* In case we have a multibyte character set the \
+- situation is more compilcated. We must not copy \
++ situation is more complicated. We must not copy \
+ bytes at the end which form an incomplete character. */\
+- wchar_t ignore[prec]; \
++ size_t ignore_size = (unsigned) prec > 1024 ? 1024 : prec;\
++ wchar_t ignore[ignore_size]; \
+ const char *str2 = string; \
+- mbstate_t ps; \
++ const char *strend = string + prec; \
++ if (strend < string) \
++ strend = (const char *) UINTPTR_MAX; \
+ \
++ mbstate_t ps; \
+ memset (&ps, '\0', sizeof (ps)); \
+- if (__mbsnrtowcs (ignore, &str2, prec, prec, &ps) \
+- == (size_t) -1) \
+- { \
+- done = -1; \
+- goto all_done; \
+- } \
++ \
++ while (str2 != NULL && str2 < strend) \
++ if (__mbsnrtowcs (ignore, &str2, strend - str2, \
++ ignore_size, &ps) == (size_t) -1) \
++ { \
++ done = -1; \
++ goto all_done; \
++ } \
++ \
+ if (str2 == NULL) \
+ len = strlen (string); \
+ else \
+--- libc/stdio-common/test-vfprintf.c 19 Aug 2003 20:23:55 -0000 1.4
++++ libc/stdio-common/test-vfprintf.c 1 May 2007 18:35:32 -0000 1.5
+@@ -94,6 +94,7 @@ main (void)
+ fprintf (fp, "%.*s", 30000, large);
+ large[20000] = '\0';
+ fprintf (fp, large);
++ fprintf (fp, "%-1.300000000s", "hello");
+
+ if (fflush (fp) != 0 || ferror (fp) != 0 || fclose (fp) != 0)
+ {
+@@ -108,11 +109,12 @@ main (void)
+ setlocale (LC_ALL, NULL));
+ exit (1);
+ }
+- else if (st.st_size != 99999)
++ else if (st.st_size != 50000 + 30000 + 19999 + 5)
+ {
+ printf ("file size incorrect for locale %s: %jd instead of %jd\n",
+ setlocale (LC_ALL, NULL),
+- (intmax_t) st.st_size, (intmax_t) 99999);
++ (intmax_t) st.st_size,
++ (intmax_t) 50000 + 30000 + 19999 + 5);
+ res = 1;
+ }
+ else
--- /dev/null
+2007-04-30 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #4439]
+ * resolv/inet_ntop.c (inet_ntop4): Take terminating '\0' into
+ account in the size check.
+ * resolv/tst-inet_ntop.c: New test.
+ * resolv/Makefile (tests): Add tst-inet_ntop.
+
+--- libc/resolv/Makefile 15 Aug 2004 20:21:59 -0000 1.48
++++ libc/resolv/Makefile 30 Apr 2007 22:30:05 -0000 1.49
+@@ -32,7 +32,7 @@ distribute := ../conf/portability.h mapv
+ routines := herror inet_addr inet_ntop inet_pton nsap_addr res_init \
+ res_hconf res_libc res-state
+
+-tests = tst-aton tst-leaks
++tests = tst-aton tst-leaks tst-inet_ntop
+ xtests = tst-leaks2
+
+ generate := mtrace-tst-leaks tst-leaks.mtrace tst-leaks2.mtrace
+--- libc/resolv/inet_ntop.c 3 Aug 2002 12:08:47 -0000 1.9
++++ libc/resolv/inet_ntop.c 30 Apr 2007 22:29:33 -0000 1.10
+@@ -96,7 +96,7 @@ inet_ntop4(src, dst, size)
+ static const char fmt[] = "%u.%u.%u.%u";
+ char tmp[sizeof "255.255.255.255"];
+
+- if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) > size) {
++ if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) >= size) {
+ __set_errno (ENOSPC);
+ return (NULL);
+ }
+--- libc/resolv/tst-inet_ntop.c 1 Jan 1970 00:00:00 -0000
++++ libc/resolv/tst-inet_ntop.c 30 Apr 2007 22:29:21 -0000 1.1
+@@ -0,0 +1,111 @@
++#include <arpa/inet.h>
++#include <errno.h>
++#include <netinet/in.h>
++#include <stdio.h>
++#include <string.h>
++
++int
++main (void)
++{
++ struct in_addr addr4;
++ struct in6_addr addr6;
++ char buf[64];
++ int result = 0;
++
++ addr4.s_addr = 0xe0e0e0e0;
++ addr6.s6_addr16[0] = 0;
++ addr6.s6_addr16[1] = 0;
++ addr6.s6_addr16[2] = 0;
++ addr6.s6_addr16[3] = 0;
++ addr6.s6_addr16[4] = 0;
++ addr6.s6_addr16[5] = 0xffff;
++ addr6.s6_addr32[3] = 0xe0e0e0e0;
++ memset (buf, 'x', sizeof buf);
++
++ if (inet_ntop (AF_INET, &addr4, buf, 15) != NULL)
++ {
++ puts ("1st inet_ntop returned non-NULL");
++ result++;
++ }
++ else if (errno != ENOSPC)
++ {
++ puts ("1st inet_ntop didn't fail with ENOSPC");
++ result++;
++ }
++ if (buf[15] != 'x')
++ {
++ puts ("1st inet_ntop wrote past the end of buffer");
++ result++;
++ }
++
++ if (inet_ntop (AF_INET, &addr4, buf, 16) != buf)
++ {
++ puts ("2nd inet_ntop did not return buf");
++ result++;
++ }
++ if (memcmp (buf, "224.224.224.224\0" "xxxxxxxx", 24) != 0)
++ {
++ puts ("2nd inet_ntop wrote past the end of buffer");
++ result++;
++ }
++
++ if (inet_ntop (AF_INET6, &addr6, buf, 22) != NULL)
++ {
++ puts ("3rd inet_ntop returned non-NULL");
++ result++;
++ }
++ else if (errno != ENOSPC)
++ {
++ puts ("3rd inet_ntop didn't fail with ENOSPC");
++ result++;
++ }
++ if (buf[22] != 'x')
++ {
++ puts ("3rd inet_ntop wrote past the end of buffer");
++ result++;
++ }
++
++ if (inet_ntop (AF_INET6, &addr6, buf, 23) != buf)
++ {
++ puts ("4th inet_ntop did not return buf");
++ result++;
++ }
++ if (memcmp (buf, "::ffff:224.224.224.224\0" "xxxxxxxx", 31) != 0)
++ {
++ puts ("4th inet_ntop wrote past the end of buffer");
++ result++;
++ }
++
++ memset (&addr6.s6_addr, 0xe0, sizeof (addr6.s6_addr));
++
++ if (inet_ntop (AF_INET6, &addr6, buf, 39) != NULL)
++ {
++ puts ("5th inet_ntop returned non-NULL");
++ result++;
++ }
++ else if (errno != ENOSPC)
++ {
++ puts ("5th inet_ntop didn't fail with ENOSPC");
++ result++;
++ }
++ if (buf[39] != 'x')
++ {
++ puts ("5th inet_ntop wrote past the end of buffer");
++ result++;
++ }
++
++ if (inet_ntop (AF_INET6, &addr6, buf, 40) != buf)
++ {
++ puts ("6th inet_ntop did not return buf");
++ result++;
++ }
++ if (memcmp (buf, "e0e0:e0e0:e0e0:e0e0:e0e0:e0e0:e0e0:e0e0\0"
++ "xxxxxxxx", 48) != 0)
++ {
++ puts ("6th inet_ntop wrote past the end of buffer");
++ result++;
++ }
++
++
++ return result;
++}
--- /dev/null
+2007-05-21 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #4514]
+ * stdio-common/vfprintf.c (vfprintf): Don't shadow workstart variable,
+ reinitialize workend at the start of each do_positional format spec
+ loop, free workstart before do_positional loops.
+ (printf_unknown): Fix size of work_buffer.
+ * stdio-common/tst-sprintf.c (main): Add 3 new testcases.
+
+--- libc/stdio-common/vfprintf.c 7 May 2007 03:43:55 -0000 1.139
++++ libc/stdio-common/vfprintf.c 21 May 2007 17:50:22 -0000 1.140
+@@ -1627,6 +1627,8 @@ do_positional:
+ /* Just a counter. */
+ size_t cnt;
+
++ free (workstart);
++ workstart = NULL;
+
+ if (grouping == (const char *) -1)
+ {
+@@ -1801,7 +1803,9 @@ do_positional:
+ int use_outdigits = specs[nspecs_done].info.i18n;
+ char pad = specs[nspecs_done].info.pad;
+ CHAR_T spec = specs[nspecs_done].info.spec;
+- CHAR_T *workstart = NULL;
++
++ workstart = NULL;
++ workend = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)];
+
+ /* Fill in last information. */
+ if (specs[nspecs_done].width_arg != -1)
+@@ -1897,8 +1901,7 @@ do_positional:
+ break;
+ }
+
+- if (__builtin_expect (workstart != NULL, 0))
+- free (workstart);
++ free (workstart);
+ workstart = NULL;
+
+ /* Write the following constant string. */
+@@ -1926,7 +1929,7 @@ printf_unknown (FILE *s, const struct pr
+
+ {
+ int done = 0;
+- CHAR_T work_buffer[MAX (info->width, info->spec) + 32];
++ CHAR_T work_buffer[MAX (sizeof (info->width), sizeof (info->prec)) * 3];
+ CHAR_T *const workend
+ = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)];
+ register CHAR_T *w;
+--- libc/stdio-common/tst-sprintf.c 25 Jun 2003 11:04:49 -0000 1.3
++++ libc/stdio-common/tst-sprintf.c 21 May 2007 17:50:42 -0000 1.4
+@@ -37,5 +37,26 @@ main (void)
+ free (dst);
+ }
+
++ if (sprintf (buf, "%1$d%3$.*2$s%4$d", 7, 67108863, "x", 8) != 3
++ || strcmp (buf, "7x8") != 0)
++ {
++ printf ("sprintf (buf, \"%%1$d%%3$.*2$s%%4$d\", 7, 67108863, \"x\", 8) produced `%s' output", buf);
++ result = 1;
++ }
++
++ if (sprintf (buf, "%67108863.16\"%d", 7) != 14
++ || strcmp (buf, "%67108863.16\"7") != 0)
++ {
++ printf ("sprintf (buf, \"%%67108863.16\\\"%%d\", 7) produced `%s' output", buf);
++ result = 1;
++ }
++
++ if (sprintf (buf, "%*\"%d", 0x3ffffff, 7) != 11
++ || strcmp (buf, "%67108863\"7") != 0)
++ {
++ printf ("sprintf (buf, \"%%*\\\"%%d\", 0x3ffffff, 7) produced `%s' output", buf);
++ result = 1;
++ }
++
+ return result;
+ }
--- /dev/null
+2007-06-06 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #4586]
+ * sysdeps/i386/ldbl2mpn.c (__mpn_extract_long_double): Treat
+ pseudo-zeros as zero.
+ * sysdeps/x86_64/ldbl2mpn.c: New file.
+ * sysdeps/ia64/ldbl2mpn.c: New file.
+
+--- libc/sysdeps/i386/ldbl2mpn.c 6 Jul 2001 04:55:52 -0000 1.4
++++ libc/sysdeps/i386/ldbl2mpn.c 8 Jun 2007 02:50:11 -0000 1.5
+@@ -19,7 +19,7 @@
+ #include "gmp.h"
+ #include "gmp-impl.h"
+ #include "longlong.h"
+-#include "ieee754.h"
++#include <ieee754.h>
+ #include <float.h>
+ #include <stdlib.h>
+
+@@ -46,7 +46,7 @@ __mpn_extract_long_double (mp_ptr res_pt
+ #elif BITS_PER_MP_LIMB == 64
+ /* Hopefully the compiler will combine the two bitfield extracts
+ and this composition into just the original quadword extract. */
+- res_ptr[0] = ((unsigned long int) u.ieee.mantissa0 << 32) | u.ieee.mantissa1;
++ res_ptr[0] = ((mp_limb_t) u.ieee.mantissa0 << 32) | u.ieee.mantissa1;
+ #define N 1
+ #else
+ #error "mp_limb size " BITS_PER_MP_LIMB "not accounted for"
+@@ -109,6 +109,13 @@ __mpn_extract_long_double (mp_ptr res_pt
+ }
+ }
+ }
++ else if (u.ieee.exponent < 0x7fff
++#if N == 2
++ && res_ptr[0] == 0
++#endif
++ && res_ptr[N - 1] == 0)
++ /* Pseudo zero. */
++ *expt = 0;
+
+ return N;
+ }
+--- libc/sysdeps/ia64/ldbl2mpn.c 1 Jan 1970 00:00:00 -0000
++++ libc/sysdeps/ia64/ldbl2mpn.c 8 Jun 2007 02:50:49 -0000 1.1
+@@ -0,0 +1 @@
++#include "../i386/ldbl2mpn.c"
+--- libc/sysdeps/x86_64/ldbl2mpn.c 1 Jan 1970 00:00:00 -0000
++++ libc/sysdeps/x86_64/ldbl2mpn.c 8 Jun 2007 02:50:35 -0000 1.1
+@@ -0,0 +1 @@
++#include "../i386/ldbl2mpn.c"
--- /dev/null
+2007-07-03 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #4702]
+ * nis/nss-default.c: Include errno.h.
+ (init): Preserve errno.
+
+--- libc/nis/nss-default.c 28 Apr 2006 21:03:17 -0000 1.3
++++ libc/nis/nss-default.c 3 Jul 2007 14:49:41 -0000 1.4
+@@ -17,6 +17,7 @@
+ 02111-1307 USA. */
+
+ #include <ctype.h>
++#include <errno.h>
+ #include <stdio.h>
+ #include <stdio_ext.h>
+ #include <stdlib.h>
+@@ -54,6 +55,7 @@ static const struct
+ static void
+ init (void)
+ {
++ int saved_errno = errno;
+ FILE *fp = fopen (default_nss, "rc");
+ if (fp != NULL)
+ {
+@@ -111,6 +113,7 @@ init (void)
+
+ fclose (fp);
+ }
++ __set_errno (saved_errno);
+ }
+
+
--- /dev/null
+2007-07-07 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #4745]
+ * stdio-common/vfscanf.c (_IO_vfscanf): Add additional test for EOF
+ in loop to look for conversion specifier to avoid testing of
+ wrong errno value.
+ * stdio-common/Makefile (tests): Add bug18, bug18a, bug19, bug19a.
+ * stdio-common/bug18.c: New file.
+ * stdio-common/bug18a.c: New file.
+ * stdio-common/bug19.c: New file.
+ * stdio-common/bug19a.c: New file.
+
+--- libc/stdio-common/vfscanf.c 27 Apr 2007 19:28:32 -0000 1.123
++++ libc/stdio-common/vfscanf.c 8 Jul 2007 04:41:22 -0000 1.124
+@@ -549,7 +549,11 @@ _IO_vfscanf (s, format, argptr, errp)
+ int save_errno = errno;
+ errno = 0;
+ do
+- if (inchar () == EOF && errno == EINTR)
++ /* We add the additional test for EOF here since otherwise
++ inchar will restore the old errno value which might be
++ EINTR but does not indicate an interrupt since nothing
++ was read at this time. */
++ if ((c == EOF || inchar () == EOF) && errno == EINTR)
+ input_error ();
+ while (ISSPACE (c));
+ errno = save_errno;
+--- libc/stdio-common/Makefile 4 Jun 2007 14:38:03 -0000 1.101
++++ libc/stdio-common/Makefile 8 Jul 2007 04:41:08 -0000 1.104
+@@ -54,7 +54,7 @@ tests := tstscanf test_rdwr test-popen t
+ tst-swprintf tst-fseek tst-fmemopen test-vfprintf tst-gets \
+ tst-perror tst-sprintf tst-rndseek tst-fdopen tst-fphex bug14 bug15 \
+ tst-popen tst-unlockedio tst-fmemopen2 tst-put-error tst-fgets \
+- tst-fwrite bug16 bug17
++ tst-fwrite bug16 bug17 bug18 bug18a bug19 bug19a
+
+ test-srcs = tst-unbputc tst-printf
+
+--- libc/stdio-common/bug18.c 1 Jan 1970 00:00:00 -0000
++++ libc/stdio-common/bug18.c 7 Jul 2007 21:37:37 -0000 1.2
+@@ -0,0 +1,48 @@
++#include <assert.h>
++#include <errno.h>
++#include <stdio.h>
++
++#ifndef CHAR
++# define CHAR char
++# define L(str) str
++# define SSCANF sscanf
++#endif
++
++
++static int
++do_test (void)
++{
++ printf("setting errno to EINTR\n");
++ errno = EINTR;
++
++ printf("checking sscanf\n");
++
++ CHAR str[] = L("7-11");
++ int i, j, n;
++
++ i = j = n = 0;
++ SSCANF (str, L(" %i - %i %n"), &i, &j, &n);
++ printf ("found %i-%i (length=%i)\n", i, j, n);
++
++ int result = 0;
++ if (i != 7)
++ {
++ printf ("i is %d, expected 7\n", i);
++ result = 1;
++ }
++ if (j != 11)
++ {
++ printf ("j is %d, expected 11\n", j);
++ result = 1;
++ }
++ if (n != 4)
++ {
++ printf ("n is %d, expected 4\n", j);
++ result = 1;
++ }
++
++ return result;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- libc/stdio-common/bug18a.c 1 Jan 1970 00:00:00 -0000
++++ libc/stdio-common/bug18a.c 7 Jul 2007 21:38:10 -0000 1.1
+@@ -0,0 +1,6 @@
++#include <wchar.h>
++#define CHAR wchar_t
++#define L(str) L##str
++#define SSCANF swscanf
++
++#include "bug18.c"
+--- libc/stdio-common/bug19.c 1 Jan 1970 00:00:00 -0000
++++ libc/stdio-common/bug19.c 8 Jul 2007 04:40:55 -0000 1.1
+@@ -0,0 +1,58 @@
++#include <assert.h>
++#include <errno.h>
++#include <stdio.h>
++
++#ifndef CHAR
++# define CHAR char
++# define L(str) str
++# define FPUTS fputs
++# define FSCANF fscanf
++#endif
++
++
++static int
++do_test (void)
++{
++ FILE *fp = tmpfile ();
++ if (fp == NULL)
++ {
++ puts ("cannot open file");
++ return 1;
++ }
++
++ FPUTS (L("7-11"), fp);
++ rewind (fp);
++
++ printf("setting errno to EINTR\n");
++ errno = EINTR;
++
++ printf("checking sscanf\n");
++
++ int i, j, n;
++
++ i = j = n = 0;
++ FSCANF (fp, L(" %i - %i %n"), &i, &j, &n);
++ printf ("found %i-%i (length=%i)\n", i, j, n);
++
++ int result = 0;
++ if (i != 7)
++ {
++ printf ("i is %d, expected 7\n", i);
++ result = 1;
++ }
++ if (j != 11)
++ {
++ printf ("j is %d, expected 11\n", j);
++ result = 1;
++ }
++ if (n != 4)
++ {
++ printf ("n is %d, expected 4\n", j);
++ result = 1;
++ }
++
++ return result;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- libc/stdio-common/bug19a.c 1 Jan 1970 00:00:00 -0000
++++ libc/stdio-common/bug19a.c 8 Jul 2007 04:40:55 -0000 1.1
+@@ -0,0 +1,7 @@
++#include <wchar.h>
++#define CHAR wchar_t
++#define L(str) L##str
++#define FPUTS fputws
++#define FSCANF fwscanf
++
++#include "bug19.c"
--- /dev/null
+2007-07-11 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #4776]
+ * elf/dl-load.c (_dl_rtld_di_serinfo): Output / in LD_LIBRARY_PATH,
+ RPATH etc. as "/" rather than "", don't segfault on empty paths,
+ instead output ".".
+ * dlfcn/Makefile (distribute): Add glreflib3.c.
+ (module-names): Add glreflib3.
+ ($(objpfx)tst-dlinfo.out): Depend on glreflib3.so rather than
+ glreflib1.so.
+ (LDFLAGS_glreflib3.so): New.
+ * dlfcn/tst-dlinfo.c (do_test): Load glreflib3.so instead of
+ glreflib1.so.
+ * dlfcn/glreflib3.c: New file.
+
+--- libc/elf/dl-load.c 30 Jun 2007 17:01:07 -0000 1.286
++++ libc/elf/dl-load.c 12 Jul 2007 18:15:27 -0000 1.287
+@@ -2273,14 +2273,17 @@ _dl_rtld_di_serinfo (struct link_map *lo
+ if (counting)
+ {
+ si->dls_cnt++;
+- si->dls_size += r->dirnamelen;
++ si->dls_size += r->dirnamelen < 2 ? r->dirnamelen : 2;
+ }
+ else
+ {
+ Dl_serpath *const sp = &si->dls_serpath[idx++];
+ sp->dls_name = allocptr;
+- allocptr = __mempcpy (allocptr,
+- r->dirname, r->dirnamelen - 1);
++ if (r->dirnamelen < 2)
++ *allocptr++ = r->dirnamelen ? '/' : '.';
++ else
++ allocptr = __mempcpy (allocptr,
++ r->dirname, r->dirnamelen - 1);
+ *allocptr++ = '\0';
+ sp->dls_flags = flags;
+ }
+--- libc/dlfcn/Makefile 28 Oct 2006 06:44:04 -0000 1.42
++++ libc/dlfcn/Makefile 12 Jul 2007 18:16:10 -0000 1.43
+@@ -23,7 +23,8 @@ libdl-routines := dlopen dlclose dlsym d
+ dlmopen
+ routines := $(patsubst %,s%,$(libdl-routines))
+ elide-routines.os := $(routines)
+-distribute := dlopenold.c glreflib1.c glreflib2.c failtestmod.c \
++distribute := dlopenold.c glreflib1.c glreflib2.c glreflib3.c \
++ failtestmod.c \
+ defaultmod1.c defaultmod2.c errmsg1mod.c modatexit.c \
+ modcxaatexit.c modstatic.c modstatic2.c \
+ bug-dlsym1-lib1.c bug-dlsym1-lib2.c
+@@ -44,8 +45,8 @@ ifeq (yes,$(have-protected))
+ tests += tstatexit
+ endif
+ endif
+-modules-names = glreflib1 glreflib2 failtestmod defaultmod1 defaultmod2 \
+- errmsg1mod modatexit modcxaatexit \
++modules-names = glreflib1 glreflib2 glreflib3 failtestmod defaultmod1 \
++ defaultmod2 errmsg1mod modatexit modcxaatexit \
+ bug-dlsym1-lib1 bug-dlsym1-lib2
+
+ failtestmod.so-no-z-defs = yes
+@@ -87,7 +88,8 @@ $(objpfx)tst-dladdr: $(libdl)
+ $(objpfx)tst-dladdr.out: $(objpfx)glreflib1.so
+
+ $(objpfx)tst-dlinfo: $(libdl)
+-$(objpfx)tst-dlinfo.out: $(objpfx)glreflib1.so
++$(objpfx)tst-dlinfo.out: $(objpfx)glreflib3.so
++LDFLAGS-glreflib3.so = -Wl,-rpath,:
+
+ LDFLAGS-default = $(LDFLAGS-rdynamic)
+ $(objpfx)default: $(libdl) $(objpfx)defaultmod1.so $(objpfx)defaultmod2.so
+--- libc/dlfcn/glreflib3.c 1 Jan 1970 00:00:00 -0000
++++ libc/dlfcn/glreflib3.c 12 Jul 2007 18:15:56 -0000 1.1
+@@ -0,0 +1 @@
++#include "glreflib1.c"
+--- libc/dlfcn/tst-dlinfo.c 15 Mar 2003 23:14:48 -0000 1.1
++++ libc/dlfcn/tst-dlinfo.c 12 Jul 2007 18:15:39 -0000 1.2
+@@ -29,7 +29,7 @@ do_test (void)
+ {
+ int status = 0;
+
+- void *handle = dlopen ("glreflib1.so", RTLD_NOW);
++ void *handle = dlopen ("glreflib3.so", RTLD_NOW);
+ if (handle == NULL)
+ error (EXIT_FAILURE, 0, "cannot load: glreflib1.so: %s", dlerror ());
+
--- /dev/null
+2007-07-20 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #4813]
+ * login/forkpty.c (forkpty): Close master and slave fds on
+ fork failure. Patch by
+ Mikulas Patocka <mikulas@artax.karlin.mff.cuni.cz>.
+
+--- libc/login/forkpty.c 6 Jul 2001 04:55:34 -0000 1.2
++++ libc/login/forkpty.c 20 Jul 2007 07:20:07 -0000 1.3
+@@ -38,6 +38,8 @@ forkpty (amaster, name, termp, winp)
+ switch (pid = fork ())
+ {
+ case -1:
++ close (master);
++ close (slave);
+ return -1;
+ case 0:
+ /* Child. */
--- /dev/null
+2007-07-31 Jakub Jelinek <jakub@redhat.com>
+
+ * stdio-common/tfformat.c (sprint_doubles): Add 12 new tests.
+
+2007-07-28 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #4858]
+ * stdio-common/printf_fp.c (___printf_fp): Fix special case of
+ #.0g and value rounded to 1.0.
+ * stdio-common/tfformat.c (sprint_doubles): Add two new tests.
+
+--- libc/stdio-common/printf_fp.c 30 Apr 2007 22:31:21 -0000 1.63
++++ libc/stdio-common/printf_fp.c 29 Jul 2007 00:25:19 -0000 1.64
+@@ -986,7 +986,9 @@ ___printf_fp (FILE *fp,
+ if (*wtp != decimalwc)
+ /* Round up. */
+ (*wtp)++;
+- else if (__builtin_expect (spec == 'g' && type == 'f' && info->alt,
++ else if (__builtin_expect (spec == 'g' && type == 'f' && info->alt
++ && wtp == wstartp + 1
++ && wstartp[0] == L'0',
+ 0))
+ /* This is a special case: the rounded number is 1.0,
+ the format is 'g' or 'G', and the alternative format
+--- libc/stdio-common/tfformat.c 30 Apr 2007 22:31:36 -0000 1.10
++++ libc/stdio-common/tfformat.c 31 Jul 2007 12:32:17 -0000 1.12
+@@ -4024,6 +4024,21 @@ sprint_double_type sprint_doubles[] =
+ {__LINE__, 1.0, "1.000000e+00", "%e"},
+ {__LINE__, .9999999999999999, "1.000000e+00", "%e"},
+
++ {__LINE__, 912.98, "913.0", "%#.4g"},
++ {__LINE__, 50.999999, "51.000", "%#.5g"},
++ {__LINE__, 0.956, "1", "%.1g"},
++ {__LINE__, 0.956, "1.", "%#.1g"},
++ {__LINE__, 0.996, "1", "%.2g"},
++ {__LINE__, 0.996, "1.0", "%#.2g"},
++ {__LINE__, 999.98, "1000", "%.4g"},
++ {__LINE__, 999.98, "1000.", "%#.4g"},
++ {__LINE__, 999.998, "1000", "%.5g"},
++ {__LINE__, 999.998, "1000.0", "%#.5g"},
++ {__LINE__, 999.9998, "1000", "%g"},
++ {__LINE__, 999.9998, "1000.00", "%#g"},
++ {__LINE__, 912.98, "913", "%.4g"},
++ {__LINE__, 50.999999, "51", "%.5g"},
++
+ {0 }
+
+ };
--- /dev/null
+2005-09-26 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #524]
+ * sysdeps/posix/getaddrinfo.c (match_prefix): Fix matching loop of
+ number of bits is multiple of 8.
+ Patch by Fredrik Tolf <fredrik@dolda2000.com>.
+
+--- libc/sysdeps/posix/getaddrinfo.c 18 May 2005 19:22:50 -0000 1.87
++++ libc/sysdeps/posix/getaddrinfo.c 26 Sep 2005 16:10:03 -0000 1.88
+@@ -1266,7 +1266,7 @@ match_prefix (const struct sockaddr_stor
+ uint8_t *mask = list[idx].prefix.s6_addr;
+ uint8_t *val = in6->sin6_addr.s6_addr;
+
+- while (bits > 8)
++ while (bits >= 8)
+ {
+ if (*mask != *val)
+ break;
--- /dev/null
+2008-03-03 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #5854]
+ * nis/ypclnt.c (yp_order): Fix handling of return value of
+ do_ypcall_tr call.
+ Patch by Jeff Moyer <jmoyer@redhat.com>.
+
+--- libc/nis/ypclnt.c 28 Apr 2006 16:59:22 -0000 1.58
++++ libc/nis/ypclnt.c 4 Mar 2008 00:27:41 -0000 1.59
+@@ -634,7 +634,7 @@ yp_order (const char *indomain, const ch
+ (caddr_t) &req, (xdrproc_t) xdr_ypresp_order,
+ (caddr_t) &resp);
+
+- if (result == YPERR_SUCCESS)
++ if (result != YPERR_SUCCESS)
+ return result;
+
+ *outorder = resp.ordernum;
--- /dev/null
+2005-09-26 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #644]
+ * sysdeps/posix/getaddrinfo.c (fls): New function.
+ (gaih_inet): Don't use ffs, use fls. Convert address to native byte
+ order first.
+ * posix/Makefile (tests): Add tst-rfc3484.
+ * posix/tst-rfc3484.c: New file.
+
+--- libc/sysdeps/posix/getaddrinfo.c 26 Sep 2005 16:10:03 -0000 1.88
++++ libc/sysdeps/posix/getaddrinfo.c 26 Sep 2005 21:10:16 -0000 1.89
+@@ -1304,6 +1304,19 @@ get_precedence (const struct sockaddr_st
+ }
+
+
++/* Find last bit set in a word. */
++static int
++fls (uint32_t a)
++{
++ uint32_t mask;
++ int n = 0;
++ for (n = 0, mask = 1 << 31; n < 32; mask >>= 1, ++n)
++ if ((a & mask) != 0)
++ break;
++ return n;
++}
++
++
+ static int
+ rfc3484_sort (const void *p1, const void *p2)
+ {
+@@ -1407,8 +1420,10 @@ rfc3484_sort (const void *p1, const void
+ in2_dst = (struct sockaddr_in *) a2->dest_addr->ai_addr;
+ in2_src = (struct sockaddr_in *) &a2->source_addr;
+
+- bit1 = ffs (in1_dst->sin_addr.s_addr ^ in1_src->sin_addr.s_addr);
+- bit2 = ffs (in2_dst->sin_addr.s_addr ^ in2_src->sin_addr.s_addr);
++ bit1 = fls (ntohl (in1_dst->sin_addr.s_addr
++ ^ in1_src->sin_addr.s_addr));
++ bit2 = fls (ntohl (in2_dst->sin_addr.s_addr
++ ^ in2_src->sin_addr.s_addr));
+ }
+ else if (a1->dest_addr->ai_family == PF_INET6)
+ {
+@@ -1435,10 +1450,10 @@ rfc3484_sort (const void *p1, const void
+
+ if (i < 4)
+ {
+- bit1 = ffs (in1_dst->sin6_addr.s6_addr32[i]
+- ^ in1_src->sin6_addr.s6_addr32[i]);
+- bit2 = ffs (in2_dst->sin6_addr.s6_addr32[i]
+- ^ in2_src->sin6_addr.s6_addr32[i]);
++ bit1 = fls (ntohl (in1_dst->sin6_addr.s6_addr32[i]
++ ^ in1_src->sin6_addr.s6_addr32[i]));
++ bit2 = fls (ntohl (in2_dst->sin6_addr.s6_addr32[i]
++ ^ in2_src->sin6_addr.s6_addr32[i]));
+ }
+ }
+
+--- libc/posix/Makefile 24 Jul 2005 21:39:12 -0000 1.185
++++ libc/posix/Makefile 26 Sep 2005 21:13:27 -0000 1.186
+@@ -87,7 +87,7 @@ tests := tstgetopt testfnm runtests run
+ tst-execvp1 tst-execvp2 tst-execlp1 tst-execlp2 \
+ tst-execv1 tst-execv2 tst-execl1 tst-execl2 \
+ tst-execve1 tst-execve2 tst-execle1 tst-execle2 \
+- tst-execvp3 tst-execvp4
++ tst-execvp3 tst-execvp4 tst-rfc3484
+ xtests := bug-ga2
+ ifeq (yes,$(build-shared))
+ test-srcs := globtest
+--- libc/posix/tst-rfc3484.c 1 Jan 1970 00:00:00 -0000
++++ libc/posix/tst-rfc3484.c 26 Sep 2005 21:12:49 -0000 1.1
+@@ -0,0 +1,98 @@
++#include <stdbool.h>
++#include <stdio.h>
++
++/* Internal definitions used in the libc code. */
++#define __getservbyname_r getservbyname_r
++#define __socket socket
++#define __getsockname getsockname
++#define __inet_aton inet_aton
++#define __gethostbyaddr_r gethostbyaddr_r
++#define __gethostbyname2_r gethostbyname2_r
++
++void
++attribute_hidden
++__check_pf (bool *p1, bool *p2)
++{
++ *p1 = *p2 = true;
++}
++int
++__idna_to_ascii_lz (const char *input, char **output, int flags)
++{
++ return 0;
++}
++int
++__idna_to_unicode_lzlz (const char *input, char **output, int flags)
++{
++ return 0;
++}
++
++#include "../sysdeps/posix/getaddrinfo.c"
++
++service_user *__nss_hosts_database attribute_hidden;
++
++
++/* This is the beginning of the real test code. The above defines
++ (among other things) the function rfc3484_sort. */
++
++
++#if __BYTE_ORDER == __BIG_ENDIAN
++# define h(n) n
++#else
++# define h(n) __bswap_constant_32 (n)
++#endif
++
++struct sockaddr_in addrs[] =
++{
++ { .sin_family = AF_INET, .sin_addr = { h (0xc0a86d1d) } },
++ { .sin_family = AF_INET, .sin_addr = { h (0xc0a85d03) } },
++ { .sin_family = AF_INET, .sin_addr = { h (0xc0a82c3d) } },
++ { .sin_family = AF_INET, .sin_addr = { h (0xc0a86002) } },
++ { .sin_family = AF_INET, .sin_addr = { h (0xc0a802f3) } },
++ { .sin_family = AF_INET, .sin_addr = { h (0xc0a80810) } },
++ { .sin_family = AF_INET, .sin_addr = { h (0xc0a85e02) } }
++};
++#define naddrs (sizeof (addrs) / sizeof (addrs[0]))
++static struct addrinfo ais[naddrs];
++static struct sort_result results[naddrs];
++
++static int expected[naddrs] =
++ {
++ 6, 1, 0, 3, 2, 4, 5
++ };
++
++
++static int
++do_test (void)
++{
++ struct sockaddr_in so;
++ so.sin_family = AF_INET;
++ so.sin_addr.s_addr = h (0xc0a85f19);
++
++ for (int i = 0; i < naddrs; ++i)
++ {
++ ais[i].ai_family = AF_INET;
++ ais[i].ai_addr = (struct sockaddr *) &addrs[i];
++ results[i].dest_addr = &ais[i];
++ results[i].got_source_addr = true;
++ memcpy(&results[i].source_addr, &so, sizeof (so));
++ results[i].source_addr_len = sizeof (so);
++ }
++
++ qsort (results, naddrs, sizeof (results[0]), rfc3484_sort);
++
++ int result = 0;
++ for (int i = 0; i < naddrs; ++i)
++ {
++ struct in_addr addr = ((struct sockaddr_in *) (results[i].dest_addr->ai_addr))->sin_addr;
++
++ int here = memcmp (&addr, &addrs[expected[i]].sin_addr,
++ sizeof (struct in_addr));
++ printf ("[%d] = %s: %s\n", i, inet_ntoa (addr), here ? "FAIL" : "OK");
++ result |= here;
++ }
++
++ return result;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
--- /dev/null
+2008-05-14 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #6461]
+ * iconv/gconv_simple.c (BODY for __gconv_transform_ascii_internal):
+ Add missing braces.
+ (BODY for __gconv_transform_internal_ascii): Likewise.
+
+--- libc/iconv/gconv_simple.c 12 Oct 2007 04:40:33 -0000 1.67
++++ libc/iconv/gconv_simple.c 14 May 2008 22:52:44 -0000 1.68
+@@ -820,9 +820,11 @@ ucs4le_internal_loop_single (struct __gc
+ STANDARD_FROM_LOOP_ERR_HANDLER (1); \
+ } \
+ else \
+- /* It's an one byte sequence. */ \
+- *((uint32_t *) outptr) = *inptr++; \
+- outptr += sizeof (uint32_t); \
++ { \
++ /* It's an one byte sequence. */ \
++ *((uint32_t *) outptr) = *inptr++; \
++ outptr += sizeof (uint32_t); \
++ } \
+ }
+ #define LOOP_NEED_FLAGS
+ #include <iconv/loop.c>
+@@ -851,9 +853,11 @@ ucs4le_internal_loop_single (struct __gc
+ STANDARD_TO_LOOP_ERR_HANDLER (4); \
+ } \
+ else \
+- /* It's an one byte sequence. */ \
+- *outptr++ = *((const uint32_t *) inptr); \
+- inptr += sizeof (uint32_t); \
++ { \
++ /* It's an one byte sequence. */ \
++ *outptr++ = *((const uint32_t *) inptr); \
++ inptr += sizeof (uint32_t); \
++ } \
+ }
+ #define LOOP_NEED_FLAGS
+ #include <iconv/loop.c>
--- /dev/null
+2008-07-08 Ulrich Drepper <drepper@redhat.com>
+
+ * stdio-common/Makefile: Add rules to build and run tst-setvbuf1.
+ * stdio-common/tst-setvbuf1.c: New file.
+ * stdio-common/tst-setvbuf1.expect: New file.
+
+ [BZ #6719]
+ * libio/iosetvbuf.c (_IO_setvbuf): Correctly clear buffering flags
+ when selecting fully-buffered stream.
+ Patch by Wang Xin <wxinee@gmail.com>.
+
+--- libc/libio/iosetvbuf.c 29 Aug 2003 19:58:27 -0000 1.20
++++ libc/libio/iosetvbuf.c 8 Jul 2008 16:20:32 -0000 1.21
+@@ -45,7 +45,7 @@ _IO_setvbuf (fp, buf, mode, size)
+ switch (mode)
+ {
+ case _IOFBF:
+- fp->_IO_file_flags &= ~_IO_LINE_BUF|_IO_UNBUFFERED;
++ fp->_IO_file_flags &= ~(_IO_LINE_BUF|_IO_UNBUFFERED);
+ if (buf == NULL)
+ {
+ if (fp->_IO_buf_base == NULL)
+--- libc/stdio-common/Makefile 24 May 2008 18:14:36 -0000 1.112
++++ libc/stdio-common/Makefile 8 Jul 2008 16:32:28 -0000 1.113
+@@ -54,7 +54,8 @@ tests := tstscanf test_rdwr test-popen t
+ tst-swprintf tst-fseek tst-fmemopen test-vfprintf tst-gets \
+ tst-perror tst-sprintf tst-rndseek tst-fdopen tst-fphex bug14 bug15 \
+ tst-popen tst-unlockedio tst-fmemopen2 tst-put-error tst-fgets \
+- tst-fwrite bug16 bug17 bug18 bug18a bug19 bug19a tst-popen2
++ tst-fwrite bug16 bug17 bug18 bug18a bug19 bug19a tst-popen2 \
++ tst-setvbuf1
+
+ test-srcs = tst-unbputc tst-printf
+
+@@ -101,3 +102,7 @@ bug15-ENV = LOCPATH=$(common-objpfx)loca
+ ifneq (,$(filter %REENTRANT, $(defines)))
+ CPPFLAGS += -D_IO_MTSAFE_IO
+ endif
++
++$(objpfx)tst-setvbuf1.out: tst-setvbuf1.expect $(objpfx)tst-setvbuf1
++ $(built-program-cmd) > $@ 2>&1
++ cmp tst-setvbuf1.expect $@
+--- libc/stdio-common/tst-setvbuf1.c 1 Jan 1970 00:00:00 -0000
++++ libc/stdio-common/tst-setvbuf1.c 8 Jul 2008 16:32:02 -0000 1.1
+@@ -0,0 +1,19 @@
++#include <stdio.h>
++
++static int
++do_test (void)
++{
++ if (setvbuf (stderr, NULL, _IOFBF, BUFSIZ) != 0)
++ {
++ puts ("Set full buffer error.");
++ return 1;
++ }
++
++ fprintf (stderr, "Output #1 <stderr>.\n");
++ printf ("Output #2 <stdout>.\n");
++
++ return 0;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- libc/stdio-common/tst-setvbuf1.expect 1 Jan 1970 00:00:00 -0000
++++ libc/stdio-common/tst-setvbuf1.expect 8 Jul 2008 16:32:14 -0000 1.1
+@@ -0,0 +1,2 @@
++Output #2 <stdout>.
++Output #1 <stderr>.
--- /dev/null
+2005-10-15 Ulrich Drepper <drepper@redhat.com>
+
+ * wcsmbs/tst-mbrtowc2.c: Use de_DE.UTF-8 instead of en_US.UTF-8.
+ * wcsmbs/Makefile: Define tst-mbrtowc2-ENV.
+
+2005-09-25 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #714]
+ * iconv/loop.c [!STORE_REST] (SINGLE): Correctly record number of
+ left-over bytes and store them correctly.
+ * wcsmbs/tst-mbrtowc2.c: New file.
+ * wcsmbs/Makefile (tests): Add tst-mbrtowc2.
+
+--- libc/iconv/loop.c 11 Jun 2003 21:38:13 -0000 1.35
++++ libc/iconv/loop.c 25 Sep 2005 16:42:36 -0000 1.36
+@@ -450,6 +450,10 @@ SINGLE(LOOPFCT) (struct __gconv_step *st
+ #else
+ /* We don't have enough input for another complete input
+ character. */
++ assert (inend - inptr > (state->__count & ~7));
++ assert (inend - inptr <= 7);
++ state->__count = (state->__count & ~7) | (inend - inptr);
++ inlen = 0;
+ while (inptr < inend)
+ state->__value.__wchb[inlen++] = *inptr++;
+ #endif
+--- libc/wcsmbs/tst-mbrtowc2.c 1 Jan 1970 00:00:00 -0000
++++ libc/wcsmbs/tst-mbrtowc2.c 15 Oct 2005 15:38:00 -0000 1.3
+@@ -0,0 +1,67 @@
++/* Derived from the test case in http://sourceware.org/bugzilla/show_bug.cgi?id=714 */
++#include <locale.h>
++#include <stdio.h>
++#include <string.h>
++#include <wchar.h>
++
++
++static struct
++{
++ const char *chp;
++ size_t nchp;
++ const char *loc;
++} tests[] =
++{
++ { (const char[]) { 0x8F, 0xA2, 0xAF }, 3, "ja_JP.EUC-JP" },
++ { (const char[]) { 0xD1, 0xA5 }, 2, "ja_JP.EUC-JP" },
++ { (const char[]) { 0x8E, 0xA5 }, 2, "ja_JP.EUC-JP" },
++ { (const char[]) { 0x8E, 0xA2, 0xA1, 0xA1 }, 4, "zh_TW.EUC-TW" },
++ { (const char[]) { 0xA1, 0xA1 }, 2, "zh_TW.EUC-TW" },
++ { (const char[]) { 0xE3, 0x80, 0x80 }, 3, "de_DE.UTF-8" },
++ { (const char[]) { 0xC3, 0xA4 }, 2, "de_DE.UTF-8" }
++};
++#define ntests (sizeof (tests) / sizeof (tests[0]))
++
++
++static int t (const char *ch, size_t nch, const char *loc);
++
++static int
++do_test (void)
++{
++ int r = 0;
++ for (int i = 0; i < ntests; ++i)
++ r |= t (tests[i].chp, tests[i].nchp, tests[i].loc);
++ return r;
++}
++
++static int
++t (const char *ch, size_t nch, const char *loc)
++{
++ int i;
++ wchar_t wch;
++ wchar_t wch2;
++ mbstate_t mbs;
++ int n = 0;
++
++ setlocale (LC_ALL, loc);
++
++ memset (&mbs, '\0', sizeof (mbstate_t));
++ for (i = 0; i < nch; i++)
++ {
++ n = mbrtowc (&wch, ch + i, 1, &mbs);
++ if (n >= 0)
++ break;
++ }
++ printf ("n = %d, count = %d, wch = %08lX\n", n, i, (unsigned long int) wch);
++
++ memset (&mbs, '\0', sizeof (mbstate_t));
++ n = mbrtowc (&wch2, ch, nch, &mbs);
++ printf ("n = %d, wch = %08lX\n", n, (unsigned long int) wch2);
++
++ int ret = n != nch || i + 1 != nch || n != nch || wch != wch2;
++ puts (ret ? "FAIL\n" : "OK\n");
++ return ret;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- libc/wcsmbs/Makefile 24 Jul 2005 20:02:03 -0000 1.24
++++ libc/wcsmbs/Makefile 25 Sep 2005 16:57:58 -0000 1.25
+@@ -40,7 +40,7 @@ routines := wcscat wcschr wcscmp wcscpy
+ wcsmbsload mbsrtowcs_l
+
+ tests := tst-wcstof wcsmbs-tst1 tst-wcsnlen tst-btowc tst-mbrtowc \
+- tst-wcrtomb tst-wcpncpy tst-mbsrtowcs
++ tst-wcrtomb tst-wcpncpy tst-mbsrtowcs tst-mbrtowc2
+
+ include ../Rules
+
--- /dev/null
+2005-10-15 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #968]
+ * string/strxfrm_l.c (STRXFRM): Fix exit conditions of two loops.
+
+--- libc/string/strxfrm_l.c 14 Mar 2004 20:52:47 -0000 1.4
++++ libc/string/strxfrm_l.c 15 Oct 2005 20:49:18 -0000 1.5
+@@ -210,8 +210,9 @@ STRXFRM (STRING_TYPE *dest, const STRING
+ /* Handle the pushed elements now. */
+ size_t backw;
+
+- for (backw = idxcnt - 1; backw >= backw_stop; --backw)
++ for (backw = idxcnt; backw > backw_stop; )
+ {
++ --backw;
+ len = weights[idxarr[backw]++];
+
+ if (needed + len < n)
+@@ -293,8 +294,9 @@ STRXFRM (STRING_TYPE *dest, const STRING
+ /* Handle the pushed elements now. */
+ size_t backw;
+
+- for (backw = idxcnt - 1; backw >= backw_stop; --backw)
++ for (backw = idxcnt; backw > backw_stop; )
+ {
++ --backw;
+ len = weights[idxarr[backw]++];
+ if (len != 0)
+ {
--- /dev/null
+2006-05-01 Ulrich Drepper <drepper@redhat.com>
+
+ * misc/tsearch.c (__tdelete): Remove unnecessary test
+ [Coverity CID 75].
+
+ * sysdeps/generic/unwind-dw2.c (execute_cfa_program): Print error
+ message for invalid DWARF data instead of crashing.
+
+2006-04-08 Ulrich Drepper <drepper@redhat.com>
+
+ * io/fts.c (fts_build): Call fts_lfree in the two error cases
+ after the loop [Coverity CID 187].
+
+ * nis/nis_getservlist.c (nis_getservlist): Also free lookup result
+ in error case [Coverity CID 189].
+
+ * nis/nis_getservlist.c (nis_getservlist): One more free call
+ needed [Coverity CID 190].
+
+2006-04-07 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/generic/unwind-dw2-fde.c (end_fde_sort): Remove
+ unnecessary test for accu->linear == NULL [Coverity CID 79].
+
+2006-04-07 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/posix/tempname.c (__gen_tempname): Change attempts_min
+ into a macro. Use preprocessor to decide how to initialize
+ attempts [Coverity CID 67].
+
+ * io/fts.c (fts_build): Comment out dead code [Coverity CID 68].
+
+ * sunrpc/rpc_parse.c (def_union): Comment out dead code
+ [Coverity CID 70].
+
+ * locale/programs/linereader.c (lr_token): Remove duplicate
+ handling of EOF [Coverity CID 71].
+
+ * locale/programs/ld-numeric.c (numeric_read) [case tok_grouping]:
+ We bail out early if ignore_content is set, so there is no need to
+ check it later again [Coverity CID 72].
+
+ * inet/inet6_option.c (inet6_option_find): Check *tptrp for NULL,
+ not tptrp [Coverity CID 73].
+
+ * inet/inet6_option.c (inet6_option_next): Check *tptrp for NULL,
+ not tptrp [Coverity CID 74].
+
+ * misc/tsearch.c (__tsearch): Don't rotate tree if memory
+ allocation failed [Coverity CID 78].
+
+2006-04-07 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/generic/unwind-dw2.c (execute_cfa_program): Fix typo in
+ the last change.
+
+2006-04-07 Ulrich Drepper <drepper@redhat.com>
+
+ * inet/rexec.c (rexec_af): If we have no canonical name don't
+ proceed further [Coverity CID 86].
+
+ * iconv/iconv_charmap.c (process_fd): Initialize inptr from inbuf,
+ not to NULL [Coverity CID 88].
+
+2006-04-06 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/generic/unwind-dw2.c (execute_cfa_program): Don't handle
+ DW_CFA_GNU_window_save if it obviously cannot work [Coverity CID 102].
+
+ * libio/fmemopen.c (fmemopen): Free stream memory in case of
+ invalid length [Coverity CID 106].
+
+ * nss/nss_files/files-key.c (search): Close stream before
+ successful return [Coverity CID 107].
+
+ * io/fts.c (fts_open): Don't allocate parent if *argv==NULL
+ [Coverity CID 108].
+
+ * sunrpc/rpc_cout.c (inline_struct): Free sizestr after use
+ [Coverity CID 110, 109].
+
+ * sunrpc/rpc_scan.c (docppline): Free file string if it is not
+ going to be used [Coverity CID 111].
+
+ * sysdeps/unix/sysv/linux/getsourcefilter.c (getsourcefilter): Free
+ memory if socket level value cannot be retrieved [Coverity CID 112].
+
+ * nis/nis_clone_dir.c (nis_clone_directory): Free all memory in
+ error case [Coverity CID 114].
+
+ * nis/nis_clone_res.c (nis_clone_result): Free all memory in the
+ error cases [Coverity CID 115].
+
+ * sunrpc/rpc_parse.c (get_definition): Free defp if tok ==
+ TOK_EOF [Coverity CID 116].
+
+ * sysdeps/unix/sysv/linux/setsourcefilter.c (setsourcefilter): Free
+ memory if socket level value cannot be retrieved [Coverity CID 117].
+
+ * elf/cache.c (save_cache): Initialize pad to avoid writing
+ uninitialized data to disk.
+
+ * elf/cache.c (save_cache): Free file_entries_new [Coverity CID 118].
+
+ * intl/finddomain.c (_nl_find_domain): Avoid strdup of expand
+ locale name, use strdupa. Remove free call [Coverity CID 119].
+
+ * sunrpc/rpc_main.c (generate_guard): Avoid extra allocation and
+ the resulting leak [Coverity CID 121].
+
+ * sunrpc/rpc_main.c (mkfile_output): Free all allocated memory
+ [Coverity CID 122].
+
+ * sunrpc/rpc_main.c (h_output): Free guard after we are done
+ [Coverity CID 123].
+
+ * sunrpc/svc_udp.c (cache_set): Free victim if newbuf allocation
+ fails [Coverity CID 126].
+
+ * sunrpc/svc_udp.c (svcudp_enablecache): Free memory in error
+ cases [Coverity CID 127].
+
+ * nis/nis_table.c (__create_ib_request): Free ibreq in case strdup
+ fails [Coverity CID 128].
+
+ * nis/nis_getservlist.c (nis_getservlist): Free all memory in case
+ of an error [Coverity CID 130, 129].
+
+ * nis/nis_print_group_entry.c (nis_print_group_entry): If
+ nis_lookup call failed, return. Free lookup result in error
+ cases [Coverity CID 131].
+
+ * nis/nis_removemember.c (nis_removemember): Free all memory in
+ error cases [Coverity CID 132].
+
+ * nis/nss_nisplus/nisplus-alias.c (_nss_nisplus_getaliasbyname_r):
+ Always free lookup result [Coverity CID 134].
+
+ * nis/nss_nisplus/nisplus-ethers.c (_nss_nisplus_gethostton_r):
+ Always free lookup result [Coverity CID 135].
+
+ * nis/nss_nisplus/nisplus-ethers.c (_nss_nisplus_getntohost_r):
+ Always free lookup result [Coverity CID 136].
+
+ * nis/nss_nisplus/nisplus-network.c (_nss_nisplus_getnetbyaddr_r):
+ Before retrying, free old result [Coverity CID 137].
+
+ * nis/nss_nisplus/nisplus-publickey.c (_nss_nisplus_netname2user):
+ Free res in case UID is zero [Coverity CID 138].
+
+ * nis/ypclnt.c (yp_update): Always free master string
+ [Coverity CID 140].
+
+ * nis/nis_creategroup.c (nis_creategroup): Free all memory in
+ error cases [Coverity CID 143, 142, 141].
+
+ * nis/nss_nis/nis-publickey.c (_nss_nis_getpublickey): Free result
+ if yp_match call succeeded [Coverity CID 155].
+
+ * nis/nss_nis/nis-publickey.c (_nss_nis_getsecretkey): Free string
+ allocated in yp_match at all times [Coverity CID 157, 156].
+
+ * nscd/nscd.c (write_pid): Close stream also if writing failed
+ [Coverity CID 165].
+
+ * nis/nis_table.c (nis_add_entry): Move test for NULL parameter
+ ahead of first use [Coverity CID 167].
+
+ * nis/nss_nis/nis-alias.c (_nss_nis_getaliasbyname_r): Move test
+ for NULL parameter ahead of first use [Coverity CID 168].
+
+ * intl/finddomain.c (_nl_find_domain): We never return NULL if we
+ found the locale [Coverity CID 169].
+
+ * inet/getnameinfo.c (getnameinfo): __getservbyport_r does not set
+ herrno [Coverity CID 178].
+
+ * nis/nis_checkpoint.c (nis_checkpoint): Don't access and returned
+ freed object [Coverity CID 182].
+nptl/
+2006-04-06 Ulrich Drepper <drepper@redhat.com>
+
+ * pthread_getattr_np.c (pthread_getattr_np): Close fp if getrlimit
+ fails [Coverity CID 105].
+
+--- libc/elf/cache.c 4 Jan 2006 17:14:52 -0000 1.27
++++ libc/elf/cache.c 7 Apr 2006 03:36:30 -0000 1.28
+@@ -421,7 +420,7 @@ save_cache (const char *cache_name)
+ if (opt_format != 2)
+ {
+ if (write (fd, file_entries, file_entries_size)
+- != (ssize_t)file_entries_size)
++ != (ssize_t) file_entries_size)
+ error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
+ }
+ if (opt_format != 0)
+@@ -430,15 +429,16 @@ save_cache (const char *cache_name)
+ if (opt_format != 2)
+ {
+ char zero[pad];
+- if (write (fd, zero, pad) != (ssize_t)pad)
++ memset (zero, '\0', pad);
++ if (write (fd, zero, pad) != (ssize_t) pad)
+ error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
+ }
+ if (write (fd, file_entries_new, file_entries_new_size)
+- != (ssize_t)file_entries_new_size)
++ != (ssize_t) file_entries_new_size)
+ error (EXIT_FAILURE, errno, _("Writing of cache data failed"));
+ }
+
+- if (write (fd, strings, total_strlen) != (ssize_t)total_strlen)
++ if (write (fd, strings, total_strlen) != (ssize_t) total_strlen)
+ error (EXIT_FAILURE, errno, _("Writing of cache data failed."));
+
+ close (fd);
+@@ -455,6 +455,7 @@ save_cache (const char *cache_name)
+ cache_name);
+
+ /* Free all allocated memory. */
++ free (file_entries_new);
+ free (file_entries);
+ free (strings);
+
+--- libc/iconv/iconv_charmap.c 7 Dec 2005 05:47:27 -0000 1.4
++++ libc/iconv/iconv_charmap.c 7 Apr 2006 07:42:58 -0000 1.5
+@@ -488,7 +488,7 @@ process_fd (struct convtable *tbl, int f
+ process it in one step. */
+ static char *inbuf = NULL;
+ static size_t maxlen = 0;
+- char *inptr = NULL;
++ char *inptr = inbuf;
+ size_t actlen = 0;
+
+ while (actlen < maxlen)
+--- libc/inet/getnameinfo.c 17 Mar 2004 20:01:25 -0000 1.33
++++ libc/inet/getnameinfo.c 6 Apr 2006 21:51:24 -0000 1.34
+@@ -403,25 +403,16 @@ getnameinfo (const struct sockaddr *sa,
+ if (!(flags & NI_NUMERICSERV))
+ {
+ struct servent *s, ts;
+- while (__getservbyport_r (((const struct sockaddr_in *) sa)->sin_port,
+- ((flags & NI_DGRAM) ? "udp" : "tcp"),
+- &ts, tmpbuf, tmpbuflen, &s))
++ int e;
++ while ((e = __getservbyport_r (((const struct sockaddr_in *) sa)->sin_port,
++ ((flags & NI_DGRAM)
++ ? "udp" : "tcp"),
++ &ts, tmpbuf, tmpbuflen, &s)))
+ {
+- if (herrno == NETDB_INTERNAL)
+- {
+- if (errno == ERANGE)
+- tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
+- 2 * tmpbuflen);
+- else
+- {
+- __set_errno (serrno);
+- return EAI_SYSTEM;
+- }
+- }
++ if (e == ERANGE)
++ tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
+ else
+- {
+- break;
+- }
++ break;
+ }
+ if (s)
+ {
+--- libc/inet/inet6_option.c 14 Jun 2003 08:43:24 -0000 1.2
++++ libc/inet/inet6_option.c 7 Apr 2006 18:24:19 -0000 1.4
+@@ -251,7 +251,7 @@ inet6_option_next (cmsg, tptrp)
+ const uint8_t *endp = CMSG_DATA (cmsg) + (ip6e->ip6e_len + 1) * 8;
+
+ const uint8_t *result;
+- if (tptrp == NULL)
++ if (*tptrp == NULL)
+ /* This is the first call, return the first option if there is one. */
+ result = (const uint8_t *) (ip6e + 1);
+ else
+@@ -308,7 +308,7 @@ inet6_option_find (cmsg, tptrp, type)
+ const uint8_t *endp = CMSG_DATA (cmsg) + (ip6e->ip6e_len + 1) * 8;
+
+ const uint8_t *next;
+- if (tptrp == NULL)
++ if (*tptrp == NULL)
+ /* This is the first call, return the first option if there is one. */
+ next = (const uint8_t *) (ip6e + 1);
+ else
+--- libc/inet/rexec.c 17 Feb 2005 01:15:44 -0000 1.24
++++ libc/inet/rexec.c 7 Apr 2006 08:08:51 -0000 1.25
+@@ -87,8 +87,11 @@ rexec_af(ahost, rport, name, pass, cmd,
+ return (-1);
+ }
+ *ahost = ahostbuf;
+- } else
++ } else {
+ *ahost = NULL;
++ __set_errno (ENOENT);
++ return -1;
++ }
+ ruserpass(res0->ai_canonname, &name, &pass);
+ retry:
+ s = __socket(res0->ai_family, res0->ai_socktype, 0);
+--- libc/intl/finddomain.c 26 Sep 2004 04:30:40 -0000 1.33
++++ libc/intl/finddomain.c 7 Apr 2006 03:27:32 -0000 1.35
+@@ -110,7 +110,7 @@ _nl_find_domain (dirname, locale, domain
+ break;
+ }
+
+- return cnt >= 0 ? retval : NULL;
++ return retval;
+ /* NOTREACHED */
+ }
+
+@@ -119,20 +119,7 @@ _nl_find_domain (dirname, locale, domain
+ done. */
+ alias_value = _nl_expand_alias (locale);
+ if (alias_value != NULL)
+- {
+-#if defined _LIBC || defined HAVE_STRDUP
+- locale = strdup (alias_value);
+- if (locale == NULL)
+- return NULL;
+-#else
+- size_t len = strlen (alias_value) + 1;
+- locale = (char *) malloc (len);
+- if (locale == NULL)
+- return NULL;
+-
+- memcpy (locale, alias_value, len);
+-#endif
+- }
++ locale = strdupa (alias_value);
+
+ /* Now we determine the single parts of the locale name. First
+ look for the language. Termination symbols are `_' and `@' if
+@@ -169,10 +156,6 @@ _nl_find_domain (dirname, locale, domain
+ }
+ }
+
+- /* The room for an alias was dynamically allocated. Free it now. */
+- if (alias_value != NULL)
+- free (locale);
+-
+ /* The space for normalized_codeset is dynamically allocated. Free it. */
+ if (mask & XPG_NORM_CODESET)
+ free ((void *) normalized_codeset);
+--- libc/io/fts.c 21 Dec 2005 08:33:31 -0000 1.31
++++ libc/io/fts.c 8 Apr 2006 19:33:17 -0000 1.34
+@@ -93,7 +93,8 @@ fts_open(argv, options, compar)
+ register FTS *sp;
+ register FTSENT *p, *root;
+ register int nitems;
+- FTSENT *parent, *tmp;
++ FTSENT *parent = NULL;
++ FTSENT *tmp;
+
+ /* Options check. */
+ if (options & ~FTS_OPTIONMASK) {
+@@ -124,9 +125,11 @@ fts_open(argv, options, compar)
+ goto mem1;
+
+ /* Allocate/initialize root's parent. */
+- if ((parent = fts_alloc(sp, "", 0)) == NULL)
+- goto mem2;
+- parent->fts_level = FTS_ROOTPARENTLEVEL;
++ 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) {
+@@ -744,6 +747,10 @@ mem1: saved_errno = errno;
+ 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;
+@@ -751,7 +758,9 @@ mem1: saved_errno = errno;
+ } else
+ p->fts_info = FTS_NSOK;
+ p->fts_accpath = cur->fts_accpath;
+- } else if (nlinks == 0
++ } 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)
+@@ -819,6 +828,7 @@ mem1: saved_errno = errno;
+ fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
+ cur->fts_info = FTS_ERR;
+ SET(FTS_STOP);
++ fts_lfree(head);
+ return (NULL);
+ }
+
+@@ -826,6 +836,7 @@ mem1: saved_errno = errno;
+ if (!nitems) {
+ if (type == BREAD)
+ cur->fts_info = FTS_DP;
++ fts_lfree(head);
+ return (NULL);
+ }
+
+--- libc/libio/fmemopen.c 23 Sep 2005 16:34:35 -0000 1.12
++++ libc/libio/fmemopen.c 7 Apr 2006 04:23:37 -0000 1.13
+@@ -202,7 +202,7 @@ fmemopen (void *buf, size_t len, const c
+ cookie_io_functions_t iof;
+ fmemopen_cookie_t *c;
+
+- if (len == 0)
++ if (__builtin_expect (len == 0, 0))
+ {
+ einval:
+ __set_errno (EINVAL);
+@@ -227,8 +227,11 @@ fmemopen (void *buf, size_t len, const c
+ }
+ else
+ {
+- if ((uintptr_t) len > -(uintptr_t) buf)
+- goto einval;
++ if (__builtin_expect ((uintptr_t) len > -(uintptr_t) buf, 0))
++ {
++ free (c);
++ goto einval;
++ }
+
+ c->buffer = buf;
+ }
+--- libc/locale/programs/ld-numeric.c 7 Dec 2005 05:47:27 -0000 1.28
++++ libc/locale/programs/ld-numeric.c 7 Apr 2006 18:30:26 -0000 1.29
+@@ -302,7 +302,7 @@ numeric_read (struct linereader *ldfile,
+ {
+ size_t act = 0;
+ size_t max = 10;
+- char *grouping = ignore_content ? NULL : xmalloc (max);
++ char *grouping = xmalloc (max);
+
+ do
+ {
+@@ -321,24 +321,20 @@ numeric_read (struct linereader *ldfile,
+ }
+
+ if (now->tok == tok_minus1)
+- {
+- if (!ignore_content)
+- grouping[act++] = '\177';
+- }
++ grouping[act++] = '\177';
+ else if (now->val.num == 0)
+ {
+ /* A value of 0 disables grouping from here on but
+ we must not store a NUL character since this
+ terminates the string. Use something different
+ which must not be used otherwise. */
+- if (!ignore_content)
+- grouping[act++] = '\377';
++ grouping[act++] = '\377';
+ }
+ else if (now->val.num > 126)
+ lr_error (ldfile, _("\
+ %s: values for field `%s' must be smaller than 127"),
+ "LC_NUMERIC", "grouping");
+- else if (!ignore_content)
++ else
+ grouping[act++] = now->val.num;
+
+ /* Next must be semicolon. */
+@@ -353,13 +349,10 @@ numeric_read (struct linereader *ldfile,
+ if (now->tok != tok_eol)
+ goto err_label;
+
+- if (!ignore_content)
+- {
+- grouping[act++] = '\0';
++ grouping[act++] = '\0';
+
+- numeric->grouping = xrealloc (grouping, act);
+- numeric->grouping_len = act;
+- }
++ numeric->grouping = xrealloc (grouping, act);
++ numeric->grouping_len = act;
+ }
+ break;
+
+--- libc/locale/programs/linereader.c 7 Dec 2005 05:47:27 -0000 1.32
++++ libc/locale/programs/linereader.c 7 Apr 2006 18:33:17 -0000 1.33
+@@ -214,12 +214,6 @@ lr_token (struct linereader *lr, const s
+ }
+ while (isspace (ch));
+
+- if (ch == EOF)
+- {
+- lr->token.tok = tok_eof;
+- return &lr->token;
+- };
+-
+ if (ch != lr->comment_char)
+ break;
+
+--- libc/misc/tsearch.c 6 Jul 2001 04:55:36 -0000 1.11
++++ libc/misc/tsearch.c 2 May 2006 00:48:29 -0000 1.13
+@@ -285,11 +285,12 @@ __tsearch (const void *key, void **vroot
+ q->key = key; /* initialize new node */
+ q->red = 1;
+ q->left = q->right = NULL;
++
++ if (nextp != rootp)
++ /* There may be two red edges in a row now, which we must avoid by
++ rotating the tree. */
++ maybe_split_for_insert (nextp, rootp, parentp, r, p_r, 1);
+ }
+- if (nextp != rootp)
+- /* There may be two red edges in a row now, which we must avoid by
+- rotating the tree. */
+- maybe_split_for_insert (nextp, rootp, parentp, r, p_r, 1);
+
+ return q;
+ }
+@@ -446,7 +447,7 @@ __tdelete (const void *key, void **vroot
+ /* Q is R's brother, P is R's parent. The subtree with root
+ R has one black edge less than the subtree with root Q. */
+ q = p->right;
+- if (q != NULL && q->red)
++ if (q->red)
+ {
+ /* If Q is red, we know that P is black. We rotate P left
+ so that Q becomes the top node in the tree, with P below
+@@ -534,7 +535,7 @@ __tdelete (const void *key, void **vroot
+ {
+ /* Comments: see above. */
+ q = p->left;
+- if (q != NULL && q->red)
++ if (q->red)
+ {
+ q->red = 0;
+ p->red = 1;
+--- libc/nis/nis_checkpoint.c 6 Jul 2001 04:55:36 -0000 1.10
++++ libc/nis/nis_checkpoint.c 6 Apr 2006 21:23:46 -0000 1.11
+@@ -24,7 +24,7 @@
+ #include "nis_intern.h"
+
+ nis_result *
+-nis_checkpoint(const_nis_name dirname)
++nis_checkpoint (const_nis_name dirname)
+ {
+ nis_result *res;
+
+@@ -48,7 +48,6 @@ nis_checkpoint(const_nis_name dirname)
+ if (__type_of (NIS_RES_OBJECT (res2)) != NIS_DIRECTORY_OBJ)
+ {
+ nis_freeresult (res2);
+- nis_freeresult (res);
+ NIS_RES_STATUS (res) = NIS_INVALIDOBJ;
+ return res;
+ }
+--- libc/nis/nis_clone_dir.c 17 Feb 2005 01:17:24 -0000 1.4
++++ libc/nis/nis_clone_dir.c 7 Apr 2006 03:53:09 -0000 1.5
+@@ -29,15 +29,24 @@ nis_clone_directory (const directory_obj
+ char *addr;
+ unsigned int size;
+ XDR xdrs;
+- directory_obj *res;
+
+ if (src == NULL)
+- return (NULL);
++ return NULL;
+
+ size = xdr_sizeof ((xdrproc_t)_xdr_directory_obj, (char *)src);
+ if ((addr = calloc(1, size)) == NULL)
+ return NULL;
+
++ xdrmem_create(&xdrs, addr, size, XDR_ENCODE);
++ if (!_xdr_directory_obj (&xdrs, (directory_obj *)src))
++ {
++ xdr_destroy (&xdrs);
++ free (addr);
++ return NULL;
++ }
++ xdr_destroy (&xdrs);
++
++ directory_obj *res;
+ if (dest == NULL)
+ {
+ if ((res = calloc (1, sizeof (directory_obj))) == NULL)
+@@ -49,18 +58,12 @@ nis_clone_directory (const directory_obj
+ else
+ res = dest;
+
+- xdrmem_create(&xdrs, addr, size, XDR_ENCODE);
+- if (!_xdr_directory_obj (&xdrs, (directory_obj *)src))
+- {
+- xdr_destroy (&xdrs);
+- free (addr);
+- return NULL;
+- }
+- xdr_destroy (&xdrs);
+ xdrmem_create (&xdrs, addr, size, XDR_DECODE);
+ if (!_xdr_directory_obj (&xdrs, res))
+ {
+ xdr_destroy (&xdrs);
++ if (res != dest)
++ free (res);
+ free (addr);
+ return NULL;
+ }
+--- libc/nis/nis_clone_res.c 17 Feb 2005 01:17:24 -0000 1.4
++++ libc/nis/nis_clone_res.c 7 Apr 2006 03:51:17 -0000 1.6
+@@ -29,7 +29,6 @@ nis_clone_result (const nis_result *src,
+ char *addr;
+ unsigned int size;
+ XDR xdrs;
+- nis_result *res;
+
+ if (src == NULL)
+ return (NULL);
+@@ -38,6 +37,16 @@ nis_clone_result (const nis_result *src,
+ if ((addr = calloc(1, size)) == NULL)
+ return NULL;
+
++ xdrmem_create (&xdrs, addr, size, XDR_ENCODE);
++ if (!_xdr_nis_result (&xdrs, (nis_result *)src))
++ {
++ xdr_destroy (&xdrs);
++ free (addr);
++ return NULL;
++ }
++ xdr_destroy (&xdrs);
++
++ nis_result *res;
+ if (dest == NULL)
+ {
+ if ((res = calloc (1, sizeof (nis_result))) == NULL)
+@@ -49,18 +58,12 @@ nis_clone_result (const nis_result *src,
+ else
+ res = dest;
+
+- xdrmem_create(&xdrs, addr, size, XDR_ENCODE);
+- if (!_xdr_nis_result (&xdrs, (nis_result *)src))
+- {
+- xdr_destroy (&xdrs);
+- free (addr);
+- return NULL;
+- }
+- xdr_destroy (&xdrs);
+- xdrmem_create(&xdrs, addr, size, XDR_DECODE);
+- if (!_xdr_nis_result(&xdrs, res))
++ xdrmem_create (&xdrs, addr, size, XDR_DECODE);
++ if (!_xdr_nis_result (&xdrs, res))
+ {
+ xdr_destroy (&xdrs);
++ if (res != dest)
++ free (res);
+ free (addr);
+ return NULL;
+ }
+--- libc/nis/nis_creategroup.c 6 Jul 2001 04:55:36 -0000 1.10
++++ libc/nis/nis_creategroup.c 6 Apr 2006 23:58:16 -0000 1.12
+@@ -46,7 +46,7 @@ nis_creategroup (const_nis_name group, u
+ else
+ return NIS_BADNAME;
+
+- obj = malloc (sizeof (nis_object));
++ obj = calloc (1, sizeof (nis_object));
+ if (__builtin_expect (obj == NULL, 0))
+ return NIS_NOMEMORY;
+
+@@ -57,7 +57,13 @@ nis_creategroup (const_nis_name group, u
+ obj->zo_domain = strdup (domainbuf);
+ if (obj->zo_name == NULL || obj->zo_owner == NULL
+ || obj->zo_group == NULL || obj->zo_domain == NULL)
+- return NIS_NOMEMORY;
++ {
++ free (obj->zo_group);
++ free (obj->zo_owner);
++ free (obj->zo_name);
++ free (obj);
++ return NIS_NOMEMORY;
++ }
+ obj->zo_access = __nis_default_access (NULL, 0);
+ obj->zo_ttl = 60 * 60;
+ obj->zo_data.zo_type = NIS_GROUP_OBJ;
+@@ -66,11 +72,11 @@ nis_creategroup (const_nis_name group, u
+ obj->zo_data.objdata_u.gr_data.gr_members.gr_members_val = NULL;
+
+ res = nis_add (buf, obj);
++ nis_free_object (obj);
+ if (res == NULL)
+ return NIS_NOMEMORY;
+ status = NIS_RES_STATUS (res);
+ nis_freeresult (res);
+- nis_free_object (obj);
+
+ return status;
+ }
+--- libc/nis/nis_getservlist.c 6 Jul 2001 04:55:36 -0000 1.8
++++ libc/nis/nis_getservlist.c 8 Apr 2006 19:24:07 -0000 1.11
+@@ -40,7 +40,10 @@ nis_getservlist (const_nis_name dir)
+ malloc (sizeof (nis_server *) *
+ (NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_len + 1));
+ if (__builtin_expect (serv == NULL, 0))
+- return NULL;
++ {
++ nis_freeresult (res);
++ return NULL;
++ }
+
+ for (i = 0; i < NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_len;
+ ++i)
+@@ -49,13 +52,41 @@ nis_getservlist (const_nis_name dir)
+ &NIS_RES_OBJECT (res)->DI_data.do_servers.do_servers_val[i];
+ serv[i] = calloc (1, sizeof (nis_server));
+ if (__builtin_expect (serv[i] == NULL, 0))
+- return NULL;
++ {
++ free_all:
++ while (i-- > 0)
++ {
++ free (serv[i]->pkey.n_bytes);
++ if (serv[i]->ep.ep_val != NULL)
++ {
++ unsigned long int j;
++ for (j = 0; j < serv[i]->ep.ep_len; ++j)
++ {
++ free (serv[i]->ep.ep_val[j].proto);
++ free (serv[i]->ep.ep_val[j].family);
++ free (serv[i]->ep.ep_val[j].uaddr);
++ }
++ free (serv[i]->ep.ep_val);
++ }
++ free (serv[i]->name);
++ free (serv[i]);
++ }
++
++ free (serv);
++
++ nis_freeresult (res);
++
++ return NULL;
++ }
+
+ if (server->name != NULL)
+ {
+ serv[i]->name = strdup (server->name);
+ if (__builtin_expect (serv[i]->name == NULL, 0))
+- return NULL;
++ {
++ ++i;
++ goto free_all;
++ }
+ }
+
+ serv[i]->ep.ep_len = server->ep.ep_len;
+@@ -66,7 +97,10 @@ nis_getservlist (const_nis_name dir)
+ serv[i]->ep.ep_val =
+ malloc (server->ep.ep_len * sizeof (endpoint));
+ if (__builtin_expect (serv[i]->ep.ep_val == NULL, 0))
+- return NULL;
++ {
++ ++i;
++ goto free_all;
++ }
+
+ for (j = 0; j < serv[i]->ep.ep_len; ++j)
+ {
+@@ -87,20 +121,20 @@ nis_getservlist (const_nis_name dir)
+ serv[i]->ep.ep_val[j].proto = NULL;
+ }
+ }
+- else
+- serv[i]->ep.ep_val = NULL;
++
+ serv[i]->key_type = server->key_type;
+ serv[i]->pkey.n_len = server->pkey.n_len;
+ if (server->pkey.n_len > 0)
+ {
+ serv[i]->pkey.n_bytes = malloc (server->pkey.n_len);
+ if (__builtin_expect (serv[i]->pkey.n_bytes == NULL, 0))
+- return NULL;
++ {
++ ++i;
++ goto free_all;
++ }
+ memcpy (serv[i]->pkey.n_bytes, server->pkey.n_bytes,
+ server->pkey.n_len);
+ }
+- else
+- serv[i]->pkey.n_bytes = NULL;
+ }
+ serv[i] = NULL;
+ }
+@@ -111,8 +145,7 @@ nis_getservlist (const_nis_name dir)
+ serv[0] = NULL;
+ }
+
+- if (res != NULL)
+- nis_freeresult (res);
++ nis_freeresult (res);
+
+ return serv;
+ }
+--- libc/nis/nis_print_group_entry.c 25 Mar 2004 03:51:53 -0000 1.9
++++ libc/nis/nis_print_group_entry.c 7 Apr 2006 00:39:14 -0000 1.10
+@@ -45,12 +45,16 @@ nis_print_group_entry (const_nis_name gr
+ }
+ res = nis_lookup (buf, FOLLOW_LINKS | EXPAND_NAME);
+
+- if (NIS_RES_STATUS(res) != NIS_SUCCESS)
++ if (res == NULL)
+ return;
+
+- if ((NIS_RES_NUMOBJ (res) != 1) ||
+- (__type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ))
+- return;
++ if (NIS_RES_STATUS (res) != NIS_SUCCESS
++ || NIS_RES_NUMOBJ (res) != 1
++ || __type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ)
++ {
++ nis_freeresult (res);
++ return;
++ }
+
+ char *mem_exp[NIS_RES_NUMOBJ (res)];
+ char *mem_imp[NIS_RES_NUMOBJ (res)];
+--- libc/nis/nis_removemember.c 29 Apr 2005 09:18:00 -0000 1.11
++++ libc/nis/nis_removemember.c 7 Apr 2006 00:34:55 -0000 1.12
+@@ -68,7 +68,10 @@ nis_removemember (const_nis_name member,
+ calloc (NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len,
+ sizeof (char *));
+ if (newmem == NULL)
+- return NIS_NOMEMORY;
++ {
++ nis_freeresult (res);
++ return NIS_NOMEMORY;
++ }
+
+ k = NIS_RES_OBJECT (res)[0].GR_data.gr_members.gr_members_len;
+ j = 0;
+@@ -96,6 +99,7 @@ nis_removemember (const_nis_name member,
+ if (newp == NULL)
+ {
+ free (newmem);
++ nis_freeresult (res);
+ return NIS_NOMEMORY;
+ }
+ newmem = newp;
+--- libc/nis/nis_table.c 8 Dec 2005 04:11:05 -0000 1.30
++++ libc/nis/nis_table.c 7 Apr 2006 00:56:07 -0000 1.32
+@@ -41,7 +41,15 @@ __create_ib_request (const_nis_name name
+
+ /* Not of "[key=value,key=value,...],foo.." format? */
+ if (cptr[0] != '[')
+- return (ibreq->ibr_name = strdup (cptr)) == NULL ? NULL : ibreq;
++ {
++ ibreq->ibr_name = strdup (cptr);
++ if (ibreq->ibr_name == NULL)
++ {
++ free (ibreq);
++ return NULL;
++ }
++ return ibreq;
++ }
+
+ /* "[key=value,...],foo" format */
+ ibreq->ibr_name = strchr (cptr, ']');
+@@ -497,15 +505,7 @@ libnsl_hidden_def (nis_list)
+ nis_result *
+ nis_add_entry (const_nis_name name, const nis_object *obj2, unsigned int flags)
+ {
+- nis_object obj;
+- nis_result *res;
+- nis_error status;
+- ib_request *ibreq;
+- size_t namelen = strlen (name);
+- char buf1[namelen + 20];
+- char buf4[namelen + 20];
+-
+- res = calloc (1, sizeof (nis_result));
++ nis_result *res = calloc (1, sizeof (nis_result));
+ if (res == NULL)
+ return NULL;
+
+@@ -515,12 +515,18 @@ nis_add_entry (const_nis_name name, cons
+ return res;
+ }
+
+- if ((ibreq = __create_ib_request (name, flags)) == NULL)
++ size_t namelen = strlen (name);
++ char buf1[namelen + 20];
++ char buf4[namelen + 20];
++
++ ib_request *ibreq = __create_ib_request (name, flags);
++ if (ibreq == NULL)
+ {
+ NIS_RES_STATUS (res) = NIS_BADNAME;
+ return res;
+ }
+
++ nis_object obj;
+ memcpy (&obj, obj2, sizeof (nis_object));
+
+ if (obj.zo_name == NULL || strlen (obj.zo_name) == 0)
+@@ -543,11 +549,12 @@ nis_add_entry (const_nis_name name, cons
+ }
+ ibreq->ibr_obj.ibr_obj_len = 1;
+
+- if ((status = __do_niscall (ibreq->ibr_name, NIS_IBADD,
+- (xdrproc_t) _xdr_ib_request,
+- (caddr_t) ibreq,
+- (xdrproc_t) _xdr_nis_result,
+- (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
++ nis_error status = __do_niscall (ibreq->ibr_name, NIS_IBADD,
++ (xdrproc_t) _xdr_ib_request,
++ (caddr_t) ibreq,
++ (xdrproc_t) _xdr_nis_result,
++ (caddr_t) res, 0, NULL);
++ if (status != NIS_SUCCESS)
+ NIS_RES_STATUS (res) = status;
+
+ nis_free_request (ibreq);
+--- libc/nis/ypclnt.c 22 Feb 2006 10:02:50 -0000 1.56
++++ libc/nis/ypclnt.c 6 Apr 2006 23:59:35 -0000 1.57
+@@ -955,16 +955,22 @@ yp_update (char *domain, char *map, unsi
+ args.update_args.datum.yp_buf_len = datalen;
+ args.update_args.datum.yp_buf_val = data;
+
+- if ((r = yp_master (domain, map, &master)) != 0)
++ if ((r = yp_master (domain, map, &master)) != YPERR_SUCCESS)
+ return r;
+
+ if (!host2netname (servername, master, domain))
+ {
+ fputs (_("yp_update: cannot convert host to netname\n"), stderr);
++ free (master);
+ return YPERR_YPERR;
+ }
+
+- if ((clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp")) == NULL)
++ clnt = clnt_create (master, YPU_PROG, YPU_VERS, "tcp");
++
++ /* We do not need the string anymore. */
++ free (master);
++
++ if (clnt == NULL)
+ {
+ clnt_pcreateerror ("yp_update: clnt_create");
+ return YPERR_RPC;
+--- libc/nis/nss_nis/nis-alias.c 16 Mar 2003 03:36:21 -0000 1.16
++++ libc/nis/nss_nis/nis-alias.c 6 Apr 2006 22:40:12 -0000 1.17
+@@ -206,32 +206,29 @@ enum nss_status
+ _nss_nis_getaliasbyname_r (const char *name, struct aliasent *alias,
+ char *buffer, size_t buflen, int *errnop)
+ {
+- enum nss_status retval;
+- int parse_res;
+- char *domain;
+- char *result;
+- int len;
+- char *p;
+- size_t namlen = strlen (name);
+- char name2[namlen + 1];
+- size_t i;
+-
+ if (name == NULL)
+ {
+ *errnop = EINVAL;
+ return NSS_STATUS_UNAVAIL;
+ }
+
++ size_t namlen = strlen (name);
++ char name2[namlen + 1];
++
++ char *domain;
+ if (yp_get_default_domain (&domain))
+ return NSS_STATUS_UNAVAIL;
+
+ /* Convert name to lowercase. */
++ size_t i;
+ for (i = 0; i < namlen; ++i)
+ name2[i] = _tolower (name[i]);
+ name2[i] = '\0';
+
+- retval = yperr2nss (yp_match (domain, "mail.aliases", name2, namlen,
+- &result, &len));
++ char *result;
++ int len;
++ enum nss_status retval = yperr2nss (yp_match (domain, "mail.aliases", name2,
++ namlen, &result, &len));
+
+ if (retval != NSS_STATUS_SUCCESS)
+ {
+@@ -247,14 +244,15 @@ _nss_nis_getaliasbyname_r (const char *n
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- p = strncpy (buffer, result, len);
++ char *p = strncpy (buffer, result, len);
+ buffer[len] = '\0';
+ while (isspace (*p))
+ ++p;
+ free (result);
+
+ alias->alias_local = 0;
+- parse_res = _nss_nis_parse_aliasent (name, p, alias, buffer, buflen, errnop);
++ int parse_res = _nss_nis_parse_aliasent (name, p, alias, buffer, buflen,
++ errnop);
+ if (parse_res < 1)
+ {
+ if (parse_res == -1)
+--- libc/nis/nss_nis/nis-publickey.c 28 Oct 2005 22:38:59 -0000 1.14
++++ libc/nis/nss_nis/nis-publickey.c 6 Apr 2006 23:22:40 -0000 1.16
+@@ -73,6 +73,7 @@ _nss_nis_getpublickey (const char *netna
+ *p = 0;
+ strncpy (pkey, result, HEXKEYBYTES + 1);
+ pkey[HEXKEYBYTES] = '\0';
++ free (result);
+ }
+ return NSS_STATUS_SUCCESS;
+ }
+@@ -115,20 +116,20 @@ _nss_nis_getsecretkey (const char *netna
+ if (result != NULL)
+ {
+ char *p = strchr (result, ':');
+- if (p == NULL)
+- return NSS_STATUS_SUCCESS;
+-
+- ++p;
+- strncpy (buf, p, 2 * (HEXKEYBYTES + 1));
+- buf[2 * HEXKEYBYTES + 1] = '\0';
+- if (!xdecrypt (buf, passwd))
+- return NSS_STATUS_SUCCESS;
+-
+- if (memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) != 0)
+- return NSS_STATUS_SUCCESS;
++ if (p != NULL)
++ {
++ ++p;
++ strncpy (buf, p, 2 * (HEXKEYBYTES + 1));
++ buf[2 * HEXKEYBYTES + 1] = '\0';
++ if (xdecrypt (buf, passwd)
++ && memcmp (buf, &(buf[HEXKEYBYTES]), KEYCHECKSUMSIZE) == 0)
++ {
++ buf[HEXKEYBYTES] = '\0';
++ strcpy (skey, buf);
++ }
++ }
+
+- buf[HEXKEYBYTES] = '\0';
+- strcpy (skey, buf);
++ free (result);
+ }
+ return NSS_STATUS_SUCCESS;
+ }
+--- libc/nis/nss_nisplus/nisplus-alias.c 25 Mar 2006 20:59:19 -0000 1.18
++++ libc/nis/nss_nisplus/nisplus-alias.c 7 Apr 2006 00:27:14 -0000 1.19
+@@ -304,10 +304,18 @@ _nss_nisplus_getaliasbyname_r (const cha
+ }
+
+ if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
+- return niserr2nss (result->status);
++ {
++ enum nss_status status = niserr2nss (result->status);
++ nis_freeresult (result);
++ return status;
++ }
+
+ parse_res = _nss_nisplus_parse_aliasent (result, 0, alias,
+ buffer, buflen, errnop);
++
++ /* We do not need the lookup result anymore. */
++ nis_freeresult (result);
++
+ if (__builtin_expect (parse_res < 1, 0))
+ {
+ __set_errno (olderr);
+--- libc/nis/nss_nisplus/nisplus-ethers.c 25 Mar 2006 20:59:19 -0000 1.22
++++ libc/nis/nss_nisplus/nisplus-ethers.c 7 Apr 2006 00:23:49 -0000 1.24
+@@ -261,17 +261,18 @@ _nss_nisplus_gethostton_r (const char *n
+
+ int parse_res = _nss_nisplus_parse_etherent (result, eth, buffer,
+ buflen, errnop);
++
++ /* We do not need the lookup result anymore. */
++ nis_freeresult (result);
++
+ if (__builtin_expect (parse_res < 1, 0))
+ {
+ __set_errno (olderr);
+
+ if (parse_res == -1)
+- {
+- nis_freeresult (result);
+- return NSS_STATUS_TRYAGAIN;
+- }
+- else
+- return NSS_STATUS_NOTFOUND;
++ return NSS_STATUS_TRYAGAIN;
++
++ return NSS_STATUS_NOTFOUND;
+ }
+
+ return NSS_STATUS_SUCCESS;
+@@ -326,13 +327,14 @@ _nss_nisplus_getntohost_r (const struct
+
+ int parse_res = _nss_nisplus_parse_etherent (result, eth, buffer,
+ buflen, errnop);
++
++ /* We do not need the lookup result anymore. */
++ nis_freeresult (result);
++
+ if (__builtin_expect (parse_res < 1, 0))
+ {
+ if (parse_res == -1)
+- {
+- nis_freeresult (result);
+- return NSS_STATUS_TRYAGAIN;
+- }
++ return NSS_STATUS_TRYAGAIN;
+
+ return NSS_STATUS_NOTFOUND;
+ }
+--- libc/nis/nss_nisplus/nisplus-network.c 25 Mar 2006 20:59:19 -0000 1.22
++++ libc/nis/nss_nisplus/nisplus-network.c 7 Apr 2006 00:14:50 -0000 1.23
+@@ -443,6 +443,7 @@ _nss_nisplus_getnetbyaddr_r (uint32_t ad
+ removed (one by one) */
+ buf2[b2len - 2] = '\0';
+ b2len -= 2;
++ nis_freeresult (result);
+ continue;
+ }
+
+--- libc/nis/nss_nisplus/nisplus-publickey.c 3 Dec 2005 22:08:17 -0000 1.17
++++ libc/nis/nss_nisplus/nisplus-publickey.c 7 Apr 2006 00:11:09 -0000 1.18
+@@ -394,6 +394,7 @@ _nss_nisplus_netname2user (char netname[
+ if (*uidp == 0)
+ {
+ syslog (LOG_ERR, _("netname2user: should not have uid 0"));
++ nis_freeresult (res);
+ return NSS_STATUS_NOTFOUND;
+ }
+
+--- libc/nptl/pthread_getattr_np.c 16 Apr 2004 23:49:09 -0000 1.11
++++ libc/nptl/pthread_getattr_np.c 7 Apr 2006 04:26:42 -0000 1.12
+@@ -83,51 +83,55 @@ pthread_getattr_np (thread_id, attr)
+ if (fp == NULL)
+ ret = errno;
+ /* We need the limit of the stack in any case. */
+- else if (getrlimit (RLIMIT_STACK, &rl) != 0)
+- ret = errno;
+ else
+ {
+- /* We need no locking. */
+- __fsetlocking (fp, FSETLOCKING_BYCALLER);
+-
+- /* Until we found an entry (which should always be the case)
+- mark the result as a failure. */
+- ret = ENOENT;
+-
+- char *line = NULL;
+- size_t linelen = 0;
+- uintptr_t last_to = 0;
+-
+- while (! feof_unlocked (fp))
++ if (getrlimit (RLIMIT_STACK, &rl) != 0)
++ ret = errno;
++ else
+ {
+- if (__getdelim (&line, &linelen, '\n', fp) <= 0)
+- break;
++ /* We need no locking. */
++ __fsetlocking (fp, FSETLOCKING_BYCALLER);
+
+- uintptr_t from;
+- uintptr_t to;
+- if (sscanf (line, "%" SCNxPTR "-%" SCNxPTR, &from, &to) != 2)
+- continue;
+- if (from <= (uintptr_t) __libc_stack_end
+- && (uintptr_t) __libc_stack_end < to)
++ /* Until we found an entry (which should always be the case)
++ mark the result as a failure. */
++ ret = ENOENT;
++
++ char *line = NULL;
++ size_t linelen = 0;
++ uintptr_t last_to = 0;
++
++ while (! feof_unlocked (fp))
+ {
+- /* Found the entry. Now we have the info we need. */
+- iattr->stacksize = rl.rlim_cur;
+- iattr->stackaddr = (void *) to;
+-
+- /* The limit might be too high. */
+- if ((size_t) iattr->stacksize
+- > (size_t) iattr->stackaddr - last_to)
+- iattr->stacksize = (size_t) iattr->stackaddr - last_to;
+-
+- /* We succeed and no need to look further. */
+- ret = 0;
+- break;
++ if (__getdelim (&line, &linelen, '\n', fp) <= 0)
++ break;
++
++ uintptr_t from;
++ uintptr_t to;
++ if (sscanf (line, "%" SCNxPTR "-%" SCNxPTR, &from, &to) != 2)
++ continue;
++ if (from <= (uintptr_t) __libc_stack_end
++ && (uintptr_t) __libc_stack_end < to)
++ {
++ /* Found the entry. Now we have the info we need. */
++ iattr->stacksize = rl.rlim_cur;
++ iattr->stackaddr = (void *) to;
++
++ /* The limit might be too high. */
++ if ((size_t) iattr->stacksize
++ > (size_t) iattr->stackaddr - last_to)
++ iattr->stacksize = (size_t) iattr->stackaddr - last_to;
++
++ /* We succeed and no need to look further. */
++ ret = 0;
++ break;
++ }
++ last_to = to;
+ }
+- last_to = to;
++
++ free (line);
+ }
+
+ fclose (fp);
+- free (line);
+ }
+ }
+
+--- libc/nscd/nscd.c 1 Jan 2006 19:15:56 -0000 1.51
++++ libc/nscd/nscd.c 6 Apr 2006 22:55:50 -0000 1.52
+@@ -487,10 +487,10 @@ write_pid (const char *file)
+ return -1;
+
+ fprintf (fp, "%d\n", getpid ());
+- if (fflush (fp) || ferror (fp))
+- return -1;
++
++ int result = fflush (fp) || ferror (fp) ? -1 : 0;
+
+ fclose (fp);
+
+- return 0;
++ return result;
+ }
+--- libc/nss/nss_files/files-key.c 6 Jul 2001 04:55:38 -0000 1.2
++++ libc/nss/nss_files/files-key.c 7 Apr 2006 04:19:55 -0000 1.3
+@@ -78,6 +78,7 @@ search (const char *netname, char *resul
+ p = __strtok_r (NULL, ":\n", &save_ptr);
+ if (p == NULL) /* malformed line? */
+ continue;
++ fclose (stream);
+ strcpy (result, p);
+ return NSS_STATUS_SUCCESS;
+ }
+--- libc/sunrpc/rpc_cout.c 21 Nov 2005 15:43:03 -0000 1.15
++++ libc/sunrpc/rpc_cout.c 7 Apr 2006 04:08:05 -0000 1.16
+@@ -551,6 +551,7 @@ inline_struct (definition *def, int flag
+ }
+ size = 0;
+ i = 0;
++ free (sizestr);
+ sizestr = NULL;
+ print_stat (indent + 1, &dl->decl);
+ }
+--- libc/sunrpc/rpc_main.c 21 Nov 2005 15:43:03 -0000 1.26
++++ libc/sunrpc/rpc_main.c 7 Apr 2006 03:14:00 -0000 1.29
+@@ -531,7 +531,7 @@ generate_guard (const char *pathname)
+
+ filename = strrchr (pathname, '/'); /* find last component */
+ filename = ((filename == NULL) ? pathname : filename + 1);
+- guard = strdup (filename);
++ guard = extendfile (filename, "_H_RPCGEN");
+ /* convert to upper case */
+ tmp = guard;
+ while (*tmp)
+@@ -541,7 +541,6 @@ generate_guard (const char *pathname)
+ tmp++;
+ }
+
+- guard = extendfile (guard, "_H_RPCGEN");
+ return guard;
+ }
+
+@@ -661,6 +660,7 @@ h_output (const char *infile, const char
+ }
+
+ fprintf (fout, "\n#endif /* !_%s */\n", guard);
++ free (guard);
+ close_input ();
+ close_output (outfilename);
+ }
+@@ -946,6 +946,8 @@ clnt_output (const char *infile, const c
+ close_output (outfilename);
+ }
+
++static const char space[] = " ";
++
+ static char *
+ file_name (const char *file, const char *ext)
+ {
+@@ -954,16 +956,17 @@ file_name (const char *file, const char
+
+ if (access (temp, F_OK) != -1)
+ return (temp);
+- else
+- return ((char *) " ");
++
++ free (temp);
++ return (char *) space;
+ }
+
+ static void
+ mkfile_output (struct commandline *cmd)
+ {
+ char *mkfilename;
+- const char *clientname, *clntname, *xdrname, *hdrname;
+- const char *servername, *svcname, *servprogname, *clntprogname;
++ char *clientname, *clntname, *xdrname, *hdrname;
++ char *servername, *svcname, *servprogname, *clntprogname;
+
+ svcname = file_name (cmd->infile, "_svc.c");
+ clntname = file_name (cmd->infile, "_clnt.c");
+@@ -977,8 +980,8 @@ mkfile_output (struct commandline *cmd)
+ }
+ else
+ {
+- servername = " ";
+- clientname = " ";
++ servername = (char *) space;
++ clientname = (char *) space;
+ }
+ servprogname = extendfile (cmd->infile, "_server");
+ clntprogname = extendfile (cmd->infile, "_client");
+@@ -988,6 +991,8 @@ mkfile_output (struct commandline *cmd)
+ char *cp, *temp;
+
+ mkfilename = alloc (strlen ("Makefile.") + strlen (cmd->infile) + 1);
++ if (mkfilename == NULL)
++ abort ();
+ temp = rindex (cmd->infile, '.');
+ cp = stpcpy (mkfilename, "Makefile.");
+ strncpy (cp, cmd->infile, (temp - cmd->infile));
+@@ -1046,6 +1051,23 @@ $(LDLIBS) \n\n");
+ f_print (fout, "clean:\n\t $(RM) core $(TARGETS) $(OBJECTS_CLNT) \
+ $(OBJECTS_SVC) $(CLIENT) $(SERVER)\n\n");
+ close_output (mkfilename);
++
++ free (clntprogname);
++ free (servprogname);
++ if (servername != space)
++ free (servername);
++ if (clientname != space)
++ free (clientname);
++ if (mkfilename != (char *) cmd->outfile)
++ free (mkfilename);
++ if (svcname != space)
++ free (svcname);
++ if (clntname != space)
++ free (clntname);
++ if (xdrname != space)
++ free (xdrname);
++ if (hdrname != space)
++ free (hdrname);
+ }
+
+ /*
+--- libc/sunrpc/rpc_parse.c 21 Nov 2005 15:43:03 -0000 1.9
++++ libc/sunrpc/rpc_parse.c 7 Apr 2006 18:36:30 -0000 1.11
+@@ -91,6 +91,7 @@ get_definition (void)
+ def_const (defp);
+ break;
+ case TOK_EOF:
++ free (defp);
+ return (NULL);
+ default:
+ error ("definition keyword expected");
+@@ -302,7 +303,9 @@ def_union (definition *defp)
+ case_list *cases;
+ /* case_list *tcase; */
+ case_list **tailp;
++#if 0
+ int flag;
++#endif
+
+ defp->def_kind = DEF_UNION;
+ scan (TOK_IDENT, &tok);
+@@ -322,7 +325,9 @@ def_union (definition *defp)
+ cases->case_name = tok.str;
+ scan (TOK_COLON, &tok);
+ /* now peek at next token */
++#if 0
+ flag = 0;
++#endif
+ if (peekscan (TOK_CASE, &tok))
+ {
+
+@@ -339,6 +344,7 @@ def_union (definition *defp)
+ }
+ while (peekscan (TOK_CASE, &tok));
+ }
++#if 0
+ else if (flag)
+ {
+
+@@ -346,6 +352,7 @@ def_union (definition *defp)
+ tailp = &cases->next;
+ cases = ALLOC (case_list);
+ };
++#endif
+
+ get_declaration (&dec, DEF_UNION);
+ cases->case_decl = dec;
+--- libc/sunrpc/rpc_scan.c 21 Nov 2005 15:43:03 -0000 1.10
++++ libc/sunrpc/rpc_scan.c 7 Apr 2006 04:04:15 -0000 1.11
+@@ -535,6 +535,7 @@ docppline (const char *line, int *lineno
+ *p = 0;
+ if (*file == 0)
+ {
++ free (file);
+ *fname = NULL;
+ }
+ else
+--- libc/sunrpc/svc_udp.c 20 Jul 2005 17:50:28 -0000 1.23
++++ libc/sunrpc/svc_udp.c 7 Apr 2006 02:18:55 -0000 1.26
+@@ -485,6 +485,7 @@ svcudp_enablecache (SVCXPRT *transp, u_l
+ uc->uc_entries = ALLOC (cache_ptr, size * SPARSENESS);
+ if (uc->uc_entries == NULL)
+ {
++ mem_free (uc, sizeof (struct udp_cache));
+ CACHE_PERROR (_("enablecache: could not allocate cache data"));
+ return 0;
+ }
+@@ -492,6 +493,8 @@ svcudp_enablecache (SVCXPRT *transp, u_l
+ uc->uc_fifo = ALLOC (cache_ptr, size);
+ if (uc->uc_fifo == NULL)
+ {
++ mem_free (uc->uc_entries, size * SPARSENESS);
++ mem_free (uc, sizeof (struct udp_cache));
+ CACHE_PERROR (_("enablecache: could not allocate cache fifo"));
+ return 0;
+ }
+@@ -545,6 +548,7 @@ cache_set (SVCXPRT *xprt, u_long replyle
+ newbuf = mem_alloc (su->su_iosz);
+ if (newbuf == NULL)
+ {
++ mem_free (victim, sizeof (struct cache_node));
+ CACHE_PERROR (_("cache_set: could not allocate new rpc_buffer"));
+ return;
+ }
+--- libc/sysdeps/generic/unwind-dw2-fde.c 18 May 2004 21:18:52 -0000 1.7
++++ libc/sysdeps/generic/unwind-dw2-fde.c 7 Apr 2006 20:50:31 -0000 1.8
+@@ -595,7 +595,7 @@ end_fde_sort (struct object *ob, struct
+ {
+ fde_compare_t fde_compare;
+
+- if (accu->linear && accu->linear->count != count)
++ if (accu->linear->count != count)
+ abort ();
+
+ if (ob->s.b.mixed_encoding)
+--- libc/sysdeps/generic/unwind-dw2.c 21 Dec 2005 21:36:17 -0000 1.10
++++ libc/sysdeps/generic/unwind-dw2.c 2 May 2006 00:45:11 -0000 1.15
+@@ -25,6 +25,7 @@
+ #include <error.h>
+ #include <libintl.h>
+ #include <dwarf2.h>
++#include <stdio.h>
+ #include <unwind.h>
+ #include <unwind-pe.h>
+ #include <unwind-dw2-fde.h>
+@@ -837,9 +838,16 @@ execute_cfa_program (const unsigned char
+ case DW_CFA_restore_state:
+ {
+ struct frame_state_reg_info *old_rs = fs->regs.prev;
+- fs->regs = *old_rs;
+- old_rs->prev = unused_rs;
+- unused_rs = old_rs;
++#ifdef _LIBC
++ if (old_rs == NULL)
++ __libc_fatal ("invalid DWARF unwind data");
++ else
++#endif
++ {
++ fs->regs = *old_rs;
++ old_rs->prev = unused_rs;
++ unused_rs = old_rs;
++ }
+ }
+ break;
+
+@@ -897,12 +905,16 @@ execute_cfa_program (const unsigned char
+ break;
+
+ case DW_CFA_GNU_window_save:
+- /* ??? Hardcoded for SPARC register window configuration. */
++ /* ??? Hardcoded for SPARC register window configuration.
++ At least do not do anything for archs which explicitly
++ define a lower register number. */
++#if DWARF_FRAME_REGISTERS >= 32
+ for (reg = 16; reg < 32; ++reg)
+ {
+ fs->regs.reg[reg].how = REG_SAVED_OFFSET;
+ fs->regs.reg[reg].loc.offset = (reg - 16) * sizeof (void *);
+ }
++#endif
+ break;
+
+ case DW_CFA_GNU_args_size:
+--- libc/sysdeps/posix/tempname.c 27 Nov 2001 03:35:06 -0000 1.36
++++ libc/sysdeps/posix/tempname.c 7 Apr 2006 19:29:07 -0000 1.37
+@@ -242,11 +242,15 @@ __gen_tempname (char *tmpl, int kind)
+ necessary to try all these combinations. Instead if a reasonable
+ number of names is tried (we define reasonable as 62**3) fail to
+ give the system administrator the chance to remove the problems. */
+- unsigned int attempts_min = 62 * 62 * 62;
++#define ATTEMPTS_MIN (62 * 62 * 62)
+
+ /* The number of times to attempt to generate a temporary file. To
+ conform to POSIX, this must be no smaller than TMP_MAX. */
+- unsigned int attempts = attempts_min < TMP_MAX ? TMP_MAX : attempts_min;
++#if ATTEMPTS_MIN < TMP_MAX
++ unsigned int attempts = TMP_MAX;
++#else
++ unsigned int attempts = ATTEMPTS_MIN;
++#endif
+
+ len = strlen (tmpl);
+ if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
+--- libc/sysdeps/unix/sysv/linux/getsourcefilter.c 7 Aug 2004 18:21:41 -0000 1.7
++++ libc/sysdeps/unix/sysv/linux/getsourcefilter.c 7 Apr 2006 04:00:47 -0000 1.8
+@@ -112,23 +112,27 @@ getsourcefilter (int s, uint32_t interfa
+ gf->gf_numsrc = *numsrc;
+
+ /* We need to provide the appropriate socket level value. */
++ int result;
+ int sol = __get_sol (group->sa_family, grouplen);
+ if (sol == -1)
+ {
+ __set_errno (EINVAL);
+- return -1;
++ result = -1;
+ }
+-
+- int result = __getsockopt (s, sol, MCAST_MSFILTER, gf, &needed);
+-
+- /* If successful, copy the results to the places the caller wants
+- them in. */
+- if (result == 0)
++ else
+ {
+- *fmode = gf->gf_fmode;
+- memcpy (slist, gf->gf_slist,
+- MIN (*numsrc, gf->gf_numsrc) * sizeof (struct sockaddr_storage));
+- *numsrc = gf->gf_numsrc;
++ result = __getsockopt (s, sol, MCAST_MSFILTER, gf, &needed);
++
++ /* If successful, copy the results to the places the caller wants
++ them in. */
++ if (result == 0)
++ {
++ *fmode = gf->gf_fmode;
++ memcpy (slist, gf->gf_slist,
++ MIN (*numsrc, gf->gf_numsrc)
++ * sizeof (struct sockaddr_storage));
++ *numsrc = gf->gf_numsrc;
++ }
+ }
+
+ if (! use_alloca)
+--- libc/sysdeps/unix/sysv/linux/setsourcefilter.c 7 Aug 2004 18:21:41 -0000 1.5
++++ libc/sysdeps/unix/sysv/linux/setsourcefilter.c 7 Apr 2006 03:40:53 -0000 1.6
+@@ -57,14 +57,15 @@ setsourcefilter (int s, uint32_t interfa
+ memcpy (gf->gf_slist, slist, numsrc * sizeof (struct sockaddr_storage));
+
+ /* We need to provide the appropriate socket level value. */
++ int result;
+ int sol = __get_sol (group->sa_family, grouplen);
+ if (sol == -1)
+ {
+ __set_errno (EINVAL);
+- return -1;
++ result = -1;
+ }
+-
+- int result = __setsockopt (s, sol, MCAST_MSFILTER, gf, needed);
++ else
++ result = __setsockopt (s, sol, MCAST_MSFILTER, gf, needed);
+
+ if (! use_alloca)
+ {
--- /dev/null
+2006-05-10 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/generic/wordexp.c (parse_glob): No need to check ifs for
+ NULL, the caller makes sure this is not the case.
+ (wordexp): Simplify ifs_white creation. [Coverity CID 231]
+
+2006-05-09 Ulrich Drepper <drepper@redhat.com>
+
+ * io/ftw.c (open_dir_stream): Return right away if REALLOC fails.
+ [Coverity CID 229, 230]
+
+ * argp/argp-help.c (hol_entry_help): Handle STATE==NULL in ARG and
+ DGETTEXT calls.
+ (hol_help): Likewise. [Coverity CID 226, 227]
+
+ * nis/nis_creategroup.c (nis_creategroup): No need to duplicate
+ the return value of __nis_default_owner and __nis_default_group,
+ it has been especially allocated. [Coverity CID 224]
+
+ * nis/nis_defaults.c (searchXYX): New functions. Used by both
+ searchgroup and searchowner. Significantly simplified.
+ (__nis_default_owner): Remove duplication. Do not locally copy the
+ string before duplicating it.
+ (__nis_default_group): Likewise.
+
+ * nis/nis_lookup.c (nis_lookup): After calling nis_free_directory,
+ we must clear the variable before calling __nisfind_server.
+
+ * nis/nis_lookup.c (nis_lookup): Always free memory allocated with
+ nis_getnames. [Coverity CID 223]
+
+ * locale/programs/locfile.c (locfile_read): Use alloca instead of
+ xmalloc to allocate local repertoire name. [Coverity CID 222]
+
+ * iconv/iconv_charmap.c (use_to_charmap): No need to dynamically
+ allocate memory for the input to add_bytes. [Coverity CID 221]
+
+ * sysdeps/generic/wordexp.c (w_addword): Free word if realloc fails
+ and it was allocated here. [Coverity CID 219, 220]
+
+ * posix/getconf.c (print_all): Free confstr data after printing.
+ [Coverity CID 218]
+
+ * sysdeps/posix/getaddrinfo.c (gaih_inet): Free canon string if
+ list allocation fails. [Coverity CID 215]
+
+ * nss/nsswitch.c (__nss_configure_lookup): Fix loop end condition.
+ [Coverity CID 213]
+
+ * argp/argp-help.c (hol_entry_cmp): Don't call canon_doc_option if
+ string is NULL. [Coverity CID 212]
+ * argp/Makefile: Add rules to build and run bug-argp1.
+ * argp/bug-argp1.c: New file.
+
+ * elf/dl-dst.h (DL_DST_REQUIRED): Be prepared for missing link map
+ in statically linked code.
+ * elf/dl-load.c (_dl_dst_substitute): When replacing ORIGIN in
+ statically built code, be prepared to have no link map.
+ [Coverity CID 205]
+
+ * argp/argp-help.c (fill_in_uparams): Handle STATE==NULL in
+ dgettext calls. [Coverity CID 204]
+
+ * argp/argp-help.c (struct uparams): Remove valid member. Change
+ the one user.
+ (uparam_names): Reduce size. Avoid relative relocations.
+ Moved to read-only segment.
+ (fill_in_uparams): Update for new layout.
+
+ * argp/argp-help.c (hol_entry_help): Remove some dead code
+ [Coverity CID 200].
+
+--- libc/argp/Makefile 16 Sep 2003 05:46:38 -0000 1.6
++++ libc/argp/Makefile 9 May 2006 22:42:24 -0000 1.7
+@@ -26,10 +26,12 @@ distribute = argp-fmtstream.h argp-namef
+ routines = $(addprefix argp-, ba fmtstream fs-xinl help parse pv \
+ pvh xinl eexst)
+
+-tests = argp-test tst-argp1
++tests = argp-test tst-argp1 bug-argp1
+
+ CFLAGS-argp-help.c = $(uses-callbacks) -fexceptions
+ CFLAGS-argp-parse.c = $(uses-callbacks)
+ CFLAGS-argp-fmtstream.c = -fexceptions
+
++bug-argp1-ARGS = -- --help
++
+ include ../Rules
+--- libc/argp/argp-help.c 9 Aug 2005 01:26:22 -0000 1.47
++++ libc/argp/argp-help.c 10 May 2006 06:28:06 -0000 1.54
+@@ -128,40 +128,37 @@ struct uparams
+ int header_col;
+ int usage_indent;
+ int rmargin;
+-
+- int valid; /* True when the values in here are valid. */
+ };
+
+ /* This is a global variable, as user options are only ever read once. */
+ static struct uparams uparams = {
+ DUP_ARGS, DUP_ARGS_NOTE,
+ SHORT_OPT_COL, LONG_OPT_COL, DOC_OPT_COL, OPT_DOC_COL, HEADER_COL,
+- USAGE_INDENT, RMARGIN,
+- 0
++ USAGE_INDENT, RMARGIN
+ };
+
+ /* A particular uparam, and what the user name is. */
+ struct uparam_name
+ {
+- const char *name; /* User name. */
+- int is_bool; /* Whether it's `boolean'. */
+- size_t uparams_offs; /* Location of the (int) field in UPARAMS. */
++ const char name[14]; /* User name. */
++ bool is_bool; /* Whether it's `boolean'. */
++ uint8_t uparams_offs; /* Location of the (int) field in UPARAMS. */
+ };
+
+ /* The name-field mappings we know about. */
+ static const struct uparam_name uparam_names[] =
+ {
+- { "dup-args", 1, offsetof (struct uparams, dup_args) },
+- { "dup-args-note", 1, offsetof (struct uparams, dup_args_note) },
+- { "short-opt-col", 0, offsetof (struct uparams, short_opt_col) },
+- { "long-opt-col", 0, offsetof (struct uparams, long_opt_col) },
+- { "doc-opt-col", 0, offsetof (struct uparams, doc_opt_col) },
+- { "opt-doc-col", 0, offsetof (struct uparams, opt_doc_col) },
+- { "header-col", 0, offsetof (struct uparams, header_col) },
+- { "usage-indent", 0, offsetof (struct uparams, usage_indent) },
+- { "rmargin", 0, offsetof (struct uparams, rmargin) },
+- { 0 }
++ { "dup-args", true, offsetof (struct uparams, dup_args) },
++ { "dup-args-note", true, offsetof (struct uparams, dup_args_note) },
++ { "short-opt-col", false, offsetof (struct uparams, short_opt_col) },
++ { "long-opt-col", false, offsetof (struct uparams, long_opt_col) },
++ { "doc-opt-col", false, offsetof (struct uparams, doc_opt_col) },
++ { "opt-doc-col", false, offsetof (struct uparams, opt_doc_col) },
++ { "header-col", false, offsetof (struct uparams, header_col) },
++ { "usage-indent", false, offsetof (struct uparams, usage_indent) },
++ { "rmargin", false, offsetof (struct uparams, rmargin) }
+ };
++#define nuparam_names (sizeof (uparam_names) / sizeof (uparam_names[0]))
+
+ /* Read user options from the environment, and fill in UPARAMS appropiately. */
+ static void
+@@ -217,22 +214,27 @@ fill_in_uparams (const struct argp_state
+ SKIPWS (arg);
+ }
+
+- for (un = uparam_names; un->name; un++)
++ un = uparam_names;
++ size_t u;
++ for (u = 0; u < nuparam_names; ++un, ++u)
+ if (strlen (un->name) == var_len
+ && strncmp (var, un->name, var_len) == 0)
+ {
+ if (unspec && !un->is_bool)
+ __argp_failure (state, 0, 0,
+- dgettext (state->root_argp->argp_domain, "\
++ dgettext (state == NULL ? NULL
++ : state->root_argp->argp_domain,
++ "\
+ %.*s: ARGP_HELP_FMT parameter requires a value"),
+ (int) var_len, var);
+ else
+ *(int *)((char *)&uparams + un->uparams_offs) = val;
+ break;
+ }
+- if (! un->name)
++ if (u == nuparam_names)
+ __argp_failure (state, 0, 0,
+- dgettext (state->root_argp->argp_domain, "\
++ dgettext (state == NULL ? NULL
++ : state->root_argp->argp_domain, "\
+ %.*s: Unknown ARGP_HELP_FMT parameter"),
+ (int) var_len, var);
+
+@@ -243,7 +245,8 @@ fill_in_uparams (const struct argp_state
+ else if (*var)
+ {
+ __argp_failure (state, 0, 0,
+- dgettext (state->root_argp->argp_domain,
++ dgettext (state == NULL ? NULL
++ : state->root_argp->argp_domain,
+ "Garbage in ARGP_HELP_FMT: %s"), var);
+ break;
+ }
+@@ -759,9 +762,9 @@ hol_entry_cmp (const struct hol_entry *e
+ const char *long2 = hol_entry_first_long (entry2);
+
+ if (doc1)
+- doc1 = canon_doc_option (&long1);
++ doc1 = long1 != NULL && canon_doc_option (&long1);
+ if (doc2)
+- doc2 = canon_doc_option (&long2);
++ doc2 = long2 != NULL && canon_doc_option (&long2);
+
+ if (doc1 != doc2)
+ /* `documentation' options always follow normal options (or
+@@ -1102,7 +1105,9 @@ hol_entry_help (struct hol_entry *entry,
+ __argp_fmtstream_putc (stream, '-');
+ __argp_fmtstream_putc (stream, *so);
+ if (!have_long_opt || uparams.dup_args)
+- arg (real, " %s", "[%s]", state->root_argp->argp_domain, stream);
++ arg (real, " %s", "[%s]",
++ state == NULL ? NULL : state->root_argp->argp_domain,
++ stream);
+ else if (real->arg)
+ hhstate->suppressed_dup_arg = 1;
+ }
+@@ -1122,26 +1127,22 @@ hol_entry_help (struct hol_entry *entry,
+ have been done on the original; but documentation options
+ should be pretty rare anyway... */
+ __argp_fmtstream_puts (stream,
+- dgettext (state->root_argp->argp_domain,
++ dgettext (state == NULL ? NULL
++ : state->root_argp->argp_domain,
+ opt->name));
+ }
+ }
+ else
+ /* A real long option. */
+ {
+- int first_long_opt = 1;
+-
+ __argp_fmtstream_set_wmargin (stream, uparams.long_opt_col);
+ for (opt = real, num = entry->num; num > 0; opt++, num--)
+ if (opt->name && ovisible (opt))
+ {
+ comma (uparams.long_opt_col, &pest);
+ __argp_fmtstream_printf (stream, "--%s", opt->name);
+- if (first_long_opt || uparams.dup_args)
+- arg (real, "=%s", "[=%s]", state->root_argp->argp_domain,
+- stream);
+- else if (real->arg)
+- hhstate->suppressed_dup_arg = 1;
++ arg (real, "=%s", "[=%s]",
++ state == NULL ? NULL : state->root_argp->argp_domain, stream);
+ }
+ }
+
+@@ -1160,7 +1161,8 @@ hol_entry_help (struct hol_entry *entry,
+ }
+ else
+ {
+- const char *tstr = real->doc ? dgettext (state->root_argp->argp_domain,
++ const char *tstr = real->doc ? dgettext (state == NULL ? NULL
++ : state->root_argp->argp_domain,
+ real->doc) : 0;
+ const char *fstr = filter_doc (tstr, real->key, entry->argp, state);
+ if (fstr && *fstr)
+@@ -1208,7 +1210,8 @@ hol_help (struct hol *hol, const struct
+
+ if (hhstate.suppressed_dup_arg && uparams.dup_args_note)
+ {
+- const char *tstr = dgettext (state->root_argp->argp_domain, "\
++ const char *tstr = dgettext (state == NULL ? NULL
++ : state->root_argp->argp_domain, "\
+ Mandatory or optional arguments to long options are also mandatory or \
+ optional for any corresponding short options.");
+ const char *fstr = filter_doc (tstr, ARGP_KEY_HELP_DUP_ARGS_NOTE,
+@@ -1555,8 +1558,7 @@ _help (const struct argp *argp, const st
+ __flockfile (stream);
+ #endif
+
+- if (! uparams.valid)
+- fill_in_uparams (state);
++ fill_in_uparams (state);
+
+ fs = __argp_make_fmtstream (stream, 0, uparams.rmargin, 0);
+ if (! fs)
+--- libc/elf/dl-dst.h 6 Mar 2004 08:12:41 -0000 1.12
++++ libc/elf/dl-dst.h 9 May 2006 21:44:31 -0000 1.13
+@@ -50,6 +50,7 @@
+ \
+ First get the origin string if it is not available yet. \
+ This can only happen for the map of the executable. */ \
++ DL_DST_REQ_STATIC \
+ if ((l)->l_origin == NULL) \
+ { \
+ assert ((l)->l_name[0] == '\0'); \
+@@ -66,6 +67,18 @@
+ \
+ __len; })
+
++#ifdef SHARED
++# define DL_DST_REQ_STATIC /* nothing */
++#else
++# define DL_DST_REQ_STATIC \
++ if ((l) == NULL) \
++ { \
++ const char *origin = _dl_get_origin (); \
++ origin_len = (origin && origin != (char *) -1 ? strlen (origin) : 0); \
++ } \
++ else
++#endif
++
+ #ifndef IS_IN_rtld
+ # define _dl_get_origin GLRO(dl_get_origin)
+ # define _dl_dst_substitute GLRO(dl_dst_substitute)
+--- libc/elf/dl-load.c 30 Apr 2006 23:46:13 -0000 1.275
++++ libc/elf/dl-load.c 9 May 2006 21:43:03 -0000 1.276
+@@ -266,7 +266,14 @@ _dl_dst_substitute (struct link_map *l,
+ ++name;
+ if ((len = is_dst (start, name, "ORIGIN", is_path,
+ INTUSE(__libc_enable_secure))) != 0)
+- repl = l->l_origin;
++ {
++#ifndef SHARED
++ if (l == NULL)
++ repl = _dl_get_origin ();
++ else
++#endif
++ repl = l->l_origin;
++ }
+ else if ((len = is_dst (start, name, "PLATFORM", is_path, 0)) != 0)
+ repl = GLRO(dl_platform);
+ else if ((len = is_dst (start, name, "LIB", is_path, 0)) != 0)
+--- libc/iconv/iconv_charmap.c 7 Apr 2006 07:42:58 -0000 1.5
++++ libc/iconv/iconv_charmap.c 10 May 2006 02:06:18 -0000 1.6
+@@ -365,19 +365,27 @@ use_to_charmap (const char *from_code, s
+ if (outptr != (char *) outbuf)
+ {
+ /* We got some output. Good, use it. */
+- struct charseq *newp;
++ union
++ {
++ struct charseq seq;
++ struct
++ {
++ const char *name;
++ uint32_t ucs4;
++ int nbytes;
++ unsigned char bytes[outlen];
++ } mem;
++ } new;
+
+ outlen = sizeof (outbuf) - outlen;
+ assert ((char *) outbuf + outlen == outptr);
+
+- newp = (struct charseq *) xmalloc (sizeof (struct charseq)
+- + outlen);
+- newp->name = out->name;
+- newp->ucs4 = out->ucs4;
+- newp->nbytes = outlen;
+- memcpy (newp->bytes, outbuf, outlen);
++ new.mem.name = out->name;
++ new.mem.ucs4 = out->ucs4;
++ new.mem.nbytes = outlen;
++ memcpy (new.mem.bytes, outbuf, outlen);
+
+- add_bytes (rettbl, newp, out);
++ add_bytes (rettbl, &new.seq, out);
+ }
+
+ /* Clear any possible state left behind. */
+--- libc/io/ftw.c 2 Mar 2006 16:29:51 -0000 1.52
++++ libc/io/ftw.c 10 May 2006 06:35:59 -0000 1.53
+@@ -301,8 +301,7 @@ open_dir_stream (int *dfdp, struct ftw_d
+ int save_err = errno;
+ free (buf);
+ __set_errno (save_err);
+- result = -1;
+- break;
++ return -1;
+ }
+ buf = newp;
+ }
+--- libc/locale/programs/locfile.c 7 Dec 2005 05:47:27 -0000 1.38
++++ libc/locale/programs/locfile.c 10 May 2006 02:12:39 -0000 1.39
+@@ -155,10 +155,11 @@ argument to `%s' must be a single charac
+
+ if (repertoire_name == NULL)
+ {
+- repertoire_name = memcpy (xmalloc (arg->val.str.lenmb + 1),
+- arg->val.str.startmb,
+- arg->val.str.lenmb);
+- ((char *) repertoire_name)[arg->val.str.lenmb] = '\0';
++ char *newp = alloca (arg->val.str.lenmb + 1);
++
++ *((char *) mempcpy (newp, arg->val.str.startmb,
++ arg->val.str.lenmb)) = '\0';
++ repertoire_name = newp;
+ }
+ break;
+
+--- libc/nis/nis_creategroup.c 6 Apr 2006 23:58:16 -0000 1.12
++++ libc/nis/nis_creategroup.c 10 May 2006 03:06:22 -0000 1.13
+@@ -52,8 +52,8 @@ nis_creategroup (const_nis_name group, u
+
+ obj->zo_oid.ctime = obj->zo_oid.mtime = time (NULL);
+ obj->zo_name = strdup (leafbuf);
+- obj->zo_owner = strdup (__nis_default_owner (NULL));
+- obj->zo_group = strdup (__nis_default_group (NULL));
++ obj->zo_owner = __nis_default_owner (NULL);
++ obj->zo_group = __nis_default_group (NULL);
+ obj->zo_domain = strdup (domainbuf);
+ if (obj->zo_name == NULL || obj->zo_owner == NULL
+ || obj->zo_group == NULL || obj->zo_domain == NULL)
+--- libc/nis/nis_defaults.c 24 Oct 2004 20:28:28 -0000 1.7
++++ libc/nis/nis_defaults.c 10 May 2006 02:54:46 -0000 1.8
+@@ -17,6 +17,7 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
++#include <assert.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -30,45 +31,36 @@
+ ** Some functions for parsing the -D param and NIS_DEFAULTS Environ
+ */
+ static nis_name
+-searchgroup (char *str)
++searchXYX (char *str, const char *what)
+ {
+- char *cptr;
+- int i;
++ assert (strlen (what) == 6);
++ assert (strncmp (str, what, 6) == 0);
++ str += 6; /* Points to the begin of the parameters. */
++
++ int i = 0;
++ while (str[i] != '\0' && str[i] != ':')
++ ++i;
++ if (i == 0) /* only "<WHAT>=" ? */
++ return strdup ("");
+
+- cptr = strstr (str, "group=");
+- if (cptr == NULL)
+- return NULL;
++ return strndup (str, i);
++}
+
+- cptr += 6; /* points to the begin of the group string */
+- i = 0;
+- while (cptr[i] != '\0' && cptr[i] != ':')
+- i++;
+- if (i == 0) /* only "group=" ? */
+- return (nis_name) "";
+
+- return strndup (cptr, i);
++static nis_name
++searchgroup (char *str)
++{
++ return searchXYX (str, "group=");
+ }
+
++
+ static nis_name
+ searchowner (char *str)
+ {
+- char *cptr;
+- int i;
+-
+- cptr = strstr (str, "owner=");
+- if (cptr == NULL)
+- return NULL;
+-
+- cptr += 6; /* points to the begin of the owner string */
+- i = 0;
+- while (cptr[i] != '\0' && cptr[i] != ':')
+- i++;
+- if (i == 0) /* only "owner=" ? */
+- return strdup ("");
+-
+- return strndup (cptr, i);
++ return searchXYX (str, "owner=");
+ }
+
++
+ static uint32_t
+ searchttl (char *str)
+ {
+@@ -358,86 +350,61 @@ searchaccess (char *str, unsigned int ac
+ return result;
+ }
+
++
+ nis_name
+ __nis_default_owner (char *defaults)
+ {
+- char default_owner[NIS_MAXNAMELEN + 1];
+- char *cptr, *dptr;
++ char *default_owner = NULL;
+
+- strcpy (default_owner, nis_local_principal ());
++ char *cptr = defaults;
++ if (cptr == NULL)
++ cptr = getenv ("NIS_DEFAULTS");
+
+- if (defaults != NULL)
++ if (cptr != NULL)
+ {
+- dptr = strstr (defaults, "owner=");
++ char *dptr = strstr (cptr, "owner=");
+ if (dptr != NULL)
+ {
+- char *p = searchowner (defaults);
+- if (strlen (p) <= NIS_MAXNAMELEN)
+- strcpy (default_owner, p);
++ char *p = searchowner (dptr);
++ if (p == NULL)
++ return NULL;
++ default_owner = strdupa (p);
+ free (p);
+ }
+ }
+- else
+- {
+- cptr = getenv ("NIS_DEFAULTS");
+- if (cptr != NULL)
+- {
+- dptr = strstr (cptr, "owner=");
+- if (dptr != NULL)
+- {
+- char *p = searchowner (cptr);
+- if (strlen (p) <= NIS_MAXNAMELEN)
+- strcpy (default_owner, p);
+- free (p);
+- }
+- }
+- }
+
+- return strdup (default_owner);
++ return strdup (default_owner ?: nis_local_principal ());
+ }
+ libnsl_hidden_def (__nis_default_owner)
+
++
+ nis_name
+ __nis_default_group (char *defaults)
+ {
+- char default_group[NIS_MAXNAMELEN + 1];
+- char *cptr, *dptr;
++ char *default_group = NULL;
+
+- strcpy (default_group, nis_local_group ());
++ char *cptr = defaults;
++ if (cptr == NULL)
++ cptr = getenv ("NIS_DEFAULTS");
+
+- if (defaults != NULL)
++ if (cptr != NULL)
+ {
+- dptr = strstr (defaults, "group=");
++ char *dptr = strstr (cptr, "group=");
+ if (dptr != NULL)
+ {
+- char *p = searchgroup (defaults);
+-
+- if (strlen (p) <= NIS_MAXNAMELEN)
+- strcpy (default_group, p);
++ char *p = searchgroup (dptr);
++ if (p == NULL)
++ return NULL;
++ default_group = strdupa (p);
+ free (p);
+ }
+ }
+- else
+- {
+- cptr = getenv ("NIS_DEFAULTS");
+- if (cptr != NULL)
+- {
+- dptr = strstr (cptr, "group=");
+- if (dptr != NULL)
+- {
+- char *p = searchgroup (cptr);
+-
+- if (strlen (p) <= NIS_MAXNAMELEN)
+- strcpy (default_group, p);
+- free (p);
+- }
+- }
+- }
+
+- return strdup (default_group);
++ return strdup (default_group ?: nis_local_group ());
+ }
+ libnsl_hidden_def (__nis_default_group)
+
++
+ uint32_t
+ __nis_default_ttl (char *defaults)
+ {
+--- libc/nis/nis_lookup.c 8 Dec 2005 20:19:11 -0000 1.16
++++ libc/nis/nis_lookup.c 10 May 2006 02:30:20 -0000 1.18
+@@ -65,7 +65,7 @@ nis_lookup (const_nis_name name, const u
+ if (status != NIS_SUCCESS)
+ {
+ NIS_RES_STATUS (res) = status;
+- return res;
++ goto out;
+ }
+
+ status = __nisbind_create (&bptr, dir->do_servers.do_servers_val,
+@@ -74,7 +74,7 @@ nis_lookup (const_nis_name name, const u
+ {
+ NIS_RES_STATUS (res) = status;
+ nis_free_directory (dir);
+- return res;
++ goto out;;
+ }
+
+ while (__nisbind_connect (&bptr) != NIS_SUCCESS)
+@@ -83,7 +83,7 @@ nis_lookup (const_nis_name name, const u
+ {
+ nis_free_directory (dir);
+ NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
+- return res;
++ goto out;
+ }
+ }
+
+@@ -121,8 +121,21 @@ nis_lookup (const_nis_name name, const u
+ req.ns_name =
+ strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
+ if (req.ns_name == NULL)
+- return NULL;
++ {
++ nis_free_directory (dir);
++ res = NULL;
++ goto out;
++ }
+
++ /* The following is a non-obvious optimization. A
++ nis_freeresult call would call xdr_free as the
++ following code. But it also would unnecessarily
++ free the result structure. We avoid this here
++ along with the necessary tests. */
++#if 1
++ xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res);
++ memset (res, '\0', sizeof (*res));
++#else
+ nis_freeresult (res);
+ res = calloc (1, sizeof (nis_result));
+ if (res == NULL)
+@@ -130,6 +143,7 @@ nis_lookup (const_nis_name name, const u
+ __nisbind_destroy (&bptr);
+ return NULL;
+ }
++#endif
+
+ link_first_try = 1; /* Try at first the old binding */
+ goto again;
+@@ -144,10 +158,12 @@ nis_lookup (const_nis_name name, const u
+ {
+ __nisbind_destroy (&bptr);
+ nis_free_directory (dir);
++ /* Otherwise __nisfind_server will not do anything. */
++ dir = NULL;
+
+ if (__nisfind_server (req.ns_name, &dir)
+ != NIS_SUCCESS)
+- return res;
++ goto out;
+
+ if (__nisbind_create (&bptr,
+ dir->do_servers.do_servers_val,
+@@ -155,7 +171,7 @@ nis_lookup (const_nis_name name, const u
+ flags) != NIS_SUCCESS)
+ {
+ nis_free_directory (dir);
+- return res;
++ goto out;
+ }
+ }
+ else
+@@ -167,7 +183,7 @@ nis_lookup (const_nis_name name, const u
+ if (__nisbind_next (&bptr) != NIS_SUCCESS)
+ {
+ nis_free_directory (dir);
+- return res;
++ goto out;
+ }
+ }
+ goto again;
+@@ -184,7 +200,7 @@ nis_lookup (const_nis_name name, const u
+ if (status != NIS_SUCCESS)
+ {
+ NIS_RES_STATUS (res) = status;
+- return res;
++ goto out;
+ }
+
+ switch (NIS_RES_STATUS (res))
+@@ -216,6 +232,7 @@ nis_lookup (const_nis_name name, const u
+ }
+ }
+
++ out:
+ if (names != namebuf)
+ nis_freenames (names);
+
+--- libc/nss/nsswitch.c 20 Dec 2005 18:41:01 -0000 1.61
++++ libc/nss/nsswitch.c 9 May 2006 22:46:57 -0000 1.63
+@@ -70,6 +70,7 @@ static const struct
+ #include "databases.def"
+ #undef DEFINE_DATABASE
+ };
++#define ndatabases (sizeof (databases) / sizeof (databases[0]))
+
+
+ __libc_lock_define_initialized (static, lock)
+@@ -211,7 +212,7 @@ __nss_configure_lookup (const char *dbna
+ service_user *new_db;
+ size_t cnt;
+
+- for (cnt = 0; cnt < sizeof databases; ++cnt)
++ for (cnt = 0; cnt < ndatabases; ++cnt)
+ {
+ int cmp = strcmp (dbname, databases[cnt].name);
+ if (cmp == 0)
+@@ -223,7 +224,7 @@ __nss_configure_lookup (const char *dbna
+ }
+ }
+
+- if (cnt == sizeof databases)
++ if (cnt == ndatabases)
+ {
+ __set_errno (EINVAL);
+ return -1;
+--- libc/posix/getconf.c 1 Jan 2006 19:15:55 -0000 1.42
++++ libc/posix/getconf.c 9 May 2006 23:58:22 -0000 1.43
+@@ -981,6 +981,7 @@ print_all (const char *path)
+ if (confstr (c->call_name, cvalue, clen) != clen)
+ error (3, errno, "confstr");
+ printf ("%.*s\n", (int) clen, cvalue);
++ free (cvalue);
+ break;
+ }
+ }
+--- libc/sysdeps/generic/wordexp.c 14 Dec 2005 12:02:26 -0000 1.48
++++ libc/sysdeps/generic/wordexp.c 10 May 2006 14:43:20 -0000 1.51
+@@ -166,6 +166,7 @@ w_addword (wordexp_t *pwordexp, char *wo
+ /* Add a word to the wordlist */
+ size_t num_p;
+ char **new_wordv;
++ bool allocated = false;
+
+ /* Internally, NULL acts like "". Convert NULLs to "" before
+ * the caller sees them.
+@@ -175,6 +176,7 @@ w_addword (wordexp_t *pwordexp, char *wo
+ word = __strdup ("");
+ if (word == NULL)
+ goto no_space;
++ allocated = true;
+ }
+
+ num_p = 2 + pwordexp->we_wordc + pwordexp->we_offs;
+@@ -187,6 +189,9 @@ w_addword (wordexp_t *pwordexp, char *wo
+ return 0;
+ }
+
++ if (allocated)
++ free (word);
++
+ no_space:
+ return WRDE_NOSPACE;
+ }
+@@ -448,8 +453,7 @@ parse_glob (char **word, size_t *word_le
+ glob_list.we_offs = 0;
+ for (; words[*offset] != '\0'; ++*offset)
+ {
+- if ((ifs && strchr (ifs, words[*offset])) ||
+- (!ifs && strchr (" \t\n", words[*offset])))
++ if (strchr (ifs, words[*offset]) != NULL)
+ /* Reached IFS */
+ break;
+
+@@ -2273,18 +2272,15 @@ wordexp (const char *words, wordexp_t *p
+ char *ifsch = ifs;
+ char *whch = ifs_white;
+
+- /* Start off with no whitespace IFS characters */
+- ifs_white[0] = '\0';
+-
+ while (*ifsch != '\0')
+ {
+- if ((*ifsch == ' ') || (*ifsch == '\t') || (*ifsch == '\n'))
++ if (*ifsch == ' ' || *ifsch == '\t' || *ifsch == '\n')
+ {
+ /* Whitespace IFS. See first whether it is already in our
+ collection. */
+ char *runp = ifs_white;
+
+- while (runp < whch && *runp != '\0' && *runp != *ifsch)
++ while (runp < whch && *runp != *ifsch)
+ ++runp;
+
+ if (runp == whch)
+--- libc/sysdeps/posix/getaddrinfo.c 4 May 2006 06:31:25 -0000 1.101
++++ libc/sysdeps/posix/getaddrinfo.c 10 May 2006 06:40:34 -0000 1.103
+@@ -1047,7 +1047,10 @@ gaih_inet (const char *name, const struc
+ struct addrinfo *ai;
+ ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
+ if (ai == NULL)
+- return -EAI_MEMORY;
++ {
++ free ((char *) canon);
++ return -EAI_MEMORY;
++ }
+
+ ai->ai_flags = req->ai_flags;
+ ai->ai_family = family;
+@@ -1065,6 +1068,10 @@ gaih_inet (const char *name, const struc
+ #endif /* _HAVE_SA_LEN */
+ ai->ai_addr->sa_family = family;
+
++ /* In case of an allocation error the list must be NULL
++ terminated. */
++ ai->ai_next = NULL;
++
+ if (family == AF_INET6)
+ {
+ struct sockaddr_in6 *sin6p =
+@@ -1088,7 +1095,6 @@ gaih_inet (const char *name, const struc
+
+ pai = &(ai->ai_next);
+ }
+- *pai = NULL;
+
+ ++*naddrs;
+
+--- libc/argp/bug-argp1.c 2006-04-19 19:21:31.748476000 +0200
++++ libc/argp/bug-argp1.c 2006-05-10 00:40:17.000000000 +0200
+@@ -0,0 +1,26 @@
++#include <argp.h>
++
++
++static const struct argp_option test_options[] =
++{
++ { NULL, 'a', NULL, OPTION_DOC, NULL },
++ { NULL, 'b', NULL, OPTION_DOC, NULL },
++ { NULL, 0, NULL, 0, NULL }
++};
++
++static struct argp test_argp =
++{
++ test_options
++};
++
++
++static int
++do_test (int argc, char *argv[])
++{
++ int i;
++ argp_parse (&test_argp, argc, argv, 0, &i, NULL);
++ return 0;
++}
++
++#define TEST_FUNCTION do_test (argc, argv)
++#include "../test-skeleton.c"
--- /dev/null
+2005-10-13 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #1466]
+ * sysdeps/generic/s_csqrt.c (__csqrt): For zero real part, return
+ principal square root.
+ * sysdeps/generic/s_csqrtf.c (__csqrtf): Likewise.
+ * sysdeps/generic/s_csqrtl.c (__csqrtl): Likewise.
+ * math/libm-test.inc (csqrt_test): Add test for returning
+ principal value.
+
+--- libc/math/libm-test.inc 6 Jan 2005 21:49:23 -0000 1.65
++++ libc/math/libm-test.inc 13 Oct 2005 19:07:12 -0000 1.66
+@@ -153,6 +153,7 @@
+ #define M_PI2_LOG10El M_PI_2l * M_LOG10El
+ #define M_PI4_LOG10El M_PI_4l * M_LOG10El
+ #define M_PI_LOG10El M_PIl * M_LOG10El
++#define M_SQRT_2_2 0.70710678118654752440084436210484903L /* sqrt (2) / 2 */
+
+ static FILE *ulps_file; /* File to document difference. */
+ static int output_ulps; /* Should ulps printed? */
+@@ -2212,6 +2213,9 @@ csqrt_test (void)
+ TEST_c_c (csqrt, 0.75L, 1.25L, 1.05065169626078392338656675760808326L, 0.594868882070379067881984030639932657L);
+ TEST_c_c (csqrt, -2, -3, 0.89597747612983812471573375529004348L, -1.6741492280355400404480393008490519L);
+ TEST_c_c (csqrt, -2, 3, 0.89597747612983812471573375529004348L, 1.6741492280355400404480393008490519L);
++ /* Principal square root should be returned (i.e., non-negative real
++ part). */
++ TEST_c_c (csqrt, 0, -1, M_SQRT_2_2, -M_SQRT_2_2);
+
+ END (csqrt, complex);
+ }
+--- libc/sysdeps/generic/s_csqrt.c 6 Jul 2001 04:55:49 -0000 1.2
++++ libc/sysdeps/generic/s_csqrt.c 13 Oct 2005 19:05:44 -0000 1.3
+@@ -79,8 +79,8 @@ __csqrt (__complex__ double x)
+ {
+ double r = __ieee754_sqrt (0.5 * fabs (__imag__ x));
+
+- __real__ res = __copysign (r, __imag__ x);
+- __imag__ res = r;
++ __real__ res = r;
++ __imag__ res = __copysign (r, __imag__ x);
+ }
+ else
+ {
+--- libc/sysdeps/generic/s_csqrtf.c 13 Jan 2004 09:08:04 -0000 1.3
++++ libc/sysdeps/generic/s_csqrtf.c 13 Oct 2005 19:05:12 -0000 1.4
+@@ -79,8 +79,8 @@ __csqrtf (__complex__ float x)
+ {
+ float r = __ieee754_sqrtf (0.5 * fabsf (__imag__ x));
+
+- __real__ res = __copysignf (r, __imag__ x);
+- __imag__ res = r;
++ __real__ res = r;
++ __imag__ res = __copysignf (r, __imag__ x);
+ }
+ else
+ {
+--- libc/sysdeps/generic/s_csqrtl.c 6 Jul 2001 04:55:49 -0000 1.2
++++ libc/sysdeps/generic/s_csqrtl.c 13 Oct 2005 19:04:31 -0000 1.3
+@@ -79,8 +79,8 @@ __csqrtl (__complex__ long double x)
+ {
+ long double r = __ieee754_sqrtl (0.5 * fabsl (__imag__ x));
+
+- __real__ res = __copysignl (r, __imag__ x);
+- __imag__ res = r;
++ __real__ res = r;
++ __imag__ res = __copysignl (r, __imag__ x);
+ }
+ else
+ {
--- /dev/null
+2006-01-03 Jakub Jelinek <jakub@redhat.com>
+
+ * posix/unistd.h (ctermid): Remove __nonnull attribute.
+
+--- libc/posix/unistd.h 16 Dec 2005 00:15:19 -0000 1.139
++++ libc/posix/unistd.h 3 Jan 2006 15:57:08 -0000 1.140
+@@ -1075,7 +1075,7 @@ extern void swab (__const void *__restri
+ It is also found in <stdio.h>. */
+ #ifdef __USE_XOPEN
+ /* Return the name of the controlling terminal. */
+-extern char *ctermid (char *__s) __THROW __nonnull ((1));
++extern char *ctermid (char *__s) __THROW;
+ #endif
+
+
--- /dev/null
+2005-11-26 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/ypclnt.c (do_ypcall): Check memory allocation suceeded before
+ calling yp_bind_ypbindprog.
+
+--- libc/nis/ypclnt.c 25 Nov 2005 16:04:44 -0000 1.52
++++ libc/nis/ypclnt.c 26 Nov 2005 22:16:03 -0000 1.53
+@@ -349,7 +349,7 @@ do_ypcall (const char *domain, u_long pr
+ if (status != YPERR_SUCCESS)
+ {
+ ydb = calloc (1, sizeof (dom_binding));
+- if (yp_bind_ypbindprog (domain, ydb) == YPERR_SUCCESS)
++ if (ydb != NULL && yp_bind_ypbindprog (domain, ydb) == YPERR_SUCCESS)
+ {
+ status = __ypclnt_call (domain, prog, xargs, req, xres,
+ resp, &ydb, 1);
--- /dev/null
+2006-02-03 Jakub Jelinek <jakub@redhat.com>
+
+ * manual/filesys.texi (futimes): Fix prototype.
+
+2004-08-09 Paul Eggert <eggert@cs.ucla.edu>
+
+ [BZ #315]
+ * manual/memory.texi (Obstacks Data Alignment): The default
+ alignment is not 4: it is enough to hold any type of data.
+ Problem reported by Benno in
+ <http://sources.redhat.com/ml/libc-alpha/2004-08/msg00055.html>.
+
+2006-02-03 Ulrich Drepper <drepper@redhat.com>
+
+ * manual/stdio.texi (Formatted Output Functions): Fix make_message
+ example. Patch by NIIBE Yutaka <gniibe@m17n.org>.
+
+2005-12-31 Andreas Jaeger <aj@suse.de>
+
+ [BZ #1395]
+ * manual/filesys.texi (Symbolic Links): Fix description of
+ canonicalize_file_name based on patch by Oskar Liljeblad
+ <oskar@osk.mine.nu>.
+
+2005-12-15 Roland McGrath <roland@redhat.com>
+
+ [BZ #1997]
+ * manual/stdio.texi (String Streams): For open_memstream, elaborate a
+ little on malloc reference.
+
+--- libc/manual/filesys.texi 15 Oct 2005 17:37:58 -0000 1.98
++++ libc/manual/filesys.texi 22 Feb 2006 07:17:46 -0000 1.100
+@@ -1250,10 +1250,10 @@ result is passed back as the return valu
+ memory allocated with @code{malloc}. If the result is not used anymore
+ the memory should be freed with a call to @code{free}.
+
+-In any of the path components except the last one is missing the
+-function returns a NULL pointer. This is also what is returned if the
+-length of the path reaches or exceeds @code{PATH_MAX} characters. In
+-any case @code{errno} is set accordingly.
++If any of the path components is missing the function returns a NULL
++pointer. This is also what is returned if the length of the path
++reaches or exceeds @code{PATH_MAX} characters. In any case
++@code{errno} is set accordingly.
+
+ @table @code
+ @item ENAMETOOLONG
+@@ -2806,7 +2806,7 @@ function.
+
+ @comment sys/time.h
+ @comment BSD
+-@deftypefun int futimes (int *@var{fd}, struct timeval @var{tvp}@t{[2]})
++@deftypefun int futimes (int @var{fd}, struct timeval @var{tvp}@t{[2]})
+ This function is like @code{utimes}, except that it takes an open file
+ descriptor as an argument instead of a file name. @xref{Low-Level
+ I/O}. This function comes from FreeBSD, and is not available on all
+--- libc/manual/memory.texi 13 Sep 2005 17:46:01 -0000 1.80
++++ libc/manual/memory.texi 22 Feb 2006 06:57:59 -0000 1.81
+@@ -1968,7 +1968,8 @@ obstack_next_free (@var{obstack-ptr}) -
+
+ Each obstack has an @dfn{alignment boundary}; each object allocated in
+ the obstack automatically starts on an address that is a multiple of the
+-specified boundary. By default, this boundary is 4 bytes.
++specified boundary. By default, this boundary is aligned so that
++the object can hold any type of data.
+
+ To access an obstack's alignment boundary, use the macro
+ @code{obstack_alignment_mask}, whose function prototype looks like
+@@ -1980,7 +1981,9 @@ this:
+ The value is a bit mask; a bit that is 1 indicates that the corresponding
+ bit in the address of an object should be 0. The mask value should be one
+ less than a power of 2; the effect is that all object addresses are
+-multiples of that power of 2. The default value of the mask is 3, so that
++multiples of that power of 2. The default value of the mask is a value
++that allows aligned objects to hold any type of data: for example, if
++its value is 3, any type of data can be stored at locations whose
+ addresses are multiples of 4. A mask value of 0 means an object can start
+ on any multiple of 1 (that is, no alignment is required).
+
+--- libc/manual/stdio.texi 25 Sep 2005 18:24:55 -0000 1.134
++++ libc/manual/stdio.texi 4 Feb 2006 07:12:54 -0000 1.136
+@@ -2357,7 +2357,8 @@ make_message (char *name, char *value)
+ @{
+ /* @r{Reallocate buffer now that we know
+ how much space is needed.} */
+- buffer = (char *) xrealloc (buffer, nchars + 1);
++ size = nchars + 1;
++ buffer = (char *) xrealloc (buffer, size);
+
+ if (buffer != NULL)
+ /* @r{Try again.} */
+@@ -4852,8 +4853,9 @@ Got r
+ @comment GNU
+ @deftypefun {FILE *} open_memstream (char **@var{ptr}, size_t *@var{sizeloc})
+ This function opens a stream for writing to a buffer. The buffer is
+-allocated dynamically (as with @code{malloc}; @pxref{Unconstrained
+-Allocation}) and grown as necessary.
++allocated dynamically and grown as necessary, using @code{malloc}.
++After you've closed the stream, this buffer is your responsibility to
++clean up using @code{free} or @code{realloc}. @xref{Unconstrained Allocation}.
+
+ When the stream is closed with @code{fclose} or flushed with
+ @code{fflush}, the locations @var{ptr} and @var{sizeloc} are updated to
--- /dev/null
+2007-03-16 Jakub Jelinek <jakub@redhat.com>
+
+ * elf/dl-open.c (dl_open_worker): Declare l in 2 different
+ smaller scopes.
+ * elf/dl-dst.h (DL_DST_REQ_STATIC): Add l as macro argument.
+ (DL_DST_REQUIRED): Adjust user.
+
+--- libc/elf/dl-dst.h 9 May 2006 21:44:31 -0000 1.13
++++ libc/elf/dl-dst.h 17 Mar 2007 17:08:00 -0000 1.14
+@@ -50,7 +51,7 @@
+ \
+ First get the origin string if it is not available yet. \
+ This can only happen for the map of the executable. */ \
+- DL_DST_REQ_STATIC \
++ DL_DST_REQ_STATIC (l) \
+ if ((l)->l_origin == NULL) \
+ { \
+ assert ((l)->l_name[0] == '\0'); \
+@@ -68,9 +69,9 @@
+ __len; })
+
+ #ifdef SHARED
+-# define DL_DST_REQ_STATIC /* nothing */
++# define DL_DST_REQ_STATIC(l) /* nothing */
+ #else
+-# define DL_DST_REQ_STATIC \
++# define DL_DST_REQ_STATIC(l) \
+ if ((l) == NULL) \
+ { \
+ const char *origin = _dl_get_origin (); \
+--- libc/elf/dl-open.c 29 Oct 2006 21:45:26 -0000 1.136
++++ libc/elf/dl-open.c 17 Mar 2007 17:07:51 -0000 1.137
+@@ -161,7 +161,7 @@ dl_open_worker (void *a)
+ struct dl_open_args *args = a;
+ const char *file = args->file;
+ int mode = args->mode;
+- struct link_map *new, *l;
++ struct link_map *new;
+ int lazy;
+ unsigned int i;
+ bool any_tls = false;
+@@ -186,6 +186,7 @@ dl_open_worker (void *a)
+ By default we assume this is the main application. */
+ call_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+
++ struct link_map *l;
+ for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
+ for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next)
+ if (caller_dlopen >= (const void *) l->l_map_start
+@@ -325,7 +326,7 @@ dl_open_worker (void *a)
+ /* Relocate the objects loaded. We do this in reverse order so that copy
+ relocs of earlier objects overwrite the data written by later objects. */
+
+- l = new;
++ struct link_map *l = new;
+ while (l->l_next)
+ l = l->l_next;
+ while (1)
--- /dev/null
+2006-02-03 Roland McGrath <roland@redhat.com>
+
+ * structs.def: Add a descriptor for pointer.val field of dtv_t.
+ * td_thr_tlsbase.c (td_thr_tlsbase): Extract pointer.val field from
+ DTV slot.
+
+2005-11-22 Jakub Jelinek <jakub@redhat.com>
+
+ * elf/rtld.c (_dl_start): Fixup for dtv_t change.
+ * sysdeps/alpha/libc-tls.c (__tls_get_addr): Likewise.
+ * sysdeps/ia64/libc-tls.c (__tls_get_addr): Likewise.
+linuxthreads_db/
+ * td_thr_tlsbase.c (td_thr_tlsbase): Fixup for dtv_t change.
+linuxthreads/
+ * pthread.c (init_one_static_tls): Fixup for dtv_t change.
+ * sysdeps/alpha/tls.h (dtv_t): Change pointer type to be struct which
+ also contains information whether the memory pointed to is static
+ TLS or not.
+ * sysdeps/i386/tls.h: Likewise.
+ * sysdeps/ia64/tls.h: Likewise.
+ * sysdeps/powerpc/tls.h: Likewise.
+ * sysdeps/s390/tls.h: Likewise.
+ * sysdeps/sh/tls.h: Likewise.
+ * sysdeps/sparc/tls.h: Likewise.
+ * sysdeps/x86_64/tls.h: Likewise.
+
+2005-01-06 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/generic/dl-tls.c: Fixup for dtv_t change.
+ Fix updating of DTV.
+ * sysdeps/generic/libc-tls.c: Likewise.
+ * sysdeps/generic/dl-tls.c: Likewise.
+ * elf/dl-reloc.c (_dl_nothread_init_static_tls): Likewise.
+nptl/
+ * allocatestack.c (init_one_static_tls): Adjust initialization of DTV
+ entry for static tls deallocation fix.
+ * sysdeps/alpha/tls.h (dtv_t): Change pointer type to be struct which
+ also contains information whether the memory pointed to is static
+ TLS or not.
+ * sysdeps/i386/tls.h: Likewise.
+ * sysdeps/ia64/tls.h: Likewise.
+ * sysdeps/powerpc/tls.h: Likewise.
+ * sysdeps/s390/tls.h: Likewise.
+ * sysdeps/sh/tls.h: Likewise.
+ * sysdeps/sparc/tls.h: Likewise.
+ * sysdeps/x86_64/tls.h: Likewise.
+
+--- libc/elf/rtld.c.jj 2005-11-17 13:07:34.000000000 +0100
++++ libc/elf/rtld.c 2005-11-22 17:37:13.000000000 +0100
+@@ -448,18 +448,19 @@ _dl_start (void *arg)
+ counter. */
+ initdtv[0].counter = 1;
+ initdtv[1].counter = 0;
++ initdtv[2].pointer.is_static = true;
+
+ /* Initialize the TLS block. */
+ # if TLS_TCB_AT_TP
+- initdtv[2].pointer = tlsblock;
++ initdtv[2].pointer.val = tlsblock;
+ # elif TLS_DTV_AT_TP
+ bootstrap_map.l_tls_offset = roundup (TLS_INIT_TCB_SIZE,
+ bootstrap_map.l_tls_align);
+- initdtv[2].pointer = (char *) tlsblock + bootstrap_map.l_tls_offset;
++ initdtv[2].pointer.val = (char *) tlsblock + bootstrap_map.l_tls_offset;
+ # else
+ # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+ # endif
+- p = __mempcpy (initdtv[2].pointer, bootstrap_map.l_tls_initimage,
++ p = __mempcpy (initdtv[2].pointer.val, bootstrap_map.l_tls_initimage,
+ bootstrap_map.l_tls_initimage_size);
+ # ifdef HAVE_BUILTIN_MEMSET
+ __builtin_memset (p, '\0', (bootstrap_map.l_tls_blocksize
+--- libc/elf/dl-reloc.c.jj 2005-02-26 02:09:47.000000000 +0100
++++ libc/elf/dl-reloc.c 2005-11-22 17:34:42.000000000 +0100
+@@ -116,7 +116,8 @@ _dl_nothread_init_static_tls (struct lin
+ /* Fill in the DTV slot so that a later LD/GD access will find it. */
+ dtv_t *dtv = THREAD_DTV ();
+ assert (map->l_tls_modid <= dtv[-1].counter);
+- dtv[map->l_tls_modid].pointer = dest;
++ dtv[map->l_tls_modid].pointer.val = dest;
++ dtv[map->l_tls_modid].pointer.is_static = true;
+
+ /* Initialize the memory. */
+ memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
+--- libc/sysdeps/alpha/libc-tls.c.jj 2003-01-17 20:19:37.000000000 +0100
++++ libc/sysdeps/alpha/libc-tls.c 2005-11-22 17:37:59.000000000 +0100
+@@ -31,7 +31,7 @@ void *
+ __tls_get_addr (tls_index *ti)
+ {
+ dtv_t *dtv = THREAD_DTV ();
+- return (char *) dtv[1].pointer + ti->ti_offset;
++ return (char *) dtv[1].pointer.val + ti->ti_offset;
+ }
+
+ #endif
+--- libc/sysdeps/ia64/libc-tls.c.jj 2003-01-12 09:54:39.000000000 +0100
++++ libc/sysdeps/ia64/libc-tls.c 2005-11-22 17:38:38.000000000 +0100
+@@ -30,7 +30,7 @@ void *
+ __tls_get_addr (size_t m, size_t offset)
+ {
+ dtv_t *dtv = THREAD_DTV ();
+- return (char *) dtv[1].pointer + offset;
++ return (char *) dtv[1].pointer.val + offset;
+ }
+
+ #endif
+--- libc/sysdeps/generic/dl-tls.c.jj 2005-02-16 11:23:02.000000000 +0100
++++ libc/sysdeps/generic/dl-tls.c 2005-11-22 17:56:09.000000000 +0100
+@@ -418,7 +418,8 @@ _dl_allocate_tls_init (void *result)
+ {
+ /* For dynamically loaded modules we simply store
+ the value indicating deferred allocation. */
+- dtv[map->l_tls_modid].pointer = TLS_DTV_UNALLOCATED;
++ dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
++ dtv[map->l_tls_modid].pointer.is_static = false;
+ continue;
+ }
+
+@@ -434,7 +435,8 @@ _dl_allocate_tls_init (void *result)
+ # endif
+
+ /* Copy the initialization image and clear the BSS part. */
+- dtv[map->l_tls_modid].pointer = dest;
++ dtv[map->l_tls_modid].pointer.val = dest;
++ dtv[map->l_tls_modid].pointer.is_static = true;
+ memset (__mempcpy (dest, map->l_tls_initimage,
+ map->l_tls_initimage_size), '\0',
+ map->l_tls_blocksize - map->l_tls_initimage_size);
+@@ -603,10 +605,11 @@ __tls_get_addr (GET_ADDR_ARGS)
+ {
+ /* If this modid was used at some point the memory
+ might still be allocated. */
+- if (dtv[total + cnt].pointer != TLS_DTV_UNALLOCATED)
++ if (! dtv[total + cnt].pointer.is_static
++ && dtv[total + cnt].pointer.val != TLS_DTV_UNALLOCATED)
+ {
+- free (dtv[total + cnt].pointer);
+- dtv[total + cnt].pointer = TLS_DTV_UNALLOCATED;
++ free (dtv[total + cnt].pointer.val);
++ dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED;
+ }
+
+ continue;
+@@ -662,16 +665,18 @@ __tls_get_addr (GET_ADDR_ARGS)
+ dtv entry free it. */
+ /* XXX Ideally we will at some point create a memory
+ pool. */
+- if (dtv[modid].pointer != TLS_DTV_UNALLOCATED)
++ if (! dtv[modid].pointer.is_static
++ && dtv[modid].pointer.val != TLS_DTV_UNALLOCATED)
+ /* Note that free is called for NULL is well. We
+ deallocate even if it is this dtv entry we are
+ supposed to load. The reason is that we call
+ memalign and not malloc. */
+- free (dtv[modid].pointer);
++ free (dtv[modid].pointer.val);
+
+ /* This module is loaded dynamically- We defer
+ memory allocation. */
+- dtv[modid].pointer = TLS_DTV_UNALLOCATED;
++ dtv[modid].pointer.is_static = false;
++ dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
+
+ if (modid == GET_ADDR_MODULE)
+ the_map = map;
+@@ -686,7 +691,7 @@ __tls_get_addr (GET_ADDR_ARGS)
+ }
+ }
+
+- p = dtv[GET_ADDR_MODULE].pointer;
++ p = dtv[GET_ADDR_MODULE].pointer.val;
+
+ if (__builtin_expect (p == TLS_DTV_UNALLOCATED, 0))
+ {
+@@ -706,7 +711,8 @@ __tls_get_addr (GET_ADDR_ARGS)
+ the_map = listp->slotinfo[idx].map;
+ }
+
+- p = dtv[GET_ADDR_MODULE].pointer = allocate_and_init (the_map);
++ p = dtv[GET_ADDR_MODULE].pointer.val = allocate_and_init (the_map);
++ dtv[GET_ADDR_MODULE].pointer.is_static = false;
+ }
+
+ return (char *) p + GET_ADDR_OFFSET;
+--- libc/sysdeps/generic/libc-tls.c.jj 2005-02-26 02:09:44.000000000 +0100
++++ libc/sysdeps/generic/libc-tls.c 2005-11-22 17:33:41.000000000 +0100
+@@ -177,17 +177,18 @@ __libc_setup_tls (size_t tcbsize, size_t
+
+ /* Initialize the TLS block. */
+ # if TLS_TCB_AT_TP
+- static_dtv[2].pointer = ((char *) tlsblock + tcb_offset
+- - roundup (memsz, align ?: 1));
++ static_dtv[2].pointer.val = ((char *) tlsblock + tcb_offset
++ - roundup (memsz, align ?: 1));
+ static_map.l_tls_offset = roundup (memsz, align ?: 1);
+ # elif TLS_DTV_AT_TP
+- static_dtv[2].pointer = (char *) tlsblock + tcb_offset;
++ static_dtv[2].pointer.val = (char *) tlsblock + tcb_offset;
+ static_map.l_tls_offset = tcb_offset;
+ # else
+ # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+ # endif
++ static_dtv[2].pointer.is_static = true;
+ /* sbrk gives us zero'd memory, so we don't need to clear the remainder. */
+- memcpy (static_dtv[2].pointer, initimage, filesz);
++ memcpy (static_dtv[2].pointer.val, initimage, filesz);
+
+ /* Install the pointer to the dtv. */
+
+--- libc/linuxthreads_db/td_thr_tlsbase.c.jj 2004-03-14 04:40:06.000000000 +0100
++++ libc/linuxthreads_db/td_thr_tlsbase.c 2005-11-22 18:01:28.000000000 +0100
+@@ -59,10 +59,10 @@ td_thr_tlsbase (const td_thrhandle_t *th
+
+ /* It could be that the memory for this module is not allocated for
+ the given thread. */
+- if (pdtv.pointer == TLS_DTV_UNALLOCATED)
++ if (pdtv.pointer.val == TLS_DTV_UNALLOCATED)
+ return TD_TLSDEFER;
+
+- *base = (char *) pdtv.pointer;
++ *base = (char *) pdtv.pointer.val;
+
+ return TD_OK;
+ #else
+--- libc/nptl/sysdeps/alpha/tls.h.jj 2004-01-16 06:23:05.000000000 +0100
++++ libc/nptl/sysdeps/alpha/tls.h 2005-11-22 17:33:41.000000000 +0100
+@@ -23,6 +23,7 @@
+ # include <dl-sysdep.h>
+
+ #ifndef __ASSEMBLER__
++# include <stdbool.h>
+ # include <stddef.h>
+ # include <stdint.h>
+
+@@ -30,7 +31,11 @@
+ typedef union dtv
+ {
+ size_t counter;
+- void *pointer;
++ struct
++ {
++ void *val;
++ bool is_static;
++ } pointer;
+ } dtv_t;
+
+ #else /* __ASSEMBLER__ */
+--- libc/nptl/sysdeps/s390/tls.h.jj 2004-03-08 19:41:36.000000000 +0100
++++ libc/nptl/sysdeps/s390/tls.h 2005-11-22 17:33:41.000000000 +0100
+@@ -22,6 +22,7 @@
+
+ #include <dl-sysdep.h>
+ #ifndef __ASSEMBLER__
++# include <stdbool.h>
+ # include <stddef.h>
+ # include <stdint.h>
+ # include <stdlib.h>
+@@ -32,7 +33,11 @@
+ typedef union dtv
+ {
+ size_t counter;
+- void *pointer;
++ struct
++ {
++ void *val;
++ bool is_static;
++ } pointer;
+ } dtv_t;
+
+
+--- libc/nptl/sysdeps/powerpc/tls.h.jj 2004-01-06 11:31:07.000000000 +0100
++++ libc/nptl/sysdeps/powerpc/tls.h 2005-11-22 17:33:41.000000000 +0100
+@@ -23,6 +23,7 @@
+ # include <dl-sysdep.h>
+
+ #ifndef __ASSEMBLER__
++# include <stdbool.h>
+ # include <stddef.h>
+ # include <stdint.h>
+
+@@ -30,7 +31,11 @@
+ typedef union dtv
+ {
+ size_t counter;
+- void *pointer;
++ struct
++ {
++ void *val;
++ bool is_static;
++ } pointer;
+ } dtv_t;
+
+ #else /* __ASSEMBLER__ */
+--- libc/nptl/sysdeps/sparc/tls.h.jj 2004-01-06 11:31:07.000000000 +0100
++++ libc/nptl/sysdeps/sparc/tls.h 2005-11-22 17:33:41.000000000 +0100
+@@ -22,6 +22,7 @@
+
+ #include <dl-sysdep.h>
+ #ifndef __ASSEMBLER__
++# include <stdbool.h>
+ # include <stddef.h>
+ # include <stdint.h>
+ # include <stdlib.h>
+@@ -31,7 +32,11 @@
+ typedef union dtv
+ {
+ size_t counter;
+- void *pointer;
++ struct
++ {
++ void *val;
++ bool is_static;
++ } pointer;
+ } dtv_t;
+
+ typedef struct
+--- libc/nptl/sysdeps/sh/tls.h.jj 2004-11-19 00:59:45.000000000 +0100
++++ libc/nptl/sysdeps/sh/tls.h 2005-11-22 17:33:41.000000000 +0100
+@@ -23,6 +23,7 @@
+ # include <dl-sysdep.h>
+
+ #ifndef __ASSEMBLER__
++# include <stdbool.h>
+ # include <stddef.h>
+ # include <stdint.h>
+
+@@ -30,7 +31,11 @@
+ typedef union dtv
+ {
+ size_t counter;
+- void *pointer;
++ struct
++ {
++ void *val;
++ bool is_static;
++ } pointer;
+ } dtv_t;
+
+ typedef struct
+--- libc/nptl/sysdeps/i386/tls.h.jj 2005-02-16 09:45:55.000000000 +0100
++++ libc/nptl/sysdeps/i386/tls.h 2005-11-22 17:33:41.000000000 +0100
+@@ -22,6 +22,7 @@
+
+ #include <dl-sysdep.h>
+ #ifndef __ASSEMBLER__
++# include <stdbool.h>
+ # include <stddef.h>
+ # include <stdint.h>
+ # include <stdlib.h>
+@@ -32,7 +33,11 @@
+ typedef union dtv
+ {
+ size_t counter;
+- void *pointer;
++ struct
++ {
++ void *val;
++ bool is_static;
++ } pointer;
+ } dtv_t;
+
+
+--- libc/nptl/sysdeps/ia64/tls.h.jj 2004-03-07 23:05:39.000000000 +0100
++++ libc/nptl/sysdeps/ia64/tls.h 2005-11-22 17:33:41.000000000 +0100
+@@ -22,6 +22,7 @@
+
+ #include <dl-sysdep.h>
+ #ifndef __ASSEMBLER__
++# include <stdbool.h>
+ # include <stddef.h>
+ # include <stdint.h>
+ # include <stdlib.h>
+@@ -32,7 +33,11 @@
+ typedef union dtv
+ {
+ size_t counter;
+- void *pointer;
++ struct
++ {
++ void *val;
++ bool is_static;
++ } pointer;
+ } dtv_t;
+
+
+--- libc/nptl/sysdeps/x86_64/tls.h.jj 2003-09-09 09:00:21.000000000 +0200
++++ libc/nptl/sysdeps/x86_64/tls.h 2005-11-22 17:33:41.000000000 +0100
+@@ -22,6 +22,7 @@
+
+ #include <asm/prctl.h> /* For ARCH_SET_FS. */
+ #ifndef __ASSEMBLER__
++# include <stdbool.h>
+ # include <stddef.h>
+ # include <stdint.h>
+ # include <stdlib.h>
+@@ -31,7 +32,11 @@
+ typedef union dtv
+ {
+ size_t counter;
+- void *pointer;
++ struct
++ {
++ void *val;
++ bool is_static;
++ } pointer;
+ } dtv_t;
+
+
+--- libc/nptl/allocatestack.c.jj 2005-11-17 13:07:35.000000000 +0100
++++ libc/nptl/allocatestack.c 2005-11-22 17:33:41.000000000 +0100
+@@ -925,7 +925,8 @@ init_one_static_tls (struct pthread *cur
+ # endif
+
+ /* Fill in the DTV slot so that a later LD/GD access will find it. */
+- dtv[map->l_tls_modid].pointer = dest;
++ dtv[map->l_tls_modid].pointer.val = dest;
++ dtv[map->l_tls_modid].pointer.is_static = true;
+
+ /* Initialize the memory. */
+ memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
+--- libc/linuxthreads/sysdeps/alpha/tls.h.jj 2005-11-17 13:07:34.000000000 +0100
++++ libc/linuxthreads/sysdeps/alpha/tls.h 2005-11-22 17:43:32.000000000 +0100
+@@ -24,12 +24,17 @@
+
+ # include <pt-machine.h>
+ # include <stddef.h>
++# include <stdbool.h>
+
+ /* Type for the dtv. */
+ typedef union dtv
+ {
+ size_t counter;
+- void *pointer;
++ struct
++ {
++ void *val;
++ bool is_static;
++ } pointer;
+ } dtv_t;
+
+
+--- libc/linuxthreads/sysdeps/s390/tls.h.jj 2005-11-17 13:07:34.000000000 +0100
++++ libc/linuxthreads/sysdeps/s390/tls.h 2005-11-22 17:42:01.000000000 +0100
+@@ -24,12 +24,17 @@
+
+ # include <pt-machine.h>
+ # include <stddef.h>
++# include <stdbool.h>
+
+ /* Type for the dtv. */
+ typedef union dtv
+ {
+ size_t counter;
+- void *pointer;
++ struct
++ {
++ void *val;
++ bool is_static;
++ } pointer;
+ } dtv_t;
+
+ typedef struct
+--- libc/linuxthreads/sysdeps/powerpc/tls.h.jj 2005-11-17 13:07:34.000000000 +0100
++++ libc/linuxthreads/sysdeps/powerpc/tls.h 2005-11-22 17:41:08.000000000 +0100
+@@ -24,12 +24,17 @@
+
+ # include <pt-machine.h>
+ # include <stddef.h>
++# include <stdbool.h>
+
+ /* Type for the dtv. */
+ typedef union dtv
+ {
+ size_t counter;
+- void *pointer;
++ struct
++ {
++ void *val;
++ bool is_static;
++ } pointer;
+ } dtv_t;
+
+ #else /* __ASSEMBLER__ */
+--- libc/linuxthreads/sysdeps/sparc/tls.h.jj 2005-11-17 13:07:34.000000000 +0100
++++ libc/linuxthreads/sysdeps/sparc/tls.h 2005-11-22 17:42:36.000000000 +0100
+@@ -24,12 +24,17 @@
+
+ # include <pt-machine.h>
+ # include <stddef.h>
++# include <stdbool.h>
+
+ /* Type for the dtv. */
+ typedef union dtv
+ {
+ size_t counter;
+- void *pointer;
++ struct
++ {
++ void *val;
++ bool is_static;
++ } pointer;
+ } dtv_t;
+
+ typedef struct
+--- libc/linuxthreads/sysdeps/sh/tls.h.jj 2005-11-17 13:07:34.000000000 +0100
++++ libc/linuxthreads/sysdeps/sh/tls.h 2005-11-22 17:42:18.000000000 +0100
+@@ -26,12 +26,17 @@
+ #ifndef __ASSEMBLER__
+ # include <stddef.h>
+ # include <stdint.h>
++# include <stdbool.h>
+
+ /* Type for the dtv. */
+ typedef union dtv
+ {
+ size_t counter;
+- void *pointer;
++ struct
++ {
++ void *val;
++ bool is_static;
++ } pointer;
+ } dtv_t;
+
+ #else /* __ASSEMBLER__ */
+--- libc/linuxthreads/sysdeps/i386/tls.h.jj 2005-11-17 13:07:34.000000000 +0100
++++ libc/linuxthreads/sysdeps/i386/tls.h 2005-11-22 17:41:26.000000000 +0100
+@@ -24,6 +24,7 @@
+ # include <pt-machine.h>
+
+ #ifndef __ASSEMBLER__
++# include <stdbool.h>
+ # include <stddef.h>
+ # include <stdint.h>
+
+@@ -31,7 +32,11 @@
+ typedef union dtv
+ {
+ size_t counter;
+- void *pointer;
++ struct
++ {
++ void *val;
++ bool is_static;
++ } pointer;
+ } dtv_t;
+
+
+--- libc/linuxthreads/sysdeps/ia64/tls.h.jj 2005-11-17 13:07:34.000000000 +0100
++++ libc/linuxthreads/sysdeps/ia64/tls.h 2005-11-22 17:41:32.000000000 +0100
+@@ -22,6 +22,7 @@
+
+ #ifndef __ASSEMBLER__
+
++# include <stdbool.h>
+ # include <dl-sysdep.h>
+ # include <pt-machine.h>
+ # include <stddef.h>
+@@ -30,7 +31,11 @@
+ typedef union dtv
+ {
+ size_t counter;
+- void *pointer;
++ struct
++ {
++ void *val;
++ bool is_static;
++ } pointer;
+ } dtv_t;
+
+ #else /* __ASSEMBLER__ */
+--- libc/linuxthreads/sysdeps/x86_64/tls.h.jj 2005-11-17 13:07:34.000000000 +0100
++++ libc/linuxthreads/sysdeps/x86_64/tls.h 2005-11-22 17:43:00.000000000 +0100
+@@ -24,12 +24,17 @@
+
+ # include <pt-machine.h>
+ # include <stddef.h>
++# include <stdbool.h>
+
+ /* Type for the dtv. */
+ typedef union dtv
+ {
+ size_t counter;
+- void *pointer;
++ struct
++ {
++ void *val;
++ bool is_static;
++ } pointer;
+ } dtv_t;
+
+
+--- libc/linuxthreads/pthread.c.jj 2004-10-06 10:04:43.000000000 +0200
++++ libc/linuxthreads/pthread.c 2005-11-22 18:02:06.000000000 +0100
+@@ -482,7 +482,8 @@ init_one_static_tls (pthread_descr descr
+ # endif
+
+ /* Fill in the DTV slot so that a later LD/GD access will find it. */
+- dtv[map->l_tls_modid].pointer = dest;
++ dtv[map->l_tls_modid].pointer.val = dest;
++ dtv[map->l_tls_modid].pointer.is_static = true;
+
+ /* Initialize the memory. */
+ memset (__mempcpy (dest, map->l_tls_initimage, map->l_tls_initimage_size),
+--- libc/nptl_db/structs.def 18 Dec 2003 02:51:04 -0000 1.2
++++ libc/nptl_db/structs.def 4 Feb 2006 00:47:58 -0000 1.3
+@@ -74,6 +74,8 @@ DB_STRUCT_FIELD (link_map, l_tls_modid)
+
+ #if !defined IS_IN_libpthread || USE_TLS
+ DB_STRUCT_ARRAY_FIELD (dtv, dtv)
++# define pointer_val pointer.val /* Field of anonymous struct in dtv_t. */
++DB_STRUCT_FIELD (dtv_t, pointer_val)
+ #endif
+ #if !defined IS_IN_libpthread || TLS_TCB_AT_TP
+ DB_STRUCT_FIELD (pthread, dtvp)
+--- libc/nptl_db/td_thr_tlsbase.c 9 Sep 2003 06:57:51 -0000 1.2
++++ libc/nptl_db/td_thr_tlsbase.c 4 Feb 2006 00:47:58 -0000 1.3
+@@ -25,7 +25,7 @@ td_thr_tlsbase (const td_thrhandle_t *th
+ psaddr_t *base)
+ {
+ td_err_e err;
+- psaddr_t dtv, dtvptr;
++ psaddr_t dtv, dtvslot, dtvptr;
+
+ if (modid < 1)
+ return TD_NOTLS;
+@@ -35,8 +35,13 @@ td_thr_tlsbase (const td_thrhandle_t *th
+ if (err != TD_OK)
+ return err;
+
+- /* Get the corresponding entry in the DTV. */
+- err = DB_GET_FIELD (dtvptr, th->th_ta_p, dtv, dtv, dtv, modid);
++ /* Find the corresponding entry in the DTV. */
++ err = DB_GET_FIELD_ADDRESS (dtvslot, th->th_ta_p, dtv, dtv, dtv, modid);
++ if (err != TD_OK)
++ return err;
++
++ /* Extract the TLS block address from that DTV slot. */
++ err = DB_GET_FIELD (dtvptr, th->th_ta_p, dtvslot, dtv_t, pointer_val, 0);
+ if (err != TD_OK)
+ return err;
+
--- /dev/null
+2005-07-30 Ulrich Drepper <drepper@redhat.com>
+
+ * elf/dl-load.c [__WORDSIZE==64] (FILEBUF_SIZE): Adjust the value
+ up. We have more program header entries now and the note section
+ was normally not loaded.
+
+--- libc/elf/dl-load.c 26 Apr 2005 04:25:58 -0000 1.268
++++ libc/elf/dl-load.c 30 Jul 2005 21:14:33 -0000 1.269
+@@ -122,19 +122,19 @@ int __stack_prot attribute_hidden attrib
+ question is how large are the ELF and program header combined. The
+ ELF header 32-bit files is 52 bytes long and in 64-bit files is 64
+ bytes long. Each program header entry is again 32 and 56 bytes
+- long respectively. I.e., even with a file which has 7 program
+- header entries we only have to read 512B. Add to this a bit of
+- margin for program notes and reading 512B and 640B for 32-bit and
+- 64-bit files respecitvely is enough. If this heuristic should
+- really fail for some file the code in `_dl_map_object_from_fd'
+- knows how to recover. */
++ long respectively. I.e., even with a file which has 10 program
++ header entries we only have to read 372B/624B respectively. Add to
++ this a bit of margin for program notes and reading 512B and 832B
++ for 32-bit and 64-bit files respecitvely is enough. If this
++ heuristic should really fail for some file the code in
++ `_dl_map_object_from_fd' knows how to recover. */
+ struct filebuf
+ {
+ ssize_t len;
+ #if __WORDSIZE == 32
+ # define FILEBUF_SIZE 512
+ #else
+-# define FILEBUF_SIZE 640
++# define FILEBUF_SIZE 832
+ #endif
+ char buf[FILEBUF_SIZE] __attribute__ ((aligned (__alignof (ElfW(Ehdr)))));
+ };
--- /dev/null
+2005-11-27 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/posix/euidaccess.c [_LIBC] (euidaccess): Don't cache
+ euid and egid.
+
+--- libc/sysdeps/posix/euidaccess.c 6 Jul 2001 04:56:01 -0000 1.11
++++ libc/sysdeps/posix/euidaccess.c 27 Nov 2005 17:13:35 -0000 1.12
+@@ -93,14 +93,6 @@ static uid_t uid;
+ /* The user's real group id. */
+ static gid_t gid;
+
+-#ifdef HAVE_GETGROUPS
+-int group_member ();
+-#else
+-#define group_member(gid) 0
+-#endif
+-
+-#endif
+-
+ /* The user's effective user id. */
+ static uid_t euid;
+
+@@ -110,6 +102,14 @@ static gid_t egid;
+ /* Nonzero if UID, GID, EUID, and EGID have valid values. */
+ static int have_ids;
+
++# ifdef HAVE_GETGROUPS
++int group_member ();
++# else
++# define group_member(gid) 0
++# endif
++
++#endif
++
+
+ /* Return 0 if the user has permission of type MODE on file PATH;
+ otherwise, return -1 and set `errno' to EACCESS.
+@@ -126,6 +126,9 @@ euidaccess (path, mode)
+ int granted;
+
+ #ifdef _LIBC
++ uid_t euid;
++ gid_t egid;
++
+ if (! __libc_enable_secure)
+ /* If we are not set-uid or set-gid, access does the same. */
+ return __access (path, mode);
+@@ -157,12 +160,8 @@ euidaccess (path, mode)
+
+ #ifdef _LIBC
+ /* Now we need the IDs. */
+- if (have_ids == 0)
+- {
+- have_ids = 1;
+- euid = __geteuid ();
+- egid = __getegid ();
+- }
++ euid = __geteuid ();
++ egid = __getegid ();
+ #endif
+
+ /* The super-user can read and write any file, and execute any file
+@@ -177,6 +176,7 @@ euidaccess (path, mode)
+ granted = (unsigned) (stats.st_mode & (mode << 3)) >> 3;
+ else
+ granted = (stats.st_mode & mode);
++ /* XXX Add support for ACLs. */
+ if (granted == mode)
+ return 0;
+ __set_errno (EACCESS);
--- /dev/null
+2005-09-26 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #713]
+ * libio/iofgets.c: Treat N==1 correctly.
+ * libio/iofgets_u.c: Likewise.
+ * libio/iofgetws.c: Likewise.
+ * libio/iofgetws_u.c: Likewise.
+ * stdio-common/Makefile (tests): Add tst-fgets.
+ * stdio-common/tst-fgets.c: New file.
+
+--- libc/stdio-common/tst-fgets.c 1 Jan 1970 00:00:00 -0000
++++ libc/stdio-common/tst-fgets.c 26 Sep 2005 23:59:46 -0000 1.1
+@@ -0,0 +1,20 @@
++/* Derived from the test case in
++ http://sourceware.org/bugzilla/show_bug.cgi?id=713. */
++#include <stdio.h>
++
++static int
++do_test (void)
++{
++ FILE *fp = fmemopen ("hello", 5, "r");
++ char buf[2];
++ char *bp = fgets (buf, sizeof (buf), fp);
++ printf ("fgets: %s\n", bp == buf ? "OK" : "ERROR");
++ int res = bp != buf;
++ bp = fgets_unlocked (buf, sizeof (buf), fp);
++ printf ("fgets_unlocked: %s\n", bp == buf ? "OK" : "ERROR");
++ res |= bp != buf;
++ return res;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- libc/stdio-common/Makefile 4 Sep 2005 20:04:54 -0000 1.93
++++ libc/stdio-common/Makefile 26 Sep 2005 23:58:58 -0000 1.94
+@@ -53,7 +53,7 @@ tests := tstscanf test_rdwr test-popen t
+ scanf11 scanf12 tst-tmpnam tst-cookie tst-obprintf tst-sscanf \
+ tst-swprintf tst-fseek tst-fmemopen test-vfprintf tst-gets \
+ tst-perror tst-sprintf tst-rndseek tst-fdopen tst-fphex bug14 bug15 \
+- tst-popen tst-unlockedio tst-fmemopen2
++ tst-popen tst-unlockedio tst-fmemopen2 tst-fgets
+
+ test-srcs = tst-unbputc tst-printf
+
+--- libc/libio/iofgets.c 29 Aug 2003 19:58:27 -0000 1.17
++++ libc/libio/iofgets.c 26 Sep 2005 23:55:00 -0000 1.18
+@@ -41,6 +41,14 @@ _IO_fgets (buf, n, fp)
+ CHECK_FILE (fp, NULL);
+ if (n <= 0)
+ return NULL;
++ if (__builtin_expect (n == 1, 0))
++ {
++ /* Another irregular case: since we have to store a NUL byte and
++ there is only room for exactly one byte, we don't have to
++ read anything. */
++ buf[0] = '\0';
++ return buf;
++ }
+ _IO_acquire_lock (fp);
+ /* This is very tricky since a file descriptor may be in the
+ non-blocking mode. The error flag doesn't mean much in this
+--- libc/libio/iofgets_u.c 4 Aug 2002 20:32:04 -0000 1.5
++++ libc/libio/iofgets_u.c 26 Sep 2005 23:54:27 -0000 1.6
+@@ -40,6 +40,14 @@ fgets_unlocked (buf, n, fp)
+ CHECK_FILE (fp, NULL);
+ if (n <= 0)
+ return NULL;
++ if (__builtin_expect (n == 1, 0))
++ {
++ /* Another irregular case: since we have to store a NUL byte and
++ there is only room for exactly one byte, we don't have to
++ read anything. */
++ buf[0] = '\0';
++ return buf;
++ }
+ /* This is very tricky since a file descriptor may be in the
+ non-blocking mode. The error flag doesn't mean much in this
+ case. We return an error only when there is a new error. */
+--- libc/libio/iofgetws.c 29 Aug 2003 19:58:27 -0000 1.4
++++ libc/libio/iofgetws.c 26 Sep 2005 23:53:54 -0000 1.5
+@@ -41,6 +41,14 @@ fgetws (buf, n, fp)
+ CHECK_FILE (fp, NULL);
+ if (n <= 0)
+ return NULL;
++ if (__builtin_expect (n == 1, 0))
++ {
++ /* Another irregular case: since we have to store a NUL byte and
++ there is only room for exactly one byte, we don't have to
++ read anything. */
++ buf[0] = L'\0';
++ return buf;
++ }
+ _IO_acquire_lock (fp);
+ /* This is very tricky since a file descriptor may be in the
+ non-blocking mode. The error flag doesn't mean much in this
+--- libc/libio/iofgetws_u.c 6 Jul 2001 04:54:55 -0000 1.2
++++ libc/libio/iofgetws_u.c 26 Sep 2005 23:53:20 -0000 1.3
+@@ -40,6 +40,14 @@ fgetws_unlocked (buf, n, fp)
+ CHECK_FILE (fp, NULL);
+ if (n <= 0)
+ return NULL;
++ if (__builtin_expect (n == 1, 0))
++ {
++ /* Another irregular case: since we have to store a NUL byte and
++ there is only room for exactly one byte, we don't have to
++ read anything. */
++ buf[0] = L'\0';
++ return buf;
++ }
+ /* This is very tricky since a file descriptor may be in the
+ non-blocking mode. The error flag doesn't mean much in this
+ case. We return an error only when there is a new error. */
--- /dev/null
+2006-03-29 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/posix/getaddrinfo.c (gaih_inet): No need to duplicate
+ 'name' for 'canon'. The final allocation will happen later.
+
+--- libc/sysdeps/posix/getaddrinfo.c 20 Dec 2005 16:49:19 -0000 1.93
++++ libc/sysdeps/posix/getaddrinfo.c 29 Mar 2006 17:49:24 -0000 1.94
+@@ -538,16 +538,10 @@ gaih_inet (const char *name, const struc
+ else
+ return -EAI_ADDRFAMILY;
+
+- dupname:
+ if (req->ai_flags & AI_CANONNAME)
+- {
+- canon = strdup (name);
+- if (canon == NULL)
+- return -EAI_MEMORY;
+- }
++ canon = name;
+ }
+-
+- if (at->family == AF_UNSPEC)
++ else if (at->family == AF_UNSPEC)
+ {
+ char *namebuf = (char *) name;
+ char *scope_delim = strchr (name, SCOPE_DELIMITER);
+@@ -595,7 +589,8 @@ gaih_inet (const char *name, const struc
+ }
+ }
+
+- goto dupname;
++ if (req->ai_flags & AI_CANONNAME)
++ canon = name;
+ }
+ }
+
--- /dev/null
+2006-01-10 Ulrich Drepper <drepper@redhat.com>
+
+ * iconv/gconv_cache.c (free_mem): Don't call munmap if gconv_cache
+ is NULL.
+
+--- libc/iconv/gconv_cache.c 20 Dec 2005 16:20:35 -0000 1.20
++++ libc/iconv/gconv_cache.c 11 Jan 2006 07:08:29 -0000 1.21
+@@ -467,7 +467,7 @@ libc_freeres_fn (free_mem)
+ if (cache_malloced)
+ free (gconv_cache);
+ #ifdef _POSIX_MAPPED_FILES
+- else
++ else if (gconv_cache != NULL)
+ __munmap (gconv_cache, cache_size);
+ #endif
+ }
--- /dev/null
+2005-01-11 Thorsten Kukuk <kukuk@suse.de>
+
+ [BZ #652]
+ * posix/getconf.c: Add new option -a to print the names of
+ the current system configuration variables to stdout.
+ Based on patch from Josh Aas <josha@sgi.com>.
+
+--- libc/posix/getconf.c 12 Jan 2005 23:39:50 -0000 1.39
++++ libc/posix/getconf.c 26 Sep 2005 23:00:46 -0000 1.40
+@@ -941,9 +941,54 @@ usage (void)
+ fprintf (stderr,
+ _("Usage: %s [-v specification] variable_name [pathname]\n"),
+ __progname);
++ fprintf (stderr,
++ _(" %s -a [pathname]\n"), __progname);
+ exit (2);
+ }
+
++static void
++print_all (const char *path)
++{
++ register const struct conf *c;
++ size_t clen;
++ long int value;
++ char *cvalue;
++ for (c = vars; c->name != NULL; ++c) {
++ printf("%-35s", c->name);
++ switch (c->call) {
++ case PATHCONF:
++ value = pathconf (path, c->call_name);
++ if (value != -1) {
++ printf("%ld", value);
++ }
++ printf("\n");
++ break;
++ case SYSCONF:
++ value = sysconf (c->call_name);
++ if (value == -1l) {
++ if (c->call_name == _SC_UINT_MAX
++ || c->call_name == _SC_ULONG_MAX)
++ printf ("%lu", value);
++ }
++ else {
++ printf ("%ld", value);
++ }
++ printf ("\n");
++ break;
++ case CONFSTR:
++ clen = confstr (c->call_name, (char *) NULL, 0);
++ cvalue = (char *) malloc (clen);
++ if (cvalue == NULL)
++ error (3, 0, _("memory exhausted"));
++ if (confstr (c->call_name, cvalue, clen) != clen)
++ error (3, errno, "confstr");
++ printf ("%.*s\n", (int) clen, cvalue);
++ break;
++ }
++ }
++ exit (0);
++}
++
+ int
+ main (int argc, char *argv[])
+ {
+@@ -1050,6 +1095,16 @@ warranty; not even for MERCHANTABILITY o
+ }
+ }
+
++ if (argc > 1 && strcmp (argv[1], "-a") == 0)
++ {
++ if (argc == 2)
++ print_all ("/");
++ else if (argc == 3)
++ print_all (argv[2]);
++ else
++ usage ();
++ }
++
+ if (argc < 2 || argc > 3)
+ usage ();
+
--- /dev/null
+2005-10-13 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #1405]
+ * libio/iogetdelim.c (_IO_getdelim): Fix truncation of return
+ value. Avoid overflow in computation.
+
+--- libc/libio/iogetdelim.c 29 Aug 2003 19:58:27 -0000 1.13
++++ libc/libio/iogetdelim.c 14 Oct 2005 06:24:58 -0000 1.14
+@@ -45,7 +45,7 @@ _IO_getdelim (lineptr, n, delimiter, fp)
+ int delimiter;
+ _IO_FILE *fp;
+ {
+- int result;
++ _IO_ssize_t result;
+ _IO_ssize_t cur_len = 0;
+ _IO_ssize_t len;
+
+@@ -91,6 +91,12 @@ _IO_getdelim (lineptr, n, delimiter, fp)
+ t = (char *) memchr ((void *) fp->_IO_read_ptr, delimiter, len);
+ if (t != NULL)
+ len = (t - fp->_IO_read_ptr) + 1;
++ if (__builtin_expect (cur_len + len + 1 < 0, 0))
++ {
++ __set_errno (EOVERFLOW);
++ result = -1;
++ goto unlock_return;
++ }
+ /* Make enough space for len+1 (for final NUL) bytes. */
+ needed = cur_len + len + 1;
+ if (needed > *n)
--- /dev/null
+2005-10-08 Jakub Jelinek <jakub@redhat.com>
+
+ * nss/getent.c (hosts_keys): Pass INADDRSZ as size rather
+ than IN6ADDRSZ to AF_INET gethostbyaddr.
+
+--- libc/nss/getent.c 10 Sep 2005 02:37:44 -0000 1.26
++++ libc/nss/getent.c 8 Oct 2005 17:28:41 -0000 1.27
+@@ -280,9 +280,9 @@ hosts_keys (int number, char *key[])
+ char addr[IN6ADDRSZ];
+
+ if (inet_pton (AF_INET6, key[i], &addr) > 0)
+- host = gethostbyaddr (addr, sizeof (addr), AF_INET6);
++ host = gethostbyaddr (addr, IN6ADDRSZ, AF_INET6);
+ else if (inet_pton (AF_INET, key[i], &addr) > 0)
+- host = gethostbyaddr (addr, sizeof (addr), AF_INET);
++ host = gethostbyaddr (addr, INADDRSZ, AF_INET);
+ else if ((host = gethostbyname2 (key[i], AF_INET6)) == NULL)
+ host = gethostbyname2 (key[i], AF_INET);
+
--- /dev/null
+2005-09-09 Ulrich Drepper <drepper@redhat.com>
+
+ * nss/getent.c (netgroup_keys): Call endnetgrent.
+
+--- libc/nss/getent.c 16 Aug 2005 15:57:39 -0000 1.25
++++ libc/nss/getent.c 10 Sep 2005 02:37:44 -0000 1.26
+@@ -410,6 +411,8 @@ netgroup_keys (int number, char *key[])
+ }
+ }
+
++ endnetgrent ();
++
+ return result;
+ }
+
--- /dev/null
+2005-07-11 Derek R. Price <derek@ximbiot.com>
+
+ [BZ #1061]
+ * sysdeps/generic/glob.c (glob): Only a 0 return from
+ getlogin_r means success, according to POSIX 1003.2.
+
+--- libc/sysdeps/generic/glob.c 27 Oct 2004 18:21:02 -0000 1.53
++++ libc/sysdeps/generic/glob.c 8 Sep 2005 08:09:03 -0000 1.54
+@@ -715,7 +715,7 @@ glob (pattern, flags, errfunc, pglob)
+ buflen = 20;
+ name = (char *) __alloca (buflen);
+
+- success = getlogin_r (name, buflen) >= 0;
++ success = getlogin_r (name, buflen) == 0;
+ # else
+ success = (name = getlogin ()) != NULL;
+ # endif
--- /dev/null
+2007-07-01 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/generic/dl-sysdep.c (_dl_important_hwcaps): Add integer
+ overflow check.
+ * elf/dl-minimal.c (__libc_memalign): Likewise. Handle malloc (0).
+ Return NULL if mmap failed instead of asserting it does not.
+ (calloc): Check for integer overflow.
+
+ * elf/dl-minimal.c (__strtoul_internal): Fix parsing of numbers bigger
+ than LONG_MAX / 10.
+
+--- libc/elf/dl-minimal.c 25 Jan 2007 17:10:40 -0000 1.53
++++ libc/elf/dl-minimal.c 4 Jul 2007 18:06:29 -0000 1.54
+@@ -75,14 +75,21 @@ __libc_memalign (size_t align, size_t n)
+ alloc_ptr = (void *) 0 + (((alloc_ptr - (void *) 0) + align - 1)
+ & ~(align - 1));
+
+- if (alloc_ptr + n >= alloc_end)
++ if (alloc_ptr + n >= alloc_end || n >= -(uintptr_t) alloc_ptr)
+ {
+ /* Insufficient space left; allocate another page. */
+ caddr_t page;
+ size_t nup = (n + GLRO(dl_pagesize) - 1) & ~(GLRO(dl_pagesize) - 1);
++ if (__builtin_expect (nup == 0, 0))
++ {
++ if (n)
++ return NULL;
++ nup = GLRO(dl_pagesize);
++ }
+ page = __mmap (0, nup, PROT_READ|PROT_WRITE,
+ MAP_ANON|MAP_PRIVATE, _dl_zerofd, 0);
+- assert (page != MAP_FAILED);
++ if (page == MAP_FAILED)
++ return NULL;
+ if (page != alloc_end)
+ alloc_ptr = page;
+ alloc_end = page + nup;
+@@ -108,7 +115,14 @@ calloc (size_t nmemb, size_t size)
+ /* New memory from the trivial malloc above is always already cleared.
+ (We make sure that's true in the rare occasion it might not be,
+ by clearing memory in free, below.) */
+- return malloc (nmemb * size);
++ size_t bytes = nmemb * size;
++
++#define HALF_SIZE_T (((size_t) 1) << (8 * sizeof (size_t) / 2))
++ if (__builtin_expect ((nmemb | size) >= HALF_SIZE_T, 0)
++ && size != 0 && bytes / size != nmemb)
++ return NULL;
++
++ return malloc (bytes);
+ }
+
+ /* This will rarely be called. */
+@@ -264,7 +278,7 @@ __strtoul_internal (const char *nptr, ch
+ while (*nptr >= '0' && *nptr <= '9')
+ {
+ unsigned long int digval = *nptr - '0';
+- if (result > LONG_MAX / 10
++ if (result > ULONG_MAX / 10
+ || (result == ULONG_MAX / 10 && digval > ULONG_MAX % 10))
+ {
+ errno = ERANGE;
+--- libc/sysdeps/generic/dl-sysdep.c 27 Oct 2006 23:11:42 -0000 1.2
++++ libc/sysdeps/generic/dl-sysdep.c 4 Jul 2007 18:06:06 -0000 1.3
+@@ -460,9 +460,21 @@ _dl_important_hwcaps (const char *platfo
+ total = temp[0].len + 1;
+ else
+ {
+- total = (1UL << (cnt - 2)) * (temp[0].len + temp[cnt - 1].len + 2);
+- for (n = 1; n + 1 < cnt; ++n)
+- total += (1UL << (cnt - 3)) * (temp[n].len + 1);
++ total = temp[0].len + temp[cnt - 1].len + 2;
++ if (cnt > 2)
++ {
++ total <<= 1;
++ for (n = 1; n + 1 < cnt; ++n)
++ total += temp[n].len + 1;
++ if (cnt > 3
++ && (cnt >= sizeof (size_t) * 8
++ || total + (sizeof (*result) << 3)
++ >= (1UL << (sizeof (size_t) * 8 - cnt + 3))))
++ _dl_signal_error (ENOMEM, NULL, NULL,
++ N_("cannot create capability list"));
++
++ total <<= cnt - 3;
++ }
+ }
+
+ /* The result structure: we use a very compressed way to store the
--- /dev/null
+2005-08-31 Bob Wilson <bob.wilson@acm.org>
+
+ * sysdeps/ieee754/flt-32/e_hypotf.c (__ieee754_hypotf): Remove the
+ exponent bias from the increment value for scaling by 2^60.
+
+2005-08-30 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/ieee754/flt-32/e_hypotf.c [!__STDC__]: Fix function name.
+
+2005-08-01 Bob Wilson <bob.wilson@acm.org>
+ Richard Sandiford <richard@codesourcery.com>
+
+ * sysdeps/ieee754/flt-32/e_hypotf.c (__ieee754_hypotf): Add missing
+ exponent bias to the value for 2^126.
+
+--- libc/sysdeps/ieee754/flt-32/e_hypotf.c 13 Jul 1999 23:58:13 -0000 1.1
++++ libc/sysdeps/ieee754/flt-32/e_hypotf.c 6 Sep 2005 05:36:56 -0000 1.3
+@@ -23,7 +23,7 @@ static char rcsid[] = "$NetBSD: e_hypotf
+ #ifdef __STDC__
+ float __ieee754_hypotf(float x, float y)
+ #else
+- float __ieee754_hypot(x,y)
++ float __ieee754_hypotf(x,y)
+ float x, y;
+ #endif
+ {
+@@ -47,20 +47,20 @@ static char rcsid[] = "$NetBSD: e_hypotf
+ return w;
+ }
+ /* scale a and b by 2**-60 */
+- ha -= 0x5d800000; hb -= 0x5d800000; k += 60;
++ ha -= 0x1e000000; hb -= 0x1e000000; k += 60;
+ SET_FLOAT_WORD(a,ha);
+ SET_FLOAT_WORD(b,hb);
+ }
+ if(hb < 0x26800000) { /* b < 2**-50 */
+ if(hb <= 0x007fffff) { /* subnormal b or 0 */
+ if(hb==0) return a;
+- SET_FLOAT_WORD(t1,0x3f000000); /* t1=2^126 */
++ SET_FLOAT_WORD(t1,0x7e800000); /* t1=2^126 */
+ b *= t1;
+ a *= t1;
+ k -= 126;
+ } else { /* scale a and b by 2^60 */
+- ha += 0x5d800000; /* a *= 2^60 */
+- hb += 0x5d800000; /* b *= 2^60 */
++ ha += 0x1e000000; /* a *= 2^60 */
++ hb += 0x1e000000; /* b *= 2^60 */
+ k -= 60;
+ SET_FLOAT_WORD(a,ha);
+ SET_FLOAT_WORD(b,hb);
--- /dev/null
+2006-02-08 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_futex_timedwait):
+ Add "memory" clobber.
+
+2006-01-05 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_futex_wait):
+ Return status.
+ (lll_futex_timed_wait): Define.
+ * sysdeps/unix/sysv/linux/x86_64/lowlevellock.h: Likewise.
+
+--- libc/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h.jj 2004-03-24 07:35:18.000000000 +0100
++++ libc/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h 2006-02-22 19:02:58.000000000 +0100
+@@ -66,18 +66,35 @@
+
+
+ #define lll_futex_wait(futex, val) \
+- do { \
+- int __ignore; \
++ ({ \
++ int __status; \
+ register __typeof (val) _val asm ("edx") = (val); \
+ __asm __volatile (LLL_EBX_LOAD \
+ LLL_ENTER_KERNEL \
+ LLL_EBX_LOAD \
+- : "=a" (__ignore) \
++ : "=a" (__status) \
+ : "0" (SYS_futex), LLL_EBX_REG (futex), "S" (0), \
+ "c" (FUTEX_WAIT), "d" (_val), \
+ "i" (offsetof (tcbhead_t, sysinfo)) \
+ : "memory"); \
+- } while (0)
++ __status; \
++ })
++
++
++#define lll_futex_timed_wait(futex, val, timeout) \
++ ({ \
++ int __status; \
++ register __typeof (val) _val asm ("edx") = (val); \
++ __asm __volatile (LLL_EBX_LOAD \
++ LLL_ENTER_KERNEL \
++ LLL_EBX_LOAD \
++ : "=a" (__status) \
++ : "0" (SYS_futex), LLL_EBX_REG (futex), "S" (timeout), \
++ "c" (FUTEX_WAIT), "d" (_val), \
++ "i" (offsetof (tcbhead_t, sysinfo)) \
++ : "memory"); \
++ __status; \
++ })
+
+
+ #define lll_futex_wake(futex, nr) \
+--- libc/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h.jj 2004-07-05 19:29:20.000000000 +0200
++++ libc/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h 2006-02-22 19:02:58.000000000 +0100
+@@ -47,16 +47,31 @@
+
+
+ #define lll_futex_wait(futex, val) \
+- do { \
+- int __ignore; \
++ ({ \
++ int __status; \
+ register __typeof (val) _val asm ("edx") = (val); \
+ __asm __volatile ("xorq %%r10, %%r10\n\t" \
+ "syscall" \
+- : "=a" (__ignore) \
++ : "=a" (__status) \
+ : "0" (SYS_futex), "D" (futex), "S" (FUTEX_WAIT), \
+ "d" (_val) \
+ : "memory", "cc", "r10", "r11", "cx"); \
+- } while (0)
++ __status; \
++ })
++
++
++#define lll_futex_timed_wait(futex, val, timeout) \
++ ({ \
++ register const struct timespec *__to __asm__ ("r10") = timeout; \
++ int __status; \
++ register __typeof (val) _val asm ("edx") = (val); \
++ __asm __volatile ("syscall" \
++ : "=a" (__status) \
++ : "0" (SYS_futex), "D" (futex), "S" (FUTEX_WAIT), \
++ "d" (_val), "r" (__to) \
++ : "memory", "cc", "r11", "cx"); \
++ __status; \
++ })
+
+
+ #define lll_futex_wake(futex, nr) \
--- /dev/null
+--- libc/sysdeps/unix/sysv/linux/i386/dl-procinfo.c 2006-10-12 12:20:15.000000000 -0400
++++ libc/sysdeps/unix/sysv/linux/i386/dl-procinfo.c 2006-10-14 18:20:17.000000000 -0400
+@@ -0,0 +1,9 @@
++#ifndef PROCINFO_CLASS
++# define PROCINFO_CLASS
++#endif
++
++#if defined (PROCINFO_DECL) || !defined (SHARED)
++PROCINFO_CLASS int _dl_nosegneg;
++#endif
++
++#include <sysdeps/i386/dl-procinfo.c>
+--- libc/sysdeps/unix/sysv/linux/i386/dl-procinfo.h 2006-10-13 09:17:08.000000000 -0400
++++ libc/sysdeps/unix/sysv/linux/i386/dl-procinfo.h 2006-10-14 16:10:51.000000000 -0400
+@@ -43,0 +44,19 @@
++
++#define DL_ARCH_IMPORTANT_HWCAP(PAIR) \
++({ \
++ int _cnt = 0; \
++ if (GLRO (dl_nosegneg)) \
++ { \
++ struct r_strlenpair *_pair = (PAIR); \
++ if (_pair) \
++ { \
++ _pair->str = "nosegneg"; \
++ _pair->len = 8; \
++ } \
++ ++_cnt; \
++ } \
++ _cnt; })
++
++#define DL_ARCH_HWCAP_MASK \
++ (GLRO (dl_nosegneg) \
++ ? (1ULL << (_DL_FIRST_PLATFORM + _DL_PLATFORMS_COUNT)) : 0LL)
+--- libc/sysdeps/unix/sysv/linux/i386/dl-osinfo.h 2006-10-12 12:31:57.000000000 -0400
++++ libc/sysdeps/unix/sysv/linux/i386/dl-osinfo.h 2006-10-14 16:02:03.000000000 -0400
+@@ -0,0 +1,14 @@
++#define DL_SYSDEP_OSRELEASE_CHECK(STR) \
++ do \
++ { \
++ const char *p; \
++ for (p = (STR); *p != '\0'; ++p) \
++ if (p[0] == 'x' && p[1] == 'e' && p[2] == 'n' && p[3] == 'U') \
++ { \
++ GLRO (dl_nosegneg) = 1; \
++ break; \
++ } \
++ } \
++ while (0)
++
++#include <sysdeps/unix/sysv/linux/dl-osinfo.h>
+--- libc/sysdeps/unix/sysv/linux/dl-osinfo.h.jj 2004-12-16 22:31:50.000000000 -0500
++++ libc/sysdeps/unix/sysv/linux/dl-osinfo.h 2006-10-12 12:23:37.000000000 -0400
+@@ -39,6 +39,9 @@ dl_fatal (const char *str)
+ }
+ #endif
+
++#ifndef DL_SYSDEP_OSRELEASE_CHECK
++# define DL_SYSDEP_OSRELEASE_CHECK(STR) do { } while (0)
++#endif
+
+ #define DL_SYSDEP_OSCHECK(FATAL) \
+ do { \
+@@ -96,6 +99,8 @@ dl_fatal (const char *str)
+ break; \
+ } \
+ \
++ DL_SYSDEP_OSRELEASE_CHECK (cp); \
++ \
+ if (parts < 3) \
+ version <<= 8 * (3 - parts); \
+ \
+--- libc/sysdeps/generic/dl-sysdep.c.jj 2004-11-05 19:24:47.000000000 -0500
++++ libc/sysdeps/generic/dl-sysdep.c 2006-10-13 09:02:01.000000000 -0400
+@@ -357,6 +357,9 @@ _dl_important_hwcaps (const char *platfo
+ if ((masked & (1UL << n)) != 0)
+ ++cnt;
+
++#ifdef DL_ARCH_IMPORTANT_HWCAP
++ cnt += DL_ARCH_IMPORTANT_HWCAP (NULL);
++#endif
+ #ifdef USE_TLS
+ /* For TLS enabled builds always add 'tls'. */
+ ++cnt;
+@@ -380,6 +383,9 @@ _dl_important_hwcaps (const char *platfo
+ /* Create temporary data structure to generate result table. */
+ temp = (struct r_strlenpair *) alloca (cnt * sizeof (*temp));
+ m = 0;
++#ifdef DL_ARCH_IMPORTANT_HWCAP
++ m += DL_ARCH_IMPORTANT_HWCAP (&temp[m]);
++#endif
+ for (n = 0; masked != 0; ++n)
+ if ((masked & (1UL << n)) != 0)
+ {
+--- libc/sysdeps/generic/dl-cache.c.jj 2004-03-18 19:36:32.000000000 -0500
++++ libc/sysdeps/generic/dl-cache.c 2006-10-13 09:14:44.000000000 -0400
+@@ -261,6 +261,11 @@ _dl_load_cache_lookup (const char *name)
+ #else
+ # define _DL_HWCAP_TLS_MASK 0
+ #endif
++#ifndef DL_ARCH_HWCAP_MASK
++# define DL_ARCH_HWCAP_MASK 0
++#endif
++ uint64_t hwcap_check_mask = ~(GLRO(dl_hwcap) | _DL_HWCAP_PLATFORM
++ | _DL_HWCAP_TLS_MASK | DL_ARCH_HWCAP_MASK);
+ #define HWCAP_CHECK \
+ if (GLRO(dl_osversion) && lib->osversion > GLRO(dl_osversion)) \
+ continue; \
+@@ -268,8 +273,7 @@ _dl_load_cache_lookup (const char *name)
+ && (lib->hwcap & _DL_HWCAP_PLATFORM) != 0 \
+ && (lib->hwcap & _DL_HWCAP_PLATFORM) != platform) \
+ continue; \
+- if (lib->hwcap \
+- & ~(GLRO(dl_hwcap) | _DL_HWCAP_PLATFORM | _DL_HWCAP_TLS_MASK)) \
++ if (lib->hwcap & hwcap_check_mask) \
+ continue
+ SEARCH_CACHE (cache_new);
+ }
+--- libc/elf/ldconfig.c.jj 2006-09-01 08:10:14.000000000 -0400
++++ libc/elf/ldconfig.c 2006-10-12 12:33:07.000000000 -0400
+@@ -44,6 +44,12 @@
+
+ #include "dl-procinfo.h"
+
++#ifdef _DL_FIRST_PLATFORM
++# define _DL_FIRST_EXTRA (_DL_FIRST_PLATFORM + _DL_PLATFORMS_COUNT)
++#else
++# define _DL_FIRST_EXTRA _DL_HWCAP_COUNT
++#endif
++
+ #ifndef LD_SO_CONF
+ # define LD_SO_CONF SYSCONFDIR "/ld.so.conf"
+ #endif
+@@ -115,6 +121,9 @@ static const char *config_file;
+ /* Mask to use for important hardware capabilities. */
+ static unsigned long int hwcap_mask = HWCAP_IMPORTANT;
+
++/* Configuration-defined capabilities defined in kernel vDSOs. */
++static const char *hwcap_extra[64 - _DL_FIRST_EXTRA];
++
+ /* Name and version of program. */
+ static void print_version (FILE *stream, struct argp_state *state);
+ void (*argp_program_version_hook) (FILE *, struct argp_state *)
+@@ -165,10 +174,10 @@ is_hwcap_platform (const char *name)
+ if (hwcap_idx != -1)
+ return 1;
+
+-#ifdef USE_TLS
+- if (strcmp (name, "tls") == 0)
+- return 1;
+-#endif
++ for (hwcap_idx = _DL_FIRST_EXTRA; hwcap_idx < 64; ++hwcap_idx)
++ if (hwcap_extra[hwcap_idx - _DL_FIRST_EXTRA] != NULL
++ && !strcmp (name, hwcap_extra[hwcap_idx - _DL_FIRST_EXTRA]))
++ return 1;
+
+ return 0;
+ }
+@@ -203,11 +212,11 @@ path_hwcap (const char *path)
+ h = _dl_string_platform (ptr + 1);
+ if (h == (uint64_t) -1)
+ {
+-#ifdef USE_TLS
+- if (strcmp (ptr + 1, "tls") == 0)
+- h = 63;
+- else
+-#endif
++ for (h = _DL_FIRST_EXTRA; h < 64; ++h)
++ if (hwcap_extra[h - _DL_FIRST_EXTRA] != NULL
++ && !strcmp (ptr + 1, hwcap_extra[h - _DL_FIRST_EXTRA]))
++ break;
++ if (h == 64)
+ break;
+ }
+ }
+@@ -1039,6 +1048,53 @@ parse_conf (const char *filename, const
+ memcpy (mempcpy (new_cp, prefix, prefix_len), cp, cp_len + 1);
+ add_dir (new_cp);
+ }
++ else if (!strncasecmp (cp, "hwcap", 5) && isblank (cp[5]))
++ {
++ cp += 6;
++ char *p, *name = NULL;
++ unsigned long int n = strtoul (cp, &cp, 0);
++ if (cp != NULL && isblank (*cp))
++ while ((p = strsep (&cp, " \t")) != NULL)
++ if (p[0] != '\0')
++ {
++ if (name == NULL)
++ name = p;
++ else
++ {
++ name = NULL;
++ break;
++ }
++ }
++ if (name == NULL)
++ {
++ error (EXIT_FAILURE, 0, _("%s:%u: bad syntax in hwcap line"),
++ filename, lineno);
++ break;
++ }
++ if (n >= (64 - _DL_FIRST_EXTRA))
++ error (EXIT_FAILURE, 0,
++ _("%s:%u: hwcap index %lu above maximum %u"),
++ filename, lineno, n, 64 - _DL_FIRST_EXTRA - 1);
++ if (hwcap_extra[n] == NULL)
++ {
++ for (unsigned long int h = 0; h < (64 - _DL_FIRST_EXTRA); ++h)
++ if (hwcap_extra[h] != NULL && !strcmp (name, hwcap_extra[h]))
++ error (EXIT_FAILURE, 0,
++ _("%s:%u: hwcap index %lu already defined as %s"),
++ filename, lineno, h, name);
++ hwcap_extra[n] = xstrdup (name);
++ }
++ else
++ {
++ if (strcmp (name, hwcap_extra[n]))
++ error (EXIT_FAILURE, 0,
++ _("%s:%u: hwcap index %lu already defined as %s"),
++ filename, lineno, n, hwcap_extra[n]);
++ if (opt_verbose)
++ error (0, 0, _("%s:%u: duplicate hwcap %lu %s"),
++ filename, lineno, n, name);
++ }
++ }
+ else
+ add_dir (cp);
+ }
+@@ -1142,6 +1198,10 @@ main (int argc, char **argv)
+ add_dir (argv[i]);
+ }
+
++#ifdef USE_TLS
++ hwcap_extra[63 - _DL_FIRST_EXTRA] = "tls";
++#endif
++
+ set_hwcap ();
+
+ if (opt_chroot)
+--- libc/sysdeps/i386/Makefile 6 Mar 2005 00:18:16 -0000
++++ libc/sysdeps/i386/Makefile 30 Jun 2006 09:16:34 -0000
+@@ -64,4 +64,12 @@ endif
+
+ ifneq (,$(filter -mno-tls-direct-seg-refs,$(CFLAGS)))
+ defines += -DNO_TLS_DIRECT_SEG_REFS
++else
++# .a libraries are not performance critical and so we
++# build them without direct TLS segment references
++# always.
++CPPFLAGS-.o += -DNO_TLS_DIRECT_SEG_REFS
++CFLAGS-.o += -mno-tls-direct-seg-refs
++CPPFLAGS-.oS += -DNO_TLS_DIRECT_SEG_REFS
++CFLAGS-.oS += -mno-tls-direct-seg-refs
+ endif
--- /dev/null
+2007-07-30 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S
+ (pthread_rwlock_timedrdlock): Copy futex retval to %esi rather than
+ %ecx.
+ * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S
+ (pthread_rwlock_timedwrlock): Likewise.
+ * sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S
+ (__pthread_rwlock_unlock): Fix MUTEX != 0 args to __lll_*.
+
+--- libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S 27 May 2007 19:19:42 -0000 1.12
++++ libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedrdlock.S 1 Aug 2007 03:39:45 -0000 1.13
+@@ -124,7 +124,7 @@ pthread_rwlock_timedrdlock:
+ leal READERS_WAKEUP(%ebp), %ebx
+ movl $SYS_futex, %eax
+ ENTER_KERNEL
+- movl %eax, %ecx
++ movl %eax, %esi
+ 17:
+
+ /* Reget the lock. */
+@@ -139,7 +139,7 @@ pthread_rwlock_timedrdlock:
+ jnz 12f
+
+ 13: subl $1, READERS_QUEUED(%ebp)
+- cmpl $-ETIMEDOUT, %ecx
++ cmpl $-ETIMEDOUT, %esi
+ jne 2b
+
+ 18: movl $ETIMEDOUT, %ecx
+@@ -217,7 +217,7 @@ pthread_rwlock_timedrdlock:
+ call __lll_mutex_lock_wait
+ jmp 13b
+
+-16: movl $-ETIMEDOUT, %ecx
++16: movl $-ETIMEDOUT, %esi
+ jmp 17b
+
+ 19: movl $EINVAL, %ecx
+--- libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S 27 May 2007 19:19:42 -0000 1.13
++++ libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_timedwrlock.S 1 Aug 2007 03:39:45 -0000 1.14
+@@ -122,7 +122,7 @@ pthread_rwlock_timedwrlock:
+ leal WRITERS_WAKEUP(%ebp), %ebx
+ movl $SYS_futex, %eax
+ ENTER_KERNEL
+- movl %eax, %ecx
++ movl %eax, %esi
+ 17:
+
+ /* Reget the lock. */
+@@ -137,7 +137,7 @@ pthread_rwlock_timedwrlock:
+ jnz 12f
+
+ 13: subl $1, WRITERS_QUEUED(%ebp)
+- cmpl $-ETIMEDOUT, %ecx
++ cmpl $-ETIMEDOUT, %esi
+ jne 2b
+
+ 18: movl $ETIMEDOUT, %ecx
+@@ -210,7 +210,7 @@ pthread_rwlock_timedwrlock:
+ call __lll_mutex_lock_wait
+ jmp 13b
+
+-16: movl $-ETIMEDOUT, %ecx
++16: movl $-ETIMEDOUT, %esi
+ jmp 17b
+
+ 19: movl $EINVAL, %ecx
+--- libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S 27 May 2007 19:19:42 -0000 1.9
++++ libc/nptl/sysdeps/unix/sysv/linux/i386/i486/pthread_rwlock_unlock.S 1 Aug 2007 03:39:57 -0000 1.10
+@@ -117,7 +117,7 @@ __pthread_rwlock_unlock:
+ #if MUTEX == 0
+ movl %edi, %ecx
+ #else
+- leal MUTEX(%edx), %ecx
++ leal MUTEX(%edi), %ecx
+ #endif
+ call __lll_mutex_lock_wait
+ jmp 2b
+@@ -126,7 +126,7 @@ __pthread_rwlock_unlock:
+ #if MUTEX == 0
+ movl %edi, %eax
+ #else
+- leal MUTEX(%edx), %eax
++ leal MUTEX(%edi), %eax
+ #endif
+ call __lll_mutex_unlock_wake
+ jmp 4b
+@@ -135,7 +135,7 @@ __pthread_rwlock_unlock:
+ #if MUTEX == 0
+ movl %edi, %eax
+ #else
+- leal MUTEX(%edx), %eax
++ leal MUTEX(%edi), %eax
+ #endif
+ call __lll_mutex_unlock_wake
+ jmp 8b
--- /dev/null
+2006-02-21 Roland McGrath <roland@redhat.com>
+
+ * sysdeps/i386/i686/memset.S: Fix treatment of unaligned pointer.
+ Reported by John Zulauf <john.zulauf@amd.com>.
+
+--- libc/sysdeps/i386/i686/memset.S 4 May 2005 06:21:50 -0000 1.9
++++ libc/sysdeps/i386/i686/memset.S 22 Feb 2006 02:39:06 -0000 1.10
+@@ -64,17 +64,17 @@ ENTRY (BP_SYM (memset))
+ movl %edx, %edi
+ cfi_rel_offset (edi, 0)
+ andl $3, %edx
+- jz 2f
+- jnp 3f
+- stosb
++ jz 2f /* aligned */
++ jp 3f /* misaligned at 3, store just one byte below */
++ stosb /* misaligned at 1 or 2, store two bytes */
+ decl %ecx
+ jz 1f
+ 3: stosb
+ decl %ecx
+ jz 1f
+- xorl $3, %edx
+- jz 2f
+- stosb
++ xorl $1, %edx
++ jnz 2f /* was misaligned at 2 or 3, now aligned */
++ stosb /* was misaligned at 1, store third byte */
+ decl %ecx
+ 2: movl %ecx, %edx
+ shrl $2, %ecx
--- /dev/null
+2004-05-14 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/unix/sysv/linux/configure.in: Use */lib64 even for ia64.
+ * sysdeps/unix/sysv/linux/configure: Rebuilt.
+ * sysdeps/unix/sysv/linux/ia64/dl-procinfo.c: New file.
+ * sysdeps/unix/sysv/linux/ia64/dl-procinfo.h: New file.
+ * sysdeps/unix/sysv/linux/ia64/ldd-rewrite.sed: Change /lib64/ld*
+ into /lib/ld*. Add LD_LIBRARY_VERSION.
+ * sysdeps/unix/sysv/linux/ia64/ldconfig.h
+ (SYSDEP_KNOWN_INTERPRETER_NAMES): Add /lib64/ld-linux-ia64.so.2.
+ * sysdeps/unix/sysv/linux/ia64/dl-cache.h: Include sparc-linux
+ dl-cache.h instead of generic dl-cache.h.
+
+--- libc/sysdeps/unix/sysv/linux/configure.jj 2003-03-23 03:10:04.000000000 +0100
++++ libc/sysdeps/unix/sysv/linux/configure 2004-05-14 15:54:35.669802684 +0200
+@@ -225,7 +225,7 @@ case "$prefix" in
+ # 64-bit libraries on bi-arch platforms go in /lib64 instead of /lib
+ case $machine in
+ sparc/sparc64 | x86_64 | powerpc/powerpc64 | s390/s390-64 | \
+- mips/mips64/n64/* )
++ mips/mips64/n64/* | ia64 )
+ libc_cv_slibdir="/lib64"
+ if test "$libdir" = '${exec_prefix}/lib'; then
+ libdir='${exec_prefix}/lib64';
+--- libc/sysdeps/unix/sysv/linux/configure.in.jj 2003-03-23 03:10:04.000000000 +0100
++++ libc/sysdeps/unix/sysv/linux/configure.in 2004-05-14 15:53:44.355998785 +0200
+@@ -158,7 +158,7 @@ case "$prefix" in
+ # 64-bit libraries on bi-arch platforms go in /lib64 instead of /lib
+ case $machine in
+ sparc/sparc64 | x86_64 | powerpc/powerpc64 | s390/s390-64 | \
+- mips/mips64/n64/* )
++ mips/mips64/n64/* | ia64 )
+ libc_cv_slibdir="/lib64"
+ if test "$libdir" = '${exec_prefix}/lib'; then
+ libdir='${exec_prefix}/lib64';
+--- libc/sysdeps/unix/sysv/linux/ia64/dl-procinfo.c.jj 2004-05-14 15:42:09.307560515 +0200
++++ libc/sysdeps/unix/sysv/linux/ia64/dl-procinfo.c 2003-09-30 00:23:24.000000000 +0200
+@@ -0,0 +1,5 @@
++#ifdef IS_IN_ldconfig
++#include <sysdeps/i386/dl-procinfo.c>
++#else
++#include <sysdeps/generic/dl-procinfo.c>
++#endif
+--- libc/sysdeps/unix/sysv/linux/ia64/ldd-rewrite.sed.jj 2002-01-17 07:49:28.000000000 +0100
++++ libc/sysdeps/unix/sysv/linux/ia64/ldd-rewrite.sed 2004-05-14 16:21:03.041325040 +0200
+@@ -1 +1,4 @@
+-s_^\(RTLDLIST=\)\([^ ]*\)-ia64\(\.so\.[0-9.]*\)[ ]*$_\1"\2-ia64\3 \2\3"_
++/LD_TRACE_LOADED_OBJECTS=1/a\
++add_env="$add_env LD_LIBRARY_VERSION=\\$verify_out"
++s_^\(RTLDLIST=\)/lib64/ld\([^ ]*\)-ia64\(\.so\.[0-9.]*\)[ ]*$_\1"/lib/ld\2-ia64\3 /lib/ld\2\3"_
++s_^\(RTLDLIST=\)\([^"][^ ]*\)-ia64\(\.so\.[0-9.]*\)[ ]*$_\1"\2-ia64\3 \2\3"_
+--- libc/sysdeps/unix/sysv/linux/ia64/ldconfig.h.jj 2001-07-06 06:56:17.000000000 +0200
++++ libc/sysdeps/unix/sysv/linux/ia64/ldconfig.h 2004-05-14 15:45:40.103783087 +0200
+@@ -1,4 +1,4 @@
+-/* Copyright (C) 2001 Free Software Foundation, Inc.
++/* Copyright (C) 2001, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+@@ -19,7 +19,8 @@
+ #include <sysdeps/generic/ldconfig.h>
+
+ #define SYSDEP_KNOWN_INTERPRETER_NAMES \
+- { "/lib/ld-linux.so.2", FLAG_ELF_LIBC6 },
++ { "/lib/ld-linux.so.2", FLAG_ELF_LIBC6 }, \
++ { "/lib64/ld-linux-ia64.so.2", FLAG_ELF_LIBC6 },
+ #define SYSDEP_KNOWN_LIBRARY_NAMES \
+ { "libc.so.6", FLAG_ELF_LIBC6 }, \
+ { "libm.so.6", FLAG_ELF_LIBC6 },
+--- libc/sysdeps/unix/sysv/linux/ia64/dl-cache.h.jj 2001-07-06 06:56:17.000000000 +0200
++++ libc/sysdeps/unix/sysv/linux/ia64/dl-cache.h 2004-05-14 15:41:11.658891907 +0200
+@@ -1,5 +1,5 @@
+ /* Support for reading /etc/ld.so.cache files written by Linux ldconfig.
+- Copyright (C) 2000 Free Software Foundation, Inc.
++ Copyright (C) 2000, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+@@ -22,4 +22,4 @@
+ #define _dl_cache_check_flags(flags) \
+ ((flags) == _DL_CACHE_DEFAULT_ID)
+
+-#include_next <dl-cache.h>
++#include <sysdeps/unix/sysv/linux/sparc/dl-cache.h>
+--- libc/sysdeps/unix/sysv/linux/ia64/dl-procinfo.h.jj 2004-05-14 15:42:13.018895395 +0200
++++ libc/sysdeps/unix/sysv/linux/ia64/dl-procinfo.h 2003-07-23 00:06:23.000000000 +0200
+@@ -0,0 +1,5 @@
++#ifdef IS_IN_ldconfig
++#include <sysdeps/unix/sysv/linux/i386/dl-procinfo.h>
++#else
++#include <sysdeps/generic/dl-procinfo.h>
++#endif
--- /dev/null
+2005-08-19 H.J. Lu <hongjiu.lu@intel.com>
+
+ * sysdeps/ia64/fpu/libm_error.c (__libm_error_support): Don't abort.
+
+--- libc/sysdeps/ia64/fpu/libm_error.c 5 Apr 2005 22:34:12 -0000 1.5
++++ libc/sysdeps/ia64/fpu/libm_error.c 20 Aug 2005 01:21:16 -0000 1.6
+@@ -81,8 +81,8 @@
+ // 12/13/04: Corrected POSIX behavior for exp2_overflow, exp2_underflow,
+ // exp10_overflow, exp10_underflow. Added ISOC to set errno for
+ // exp10_underflow.
+-// 12/14/04: Corrected POSIX behavior for nextafter_overflow,
+-// nextafter_underflow, nexttoward_overflow, nexttoward_underflow.
++// 12/14/04: Corrected POSIX behavior for nextafter_overflow,
++// nextafter_underflow, nexttoward_overflow, nexttoward_underflow.
+ // Added ISOC to set errno for nextafter and nexttoward underflow.
+ // 12/15/04: Corrected POSIX behavior for exp, exp2, and exp10 underflow.
+ // 03/31/05: Added missing ALIGNIT statement to 6 float constants.
+@@ -674,7 +674,7 @@ else if(_LIB_VERSIONIMF==_ISOC_)
+ ERRNO_DOMAIN; break;
+ }
+ default:
+- abort();
++ break;
+ }
+ return;
+ }
+@@ -1374,7 +1374,7 @@ switch(input_tag)
+ ERRNO_RANGE; break;
+ }
+ default:
+- abort();
++ break;
+ }
+ return;
+ /* _POSIX_ */
--- /dev/null
+2005-03-21 David Mosberger <davidm@hpl.hp.com>
+
+ * sysdeps/ia64/_mcount.S: Newer kernels don't like register-frames
+ with more than 8 output registers. Fix this by passing original
+ ar.pfs to _mcount_ret_helper via r3.
+
+--- libc/sysdeps/ia64/_mcount.S 6 Jul 2001 04:55:54 -0000 1.4
++++ libc/sysdeps/ia64/_mcount.S 22 Mar 2005 09:06:17 -0000 1.5
+@@ -72,6 +72,7 @@ LEAF(_mcount)
+ mov b7 = loc0
+ mov rp = in2
+ ;;
++ mov r3 = in0
+ mov r8 = loc2
+ mov r15 = loc3
+ mov b6 = r2
+@@ -81,10 +82,10 @@ END(_mcount)
+ LOCAL_LEAF(_mcount_ret_helper)
+ .prologue
+ .altrp b7
+- .save ar.pfs, r40
++ .save ar.pfs, r3
+ .body
+- alloc r2 = ar.pfs, 0, 0, 9, 0
+- mov ar.pfs = r40
++ alloc r2 = ar.pfs, 0, 0, 8, 0
++ mov ar.pfs = r3
+ br b7
+ END(_mcount_ret_helper)
+
--- /dev/null
+--- libc/fedora/glibc_post_upgrade.c.jj 2004-12-20 02:59:25.000000000 -0500
++++ libc/fedora/glibc_post_upgrade.c 2005-06-14 10:54:32.000000000 -0400
+@@ -27,6 +27,39 @@ __attribute__((noinline)) void sayn (lon
+ __attribute__((noinline)) void message (char *const path[]);
+ __attribute__((noinline)) int check_elf (const char *name);
+
++#ifdef __i386__
++static int
++is_ia64 (void)
++{
++ unsigned int fl1, fl2;
++
++ /* See if we can use cpuid. */
++ __asm__ ("pushfl; pushfl; popl %0; movl %0,%1; xorl %2,%0;"
++ "pushl %0; popfl; pushfl; popl %0; popfl"
++ : "=&r" (fl1), "=&r" (fl2)
++ : "i" (0x00200000));
++ if (((fl1 ^ fl2) & 0x00200000) == 0)
++ return 0;
++
++ /* Host supports cpuid. See if cpuid gives capabilities, try
++ CPUID(0). Preserve %ebx and %ecx; cpuid insn clobbers these, we
++ don't need their CPUID values here, and %ebx may be the PIC
++ register. */
++ __asm__ ("pushl %%ecx; pushl %%ebx; cpuid; popl %%ebx; popl %%ecx"
++ : "=a" (fl1) : "0" (0) : "edx", "cc");
++ if (fl1 == 0)
++ return 0;
++
++ /* Invoke CPUID(1), return %edx; caller can examine bits to
++ determine what's supported. */
++ __asm__ ("pushl %%ecx; pushl %%ebx; cpuid; popl %%ebx; popl %%ecx"
++ : "=d" (fl2), "=a" (fl1) : "1" (1) : "cc");
++ return (fl2 & (1 << 30)) != 0;
++}
++#else
++#define is_ia64() 0
++#endif
++
+ int
+ main (void)
+ {
+@@ -162,9 +195,16 @@ main (void)
+ #ifndef ICONVCONFIG
+ #define ICONVCONFIG "/usr/sbin/iconvconfig"
+ #endif
++ const char *iconv_cache = GCONV_MODULES_DIR"/gconv-modules.cache";
++ const char *iconv_dir = GCONV_MODULES_DIR;
++ if (is_ia64 ())
++ {
++ iconv_cache = "/emul/ia32-linux"GCONV_MODULES_DIR"/gconv-modules.cache";
++ iconv_dir = "/emul/ia32-linux"GCONV_MODULES_DIR;
++ }
+ verbose_exec (113, ICONVCONFIG, "/usr/sbin/iconvconfig",
+- "-o", GCONV_MODULES_DIR"/gconv-modules.cache",
+- "--nostdlib", GCONV_MODULES_DIR);
++ "-o", iconv_cache,
++ "--nostdlib", iconv_dir);
+ }
+
+ /* Check if telinit is available and the init fifo as well. */
--- /dev/null
+2005-11-19 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/unix/sysv/linux/ia64/bits/shm.h (shmatt_t): New type.
+ (struct shmid_ds): Use it for shm_nattch field.
+
+--- libc/sysdeps/unix/sysv/linux/ia64/bits/shm.h 20 Dec 2002 10:31:09 -0000 1.5
++++ libc/sysdeps/unix/sysv/linux/ia64/bits/shm.h 19 Nov 2005 17:17:15 -0000 1.6
+@@ -38,6 +38,8 @@
+ /* Segment low boundary address multiple. */
+ #define SHMLBA (1024 * 1024)
+
++/* Type to count number of attaches. */
++typedef unsigned long int shmatt_t;
+
+ /* Data structure describing a set of semaphores. */
+ struct shmid_ds
+@@ -49,7 +51,7 @@ struct shmid_ds
+ __time_t shm_ctime; /* time of last change by shmctl() */
+ __pid_t shm_cpid; /* pid of creator */
+ __pid_t shm_lpid; /* pid of last shmop */
+- unsigned long int shm_nattch; /* number of current attaches */
++ shmatt_t shm_nattch; /* number of current attaches */
+ unsigned long int __unused1;
+ unsigned long int __unused2;
+ };
--- /dev/null
+2005-09-24 Jakub Jelinek <jakub@redhat.com>
+
+ * inet/getnetgrent_r.c (innetgr): Call endfct even if result != 0.
+ Return 1 only if result == 1. Patch by Benoit Capelle.
+
+--- libc/inet/getnetgrent_r.c 10 Sep 2005 03:16:29 -0000 1.29
++++ libc/inet/getnetgrent_r.c 25 Sep 2005 22:54:19 -0000 1.30
+@@ -409,9 +409,6 @@ innetgr (const char *netgroup, const cha
+ }
+ }
+
+- if (result != 0)
+- break;
+-
+ /* If we found one service which does know the given
+ netgroup we don't try further. */
+ status = NSS_STATUS_RETURN;
+@@ -422,6 +419,9 @@ innetgr (const char *netgroup, const cha
+ if (endfct != NULL)
+ (*endfct) (&entry);
+
++ if (result != 0)
++ break;
++
+ /* Look for the next service. */
+ no_more = __nss_next (&entry.nip, "setnetgrent",
+ &setfct.ptr, status, 0);
+@@ -444,6 +444,6 @@ innetgr (const char *netgroup, const cha
+ /* Free the memory. */
+ free_memory (&entry);
+
+- return result;
++ return result == 1;
+ }
+ libc_hidden_def (innetgr)
--- /dev/null
+2005-09-09 Jakub Jelinek <jakub@redhat.com>
+
+ * inet/getnetgrent_r.c: Include assert.
+ (setup): Remove FUNC_NAME and ALL arguments, assume they are always
+ "setnetgrent" and 1.
+ (endnetgrent_hook): New function.
+ (internal_endnetgrent): Use it.
+ (__internal_setnetgrent_reuse): Use it. Adjust setup caller.
+ If status is NSS_STATUS_SUCCESS, yet action is continue, call
+ endnetgrent hook.
+ (internal_getnetgrent_r): Use __nss_lookup_function rather than
+ setup. Recompute getfct pointer after successful
+ __internal_setnetgrent_reuse. Don't use __nss_next.
+ (innetgr): Use __nss_lookup_function instead of __nss_lookup.
+ Adjust setup caller.
+ * nss/nss_files/files-netgrp.c (_nss_files_endnetgrent): Always clear
+ data_size and cursor. Add libnss_files_hidden_proto and
+ libnss_files_hidden_def.
+ (_nss_files_setnetgrent): Call _nss_files_endnetgrent on failure.
+ * nis/nss_nis/nis-netgrp.c (internal_endnetgrent): Always clear
+ data_size and cursor.
+ (_nss_nis_setnetgrent): Don't call internal_endnetgrent.
+ (_nss_nis_getnetgrent_r): Remove result->cursor == NULL handling.
+ * nis/nss_nisplus/nisplus-netgrp.c (internal_endnetgrent): Always clear
+ data_size and position.
+ (_nss_nisplus_setnetgrent): Don't call internal_endnetgrent.
+
+2005-09-09 Ulrich Drepper <drepper@redhat.com>
+
+ * nss/nss_files/files-netgrp.c (_nss_files_setnetgrent): We don't
+ need locking for the stream. Use feof_unlocked.
+
+--- libc/inet/getnetgrent_r.c 14 Aug 2004 04:16:22 -0000 1.28
++++ libc/inet/getnetgrent_r.c 10 Sep 2005 03:16:29 -0000 1.29
+@@ -16,6 +17,7 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
++#include <assert.h>
+ #include <bits/libc-lock.h>
+ #include <errno.h>
+ #include <netdb.h>
+@@ -33,15 +35,13 @@ __libc_lock_define_initialized (static,
+ static struct __netgrent dataset;
+
+ /* The lookup function for the first entry of this service. */
+-extern int __nss_netgroup_lookup (service_user **nip, const char *name,
++extern int __nss_netgroup_lookup (service_user **nipp, const char *name,
+ void **fctp) internal_function;
+
+-
+-/* Set up NIP to run through the services. If ALL is zero, use NIP's
+- current location if it's not nil. Return nonzero if there are no
++/* Set up NIP to run through the services. Return nonzero if there are no
+ services (left). */
+-static enum nss_status
+-setup (void **fctp, const char *func_name, int all, service_user **nipp)
++static int
++setup (void **fctp, service_user **nipp)
+ {
+ /* Remember the first service_entry, it's always the same. */
+ static service_user *startp;
+@@ -51,7 +51,7 @@ setup (void **fctp, const char *func_nam
+ {
+ /* Executing this more than once at the same time must yield the
+ same result every time. So we need no locking. */
+- no_more = __nss_netgroup_lookup (nipp, func_name, fctp);
++ no_more = __nss_netgroup_lookup (nipp, "setnetgrent", fctp);
+ startp = no_more ? (service_user *) -1 : *nipp;
+ }
+ else if (startp == (service_user *) -1)
+@@ -59,11 +59,10 @@ setup (void **fctp, const char *func_nam
+ return 1;
+ else
+ {
+- if (all || *nipp == NULL)
+- /* Reset to the beginning of the service list. */
+- *nipp = startp;
++ /* Reset to the beginning of the service list. */
++ *nipp = startp;
+ /* Look up the first function. */
+- no_more = __nss_lookup (nipp, func_name, fctp);
++ no_more = __nss_lookup (nipp, "setnetgrent", fctp);
+ }
+ return no_more;
+ }
+@@ -87,6 +86,20 @@ free_memory (struct __netgrent *data)
+ }
+ }
+ \f
++static void
++endnetgrent_hook (struct __netgrent *datap)
++{
++ enum nss_status (*endfct) (struct __netgrent *);
++
++ if (datap->nip == NULL)
++ return;
++
++ endfct = __nss_lookup_function (datap->nip, "endnetgrent");
++ if (endfct != NULL)
++ (void) (*endfct) (datap);
++ datap->nip = NULL;
++}
++
+ static int
+ internal_function
+ __internal_setnetgrent_reuse (const char *group, struct __netgrent *datap,
+@@ -100,14 +113,29 @@ __internal_setnetgrent_reuse (const char
+ enum nss_status status = NSS_STATUS_UNAVAIL;
+ struct name_list *new_elem;
+
++ /* Free data from previous service. */
++ endnetgrent_hook (datap);
++
+ /* Cycle through all the services and run their setnetgrent functions. */
+- int no_more = setup (&fct.ptr, "setnetgrent", 1, &datap->nip);
++ int no_more = setup (&fct.ptr, &datap->nip);
+ while (! no_more)
+ {
++ assert (datap->data == NULL);
++
+ /* Ignore status, we force check in `__nss_next'. */
+ status = (*fct.f) (group, datap);
+
++ service_user *old_nip = datap->nip;
+ no_more = __nss_next (&datap->nip, "setnetgrent", &fct.ptr, status, 0);
++
++ if (status == NSS_STATUS_SUCCESS && ! no_more)
++ {
++ enum nss_status (*endfct) (struct __netgrent *);
++
++ endfct = __nss_lookup_function (old_nip, "endnetgrent");
++ if (endfct != NULL)
++ (void) (*endfct) (datap);
++ }
+ }
+
+ /* Add the current group to the list of known groups. */
+@@ -157,34 +185,13 @@ setnetgrent (const char *group)
+ return result;
+ }
+
+-
+ void internal_endnetgrent (struct __netgrent *datap);
+ libc_hidden_proto (internal_endnetgrent)
+
+ void
+ internal_endnetgrent (struct __netgrent *datap)
+ {
+- service_user *old_nip;
+- union
+- {
+- enum nss_status (*f) (struct __netgrent *);
+- void *ptr;
+- } fct;
+-
+- /* Remember which was the last used service. */
+- old_nip = datap->nip;
+-
+- /* Cycle through all the services and run their endnetgrent functions. */
+- int no_more = setup (&fct.ptr, "endnetgrent", 1, &datap->nip);
+- while (! no_more)
+- {
+- /* Ignore status, we force check in `__nss_next'. */
+- (void) (*fct.f) (datap);
+-
+- no_more = (datap->nip == old_nip
+- || __nss_next (&datap->nip, "endnetgrent", &fct.ptr, 0, 1));
+- }
+-
++ endnetgrent_hook (datap);
+ /* Now free list of all netgroup names from last run. */
+ free_memory (datap);
+ }
+@@ -213,11 +220,7 @@ internal_getnetgrent_r (char **hostp, ch
+ struct __netgrent *datap,
+ char *buffer, size_t buflen, int *errnop)
+ {
+- union
+- {
+- enum nss_status (*f) (struct __netgrent *, char *, size_t, int *);
+- void *ptr;
+- } fct;
++ enum nss_status (*fct) (struct __netgrent *, char *, size_t, int *);
+
+ /* Initialize status to return if no more functions are found. */
+ enum nss_status status = NSS_STATUS_NOTFOUND;
+@@ -225,10 +228,12 @@ internal_getnetgrent_r (char **hostp, ch
+ /* Run through available functions, starting with the same function last
+ run. We will repeat each function as long as it succeeds, and then go
+ on to the next service action. */
+- int no_more = setup (&fct.ptr, "getnetgrent_r", 0, &datap->nip);
++ int no_more = (datap->nip == NULL
++ || (fct = __nss_lookup_function (datap->nip, "getnetgrent_r"))
++ == NULL);
+ while (! no_more)
+ {
+- status = (*fct.f) (datap, buffer, buflen, &errno);
++ status = (*fct) (datap, buffer, buflen, &errno);
+
+ if (status == NSS_STATUS_RETURN)
+ {
+@@ -246,8 +251,12 @@ internal_getnetgrent_r (char **hostp, ch
+ datap, errnop);
+ }
+
+- if (found)
+- continue;
++ if (found && datap->nip != NULL)
++ {
++ fct = __nss_lookup_function (datap->nip, "getnetgrent_r");
++ if (fct != NULL)
++ continue;
++ }
+ }
+ else if (status == NSS_STATUS_SUCCESS && datap->type == group_val)
+ {
+@@ -279,7 +288,7 @@ internal_getnetgrent_r (char **hostp, ch
+ }
+ }
+
+- no_more = __nss_next (&datap->nip, "getnetgrent_r", &fct.ptr, status, 0);
++ break;
+ }
+
+ if (status == NSS_STATUS_SUCCESS)
+@@ -322,16 +331,8 @@ innetgr (const char *netgroup, const cha
+ int (*f) (const char *, struct __netgrent *);
+ void *ptr;
+ } setfct;
+- union
+- {
+- void (*f) (struct __netgrent *);
+- void *ptr;
+- } endfct;
+- union
+- {
+- int (*f) (struct __netgrent *, char *, size_t, int *);
+- void *ptr;
+- } getfct;
++ void (*endfct) (struct __netgrent *);
++ int (*getfct) (struct __netgrent *, char *, size_t, int *);
+ struct __netgrent entry;
+ int result = 0;
+ const char *current_group = netgroup;
+@@ -345,18 +346,21 @@ innetgr (const char *netgroup, const cha
+ the work during one walk through the service list. */
+ while (1)
+ {
+- int no_more = setup (&setfct.ptr, "setnetgrent", 1, &entry.nip);
++ int no_more = setup (&setfct.ptr, &entry.nip);
+ while (! no_more)
+ {
++ assert (entry.data == NULL);
++
+ /* Open netgroup. */
+ enum nss_status status = (*setfct.f) (current_group, &entry);
+
+ if (status == NSS_STATUS_SUCCESS
+- && __nss_lookup (&entry.nip, "getnetgrent_r", &getfct.ptr) == 0)
++ && (getfct = __nss_lookup_function (entry.nip, "getnetgrent_r"))
++ != NULL)
+ {
+ char buffer[1024];
+
+- while ((*getfct.f) (&entry, buffer, sizeof buffer, &errno)
++ while ((*getfct) (&entry, buffer, sizeof buffer, &errno)
+ == NSS_STATUS_SUCCESS)
+ {
+ if (entry.type == group_val)
+@@ -414,8 +418,9 @@ innetgr (const char *netgroup, const cha
+ }
+
+ /* Free all resources of the service. */
+- if (__nss_lookup (&entry.nip, "endnetgrent", &endfct.ptr) == 0)
+- (*endfct.f) (&entry);
++ endfct = __nss_lookup_function (entry.nip, "endnetgrent");
++ if (endfct != NULL)
++ (*endfct) (&entry);
+
+ /* Look for the next service. */
+ no_more = __nss_next (&entry.nip, "setnetgrent",
+--- libc/nis/nss_nisplus/nisplus-netgrp.c 10 Dec 2004 10:43:30 -0000 1.14
++++ libc/nis/nss_nisplus/nisplus-netgrp.c 10 Sep 2005 03:18:49 -0000 1.15
+@@ -141,13 +141,10 @@ _nss_nisplus_getnetgrent_r (struct __net
+ static void
+ internal_endnetgrent (struct __netgrent *netgrp)
+ {
+- if (netgrp->data != NULL)
+- {
+- nis_freeresult ((nis_result *) netgrp->data);
+- netgrp->data = NULL;
+- netgrp->data_size = 0;
+- netgrp->position = 0;
+- }
++ nis_freeresult ((nis_result *) netgrp->data);
++ netgrp->data = NULL;
++ netgrp->data_size = 0;
++ netgrp->position = 0;
+ }
+
+ enum nss_status
+@@ -161,8 +158,6 @@ _nss_nisplus_setnetgrent (const char *gr
+
+ status = NSS_STATUS_SUCCESS;
+
+- internal_endnetgrent (netgrp);
+-
+ sprintf (buf, "[name=%s],netgroup.org_dir", group);
+
+ netgrp->data = (char *) nis_list (buf, EXPAND_NAME, NULL, NULL);
+--- libc/nis/nss_nis/nis-netgrp.c 16 Aug 2005 16:04:13 -0000 1.13
++++ libc/nis/nss_nis/nis-netgrp.c 10 Sep 2005 03:19:20 -0000 1.14
+@@ -41,13 +41,10 @@ _nss_netgroup_parseline (char **cursor,
+ static void
+ internal_nis_endnetgrent (struct __netgrent *netgrp)
+ {
+- if (netgrp->data != NULL)
+- {
+- free (netgrp->data);
+- netgrp->data = NULL;
+- netgrp->data_size = 0;
+- netgrp->cursor = NULL;
+- }
++ free (netgrp->data);
++ netgrp->data = NULL;
++ netgrp->data_size = 0;
++ netgrp->cursor = NULL;
+ }
+
+ enum nss_status
+@@ -65,8 +62,6 @@ _nss_nis_setnetgrent (const char *group,
+ if (yp_get_default_domain (&domain))
+ return NSS_STATUS_UNAVAIL;
+
+- internal_nis_endnetgrent (netgrp);
+-
+ status = yperr2nss (yp_match (domain, "netgroup", group, strlen (group),
+ &netgrp->data, &len));
+ if (status == NSS_STATUS_SUCCESS)
+@@ -99,9 +94,6 @@ enum nss_status
+ _nss_nis_getnetgrent_r (struct __netgrent *result, char *buffer, size_t buflen,
+ int *errnop)
+ {
+- if (result->cursor == NULL)
+- return NSS_STATUS_NOTFOUND;
+-
+ return _nss_netgroup_parseline (&result->cursor, result, buffer, buflen,
+ errnop);
+ }
+--- libc/nss/nss_files/files-netgrp.c 24 Oct 2004 09:05:12 -0000 1.13
++++ libc/nss/nss_files/files-netgrp.c 10 Sep 2005 00:06:32 -0000 1.14
+@@ -22,6 +22,7 @@
+ #include <errno.h>
+ #include <netdb.h>
+ #include <stdio.h>
++#include <stdio_ext.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include "nsswitch.h"
+@@ -29,6 +30,7 @@
+
+ #define DATAFILE "/etc/netgroup"
+
++libnss_files_hidden_proto (_nss_files_endnetgrent)
+
+ #define EXPAND(needed) \
+ do \
+@@ -75,7 +77,9 @@ _nss_files_setnetgrent (const char *grou
+ status = NSS_STATUS_NOTFOUND;
+ result->cursor = result->data;
+
+- while (!feof (fp))
++ __fsetlocking (fp, FSETLOCKING_BYCALLER);
++
++ while (!feof_unlocked (fp))
+ {
+ ssize_t curlen = getline (&line, &line_len, fp);
+ int found;
+@@ -140,6 +144,9 @@ _nss_files_setnetgrent (const char *grou
+ /* We don't need the file and the line buffer anymore. */
+ free (line);
+ fclose (fp);
++
++ if (status != NSS_STATUS_SUCCESS)
++ _nss_files_endnetgrent (result);
+ }
+
+ return status;
+@@ -150,16 +157,13 @@ int
+ _nss_files_endnetgrent (struct __netgrent *result)
+ {
+ /* Free allocated memory for data if some is present. */
+- if (result->data != NULL)
+- {
+- free (result->data);
+- result->data = NULL;
+- result->data_size = 0;
+- result->cursor = NULL;
+- }
+-
++ free (result->data);
++ result->data = NULL;
++ result->data_size = 0;
++ result->cursor = NULL;
+ return NSS_STATUS_SUCCESS;
+ }
++libnss_files_hidden_def (_nss_files_endnetgrent)
+
+ static char *
+ strip_whitespace (char *str)
--- /dev/null
+2006-08-28 Ulrich Drepper <drepper@redhat.com>
+
+ * elf/dl-load.c (_dl_init_paths): Expand DSTs.
+
+--- libc/elf/dl-load.c 27 Jun 2006 14:23:02 -0000 1.278
++++ libc/elf/dl-load.c 29 Aug 2006 01:43:42 -0000 1.279
+@@ -749,7 +749,25 @@ _dl_init_paths (const char *llp)
+ {
+ size_t nllp;
+ const char *cp = llp;
+- char *llp_tmp = strdupa (llp);
++ char *llp_tmp;
++
++#ifdef SHARED
++ /* Expand DSTs. */
++ size_t cnt = DL_DST_COUNT (llp, 1);
++ if (__builtin_expect (cnt == 0, 1))
++ llp_tmp = strdupa (llp);
++ else
++ {
++ /* Determine the length of the substituted string. */
++ size_t total = DL_DST_REQUIRED (l, llp, strlen (llp), cnt);
++
++ /* Allocate the necessary memory. */
++ llp_tmp = (char *) alloca (total + 1);
++ llp_tmp = _dl_dst_substitute (l, llp, llp_tmp, 1);
++ }
++#else
++ llp_tmp = strdupa (llp);
++#endif
+
+ /* Decompose the LD_LIBRARY_PATH contents. First determine how many
+ elements it has. */
--- /dev/null
+2005-10-26 Jakub Jelinek <jakub@redhat.com>
+
+ * elf/dl-conflict.c (_dl_resolve_conflicts): Use _dl_debug_printf
+ instead of _dl_printf to print conflict processing debug message.
+ Reported by John Reiser <jreiser@BitWagon.com>.
+
+--- libc/elf/dl-conflict.c 14 Oct 2004 01:53:55 -0000 1.12
++++ libc/elf/dl-conflict.c 31 Oct 2005 01:28:48 -0000 1.13
+@@ -34,8 +34,8 @@ _dl_resolve_conflicts (struct link_map *
+ {
+ #if ! ELF_MACHINE_NO_RELA
+ if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_RELOC, 0))
+- _dl_printf ("\nconflict processing: %s\n",
+- l->l_name[0] ? l->l_name : rtld_progname);
++ _dl_debug_printf ("\nconflict processing: %s\n",
++ l->l_name[0] ? l->l_name : rtld_progname);
+
+ {
+ /* Do the conflict relocation of the object and library GOT and other
--- /dev/null
+2005-12-27 Jakub Jelinek <jakub@redhat.com>
+
+ * elf/ldconfig.c (search_dir): Skip prelink temporaries.
+
+--- libc/elf/ldconfig.c 1 Jan 2006 19:15:56 -0000 1.52
++++ libc/elf/ldconfig.c 6 Mar 2006 08:40:11 -0000 1.53
+@@ -693,7 +693,20 @@ search_dir (const struct dir_entry *entr
+ #endif
+ !is_hwcap_platform (direntry->d_name)))
+ continue;
+- len = strlen (entry->path) + strlen (direntry->d_name);
++ len = strlen (direntry->d_name);
++ /* Skip temporary files created by the prelink program. Files with
++ names like these are never really DSOs we want to look at. */
++ if (len >= sizeof (".#prelink#") - 1)
++ {
++ if (strcmp (direntry->d_name + len - sizeof (".#prelink#") + 1,
++ ".#prelink#") == 0)
++ continue;
++ if (len >= sizeof (".#prelink#.XXXXXX") - 1
++ && memcmp (direntry->d_name + len - sizeof (".#prelink#.XXXXXX")
++ + 1, ".#prelink#.", sizeof (".#prelink#.") - 1) == 0)
++ continue;
++ }
++ len += strlen (entry->path);
+ if (len > file_name_len)
+ {
+ file_name_len = len + 1;
--- /dev/null
+2005-09-20 Roland McGrath <roland@redhat.com>
+
+ * sysdeps/unix/sysv/linux/lddlibc4.c (main): Use execv, not execl.
+
+--- libc/sysdeps/unix/sysv/linux/lddlibc4.c 6 Jul 2001 04:56:12 -0000 1.4
++++ libc/sysdeps/unix/sysv/linux/lddlibc4.c 20 Sep 2005 07:46:19 -0000 1.5
+@@ -84,5 +84,5 @@ main (int argc, char *argv[])
+ putenv (buf);
+
+ /* Now we can execute the binary. */
+- return execl (filename, NULL) ? 4 : 0;
++ return execv (filename, &argv[argc]) ? 4 : 0;
+ }
--- /dev/null
+2006-02-23 Jakub Jelinek <jakub@redhat.com>
+
+ * spinlock.h (atomic_increment): Rename to lt_atomic_increment.
+ (atomic_decrement): Rename to lt_atomic_decrement.
+ * pthread.c (__pthread_restart_old, __pthread_suspend_old,
+ __pthread_timedsuspend_old): Adjust callers.
+
+--- libc/linuxthreads/spinlock.h.jj 2003-07-31 21:16:04.000000000 +0200
++++ libc/linuxthreads/spinlock.h 2006-02-23 10:30:04.000000000 +0100
+@@ -172,7 +172,7 @@ static inline int __pthread_alt_trylock
+
+ /* Operations on pthread_atomic, which is defined in internals.h */
+
+-static inline long atomic_increment(struct pthread_atomic *pa)
++static inline long lt_atomic_increment(struct pthread_atomic *pa)
+ {
+ long oldval;
+
+@@ -184,7 +184,7 @@ static inline long atomic_increment(stru
+ }
+
+
+-static inline long atomic_decrement(struct pthread_atomic *pa)
++static inline long lt_atomic_decrement(struct pthread_atomic *pa)
+ {
+ long oldval;
+
+--- libc/linuxthreads/pthread.c.jj 2005-01-09 21:02:37.000000000 +0100
++++ libc/linuxthreads/pthread.c 2006-02-23 10:30:04.000000000 +0100
+@@ -1231,13 +1231,13 @@ void __pthread_wait_for_restart_signal(p
+
+ void __pthread_restart_old(pthread_descr th)
+ {
+- if (atomic_increment(&th->p_resume_count) == -1)
++ if (lt_atomic_increment(&th->p_resume_count) == -1)
+ kill(th->p_pid, __pthread_sig_restart);
+ }
+
+ void __pthread_suspend_old(pthread_descr self)
+ {
+- if (atomic_decrement(&self->p_resume_count) <= 0)
++ if (lt_atomic_decrement(&self->p_resume_count) <= 0)
+ __pthread_wait_for_restart_signal(self);
+ }
+
+@@ -1248,7 +1248,7 @@ __pthread_timedsuspend_old(pthread_descr
+ int was_signalled = 0;
+ sigjmp_buf jmpbuf;
+
+- if (atomic_decrement(&self->p_resume_count) == 0) {
++ if (lt_atomic_decrement(&self->p_resume_count) == 0) {
+ /* Set up a longjmp handler for the restart signal, unblock
+ the signal and sleep. */
+
+@@ -1305,9 +1305,9 @@ __pthread_timedsuspend_old(pthread_descr
+ being delivered. */
+
+ if (!was_signalled) {
+- if (atomic_increment(&self->p_resume_count) != -1) {
++ if (lt_atomic_increment(&self->p_resume_count) != -1) {
+ __pthread_wait_for_restart_signal(self);
+- atomic_decrement(&self->p_resume_count); /* should be zero now! */
++ lt_atomic_decrement(&self->p_resume_count); /* should be zero now! */
+ /* woke spontaneously and consumed restart signal */
+ return 1;
+ }
--- /dev/null
+2005-09-09 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #1318]
+ * locale/loadarchive.c (_nl_load_locale_from_archive): Free
+ normalized_codeset even if p was already normalized.
+ Reported by Jaroslav Snajdr <jsnajdr@kerio.com>.
+
+--- libc/locale/loadarchive.c 12 Sep 2003 22:26:49 -0000 1.18
++++ libc/locale/loadarchive.c 9 Sep 2005 16:56:52 -0000 1.19
+@@ -185,9 +185,9 @@ _nl_load_locale_from_archive (int catego
+ memcpy (__mempcpy (__mempcpy (newname, name, p - name),
+ normalized_codeset, normlen),
+ rest, restlen);
+- free ((char *) normalized_codeset);
+ name = newname;
+ }
++ free ((char *) normalized_codeset);
+ }
+ }
+
--- /dev/null
+2005-08-19 Bruno Haible <bruno@clisp.org>
+
+ * intl/localealias.c (read_alias_file): In case of failure, close the
+ file descriptor and sort the array before returning.
+
+--- libc/intl/localealias.c 4 Sep 2003 08:25:12 -0000 1.42
++++ libc/intl/localealias.c 20 Aug 2005 01:16:17 -0000 1.43
+@@ -295,7 +295,7 @@ read_alias_file (fname, fname_len)
+
+ if (nmap >= maxmap)
+ if (__builtin_expect (extend_alias_table (), 0))
+- return added;
++ goto out;
+
+ alias_len = strlen (alias) + 1;
+ value_len = strlen (value) + 1;
+@@ -308,7 +308,7 @@ read_alias_file (fname, fname_len)
+ ? alias_len + value_len : 1024));
+ char *new_pool = (char *) realloc (string_space, new_size);
+ if (new_pool == NULL)
+- return added;
++ goto out;
+
+ if (__builtin_expect (string_space != new_pool, 0))
+ {
+@@ -349,6 +349,7 @@ read_alias_file (fname, fname_len)
+ while (strchr (buf, '\n') == NULL);
+ }
+
++out:
+ /* Should we test for ferror()? I think we have to silently ignore
+ errors. --drepper */
+ fclose (fp);
--- /dev/null
+2007-04-19 Ulrich Drepper <drepper@redhat.com>
+
+ * include/sys/mman.h: Mark madvise hidden.
+ * sysdeps/generic/madvise.c: Add libc_hidden_def.
+
+--- libc/sysdeps/generic/madvise.c 14 Dec 2005 09:36:14 -0000 1.1
++++ libc/sysdeps/generic/madvise.c 19 Apr 2007 17:42:34 -0000 1.2
+@@ -29,5 +29,6 @@ madvise (__ptr_t addr, size_t len, int a
+ __set_errno (ENOSYS);
+ return -1;
+ }
++libc_hidden_def (madvise)
+ stub_warning (madvise)
+ #include <stub-tag.h>
+--- libc/include/sys/mman.h 14 Oct 2005 21:06:10 -0000 1.6
++++ libc/include/sys/mman.h 19 Apr 2007 17:40:54 -0000 1.7
+@@ -12,4 +12,7 @@ extern int __mprotect (void *__addr, siz
+ /* This one is Linux specific. */
+ extern void *__mremap (void *__addr, size_t __old_len,
+ size_t __new_len, int __may_move);
++
++libc_hidden_proto (madvise);
++
+ #endif
--- /dev/null
+2006-01-04 Joseph S. Myers <joseph@codesourcery.com>
+
+ * sysdeps/ieee754/bits/nan.h: Fix typo.
+
+--- libc/sysdeps/ieee754/bits/nan.h 16 Apr 2004 22:03:35 -0000 1.9
++++ libc/sysdeps/ieee754/bits/nan.h 4 Jan 2006 06:21:57 -0000 1.10
+@@ -26,13 +26,13 @@
+
+ #if __GNUC_PREREQ(3,3)
+
+-# define NAN (__builtin_nanf(""))
++# define NAN (__builtin_nanf (""))
+
+-#elif defined__GNUC__
++#elif defined __GNUC__
+
+ # define NAN \
+- (__extension__ \
+- ((union { unsigned __l __attribute__((__mode__(__SI__))); float __d; }) \
++ (__extension__ \
++ ((union { unsigned __l __attribute__ ((__mode__ (__SI__))); float __d; }) \
+ { __l: 0x7fc00000UL }).__d)
+
+ #else
--- /dev/null
+2006-05-01 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nss_nis/nis-pwd.c (internal_nis_getpwent_r): Don't try to
+ free outkey in error case when batch_read is set.
+
+ * nis/nss_nis/nis-grp.c (internal_nis_getgrent_r): Don't try to
+ free outkey in error case when batch_read is set [Coverity CID 196].
+
+2006-04-30 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nss_nisplus/nisplus-publickey.c (parse_grp_str): PIDLIST is
+ supposed to have NGRPS elements.
+
+ * nis/nss_nisplus/nisplus-parser.c: Minor optimizations and
+ cleanups. Avoid copying data if it can be used in the old place.
+
+2006-04-29 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nss_nisplus/nisplus-ethers.c: Add missing null pointer check.
+ * nis/nss_nisplus/nisplus-hosts.c: Likewise.
+ * nis/nss_nisplus/nisplus-network.c: Likewise.
+ * nis/nss_nisplus/nisplus-proto.c: Likewise.
+ * nis/nss_nisplus/nisplus-rpc.c: Likewise.
+ * nis/nss_nisplus/nisplus-service.c: Likewise.
+ * nis/nss_nisplus/nisplus-spwd.c: Likewise.
+
+ * nis/nisplus-parser.h (_nss_nisplus_parse_pwent): Add entry
+ parameter.
+ (_nss_nisplus_parse_pwent_chk): New prototype.
+ * nis/nss_nisplus/nisplus-parser.c (_nss_nisplus_parse_pwent):
+ Add entry parameter. Use it for column value in all accesses.
+ Move checks for well-formed reply to...
+ (_nss_nisplus_parse_pwent_chk): ...here. New function.
+ * nis/nss_nisplus/nisplus-pwd.c: Support SETENT_BATCH_READ option.
+
+ * nis/nss_nisplus/nisplus-parser.c: Some cleanups. Remove
+ hidden_def definitions.
+ * nis/nisplus-parser.h: Add parameter names. Remove hidden_proto
+ definitions.
+
+2006-04-28 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nss_nis/nis-spwd.c (internal_nis_getspent_r): Remove data
+ variable.
+
+ * nis/nss-nis.h: Define response_t and intern_t. Declare _nis_saveit.
+ * nis/nss_nis/nis-pwd.c: Remove response_t and intern_t definition.
+ (saveit): Renamed to _nis_saveit. Take parameter which is pointer
+ to the intern_t object. Change all users.
+ * nis/nss_nis/nis-grp.c: Remove response_t, intern_t, and saveit
+ definition. Use _nis_saveit instead of saveit.
+ * nis/nss_nis/nis-service.c: Likewise.
+ * nis/nss_nis/nis-initgroups.c: Likewise.
+ (internal_setgrent): Adjust for buffer handling.
+ (internal_getgrent_r): Likewise.
+ * nis/nss_nis/nis-rpc.c: Likewise.
+
+ * nis/nss-default.c (vars): Add SETENT_BATCH_READ.
+ * nis/nss: Document SETENT_BATCH_READ.
+ * nis/libnsl.h: Define NSS_FLAG_SETENT_BATCH_READ.
+ * nis/nss_nis/nis-service.c (saveit): Don't add NUL byte if the
+ string is already NUL terminated.
+ (internal_nis_endservent): No need to return anything. Change callers.
+ (internal_nis_setservent): One more initialization.
+ * nis/nss_nis/nis-pwd.c: Support SETENT_BATCH_READ option.
+ * nis/nss_nis/nis-grp.c: Likewise.
+
+ * nis/nss-default.c (init): Rewrite parser to get the variables
+ from a table.
+
+ * nis/nss_nis/nis-service.c: Avoid passing pointer to static
+ variable around. Reduce number of memory allocations by creating
+ list of memory pools.
+
+ * nis/ypclnt.c (__xdr_ypresp_all): Minor optimization in string
+ handling. Fix typo in comment.
+
+2006-04-23 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nss_nisplus/nisplus-netgrp.c: Cleanups.
+
+2006-04-15 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nss_nisplus/nisplus-publickey.c: Minor cleanups throughout.
+ * nis/nss_nisplus/nisplus-service.c (_nss_nisplus_parse_servent):
+ Significant cleanups. Correct adjustment for pointer array.
+ * nis/nss_nisplus/nisplus-rpc.c (_nss_nisplus_parse_rpcent):
+ Likewise.
+ * nis/nss_nisplus/nisplus-proto.c (_nss_nisplus_parse_protoent):
+ Likewise.
+ * nis/nss_nisplus/nisplus-network.c (_nss_nisplus_parse_netent):
+ Likewise.
+ * nis/nss_nisplus/nisplus-hosts.c (_nss_nisplus_parse_hostent):
+ Likewise.
+
+2006-04-14 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nss_nisplus/nisplus-ethers.c (_nss_nisplus_parse_etherent):
+ Minor cleanups. NUL terminate name string.
+
+ * nis/Versions: No need to export _nss_nisplus_parse_grent,
+ _nss_nisplus_parse_pwent, and _nss_nisplus_parse_spent.
+
+ * nis/nss_nisplus/nisplus-alias.c (_nss_nisplus_parse_aliasent):
+ Avoid unnecessary allocation. Fix adjustment for pointer value.
+
+ * nis/nss_nisplus/nisplus-parser.c: Cleanups, use NIS_RES_*
+ macros. Avoid unnecessary allocation.
+
+2006-04-13 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/Makefile (libnsl-routimes): Add nss-default.
+ * nis/Versions (libnsl) [GLIBC_PRIVATE]: Export _nsl_default_nss.
+ * nis/nss-nis.c: Move /etc/default/nss handling to...
+ * nis/nss-default.c: ...here. New file.
+ * nis/libnsl.h: New file.
+ * nis/nss-nis.h: Remove NSS_FLAG_* definitions and _nis_default_nss
+ plus auxilary definitions.
+ * nis/nss_nis/nis-initgroups.c: Use _nsl_default_nss instead of
+ _nis_default_nss.
+ * nis/nss_nis/nis-service.c: Likewise.
+
+2006-04-08 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nss_nis/nis-alias.c: Optimize use of yperr2nss. Avoid calling
+ it for YPERR_SUCCESS. Minor cleanups. Add __builtin_expect.
+ * nis/nss_nis/nis-ethers.c: Likewise.
+ * nis/nss_nis/nis-grp.c: Likewise.
+ * nis/nss_nis/nis-hosts.c: Likewise.
+ * nis/nss_nis/nis-initgroups.c: Likewise.
+ * nis/nss_nis/nis-netgrp.c: Likewise.
+ * nis/nss_nis/nis-network.c: Likewise.
+ * nis/nss_nis/nis-proto.c: Likewise.
+ * nis/nss_nis/nis-publickey.c: Likewise.
+ * nis/nss_nis/nis-pwd.c: Likewise.
+ * nis/nss_nis/nis-rpc.c: Likewise.
+ * nis/nss_nis/nis-service.c: Likewise.
+ * nis/nss_nis/nis-spwd.c: Likewise.
+
+ * nis/nis_ping.c: Remove unnecessary conditionals before
+ nis_freeresult calls.
+ * nis/nis_ismember.c: Likewise.
+
+--- libc/nis/Makefile 8 Sep 2004 15:26:01 -0000 1.31
++++ libc/nis/Makefile 14 Apr 2006 05:45:49 -0000 1.32
+@@ -54,7 +54,7 @@ libnsl-routines = yp_xdr ypclnt ypupdate
+ nis_print_group_entry nis_domain_of nis_domain_of_r\
+ nis_modify nis_remove nis_add nis_defaults\
+ nis_findserv nis_callback nis_clone_dir nis_clone_obj\
+- nis_clone_res
++ nis_clone_res nss-default
+
+ libnss_compat-routines := $(addprefix compat-,grp pwd spwd initgroups)
+ libnss_compat-inhibit-o = $(filter-out .os,$(object-suffixes))
+--- libc/nis/Versions 1 Feb 2002 23:11:22 -0000 1.7
++++ libc/nis/Versions 14 Apr 2006 21:07:54 -0000 1.9
+@@ -57,6 +57,9 @@ libnsl {
+ GLIBC_2.2 {
+ xdr_ypall;
+ }
++ GLIBC_PRIVATE {
++ _nsl_default_nss;
++ }
+ }
+
+ libnss_compat {
+@@ -117,8 +120,7 @@ libnss_nisplus {
+ _nss_nisplus_getservbyname_r; _nss_nisplus_getservbynumber_r;
+ _nss_nisplus_getservent_r; _nss_nisplus_getspent_r;
+ _nss_nisplus_getspnam_r; _nss_nisplus_netname2user;
+- _nss_nisplus_parse_grent; _nss_nisplus_parse_pwent;
+- _nss_nisplus_parse_spent; _nss_nisplus_setaliasent;
++ _nss_nisplus_setaliasent;
+ _nss_nisplus_setetherent; _nss_nisplus_setgrent; _nss_nisplus_sethostent;
+ _nss_nisplus_setnetent; _nss_nisplus_setnetgrent; _nss_nisplus_setprotoent;
+ _nss_nisplus_setpwent; _nss_nisplus_setrpcent; _nss_nisplus_setservent;
+--- libc/nis/nis_ismember.c 6 Jul 2001 04:55:36 -0000 1.6
++++ libc/nis/nis_ismember.c 8 Apr 2006 20:12:26 -0000 1.7
+@@ -47,8 +47,7 @@ internal_ismember (const_nis_name princi
+ res = nis_lookup (buf, EXPAND_NAME|FOLLOW_LINKS);
+ if (res == NULL || NIS_RES_STATUS (res) != NIS_SUCCESS)
+ {
+- if (res)
+- nis_freeresult (res);
++ nis_freeresult (res);
+ return 0;
+ }
+
+--- libc/nis/nis_ping.c 6 Jul 2001 04:55:36 -0000 1.12
++++ libc/nis/nis_ping.c 8 Apr 2006 20:11:14 -0000 1.13
+@@ -39,8 +39,7 @@ nis_ping (const_nis_name dirname, unsign
+ res = nis_lookup (dirname, MASTER_ONLY);
+ if (res == NULL || NIS_RES_STATUS (res) != NIS_SUCCESS)
+ {
+- if (res)
+- nis_freeresult (res);
++ nis_freeresult (res);
+ return;
+ }
+ obj = res->objects.objects_val;
+@@ -51,8 +50,7 @@ nis_ping (const_nis_name dirname, unsign
+ /* Check if obj is really a diryectory object */
+ if (__type_of (obj) != NIS_DIRECTORY_OBJ)
+ {
+- if (res != NULL)
+- nis_freeresult (res);
++ nis_freeresult (res);
+ return;
+ }
+
+@@ -68,6 +66,5 @@ nis_ping (const_nis_name dirname, unsign
+ NIS_PING, (xdrproc_t) _xdr_ping_args,
+ (caddr_t) &args, (xdrproc_t) xdr_void,
+ (caddr_t) NULL, 0, NULL);
+- if (res)
+- nis_freeresult (res);
++ nis_freeresult (res);
+ }
+--- libc/nis/nisplus-parser.h 24 Oct 2004 21:22:48 -0000 1.4
++++ libc/nis/nisplus-parser.h 29 Apr 2006 20:16:35 -0000 1.6
+@@ -24,15 +24,16 @@
+ #include <grp.h>
+ #include <shadow.h>
+
+-extern int _nss_nisplus_parse_pwent (nis_result *, struct passwd *,
+- char *, size_t, int *);
+-extern int _nss_nisplus_parse_grent (nis_result *, u_long, struct group *,
+- char *, size_t, int *);
+-extern int _nss_nisplus_parse_spent (nis_result *, struct spwd *,
+- char *, size_t, int *);
+-
+-libnss_nisplus_hidden_proto (_nss_nisplus_parse_pwent)
+-libnss_nisplus_hidden_proto (_nss_nisplus_parse_grent)
+-libnss_nisplus_hidden_proto (_nss_nisplus_parse_spent)
++extern int _nss_nisplus_parse_pwent (nis_result *result, size_t entry,
++ struct passwd *pw, char *buffer,
++ size_t buflen, int *errnop);
++extern int _nss_nisplus_parse_pwent_chk (nis_result *result, struct passwd *pw,
++ char *buffer, size_t buflen,
++ int *errnop);
++extern int _nss_nisplus_parse_grent (nis_result *result, u_long entry,
++ struct group *gr, char *buffer,
++ size_t buflen, int *errnop);
++extern int _nss_nisplus_parse_spent (nis_result *result, struct spwd *sp,
++ char *buffer, size_t buflen, int *errnop);
+
+ #endif
+--- libc/nis/nss 2 Apr 2004 09:14:48 -0000 1.2
++++ libc/nis/nss 28 Apr 2006 21:02:23 -0000 1.3
+@@ -1,7 +1,7 @@
+ # /etc/default/nss
+ # This file can theoretically contain a bunch of customization variables
+-# for Name Service Switch in the GNU C library. For now there are only two
+-# variables:
++# for Name Service Switch in the GNU C library. For now there are only
++# three variables:
+ #
+ # NETID_AUTHORITATIVE
+ # If set to TRUE, the initgroups() function will accept the information
+@@ -18,3 +18,11 @@
+ # primary service names and service aliases. The system administrator
+ # has to make sure it is correctly generated.
+ #SERVICES_AUTHORITATIVE=TRUE
++#
++# SETENT_BATCH_READ
++# If set to TRUE, various setXXent() functions will read the entire
++# database at once and then hand out the requests one by one from
++# memory with every getXXent() call. Otherwise each getXXent() call
++# might result into a network communication with the server to get
++# the next entry.
++#SETENT_BATCH_READ=TRUE
+--- libc/nis/nss-nis.c 20 Apr 2004 18:52:12 -0000 1.5
++++ libc/nis/nss-nis.c 14 Apr 2006 05:48:48 -0000 1.6
+@@ -16,13 +16,6 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+-#include <ctype.h>
+-#include <stdio.h>
+-#include <stdio_ext.h>
+-#include <stdlib.h>
+-#include <string.h>
+-#include <rpcsvc/ypclnt.h>
+-
+ #include "nss-nis.h"
+ #include "nsswitch.h"
+
+@@ -50,81 +43,3 @@ const enum nss_status __yperr2nss_tab[]
+ };
+ const unsigned int __yperr2nss_count = (sizeof (__yperr2nss_tab)
+ / sizeof (__yperr2nss_tab[0]));
+-
+-int _nis_default_nss_flags;
+-
+-static const char default_nss[] = "/etc/default/nss";
+-
+-int
+-_nis_check_default_nss (void)
+-{
+- FILE *fp = fopen (default_nss, "rc");
+- int flags = NSS_FLAG_SET;
+- if (fp != NULL)
+- {
+- char *line = NULL;
+- size_t linelen = 0;
+-
+- __fsetlocking (fp, FSETLOCKING_BYCALLER);
+-
+- while (!feof_unlocked (fp))
+- {
+- ssize_t n = getline (&line, &linelen, fp);
+- if (n <= 0)
+- break;
+-
+- /* There currently are only two variables we expect, so
+- simplify the parsing. Recognize only
+-
+- NETID_AUTHORITATIVE = TRUE
+- SERVICES_AUTHORITATIVE = TRUE
+-
+- with arbitrary white spaces. */
+- char *cp = line;
+- while (isspace (*cp))
+- ++cp;
+-
+- /* Recognize comment lines. */
+- if (*cp == '#')
+- continue;
+-
+- static const char netid_authoritative[] = "NETID_AUTHORITATIVE";
+- static const char services_authoritative[]
+- = "SERVICES_AUTHORITATIVE";
+- size_t flag_len;
+- if (strncmp (cp, netid_authoritative,
+- flag_len = sizeof (netid_authoritative) - 1) != 0
+- && strncmp (cp, services_authoritative,
+- flag_len = sizeof (services_authoritative) - 1)
+- != 0)
+- continue;
+-
+- cp += flag_len;
+- while (isspace (*cp))
+- ++cp;
+- if (*cp++ != '=')
+- continue;
+- while (isspace (*cp))
+- ++cp;
+-
+- if (strncmp (cp, "TRUE", 4) != 0)
+- continue;
+- cp += 4;
+-
+- while (isspace (*cp))
+- ++cp;
+-
+- if (*cp == '\0')
+- flags |= flag_len == sizeof (netid_authoritative) - 1
+- ? NSS_FLAG_NETID_AUTHORITATIVE
+- : NSS_FLAG_SERVICES_AUTHORITATIVE;
+- }
+-
+- free (line);
+-
+- fclose (fp);
+- }
+-
+- _nis_default_nss_flags = flags;
+- return flags;
+-}
+--- libc/nis/nss-nis.h 2 Apr 2004 09:15:04 -0000 1.5
++++ libc/nis/nss-nis.h 29 Apr 2006 01:07:41 -0000 1.7
+@@ -36,16 +36,24 @@ yperr2nss (int errval)
+ return __yperr2nss_tab[(unsigned int) errval];
+ }
+
+-#define NSS_FLAG_SET 1
+-#define NSS_FLAG_NETID_AUTHORITATIVE 2
+-#define NSS_FLAG_SERVICES_AUTHORITATIVE 4
+-extern int _nis_default_nss_flags attribute_hidden;
+-extern int _nis_check_default_nss (void) attribute_hidden;
+
+-extern inline __attribute__((always_inline)) int
+-_nis_default_nss (void)
++struct response_t
+ {
+- return _nis_default_nss_flags ?: _nis_check_default_nss ();
+-}
++ struct response_t *next;
++ size_t size;
++ char mem[0];
++};
++
++typedef struct intern_t
++{
++ struct response_t *start;
++ struct response_t *next;
++ size_t offset;
++} intern_t;
++
++
++extern int _nis_saveit (int instatus, char *inkey, int inkeylen, char *inval,
++ int invallen, char *indata) attribute_hidden;
++
+
+ #endif /* nis/nss-nis.h */
+--- libc/nis/ypclnt.c 6 Apr 2006 23:59:35 -0000 1.57
++++ libc/nis/ypclnt.c 28 Apr 2006 16:59:22 -0000 1.58
+@@ -686,10 +686,10 @@ __xdr_ypresp_all (XDR *xdrs, struct ypre
+ if we don't modify the length. So add an extra NUL
+ character to avoid trouble with broken code. */
+ objp->status = YP_TRUE;
+- memcpy (key, resp.ypresp_all_u.val.key.keydat_val, keylen);
+- key[keylen] = '\0';
+- memcpy (val, resp.ypresp_all_u.val.val.valdat_val, vallen);
+- val[vallen] = '\0';
++ *((char *) __mempcpy (key, resp.ypresp_all_u.val.key.keydat_val,
++ keylen)) = '\0';
++ *((char *) __mempcpy (val, resp.ypresp_all_u.val.val.valdat_val,
++ vallen)) = '\0';
+ xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
+ if ((*objp->foreach) (objp->status, key, keylen,
+ val, vallen, objp->data))
+@@ -700,7 +700,7 @@ __xdr_ypresp_all (XDR *xdrs, struct ypre
+ objp->status = resp.ypresp_all_u.val.stat;
+ xdr_free ((xdrproc_t) xdr_ypresp_all, (char *) &resp);
+ /* Sun says we don't need to make this call, but must return
+- immediatly. Since Solaris makes this call, we will call
++ immediately. Since Solaris makes this call, we will call
+ the callback function, too. */
+ (*objp->foreach) (objp->status, NULL, 0, NULL, 0, objp->data);
+ return TRUE;
+--- libc/nis/nss_nis/nis-alias.c 6 Apr 2006 22:40:12 -0000 1.17
++++ libc/nis/nss_nis/nis-alias.c 9 Apr 2006 02:08:28 -0000 1.18
+@@ -125,52 +125,53 @@ internal_nis_getaliasent_r (struct alias
+ size_t buflen, int *errnop)
+ {
+ char *domain;
+- char *result;
+- int len;
+- char *outkey;
+- int keylen;
+- char *p;
+- int parse_res;
+
+- if (yp_get_default_domain (&domain))
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+ alias->alias_local = 0;
+
+ /* Get the next entry until we found a correct one. */
++ int parse_res;
+ do
+ {
+- enum nss_status retval;
++ char *result;
++ int len;
++ char *outkey;
++ int keylen;
++ int yperr;
+
+ if (new_start)
+- retval = yperr2nss (yp_first (domain, "mail.aliases",
+- &outkey, &keylen, &result, &len));
++ yperr = yp_first (domain, "mail.aliases", &outkey, &keylen, &result,
++ &len);
+ else
+- retval = yperr2nss ( yp_next (domain, "mail.aliases", oldkey,
+- oldkeylen, &outkey, &keylen,
+- &result, &len));
+- if (retval != NSS_STATUS_SUCCESS)
++ yperr = yp_next (domain, "mail.aliases", oldkey, oldkeylen, &outkey,
++ &keylen, &result, &len);
++
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+ {
++ enum nss_status retval = yperr2nss (yperr);
++
+ if (retval == NSS_STATUS_TRYAGAIN)
+ *errnop = errno;
+ return retval;
+ }
+
+- if ((size_t) (len + 1) > buflen)
++ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+- p = strncpy (buffer, result, len);
++ char *p = strncpy (buffer, result, len);
+ buffer[len] = '\0';
+ while (isspace (*p))
+ ++p;
+ free (result);
+
+- parse_res = _nss_nis_parse_aliasent (outkey, p, alias, buffer, buflen,
+- errnop);
+- if (parse_res == -1)
++ parse_res = _nss_nis_parse_aliasent (outkey, p, alias, buffer,
++ buflen, errnop);
++ if (__builtin_expect (parse_res == -1, 0))
+ {
+ free (outkey);
+ *errnop = ERANGE;
+@@ -216,7 +217,7 @@ _nss_nis_getaliasbyname_r (const char *n
+ char name2[namlen + 1];
+
+ char *domain;
+- if (yp_get_default_domain (&domain))
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+ /* Convert name to lowercase. */
+@@ -227,17 +228,18 @@ _nss_nis_getaliasbyname_r (const char *n
+
+ char *result;
+ int len;
+- enum nss_status retval = yperr2nss (yp_match (domain, "mail.aliases", name2,
+- namlen, &result, &len));
++ int yperr = yp_match (domain, "mail.aliases", name2, namlen, &result, &len);
+
+- if (retval != NSS_STATUS_SUCCESS)
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+ {
++ enum nss_status retval = yperr2nss (yperr);
++
+ if (retval == NSS_STATUS_TRYAGAIN)
+ *errnop = errno;
+ return retval;
+ }
+
+- if ((size_t) (len + 1) > buflen)
++ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+@@ -253,7 +255,7 @@ _nss_nis_getaliasbyname_r (const char *n
+ alias->alias_local = 0;
+ int parse_res = _nss_nis_parse_aliasent (name, p, alias, buffer, buflen,
+ errnop);
+- if (parse_res < 1)
++ if (__builtin_expect (parse_res < 1, 0))
+ {
+ if (parse_res == -1)
+ return NSS_STATUS_TRYAGAIN;
+--- libc/nis/nss_nis/nis-ethers.c 2 Apr 2004 15:09:32 -0000 1.24
++++ libc/nis/nss_nis/nis-ethers.c 9 Apr 2006 02:08:28 -0000 1.25
+@@ -182,45 +182,46 @@ enum nss_status
+ _nss_nis_gethostton_r (const char *name, struct etherent *eth,
+ char *buffer, size_t buflen, int *errnop)
+ {
+- struct parser_data *data = (void *) buffer;
+- enum nss_status retval;
+- char *domain, *result, *p;
+- int len, parse_res;
+-
+ if (name == NULL)
+ {
+ *errnop = EINVAL;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+- if (yp_get_default_domain (&domain))
++ char *domain;
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+- retval = yperr2nss (yp_match (domain, "ethers.byname", name,
+- strlen (name), &result, &len));
++ char *result;
++ int len;
++ int yperr = yp_match (domain, "ethers.byname", name, strlen (name), &result,
++ &len);
+
+- if (retval != NSS_STATUS_SUCCESS)
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+ {
++ enum nss_status retval = yperr2nss (yperr);
++
+ if (retval == NSS_STATUS_TRYAGAIN)
+ *errnop = errno;
+ return retval;
+ }
+
+- if ((size_t) (len + 1) > buflen)
++ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- p = strncpy (buffer, result, len);
++ char *p = strncpy (buffer, result, len);
+ buffer[len] = '\0';
+ while (isspace (*p))
+ ++p;
+ free (result);
+
+- parse_res = _nss_files_parse_etherent (p, eth, data, buflen, errnop);
+- if (parse_res < 1)
++ int parse_res = _nss_files_parse_etherent (p, eth, (void *) buffer, buflen,
++ errnop);
++ if (__builtin_expect (parse_res < 1, 0))
+ {
+ if (parse_res == -1)
+ return NSS_STATUS_TRYAGAIN;
+@@ -234,54 +235,54 @@ enum nss_status
+ _nss_nis_getntohost_r (const struct ether_addr *addr, struct etherent *eth,
+ char *buffer, size_t buflen, int *errnop)
+ {
+- struct parser_data *data = (void *) buffer;
+- enum nss_status retval;
+- char *domain, *result, *p;
+- int len, nlen, parse_res;
+- char buf[33];
+-
+ if (addr == NULL)
+ {
+ *errnop = EINVAL;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+- if (yp_get_default_domain (&domain))
++ char *domain;
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+- nlen = sprintf (buf, "%x:%x:%x:%x:%x:%x",
+- (int) addr->ether_addr_octet[0],
+- (int) addr->ether_addr_octet[1],
+- (int) addr->ether_addr_octet[2],
+- (int) addr->ether_addr_octet[3],
+- (int) addr->ether_addr_octet[4],
+- (int) addr->ether_addr_octet[5]);
+-
+- retval = yperr2nss (yp_match (domain, "ethers.byaddr", buf,
+- nlen, &result, &len));
++ char buf[33];
++ int nlen = snprintf (buf, sizeof (buf), "%x:%x:%x:%x:%x:%x",
++ (int) addr->ether_addr_octet[0],
++ (int) addr->ether_addr_octet[1],
++ (int) addr->ether_addr_octet[2],
++ (int) addr->ether_addr_octet[3],
++ (int) addr->ether_addr_octet[4],
++ (int) addr->ether_addr_octet[5]);
++
++ char *result;
++ int len;
++ int yperr = yp_match (domain, "ethers.byaddr", buf, nlen, &result, &len);
+
+- if (retval != NSS_STATUS_SUCCESS)
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+ {
++ enum nss_status retval = yperr2nss (yperr);
++
+ if (retval == NSS_STATUS_TRYAGAIN)
+ *errnop = errno;
+ return retval;
+ }
+
+- if ((size_t) (len + 1) > buflen)
++ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- p = strncpy (buffer, result, len);
++ char *p = strncpy (buffer, result, len);
+ buffer[len] = '\0';
+ while (isspace (*p))
+ ++p;
+ free (result);
+
+- parse_res = _nss_files_parse_etherent (p, eth, data, buflen, errnop);
+- if (parse_res < 1)
++ int parse_res = _nss_files_parse_etherent (p, eth, (void *) buffer, buflen,
++ errnop);
++ if (__builtin_expect (parse_res < 1, 0))
+ {
+ if (parse_res == -1)
+ return NSS_STATUS_TRYAGAIN;
+--- libc/nis/nss_nis/nis-grp.c 29 Mar 2004 20:02:41 -0000 1.19
++++ libc/nis/nss_nis/nis-grp.c 1 May 2006 22:22:09 -0000 1.23
+@@ -17,20 +17,17 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+-#include <nss.h>
+-/* The following is an ugly trick to avoid a prototype declaration for
+- _nss_nis_endgrent. */
+-#define _nss_nis_endgrent _nss_nis_endgrent_XXX
+-#include <grp.h>
+-#undef _nss_nis_endgrent
+ #include <ctype.h>
+ #include <errno.h>
++#include <grp.h>
++#include <nss.h>
+ #include <string.h>
+ #include <bits/libc-lock.h>
+ #include <rpcsvc/yp.h>
+ #include <rpcsvc/ypclnt.h>
+
+ #include "nss-nis.h"
++#include <libnsl.h>
+
+ /* Get the declaration of the parser function. */
+ #define ENTNAME grent
+@@ -44,12 +41,12 @@ __libc_lock_define_initialized (static,
+ static bool_t new_start = 1;
+ static char *oldkey;
+ static int oldkeylen;
++static intern_t intern;
+
+-enum nss_status
+-_nss_nis_setgrent (int stayopen)
+-{
+- __libc_lock_lock (lock);
+
++static void
++internal_nis_endgrent (void)
++{
+ new_start = 1;
+ if (oldkey != NULL)
+ {
+@@ -58,72 +55,186 @@ _nss_nis_setgrent (int stayopen)
+ oldkeylen = 0;
+ }
+
++ struct response_t *curr = intern.next;
++
++ while (curr != NULL)
++ {
++ struct response_t *last = curr;
++ curr = curr->next;
++ free (last);
++ }
++
++ intern.next = intern.start = NULL;
++}
++
++
++enum nss_status
++_nss_nis_endgrent (void)
++{
++ __libc_lock_lock (lock);
++
++ internal_nis_endgrent ();
++
+ __libc_lock_unlock (lock);
+
+ return NSS_STATUS_SUCCESS;
+ }
+-/* Make _nss_nis_endgrent an alias of _nss_nis_setgrent. We do this
+- even though the prototypes don't match. The argument of setgrent
+- is not used so this makes no difference. */
+-strong_alias (_nss_nis_setgrent, _nss_nis_endgrent)
++
++
++enum nss_status
++internal_nis_setgrent (void)
++{
++ /* We have to read all the data now. */
++ char *domain;
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
++ return NSS_STATUS_UNAVAIL;
++
++ struct ypall_callback ypcb;
++
++ ypcb.foreach = _nis_saveit;
++ ypcb.data = (char *) &intern;
++ enum nss_status status = yperr2nss (yp_all (domain, "group.byname", &ypcb));
++
++
++ /* Mark the last buffer as full. */
++ if (intern.next != NULL)
++ intern.next->size = intern.offset;
++
++ intern.next = intern.start;
++ intern.offset = 0;
++
++ return status;
++}
++
++
++enum nss_status
++_nss_nis_setgrent (int stayopen)
++{
++ enum nss_status result = NSS_STATUS_SUCCESS;
++
++ __libc_lock_lock (lock);
++
++ internal_nis_endgrent ();
++
++ if (_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ)
++ result = internal_nis_setgrent ();
++
++ __libc_lock_unlock (lock);
++
++ return result;
++}
++
+
+ static enum nss_status
+ internal_nis_getgrent_r (struct group *grp, char *buffer, size_t buflen,
+ int *errnop)
+ {
+- struct parser_data *data = (void *) buffer;
+- char *domain, *result, *outkey;
+- int len, keylen, parse_res;
++ /* If we read the entire database at setpwent time we just iterate
++ over the data we have in memory. */
++ bool batch_read = intern.start != NULL;
+
+- if (yp_get_default_domain (&domain))
++ char *domain = NULL;
++ if (!batch_read && __builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+ /* Get the next entry until we found a correct one. */
++ int parse_res;
+ do
+ {
+- enum nss_status retval;
+- char *p;
++ char *result;
++ char *outkey;
++ int len;
++ int keylen;
++
++ if (batch_read)
++ {
++ struct response_t *bucket;
++
++ handle_batch_read:
++ bucket = intern.next;
++
++ if (__builtin_expect (intern.offset >= bucket->size, 0))
++ {
++ if (bucket->next == NULL)
++ return NSS_STATUS_NOTFOUND;
++
++ /* We look at all the content in the current bucket. Go on
++ to the next. */
++ bucket = intern.next = bucket->next;
++ intern.offset = 0;
++ }
++
++ for (result = &bucket->mem[intern.offset]; isspace (*result);
++ ++result)
++ ++intern.offset;
+
+- if (new_start)
+- retval = yperr2nss (yp_first (domain, "group.byname",
+- &outkey, &keylen, &result, &len));
++ len = strlen (result);
++ }
+ else
+- retval = yperr2nss ( yp_next (domain, "group.byname",
+- oldkey, oldkeylen,
+- &outkey, &keylen, &result, &len));
++ {
++ int yperr;
+
+- if (retval != NSS_STATUS_SUCCESS)
+- {
+- if (retval == NSS_STATUS_TRYAGAIN)
+- *errnop = errno;
+- return retval;
+- }
++ if (new_start)
++ {
++ /* Maybe we should read the database in one piece. */
++ if ((_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ)
++ && internal_nis_setgrent () == NSS_STATUS_SUCCESS
++ && intern.start != NULL)
++ {
++ batch_read = true;
++ goto handle_batch_read;
++ }
++
++ yperr = yp_first (domain, "group.byname", &outkey, &keylen,
++ &result, &len);
++ }
++ else
++ yperr = yp_next (domain, "group.byname", oldkey, oldkeylen,
++ &outkey, &keylen, &result, &len);
++
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
++ {
++ enum nss_status retval = yperr2nss (yperr);
++
++ if (retval == NSS_STATUS_TRYAGAIN)
++ *errnop = errno;
++ return retval;
++ }
++ }
+
+- if ((size_t) (len + 1) > buflen)
++ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- p = strncpy (buffer, result, len);
++ char *p = strncpy (buffer, result, len);
+ buffer[len] = '\0';
+ while (isspace (*p))
+ ++p;
+- free (result);
++ if (!batch_read)
++ free (result);
+
+- parse_res = _nss_files_parse_grent (p, grp, data, buflen, errnop);
+- if (parse_res == -1)
++ parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen,
++ errnop);
++ if (__builtin_expect (parse_res == -1, 0))
+ {
+- free (outkey);
++ if (!batch_read)
++ free (outkey);
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- free (oldkey);
+- oldkey = outkey;
+- oldkeylen = keylen;
+- new_start = 0;
++ if (batch_read)
++ intern.offset += len + 1;
++ else
++ {
++ free (oldkey);
++ oldkey = outkey;
++ oldkeylen = keylen;
++ new_start = 0;
++ }
+ }
+ while (parse_res < 1);
+
+@@ -149,45 +260,46 @@ enum nss_status
+ _nss_nis_getgrnam_r (const char *name, struct group *grp,
+ char *buffer, size_t buflen, int *errnop)
+ {
+- struct parser_data *data = (void *) buffer;
+- enum nss_status retval;
+- char *domain, *result, *p;
+- int len, parse_res;
+-
+ if (name == NULL)
+ {
+ *errnop = EINVAL;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+- if (yp_get_default_domain (&domain))
++ char *domain;
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+- retval = yperr2nss (yp_match (domain, "group.byname", name,
+- strlen (name), &result, &len));
++ char *result;
++ int len;
++ int yperr = yp_match (domain, "group.byname", name, strlen (name), &result,
++ &len);
+
+- if (retval != NSS_STATUS_SUCCESS)
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+ {
++ enum nss_status retval = yperr2nss (yperr);
++
+ if (retval == NSS_STATUS_TRYAGAIN)
+ *errnop = errno;
+ return retval;
+ }
+
+- if ((size_t) (len + 1) > buflen)
++ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- p = strncpy (buffer, result, len);
++ char *p = strncpy (buffer, result, len);
+ buffer[len] = '\0';
+ while (isspace (*p))
+ ++p;
+ free (result);
+
+- parse_res = _nss_files_parse_grent (p, grp, data, buflen, errnop);
+- if (parse_res < 1)
++ int parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen,
++ errnop);
++ if (__builtin_expect (parse_res < 1, 0))
+ {
+ if (parse_res == -1)
+ return NSS_STATUS_TRYAGAIN;
+@@ -201,42 +313,42 @@ enum nss_status
+ _nss_nis_getgrgid_r (gid_t gid, struct group *grp,
+ char *buffer, size_t buflen, int *errnop)
+ {
+- struct parser_data *data = (void *) buffer;
+- enum nss_status retval;
+- char *domain, *result, *p;
+- int len, nlen, parse_res;
+- char buf[32];
+-
+- if (yp_get_default_domain (&domain))
++ char *domain;
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+- nlen = sprintf (buf, "%lu", (unsigned long int) gid);
++ char buf[32];
++ int nlen = sprintf (buf, "%lu", (unsigned long int) gid);
+
+- retval = yperr2nss (yp_match (domain, "group.bygid", buf,
+- nlen, &result, &len));
++ char *result;
++ int len;
++ int yperr = yp_match (domain, "group.bygid", buf, nlen, &result, &len);
+
+- if (retval != NSS_STATUS_SUCCESS)
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+ {
++ enum nss_status retval = yperr2nss (yperr);
++
+ if (retval == NSS_STATUS_TRYAGAIN)
+ *errnop = errno;
+ return retval;
+ }
+
+- if ((size_t) (len + 1) > buflen)
++ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- p = strncpy (buffer, result, len);
++ char *p = strncpy (buffer, result, len);
+ buffer[len] = '\0';
+ while (isspace (*p))
+ ++p;
+ free (result);
+
+- parse_res = _nss_files_parse_grent (p, grp, data, buflen, errnop);
+- if (parse_res < 1)
++ int parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen,
++ errnop);
++ if (__builtin_expect (parse_res < 1, 0))
+ {
+ if (parse_res == -1)
+ return NSS_STATUS_TRYAGAIN;
+--- libc/nis/nss_nis/nis-hosts.c 16 Mar 2003 03:36:21 -0000 1.25
++++ libc/nis/nss_nis/nis-hosts.c 9 Apr 2006 02:08:28 -0000 1.26
+@@ -131,17 +131,11 @@ internal_nis_gethostent_r (struct hosten
+ int af, int flags)
+ {
+ char *domain;
+- char *result;
+- int len, parse_res;
+- char *outkey;
+- int keylen;
+- struct parser_data *data = (void *) buffer;
+- size_t linebuflen = buffer + buflen - data->linebuffer;
+-
+- if (yp_get_default_domain (&domain))
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+- if (buflen < sizeof *data + 1)
++ struct parser_data *data = (void *) buffer;
++ if (__builtin_expect (buflen < sizeof *data + 1, 0))
+ {
+ *errnop = ERANGE;
+ *h_errnop = NETDB_INTERNAL;
+@@ -149,21 +143,26 @@ internal_nis_gethostent_r (struct hosten
+ }
+
+ /* Get the next entry until we found a correct one. */
++ const size_t linebuflen = buffer + buflen - data->linebuffer;
++ int parse_res;
+ do
+ {
+- enum nss_status retval;
+- char *p;
+-
++ char *result;
++ int len;
++ char *outkey;
++ int keylen;
++ int yperr;
+ if (new_start)
+- retval = yperr2nss (yp_first (domain, "hosts.byname",
+- &outkey, &keylen, &result, &len));
++ yperr = yp_first (domain, "hosts.byname", &outkey, &keylen, &result,
++ &len);
+ else
+- retval = yperr2nss ( yp_next (domain, "hosts.byname",
+- oldkey, oldkeylen,
+- &outkey, &keylen, &result, &len));
++ yperr = yp_next (domain, "hosts.byname", oldkey, oldkeylen, &outkey,
++ &keylen, &result, &len);
+
+- if (retval != NSS_STATUS_SUCCESS)
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+ {
++ enum nss_status retval = yperr2nss (yperr);
++
+ switch (retval)
+ {
+ case NSS_STATUS_TRYAGAIN:
+@@ -180,7 +179,7 @@ internal_nis_gethostent_r (struct hosten
+ return retval;
+ }
+
+- if ((size_t) (len + 1) > linebuflen)
++ if (__builtin_expect ((size_t) (len + 1) > linebuflen, 0))
+ {
+ free (result);
+ *h_errnop = NETDB_INTERNAL;
+@@ -188,14 +187,14 @@ internal_nis_gethostent_r (struct hosten
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- p = strncpy (data->linebuffer, result, len);
++ char *p = strncpy (data->linebuffer, result, len);
+ data->linebuffer[len] = '\0';
+ while (isspace (*p))
+ ++p;
+ free (result);
+
+ parse_res = parse_line (p, host, data, buflen, errnop, af, flags);
+- if (parse_res == -1)
++ if (__builtin_expect (parse_res == -1, 0))
+ {
+ free (outkey);
+ *h_errnop = NETDB_INTERNAL;
+@@ -235,11 +234,7 @@ internal_gethostbyname2_r (const char *n
+ char *buffer, size_t buflen, int *errnop,
+ int *h_errnop, int flags)
+ {
+- enum nss_status retval;
+- char *domain, *result, *p;
+- int len, parse_res;
+ struct parser_data *data = (void *) buffer;
+- size_t linebuflen = buffer + buflen - data->linebuffer;
+
+ if (name == NULL)
+ {
+@@ -247,6 +242,7 @@ internal_gethostbyname2_r (const char *n
+ return NSS_STATUS_UNAVAIL;
+ }
+
++ char *domain;
+ if (yp_get_default_domain (&domain))
+ return NSS_STATUS_UNAVAIL;
+
+@@ -256,24 +252,24 @@ internal_gethostbyname2_r (const char *n
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+- else
+- {
+- /* Convert name to lowercase. */
+- size_t namlen = strlen (name);
+- char name2[namlen + 1];
+- size_t i;
+-
+- for (i = 0; i < namlen; ++i)
+- name2[i] = tolower (name[i]);
+- name2[i] = '\0';
+
+- retval = yperr2nss (yp_match (domain, "hosts.byname", name2,
+- namlen, &result, &len));
++ /* Convert name to lowercase. */
++ size_t namlen = strlen (name);
++ char name2[namlen + 1];
++ size_t i;
++
++ for (i = 0; i < namlen; ++i)
++ name2[i] = tolower (name[i]);
++ name2[i] = '\0';
+
+- }
++ char *result;
++ int len;
++ int yperr = yp_match (domain, "hosts.byname", name2, namlen, &result, &len);
+
+- if (retval != NSS_STATUS_SUCCESS)
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+ {
++ enum nss_status retval = yperr2nss (yperr);
++
+ if (retval == NSS_STATUS_TRYAGAIN)
+ {
+ *h_errnop = TRY_AGAIN;
+@@ -284,7 +280,8 @@ internal_gethostbyname2_r (const char *n
+ return retval;
+ }
+
+- if ((size_t) (len + 1) > linebuflen)
++ const size_t linebuflen = buffer + buflen - data->linebuffer;
++ if (__builtin_expect ((size_t) (len + 1) > linebuflen, 0))
+ {
+ free (result);
+ *h_errnop = NETDB_INTERNAL;
+@@ -292,15 +289,15 @@ internal_gethostbyname2_r (const char *n
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- p = strncpy (data->linebuffer, result, len);
++ char *p = strncpy (data->linebuffer, result, len);
+ data->linebuffer[len] = '\0';
+ while (isspace (*p))
+ ++p;
+ free (result);
+
+- parse_res = parse_line (p, host, data, buflen, errnop, af, flags);
++ int parse_res = parse_line (p, host, data, buflen, errnop, af, flags);
+
+- if (parse_res < 1 || host->h_addrtype != af)
++ if (__builtin_expect (parse_res < 1 || host->h_addrtype != af, 0))
+ {
+ if (parse_res == -1)
+ {
+@@ -351,42 +348,42 @@ _nss_nis_gethostbyaddr_r (const void *ad
+ struct hostent *host, char *buffer, size_t buflen,
+ int *errnop, int *h_errnop)
+ {
+- enum nss_status retval;
+- char *domain, *result, *p;
+- int len, parse_res;
+- char *buf;
+- struct parser_data *data = (void *) buffer;
+- size_t linebuflen = buffer + buflen - data->linebuffer;
+-
+- if (yp_get_default_domain (&domain))
++ char *domain;
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+- if (buflen < sizeof *data + 1)
++ struct parser_data *data = (void *) buffer;
++ if (__builtin_expect (buflen < sizeof *data + 1, 0))
+ {
+ *errnop = ERANGE;
+ *h_errnop = NETDB_INTERNAL;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- buf = inet_ntoa (*(const struct in_addr *) addr);
++ char *buf = inet_ntoa (*(const struct in_addr *) addr);
+
+- retval = yperr2nss (yp_match (domain, "hosts.byaddr", buf,
+- strlen (buf), &result, &len));
++ char *result;
++ int len;
++ int yperr = yp_match (domain, "hosts.byaddr", buf, strlen (buf), &result,
++ &len);
+
+- if (retval != NSS_STATUS_SUCCESS)
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+ {
++ enum nss_status retval = yperr2nss (yperr);
++
+ if (retval == NSS_STATUS_TRYAGAIN)
+ {
+ *h_errnop = TRY_AGAIN;
+ *errnop = errno;
+ }
+- if (retval == NSS_STATUS_NOTFOUND)
++ else if (retval == NSS_STATUS_NOTFOUND)
+ *h_errnop = HOST_NOT_FOUND;
+
+ return retval;
+ }
+
+- if ((size_t) (len + 1) > linebuflen)
++ const size_t linebuflen = buffer + buflen - data->linebuffer;
++ if (__builtin_expect ((size_t) (len + 1) > linebuflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+@@ -394,15 +391,16 @@ _nss_nis_gethostbyaddr_r (const void *ad
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- p = strncpy (data->linebuffer, result, len);
++ char *p = strncpy (data->linebuffer, result, len);
+ data->linebuffer[len] = '\0';
+ while (isspace (*p))
+ ++p;
+ free (result);
+
+- parse_res = parse_line (p, host, data, buflen, errnop, af,
+- ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0));
+- if (parse_res < 1)
++ int parse_res = parse_line (p, host, data, buflen, errnop, af,
++ ((_res.options & RES_USE_INET6)
++ ? AI_V4MAPPED : 0));
++ if (__builtin_expect (parse_res < 1, 0))
+ {
+ if (parse_res == -1)
+ {
+--- libc/nis/nss_nis/nis-initgroups.c 2 Apr 2004 15:09:32 -0000 1.14
++++ libc/nis/nss_nis/nis-initgroups.c 29 Apr 2006 01:12:53 -0000 1.17
+@@ -30,6 +30,7 @@
+ #include <sys/param.h>
+
+ #include "nss-nis.h"
++#include <libnsl.h>
+
+ /* Get the declaration of the parser function. */
+ #define ENTNAME grent
+@@ -37,47 +38,6 @@
+ #define EXTERN_PARSER
+ #include <nss/nss_files/files-parse.c>
+
+-struct response_t
+-{
+- struct response_t *next;
+- char val[0];
+-};
+-
+-struct intern_t
+-{
+- struct response_t *start;
+- struct response_t *next;
+-};
+-typedef struct intern_t intern_t;
+-
+-static int
+-saveit (int instatus, char *inkey, int inkeylen, char *inval,
+- int invallen, char *indata)
+-{
+- intern_t *intern = (intern_t *) indata;
+-
+- if (instatus != YP_TRUE)
+- return 1;
+-
+- if (inkey && inkeylen > 0 && inval && invallen > 0)
+- {
+- struct response_t *newp = malloc (sizeof (struct response_t)
+- + invallen + 1);
+- if (newp == NULL)
+- return 1; /* We have no error code for out of memory */
+-
+- if (intern->start == NULL)
+- intern->start = newp;
+- else
+- intern->next->next = newp;
+- intern->next = newp;
+-
+- newp->next = NULL;
+- *((char *) mempcpy (newp->val, inval, invallen)) = '\0';
+- }
+-
+- return 0;
+-}
+
+ static enum nss_status
+ internal_setgrent (char *domainname, intern_t *intern)
+@@ -85,41 +45,72 @@ internal_setgrent (char *domainname, int
+ struct ypall_callback ypcb;
+ enum nss_status status;
+
+- intern->start = NULL;
+-
+- ypcb.foreach = saveit;
++ ypcb.foreach = _nis_saveit;
+ ypcb.data = (char *) intern;
+ status = yperr2nss (yp_all (domainname, "group.byname", &ypcb));
++
++ /* Mark the last buffer as full. */
++ if (intern->next != NULL)
++ intern->next->size = intern->offset;
++
+ intern->next = intern->start;
++ intern->offset = 0;
+
+ return status;
+ }
+
++
+ static enum nss_status
+ internal_getgrent_r (struct group *grp, char *buffer, size_t buflen,
+ int *errnop, intern_t *intern)
+ {
+- struct parser_data *data = (void *) buffer;
+- int parse_res;
+- char *p;
+-
+ if (intern->start == NULL)
+ return NSS_STATUS_NOTFOUND;
+
+ /* Get the next entry until we found a correct one. */
++ int parse_res;
+ do
+ {
+- if (intern->next == NULL)
+- return NSS_STATUS_NOTFOUND;
++ struct response_t *bucket = intern->next;
++
++ if (__builtin_expect (intern->offset >= bucket->size, 0))
++ {
++ if (bucket->next == NULL)
++ return NSS_STATUS_NOTFOUND;
++
++ /* We look at all the content in the current bucket. Go on
++ to the next. */
++ bucket = intern->next = bucket->next;
++ intern->offset = 0;
++ }
+
+- p = strncpy (buffer, intern->next->val, buflen);
+- while (isspace (*p))
+- ++p;
++ char *p;
++ for (p = &bucket->mem[intern->offset]; isspace (*p); ++p)
++ ++intern->offset;
+
+- parse_res = _nss_files_parse_grent (p, grp, data, buflen, errnop);
+- if (parse_res == -1)
++ size_t len = strlen (p) + 1;
++ if (__builtin_expect (len > buflen, 0))
++ {
++ *errnop = ERANGE;
++ return NSS_STATUS_TRYAGAIN;
++ }
++
++ /* We unfortunately have to copy the data in the user-provided
++ buffer because that buffer might be around for a very long
++ time and the servent structure must remain valid. If we would
++ rely on the BUCKET memory the next 'setservent' or 'endservent'
++ call would destroy it.
++
++ The important thing is that it is a single NUL-terminated
++ string. This is what the parsing routine expects. */
++ p = memcpy (buffer, &bucket->mem[intern->offset], len);
++
++ parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen,
++ errnop);
++ if (__builtin_expect (parse_res == -1, 0))
+ return NSS_STATUS_TRYAGAIN;
+- intern->next = intern->next->next;
++
++ intern->offset += len;
+ }
+ while (!parse_res);
+
+@@ -166,13 +157,12 @@ initgroups_netid (uid_t uid, gid_t group
+ ssize_t keylen = snprintf (key, sizeof (key), "unix.%lu@%s",
+ (unsigned long int) uid, domainname);
+
+- enum nss_status retval;
+ char *result;
+ int reslen;
+- retval = yperr2nss (yp_match (domainname, "netid.byname", key, keylen,
+- &result, &reslen));
+- if (retval != NSS_STATUS_SUCCESS)
+- return retval;
++ int yperr = yp_match (domainname, "netid.byname", key, keylen, &result,
++ &reslen);
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
++ return yperr2nss (yperr);
+
+ /* Parse the result: following the colon is a comma separated list of
+ group IDs. */
+@@ -207,7 +197,6 @@ initgroups_netid (uid_t uid, gid_t group
+ if (*start == *size)
+ {
+ /* Need a bigger buffer. */
+- gid_t *newgroups;
+ long int newsize;
+
+ if (limit > 0 && *size == limit)
+@@ -219,7 +208,7 @@ initgroups_netid (uid_t uid, gid_t group
+ else
+ newsize = MIN (limit, 2 * *size);
+
+- newgroups = realloc (groups, newsize * sizeof (*groups));
++ gid_t *newgroups = realloc (groups, newsize * sizeof (*groups));
+ if (newgroups == NULL)
+ goto errout;
+ *groupsp = groups = newgroups;
+@@ -247,7 +236,7 @@ _nss_nis_initgroups_dyn (const char *use
+ return NSS_STATUS_UNAVAIL;
+
+ /* Check whether we are supposed to use the netid.byname map. */
+- if (_nis_default_nss () & NSS_FLAG_NETID_AUTHORITATIVE)
++ if (_nsl_default_nss () & NSS_FLAG_NETID_AUTHORITATIVE)
+ {
+ /* We need the user ID. */
+ uid_t uid;
+@@ -262,7 +251,7 @@ _nss_nis_initgroups_dyn (const char *use
+ size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
+ char *tmpbuf;
+ enum nss_status status;
+- intern_t intern = { NULL, NULL };
++ intern_t intern = { NULL, NULL, 0 };
+ gid_t *groups = *groupsp;
+
+ status = internal_setgrent (domainname, &intern);
+--- libc/nis/nss_nis/nis-netgrp.c 10 Sep 2005 03:19:20 -0000 1.14
++++ libc/nis/nss_nis/nis-netgrp.c 9 Apr 2006 02:08:28 -0000 1.15
+@@ -47,24 +47,25 @@ internal_nis_endnetgrent (struct __netgr
+ netgrp->cursor = NULL;
+ }
+
++
+ enum nss_status
+ _nss_nis_setnetgrent (const char *group, struct __netgrent *netgrp)
+ {
+- char *domain;
+ int len;
+ enum nss_status status;
+
+ status = NSS_STATUS_SUCCESS;
+
+- if (group == NULL || group[0] == '\0')
++ if (__builtin_expect (group == NULL || group[0] == '\0', 0))
+ return NSS_STATUS_UNAVAIL;
+
+- if (yp_get_default_domain (&domain))
++ char *domain;
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+ status = yperr2nss (yp_match (domain, "netgroup", group, strlen (group),
+ &netgrp->data, &len));
+- if (status == NSS_STATUS_SUCCESS)
++ if (__builtin_expect (status == NSS_STATUS_SUCCESS, 1))
+ {
+ /* Our implementation of yp_match already allocates a buffer
+ which is one byte larger than the value in LEN specifies
+@@ -90,6 +91,7 @@ _nss_nis_endnetgrent (struct __netgrent
+ return NSS_STATUS_SUCCESS;
+ }
+
++
+ enum nss_status
+ _nss_nis_getnetgrent_r (struct __netgrent *result, char *buffer, size_t buflen,
+ int *errnop)
+--- libc/nis/nss_nis/nis-network.c 16 Mar 2003 03:36:21 -0000 1.19
++++ libc/nis/nss_nis/nis-network.c 9 Apr 2006 02:08:28 -0000 1.20
+@@ -73,28 +73,32 @@ internal_nis_getnetent_r (struct netent
+ int *errnop, int *herrnop)
+ {
+ struct parser_data *data = (void *) buffer;
+- char *domain, *result, *outkey;
+- int len, keylen, parse_res;
+
+- if (yp_get_default_domain (&domain))
++ char *domain;
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+ /* Get the next entry until we found a correct one. */
++ int parse_res;
+ do
+ {
+- enum nss_status retval;
+- char *p;
++ char *result;
++ char *outkey;
++ int len;
++ int keylen;
++ int yperr;
+
+ if (new_start)
+- retval = yperr2nss (yp_first (domain, "networks.byname",
+- &outkey, &keylen, &result, &len));
++ yperr = yp_first (domain, "networks.byname", &outkey, &keylen, &result,
++ &len);
+ else
+- retval = yperr2nss ( yp_next (domain, "networks.byname",
+- oldkey, oldkeylen,
+- &outkey, &keylen, &result, &len));
++ yperr = yp_next (domain, "networks.byname", oldkey, oldkeylen, &outkey,
++ &keylen, &result, &len);
+
+- if (retval != NSS_STATUS_SUCCESS)
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+ {
++ enum nss_status retval = yperr2nss (yperr);
++
+ if (retval == NSS_STATUS_TRYAGAIN)
+ {
+ *herrnop = NETDB_INTERNAL;
+@@ -103,7 +107,7 @@ internal_nis_getnetent_r (struct netent
+ return retval;
+ }
+
+- if ((size_t) (len + 1) > buflen)
++ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+@@ -111,14 +115,14 @@ internal_nis_getnetent_r (struct netent
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- p = strncpy (buffer, result, len);
++ char *p = strncpy (buffer, result, len);
+ buffer[len] = '\0';
+ while (isspace (*p))
+ ++p;
+ free (result);
+
+ parse_res = _nss_files_parse_netent (p, net, data, buflen, errnop);
+- if (parse_res == -1)
++ if (__builtin_expect (parse_res == -1, 0))
+ {
+ free (outkey);
+ *herrnop = NETDB_INTERNAL;
+@@ -155,11 +159,6 @@ enum nss_status
+ _nss_nis_getnetbyname_r (const char *name, struct netent *net, char *buffer,
+ size_t buflen, int *errnop, int *herrnop)
+ {
+- enum nss_status retval;
+- struct parser_data *data = (void *) buffer;
+- char *domain, *result, *p;
+- int len, parse_res;
+-
+ if (name == NULL)
+ {
+ *errnop = EINVAL;
+@@ -167,33 +166,36 @@ _nss_nis_getnetbyname_r (const char *nam
+ return NSS_STATUS_UNAVAIL;
+ }
+
+- if (yp_get_default_domain (&domain))
++ char *domain;
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
++ struct parser_data *data = (void *) buffer;
+ if (buflen < sizeof *data + 1)
+ {
+ *herrnop = NETDB_INTERNAL;
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+- else
+- {
+- /* Convert name to lowercase. */
+- size_t namlen = strlen (name);
+- char name2[namlen + 1];
+- size_t i;
+-
+- for (i = 0; i < namlen; ++i)
+- name2[i] = _tolower (name[i]);
+- name2[i] = '\0';
+
+- retval = yperr2nss (yp_match (domain, "networks.byname", name2,
+- namlen, &result, &len));
+- }
++ /* Convert name to lowercase. */
++ size_t namlen = strlen (name);
++ char name2[namlen + 1];
++ size_t i;
++
++ for (i = 0; i < namlen; ++i)
++ name2[i] = _tolower (name[i]);
++ name2[i] = '\0';
+
++ char *result;
++ int len;
++ int yperr = yp_match (domain, "networks.byname", name2, namlen, &result,
++ &len);
+
+- if (retval != NSS_STATUS_SUCCESS)
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+ {
++ enum nss_status retval = yperr2nss (yperr);
++
+ if (retval == NSS_STATUS_TRYAGAIN)
+ {
+ *errnop = errno;
+@@ -202,7 +204,7 @@ _nss_nis_getnetbyname_r (const char *nam
+ return retval;
+ }
+
+- if ((size_t) (len + 1) > buflen)
++ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+@@ -210,15 +212,15 @@ _nss_nis_getnetbyname_r (const char *nam
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- p = strncpy (buffer, result, len);
++ char *p = strncpy (buffer, result, len);
+ buffer[len] = '\0';
+ while (isspace (*p))
+ ++p;
+ free (result);
+
+- parse_res = _nss_files_parse_netent (p, net, data, buflen, errnop);
++ int parse_res = _nss_files_parse_netent (p, net, data, buflen, errnop);
+
+- if (parse_res < 1)
++ if (__builtin_expect (parse_res < 1, 0))
+ {
+ *herrnop = NETDB_INTERNAL;
+ if (parse_res == -1)
+@@ -235,32 +237,26 @@ _nss_nis_getnetbyaddr_r (uint32_t addr,
+ char *buffer, size_t buflen, int *errnop,
+ int *herrnop)
+ {
+- struct parser_data *data = (void *) buffer;
+ char *domain;
+- char *result;
+- int len;
+- char buf[256];
+- int blen;
+- struct in_addr in;
+- char *p;
+-
+- if (yp_get_default_domain (&domain))
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+- in = inet_makeaddr (addr, 0);
+- strcpy (buf, inet_ntoa (in));
+- blen = strlen (buf);
++ struct in_addr in = inet_makeaddr (addr, 0);
++ char *buf = inet_ntoa (in);
++ size_t blen = strlen (buf);
+
+ while (1)
+ {
+- enum nss_status retval;
+- int parse_res;
++ char *result;
++ int len;
+
+- retval = yperr2nss (yp_match (domain, "networks.byaddr", buf,
+- strlen (buf), &result, &len));
++ int yperr = yp_match (domain, "networks.byaddr", buf, blen, &result,
++ &len);
+
+- if (retval != NSS_STATUS_SUCCESS)
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+ {
++ enum nss_status retval = yperr2nss (yperr);
++
+ if (retval == NSS_STATUS_NOTFOUND)
+ {
+ if (buf[blen - 2] == '.' && buf[blen - 1] == '0')
+@@ -282,7 +278,7 @@ _nss_nis_getnetbyaddr_r (uint32_t addr,
+ }
+ }
+
+- if ((size_t) (len + 1) > buflen)
++ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+@@ -290,15 +286,16 @@ _nss_nis_getnetbyaddr_r (uint32_t addr,
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- p = strncpy (buffer, result, len);
++ char *p = strncpy (buffer, result, len);
+ buffer[len] = '\0';
+ while (isspace (*p))
+ ++p;
+ free (result);
+
+- parse_res = _nss_files_parse_netent (p, net, data, buflen, errnop);
++ int parse_res = _nss_files_parse_netent (p, net, (void *) buffer,
++ buflen, errnop);
+
+- if (parse_res < 1)
++ if (__builtin_expect (parse_res < 1, 0))
+ {
+ *herrnop = NETDB_INTERNAL;
+ if (parse_res == -1)
+--- libc/nis/nss_nis/nis-proto.c 2 Apr 2004 15:09:32 -0000 1.21
++++ libc/nis/nss_nis/nis-proto.c 9 Apr 2006 02:08:28 -0000 1.22
+@@ -179,45 +179,46 @@ enum nss_status
+ _nss_nis_getprotobyname_r (const char *name, struct protoent *proto,
+ char *buffer, size_t buflen, int *errnop)
+ {
+- struct parser_data *data = (void *) buffer;
+- enum nss_status retval;
+- char *domain, *result, *p;
+- int len, parse_res;
+-
+ if (name == NULL)
+ {
+ *errnop = EINVAL;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+- if (yp_get_default_domain (&domain))
++ char *domain;
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+- retval = yperr2nss (yp_match (domain, "protocols.byname", name,
+- strlen (name), &result, &len));
++ char *result;
++ int len;
++ int yperr = yp_match (domain, "protocols.byname", name, strlen (name),
++ &result, &len);
+
+- if (retval != NSS_STATUS_SUCCESS)
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+ {
++ enum nss_status retval = yperr2nss (yperr);
++
+ if (retval == NSS_STATUS_TRYAGAIN)
+ *errnop = errno;
+ return retval;
+ }
+
+- if ((size_t) (len + 1) > buflen)
++ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- p = strncpy (buffer, result, len);
++ char *p = strncpy (buffer, result, len);
+ buffer[len] = '\0';
+ while (isspace (*p))
+ ++p;
+ free (result);
+
+- parse_res = _nss_files_parse_protoent (p, proto, data, buflen, errnop);
+- if (parse_res < 1)
++ int parse_res = _nss_files_parse_protoent (p, proto, (void *) buffer, buflen,
++ errnop);
++ if (__builtin_expect (parse_res < 1, 0))
+ {
+ if (parse_res == -1)
+ return NSS_STATUS_TRYAGAIN;
+@@ -231,42 +232,43 @@ enum nss_status
+ _nss_nis_getprotobynumber_r (int number, struct protoent *proto,
+ char *buffer, size_t buflen, int *errnop)
+ {
+- struct parser_data *data = (void *) buffer;
+- enum nss_status retval;
+- char *domain, *result, *p;
+- int len, nlen, parse_res;
+- char buf[32];
+-
+- if (yp_get_default_domain (&domain))
++ char *domain;
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+- nlen = sprintf (buf, "%d", number);
++ char buf[32];
++ int nlen = snprintf (buf, sizeof (buf), "%d", number);
+
+- retval = yperr2nss (yp_match (domain, "protocols.bynumber", buf,
+- nlen, &result, &len));
++ char *result;
++ int len;
++ int yperr = yp_match (domain, "protocols.bynumber", buf, nlen, &result,
++ &len);
+
+- if (retval != NSS_STATUS_SUCCESS)
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+ {
++ enum nss_status retval = yperr2nss (yperr);
++
+ if (retval == NSS_STATUS_TRYAGAIN)
+ *errnop = errno;
+ return retval;
+ }
+
+- if ((size_t) (len + 1) > buflen)
++ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- p = strncpy (buffer, result, len);
++ char *p = strncpy (buffer, result, len);
+ buffer[len] = '\0';
+ while (isspace (*p))
+ ++p;
+ free (result);
+
+- parse_res = _nss_files_parse_protoent (p, proto, data, buflen, errnop);
+- if (parse_res < 1)
++ int parse_res = _nss_files_parse_protoent (p, proto, (void *) buffer, buflen,
++ errnop);
++ if (__builtin_expect (parse_res < 1, 0))
+ {
+ if (parse_res == -1)
+ return NSS_STATUS_TRYAGAIN;
+--- libc/nis/nss_nis/nis-publickey.c 6 Apr 2006 23:22:40 -0000 1.16
++++ libc/nis/nss_nis/nis-publickey.c 9 Apr 2006 02:08:28 -0000 1.17
+@@ -36,10 +36,6 @@ extern int xdecrypt (char *, char *);
+ enum nss_status
+ _nss_nis_getpublickey (const char *netname, char *pkey, int *errnop)
+ {
+- enum nss_status retval;
+- char *domain, *result;
+- int len;
+-
+ pkey[0] = 0;
+
+ if (netname == NULL)
+@@ -48,19 +44,23 @@ _nss_nis_getpublickey (const char *netna
+ return NSS_STATUS_UNAVAIL;
+ }
+
+- domain = strchr (netname, '@');
+- if (!domain)
++ char *domain = strchr (netname, '@');
++ if (domain == NULL)
+ {
+ *errnop = EINVAL;
+ return NSS_STATUS_UNAVAIL;
+ }
+ ++domain;
+
+- retval = yperr2nss (yp_match (domain, "publickey.byname", netname,
+- strlen (netname), &result, &len));
++ char *result;
++ int len;
++ int yperr = yp_match (domain, "publickey.byname", netname, strlen (netname),
++ &result, &len);
+
+- if (retval != NSS_STATUS_SUCCESS)
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+ {
++ enum nss_status retval = yperr2nss (yperr);
++
+ if (retval == NSS_STATUS_TRYAGAIN)
+ *errnop = errno;
+ return retval;
+@@ -82,11 +82,6 @@ enum nss_status
+ _nss_nis_getsecretkey (const char *netname, char *skey, char *passwd,
+ int *errnop)
+ {
+- enum nss_status retval;
+- char buf[2 * (HEXKEYBYTES + 1)];
+- char *domain, *result;
+- int len;
+-
+ skey[0] = 0;
+
+ if (netname == NULL || passwd == NULL)
+@@ -95,19 +90,23 @@ _nss_nis_getsecretkey (const char *netna
+ return NSS_STATUS_UNAVAIL;
+ }
+
+- domain = strchr (netname, '@');
+- if (!domain)
++ char *domain = strchr (netname, '@');
++ if (domain == NULL)
+ {
+ *errnop = EINVAL;
+ return NSS_STATUS_UNAVAIL;
+ }
+ ++domain;
+
+- retval = yperr2nss (yp_match (domain, "publickey.byname", netname,
+- strlen (netname), &result, &len));
++ char *result;
++ int len;
++ int yperr = yp_match (domain, "publickey.byname", netname, strlen (netname),
++ &result, &len);
+
+- if (retval != NSS_STATUS_SUCCESS)
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+ {
++ enum nss_status retval = yperr2nss (yperr);
++
+ if (retval == NSS_STATUS_TRYAGAIN)
+ *errnop = errno;
+ return retval;
+@@ -118,6 +117,8 @@ _nss_nis_getsecretkey (const char *netna
+ char *p = strchr (result, ':');
+ if (p != NULL)
+ {
++ char buf[2 * (HEXKEYBYTES + 1)];
++
+ ++p;
+ strncpy (buf, p, 2 * (HEXKEYBYTES + 1));
+ buf[2 * HEXKEYBYTES + 1] = '\0';
+@@ -195,13 +196,8 @@ enum nss_status
+ _nss_nis_netname2user (char netname[MAXNETNAMELEN + 1], uid_t *uidp,
+ gid_t *gidp, int *gidlenp, gid_t *gidlist, int *errnop)
+ {
+- char *domain;
+- int yperr;
+- char *lookup;
+- int len;
+-
+- domain = strchr (netname, '@');
+- if (!domain)
++ char *domain = strchr (netname, '@');
++ if (domain == NULL)
+ {
+ *errnop = EINVAL;
+ return NSS_STATUS_UNAVAIL;
+@@ -209,9 +205,10 @@ _nss_nis_netname2user (char netname[MAXN
+
+ /* Point past the '@' character */
+ ++domain;
+- lookup = NULL;
+- yperr = yp_match (domain, "netid.byname", netname, strlen (netname),
+- &lookup, &len);
++ char *lookup = NULL;
++ int len;
++ int yperr = yp_match (domain, "netid.byname", netname, strlen (netname),
++ &lookup, &len);
+ switch (yperr)
+ {
+ case YPERR_SUCCESS:
+@@ -224,17 +221,15 @@ _nss_nis_netname2user (char netname[MAXN
+ return NSS_STATUS_UNAVAIL;
+ }
+
+- if (lookup)
+- {
+- enum nss_status err;
+-
+- lookup[len] = '\0';
+- err = parse_netid_str (lookup, uidp, gidp, gidlenp, gidlist);
+- free (lookup);
+- return err;
+- }
+- else
++ if (lookup == NULL)
+ return NSS_STATUS_NOTFOUND;
+
+- return NSS_STATUS_SUCCESS;
++
++ lookup[len] = '\0';
++
++ enum nss_status err = parse_netid_str (lookup, uidp, gidp, gidlenp, gidlist);
++
++ free (lookup);
++
++ return err;
+ }
+--- libc/nis/nss_nis/nis-pwd.c 19 Jan 2003 19:09:10 -0000 1.18
++++ libc/nis/nss_nis/nis-pwd.c 1 May 2006 22:31:15 -0000 1.21
+@@ -17,20 +17,18 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+-#include <nss.h>
+-/* The following is an ugly trick to avoid a prototype declaration for
+- _nss_nis_endpwent. */
+-#define _nss_nis_endpwent _nss_nis_endpwent_XXX
+-#include <pwd.h>
+-#undef _nss_nis_endpwent
++#include <assert.h>
+ #include <ctype.h>
+ #include <errno.h>
++#include <nss.h>
++#include <pwd.h>
+ #include <string.h>
+ #include <bits/libc-lock.h>
+ #include <rpcsvc/yp.h>
+ #include <rpcsvc/ypclnt.h>
+
+ #include "nss-nis.h"
++#include <libnsl.h>
+
+ /* Get the declaration of the parser function. */
+ #define ENTNAME pwent
+@@ -44,12 +42,72 @@ __libc_lock_define_initialized (static,
+ static bool_t new_start = 1;
+ static char *oldkey;
+ static int oldkeylen;
++static intern_t intern;
+
+-enum nss_status
+-_nss_nis_setpwent (int stayopen)
++
++int
++_nis_saveit (int instatus, char *inkey, int inkeylen, char *inval,
++ int invallen, char *indata)
+ {
+- __libc_lock_lock (lock);
++ intern_t *intern = (intern_t *) indata;
++
++ if (instatus != YP_TRUE)
++ return 1;
++
++ if (inkey && inkeylen > 0 && inval && invallen > 0)
++ {
++ struct response_t *bucket = intern->next;
+
++ if (__builtin_expect (bucket == NULL, 0))
++ {
++#define MINSIZE 4096 - 4 * sizeof (void *)
++ const size_t minsize = MAX (MINSIZE, 2 * (invallen + 1));
++ bucket = malloc (sizeof (struct response_t) + minsize);
++ if (bucket == NULL)
++ /* We have no error code for out of memory. */
++ return 1;
++
++ bucket->next = NULL;
++ bucket->size = minsize;
++ intern->start = intern->next = bucket;
++ intern->offset = 0;
++ }
++ else if (__builtin_expect (invallen + 1 > bucket->size - intern->offset,
++ 0))
++ {
++ /* We need a new (larger) buffer. */
++ const size_t newsize = 2 * MAX (bucket->size, invallen + 1);
++ struct response_t *newp = malloc (sizeof (struct response_t)
++ + newsize);
++ if (newp == NULL)
++ /* We have no error code for out of memory. */
++ return 1;
++
++ /* Mark the old bucket as full. */
++ bucket->size = intern->offset;
++
++ newp->next = NULL;
++ newp->size = newsize;
++ bucket = intern->next = bucket->next = newp;
++ intern->offset = 0;
++ }
++
++ char *p = mempcpy (&bucket->mem[intern->offset], inval, invallen);
++ if (__builtin_expect (p[-1] != '\0', 0))
++ {
++ *p = '\0';
++ ++invallen;
++ }
++ intern->offset += invallen;
++ }
++
++ return 0;
++}
++
++
++static void
++internal_nis_endpwent (void)
++{
+ new_start = 1;
+ if (oldkey != NULL)
+ {
+@@ -58,52 +116,159 @@ _nss_nis_setpwent (int stayopen)
+ oldkeylen = 0;
+ }
+
++ struct response_t *curr = intern.next;
++
++ while (curr != NULL)
++ {
++ struct response_t *last = curr;
++ curr = curr->next;
++ free (last);
++ }
++
++ intern.next = intern.start = NULL;
++}
++
++
++enum nss_status
++_nss_nis_endpwent (void)
++{
++ __libc_lock_lock (lock);
++
++ internal_nis_endpwent ();
++
+ __libc_lock_unlock (lock);
+
+ return NSS_STATUS_SUCCESS;
+ }
+-/* Make _nss_nis_endpwent an alias of _nss_nis_setpwent. We do this
+- even though the prototypes don't match. The argument of setpwent
+- is not used so this makes no difference. */
+-strong_alias (_nss_nis_setpwent, _nss_nis_endpwent)
++
++
++enum nss_status
++internal_nis_setpwent (void)
++{
++ /* We have to read all the data now. */
++ char *domain;
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
++ return NSS_STATUS_UNAVAIL;
++
++ struct ypall_callback ypcb;
++
++ ypcb.foreach = _nis_saveit;
++ ypcb.data = (char *) &intern;
++ enum nss_status status = yperr2nss (yp_all (domain, "passwd.byname", &ypcb));
++
++
++ /* Mark the last buffer as full. */
++ if (intern.next != NULL)
++ intern.next->size = intern.offset;
++
++ intern.next = intern.start;
++ intern.offset = 0;
++
++ return status;
++}
++
++
++enum nss_status
++_nss_nis_setpwent (int stayopen)
++{
++ enum nss_status result = NSS_STATUS_SUCCESS;
++
++ __libc_lock_lock (lock);
++
++ internal_nis_endpwent ();
++
++ if (_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ)
++ result = internal_nis_setpwent ();
++
++ __libc_lock_unlock (lock);
++
++ return result;
++}
++
+
+ static enum nss_status
+ internal_nis_getpwent_r (struct passwd *pwd, char *buffer, size_t buflen,
+ int *errnop)
+ {
+- struct parser_data *data = (void *) buffer;
+- char *domain;
+- int parse_res;
++ /* If we read the entire database at setpwent time we just iterate
++ over the data we have in memory. */
++ bool batch_read = intern.start != NULL;
+
+- if (yp_get_default_domain (&domain))
++ char *domain = NULL;
++ if (!batch_read && __builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+ /* Get the next entry until we found a correct one. */
++ int parse_res;
+ do
+ {
+- enum nss_status retval;
+- char *result, *outkey, *result2, *p;
+- int len, keylen, len2;
+- size_t namelen;
++ char *result;
++ char *outkey;
++ int len;
++ int keylen;
+
+- if (new_start)
+- retval = yperr2nss (yp_first (domain, "passwd.byname",
+- &outkey, &keylen, &result, &len));
++ if (batch_read)
++ {
++ struct response_t *bucket;
++
++ handle_batch_read:
++ bucket = intern.next;
++
++ if (__builtin_expect (intern.offset >= bucket->size, 0))
++ {
++ if (bucket->next == NULL)
++ return NSS_STATUS_NOTFOUND;
++
++ /* We look at all the content in the current bucket. Go on
++ to the next. */
++ bucket = intern.next = bucket->next;
++ intern.offset = 0;
++ }
++
++ for (result = &bucket->mem[intern.offset]; isspace (*result);
++ ++result)
++ ++intern.offset;
++
++ len = strlen (result);
++ }
+ else
+- retval = yperr2nss ( yp_next (domain, "passwd.byname",
+- oldkey, oldkeylen,
+- &outkey, &keylen, &result, &len));
+-
+- if (retval != NSS_STATUS_SUCCESS)
+- {
+- if (retval == NSS_STATUS_TRYAGAIN)
+- *errnop = errno;
+- return retval;
+- }
++ {
++ int yperr;
++
++ if (new_start)
++ {
++ /* Maybe we should read the database in one piece. */
++ if ((_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ)
++ && internal_nis_setpwent () == NSS_STATUS_SUCCESS
++ && intern.start != NULL)
++ {
++ batch_read = true;
++ goto handle_batch_read;
++ }
++
++ yperr = yp_first (domain, "passwd.byname", &outkey, &keylen,
++ &result, &len);
++ }
++ else
++ yperr = yp_next (domain, "passwd.byname", oldkey, oldkeylen,
++ &outkey, &keylen, &result, &len);
++
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
++ {
++ enum nss_status retval = yperr2nss (yperr);
++
++ if (retval == NSS_STATUS_TRYAGAIN)
++ *errnop = errno;
++ return retval;
++ }
++ }
+
+ /* Check for adjunct style secret passwords. They can be
+ recognized by a password starting with "##". */
+- p = strchr (result, ':');
++ char *p = strchr (result, ':');
++ size_t namelen;
++ char *result2;
++ int len2;
+ if (p != NULL /* This better should be true in all cases. */
+ && p[1] == '#' && p[2] == '#'
+ && (namelen = p - result,
+@@ -128,7 +293,8 @@ internal_nis_getpwent_r (struct passwd *
+ }
+
+ restlen = len - (p - result);
+- if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen)
++ if (__builtin_expect ((size_t) (namelen + (endp - encrypted)
++ + restlen + 2) > buflen, 0))
+ {
+ free (result2);
+ free (result);
+@@ -136,10 +302,10 @@ internal_nis_getpwent_r (struct passwd *
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- __mempcpy (__mempcpy (__mempcpy (__mempcpy (buffer, result, namelen),
+- ":", 1),
+- encrypted, endp - encrypted),
+- p, restlen + 1);
++ mempcpy (mempcpy (mempcpy (mempcpy (buffer, result, namelen),
++ ":", 1),
++ encrypted, endp - encrypted),
++ p, restlen + 1);
+ p = buffer;
+
+ free (result2);
+@@ -147,33 +313,41 @@ internal_nis_getpwent_r (struct passwd *
+ else
+ {
+ non_adjunct:
+- if ((size_t) (len + 1) > buflen)
++ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- p = strncpy (buffer, result, len);
+- buffer[len] = '\0';
++ p = buffer;
++ *((char *) mempcpy (buffer, result, len)) = '\0';
+ }
+
+ while (isspace (*p))
+ ++p;
+- free (result);
++ if (!batch_read)
++ free (result);
+
+- parse_res = _nss_files_parse_pwent (p, pwd, data, buflen, errnop);
+- if (parse_res == -1)
++ parse_res = _nss_files_parse_pwent (p, pwd, (void *) buffer, buflen,
++ errnop);
++ if (__builtin_expect (parse_res == -1, 0))
+ {
+- free (outkey);
++ if (!batch_read)
++ free (outkey);
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- free (oldkey);
+- oldkey = outkey;
+- oldkeylen = keylen;
+- new_start = 0;
++ if (batch_read)
++ intern.offset += len + 1;
++ else
++ {
++ free (oldkey);
++ oldkey = outkey;
++ oldkeylen = keylen;
++ new_start = 0;
++ }
+ }
+ while (parse_res < 1);
+
+@@ -199,28 +373,26 @@ enum nss_status
+ _nss_nis_getpwnam_r (const char *name, struct passwd *pwd,
+ char *buffer, size_t buflen, int *errnop)
+ {
+- struct parser_data *data = (void *) buffer;
+- enum nss_status retval;
+- char *domain, *result, *result2, *p;
+- int len, len2, parse_res;
+- size_t namelen;
+-
+ if (name == NULL)
+ {
+ *errnop = EINVAL;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+- if (yp_get_default_domain (&domain))
++ char *domain;
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+- namelen = strlen (name);
++ size_t namelen = strlen (name);
+
+- retval = yperr2nss (yp_match (domain, "passwd.byname", name,
+- namelen, &result, &len));
++ char *result;
++ int len;
++ int yperr = yp_match (domain, "passwd.byname", name, namelen, &result, &len);
+
+- if (retval != NSS_STATUS_SUCCESS)
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+ {
++ enum nss_status retval = yperr2nss (yperr);
++
+ if (retval == NSS_STATUS_TRYAGAIN)
+ *errnop = errno;
+ return retval;
+@@ -228,7 +400,9 @@ _nss_nis_getpwnam_r (const char *name, s
+
+ /* Check for adjunct style secret passwords. They can be recognized
+ by a password starting with "##". */
+- p = strchr (result, ':');
++ char *result2;
++ int len2;
++ char *p = strchr (result, ':');
+ if (p != NULL /* This better should be true in all cases. */
+ && p[1] == '#' && p[2] == '#'
+ && yp_match (domain, "passwd.adjunct.byname", name, namelen,
+@@ -238,7 +412,6 @@ _nss_nis_getpwnam_r (const char *name, s
+ therein into original result. */
+ char *encrypted = strchr (result2, ':');
+ char *endp;
+- size_t restlen;
+
+ if (encrypted == NULL
+ || (endp = strchr (++encrypted, ':')) == NULL
+@@ -251,8 +424,9 @@ _nss_nis_getpwnam_r (const char *name, s
+ goto non_adjunct;
+ }
+
+- restlen = len - (p - result);
+- if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen)
++ size_t restlen = len - (p - result);
++ if (__builtin_expect ((size_t) (namelen + (endp - encrypted)
++ + restlen + 2) > buflen, 0))
+ {
+ free (result2);
+ free (result);
+@@ -271,7 +445,7 @@ _nss_nis_getpwnam_r (const char *name, s
+ else
+ {
+ non_adjunct:
+- if ((size_t) (len + 1) > buflen)
++ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+@@ -286,8 +460,9 @@ _nss_nis_getpwnam_r (const char *name, s
+ ++p;
+ free (result);
+
+- parse_res = _nss_files_parse_pwent (p, pwd, data, buflen, errnop);
+- if (parse_res < 1)
++ int parse_res = _nss_files_parse_pwent (p, pwd, (void *) buffer, buflen,
++ errnop);
++ if (__builtin_expect (parse_res < 1, 0))
+ {
+ if (parse_res == -1)
+ return NSS_STATUS_TRYAGAIN;
+@@ -302,23 +477,21 @@ enum nss_status
+ _nss_nis_getpwuid_r (uid_t uid, struct passwd *pwd,
+ char *buffer, size_t buflen, int *errnop)
+ {
+- struct parser_data *data = (void *) buffer;
+- enum nss_status retval;
+- char *domain, *result, *p, *result2;
+- int len, nlen, parse_res, len2;
+- char buf[32];
+- size_t namelen;
+-
+- if (yp_get_default_domain (&domain))
++ char *domain;
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+- nlen = sprintf (buf, "%lu", (unsigned long int) uid);
++ char buf[32];
++ int nlen = snprintf (buf, sizeof (buf), "%lu", (unsigned long int) uid);
+
+- retval = yperr2nss (yp_match (domain, "passwd.byuid", buf,
+- nlen, &result, &len));
++ char *result;
++ int len;
++ int yperr = yp_match (domain, "passwd.byuid", buf, nlen, &result, &len);
+
+- if (retval != NSS_STATUS_SUCCESS)
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+ {
++ enum nss_status retval = yperr2nss (yperr);
++
+ if (retval == NSS_STATUS_TRYAGAIN)
+ *errnop = errno;
+ return retval;
+@@ -326,7 +499,10 @@ _nss_nis_getpwuid_r (uid_t uid, struct p
+
+ /* Check for adjunct style secret passwords. They can be recognized
+ by a password starting with "##". */
+- p = strchr (result, ':');
++ char *result2;
++ int len2;
++ size_t namelen;
++ char *p = strchr (result, ':');
+ if (p != NULL /* This better should be true in all cases. */
+ && p[1] == '#' && p[2] == '#'
+ && (namelen = p - result,
+@@ -351,7 +527,8 @@ _nss_nis_getpwuid_r (uid_t uid, struct p
+ }
+
+ restlen = len - (p - result);
+- if ((size_t) (namelen + (endp - encrypted) + restlen + 2) > buflen)
++ if (__builtin_expect ((size_t) (namelen + (endp - encrypted)
++ + restlen + 2) > buflen, 0))
+ {
+ free (result2);
+ free (result);
+@@ -370,7 +547,7 @@ _nss_nis_getpwuid_r (uid_t uid, struct p
+ else
+ {
+ non_adjunct:
+- if ((size_t) (len + 1) > buflen)
++ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+@@ -385,8 +562,9 @@ _nss_nis_getpwuid_r (uid_t uid, struct p
+ ++p;
+ free (result);
+
+- parse_res = _nss_files_parse_pwent (p, pwd, data, buflen, errnop);
+- if (parse_res < 1)
++ int parse_res = _nss_files_parse_pwent (p, pwd, (void *) buffer, buflen,
++ errnop);
++ if (__builtin_expect (parse_res < 1, 0))
+ {
+ if (parse_res == -1)
+ return NSS_STATUS_TRYAGAIN;
+--- libc/nis/nss_nis/nis-rpc.c 2 Apr 2004 15:09:32 -0000 1.19
++++ libc/nis/nss_nis/nis-rpc.c 29 Apr 2006 01:12:53 -0000 1.21
+@@ -35,59 +36,22 @@
+
+ __libc_lock_define_initialized (static, lock)
+
+-struct response_t
+-{
+- struct response_t *next;
+- char val[0];
+-};
+-
+-struct intern_t
+-{
+- struct response_t *start;
+- struct response_t *next;
+-};
+-typedef struct intern_t intern_t;
+-
+-static intern_t intern = {NULL, NULL};
+-
+-static int
+-saveit (int instatus, char *inkey, int inkeylen, char *inval,
+- int invallen, char *indata)
+-{
+- intern_t *intern = (intern_t *)indata;
+-
+- if (instatus != YP_TRUE)
+- return 1;
++static intern_t intern;
+
+- if (inkey && inkeylen > 0 && inval && invallen > 0)
+- {
+- struct response_t *newp = malloc (sizeof (struct response_t)
+- + invallen + 1);
+- if (newp == NULL)
+- return 1; /* We have no error code for out of memory */
+-
+- if (intern->start == NULL)
+- intern->start = newp;
+- else
+- intern->next->next = newp;
+- intern->next = newp;
+-
+- newp->next = NULL;
+- *((char *) mempcpy (newp->val, inval, invallen)) = '\0';
+- }
+-
+- return 0;
+-}
+
+ static void
+ internal_nis_endrpcent (intern_t *intern)
+ {
+- while (intern->start != NULL)
++ struct response_t *curr = intern->next;
++
++ while (curr != NULL)
+ {
+- intern->next = intern->start;
+- intern->start = intern->start->next;
+- free (intern->next);
++ struct response_t *last = curr;
++ curr = curr->next;
++ free (last);
+ }
++
++ intern->next = intern->start = NULL;
+ }
+
+ static enum nss_status
+@@ -102,10 +66,16 @@ internal_nis_setrpcent (intern_t *intern
+
+ internal_nis_endrpcent (intern);
+
+- ypcb.foreach = saveit;
+- ypcb.data = (char *)intern;
+- status = yperr2nss (yp_all(domainname, "rpc.bynumber", &ypcb));
++ ypcb.foreach = _nis_saveit;
++ ypcb.data = (char *) intern;
++ status = yperr2nss (yp_all (domainname, "rpc.bynumber", &ypcb));
++
++ /* Mark the last buffer as full. */
++ if (intern->next != NULL)
++ intern->next->size = intern->offset;
++
+ intern->next = intern->start;
++ intern->offset = 0;
+
+ return status;
+ }
+@@ -138,29 +108,56 @@ _nss_nis_endrpcent (void)
+
+ static enum nss_status
+ internal_nis_getrpcent_r (struct rpcent *rpc, char *buffer, size_t buflen,
+- int *errnop, intern_t *data)
++ int *errnop, intern_t *intern)
+ {
+ struct parser_data *pdata = (void *) buffer;
+ int parse_res;
+ char *p;
+
+- if (data->start == NULL)
+- internal_nis_setrpcent (data);
++ if (intern->start == NULL)
++ internal_nis_setrpcent (intern);
+
+ /* Get the next entry until we found a correct one. */
+ do
+ {
+- if (data->next == NULL)
+- return NSS_STATUS_NOTFOUND;
++ struct response_t *bucket = intern->next;
++
++ if (__builtin_expect (intern->offset >= bucket->size, 0))
++ {
++ if (bucket->next == NULL)
++ return NSS_STATUS_NOTFOUND;
+
+- p = strncpy (buffer, data->next->val, buflen);
+- while (isspace (*p))
+- ++p;
++ /* We look at all the content in the current bucket. Go on
++ to the next. */
++ bucket = intern->next = bucket->next;
++ intern->offset = 0;
++ }
++
++ for (p = &bucket->mem[intern->offset]; isspace (*p); ++p)
++ ++intern->offset;
++
++ size_t len = strlen (p) + 1;
++ if (__builtin_expect (len > buflen, 0))
++ {
++ *errnop = ERANGE;
++ return NSS_STATUS_TRYAGAIN;
++ }
++
++ /* We unfortunately have to copy the data in the user-provided
++ buffer because that buffer might be around for a very long
++ time and the servent structure must remain valid. If we would
++ rely on the BUCKET memory the next 'setservent' or 'endservent'
++ call would destroy it.
++
++ The important thing is that it is a single NUL-terminated
++ string. This is what the parsing routine expects. */
++ p = memcpy (buffer, &bucket->mem[intern->offset], len);
+
+ parse_res = _nss_files_parse_rpcent (p, rpc, pdata, buflen, errnop);
+- if (parse_res == -1)
++ if (__builtin_expect (parse_res == -1, 0))
+ return NSS_STATUS_TRYAGAIN;
+- data->next = data->next->next;
++
++ intern->offset += len;
+ }
+ while (!parse_res);
+
+@@ -186,21 +183,18 @@ enum nss_status
+ _nss_nis_getrpcbyname_r (const char *name, struct rpcent *rpc,
+ char *buffer, size_t buflen, int *errnop)
+ {
+- intern_t data = {NULL, NULL};
+- enum nss_status status;
+- int found;
+-
+ if (name == NULL)
+ {
+ *errnop = EINVAL;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+- status = internal_nis_setrpcent (&data);
+- if (status != NSS_STATUS_SUCCESS)
++ intern_t data = { NULL, NULL, 0 };
++ enum nss_status status = internal_nis_setrpcent (&data);
++ if (__builtin_expect (status != NSS_STATUS_SUCCESS, 0))
+ return status;
+
+- found = 0;
++ int found = 0;
+ while (!found &&
+ ((status = internal_nis_getrpcent_r (rpc, buffer, buflen, errnop,
+ &data)) == NSS_STATUS_SUCCESS))
+@@ -226,53 +220,52 @@ _nss_nis_getrpcbyname_r (const char *nam
+
+ internal_nis_endrpcent (&data);
+
+- if (!found && status == NSS_STATUS_SUCCESS)
++ if (__builtin_expect (!found && status == NSS_STATUS_SUCCESS, 0))
+ return NSS_STATUS_NOTFOUND;
+- else
+- return status;
++
++ return status;
+ }
+
+ enum nss_status
+ _nss_nis_getrpcbynumber_r (int number, struct rpcent *rpc,
+ char *buffer, size_t buflen, int *errnop)
+ {
+- struct parser_data *data = (void *) buffer;
+- enum nss_status retval;
+- char *domain, *result, *p;
+- int len, nlen, parse_res;
+- char buf[32];
+-
+- if (yp_get_default_domain (&domain))
++ char *domain;
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+- nlen = sprintf (buf, "%d", number);
++ char buf[32];
++ int nlen = snprintf (buf, sizeof (buf), "%d", number);
+
+- retval = yperr2nss (yp_match (domain, "rpc.bynumber", buf,
+- nlen, &result, &len));
++ char *result;
++ int len;
++ int yperr = yp_match (domain, "rpc.bynumber", buf, nlen, &result, &len);
+
+- if (retval != NSS_STATUS_SUCCESS)
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+ {
++ enum nss_status retval = yperr2nss (yperr);
++
+ if (retval == NSS_STATUS_TRYAGAIN)
+ *errnop = errno;
+ return retval;
+ }
+
+- if ((size_t) (len + 1) > buflen)
++ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- p = strncpy (buffer, result, len);
++ char *p = strncpy (buffer, result, len);
+ buffer[len] = '\0';
+ while (isspace (*p))
+ ++p;
+ free (result);
+
+- parse_res = _nss_files_parse_rpcent (p, rpc, data, buflen, errnop);
+-
+- if (parse_res < 1)
++ int parse_res = _nss_files_parse_rpcent (p, rpc, (void *) buffer, buflen,
++ errnop);
++ if (__builtin_expect (parse_res < 1, 0))
+ {
+ if (parse_res == -1)
+ return NSS_STATUS_TRYAGAIN;
+--- libc/nis/nss_nis/nis-service.c 2 Apr 2004 15:09:32 -0000 1.27
++++ libc/nis/nss_nis/nis-service.c 29 Apr 2006 01:11:05 -0000 1.33
+@@ -27,6 +27,7 @@
+ #include <rpcsvc/ypclnt.h>
+
+ #include "nss-nis.h"
++#include <libnsl.h>
+
+
+ /* Get the declaration of the parser function. */
+@@ -36,20 +37,7 @@
+
+ __libc_lock_define_initialized (static, lock)
+
+-struct response_t
+-{
+- struct response_t *next;
+- char val[0];
+-};
+-
+-struct intern_t
+-{
+- struct response_t *start;
+- struct response_t *next;
+-};
+-typedef struct intern_t intern_t;
+-
+-static intern_t intern = { NULL, NULL };
++static intern_t intern;
+
+ struct search_t
+ {
+@@ -64,63 +52,31 @@ struct search_t
+ };
+
+ static int
+-saveit (int instatus, char *inkey, int inkeylen, char *inval,
+- int invallen, char *indata)
+-{
+- intern_t *intern = (intern_t *) indata;
+-
+- if (instatus != YP_TRUE)
+- return 1;
+-
+- if (inkey && inkeylen > 0 && inval && invallen > 0)
+- {
+- struct response_t *newp = malloc (sizeof (struct response_t)
+- + invallen + 1);
+- if (newp == NULL)
+- return 1; /* We have no error code for out of memory */
+-
+- if (intern->start == NULL)
+- intern->start = newp;
+- else
+- intern->next->next = newp;
+- intern->next = newp;
+-
+- newp->next = NULL;
+- *((char *) mempcpy (newp->val, inval, invallen)) = '\0';
+- }
+-
+- return 0;
+-}
+-
+-static int
+ dosearch (int instatus, char *inkey, int inkeylen, char *inval,
+ int invallen, char *indata)
+ {
+ struct search_t *req = (struct search_t *) indata;
+
+- if (instatus != YP_TRUE)
++ if (__builtin_expect (instatus != YP_TRUE, 0))
+ return 1;
+
+ if (inkey && inkeylen > 0 && inval && invallen > 0)
+ {
+- struct parser_data *pdata = (void *) req->buffer;
+- int parse_res;
+- char *p;
+-
+- if ((size_t) (invallen + 1) > req->buflen)
++ if (__builtin_expect ((size_t) (invallen + 1) > req->buflen, 0))
+ {
+ *req->errnop = ERANGE;
+ req->status = NSS_STATUS_TRYAGAIN;
+ return 1;
+ }
+
+- p = strncpy (req->buffer, inval, invallen);
++ char *p = strncpy (req->buffer, inval, invallen);
+ req->buffer[invallen] = '\0';
+ while (isspace (*p))
+ ++p;
+
+- parse_res = _nss_files_parse_servent (p, req->serv, pdata, req->buflen,
+- req->errnop);
++ int parse_res = _nss_files_parse_servent (p, req->serv,
++ (void *) req->buffer,
++ req->buflen, req->errnop);
+ if (parse_res == -1)
+ {
+ req->status = NSS_STATUS_TRYAGAIN;
+@@ -154,35 +110,35 @@ dosearch (int instatus, char *inkey, int
+ return 0;
+ }
+
+-static enum nss_status
+-internal_nis_endservent (intern_t * intern)
++static void
++internal_nis_endservent (void)
+ {
+- while (intern->start != NULL)
++ struct response_t *curr = intern.next;
++
++ while (curr != NULL)
+ {
+- intern->next = intern->start;
+- intern->start = intern->start->next;
+- free (intern->next);
++ struct response_t *last = curr;
++ curr = curr->next;
++ free (last);
+ }
+
+- return NSS_STATUS_SUCCESS;
++ intern.next = intern.start = NULL;
+ }
+
+ enum nss_status
+ _nss_nis_endservent (void)
+ {
+- enum nss_status status;
+-
+ __libc_lock_lock (lock);
+
+- status = internal_nis_endservent (&intern);
++ internal_nis_endservent ();
+
+ __libc_lock_unlock (lock);
+
+- return status;
++ return NSS_STATUS_SUCCESS;
+ }
+
+ static enum nss_status
+-internal_nis_setservent (intern_t *intern)
++internal_nis_setservent (void)
+ {
+ char *domainname;
+ struct ypall_callback ypcb;
+@@ -191,12 +147,18 @@ internal_nis_setservent (intern_t *inter
+ if (yp_get_default_domain (&domainname))
+ return NSS_STATUS_UNAVAIL;
+
+- (void) internal_nis_endservent (intern);
++ internal_nis_endservent ();
+
+- ypcb.foreach = saveit;
+- ypcb.data = (char *) intern;
++ ypcb.foreach = _nis_saveit;
++ ypcb.data = (char *) &intern;
+ status = yperr2nss (yp_all (domainname, "services.byname", &ypcb));
+- intern->next = intern->start;
++
++ /* Mark the last buffer as full. */
++ if (intern.next != NULL)
++ intern.next->size = intern.offset;
++
++ intern.next = intern.start;
++ intern.offset = 0;
+
+ return status;
+ }
+@@ -208,7 +170,7 @@ _nss_nis_setservent (int stayopen)
+
+ __libc_lock_lock (lock);
+
+- status = internal_nis_setservent (&intern);
++ status = internal_nis_setservent ();
+
+ __libc_lock_unlock (lock);
+
+@@ -217,29 +179,56 @@ _nss_nis_setservent (int stayopen)
+
+ static enum nss_status
+ internal_nis_getservent_r (struct servent *serv, char *buffer,
+- size_t buflen, int *errnop, intern_t *data)
++ size_t buflen, int *errnop)
+ {
+ struct parser_data *pdata = (void *) buffer;
+ int parse_res;
+ char *p;
+
+- if (data->start == NULL)
+- internal_nis_setservent (data);
++ if (intern.start == NULL)
++ internal_nis_setservent ();
+
+- /* Get the next entry until we found a correct one. */
++ /* Get the next entry until we found a correct one. */
+ do
+ {
+- if (data->next == NULL)
+- return NSS_STATUS_NOTFOUND;
++ struct response_t *bucket = intern.next;
+
+- p = strncpy (buffer, data->next->val, buflen);
+- while (isspace (*p))
+- ++p;
++ if (__builtin_expect (intern.offset >= bucket->size, 0))
++ {
++ if (bucket->next == NULL)
++ return NSS_STATUS_NOTFOUND;
++
++ /* We look at all the content in the current bucket. Go on
++ to the next. */
++ bucket = intern.next = bucket->next;
++ intern.offset = 0;
++ }
++
++ for (p = &bucket->mem[intern.offset]; isspace (*p); ++p)
++ ++intern.offset;
++
++ size_t len = strlen (p) + 1;
++ if (__builtin_expect (len > buflen, 0))
++ {
++ *errnop = ERANGE;
++ return NSS_STATUS_TRYAGAIN;
++ }
++
++ /* We unfortunately have to copy the data in the user-provided
++ buffer because that buffer might be around for a very long
++ time and the servent structure must remain valid. If we would
++ rely on the BUCKET memory the next 'setservent' or 'endservent'
++ call would destroy it.
++
++ The important thing is that it is a single NUL-terminated
++ string. This is what the parsing routine expects. */
++ p = memcpy (buffer, &bucket->mem[intern.offset], len);
+
+ parse_res = _nss_files_parse_servent (p, serv, pdata, buflen, errnop);
+- if (parse_res == -1)
++ if (__builtin_expect (parse_res == -1, 0))
+ return NSS_STATUS_TRYAGAIN;
+- data->next = data->next->next;
++
++ intern.offset += len;
+ }
+ while (!parse_res);
+
+@@ -254,7 +243,7 @@ _nss_nis_getservent_r (struct servent *s
+
+ __libc_lock_lock (lock);
+
+- status = internal_nis_getservent_r (serv, buffer, buflen, errnop, &intern);
++ status = internal_nis_getservent_r (serv, buffer, buflen, errnop);
+
+ __libc_lock_unlock (lock);
+
+@@ -266,60 +255,56 @@ _nss_nis_getservbyname_r (const char *na
+ struct servent *serv, char *buffer, size_t buflen,
+ int *errnop)
+ {
+- enum nss_status status;
+- char *domain;
+-
+ if (name == NULL)
+ {
+ *errnop = EINVAL;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+- if (yp_get_default_domain (&domain))
++ char *domain;
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+ /* If the protocol is given, we could try if our NIS server knows
+ about services.byservicename map. If yes, we only need one query. */
+- char key[strlen (name) + (protocol ? strlen (protocol) : 0) + 2];
+- char *cp, *result;
+- size_t keylen, len;
+- int int_len;
++ size_t keylen = strlen (name) + 1 + (protocol ? strlen (protocol) : 0);
++ char key[keylen + 1];
+
+ /* key is: "name/proto" */
+- cp = stpcpy (key, name);
+- if (protocol)
++ char *cp = stpcpy (key, name);
++ if (protocol != NULL)
+ {
+ *cp++ = '/';
+ strcpy (cp, protocol);
+ }
+- keylen = strlen (key);
+- status = yperr2nss (yp_match (domain, "services.byservicename", key,
+- keylen, &result, &int_len));
+- len = int_len;
++
++ char *result;
++ int int_len;
++ enum nss_status status = yperr2nss (yp_match (domain,
++ "services.byservicename", key,
++ keylen, &result, &int_len));
++ size_t len = int_len;
+
+ /* If we found the key, it's ok and parse the result. If not,
+ fall through and parse the complete table. */
+- if (status == NSS_STATUS_SUCCESS)
++ if (__builtin_expect (status == NSS_STATUS_SUCCESS, 1))
+ {
+- struct parser_data *pdata = (void *) buffer;
+- int parse_res;
+- char *p;
+-
+- if ((size_t) (len + 1) > buflen)
++ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- p = strncpy (buffer, result, len);
++ char *p = strncpy (buffer, result, len);
+ buffer[len] = '\0';
+ while (isspace (*p))
+ ++p;
+ free (result);
+- parse_res = _nss_files_parse_servent (p, serv, pdata,
+- buflen, errnop);
+- if (parse_res < 0)
++
++ int parse_res = _nss_files_parse_servent (p, serv, (void *) buffer,
++ buflen, errnop);
++ if (__builtin_expect (parse_res < 0, 0))
+ {
+ if (parse_res == -1)
+ return NSS_STATUS_TRYAGAIN;
+@@ -331,7 +316,7 @@ _nss_nis_getservbyname_r (const char *na
+ }
+
+ /* Check if it is safe to rely on services.byservicename. */
+- if (_nis_default_nss () & NSS_FLAG_SERVICES_AUTHORITATIVE)
++ if (_nsl_default_nss () & NSS_FLAG_SERVICES_AUTHORITATIVE)
+ return status;
+
+ struct ypall_callback ypcb;
+@@ -360,10 +345,8 @@ _nss_nis_getservbyport_r (int port, cons
+ struct servent *serv, char *buffer,
+ size_t buflen, int *errnop)
+ {
+- enum nss_status status;
+ char *domain;
+-
+- if (yp_get_default_domain (&domain))
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+ /* If the protocol is given, we only need one query.
+@@ -372,48 +355,45 @@ _nss_nis_getservbyport_r (int port, cons
+ const char *proto = protocol != NULL ? protocol : "tcp";
+ do
+ {
++ /* key is: "port/proto" */
+ char key[sizeof (int) * 3 + strlen (proto) + 2];
++ size_t keylen = snprintf (key, sizeof (key), "%d/%s", ntohs (port),
++ proto);
++
+ char *result;
+- size_t keylen, len;
+ int int_len;
+-
+- /* key is: "port/proto" */
+- keylen = snprintf (key, sizeof (key), "%d/%s", ntohs (port), proto);
+- status = yperr2nss (yp_match (domain, "services.byname", key,
+- keylen, &result, &int_len));
+- len = int_len;
++ enum nss_status status = yperr2nss (yp_match (domain, "services.byname",
++ key, keylen, &result,
++ &int_len));
++ size_t len = int_len;
+
+ /* If we found the key, it's ok and parse the result. If not,
+ fall through and parse the complete table. */
+ if (status == NSS_STATUS_SUCCESS)
+ {
+- struct parser_data *pdata = (void *) buffer;
+- int parse_res;
+- char *p;
+-
+- if ((size_t) (len + 1) > buflen)
++ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- p = strncpy (buffer, result, len);
++ char *p = strncpy (buffer, result, len);
+ buffer[len] = '\0';
+ while (isspace (*p))
+ ++p;
+ free (result);
+- parse_res = _nss_files_parse_servent (p, serv, pdata,
+- buflen, errnop);
+- if (parse_res < 0)
++ int parse_res = _nss_files_parse_servent (p, serv, (void *) buffer,
++ buflen, errnop);
++ if (__builtin_expect (parse_res < 0, 0))
+ {
+ if (parse_res == -1)
+ return NSS_STATUS_TRYAGAIN;
+ else
+ return NSS_STATUS_NOTFOUND;
+ }
+- else
+- return NSS_STATUS_SUCCESS;
++
++ return NSS_STATUS_SUCCESS;
+ }
+ }
+ while (protocol == NULL && (proto[0] == 't' ? (proto = "udp") : NULL));
+@@ -434,7 +414,8 @@ _nss_nis_getservbyport_r (int port, cons
+ req.buflen = buflen;
+ req.errnop = errnop;
+ req.status = NSS_STATUS_NOTFOUND;
+- status = yperr2nss (yp_all (domain, "services.byname", &ypcb));
++ enum nss_status status = yperr2nss (yp_all (domain, "services.byname",
++ &ypcb));
+
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+--- libc/nis/nss_nis/nis-spwd.c 19 Jan 2003 19:20:34 -0000 1.14
++++ libc/nis/nss_nis/nis-spwd.c 29 Apr 2006 01:09:49 -0000 1.16
+@@ -68,49 +68,52 @@ static enum nss_status
+ internal_nis_getspent_r (struct spwd *sp, char *buffer, size_t buflen,
+ int *errnop)
+ {
+- struct parser_data *data = (void *) buffer;
+- char *domain, *result, *outkey;
+- int len, keylen, parse_res;
+-
+- if (yp_get_default_domain (&domain))
++ char *domain;
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+ /* Get the next entry until we found a correct one. */
++ int parse_res;
+ do
+ {
+- enum nss_status retval;
+- char *p;
++ char *result;
++ char *outkey;
++ int len;
++ int keylen;
++ int yperr;
+
+ if (new_start)
+- retval = yperr2nss (yp_first (domain, "shadow.byname",
+- &outkey, &keylen, &result, &len));
++ yperr = yp_first (domain, "shadow.byname", &outkey, &keylen, &result,
++ &len);
+ else
+- retval = yperr2nss ( yp_next (domain, "shadow.byname",
+- oldkey, oldkeylen,
+- &outkey, &keylen, &result, &len));
++ yperr = yp_next (domain, "shadow.byname", oldkey, oldkeylen, &outkey,
++ &keylen, &result, &len);
+
+- if (retval != NSS_STATUS_SUCCESS)
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+ {
++ enum nss_status retval = yperr2nss (yperr);
++
+ if (retval == NSS_STATUS_TRYAGAIN)
+ *errnop = errno;
+ return retval;
+ }
+
+- if ((size_t) (len + 1) > buflen)
++ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- p = strncpy (buffer, result, len);
++ char *p = strncpy (buffer, result, len);
+ buffer[len] = '\0';
+ while (isspace (*p))
+ ++p;
+ free (result);
+
+- parse_res = _nss_files_parse_spent (p, sp, data, buflen, errnop);
+- if (parse_res == -1)
++ parse_res = _nss_files_parse_spent (p, sp, (void *) buffer, buflen,
++ errnop);
++ if (__builtin_expect (parse_res == -1, 0))
+ {
+ free (outkey);
+ *errnop = ERANGE;
+@@ -146,45 +149,46 @@ enum nss_status
+ _nss_nis_getspnam_r (const char *name, struct spwd *sp,
+ char *buffer, size_t buflen, int *errnop)
+ {
+- struct parser_data *data = (void *) buffer;
+- enum nss_status retval;
+- char *domain, *result, *p;
+- int len, parse_res;
+-
+ if (name == NULL)
+ {
+ *errnop = EINVAL;
+ return NSS_STATUS_UNAVAIL;
+ }
+
+- if (yp_get_default_domain (&domain))
++ char *domain;
++ if (__builtin_expect (yp_get_default_domain (&domain), 0))
+ return NSS_STATUS_UNAVAIL;
+
+- retval = yperr2nss (yp_match (domain, "shadow.byname", name,
+- strlen (name), &result, &len));
++ char *result;
++ int len;
++ int yperr = yp_match (domain, "shadow.byname", name, strlen (name), &result,
++ &len);
+
+- if (retval != NSS_STATUS_SUCCESS)
++ if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
+ {
++ enum nss_status retval = yperr2nss (yperr);
++
+ if (retval == NSS_STATUS_TRYAGAIN)
+ *errnop = errno;
+ return retval;
+ }
+
+- if ((size_t) (len + 1) > buflen)
++ if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
+ {
+ free (result);
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- p = strncpy (buffer, result, len);
++ char *p = strncpy (buffer, result, len);
+ buffer[len] = '\0';
+ while (isspace (*p))
+ ++p;
+ free (result);
+
+- parse_res = _nss_files_parse_spent (p, sp, data, buflen, errnop);
+- if (parse_res < 1)
++ int parse_res = _nss_files_parse_spent (p, sp, (void *) buffer, buflen,
++ errnop);
++ if (__builtin_expect (parse_res < 1, 0))
+ {
+ if (parse_res == -1)
+ return NSS_STATUS_TRYAGAIN;
+--- libc/nis/nss_nisplus/nisplus-alias.c 7 Apr 2006 00:27:14 -0000 1.19
++++ libc/nis/nss_nisplus/nisplus-alias.c 14 Apr 2006 20:38:29 -0000 1.20
+@@ -36,11 +36,11 @@ static u_long next_entry;
+ static nis_name tablename_val;
+ static size_t tablename_len;
+
+-#define NISENTRYVAL(idx,col,res) \
+- ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
++#define NISENTRYVAL(idx, col, res) \
++ (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
+
+-#define NISENTRYLEN(idx,col,res) \
+- ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
++#define NISENTRYLEN(idx, col, res) \
++ (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
+
+ static enum nss_status
+ _nss_create_tablename (int *errnop)
+@@ -79,16 +79,12 @@ _nss_nisplus_parse_aliasent (nis_result
+ return 0;
+
+ if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
+- || __type_of (&result->objects.objects_val[entry]) != NIS_ENTRY_OBJ
+- || strcmp (result->objects.objects_val[entry].EN_data.en_type,
++ || __type_of (&NIS_RES_OBJECT (result)[entry]) != NIS_ENTRY_OBJ
++ || strcmp (NIS_RES_OBJECT (result)[entry].EN_data.en_type,
+ "mail_aliases") != 0
+- || result->objects.objects_val[entry].EN_data.en_cols.en_cols_len < 2)
++ || NIS_RES_OBJECT (result)[entry].EN_data.en_cols.en_cols_len < 2)
+ return 0;
+
+- char *first_unused = buffer + NISENTRYLEN (0, 1, result) + 1;
+- size_t room_left = (buflen - (buflen % __alignof__ (char *))
+- - NISENTRYLEN (0, 1, result) - 2);
+-
+ if (NISENTRYLEN (entry, 1, result) >= buflen)
+ {
+ /* The line is too long for our buffer. */
+@@ -101,13 +97,15 @@ _nss_nisplus_parse_aliasent (nis_result
+ NISENTRYLEN (entry, 1, result));
+ *cp = '\0';
+
+- if (NISENTRYLEN(entry, 0, result) >= room_left)
+- goto no_more_room;
++ char *first_unused = cp + 1;
++ size_t room_left = buflen - (first_unused - buffer);
+
+ alias->alias_local = 0;
+ alias->alias_members_len = 0;
+- *first_unused = '\0';
+- ++first_unused;
++
++ if (NISENTRYLEN (entry, 0, result) >= room_left)
++ goto no_more_room;
++
+ cp = __stpncpy (first_unused, NISENTRYVAL (entry, 0, result),
+ NISENTRYLEN (entry, 0, result));
+ *cp = '\0';
+@@ -118,11 +116,20 @@ _nss_nisplus_parse_aliasent (nis_result
+ if (cp != NULL)
+ *cp = '\0';
+
+- first_unused += strlen (alias->alias_name) +1;
++ size_t len = strlen (alias->alias_name) + 1;
++ first_unused += len;
++ room_left -= len;
++
+ /* Adjust the pointer so it is aligned for
+ storing pointers. */
+- first_unused += __alignof__ (char *) - 1;
+- first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
++ size_t adjust = ((__alignof__ (char *)
++ - (first_unused - (char *) 0) % __alignof__ (char *))
++ % __alignof__ (char *));
++ if (room_left < adjust)
++ goto no_more_room;
++ first_unused += adjust;
++ room_left -= adjust;
++
+ alias->alias_members = (char **) first_unused;
+
+ char *line = buffer;
+@@ -146,8 +153,10 @@ _nss_nisplus_parse_aliasent (nis_result
+ if (line != alias->alias_members[alias->alias_members_len])
+ {
+ *line++ = '\0';
+- alias->alias_members_len++;
++ ++alias->alias_members_len;
+ }
++ else if (*line == ',')
++ ++line;
+ }
+
+ return alias->alias_members_len == 0 ? 0 : 1;
+--- libc/nis/nss_nisplus/nisplus-ethers.c 7 Apr 2006 00:23:49 -0000 1.24
++++ libc/nis/nss_nisplus/nisplus-ethers.c 30 Apr 2006 05:44:23 -0000 1.26
+@@ -38,11 +38,11 @@ static nis_name tablename_val;
+ static u_long tablename_len;
+
+
+-#define NISENTRYVAL(idx,col,res) \
+- ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
++#define NISENTRYVAL(idx, col, res) \
++ (NIS_RES_OBJECT (res)[idx].zo_data.objdata_u.en_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
+
+-#define NISENTRYLEN(idx,col,res) \
+- ((res)->objects.objects_val[(idx)].zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
++#define NISENTRYLEN(idx, col, res) \
++ (NIS_RES_OBJECT (res)[idx].zo_data.objdata_u.en_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
+
+ static int
+ _nss_nisplus_parse_etherent (nis_result *result, struct etherent *ether,
+@@ -55,7 +55,7 @@ _nss_nisplus_parse_etherent (nis_result
+ return 0;
+
+ if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
+- || result->objects.objects_len != 1
++ || NIS_RES_NUMOBJ (result) != 1
+ || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
+ || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type,
+ "ethers_tbl") != 0
+@@ -63,13 +63,15 @@ _nss_nisplus_parse_etherent (nis_result
+ return 0;
+
+ /* Generate the ether entry format and use the normal parser */
+- if (NISENTRYLEN (0, 0, result) +1 > room_left)
++ if (NISENTRYLEN (0, 0, result) + 1 > room_left)
+ {
+ *errnop = ERANGE;
+ return -1;
+ }
+- strncpy (p, NISENTRYVAL (0, 0, result), NISENTRYLEN (0, 0, result));
+- room_left -= (NISENTRYLEN (0, 0, result) +1);
++ char *cp = __stpncpy (p, NISENTRYVAL (0, 0, result),
++ NISENTRYLEN (0, 0, result));
++ *cp = '\0';
++ room_left -= NISENTRYLEN (0, 0, result) + 1;
+ ether->e_name = p;
+
+ struct ether_addr *ea = ether_aton (NISENTRYVAL (0, 1, result));
+@@ -174,6 +176,11 @@ internal_nisplus_getetherent_r (struct e
+ {
+ saved_result = NULL;
+ result = nis_first_entry (tablename_val);
++ if (result == NULL)
++ {
++ *errnop = errno;
++ return NSS_STATUS_TRYAGAIN;
++ }
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ return niserr2nss (result->status);
+ }
+@@ -181,6 +188,11 @@ internal_nisplus_getetherent_r (struct e
+ {
+ saved_result = result;
+ result = nis_next_entry (tablename_val, &result->cookie);
++ if (result == NULL)
++ {
++ *errnop = errno;
++ return NSS_STATUS_TRYAGAIN;
++ }
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ {
+ nis_freeresult (saved_result);
+--- libc/nis/nss_nisplus/nisplus-hosts.c 25 Mar 2006 20:59:19 -0000 1.29
++++ libc/nis/nss_nisplus/nisplus-hosts.c 30 Apr 2006 05:44:23 -0000 1.31
+@@ -36,15 +36,16 @@ static nis_result *result;
+ static nis_name tablename_val;
+ static u_long tablename_len;
+
+-#define NISENTRYVAL(idx,col,res) \
+- ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
++#define NISENTRYVAL(idx, col, res) \
++ (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
+
+-#define NISENTRYLEN(idx,col,res) \
+- ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
++#define NISENTRYLEN(idx, col, res) \
++ (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
+
+ /* Get implementation for some internal functions. */
+ #include <resolv/mapv4v6addr.h>
+
++
+ static int
+ _nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host,
+ char *buffer, size_t buflen, int *errnop,
+@@ -53,27 +54,26 @@ _nss_nisplus_parse_hostent (nis_result *
+ unsigned int i;
+ char *first_unused = buffer;
+ size_t room_left = buflen;
+- char *data, *p, *line;
+
+ if (result == NULL)
+ return 0;
+
+ if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) ||
+- __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ ||
+- strcmp(result->objects.objects_val[0].EN_data.en_type,
+- "hosts_tbl") != 0 ||
+- result->objects.objects_val[0].EN_data.en_cols.en_cols_len < 4)
++ __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ ||
++ strcmp(NIS_RES_OBJECT (result)[0].EN_data.en_type, "hosts_tbl") != 0 ||
++ NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 4)
+ return 0;
+
+- if (room_left < NISENTRYLEN (0, 2, result) + 1)
++ char *data = first_unused;
++
++ if (room_left < (af == AF_INET6 || (flags & AI_V4MAPPED) != 0
++ ? IN6ADDRSZ : INADDRSZ))
+ {
+ no_more_room:
+ *errnop = ERANGE;
+ return -1;
+ }
+
+- data = first_unused;
+-
+ /* Parse address. */
+ if (af == AF_INET && inet_pton (af, NISENTRYVAL (0, 2, result), data) > 0)
+ {
+@@ -99,51 +99,53 @@ _nss_nisplus_parse_hostent (nis_result *
+ /* Illegal address: ignore line. */
+ return 0;
+
+- first_unused+=host->h_length;
+- room_left-=host->h_length;
++ first_unused += host->h_length;
++ room_left -= host->h_length;
+
+ if (NISENTRYLEN (0, 0, result) + 1 > room_left)
+ goto no_more_room;
+
+- p = __stpncpy (first_unused, NISENTRYVAL (0, 0, result),
+- NISENTRYLEN (0, 0, result));
+- *p = '\0';
+- room_left -= (NISENTRYLEN (0, 0, result) + 1);
+ host->h_name = first_unused;
+- first_unused += NISENTRYLEN (0, 0, result) +1;
+- p = first_unused;
+-
+- line = p;
+- for (i = 0; i < result->objects.objects_len; ++i)
++ first_unused = __stpncpy (first_unused, NISENTRYVAL (0, 0, result),
++ NISENTRYLEN (0, 0, result));
++ *first_unused++ = '\0';
++ room_left -= NISENTRYLEN (0, 0, result) + 1;
++
++ /* XXX Rewrite at some point to allocate the array first and then
++ copy the strings. It wasteful to first concatenate the strings
++ to just split them again later. */
++ char *line = first_unused;
++ for (i = 0; i < NIS_RES_NUMOBJ (result); ++i)
+ {
+ if (strcmp (NISENTRYVAL (i, 1, result), host->h_name) != 0)
+ {
+ if (NISENTRYLEN (i, 1, result) + 2 > room_left)
+ goto no_more_room;
+
+- *p++ = ' ';
+- p = __stpncpy (p, NISENTRYVAL (i, 1, result),
+- NISENTRYLEN (i, 1, result));
+- *p = '\0';
+- room_left -= (NISENTRYLEN (i, 1, result) + 1);
++ *first_unused++ = ' ';
++ first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result),
++ NISENTRYLEN (i, 1, result));
++ *first_unused = '\0';
++ room_left -= NISENTRYLEN (i, 1, result) + 1;
+ }
+ }
+- *p++ = '\0';
+- first_unused = p;
++ *first_unused++ = '\0';
+
+ /* Adjust the pointer so it is aligned for
+ storing pointers. */
+- first_unused += __alignof__ (char *) - 1;
+- first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
+- host->h_addr_list = (char **) first_unused;
+- if (room_left < 2 * sizeof (char *))
++ size_t adjust = ((__alignof__ (char *)
++ - (first_unused - (char *) 0) % __alignof__ (char *))
++ % __alignof__ (char *));
++ if (room_left < adjust + 3 * sizeof (char *))
+ goto no_more_room;
++ first_unused += adjust;
++ room_left -= adjust;
++ host->h_addr_list = (char **) first_unused;
+
+- room_left -= (2 * sizeof (char *));
++ room_left -= 3 * sizeof (char *);
+ host->h_addr_list[0] = data;
+ host->h_addr_list[1] = NULL;
+ host->h_aliases = &host->h_addr_list[2];
+- host->h_aliases[0] = NULL;
+
+ i = 0;
+ while (*line != '\0')
+@@ -159,23 +161,21 @@ _nss_nisplus_parse_hostent (nis_result *
+ goto no_more_room;
+
+ room_left -= sizeof (char *);
+- host->h_aliases[i] = line;
++ host->h_aliases[i++] = line;
+
+ while (*line != '\0' && *line != ' ')
+ ++line;
+
+ if (*line == ' ')
+- {
+- *line = '\0';
+- ++line;
+- ++i;
+- }
+- else
+- host->h_aliases[i+1] = NULL;
++ *line++ = '\0';
+ }
++
++ host->h_aliases[i] = NULL;
++
+ return 1;
+ }
+
++
+ static enum nss_status
+ _nss_create_tablename (int *errnop)
+ {
+@@ -265,6 +265,11 @@ internal_nisplus_gethostent_r (struct ho
+ }
+
+ result = nis_first_entry (tablename_val);
++ if (result == NULL)
++ {
++ *errnop = errno;
++ return NSS_STATUS_TRYAGAIN;
++ }
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ {
+ enum nss_status retval = niserr2nss (result->status);
+@@ -279,11 +284,13 @@ internal_nisplus_gethostent_r (struct ho
+ }
+ else
+ {
+- nis_result *res2;
+-
+ saved_res = result;
+- res2 = nis_next_entry(tablename_val, &result->cookie);
+- result = res2;
++ result = nis_next_entry (tablename_val, &result->cookie);
++ if (result == NULL)
++ {
++ *errnop = errno;
++ return NSS_STATUS_TRYAGAIN;
++ }
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ {
+ enum nss_status retval= niserr2nss (result->status);
+--- libc/nis/nss_nisplus/nisplus-netgrp.c 3 Dec 2005 22:11:34 -0000 1.16
++++ libc/nis/nss_nisplus/nisplus-netgrp.c 24 Apr 2006 04:22:52 -0000 1.17
+@@ -27,11 +27,11 @@
+
+ #include "nss-nisplus.h"
+
+-#define NISENTRYVAL(idx,col,res) \
+- ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
++#define NISENTRYVAL(idx, col, res) \
++ (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
+
+-#define NISENTRYLEN(idx,col,res) \
+- ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
++#define NISENTRYLEN(idx, col, res) \
++ (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
+
+ enum nss_status
+ _nss_nisplus_getnetgrent_r (struct __netgrent *result, char *buffer,
+--- libc/nis/nss_nisplus/nisplus-network.c 7 Apr 2006 00:14:50 -0000 1.23
++++ libc/nis/nss_nisplus/nisplus-network.c 30 Apr 2006 05:44:23 -0000 1.25
+@@ -36,11 +36,11 @@ static nis_result *result;
+ static nis_name tablename_val;
+ static u_long tablename_len;
+
+-#define NISENTRYVAL(idx,col,res) \
+- ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
++#define NISENTRYVAL(idx, col, res) \
++ (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
+
+-#define NISENTRYLEN(idx,col,res) \
+- ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
++#define NISENTRYLEN(idx, col, res) \
++ (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
+
+
+ static int
+@@ -54,10 +54,10 @@ _nss_nisplus_parse_netent (nis_result *r
+ return 0;
+
+ if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
+- || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
+- || strcmp (result->objects.objects_val[0].EN_data.en_type,
++ || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
++ || strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type,
+ "networks_tbl") != 0
+- || result->objects.objects_val[0].EN_data.en_cols.en_cols_len < 3)
++ || NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 3)
+ return 0;
+
+ if (NISENTRYLEN (0, 0, result) >= room_left)
+@@ -72,39 +72,45 @@ _nss_nisplus_parse_netent (nis_result *r
+ NISENTRYLEN (0, 0, result));
+ first_unused[NISENTRYLEN (0, 0, result)] = '\0';
+ network->n_name = first_unused;
+- room_left -= (strlen (first_unused) +1);
+- first_unused += strlen (first_unused) +1;
++ size_t len = strlen (first_unused) + 1;
++ room_left -= len;
++ first_unused += len;
++
+ network->n_addrtype = 0;
+ network->n_net = inet_network (NISENTRYVAL (0, 2, result));
+- char *p = first_unused;
+
+- char *line = p;
+- for (unsigned int i = 0; i < result->objects.objects_len; ++i)
++ /* XXX Rewrite at some point to allocate the array first and then
++ copy the strings. It wasteful to first concatenate the strings
++ to just split them again later. */
++ char *line = first_unused;
++ for (unsigned int i = 0; i < NIS_RES_NUMOBJ (result); ++i)
+ {
+ if (strcmp (NISENTRYVAL (i, 1, result), network->n_name) != 0)
+ {
+ if (NISENTRYLEN (i, 1, result) + 2 > room_left)
+ goto no_more_room;
+
+- *p++ = ' ';
+- p = __stpncpy (p, NISENTRYVAL (i, 1, result),
+- NISENTRYLEN (i, 1, result));
+- *p = '\0';
++ *first_unused++ = ' ';
++ first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result),
++ NISENTRYLEN (i, 1, result));
+ room_left -= (NISENTRYLEN (i, 1, result) + 1);
+ }
+ }
+- *p++ = '\0';
+- first_unused = p;
++ *first_unused++ = '\0';
+
+ /* Adjust the pointer so it is aligned for
+ storing pointers. */
+- first_unused += __alignof__ (char *) - 1;
+- first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
+- network->n_aliases = (char **) first_unused;
+- if (room_left < 2 * sizeof (char *))
++ size_t adjust = ((__alignof__ (char *)
++ - (first_unused - (char *) 0) % __alignof__ (char *))
++ % __alignof__ (char *));
++ if (room_left < adjust + sizeof (char *))
+ goto no_more_room;
+- room_left -= (2 * sizeof (char *));
+- network->n_aliases[0] = NULL;
++ first_unused += adjust;
++ room_left -= adjust;
++ network->n_aliases = (char **) first_unused;
++
++ /* For the terminating NULL pointer. */
++ room_left -= sizeof (char *);
+
+ unsigned int i = 0;
+ while (*line != '\0')
+@@ -120,24 +126,20 @@ _nss_nisplus_parse_netent (nis_result *r
+ goto no_more_room;
+
+ room_left -= sizeof (char *);
+- network->n_aliases[i] = line;
++ network->n_aliases[i++] = line;
+
+ while (*line != '\0' && *line != ' ')
+ ++line;
+
+ if (*line == ' ')
+- {
+- *line = '\0';
+- ++line;
+- ++i;
+- }
+- else
+- network->n_aliases[i + 1] = NULL;
++ *line++ = '\0';
+ }
++ network->n_aliases[i] = NULL;
+
+ return 1;
+ }
+
++
+ static enum nss_status
+ _nss_create_tablename (int *errnop)
+ {
+@@ -230,6 +232,11 @@ internal_nisplus_getnetent_r (struct net
+ }
+
+ result = nis_first_entry (tablename_val);
++ if (result == NULL)
++ {
++ *errnop = errno;
++ return NSS_STATUS_TRYAGAIN;
++ }
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ {
+ int retval = niserr2nss (result->status);
+@@ -247,9 +254,13 @@ internal_nisplus_getnetent_r (struct net
+ }
+ else
+ {
+- nis_result *res = nis_next_entry (tablename_val, &result->cookie);
+ saved_res = result;
+- result = res;
++ result = nis_next_entry (tablename_val, &result->cookie);
++ if (result == NULL)
++ {
++ *errnop = errno;
++ return NSS_STATUS_TRYAGAIN;
++ }
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ {
+ int retval = niserr2nss (result->status);
+--- libc/nis/nss_nisplus/nisplus-parser.c 24 Oct 2004 21:23:20 -0000 1.11
++++ libc/nis/nss_nisplus/nisplus-parser.c 30 Apr 2006 07:00:12 -0000 1.16
+@@ -25,33 +25,37 @@
+
+ #include "nisplus-parser.h"
+
+-#define NISENTRYVAL(idx,col,res) \
+- ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
++#define NISENTRYVAL(idx, col, res) \
++ (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
+
+-#define NISENTRYLEN(idx,col,res) \
+- ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
++#define NISENTRYLEN(idx, col, res) \
++ (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
+
+
+ int
+-_nss_nisplus_parse_pwent (nis_result *result, struct passwd *pw,
++_nss_nisplus_parse_pwent_chk (nis_result *result, struct passwd *pw,
++ char *buffer, size_t buflen, int *errnop)
++{
++ if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
++ || NIS_RES_NUMOBJ (result) != 1
++ || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
++ || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type, "passwd_tbl") != 0
++ || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 7)
++ return 0;
++
++ return _nss_nisplus_parse_pwent (result, 0, pw, buffer, buflen, errnop);
++}
++
++
++int
++_nss_nisplus_parse_pwent (nis_result *result, size_t entry, struct passwd *pw,
+ char *buffer, size_t buflen, int *errnop)
+ {
+ char *first_unused = buffer;
+ size_t room_left = buflen;
+ size_t len;
+
+- if (result == NULL)
+- return 0;
+-
+- if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
+- || result->objects.objects_len != 1
+- || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
+- || strcmp (result->objects.objects_val->EN_data.en_type,
+- "passwd_tbl") != 0
+- || result->objects.objects_val->EN_data.en_cols.en_cols_len < 7)
+- return 0;
+-
+- if (NISENTRYLEN (0, 0, result) >= room_left)
++ if (NISENTRYLEN (entry, 0, result) >= room_left)
+ {
+ /* The line is too long for our buffer. */
+ no_more_room:
+@@ -59,89 +63,95 @@ _nss_nisplus_parse_pwent (nis_result *re
+ return -1;
+ }
+
+- strncpy (first_unused, NISENTRYVAL (0, 0, result),
+- NISENTRYLEN (0, 0, result));
+- first_unused[NISENTRYLEN (0, 0, result)] = '\0';
++ strncpy (first_unused, NISENTRYVAL (entry, 0, result),
++ NISENTRYLEN (entry, 0, result));
++ first_unused[NISENTRYLEN (entry, 0, result)] = '\0';
+ len = strlen (first_unused);
+ if (len == 0) /* No name ? Should never happen, database is corrupt */
+ return 0;
+ pw->pw_name = first_unused;
+- room_left -= (len + 1);
+- first_unused += (len + 1);
++ room_left -= len + 1;
++ first_unused += len + 1;
+
+- if (NISENTRYLEN (0, 1, result) >= room_left)
++ if (NISENTRYLEN (entry, 1, result) >= room_left)
+ goto no_more_room;
+
+- strncpy (first_unused, NISENTRYVAL (0, 1, result),
+- NISENTRYLEN (0, 1, result));
+- first_unused[NISENTRYLEN (0, 1, result)] = '\0';
++ strncpy (first_unused, NISENTRYVAL (entry, 1, result),
++ NISENTRYLEN (entry, 1, result));
++ first_unused[NISENTRYLEN (entry, 1, result)] = '\0';
+ pw->pw_passwd = first_unused;
+ len = strlen (first_unused);
+- room_left -= (len + 1);
+- first_unused += (len + 1);
++ room_left -= len + 1;
++ first_unused += len + 1;
+
+- if (NISENTRYLEN(0, 2, result) >= room_left)
+- goto no_more_room;
++ char *numstr = NISENTRYVAL (entry, 2, result);
++ len = NISENTRYLEN (entry, 2, result);
++ if (len == 0 && numstr[len - 1] != '\0')
++ {
++ if (len >= room_left)
++ goto no_more_room;
+
+- strncpy (first_unused, NISENTRYVAL (0, 2, result),
+- NISENTRYLEN (0, 2, result));
+- first_unused[NISENTRYLEN (0, 2, result)] = '\0';
+- len = strlen (first_unused);
+- if (len == 0) /* If we don't have a uid, it's an invalid shadow entry */
++ strncpy (first_unused, numstr, len);
++ first_unused[len] = '\0';
++ numstr = first_unused;
++ }
++ if (numstr[0] == '\0')
++ /* If we don't have a uid, it's an invalid shadow entry. */
+ return 0;
+- pw->pw_uid = strtoul (first_unused, NULL, 10);
+- room_left -= (len + 1);
+- first_unused += (len + 1);
++ pw->pw_uid = strtoul (numstr, NULL, 10);
+
+- if (NISENTRYLEN (0, 3, result) >= room_left)
+- goto no_more_room;
++ numstr = NISENTRYVAL (entry, 3, result);
++ len = NISENTRYLEN (entry, 3, result);
++ if (len == 0 && numstr[len - 1] != '\0')
++ {
++ if (len >= room_left)
++ goto no_more_room;
+
+- strncpy (first_unused, NISENTRYVAL (0, 3, result),
+- NISENTRYLEN (0, 3, result));
+- first_unused[NISENTRYLEN (0, 3, result)] = '\0';
+- len = strlen (first_unused);
+- if (len == 0) /* If we don't have a gid, it's an invalid shadow entry */
++ strncpy (first_unused, numstr, len);
++ first_unused[len] = '\0';
++ numstr = first_unused;
++ }
++ if (numstr[0] == '\0')
++ /* If we don't have a gid, it's an invalid shadow entry. */
+ return 0;
+- pw->pw_gid = strtoul (first_unused, NULL, 10);
+- room_left -= (len + 1);
+- first_unused += (len + 1);
++ pw->pw_gid = strtoul (numstr, NULL, 10);
+
+- if (NISENTRYLEN(0, 4, result) >= room_left)
++ if (NISENTRYLEN(entry, 4, result) >= room_left)
+ goto no_more_room;
+
+- strncpy (first_unused, NISENTRYVAL (0, 4, result),
+- NISENTRYLEN (0, 4, result));
+- first_unused[NISENTRYLEN (0, 4, result)] = '\0';
++ strncpy (first_unused, NISENTRYVAL (entry, 4, result),
++ NISENTRYLEN (entry, 4, result));
++ first_unused[NISENTRYLEN (entry, 4, result)] = '\0';
+ pw->pw_gecos = first_unused;
+ len = strlen (first_unused);
+- room_left -= (len + 1);
+- first_unused += (len + 1);
++ room_left -= len + 1;
++ first_unused += len + 1;
+
+- if (NISENTRYLEN (0, 5, result) >= room_left)
++ if (NISENTRYLEN (entry, 5, result) >= room_left)
+ goto no_more_room;
+
+- strncpy (first_unused, NISENTRYVAL (0, 5, result),
+- NISENTRYLEN (0, 5, result));
+- first_unused[NISENTRYLEN (0, 5, result)] = '\0';
++ strncpy (first_unused, NISENTRYVAL (entry, 5, result),
++ NISENTRYLEN (entry, 5, result));
++ first_unused[NISENTRYLEN (entry, 5, result)] = '\0';
+ pw->pw_dir = first_unused;
+ len = strlen (first_unused);
+- room_left -= (len + 1);
+- first_unused += (len + 1);
++ room_left -= len + 1;
++ first_unused += len + 1;
+
+- if (NISENTRYLEN (0, 6, result) >= room_left)
++ if (NISENTRYLEN (entry, 6, result) >= room_left)
+ goto no_more_room;
+
+- strncpy (first_unused, NISENTRYVAL (0, 6, result),
+- NISENTRYLEN (0, 6, result));
+- first_unused[NISENTRYLEN (0, 6, result)] = '\0';
++ strncpy (first_unused, NISENTRYVAL (entry, 6, result),
++ NISENTRYLEN (entry, 6, result));
++ first_unused[NISENTRYLEN (entry, 6, result)] = '\0';
+ pw->pw_shell = first_unused;
+ len = strlen (first_unused);
+- room_left -= (len + 1);
+- first_unused += (len + 1);
++ room_left -= len + 1;
++ first_unused += len + 1;
+
+ return 1;
+ }
+-libnss_nisplus_hidden_def (_nss_nisplus_parse_pwent)
++
+
+ int
+ _nss_nisplus_parse_grent (nis_result *result, u_long entry, struct group *gr,
+@@ -157,10 +167,10 @@ _nss_nisplus_parse_grent (nis_result *re
+ return 0;
+
+ if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
+- || __type_of(result->objects.objects_val) != NIS_ENTRY_OBJ
+- || strcmp (result->objects.objects_val[entry].EN_data.en_type,
++ || __type_of(NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
++ || strcmp (NIS_RES_OBJECT (result)[entry].EN_data.en_type,
+ "group_tbl") != 0
+- || result->objects.objects_val[entry].EN_data.en_cols.en_cols_len < 4)
++ || NIS_RES_OBJECT (result)[entry].EN_data.en_cols.en_cols_len < 4)
+ return 0;
+
+ if (NISENTRYLEN (entry, 0, result) >= room_left)
+@@ -178,8 +188,8 @@ _nss_nisplus_parse_grent (nis_result *re
+ if (len == 0) /* group table is corrupt */
+ return 0;
+ gr->gr_name = first_unused;
+- room_left -= (len + 1);
+- first_unused += (len + 1);
++ room_left -= len + 1;
++ first_unused += len + 1;
+
+ if (NISENTRYLEN (entry, 1, result) >= room_left)
+ goto no_more_room;
+@@ -189,21 +199,24 @@ _nss_nisplus_parse_grent (nis_result *re
+ first_unused[NISENTRYLEN (entry, 1, result)] = '\0';
+ gr->gr_passwd = first_unused;
+ len = strlen (first_unused);
+- room_left -= (len + 1);
+- first_unused += (len + 1);
++ room_left -= len + 1;
++ first_unused += len + 1;
+
+- if (NISENTRYLEN (entry, 2, result) >= room_left)
+- goto no_more_room;
++ char *numstr = NISENTRYVAL (entry, 2, result);
++ len = NISENTRYLEN (entry, 2, result);
++ if (len == 0 && numstr[len - 1] != '\0')
++ {
++ if (len >= room_left)
++ goto no_more_room;
+
+- strncpy (first_unused, NISENTRYVAL (entry, 2, result),
+- NISENTRYLEN (entry, 2, result));
+- first_unused[NISENTRYLEN (entry, 2, result)] = '\0';
+- len = strlen (first_unused);
+- if (len == 0) /* We should always have an gid */
++ strncpy (first_unused, numstr, len);
++ first_unused[len] = '\0';
++ numstr = first_unused;
++ }
++ if (numstr[0] == '\0')
++ /* We should always have a gid. */
+ return 0;
+- gr->gr_gid = strtoul (first_unused, NULL, 10);
+- room_left -= (strlen (first_unused) + 1);
+- first_unused += strlen (first_unused) + 1;
++ gr->gr_gid = strtoul (numstr, NULL, 10);
+
+ if (NISENTRYLEN (entry, 3, result) >= room_left)
+ goto no_more_room;
+@@ -213,12 +226,17 @@ _nss_nisplus_parse_grent (nis_result *re
+ first_unused[NISENTRYLEN (entry, 3, result)] = '\0';
+ line = first_unused;
+ len = strlen (line);
+- room_left -= (len + 1);
+- first_unused += (len + 1);
++ room_left -= len + 1;
++ first_unused += len + 1;
+ /* Adjust the pointer so it is aligned for
+ storing pointers. */
+- first_unused += __alignof__ (char *) - 1;
+- first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
++ size_t adjust = ((__alignof__ (char *)
++ - (first_unused - (char *) 0) % __alignof__ (char *))
++ % __alignof__ (char *));
++ if (room_left < adjust)
++ goto no_more_room;
++ first_unused += adjust;
++ room_left -= adjust;
+ gr->gr_mem = (char **) first_unused;
+
+ count = 0;
+@@ -243,12 +261,10 @@ _nss_nisplus_parse_grent (nis_result *re
+ {
+ int is = isspace (*line);
+
+- *line = '\0';
++ *line++ = '\0';
+ if (is)
+ while (*line != '\0' && (*line == ',' || isspace (*line)))
+ ++line;
+- else
+- ++line;
+ }
+ }
+ if (room_left < sizeof (char *))
+@@ -258,7 +274,7 @@ _nss_nisplus_parse_grent (nis_result *re
+
+ return 1;
+ }
+-libnss_nisplus_hidden_def (_nss_nisplus_parse_grent)
++
+
+ int
+ _nss_nisplus_parse_spent (nis_result *result, struct spwd *sp,
+@@ -272,11 +288,10 @@ _nss_nisplus_parse_spent (nis_result *re
+ return 0;
+
+ if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
+- || result->objects.objects_len != 1
+- || __type_of(result->objects.objects_val) != NIS_ENTRY_OBJ
+- || strcmp (result->objects.objects_val->EN_data.en_type,
+- "passwd_tbl") != 0
+- || result->objects.objects_val[0].EN_data.en_cols.en_cols_len < 8)
++ || NIS_RES_NUMOBJ (result) != 1
++ || __type_of(NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
++ || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type, "passwd_tbl") != 0
++ || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 8)
+ return 0;
+
+ if (NISENTRYLEN (0, 0, result) >= room_left)
+@@ -294,8 +309,8 @@ _nss_nisplus_parse_spent (nis_result *re
+ if (len == 0)
+ return 0;
+ sp->sp_namp = first_unused;
+- room_left -= (len + 1);
+- first_unused += (len + 1);
++ room_left -= len + 1;
++ first_unused += len + 1;
+
+ if (NISENTRYLEN (0, 1, result) >= room_left)
+ goto no_more_room;
+@@ -305,8 +320,8 @@ _nss_nisplus_parse_spent (nis_result *re
+ first_unused[NISENTRYLEN (0, 1, result)] = '\0';
+ sp->sp_pwdp = first_unused;
+ len = strlen (first_unused);
+- room_left -= (len + 1);
+- first_unused += (len + 1);
++ room_left -= len + 1;
++ first_unused += len + 1;
+
+ sp->sp_lstchg = sp->sp_min = sp->sp_max = sp->sp_warn = sp->sp_inact =
+ sp->sp_expire = -1;
+@@ -314,10 +329,8 @@ _nss_nisplus_parse_spent (nis_result *re
+
+ if (NISENTRYLEN (0, 7, result) > 0)
+ {
+- char *line, *cp;
+-
+- line = NISENTRYVAL (0, 7, result);
+- cp = strchr (line, ':');
++ char *line = NISENTRYVAL (0, 7, result);
++ char *cp = strchr (line, ':');
+ if (cp == NULL)
+ return 1;
+ *cp++ = '\0';
+@@ -373,4 +386,3 @@ _nss_nisplus_parse_spent (nis_result *re
+
+ return 1;
+ }
+-libnss_nisplus_hidden_def (_nss_nisplus_parse_spent)
+--- libc/nis/nss_nisplus/nisplus-proto.c 25 Mar 2006 20:59:19 -0000 1.21
++++ libc/nis/nss_nisplus/nisplus-proto.c 30 Apr 2006 05:44:23 -0000 1.25
+@@ -35,20 +35,20 @@ static nis_result *result;
+ static nis_name tablename_val;
+ static u_long tablename_len;
+
+-#define NISENTRYVAL(idx,col,res) \
+- ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
++#define NISENTRYVAL(idx, col, res) \
++ (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
++
++#define NISENTRYLEN(idx, col, res) \
++ (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
+
+-#define NISENTRYLEN(idx,col,res) \
+- ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
+
+ static int
+-_nss_nisplus_parse_protoent (nis_result * result, struct protoent *proto,
++_nss_nisplus_parse_protoent (nis_result *result, struct protoent *proto,
+ char *buffer, size_t buflen, int *errnop)
+ {
+ char *first_unused = buffer;
+ size_t room_left = buflen;
+ unsigned int i;
+- char *p, *line;
+
+ if (result == NULL)
+ return 0;
+@@ -71,41 +71,44 @@ _nss_nisplus_parse_protoent (nis_result
+ NISENTRYLEN (0, 0, result));
+ first_unused[NISENTRYLEN (0, 0, result)] = '\0';
+ proto->p_name = first_unused;
+- room_left -= (strlen (first_unused) +1);
+- first_unused += strlen (first_unused) +1;
++ size_t len = strlen (first_unused) + 1;
++ room_left -= len;
++ first_unused += len;
+
+
+- if (NISENTRYLEN (0, 2, result) + 1 > room_left)
+- goto no_more_room;
+ proto->p_proto = atoi (NISENTRYVAL (0, 2, result));
+- p = first_unused;
+
+- line = p;
+- for (i = 0; i < result->objects.objects_len; ++i)
++ /* XXX Rewrite at some point to allocate the array first and then
++ copy the strings. It wasteful to first concatenate the strings
++ to just split them again later. */
++ char *line = first_unused;
++ for (i = 0; i < NIS_RES_NUMOBJ (result); ++i)
+ {
+ if (strcmp (NISENTRYVAL (i, 1, result), proto->p_name) != 0)
+ {
+ if (NISENTRYLEN (i, 1, result) + 2 > room_left)
+ goto no_more_room;
+- *p++ = ' ';
+- p = __stpncpy (p, NISENTRYVAL (i, 1, result),
+- NISENTRYLEN (i, 1, result));
+- *p = '\0';
+- room_left -= (NISENTRYLEN (i, 1, result) + 1);
++ *first_unused++ = ' ';
++ first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result),
++ NISENTRYLEN (i, 1, result));
++ room_left -= NISENTRYLEN (i, 1, result) + 1;
+ }
+ }
+- *p++ = '\0';
+- first_unused = p;
++ *first_unused++ = '\0';
+
+ /* Adjust the pointer so it is aligned for
+ storing pointers. */
+- first_unused += __alignof__ (char *) - 1;
+- first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
+- proto->p_aliases = (char **) first_unused;
+- if (room_left < sizeof (char *))
++ size_t adjust = ((__alignof__ (char *)
++ - (first_unused - (char *) 0) % __alignof__ (char *))
++ % __alignof__ (char *));
++ if (room_left < adjust + sizeof (char *))
+ goto no_more_room;
++ first_unused += adjust;
++ room_left -= adjust;
++ proto->p_aliases = (char **) first_unused;
++
++ /* For the terminating NULL pointer. */
+ room_left -= sizeof (char *);
+- proto->p_aliases[0] = NULL;
+
+ i = 0;
+ while (*line != '\0')
+@@ -120,20 +123,15 @@ _nss_nisplus_parse_protoent (nis_result
+ goto no_more_room;
+
+ room_left -= sizeof (char *);
+- proto->p_aliases[i] = line;
++ proto->p_aliases[i++] = line;
+
+ while (*line != '\0' && *line != ' ')
+ ++line;
+
+ if (*line == ' ')
+- {
+- *line = '\0';
+- ++line;
+- ++i;
+- }
+- else
+- proto->p_aliases[i+1] = NULL;
++ *line++ = '\0';
+ }
++ proto->p_aliases[i] = NULL;
+
+ return 1;
+ }
+@@ -229,6 +227,11 @@ internal_nisplus_getprotoent_r (struct p
+ }
+
+ result = nis_first_entry (tablename_val);
++ if (result == NULL)
++ {
++ *errnop = errno;
++ return NSS_STATUS_TRYAGAIN;
++ }
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ return niserr2nss (result->status);
+ }
+@@ -236,7 +239,11 @@ internal_nisplus_getprotoent_r (struct p
+ {
+ saved_res = result;
+ result = nis_next_entry (tablename_val, &result->cookie);
+-
++ if (result == NULL)
++ {
++ *errnop = errno;
++ return NSS_STATUS_TRYAGAIN;
++ }
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ {
+ nis_freeresult (saved_res);
+--- libc/nis/nss_nisplus/nisplus-publickey.c 7 Apr 2006 00:11:09 -0000 1.18
++++ libc/nis/nss_nisplus/nisplus-publickey.c 30 Apr 2006 15:35:10 -0000 1.20
+@@ -91,20 +91,20 @@ _nss_nisplus_getpublickey (const char *n
+ return retval;
+ }
+
+- if (res->objects.objects_len > 1)
++ if (NIS_RES_NUMOBJ (res) > 1)
+ {
+ /*
+ * More than one principal with same uid?
+ * something wrong with cred table. Should be unique
+ * Warn user and continue.
+ */
+- printf (_("DES entry for netname %s not unique\n"), netname);
++ syslog (LOG_ERR, _("DES entry for netname %s not unique\n"), netname);
+ nis_freeresult (res);
+ return NSS_STATUS_SUCCESS;
+ }
+
+- len = ENTRY_LEN (res->objects.objects_val, 3);
+- memcpy (pkey, ENTRY_VAL (res->objects.objects_val,3), len);
++ len = ENTRY_LEN (NIS_RES_OBJECT (res), 3);
++ memcpy (pkey, ENTRY_VAL (NIS_RES_OBJECT (res),3), len);
+ pkey[len] = 0;
+ cptr = strchr (pkey, ':');
+ if (cptr)
+@@ -114,6 +114,7 @@ _nss_nisplus_getpublickey (const char *n
+ return NSS_STATUS_SUCCESS;
+ }
+
++
+ enum nss_status
+ _nss_nisplus_getsecretkey (const char *netname, char *skey, char *passwd,
+ int *errnop)
+@@ -172,20 +173,20 @@ _nss_nisplus_getsecretkey (const char *n
+ return retval;
+ }
+
+- if (res->objects.objects_len > 1)
++ if (NIS_RES_NUMOBJ (res) > 1)
+ {
+ /*
+ * More than one principal with same uid?
+ * something wrong with cred table. Should be unique
+ * Warn user and continue.
+ */
+- printf (_("DES entry for netname %s not unique\n"), netname);
++ syslog (LOG_ERR, _("DES entry for netname %s not unique\n"), netname);
+ nis_freeresult (res);
+ return NSS_STATUS_SUCCESS;
+ }
+
+- len = ENTRY_LEN (res->objects.objects_val, 4);
+- memcpy (buf, ENTRY_VAL (res->objects.objects_val,4), len);
++ len = ENTRY_LEN (NIS_RES_OBJECT (res), 4);
++ memcpy (buf, ENTRY_VAL (NIS_RES_OBJECT (res), 4), len);
+ buf[len] = '\0';
+ cptr = strchr (buf, ':');
+ if (cptr)
+@@ -204,6 +205,7 @@ _nss_nisplus_getsecretkey (const char *n
+ return NSS_STATUS_SUCCESS;
+ }
+
++
+ /* Parse information from the passed string.
+ The format of the string passed is gid,grp,grp, ... */
+ static enum nss_status
+@@ -224,8 +226,12 @@ parse_grp_str (const char *s, gid_t *gid
+ gidlen = 0;
+
+ /* After strtoul() ep should point to the marker ',', which means
+- here starts a new value. */
+- while (ep != NULL && *ep == ',')
++ here starts a new value.
++
++ The Sun man pages show that GIDLIST should contain at least NGRPS
++ elements. Limiting the number written by this value is the best
++ we can do. */
++ while (ep != NULL && *ep == ',' && gidlen < NGRPS)
+ {
+ ep++;
+ s = ep;
+@@ -305,7 +311,7 @@ _nss_nisplus_netname2user (char netname[
+ return NSS_STATUS_UNAVAIL;
+ }
+
+- if (res->objects.objects_len > 1)
++ if (NIS_RES_NUMOBJ (res) > 1)
+ /*
+ * A netname belonging to more than one principal?
+ * Something wrong with cred table. should be unique.
+@@ -315,8 +321,8 @@ _nss_nisplus_netname2user (char netname[
+ _("netname2user: DES entry for %s in directory %s not unique"),
+ netname, domain);
+
+- len = ENTRY_LEN (res->objects.objects_val, 0);
+- strncpy (principal, ENTRY_VAL (res->objects.objects_val, 0), len);
++ len = ENTRY_LEN (NIS_RES_OBJECT (res), 0);
++ strncpy (principal, ENTRY_VAL (NIS_RES_OBJECT (res), 0), len);
+ principal[len] = '\0';
+ nis_freeresult (res);
+
+@@ -328,7 +334,7 @@ _nss_nisplus_netname2user (char netname[
+ * LOCAL entry in **local** cred table.
+ */
+ domain = nis_local_directory ();
+- if ((strlen (principal) + strlen (domain) + 45) > (size_t) NIS_MAXNAMELEN)
++ if (strlen (principal) + strlen (domain) + 45 > (size_t) NIS_MAXNAMELEN)
+ {
+ syslog (LOG_ERR, _("netname2user: principal name `%s' too long"),
+ principal);
+@@ -379,7 +385,7 @@ _nss_nisplus_netname2user (char netname[
+ return NSS_STATUS_UNAVAIL;
+ }
+
+- if (res->objects.objects_len > 1)
++ if (NIS_RES_NUMOBJ (res) > 1)
+ /*
+ * A principal can have more than one LOCAL entry?
+ * Something wrong with cred table.
+@@ -389,7 +395,7 @@ _nss_nisplus_netname2user (char netname[
+ _("netname2user: LOCAL entry for %s in directory %s not unique"),
+ netname, domain);
+ /* Fetch the uid */
+- *uidp = strtoul (ENTRY_VAL (res->objects.objects_val, 2), NULL, 10);
++ *uidp = strtoul (ENTRY_VAL (NIS_RES_OBJECT (res), 2), NULL, 10);
+
+ if (*uidp == 0)
+ {
+@@ -398,7 +404,7 @@ _nss_nisplus_netname2user (char netname[
+ return NSS_STATUS_NOTFOUND;
+ }
+
+- parse_grp_str (ENTRY_VAL (res->objects.objects_val, 3),
++ parse_grp_str (ENTRY_VAL (NIS_RES_OBJECT (res), 3),
+ gidp, gidlenp, gidlist, errnop);
+
+ nis_freeresult (res);
+--- libc/nis/nss_nisplus/nisplus-pwd.c 25 Mar 2006 20:59:19 -0000 1.21
++++ libc/nis/nss_nisplus/nisplus-pwd.c 29 Apr 2006 20:19:09 -0000 1.22
+@@ -28,10 +28,18 @@
+
+ #include "nss-nisplus.h"
+ #include "nisplus-parser.h"
++#include <libnsl.h>
++
+
+ __libc_lock_define_initialized (static, lock)
+
++/* Previous result of iteration. */
+ static nis_result *result;
++
++/* All results of batch table load. */
++static nis_result *cached_results;
++static size_t cached_results_iter;
++
+ nis_name pwd_tablename_val attribute_hidden;
+ size_t pwd_tablename_len attribute_hidden;
+
+@@ -69,95 +77,195 @@ _nss_pwd_create_tablename (int *errnop)
+ }
+
+
+-enum nss_status
+-_nss_nisplus_setpwent (int stayopen)
++static void
++internal_nisplus_endpwent (void)
+ {
+- enum nss_status status = NSS_STATUS_SUCCESS;
+-
+- __libc_lock_lock (lock);
++ if (cached_results != NULL)
++ {
++ nis_freeresult (cached_results);
++ cached_results = NULL;
++ cached_results_iter = 0;
++ }
+
+ if (result != NULL)
+ {
+ nis_freeresult (result);
+ result = NULL;
+ }
++}
++
++
++static enum nss_status
++internal_nisplus_setpwent (int *errnop)
++{
++ enum nss_status status;
++
++ cached_results = nis_list (pwd_tablename_val, FOLLOW_PATH | FOLLOW_LINKS,
++ NULL, NULL);
++
++ if (cached_results == NULL)
++ {
++ *errnop = errno;
++ status = NSS_STATUS_TRYAGAIN;
++ }
++ else if (__builtin_expect ((status = niserr2nss (cached_results->status))
++ != NSS_STATUS_SUCCESS, 0))
++ {
++ nis_freeresult (cached_results);
++ cached_results = NULL;
++ }
++ else if (__builtin_expect (__type_of (NIS_RES_OBJECT (cached_results))
++ != NIS_ENTRY_OBJ
++ || strcmp (NIS_RES_OBJECT (cached_results)->EN_data.en_type,
++ "passwd_tbl") != 0
++ || NIS_RES_OBJECT (cached_results)->EN_data.en_cols.en_cols_len < 7,
++ 0))
++ {
++ nis_freeresult (cached_results);
++ cached_results = NULL;
++ status = NSS_STATUS_NOTFOUND;
++ }
++
++ return status;
++}
++
++
++enum nss_status
++_nss_nisplus_setpwent (int stayopen)
++{
++ enum nss_status status = NSS_STATUS_SUCCESS;
++
++ __libc_lock_lock (lock);
++
++ internal_nisplus_endpwent ();
+
+ if (pwd_tablename_val == NULL)
+ {
++ // XXX We need to be able to set errno. Pass in new parameter.
+ int err;
+ status = _nss_pwd_create_tablename (&err);
+ }
+
++ if (status == NSS_STATUS_SUCCESS
++ && (_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ))
++ {
++ // XXX We need to be able to set errno. Pass in new parameter.
++ int err;
++ status = internal_nisplus_setpwent (&err);
++ }
++
+ __libc_lock_unlock (lock);
+
+ return status;
+ }
+
++
+ enum nss_status
+ _nss_nisplus_endpwent (void)
+ {
+ __libc_lock_lock (lock);
+
+- if (result != NULL)
+- {
+- nis_freeresult (result);
+- result = NULL;
+- }
++ internal_nisplus_endpwent ();
+
+ __libc_lock_unlock (lock);
+
+ return NSS_STATUS_SUCCESS;
+ }
+
++
+ static enum nss_status
+ internal_nisplus_getpwent_r (struct passwd *pw, char *buffer, size_t buflen,
+ int *errnop)
+ {
+- int parse_res;
++ int parse_res = -1;
++ nis_result *saved_res = NULL;
+
+ /* Get the next entry until we found a correct one. */
+ do
+ {
+- nis_result *saved_res;
+-
+- if (result == NULL)
++ if (cached_results != NULL)
+ {
+- saved_res = NULL;
+- if (pwd_tablename_val == NULL)
+- {
+- enum nss_status status = _nss_pwd_create_tablename (errnop);
+-
+- if (status != NSS_STATUS_SUCCESS)
+- return status;
+- }
+-
+- result = nis_first_entry (pwd_tablename_val);
+- if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+- return niserr2nss (result->status);
++ handle_batch_read:
++ /* See whether we reported the last problem. */
++ if (cached_results_iter >= NIS_RES_NUMOBJ (cached_results))
++ return NSS_STATUS_NOTFOUND;
++
++ parse_res = _nss_nisplus_parse_pwent (cached_results,
++ cached_results_iter, pw,
++ buffer, buflen, errnop);
+ }
+ else
+ {
+- saved_res = result;
+- result = nis_next_entry (pwd_tablename_val, &result->cookie);
+- if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
++ if (result == NULL)
++ {
++ if (pwd_tablename_val == NULL)
++ {
++ enum nss_status status = _nss_pwd_create_tablename (errnop);
++
++ if (status != NSS_STATUS_SUCCESS)
++ return status;
++ }
++
++ /* Determine whether we should instead read all entries at
++ once. */
++ if (_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ)
++ {
++ enum nss_status status = internal_nisplus_setpwent (errnop);
++
++ if (status == NSS_STATUS_SUCCESS && cached_results != NULL)
++ goto handle_batch_read;
++ }
++
++ saved_res = NULL;
++
++ result = nis_first_entry (pwd_tablename_val);
++ if (result == NULL)
++ {
++ *errnop = errno;
++ return NSS_STATUS_TRYAGAIN;
++ }
++ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
++ return niserr2nss (result->status);
++ }
++ else
+ {
+- nis_freeresult (saved_res);
+- return niserr2nss (result->status);
++ saved_res = result;
++ result = nis_next_entry (pwd_tablename_val, &result->cookie);
++ if (result == NULL)
++ {
++ *errnop = errno;
++ return NSS_STATUS_TRYAGAIN;
++ }
++ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
++ {
++ nis_freeresult (saved_res);
++ return niserr2nss (result->status);
++ }
+ }
++
++ parse_res = _nss_nisplus_parse_pwent_chk (result, pw, buffer,
++ buflen, errnop);
+ }
+
+- parse_res = _nss_nisplus_parse_pwent (result, pw, buffer,
+- buflen, errnop);
+ if (__builtin_expect (parse_res == -1, 0))
+ {
+- nis_freeresult (result);
+- result = saved_res;
++ if (cached_results == NULL)
++ {
++ nis_freeresult (result);
++ result = saved_res;
++ }
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- if (saved_res)
+- nis_freeresult (saved_res);
++ if (cached_results != NULL)
++ ++cached_results_iter;
++ else
++ if (saved_res)
++ {
++ nis_freeresult (saved_res);
++ saved_res = NULL;
++ }
+ }
+ while (!parse_res);
+
+@@ -223,7 +331,8 @@ _nss_nisplus_getpwnam_r (const char *nam
+ return status;
+ }
+
+- parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop);
++ parse_res = _nss_nisplus_parse_pwent_chk (result, pw, buffer, buflen,
++ errnop);
+
+ nis_freeresult (result);
+
+@@ -282,7 +391,8 @@ _nss_nisplus_getpwuid_r (const uid_t uid
+ return status;
+ }
+
+- parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop);
++ parse_res = _nss_nisplus_parse_pwent_chk (result, pw, buffer, buflen,
++ errnop);
+
+ nis_freeresult (result);
+
+--- libc/nis/nss_nisplus/nisplus-rpc.c 25 Mar 2006 20:59:19 -0000 1.21
++++ libc/nis/nss_nisplus/nisplus-rpc.c 30 Apr 2006 05:44:23 -0000 1.23
+@@ -35,11 +35,12 @@ static nis_result *result;
+ static nis_name tablename_val;
+ static u_long tablename_len;
+
+-#define NISENTRYVAL(idx,col,res) \
+- ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
++#define NISENTRYVAL(idx, col, res) \
++ (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
++
++#define NISENTRYLEN(idx, col, res) \
++ (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
+
+-#define NISENTRYLEN(idx,col,res) \
+- ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
+
+ static int
+ _nss_nisplus_parse_rpcent (nis_result *result, struct rpcent *rpc,
+@@ -48,17 +49,16 @@ _nss_nisplus_parse_rpcent (nis_result *r
+ char *first_unused = buffer;
+ size_t room_left = buflen;
+ unsigned int i;
+- char *p, *line;
++ char *line;
+
+
+ if (result == NULL)
+ return 0;
+
+ if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
+- || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
+- || strcmp (result->objects.objects_val[0].EN_data.en_type,
+- "rpc_tbl") != 0
+- || result->objects.objects_val[0].EN_data.en_cols.en_cols_len < 3)
++ || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
++ || strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type, "rpc_tbl") != 0
++ || NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 3)
+ return 0;
+
+ if (NISENTRYLEN (0, 0, result) >= room_left)
+@@ -71,37 +71,43 @@ _nss_nisplus_parse_rpcent (nis_result *r
+ NISENTRYLEN (0, 0, result));
+ first_unused[NISENTRYLEN (0, 0, result)] = '\0';
+ rpc->r_name = first_unused;
+- room_left -= (strlen (first_unused) + 1);
+- first_unused += strlen (first_unused) + 1;
++ size_t len = strlen (first_unused) + 1;
++ room_left -= len;
++ first_unused += len;
++
+ rpc->r_number = atoi (NISENTRYVAL (0, 2, result));
+- p = first_unused;
+
+- line = p;
+- for (i = 0; i < result->objects.objects_len; ++i)
++ /* XXX Rewrite at some point to allocate the array first and then
++ copy the strings. It wasteful to first concatenate the strings
++ to just split them again later. */
++ line = first_unused;
++ for (i = 0; i < NIS_RES_NUMOBJ (result); ++i)
+ {
+ if (strcmp (NISENTRYVAL (i, 1, result), rpc->r_name) != 0)
+ {
+ if (NISENTRYLEN (i, 1, result) + 2 > room_left)
+ goto no_more_room;
+- *p++ = ' ';
+- p = __stpncpy (p, NISENTRYVAL (i, 1, result),
+- NISENTRYLEN (i, 1, result));
+- *p = '\0';
+- room_left -= (NISENTRYLEN (i, 1, result) + 1);
++ *first_unused++ = ' ';
++ first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result),
++ NISENTRYLEN (i, 1, result));
++ room_left -= NISENTRYLEN (i, 1, result) + 1;
+ }
+ }
+- ++p;
+- first_unused = p;
++ *first_unused++ = '\0';
+
+ /* Adjust the pointer so it is aligned for
+ storing pointers. */
+- first_unused += __alignof__ (char *) - 1;
+- first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
+- rpc->r_aliases = (char **) first_unused;
+- if (room_left < sizeof (char *))
++ size_t adjust = ((__alignof__ (char *)
++ - (first_unused - (char *) 0) % __alignof__ (char *))
++ % __alignof__ (char *));
++ if (room_left < adjust + sizeof (char *))
+ goto no_more_room;
++ first_unused += adjust;
++ room_left -= adjust;
++ rpc->r_aliases = (char **) first_unused;
++
++ /* For the terminating NULL pointer. */
+ room_left -= sizeof (char *);
+- rpc->r_aliases[0] = NULL;
+
+ i = 0;
+ while (*line != '\0')
+@@ -117,24 +123,20 @@ _nss_nisplus_parse_rpcent (nis_result *r
+ goto no_more_room;
+
+ room_left -= sizeof (char *);
+- rpc->r_aliases[i] = line;
++ rpc->r_aliases[i++] = line;
+
+ while (*line != '\0' && *line != ' ')
+ ++line;
+
+ if (*line == ' ')
+- {
+- *line = '\0';
+- ++line;
+- ++i;
+- }
+- else
+- rpc->r_aliases[i+1] = NULL;
++ *line++ = '\0';
+ }
++ rpc->r_aliases[i] = NULL;
+
+ return 1;
+ }
+
++
+ static enum nss_status
+ _nss_create_tablename (int *errnop)
+ {
+@@ -227,6 +229,11 @@ internal_nisplus_getrpcent_r (struct rpc
+ }
+
+ result = nis_first_entry (tablename_val);
++ if (result == NULL)
++ {
++ *errnop = errno;
++ return NSS_STATUS_TRYAGAIN;
++ }
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ return niserr2nss (result->status);
+ }
+@@ -234,6 +241,11 @@ internal_nisplus_getrpcent_r (struct rpc
+ {
+ saved_res = result;
+ result = nis_next_entry (tablename_val, &result->cookie);
++ if (result == NULL)
++ {
++ *errnop = errno;
++ return NSS_STATUS_TRYAGAIN;
++ }
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ {
+ nis_freeresult (saved_res);
+--- libc/nis/nss_nisplus/nisplus-service.c 25 Mar 2006 20:59:19 -0000 1.23
++++ libc/nis/nss_nisplus/nisplus-service.c 30 Apr 2006 05:44:23 -0000 1.25
+@@ -35,11 +35,12 @@ static nis_result *result;
+ static nis_name tablename_val;
+ static u_long tablename_len;
+
+-#define NISENTRYVAL(idx,col,res) \
+- ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
++#define NISENTRYVAL(idx, col, res) \
++ (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
++
++#define NISENTRYLEN(idx, col, res) \
++ (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
+
+-#define NISENTRYLEN(idx,col,res) \
+- ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_len)
+
+ static int
+ _nss_nisplus_parse_servent (nis_result *result, struct servent *serv,
+@@ -52,10 +53,9 @@ _nss_nisplus_parse_servent (nis_result *
+ return 0;
+
+ if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
+- || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
+- || strcmp (result->objects.objects_val->EN_data.en_type,
+- "services_tbl") != 0
+- || result->objects.objects_val->EN_data.en_cols.en_cols_len < 4)
++ || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
++ || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type, "services_tbl") != 0
++ || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 4)
+ return 0;
+
+ if (NISENTRYLEN (0, 0, result) >= room_left)
+@@ -68,8 +68,9 @@ _nss_nisplus_parse_servent (nis_result *
+ NISENTRYLEN (0, 0, result));
+ first_unused[NISENTRYLEN (0, 0, result)] = '\0';
+ serv->s_name = first_unused;
+- room_left -= (strlen (first_unused) +1);
+- first_unused += strlen (first_unused) +1;
++ size_t len = strlen (first_unused) + 1;
++ room_left -= len;
++ first_unused += len;
+
+ if (NISENTRYLEN (0, 2, result) >= room_left)
+ goto no_more_room;
+@@ -77,38 +78,43 @@ _nss_nisplus_parse_servent (nis_result *
+ NISENTRYLEN (0, 2, result));
+ first_unused[NISENTRYLEN (0, 2, result)] = '\0';
+ serv->s_proto = first_unused;
+- room_left -= strlen (first_unused) + 1;
+- first_unused += strlen (first_unused) + 1;
++ len = strlen (first_unused) + 1;
++ room_left -= len;
++ first_unused += len;
+
+ serv->s_port = htons (atoi (NISENTRYVAL (0, 3, result)));
+- char *p = first_unused;
+
+- char *line = p;
+- for (unsigned int i = 0; i < result->objects.objects_len; ++i)
++ /* XXX Rewrite at some point to allocate the array first and then
++ copy the strings. It wasteful to first concatenate the strings
++ to just split them again later. */
++ char *line = first_unused;
++ for (unsigned int i = 0; i < NIS_RES_NUMOBJ (result); ++i)
+ {
+ if (strcmp (NISENTRYVAL (i, 1, result), serv->s_name) != 0)
+ {
+ if (NISENTRYLEN (i, 1, result) + 2 > room_left)
+ goto no_more_room;
+- *p++ = ' ';
+- p = __stpncpy (p, NISENTRYVAL (i, 1, result),
+- NISENTRYLEN (i, 1, result));
+- *p = '\0';
+- room_left -= (NISENTRYLEN (i, 1, result) + 1);
++ *first_unused++ = ' ';
++ first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result),
++ NISENTRYLEN (i, 1, result));
++ room_left -= NISENTRYLEN (i, 1, result) + 1;
+ }
+ }
+- *p++ = '\0';
+- first_unused = p;
++ *first_unused++ = '\0';
+
+ /* Adjust the pointer so it is aligned for
+ storing pointers. */
+- first_unused += __alignof__ (char *) - 1;
+- first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
+- serv->s_aliases = (char **) first_unused;
+- if (room_left < sizeof (char *))
++ size_t adjust = ((__alignof__ (char *)
++ - (first_unused - (char *) 0) % __alignof__ (char *))
++ % __alignof__ (char *));
++ if (room_left < adjust + sizeof (char *))
+ goto no_more_room;
++ first_unused += adjust;
++ room_left -= adjust;
++ serv->s_aliases = (char **) first_unused;
++
++ /* For the terminating NULL pointer. */
+ room_left -= (sizeof (char *));
+- serv->s_aliases[0] = NULL;
+
+ unsigned int i = 0;
+ while (*line != '\0')
+@@ -124,24 +130,20 @@ _nss_nisplus_parse_servent (nis_result *
+ goto no_more_room;
+
+ room_left -= sizeof (char *);
+- serv->s_aliases[i] = line;
++ serv->s_aliases[i++] = line;
+
+ while (*line != '\0' && *line != ' ')
+ ++line;
+
+ if (*line == ' ')
+- {
+- *line = '\0';
+- ++line;
+- ++i;
+- }
+- else
+- serv->s_aliases[i+1] = NULL;
++ *line++ = '\0';
+ }
++ serv->s_aliases[i] = NULL;
+
+ return 1;
+ }
+
++
+ static enum nss_status
+ _nss_create_tablename (int *errnop)
+ {
+@@ -232,6 +234,11 @@ internal_nisplus_getservent_r (struct se
+ }
+
+ result = nis_first_entry (tablename_val);
++ if (result == NULL)
++ {
++ *errnop = errno;
++ return NSS_STATUS_TRYAGAIN;
++ }
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ return niserr2nss (result->status);
+ }
+@@ -239,6 +246,11 @@ internal_nisplus_getservent_r (struct se
+ {
+ saved_res = result;
+ result = nis_next_entry (tablename_val, &result->cookie);
++ if (result == NULL)
++ {
++ *errnop = errno;
++ return NSS_STATUS_TRYAGAIN;
++ }
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ {
+ nis_freeresult (saved_res);
+@@ -320,10 +332,10 @@ _nss_nisplus_getservbyname_r (const char
+ database is correct, we should find it in the first case, too */
+ if ((result->status != NIS_SUCCESS
+ && result->status != NIS_S_SUCCESS)
+- || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
+- || strcmp (result->objects.objects_val->EN_data.en_type,
++ || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
++ || strcmp (NIS_RES_OBJECT (result)->EN_data.en_type,
+ "services_tbl") != 0
+- || result->objects.objects_val->EN_data.en_cols.en_cols_len < 4)
++ || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 4)
+ snprintf (buf, sizeof (buf), "[cname=%s,proto=%s],%s", name, protocol,
+ tablename_val);
+ else
+--- libc/nis/nss_nisplus/nisplus-spwd.c 3 Dec 2005 20:38:57 -0000 1.19
++++ libc/nis/nss_nisplus/nisplus-spwd.c 30 Apr 2006 05:44:23 -0000 1.20
+@@ -99,6 +99,11 @@ internal_nisplus_getspent_r (struct spwd
+ }
+
+ result = nis_first_entry (pwd_tablename_val);
++ if (result == NULL)
++ {
++ *errnop = errno;
++ return NSS_STATUS_TRYAGAIN;
++ }
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ return niserr2nss (result->status);
+ }
+@@ -106,6 +111,11 @@ internal_nisplus_getspent_r (struct spwd
+ {
+ saved_res = result;
+ result = nis_next_entry (pwd_tablename_val, &result->cookie);
++ if (result == NULL)
++ {
++ *errnop = errno;
++ return NSS_STATUS_TRYAGAIN;
++ }
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ {
+ nis_freeresult (saved_res);
+--- libc/nis/libnsl.h 1 Jan 1970 00:00:00 -0000
++++ libc/nis/libnsl.h 28 Apr 2006 21:01:49 -0000 1.2
+@@ -0,0 +1,25 @@
++/* Copyright (C) 2005, 2006 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#define NSS_FLAG_NETID_AUTHORITATIVE 1
++#define NSS_FLAG_SERVICES_AUTHORITATIVE 2
++#define NSS_FLAG_SETENT_BATCH_READ 4
++
++
++/* Get current set of default flags. */
++extern int _nsl_default_nss (void);
+--- libc/nis/nss-default.c 2006-04-19 19:21:31.748476000 +0200
++++ libc/nis/nss-default.c 2006-05-03 21:38:01.000000000 +0200
+@@ -0,0 +1,124 @@
++/* Copyright (C) 1996, 2001, 2004, 2006 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <ctype.h>
++#include <stdio.h>
++#include <stdio_ext.h>
++#include <stdlib.h>
++#include <string.h>
++#include <bits/libc-lock.h>
++
++#include <libnsl.h>
++
++
++/* Path of the file. */
++static const char default_nss[] = "/etc/default/nss";
++
++/* Flags once read from the file. */
++static int default_nss_flags;
++
++/* Code to make sure we call 'init' once. */
++__libc_once_define (static, once);
++
++/* Table of the recognized variables. */
++static const struct
++{
++ char name[23];
++ unsigned int len;
++ int flag;
++} vars[] =
++ {
++#define STRNLEN(s) s, sizeof (s) - 1
++ { STRNLEN ("NETID_AUTHORITATIVE"), NSS_FLAG_NETID_AUTHORITATIVE },
++ { STRNLEN ("SERVICES_AUTHORITATIVE"), NSS_FLAG_SERVICES_AUTHORITATIVE },
++ { STRNLEN ("SETENT_BATCH_READ"), NSS_FLAG_SETENT_BATCH_READ }
++ };
++#define nvars (sizeof (vars) / sizeof (vars[0]))
++
++
++static void
++init (void)
++{
++ FILE *fp = fopen (default_nss, "rc");
++ if (fp != NULL)
++ {
++ char *line = NULL;
++ size_t linelen = 0;
++
++ __fsetlocking (fp, FSETLOCKING_BYCALLER);
++
++ while (!feof_unlocked (fp))
++ {
++ ssize_t n = getline (&line, &linelen, fp);
++ if (n <= 0)
++ break;
++
++ /* Recognize only
++
++ <THE-VARIABLE> = TRUE
++
++ with arbitrary white spaces. */
++ char *cp = line;
++ while (isspace (*cp))
++ ++cp;
++
++ /* Recognize comment lines. */
++ if (*cp == '#')
++ continue;
++
++ int idx;
++ for (idx = 0; idx < nvars; ++idx)
++ if (strncmp (cp, vars[idx].name, vars[idx].len) == 0)
++ break;
++ if (idx == nvars)
++ continue;
++
++ cp += vars[idx].len;
++ while (isspace (*cp))
++ ++cp;
++ if (*cp++ != '=')
++ continue;
++ while (isspace (*cp))
++ ++cp;
++
++ if (strncmp (cp, "TRUE", 4) != 0)
++ continue;
++ cp += 4;
++
++ while (isspace (*cp))
++ ++cp;
++
++ if (*cp == '\0')
++ default_nss_flags |= vars[idx].flag;
++ }
++
++ free (line);
++
++ fclose (fp);
++ }
++}
++
++
++int
++_nsl_default_nss (void)
++{
++ /* If we have not yet read the file yet do it now. */
++ __libc_once (once, init);
++
++ return default_nss_flags;
++}
--- /dev/null
+2006-05-18 Jakub Jelinek <jakub@redhat.com>
+
+ * nis/nss_compat/compat-pwd.c (internal_setpwent): If nss_set*ent
+ returned NSS_STATUS_UNAVAIL, still return NSS_STATUS_SUCCESS.
+ * nis/nss_compat/compat-spwd.c (internal_setspent): Likewise.
+ * nis/nss_compat/compat-grp.c (internal_setgrent): Likewise.
+
+--- libc/nis/nss_compat/compat-grp.c 6 Jul 2005 21:04:53 -0000 1.30
++++ libc/nis/nss_compat/compat-grp.c 18 May 2006 14:51:05 -0000 1.31
+@@ -138,7 +138,11 @@ internal_setgrent (ent_t *ent, int stayo
+ rewind (ent->stream);
+
+ if (status == NSS_STATUS_SUCCESS && nss_setgrent)
+- return nss_setgrent (stayopen);
++ {
++ status = nss_setgrent (stayopen);
++ if (status == NSS_STATUS_UNAVAIL)
++ status = NSS_STATUS_SUCCESS;
++ }
+
+ return status;
+ }
+--- libc/nis/nss_compat/compat-pwd.c 6 Jul 2005 21:03:32 -0000 1.35
++++ libc/nis/nss_compat/compat-pwd.c 18 May 2006 14:51:05 -0000 1.36
+@@ -258,7 +258,11 @@ internal_setpwent (ent_t *ent, int stayo
+ give_pwd_free (&ent->pwd);
+
+ if (status == NSS_STATUS_SUCCESS && nss_setpwent)
+- return nss_setpwent (stayopen);
++ {
++ status = nss_setpwent (stayopen);
++ if (status == NSS_STATUS_UNAVAIL)
++ status = NSS_STATUS_SUCCESS;
++ }
+
+ return status;
+ }
+--- libc/nis/nss_compat/compat-spwd.c 6 Jul 2005 21:02:30 -0000 1.28
++++ libc/nis/nss_compat/compat-spwd.c 18 May 2006 14:51:05 -0000 1.29
+@@ -212,7 +212,11 @@ internal_setspent (ent_t *ent, int stayo
+ give_spwd_free (&ent->pwd);
+
+ if (status == NSS_STATUS_SUCCESS && nss_setspent)
+- return nss_setspent (stayopen);
++ {
++ status = nss_setspent (stayopen);
++ if (status == NSS_STATUS_UNAVAIL)
++ status = NSS_STATUS_SUCCESS;
++ }
+
+ return status;
+ }
--- /dev/null
+2006-08-07 Jakub Jelinek <jakub@redhat.com>
+ Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nis_call.c (rec_dirsearch) [case LOWER_NAME]: Don't take
+ short cut if only one name component is stripped away.
+
+2006-08-07 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nis_call.c: Minor cleanups throughout.
+ (rec_dirsearch) [HIGHER_NAME]: Correctly size ndomain array.
+ (first_shoot): Add search_parent_first parameter. Only if it is set
+ search parent server first.
+ If directory for table found through cold start cache is not the same
+ as referenced in the cache, don't use it.
+ (__nisfind_server): Take additional parameter. Pass it on to
+ first_shoot.
+ (__prepare_niscall): Adjust __nisfind_server call.
+ * nis/rpcsvc/nislib.h: Adjust __nisfind_server prototype.
+ * nis/nis_table.c: Adjust __nisfind_server call.
+ * nis/nis_lookup.c: Likewise.
+ (nis_lookup): Don't loop endlessly if name is reduced to ".".
+
+--- libc/nis/nis_call.c 24 May 2006 07:30:09 -0000 1.29.4.6
++++ libc/nis/nis_call.c 7 Aug 2006 19:24:42 -0000
+@@ -125,7 +125,7 @@ __nisbind_connect (dir_binding *dbp)
+ dbp->addr.sin_addr.s_addr =
+ inetstr2int (serv->ep.ep_val[dbp->current_ep].uaddr);
+
+- if (dbp->addr.sin_addr.s_addr == 0)
++ if (dbp->addr.sin_addr.s_addr == INADDR_NONE)
+ return NIS_FAIL;
+
+ /* Check, if the host is online and rpc.nisd is running. Much faster
+@@ -340,7 +340,7 @@ rec_dirsearch (const_nis_name name, dire
+ case HIGHER_NAME:
+ { /* We need data from a parent domain */
+ directory_obj *obj;
+- char ndomain [strlen (name) + 3];
++ char ndomain[strlen (dir->do_name) + 3];
+
+ nis_domain_of_r (dir->do_name, ndomain, sizeof (ndomain));
+
+@@ -388,7 +388,6 @@ rec_dirsearch (const_nis_name name, dire
+ char domain[namelen + 3];
+ char ndomain[namelen + 3];
+ char *cp;
+- u_int run = 0;
+
+ strcpy (domain, name);
+
+@@ -402,16 +401,9 @@ rec_dirsearch (const_nis_name name, dire
+ nis_leaf_of_r (domain, leaf, sizeof (leaf));
+ nis_domain_of_r (domain, ndomain, sizeof (ndomain));
+ strcpy (domain, ndomain);
+- ++run;
+ }
+ while (nis_dir_cmp (domain, dir->do_name) != SAME_NAME);
+
+- if (run == 1)
+- {
+- /* We have found the directory above. Use it. */
+- return dir;
+- }
+-
+ cp = strchr (leaf, '\0');
+ *cp++ = '.';
+ strcpy (cp, domain);
+@@ -461,31 +453,44 @@ rec_dirsearch (const_nis_name name, dire
+ /* We try to query the current server for the searched object,
+ maybe he know about it ? */
+ static directory_obj *
+-first_shoot (const_nis_name name, directory_obj *dir)
++first_shoot (const_nis_name name, int search_parent_first, directory_obj *dir)
+ {
+ directory_obj *obj = NULL;
+ fd_result *fd_res;
+ XDR xdrs;
+ char domain[strlen (name) + 3];
+
++#if 0
+ if (nis_dir_cmp (name, dir->do_name) == SAME_NAME)
+ return dir;
++#endif
+
+- nis_domain_of_r (name, domain, sizeof (domain));
++ const char *search_name = name;
++ if (search_parent_first)
++ {
++ nis_domain_of_r (name, domain, sizeof (domain));
++ search_name = domain;
++ }
+
+- if (nis_dir_cmp (domain, dir->do_name) == SAME_NAME)
++ if (nis_dir_cmp (search_name, dir->do_name) == SAME_NAME)
+ return dir;
+
+- fd_res = __nis_finddirectory (dir, domain);
++ fd_res = __nis_finddirectory (dir, search_name);
+ if (fd_res == NULL)
+ return NULL;
+ if (fd_res->status == NIS_SUCCESS
+ && (obj = calloc (1, sizeof (directory_obj))) != NULL)
+ {
+- xdrmem_create(&xdrs, fd_res->dir_data.dir_data_val,
+- fd_res->dir_data.dir_data_len, XDR_DECODE);
++ xdrmem_create (&xdrs, fd_res->dir_data.dir_data_val,
++ fd_res->dir_data.dir_data_len, XDR_DECODE);
+ _xdr_directory_obj (&xdrs, obj);
+ xdr_destroy (&xdrs);
++
++ if (strcmp (dir->do_name, obj->do_name) != 0)
++ {
++ nis_free_directory (obj);
++ obj = NULL;
++ }
+ }
+
+ __free_fdresult (fd_res);
+@@ -497,7 +502,8 @@ first_shoot (const_nis_name name, direct
+ }
+
+ nis_error
+-__nisfind_server (const_nis_name name, directory_obj **dir)
++__nisfind_server (const_nis_name name, int search_parent_first,
++ directory_obj **dir)
+ {
+ if (name == NULL)
+ return NIS_BADNAME;
+@@ -520,7 +526,7 @@ __nisfind_server (const_nis_name name, d
+ return NIS_UNAVAIL;
+
+ /* Try at first, if servers in "dir" know our object */
+- obj = first_shoot (name, *dir);
++ obj = first_shoot (name, search_parent_first, *dir);
+ if (obj == NULL)
+ {
+ obj = rec_dirsearch (name, *dir, &status);
+@@ -539,7 +545,7 @@ nis_error
+ __prepare_niscall (const_nis_name name, directory_obj **dirp,
+ dir_binding *bptrp, unsigned int flags)
+ {
+- nis_error retcode = __nisfind_server (name, dirp);
++ nis_error retcode = __nisfind_server (name, 1, dirp);
+ if (__builtin_expect (retcode != NIS_SUCCESS, 0))
+ return retcode;
+
+--- libc/nis/nis_lookup.c 24 May 2006 07:30:09 -0000 1.13.4.4
++++ libc/nis/nis_lookup.c 7 Aug 2006 19:24:42 -0000
+@@ -127,7 +127,7 @@ nis_lookup (const_nis_name name, const u
+ /* Otherwise __nisfind_server will not do anything. */
+ dir = NULL;
+
+- if (__nisfind_server (req.ns_name, &dir)
++ if (__nisfind_server (req.ns_name, 1, &dir)
+ != NIS_SUCCESS)
+ goto out;
+
+@@ -147,6 +147,11 @@ nis_lookup (const_nis_name name, const u
+ nis_domain_of_r (req.ns_name, ndomain,
+ sizeof (ndomain));
+ req.ns_name = strdupa (ndomain);
++ if (strcmp (ndomain, ".") == 0)
++ {
++ NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
++ goto out;
++ }
+
+ __nisbind_destroy (&bptr);
+ nis_free_directory (dir);
+--- libc/nis/nis_table.c 21 May 2006 22:00:48 -0000 1.22.2.7
++++ libc/nis/nis_table.c 7 Aug 2006 19:24:42 -0000
+@@ -271,7 +271,8 @@ nis_list (const_nis_name name, unsigned
+
+ memset (res, '\0', sizeof (nis_result));
+
+- status = __nisfind_server (ibreq->ibr_name, &dir);
++ status = __nisfind_server (ibreq->ibr_name,
++ ibreq->ibr_srch.ibr_srch_val != NULL, &dir);
+ if (status != NIS_SUCCESS)
+ {
+ NIS_RES_STATUS (res) = status;
+--- libc/nis/rpcsvc/nislib.h 6 Jul 2001 04:55:37 -0000 1.14
++++ libc/nis/rpcsvc/nislib.h 7 Aug 2006 19:24:42 -0000
+@@ -276,7 +276,8 @@ extern nis_error __nisbind_create (dir_b
+ extern nis_error __nisbind_connect (dir_binding *) __THROW;
+ extern nis_error __nisbind_next (dir_binding *) __THROW;
+ extern void __nisbind_destroy (dir_binding *) __THROW;
+-extern nis_error __nisfind_server (const_nis_name, directory_obj **) __THROW;
++extern nis_error __nisfind_server (const_nis_name, int, directory_obj **)
++ __THROW;
+
+ #endif
+
--- /dev/null
+2006-12-05 Jakub Jelinek <jakub@redhat.com>
+
+ * nis/nis_subr.c (nis_getnames): Revert last change.
+
+2006-10-11 Jakub Jelinek <jakub@redhat.com>
+
+ * nis/nis_defaults.c (__nis_default_access): Don't call getenv twice.
+
+ * nis/nis_subr.c (nis_getnames): Use __secure_getenv instead of getenv.
+ * sysdeps/generic/unsecvars.h: Add NIS_PATH.
+
+--- libc/nis/nis_defaults.c 10 May 2006 02:54:46 -0000 1.8
++++ libc/nis/nis_defaults.c 11 Oct 2006 16:22:34 -0000 1.9
+@@ -447,7 +447,7 @@ __nis_default_access (char *param, unsig
+ {
+ cptr = getenv ("NIS_DEFAULTS");
+ if (cptr != NULL && strstr (cptr, "access=") != NULL)
+- result = searchaccess (getenv ("NIS_DEFAULTS"), result);
++ result = searchaccess (cptr, result);
+ }
+
+ return result;
+--- libc/sysdeps/generic/unsecvars.h 6 Jan 2005 22:40:19 -0000 1.8
++++ libc/sysdeps/generic/unsecvars.h 11 Oct 2006 16:24:05 -0000 1.9
+@@ -18,6 +18,7 @@
+ "LOCALDOMAIN\0" \
+ "LOCPATH\0" \
+ "MALLOC_TRACE\0" \
++ "NIS_PATH\0" \
+ "NLSPATH\0" \
+ "RESOLV_HOST_CONF\0" \
+ "RES_OPTIONS\0" \
--- /dev/null
+2006-06-16 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nis_subr.c (nis_getnames): Fix the implementation to better
+ match what Solaris does.
+
+2006-05-25 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nis_removemember.c (nis_removemember): Avoid unnecessary
+ copying. No need to allocate new array for group members. Just
+ move the pointers and update the size.
+
+ * nis/nis_addmember.c (nis_addmember): Avoid unnecessary copying.
+ Avoid memory leak in case realloc fails. Simplification for
+ better code generation.
+
+ * nis/nis_callback.c (__nis_create_callback): Always call xdr_free
+ for cleanup when cb!=NULL [Coverity CID 233].
+
+--- libc/nis/nis_addmember.c 25 Oct 2004 03:15:59 -0000 1.7
++++ libc/nis/nis_addmember.c 25 May 2006 17:15:32 -0000 1.8
+@@ -28,13 +28,12 @@ nis_addmember (const_nis_name member, co
+ {
+ size_t grouplen = strlen (group);
+ char buf[grouplen + 14 + NIS_MAXNAMELEN];
+- char leafbuf[grouplen + 2];
+ char domainbuf[grouplen + 2];
+ nis_result *res, *res2;
+ nis_error status;
+ char *cp, *cp2;
+
+- cp = stpcpy (buf, nis_leaf_of_r (group, leafbuf, sizeof (leafbuf) - 1));
++ cp = rawmemchr (nis_leaf_of_r (group, buf, sizeof (buf) - 1), '\0');
+ cp = stpcpy (cp, ".groups_dir");
+ cp2 = nis_domain_of_r (group, domainbuf, sizeof (domainbuf) - 1);
+ if (cp2 != NULL && cp2[0] != '\0')
+@@ -42,30 +41,35 @@ nis_addmember (const_nis_name member, co
+ *cp++ = '.';
+ stpcpy (cp, cp2);
+ }
+- res = nis_lookup (buf, FOLLOW_LINKS|EXPAND_NAME);
++ res = nis_lookup (buf, FOLLOW_LINKS | EXPAND_NAME);
+ if (NIS_RES_STATUS (res) != NIS_SUCCESS)
+ {
+ status = NIS_RES_STATUS (res);
+ nis_freeresult (res);
+ return status;
+ }
+- if ((NIS_RES_NUMOBJ (res) != 1) ||
+- (__type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ))
++ if (NIS_RES_NUMOBJ (res) != 1
++ || __type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ)
+ {
+ nis_freeresult (res);
+ return NIS_INVALIDOBJ;
+ }
+
+- NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val
++ u_int gr_members_len
++ = NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len;
++
++ nis_name *new_gr_members_val
+ = realloc (NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val,
+- (NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len + 1)
+- * sizeof (char *));
+- if (NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val == NULL)
++ (gr_members_len + 1) * sizeof (nis_name));
++ if (new_gr_members_val == NULL)
+ goto nomem_out;
+- NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val[NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_len] = strdup (member);
+- if (NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val[NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_len] == NULL)
++
++ NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val
++ = new_gr_members_val;
++
++ new_gr_members_val[gr_members_len] = strdup (member);
++ if (new_gr_members_val[gr_members_len] == NULL)
+ {
+- free (NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val);
+ nomem_out:
+ nis_freeresult (res);
+ return NIS_NOMEMORY;
+--- libc/nis/nis_callback.c 20 May 2006 00:30:32 -0000 1.21
++++ libc/nis/nis_callback.c 25 May 2006 15:51:26 -0000 1.22
+@@ -360,8 +360,7 @@ __nis_create_callback (int (*callback) (
+ {
+ if (cb->xprt)
+ svc_destroy (cb->xprt);
+- if (cb->serv)
+- xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
++ xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
+ free (cb);
+ }
+ if (!nomsg)
+--- libc/nis/nis_removemember.c 7 Apr 2006 00:34:55 -0000 1.12
++++ libc/nis/nis_removemember.c 25 May 2006 18:30:53 -0000 1.13
+@@ -28,15 +28,12 @@ nis_removemember (const_nis_name member,
+ {
+ size_t grouplen = strlen (group);
+ char buf[grouplen + 14 + NIS_MAXNAMELEN];
+- char leafbuf[grouplen + 2];
+ char domainbuf[grouplen + 2];
+- nis_name *newmem;
+ nis_result *res, *res2;
+ nis_error status;
+ char *cp, *cp2;
+- unsigned long int i, j, k;
+
+- cp = stpcpy (buf, nis_leaf_of_r (group, leafbuf, sizeof (leafbuf) - 1));
++ cp = rawmemchr (nis_leaf_of_r (group, buf, sizeof (buf) - 1), '\0');
+ cp = stpcpy (cp, ".groups_dir");
+ cp2 = nis_domain_of_r (group, domainbuf, sizeof (domainbuf) - 1);
+ if (cp2 != NULL && cp2[0] != '\0')
+@@ -44,68 +41,41 @@ nis_removemember (const_nis_name member,
+ cp = stpcpy (cp, ".");
+ stpcpy (cp, cp2);
+ }
+- res = nis_lookup (buf, FOLLOW_LINKS|EXPAND_NAME);
+- if (res == NULL || NIS_RES_STATUS (res) != NIS_SUCCESS)
++ res = nis_lookup (buf, FOLLOW_LINKS | EXPAND_NAME);
++ if (res == NULL)
++ return NIS_NOMEMORY;
++ if (NIS_RES_STATUS (res) != NIS_SUCCESS)
+ {
+- if (res)
+- {
+- status = NIS_RES_STATUS (res);
+- nis_freeresult (res);
+- }
+- else
+- return NIS_NOMEMORY;
++ status = NIS_RES_STATUS (res);
++ nis_freeresult (res);
+ return status;
+ }
+
+- if ((res->objects.objects_len != 1) ||
+- (__type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ))
++ if (NIS_RES_NUMOBJ (res) != 1
++ || __type_of (NIS_RES_OBJECT (res)) != NIS_GROUP_OBJ)
+ {
+ nis_freeresult (res);
+ return NIS_INVALIDOBJ;
+ }
+
+- newmem =
+- calloc (NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len,
+- sizeof (char *));
+- if (newmem == NULL)
+- {
+- nis_freeresult (res);
+- return NIS_NOMEMORY;
+- }
+-
+- k = NIS_RES_OBJECT (res)[0].GR_data.gr_members.gr_members_len;
+- j = 0;
+- for (i = 0; i < NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len;
+- ++i)
+- {
+- if (strcmp (NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_val[i],
+- member) != 0)
+- {
+- newmem[j] = NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_val[i];
+- ++j;
+- }
+- else
+- {
+- free (NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_val[i]);
+- --k;
+- }
+- }
+- free (NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val);
+- assert (k <= NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len);
+- /* This realloc() call always decreases the size. This cannot
+- fail. We still have the test but do not recover memory
+- (i.e., we overwrite the input pointer). */
+- nis_name *newp = realloc (newmem, k * sizeof (char*));
+- if (newp == NULL)
+- {
+- free (newmem);
+- nis_freeresult (res);
+- return NIS_NOMEMORY;
+- }
+- newmem = newp;
+-
+- NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_val = newmem;
+- NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_len = k;
++ nis_name *gr_members_val
++ = NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_val;
++ u_int gr_members_len
++ = NIS_RES_OBJECT(res)->GR_data.gr_members.gr_members_len;
++
++ u_int j = 0;
++ for (u_int i = 0; i < gr_members_len; ++i)
++ if (strcmp (gr_members_val[i], member) != 0)
++ gr_members_val[j++] = gr_members_val[i];
++ else
++ free (gr_members_val[i]);
++
++ /* There is no need to reallocate the gr_members_val array. We
++ just adjust the size to match the number of strings still in
++ it. Yes, xdr_array will use mem_free with a size parameter
++ but this is mapped to a simple free call which determines the
++ size of the block by itself. */
++ NIS_RES_OBJECT (res)->GR_data.gr_members.gr_members_len = j;
+
+ cp = stpcpy (buf, NIS_RES_OBJECT (res)->zo_name);
+ *cp++ = '.';
+--- libc/nis/nis_subr.c 16 Aug 2005 15:59:46 -0000 1.14
++++ libc/nis/nis_subr.c 16 Jun 2006 22:30:02 -0000 1.15
+@@ -107,25 +107,23 @@ count_dots (const_nis_name str)
+ nis_name *
+ nis_getnames (const_nis_name name)
+ {
+- nis_name *getnames = NULL;
+- char local_domain[NIS_MAXNAMELEN + 1];
++ const char *local_domain = nis_local_directory ();
++ size_t local_domain_len = strlen (local_domain);
++ size_t name_len = strlen (name);
+ char *path;
+- char *cp;
+- int count;
+ int pos = 0;
+- int have_point;
+ char *saveptr;
++ int have_point;
++ const char *cp;
++ const char *cp2;
+
+- strncpy (local_domain, nis_local_directory (), NIS_MAXNAMELEN);
+- local_domain[NIS_MAXNAMELEN] = '\0';
+-
+- count = 1;
+- getnames = malloc ((count + 1) * sizeof (char *));
++ int count = 2;
++ nis_name *getnames = malloc ((count + 1) * sizeof (char *));
+ if (__builtin_expect (getnames == NULL, 0))
+ return NULL;
+
+ /* Do we have a fully qualified NIS+ name ? If yes, give it back */
+- if (name[strlen (name) - 1] == '.')
++ if (name[name_len - 1] == '.')
+ {
+ if ((getnames[0] = strdup (name)) == NULL)
+ {
+@@ -141,6 +139,44 @@ nis_getnames (const_nis_name name)
+ return getnames;
+ }
+
++ /* If the passed NAME is shared a suffix (the latter of course with
++ a final dot) with each other we pass back NAME with a final
++ dot. */
++ if (local_domain_len > 2)
++ {
++ have_point = 0;
++ cp = &local_domain[local_domain_len - 2];
++ cp2 = &name[name_len - 1];
++
++ while (*cp == *cp2)
++ {
++ if (*cp == '.')
++ have_point = 1;
++ --cp;
++ --cp2;
++ if (cp < local_domain)
++ {
++ have_point = cp2 < name || *cp2 == '.';
++ break;
++ }
++ if (cp2 < name)
++ {
++ have_point = *cp == '.';
++ break;
++ }
++ }
++
++ if (have_point)
++ {
++ getnames[0] = malloc (name_len + 2);
++ if (getnames[0] == NULL)
++ goto free_null;
++
++ strcpy (stpcpy (getnames[0], name), ".");
++ ++pos;
++ }
++ }
++
+ /* Get the search path, where we have to search "name" */
+ path = getenv ("NIS_PATH");
+ if (path == NULL)
+@@ -148,17 +184,17 @@ nis_getnames (const_nis_name name)
+ else
+ path = strdupa (path);
+
+- have_point = (strchr (name, '.') != NULL);
++ have_point = strchr (name, '.') != NULL;
+
+ cp = __strtok_r (path, ":", &saveptr);
+ while (cp)
+ {
+ if (strcmp (cp, "$") == 0)
+ {
+- char *cptr = local_domain;
++ const char *cptr = local_domain;
+ char *tmp;
+
+- while ((have_point && *cptr != '\0') || (count_dots (cptr) >= 2))
++ while (*cptr != '\0' && count_dots (cptr) >= 2)
+ {
+ if (pos >= count)
+ {
+@@ -169,8 +205,7 @@ nis_getnames (const_nis_name name)
+ goto free_null;
+ getnames = newp;
+ }
+- tmp = malloc (strlen (cptr) + strlen (local_domain) +
+- strlen (name) + 2);
++ tmp = malloc (strlen (cptr) + local_domain_len + name_len + 2);
+ if (__builtin_expect (tmp == NULL, 0))
+ goto free_null;
+
+@@ -200,7 +235,7 @@ nis_getnames (const_nis_name name)
+ {
+ char *p;
+
+- tmp = malloc (cplen + strlen (local_domain) + strlen (name) + 2);
++ tmp = malloc (cplen + local_domain_len + name_len + 2);
+ if (__builtin_expect (tmp == NULL, 0))
+ goto free_null;
+
+@@ -216,7 +251,7 @@ nis_getnames (const_nis_name name)
+ {
+ char *p;
+
+- tmp = malloc (cplen + strlen (name) + 2);
++ tmp = malloc (cplen + name_len + 2);
+ if (__builtin_expect (tmp == NULL, 0))
+ goto free_null;
+
--- /dev/null
+2006-05-04 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nis_table.c (get_tablepath): Renamed from __get_tablepath.
+ Adjust all callers.
+ Free res object content before returning.
+
+ * sunrpc/xdr_array.c (xdr_array): Use calloc instead of malloc&bzero.
+
+ * sunrpc/key_call.c (__rpc_thread_key_cleanup): Also free
+ client->cl_auth.
+
+ * sunrpc/rpc_thread.c (__rpc_thread_destroy): Don't skip entire
+ cleanup for initial thread, just the free call on TVP.
+
+--- libc/nis/nis_table.c 7 Apr 2006 00:56:07 -0000 1.32
++++ libc/nis/nis_table.c 5 May 2006 06:32:33 -0000 1.36
+@@ -25,7 +25,7 @@
+
+
+ static struct ib_request *
+-__create_ib_request (const_nis_name name, unsigned int flags)
++create_ib_request (const_nis_name name, unsigned int flags)
+ {
+ struct ib_request *ibreq = calloc (1, sizeof (struct ib_request));
+ nis_attr *search_val = NULL;
+@@ -91,13 +91,13 @@ __create_ib_request (const_nis_name name
+ if (cptr != NULL)
+ *cptr++ = '\0';
+
+- if (!val)
++ if (__builtin_expect (val == NULL, 0))
+ {
+ nis_free_request (ibreq);
+ return NULL;
+ }
+ *val++ = '\0';
+- if ((search_len + 1) >= size)
++ if (search_len + 1 >= size)
+ {
+ size += 1;
+ nis_attr *newp = realloc (search_val, size * sizeof (nis_attr));
+@@ -106,7 +106,7 @@ __create_ib_request (const_nis_name name
+ search_val = newp;
+ }
+ search_val[search_len].zattr_ndx = strdup (key);
+- if ((search_val[search_len].zattr_ndx) == NULL)
++ if (search_val[search_len].zattr_ndx == NULL)
+ goto free_null;
+
+ search_val[search_len].zattr_val.zattr_val_len = strlen (val) + 1;
+@@ -129,7 +129,7 @@ __create_ib_request (const_nis_name name
+ static const struct timeval RPCTIMEOUT = {10, 0};
+
+ static char *
+-__get_tablepath (char *name, dir_binding *bptr)
++get_tablepath (char *name, dir_binding *bptr)
+ {
+ enum clnt_stat result;
+ nis_result res;
+@@ -152,7 +152,12 @@ __get_tablepath (char *name, dir_binding
+ else
+ cptr = "";
+
+- return strdup (cptr);
++ char *str = strdup (cptr);
++
++ if (result == RPC_SUCCESS)
++ xdr_free ((xdrproc_t) _xdr_nis_result, (char *) &res);
++
++ return str;
+ }
+
+ nis_result *
+@@ -162,7 +167,7 @@ nis_list (const_nis_name name, unsigned
+ const void *userdata),
+ const void *userdata)
+ {
+- nis_result *res = calloc (1, sizeof (nis_result));
++ nis_result *res = malloc (sizeof (nis_result));
+ ib_request *ibreq;
+ int status;
+ enum clnt_stat clnt_status;
+@@ -181,14 +186,18 @@ nis_list (const_nis_name name, unsigned
+
+ if (name == NULL)
+ {
+- NIS_RES_STATUS (res) = NIS_BADNAME;
++ status = NIS_BADNAME;
++ err_out:
++ memset (res, '\0', sizeof (nis_result));
++ NIS_RES_STATUS (res) = status;
+ return res;
+ }
+
+- if ((ibreq = __create_ib_request (name, flags)) == NULL)
++ ibreq = create_ib_request (name, flags);
++ if (ibreq == NULL)
+ {
+- NIS_RES_STATUS (res) = NIS_BADNAME;
+- return res;
++ status = NIS_BADNAME;
++ goto err_out;
+ }
+
+ if ((flags & EXPAND_NAME)
+@@ -200,16 +209,16 @@ nis_list (const_nis_name name, unsigned
+ if (names == NULL)
+ {
+ nis_free_request (ibreq);
+- NIS_RES_STATUS (res) = NIS_BADNAME;
+- return res;
++ status = NIS_BADNAME;
++ goto err_out;
+ }
+ ibreq->ibr_name = strdup (names[name_nr]);
+ if (ibreq->ibr_name == NULL)
+ {
+ nis_freenames (names);
+ nis_free_request (ibreq);
+- NIS_RES_STATUS (res) = NIS_NOMEMORY;
+- return res;
++ status = NIS_NOMEMORY;
++ goto err_out;
+ }
+ }
+ else
+@@ -236,14 +245,14 @@ nis_list (const_nis_name name, unsigned
+
+ status = __nisbind_create (&bptr, dir->do_servers.do_servers_val,
+ dir->do_servers.do_servers_len, flags);
+- if (status != NIS_SUCCESS)
++ if (__builtin_expect (status != NIS_SUCCESS, 0))
+ {
+ NIS_RES_STATUS (res) = status;
+ goto fail2;
+ }
+
+ while (__nisbind_connect (&bptr) != NIS_SUCCESS)
+- if (__nisbind_next (&bptr) != NIS_SUCCESS)
++ if (__builtin_expect (__nisbind_next (&bptr) != NIS_SUCCESS, 0))
+ {
+ NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
+ goto fail;
+@@ -262,7 +271,7 @@ nis_list (const_nis_name name, unsigned
+ (xdrproc_t) _xdr_nis_result,
+ (caddr_t) res, RPCTIMEOUT);
+
+- if (clnt_status != RPC_SUCCESS)
++ if (__builtin_expect (clnt_status != RPC_SUCCESS, 0))
+ NIS_RES_STATUS (res) = NIS_RPCERROR;
+ else
+ switch (NIS_RES_STATUS (res))
+@@ -276,7 +285,7 @@ nis_list (const_nis_name name, unsigned
+ free (ibreq->ibr_name);
+ ibreq->ibr_name = NULL;
+ /* If we hit the link limit, bail. */
+- if (count_links > NIS_MAXLINKS)
++ if (__builtin_expect (count_links > NIS_MAXLINKS, 0))
+ {
+ NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
+ ++done;
+@@ -335,7 +344,7 @@ nis_list (const_nis_name name, unsigned
+ {
+ if (tablepath == NULL)
+ {
+- tablepath = __get_tablepath (ibreq->ibr_name, &bptr);
++ tablepath = get_tablepath (ibreq->ibr_name, &bptr);
+ tableptr = tablepath;
+ }
+ if (tableptr == NULL)
+@@ -400,7 +409,7 @@ nis_list (const_nis_name name, unsigned
+ {
+ if (tablepath == NULL)
+ {
+- tablepath = __get_tablepath (ibreq->ibr_name, &bptr);
++ tablepath = get_tablepath (ibreq->ibr_name, &bptr);
+ tableptr = tablepath;
+ }
+ if (tableptr == NULL)
+@@ -454,7 +463,7 @@ nis_list (const_nis_name name, unsigned
+ /* Try the next domainname if we don't follow a link. */
+ free (ibreq->ibr_name);
+ ibreq->ibr_name = NULL;
+- if (count_links)
++ if (__builtin_expect (count_links, 0))
+ {
+ NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
+ ++done;
+@@ -515,11 +524,7 @@ nis_add_entry (const_nis_name name, cons
+ return res;
+ }
+
+- size_t namelen = strlen (name);
+- char buf1[namelen + 20];
+- char buf4[namelen + 20];
+-
+- ib_request *ibreq = __create_ib_request (name, flags);
++ ib_request *ibreq = create_ib_request (name, flags);
+ if (ibreq == NULL)
+ {
+ NIS_RES_STATUS (res) = NIS_BADNAME;
+@@ -529,6 +534,10 @@ nis_add_entry (const_nis_name name, cons
+ nis_object obj;
+ memcpy (&obj, obj2, sizeof (nis_object));
+
++ size_t namelen = strlen (name);
++ char buf1[namelen + 20];
++ char buf4[namelen + 20];
++
+ if (obj.zo_name == NULL || strlen (obj.zo_name) == 0)
+ obj.zo_name = nis_leaf_of_r (name, buf1, sizeof (buf1));
+
+@@ -554,7 +563,7 @@ nis_add_entry (const_nis_name name, cons
+ (caddr_t) ibreq,
+ (xdrproc_t) _xdr_nis_result,
+ (caddr_t) res, 0, NULL);
+- if (status != NIS_SUCCESS)
++ if (__builtin_expect (status != NIS_SUCCESS, 0))
+ NIS_RES_STATUS (res) = status;
+
+ nis_free_request (ibreq);
+@@ -578,7 +587,8 @@ nis_modify_entry (const_nis_name name, c
+ if (res == NULL)
+ return NULL;
+
+- if (( ibreq =__create_ib_request (name, flags)) == NULL)
++ ibreq = create_ib_request (name, flags);
++ if (ibreq == NULL)
+ {
+ NIS_RES_STATUS (res) = NIS_BADNAME;
+ return res;
+@@ -606,10 +616,11 @@ nis_modify_entry (const_nis_name name, c
+ }
+ ibreq->ibr_obj.ibr_obj_len = 1;
+
+- if ((status = __do_niscall (ibreq->ibr_name, NIS_IBMODIFY,
+- (xdrproc_t) _xdr_ib_request,
+- (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
+- (caddr_t) res, 0, NULL)) != NIS_SUCCESS)
++ status = __do_niscall (ibreq->ibr_name, NIS_IBMODIFY,
++ (xdrproc_t) _xdr_ib_request,
++ (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
++ (caddr_t) res, 0, NULL);
++ if (__builtin_expect (status != NIS_SUCCESS, 0))
+ NIS_RES_STATUS (res) = status;
+
+ nis_free_request (ibreq);
+@@ -635,7 +646,8 @@ nis_remove_entry (const_nis_name name, c
+ return res;
+ }
+
+- if ((ibreq =__create_ib_request (name, flags)) == NULL)
++ ibreq = create_ib_request (name, flags);
++ if (ibreq == NULL)
+ {
+ NIS_RES_STATUS (res) = NIS_BADNAME;
+ return res;
+@@ -681,7 +693,7 @@ nis_first_entry (const_nis_name name)
+ return res;
+ }
+
+- ibreq = __create_ib_request (name, 0);
++ ibreq = create_ib_request (name, 0);
+ if (ibreq == NULL)
+ {
+ NIS_RES_STATUS (res) = NIS_BADNAME;
+@@ -693,7 +705,7 @@ nis_first_entry (const_nis_name name)
+ (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
+ (caddr_t) res, 0, NULL);
+
+- if (status != NIS_SUCCESS)
++ if (__builtin_expect (status != NIS_SUCCESS, 0))
+ NIS_RES_STATUS (res) = status;
+
+ nis_free_request (ibreq);
+@@ -718,7 +730,7 @@ nis_next_entry (const_nis_name name, con
+ return res;
+ }
+
+- ibreq = __create_ib_request (name, 0);
++ ibreq = create_ib_request (name, 0);
+ if (ibreq == NULL)
+ {
+ NIS_RES_STATUS (res) = NIS_BADNAME;
+@@ -736,7 +748,7 @@ nis_next_entry (const_nis_name name, con
+ (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result,
+ (caddr_t) res, 0, NULL);
+
+- if (status != NIS_SUCCESS)
++ if (__builtin_expect (status != NIS_SUCCESS, 0))
+ NIS_RES_STATUS (res) = status;
+
+ if (cookie != NULL)
+--- libc/sunrpc/key_call.c 6 Mar 2005 00:25:54 -0000 1.19
++++ libc/sunrpc/key_call.c 4 May 2006 18:22:38 -0000 1.20
+@@ -552,8 +552,11 @@ __rpc_thread_key_cleanup (void)
+ struct key_call_private *kcp = RPC_THREAD_VARIABLE(key_call_private_s);
+
+ if (kcp) {
+- if (kcp->client)
++ if (kcp->client) {
++ if (kcp->client->cl_auth)
++ auth_destroy (kcp->client->cl_auth);
+ clnt_destroy(kcp->client);
++ }
+ free (kcp);
+ }
+ }
+--- libc/sunrpc/rpc_thread.c 22 Feb 2003 01:57:51 -0000 1.10
++++ libc/sunrpc/rpc_thread.c 4 May 2006 18:07:29 -0000 1.11
+@@ -20,7 +20,7 @@ __rpc_thread_destroy (void)
+ {
+ struct rpc_thread_variables *tvp = __libc_tsd_get (RPC_VARS);
+
+- if (tvp != NULL && tvp != &__libc_tsd_RPC_VARS_mem) {
++ if (tvp != NULL) {
+ __rpc_thread_svc_cleanup ();
+ __rpc_thread_clnt_cleanup ();
+ __rpc_thread_key_cleanup ();
+@@ -29,7 +29,8 @@ __rpc_thread_destroy (void)
+ free (tvp->svcraw_private_s);
+ free (tvp->authdes_cache_s);
+ free (tvp->authdes_lru_s);
+- free (tvp);
++ if (tvp != &__libc_tsd_RPC_VARS_mem)
++ free (tvp);
+ __libc_tsd_set (RPC_VARS, NULL);
+ }
+ }
+--- libc/sunrpc/xdr_array.c 20 Jul 2005 17:50:28 -0000 1.9
++++ libc/sunrpc/xdr_array.c 4 May 2006 20:55:11 -0000 1.10
+@@ -74,7 +74,6 @@ xdr_array (xdrs, addrp, sizep, maxsize,
+ caddr_t target = *addrp;
+ u_int c; /* the actual element count */
+ bool_t stat = TRUE;
+- u_int nodesize;
+
+ /* like strings, arrays are really counted arrays */
+ if (!INTUSE(xdr_u_int) (xdrs, sizep))
+@@ -90,7 +89,6 @@ xdr_array (xdrs, addrp, sizep, maxsize,
+ {
+ return FALSE;
+ }
+- nodesize = c * elsize;
+
+ /*
+ * if we are deserializing, we may need to allocate an array.
+@@ -102,7 +100,7 @@ xdr_array (xdrs, addrp, sizep, maxsize,
+ case XDR_DECODE:
+ if (c == 0)
+ return TRUE;
+- *addrp = target = mem_alloc (nodesize);
++ *addrp = target = calloc (c, elsize);
+ if (target == NULL)
+ {
+ #ifdef USE_IN_LIBIO
+@@ -114,7 +112,6 @@ xdr_array (xdrs, addrp, sizep, maxsize,
+ (void) fputs (_("xdr_array: out of memory\n"), stderr);
+ return FALSE;
+ }
+- __bzero (target, nodesize);
+ break;
+
+ case XDR_FREE:
+@@ -137,7 +134,7 @@ xdr_array (xdrs, addrp, sizep, maxsize,
+ */
+ if (xdrs->x_op == XDR_FREE)
+ {
+- mem_free (*addrp, nodesize);
++ mem_free (*addrp, c * elsize);
+ *addrp = NULL;
+ }
+ return stat;
--- /dev/null
+2006-05-17 Jakub Jelinek <jakub@redhat.com>
+
+ * sunrpc/key_call.c (getkeyserv_handle): Call auth_destroy if
+ pid changed.
+
+--- libc/sunrpc/key_call.c 4 May 2006 18:22:38 -0000 1.20
++++ libc/sunrpc/key_call.c 17 May 2006 15:10:44 -0000 1.21
+@@ -400,6 +400,7 @@ getkeyserv_handle (int vers)
+ /* if pid has changed, destroy client and rebuild */
+ if (kcp->client != NULL && kcp->pid != __getpid ())
+ {
++ auth_destroy (kcp->client->cl_auth);
+ clnt_destroy (kcp->client);
+ kcp->client = NULL;
+ }
--- /dev/null
+2006-05-23 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nis_lookup.c (nis_lookup): Use __prepare_niscall instead of
+ doing it all here. When server does not know the answer do not
+ fail immediate, try parent first.
+
+ * nis/nis_domain_of_r.c (nis_domain_of_r): Add missing buffer
+ overflow test.
+
+2006-05-20 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nis_call.c (__prepare_niscall): New function. Split out
+ from __do_niscall.
+ * nis/nis_table.c (__create_ib_request): Renamed from create_ib_request
+ and exported.
+ (__follow_path): New function. Split out from nis_list.
+ * nis/nis_xdr.h: Add libnsl_hidden_proto for _xdr_ib_request and
+ _xdr_nis_result.
+ * nis/nis_xdr.c: Add libnsl_hidden_def for _xdr_ib_request and
+ _xdr_nis_result.
+ * nis/libnsl.h: Declare __prepare_niscall, __create_ib_request,
+ and __follow_path.
+ * nis/Versions: Export __prepare_niscall, __create_ib_request,
+ __follow_path, __do_niscall3, _xdr_ib_request, and _xdr_nis_result
+ from libnsl for version GLIBC_PRIVATE.
+ * nis/nisplus-parser.h: Remove _nss_nisplus_parse_pwent_chk.
+ Remove entry parameter from _nss_nisplus_parse_pwent and
+ _nss_nisplus_parse_grent.
+ * nis/nss_nisplus/nisplus-parser.c: Likewise.
+ * nis/nss_nisplus/nisplus-pwd.c: Remove support for SETENT_BATCH_READ
+ again. Rewrite getpwent handling to not use nis_first_entry and
+ nis_next_entry. Roll out own niscall handling.
+ * nis/nss_nisplus/nisplus-grp.c: Likewise.
+
+2006-05-19 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nis_call.c (__do_niscall3): Avoid code duplication in error
+ handling.
+
+ * nis/nis_callback.c (internal_nis_do_callback): Don't use malloc
+ to allocate memory for my_pollfd. Better initialization of
+ cb_is_running. Use TEMP_FAILURE_RETRY.
+
+ * nis/nis_callback.c (__nis_create_callback): Calls to
+ svcudp_bufcreate and svctcp_create can fail. Free ->xprt if
+ asprintf call fails.
+
+2006-05-18 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nis_callback.c (__nis_create_callback): Use asprinf instead
+ of snprintf+strdup. Handle OOM.
+ * nis/nis_callback.c (__nis_create_callback): Allocate cb and
+ cb->serv together. Remove now obsolete free calls.
+ (__nis_destroy_callback): Remove now obsolete free call.
+
+2006-05-18 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nis_call.c (rec_dirsearch): Little optimization: pull
+ nis_free_directory forward to avoid duplication.
+
+2006-05-17 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nis_call.c (rec_dirsearch): Handle __nis_finddirectory and
+ rec_dirsearch returning NULL.
+ (first_shoot): Handle __nis_finddirectory returning NULL.
+ (__nisfind_server): Fix leak when rec_dirsearch returns NULL.
+
+--- libc/nis/Versions 14 Apr 2006 21:07:54 -0000 1.9
++++ libc/nis/Versions 20 May 2006 19:21:52 -0000 1.10
+@@ -58,7 +58,8 @@ libnsl {
+ xdr_ypall;
+ }
+ GLIBC_PRIVATE {
+- _nsl_default_nss;
++ _nsl_default_nss; __prepare_niscall; __follow_path; __do_niscall3;
++ __create_ib_request; _xdr_ib_request; _xdr_nis_result;
+ }
+ }
+
+--- libc/nis/libnsl.h 28 Apr 2006 21:01:49 -0000 1.2
++++ libc/nis/libnsl.h 20 May 2006 20:17:22 -0000 1.4
+@@ -16,6 +16,8 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
++#include <rpcsvc/nis.h>
++
+ #define NSS_FLAG_NETID_AUTHORITATIVE 1
+ #define NSS_FLAG_SERVICES_AUTHORITATIVE 2
+ #define NSS_FLAG_SETENT_BATCH_READ 4
+@@ -23,3 +25,16 @@
+
+ /* Get current set of default flags. */
+ extern int _nsl_default_nss (void);
++
++/* Set up everything for a call to __do_niscall3. */
++extern nis_error __prepare_niscall (const_nis_name name, directory_obj **dirp,
++ dir_binding *bptrp, unsigned int flags);
++libnsl_hidden_proto (__prepare_niscall)
++
++extern struct ib_request *__create_ib_request (const_nis_name name,
++ unsigned int flags);
++libnsl_hidden_proto (__create_ib_request)
++
++extern nis_error __follow_path (char **tablepath, char **tableptr,
++ struct ib_request *ibreq, dir_binding *bptr);
++libnsl_hidden_proto (__follow_path)
+--- libc/nis/nis_call.c 7 Apr 2006 06:53:11 -0000 1.37
++++ libc/nis/nis_call.c 24 May 2006 05:59:50 -0000 1.45
+@@ -30,6 +30,7 @@
+
+ #include "nis_xdr.h"
+ #include "nis_intern.h"
++#include <libnsl.h>
+
+ static const struct timeval RPCTIMEOUT = {10, 0};
+ static const struct timeval UDPTIMEOUT = {5, 0};
+@@ -256,6 +257,7 @@ __do_niscall3 (dir_binding *dbp, u_long
+ || ((nis_result *)resp)->status == NIS_NOSUCHNAME
+ || ((nis_result *)resp)->status == NIS_NOT_ME)
+ {
++ next_server:
+ if (__nisbind_next (dbp) == NIS_SUCCESS)
+ {
+ while (__nisbind_connect (dbp) != NIS_SUCCESS)
+@@ -273,38 +275,14 @@ __do_niscall3 (dir_binding *dbp, u_long
+ if (((fd_result *)resp)->status == NIS_SYSTEMERROR
+ || ((fd_result *)resp)->status == NIS_NOSUCHNAME
+ || ((fd_result *)resp)->status == NIS_NOT_ME)
+- {
+- if (__nisbind_next (dbp) == NIS_SUCCESS)
+- {
+- while (__nisbind_connect (dbp) != NIS_SUCCESS)
+- {
+- if (__nisbind_next (dbp) != NIS_SUCCESS)
+- return NIS_SUCCESS;
+- }
+- }
+- else
+- break; /* No more servers to search in */
+- goto again;
+- }
++ goto next_server;
+ break;
+ case NIS_DUMPLOG: /* log_result */
+ case NIS_DUMP:
+ if (((log_result *)resp)->lr_status == NIS_SYSTEMERROR
+ || ((log_result *)resp)->lr_status == NIS_NOSUCHNAME
+ || ((log_result *)resp)->lr_status == NIS_NOT_ME)
+- {
+- if (__nisbind_next (dbp) == NIS_SUCCESS)
+- {
+- while (__nisbind_connect (dbp) != NIS_SUCCESS)
+- {
+- if (__nisbind_next (dbp) != NIS_SUCCESS)
+- return NIS_SUCCESS;
+- }
+- }
+- else
+- break; /* No more servers to search in */
+- goto again;
+- }
++ goto next_server;
+ break;
+ default:
+ break;
+@@ -316,6 +294,8 @@ __do_niscall3 (dir_binding *dbp, u_long
+
+ return retcode;
+ }
++libnsl_hidden_def (__do_niscall3)
++
+
+ nis_error
+ __do_niscall2 (const nis_server *server, u_int server_len, u_long prog,
+@@ -368,6 +348,12 @@ rec_dirsearch (const_nis_name name, dire
+ domain ! (Now I understand why a root server must be a
+ replica of the parent domain) */
+ fd_res = __nis_finddirectory (dir, ndomain);
++ if (fd_res == NULL)
++ {
++ nis_free_directory (dir);
++ *status = NIS_NOMEMORY;
++ return NULL;
++ }
+ *status = fd_res->status;
+ if (fd_res->status != NIS_SUCCESS)
+ {
+@@ -375,27 +361,25 @@ rec_dirsearch (const_nis_name name, dire
+ __free_fdresult (fd_res);
+ return dir;
+ }
++ nis_free_directory (dir);
+ obj = calloc (1, sizeof (directory_obj));
++ if (obj == NULL)
++ {
++ __free_fdresult (fd_res);
++ *status = NIS_NOMEMORY;
++ return NULL;
++ }
+ xdrmem_create (&xdrs, fd_res->dir_data.dir_data_val,
+ fd_res->dir_data.dir_data_len, XDR_DECODE);
+ _xdr_directory_obj (&xdrs, obj);
+ xdr_destroy (&xdrs);
+ __free_fdresult (fd_res);
+- if (obj != NULL)
+- {
+- /* We have found a NIS+ server serving ndomain, now
+- let us search for "name" */
+- nis_free_directory (dir);
+- return rec_dirsearch (name, obj, status);
+- }
+- else
+- {
+- /* Ups, very bad. Are we already the root server ? */
+- nis_free_directory (dir);
+- return NULL;
+- }
++
++ /* We have found a NIS+ server serving ndomain, now
++ let us search for "name" */
++ return rec_dirsearch (name, obj, status);
+ }
+- break;
++ break;
+ case LOWER_NAME:
+ {
+ directory_obj *obj;
+@@ -433,6 +417,12 @@ rec_dirsearch (const_nis_name name, dire
+ strcpy (cp, domain);
+
+ fd_res = __nis_finddirectory (dir, leaf);
++ if (fd_res == NULL)
++ {
++ nis_free_directory (dir);
++ *status = NIS_NOMEMORY;
++ return NULL;
++ }
+ *status = fd_res->status;
+ if (fd_res->status != NIS_SUCCESS)
+ {
+@@ -440,21 +430,24 @@ rec_dirsearch (const_nis_name name, dire
+ __free_fdresult (fd_res);
+ return dir;
+ }
+- obj = calloc(1, sizeof(directory_obj));
+- xdrmem_create(&xdrs, fd_res->dir_data.dir_data_val,
+- fd_res->dir_data.dir_data_len, XDR_DECODE);
+- _xdr_directory_obj(&xdrs, obj);
+- xdr_destroy(&xdrs);
+- __free_fdresult (fd_res);
+- if (obj != NULL)
++ nis_free_directory (dir);
++ obj = calloc (1, sizeof(directory_obj));
++ if (obj == NULL)
+ {
+- /* We have found a NIS+ server serving ndomain, now
+- let us search for "name" */
+- nis_free_directory (dir);
+- return rec_dirsearch (name, obj, status);
++ __free_fdresult (fd_res);
++ *status = NIS_NOMEMORY;
++ return NULL;
+ }
++ xdrmem_create (&xdrs, fd_res->dir_data.dir_data_val,
++ fd_res->dir_data.dir_data_len, XDR_DECODE);
++ _xdr_directory_obj (&xdrs, obj);
++ xdr_destroy (&xdrs);
++ __free_fdresult (fd_res);
++ /* We have found a NIS+ server serving ndomain, now
++ let us search for "name" */
++ return rec_dirsearch (name, obj, status);
+ }
+- break;
++ break;
+ case BAD_NAME:
+ nis_free_directory (dir);
+ *status = NIS_BADNAME;
+@@ -484,6 +477,8 @@ first_shoot (const_nis_name name, direct
+ return dir;
+
+ fd_res = __nis_finddirectory (dir, domain);
++ if (fd_res == NULL)
++ return NULL;
+ if (fd_res->status == NIS_SUCCESS
+ && (obj = calloc (1, sizeof (directory_obj))) != NULL)
+ {
+@@ -513,74 +508,95 @@ __nisfind_server (const_nis_name name, d
+ dir = __nis_cache_search (name, flags, &cinfo);
+ #endif
+
++ nis_error result = NIS_SUCCESS;
+ if (*dir == NULL)
+ {
+ nis_error status;
+ directory_obj *obj;
+
+ *dir = readColdStartFile ();
+- if (*dir == NULL) /* No /var/nis/NIS_COLD_START->no NIS+ installed */
++ if (*dir == NULL)
++ /* No /var/nis/NIS_COLD_START->no NIS+ installed. */
+ return NIS_UNAVAIL;
+
+ /* Try at first, if servers in "dir" know our object */
+ obj = first_shoot (name, *dir);
+ if (obj == NULL)
+ {
+- *dir = rec_dirsearch (name, *dir, &status);
+- if (*dir == NULL)
+- return status;
++ obj = rec_dirsearch (name, *dir, &status);
++ if (obj == NULL)
++ result = status;
+ }
+- else
+- *dir = obj;
++
++ *dir = obj;
+ }
+
+- return NIS_SUCCESS;
++ return result;
+ }
+
++
+ nis_error
+-__do_niscall (const_nis_name name, u_long prog, xdrproc_t xargs,
+- caddr_t req, xdrproc_t xres, caddr_t resp, unsigned int flags,
+- nis_cb *cb)
++__prepare_niscall (const_nis_name name, directory_obj **dirp,
++ dir_binding *bptrp, unsigned int flags)
+ {
+- nis_error retcode;
+- dir_binding bptr;
+- directory_obj *dir = NULL;
++ nis_error retcode = __nisfind_server (name, dirp);
++ if (__builtin_expect (retcode != NIS_SUCCESS, 0))
++ return retcode;
++
+ nis_server *server;
+ u_int server_len;
+- int saved_errno = errno;
+-
+- retcode = __nisfind_server (name, &dir);
+- if (retcode != NIS_SUCCESS)
+- return retcode;
+
+ if (flags & MASTER_ONLY)
+ {
+- server = dir->do_servers.do_servers_val;
++ server = (*dirp)->do_servers.do_servers_val;
+ server_len = 1;
+ }
+ else
+ {
+- server = dir->do_servers.do_servers_val;
+- server_len = dir->do_servers.do_servers_len;
++ server = (*dirp)->do_servers.do_servers_val;
++ server_len = (*dirp)->do_servers.do_servers_len;
+ }
+
+- retcode = __nisbind_create (&bptr, server, server_len, flags);
++ retcode = __nisbind_create (bptrp, server, server_len, flags);
++ if (retcode == NIS_SUCCESS)
++ {
++ do
++ if (__nisbind_connect (bptrp) == NIS_SUCCESS)
++ return NIS_SUCCESS;
++ while (__nisbind_next (bptrp) == NIS_SUCCESS);
++
++ __nisbind_destroy (bptrp);
++ memset (bptrp, '\0', sizeof (*bptrp));
++
++ retcode = NIS_NAMEUNREACHABLE;
++ }
++
++ nis_free_directory (*dirp);
++ *dirp = NULL;
++
++ return retcode;
++}
++libnsl_hidden_def (__prepare_niscall)
++
++
++nis_error
++__do_niscall (const_nis_name name, u_long prog, xdrproc_t xargs,
++ caddr_t req, xdrproc_t xres, caddr_t resp, unsigned int flags,
++ nis_cb *cb)
++{
++ dir_binding bptr;
++ directory_obj *dir = NULL;
++ int saved_errno = errno;
++
++ nis_error retcode = __prepare_niscall (name, &dir, &bptr, flags);
+ if (retcode == NIS_SUCCESS)
+ {
+- while (__nisbind_connect (&bptr) != NIS_SUCCESS)
+- {
+- if (__nisbind_next (&bptr) != NIS_SUCCESS)
+- {
+- nis_free_directory (dir);
+- return NIS_NAMEUNREACHABLE;
+- }
+- }
+ retcode = __do_niscall3 (&bptr, prog, xargs, req, xres, resp, flags, cb);
+
+ __nisbind_destroy (&bptr);
+- }
+
+- nis_free_directory (dir);
++ nis_free_directory (dir);
++ }
+
+ __set_errno (saved_errno);
+
+--- libc/nis/nis_callback.c 17 Feb 2005 01:15:45 -0000 1.17
++++ libc/nis/nis_callback.c 20 May 2006 00:30:32 -0000 1.21
+@@ -197,22 +197,18 @@ internal_nis_do_callback (struct dir_bin
+ struct nis_cb *cb)
+ {
+ struct timeval TIMEOUT = {25, 0};
+- bool_t cb_is_running = FALSE;
++ bool_t cb_is_running;
+
+ data = cb;
+
+ for (;;)
+ {
+- struct pollfd *my_pollfd;
++ struct pollfd my_pollfd[svc_max_pollfd];
+ int i;
+
+ if (svc_max_pollfd == 0 && svc_pollfd == NULL)
+ return NIS_CBERROR;
+
+- my_pollfd = malloc (sizeof (struct pollfd) * svc_max_pollfd);
+- if (__builtin_expect (my_pollfd == NULL, 0))
+- return NIS_NOMEMORY;
+-
+ for (i = 0; i < svc_max_pollfd; ++i)
+ {
+ my_pollfd[i].fd = svc_pollfd[i].fd;
+@@ -220,20 +216,17 @@ internal_nis_do_callback (struct dir_bin
+ my_pollfd[i].revents = 0;
+ }
+
+- switch (i = __poll (my_pollfd, svc_max_pollfd, 25*1000))
++ switch (i = TEMP_FAILURE_RETRY (__poll (my_pollfd, svc_max_pollfd,
++ 25*1000)))
+ {
+ case -1:
+- free (my_pollfd);
+- if (errno == EINTR)
+- continue;
+ return NIS_CBERROR;
+ case 0:
+- free (my_pollfd);
+ /* See if callback 'thread' in the server is still alive. */
+- memset ((char *) &cb_is_running, 0, sizeof (cb_is_running));
++ cb_is_running = FALSE;
+ if (clnt_call (bptr->clnt, NIS_CALLBACK, (xdrproc_t) xdr_netobj,
+ (caddr_t) cookie, (xdrproc_t) xdr_bool,
+- (caddr_t) & cb_is_running, TIMEOUT) != RPC_SUCCESS)
++ (caddr_t) &cb_is_running, TIMEOUT) != RPC_SUCCESS)
+ cb_is_running = FALSE;
+
+ if (cb_is_running == FALSE)
+@@ -244,7 +237,6 @@ internal_nis_do_callback (struct dir_bin
+ break;
+ default:
+ svc_getreq_poll (my_pollfd, i);
+- free (my_pollfd);
+ if (data->nomore)
+ return data->result;
+ }
+@@ -275,15 +267,14 @@ __nis_create_callback (int (*callback) (
+ int sock = RPC_ANYSOCK;
+ struct sockaddr_in sin;
+ int len = sizeof (struct sockaddr_in);
+- char addr[NIS_MAXNAMELEN + 1];
+ unsigned short port;
++ int nomsg = 0;
+
+- cb = (struct nis_cb *) calloc (1, sizeof (struct nis_cb));
++ cb = (struct nis_cb *) calloc (1,
++ sizeof (struct nis_cb) + sizeof (nis_server));
+ if (__builtin_expect (cb == NULL, 0))
+ goto failed;
+- cb->serv = (nis_server *) calloc (1, sizeof (nis_server));
+- if (__builtin_expect (cb->serv == NULL, 0))
+- goto failed;
++ cb->serv = (nis_server *) (cb + 1);
+ cb->serv->name = strdup (nis_local_principal ());
+ if (__builtin_expect (cb->serv->name == NULL, 0))
+ goto failed;
+@@ -326,15 +317,20 @@ __nis_create_callback (int (*callback) (
+ cb->serv->ep.ep_val[0].proto = strdup ((flags & USE_DGRAM) ? "udp" : "tcp");
+ if (__builtin_expect (cb->serv->ep.ep_val[0].proto == NULL, 0))
+ goto failed;
+- cb->xprt = (flags & USE_DGRAM) ? svcudp_bufcreate (sock, 100, 8192) :
+- svctcp_create (sock, 100, 8192);
++ cb->xprt = ((flags & USE_DGRAM)
++ ? svcudp_bufcreate (sock, 100, 8192)
++ : svctcp_create (sock, 100, 8192));
++ if (cb->xprt == NULL)
++ {
++ nomsg = 1;
++ goto failed;
++ }
+ cb->sock = cb->xprt->xp_sock;
+ if (!svc_register (cb->xprt, CB_PROG, CB_VERS, cb_prog_1, 0))
+ {
+ xprt_unregister (cb->xprt);
+ svc_destroy (cb->xprt);
+ xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
+- free (cb->serv);
+ free (cb);
+ syslog (LOG_ERR, "NIS+: failed to register callback dispatcher");
+ return NULL;
+@@ -345,30 +341,31 @@ __nis_create_callback (int (*callback) (
+ xprt_unregister (cb->xprt);
+ svc_destroy (cb->xprt);
+ xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
+- free (cb->serv);
+ free (cb);
+ syslog (LOG_ERR, "NIS+: failed to read local socket info");
+ return NULL;
+ }
+ port = ntohs (sin.sin_port);
+ get_myaddress (&sin);
+- snprintf (addr, sizeof (addr), "%s.%d.%d", inet_ntoa (sin.sin_addr),
+- (port & 0xFF00) >> 8, port & 0x00FF);
+- cb->serv->ep.ep_val[0].uaddr = strdup (addr);
++
++ if (asprintf (&cb->serv->ep.ep_val[0].uaddr, "%s.%d.%d",
++ inet_ntoa (sin.sin_addr), (port & 0xFF00) >> 8, port & 0x00FF)
++ < 0)
++ goto failed;
+
+ return cb;
+
+ failed:
+ if (cb)
+ {
++ if (cb->xprt)
++ svc_destroy (cb->xprt);
+ if (cb->serv)
+- {
+- xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
+- free (cb->serv);
+- }
++ xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
+ free (cb);
+ }
+- syslog (LOG_ERR, "NIS+: out of memory allocating callback");
++ if (!nomsg)
++ syslog (LOG_ERR, "NIS+: out of memory allocating callback");
+ return NULL;
+ }
+
+@@ -379,7 +376,6 @@ __nis_destroy_callback (struct nis_cb *c
+ svc_destroy (cb->xprt);
+ close (cb->sock);
+ xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
+- free (cb->serv);
+ free (cb);
+
+ return NIS_SUCCESS;
+--- libc/nis/nis_domain_of_r.c 15 Dec 2004 17:40:54 -0000 1.5
++++ libc/nis/nis_domain_of_r.c 24 May 2006 04:06:24 -0000 1.6
+@@ -29,6 +29,7 @@ nis_domain_of_r (const_nis_name name, ch
+
+ if (buffer == NULL)
+ {
++ erange:
+ __set_errno (ERANGE);
+ return NULL;
+ }
+@@ -44,7 +45,11 @@ nis_domain_of_r (const_nis_name name, ch
+ cptr_len = strlen (cptr);
+
+ if (cptr_len == 0)
+- return strcpy (buffer, ".");
++ {
++ if (buflen < 2)
++ goto erange;
++ return strcpy (buffer, ".");
++ }
+
+ if (__builtin_expect (cptr_len >= buflen, 0))
+ {
+--- libc/nis/nis_intern.h 13 Dec 2001 03:38:06 -0000 1.20
++++ libc/nis/nis_intern.h 20 May 2006 20:18:03 -0000 1.21
+@@ -66,6 +66,7 @@ extern nis_error __do_niscall3 (dir_bind
+ xdrproc_t xargs, caddr_t req,
+ xdrproc_t xres, caddr_t resp,
+ unsigned int flags, nis_cb *cb);
++libnsl_hidden_proto (__do_niscall3)
+
+ extern u_short __pmap_getnisport (struct sockaddr_in *address, u_long program,
+ u_long version, u_int protocol);
+--- libc/nis/nis_lookup.c 10 May 2006 02:30:20 -0000 1.18
++++ libc/nis/nis_lookup.c 24 May 2006 06:00:54 -0000 1.19
+@@ -21,6 +21,8 @@
+ #include <rpcsvc/nis.h>
+ #include "nis_xdr.h"
+ #include "nis_intern.h"
++#include <libnsl.h>
++
+
+ nis_result *
+ nis_lookup (const_nis_name name, const unsigned int flags)
+@@ -61,36 +63,18 @@ nis_lookup (const_nis_name name, const u
+ req.ns_object.ns_object_len = 0;
+ req.ns_object.ns_object_val = NULL;
+
+- status = __nisfind_server (req.ns_name, &dir);
+- if (status != NIS_SUCCESS)
++ status = __prepare_niscall (req.ns_name, &dir, &bptr, flags);
++ if (__builtin_expect (status != NIS_SUCCESS, 0))
+ {
+ NIS_RES_STATUS (res) = status;
+ goto out;
+ }
+
+- status = __nisbind_create (&bptr, dir->do_servers.do_servers_val,
+- dir->do_servers.do_servers_len, flags);
+- if (status != NIS_SUCCESS)
+- {
+- NIS_RES_STATUS (res) = status;
+- nis_free_directory (dir);
+- goto out;;
+- }
+-
+- while (__nisbind_connect (&bptr) != NIS_SUCCESS)
+- {
+- if (__nisbind_next (&bptr) != NIS_SUCCESS)
+- {
+- nis_free_directory (dir);
+- NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
+- goto out;
+- }
+- }
+-
+ do
+ {
+ static const struct timeval RPCTIMEOUT = {10, 0};
+ enum clnt_stat result;
++ char ndomain[strlen (req.ns_name) + 1];
+
+ again:
+ result = clnt_call (bptr.clnt, NIS_LOOKUP,
+@@ -106,11 +90,9 @@ nis_lookup (const_nis_name name, const u
+
+ if (NIS_RES_STATUS (res) == NIS_SUCCESS)
+ {
+- if (__type_of(NIS_RES_OBJECT (res)) == NIS_LINK_OBJ
++ if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ
+ && (flags & FOLLOW_LINKS)) /* We are following links */
+ {
+- if (count_links)
+- free (req.ns_name);
+ /* if we hit the link limit, bail */
+ if (count_links > NIS_MAXLINKS)
+ {
+@@ -119,31 +101,15 @@ nis_lookup (const_nis_name name, const u
+ }
+ ++count_links;
+ req.ns_name =
+- strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
+- if (req.ns_name == NULL)
+- {
+- nis_free_directory (dir);
+- res = NULL;
+- goto out;
+- }
++ strdupa (NIS_RES_OBJECT (res)->LI_data.li_name);
+
+ /* The following is a non-obvious optimization. A
+ nis_freeresult call would call xdr_free as the
+ following code. But it also would unnecessarily
+ free the result structure. We avoid this here
+ along with the necessary tests. */
+-#if 1
+ xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res);
+ memset (res, '\0', sizeof (*res));
+-#else
+- nis_freeresult (res);
+- res = calloc (1, sizeof (nis_result));
+- if (res == NULL)
+- {
+- __nisbind_destroy (&bptr);
+- return NULL;
+- }
+-#endif
+
+ link_first_try = 1; /* Try at first the old binding */
+ goto again;
+@@ -176,7 +142,24 @@ nis_lookup (const_nis_name name, const u
+ }
+ else
+ if (__nisbind_next (&bptr) != NIS_SUCCESS)
+- break; /* No more servers to search */
++ {
++ /* No more servers to search. Try parent. */
++ nis_domain_of_r (req.ns_name, ndomain,
++ sizeof (ndomain));
++ req.ns_name = strdupa (ndomain);
++
++ __nisbind_destroy (&bptr);
++ nis_free_directory (dir);
++ dir = NULL;
++ status = __prepare_niscall (req.ns_name, &dir,
++ &bptr, flags);
++ if (__builtin_expect (status != NIS_SUCCESS, 0))
++ {
++ NIS_RES_STATUS (res) = status;
++ goto out;
++ }
++ goto again;
++ }
+
+ while (__nisbind_connect (&bptr) != NIS_SUCCESS)
+ {
+--- libc/nis/nis_table.c 5 May 2006 06:32:33 -0000 1.36
++++ libc/nis/nis_table.c 20 May 2006 19:14:20 -0000 1.37
+@@ -17,15 +17,17 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
++#include <assert.h>
+ #include <string.h>
+ #include <rpcsvc/nis.h>
+
+ #include "nis_xdr.h"
+ #include "nis_intern.h"
++#include "libnsl.h"
+
+
+-static struct ib_request *
+-create_ib_request (const_nis_name name, unsigned int flags)
++struct ib_request *
++__create_ib_request (const_nis_name name, unsigned int flags)
+ {
+ struct ib_request *ibreq = calloc (1, sizeof (struct ib_request));
+ nis_attr *search_val = NULL;
+@@ -125,6 +127,7 @@ create_ib_request (const_nis_name name,
+
+ return ibreq;
+ }
++libnsl_hidden_def (__create_ib_request)
+
+ static const struct timeval RPCTIMEOUT = {10, 0};
+
+@@ -160,6 +163,38 @@ get_tablepath (char *name, dir_binding *
+ return str;
+ }
+
++
++nis_error
++__follow_path (char **tablepath, char **tableptr, struct ib_request *ibreq,
++ dir_binding *bptr)
++{
++ if (*tablepath == NULL)
++ {
++ *tablepath = get_tablepath (ibreq->ibr_name, bptr);
++ if (*tablepath == NULL)
++ return NIS_NOMEMORY;
++
++ *tableptr = *tablepath;
++ }
++ if (*tableptr == NULL)
++ return NIS_NOTFOUND;
++
++ char *newname = strsep (tableptr, ":");
++ if (newname[0] == '\0')
++ return NIS_NOTFOUND;
++
++ newname = strdup (newname);
++ if (newname == NULL)
++ return NIS_NOMEMORY;
++
++ free (ibreq->ibr_name);
++ ibreq->ibr_name = newname;
++
++ return NIS_SUCCESS;
++}
++libnsl_hidden_def (__follow_path)
++
++
+ nis_result *
+ nis_list (const_nis_name name, unsigned int flags,
+ int (*callback) (const_nis_name name,
+@@ -193,7 +228,7 @@ nis_list (const_nis_name name, unsigned
+ return res;
+ }
+
+- ibreq = create_ib_request (name, flags);
++ ibreq = __create_ib_request (name, flags);
+ if (ibreq == NULL)
+ {
+ status = NIS_BADNAME;
+@@ -260,6 +295,7 @@ nis_list (const_nis_name name, unsigned
+
+ if (callback != NULL)
+ {
++ assert (cb == NULL);
+ cb = __nis_create_callback (callback, userdata, flags);
+ ibreq->ibr_cbhost.ibr_cbhost_len = 1;
+ ibreq->ibr_cbhost.ibr_cbhost_val = cb->serv;
+@@ -327,69 +363,30 @@ nis_list (const_nis_name name, unsigned
+ following code. But it also would unnecessarily
+ free the result structure. We avoid this here
+ along with the necessary tests. */
+-#if 1
+ xdr_free ((xdrproc_t) _xdr_nis_result, (char *)res);
+ memset (res, '\0', sizeof (*res));
+-#else
+- nis_freeresult (res);
+- res = calloc (1, sizeof (nis_result));
+- if (res == NULL)
+- goto fail;
+-#endif
+ first_try = 1; /* Try at first the old binding */
+ goto again;
+ }
+ else if ((flags & FOLLOW_PATH)
+ && NIS_RES_STATUS (res) == NIS_PARTIAL)
+ {
+- if (tablepath == NULL)
+- {
+- tablepath = get_tablepath (ibreq->ibr_name, &bptr);
+- tableptr = tablepath;
+- }
+- if (tableptr == NULL)
++ clnt_status = __follow_path (&tablepath, &tableptr, ibreq,
++ &bptr);
++ if (clnt_status != NIS_SUCCESS)
+ {
+- ++done;
+- break;
+- }
+- free (ibreq->ibr_name);
+- ibreq->ibr_name = strsep (&tableptr, ":");
+- if (ibreq->ibr_name == NULL || ibreq->ibr_name[0] == '\0')
+- {
+- ibreq->ibr_name = strdup ("");
+- if (ibreq->ibr_name == NULL)
+- {
+- NIS_RES_STATUS (res) = NIS_NOMEMORY;
+- goto fail;
+- }
++ NIS_RES_STATUS (res) = clnt_status;
+ ++done;
+ }
+ else
+ {
+- ibreq->ibr_name = strdup (ibreq->ibr_name);
+ /* The following is a non-obvious optimization. A
+ nis_freeresult call would call xdr_free as the
+ following code. But it also would unnecessarily
+ free the result structure. We avoid this here
+ along with the necessary tests. */
+-#if 1
+- xdr_free ((xdrproc_t) _xdr_nis_result, (char *)res);
++ xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res);
+ memset (res, '\0', sizeof (*res));
+- if (ibreq->ibr_name == NULL)
+- {
+- NIS_RES_STATUS (res) = NIS_NOMEMORY;
+- goto fail;
+- }
+-#else
+- nis_freeresult (res);
+- res = calloc (1, sizeof (nis_result));
+- if (res == NULL || ibreq->ibr_name == NULL)
+- {
+- free (res);
+- res = NULL;
+- goto fail;
+- }
+-#endif
+ first_try = 1;
+ goto again;
+ }
+@@ -407,30 +404,10 @@ nis_list (const_nis_name name, unsigned
+ ++done;
+ else
+ {
+- if (tablepath == NULL)
+- {
+- tablepath = get_tablepath (ibreq->ibr_name, &bptr);
+- tableptr = tablepath;
+- }
+- if (tableptr == NULL)
+- {
+- ++done;
+- break;
+- }
+- free (ibreq->ibr_name);
+- ibreq->ibr_name = strsep (&tableptr, ":");
+- if (ibreq->ibr_name == NULL || ibreq->ibr_name[0] == '\0')
+- {
+- ibreq->ibr_name = strdup ("");
+- ++done;
+- }
+- else
+- ibreq->ibr_name = strdup (ibreq->ibr_name);
+- if (ibreq->ibr_name == NULL)
+- {
+- NIS_RES_STATUS (res) = NIS_NOMEMORY;
+- goto fail;
+- }
++ NIS_RES_STATUS (res)
++ = __follow_path (&tablepath, &tableptr, ibreq, &bptr);
++ if (NIS_RES_STATUS (res) != NIS_SUCCESS)
++ ++done;
+ }
+ }
+ break;
+@@ -524,7 +501,7 @@ nis_add_entry (const_nis_name name, cons
+ return res;
+ }
+
+- ib_request *ibreq = create_ib_request (name, flags);
++ ib_request *ibreq = __create_ib_request (name, flags);
+ if (ibreq == NULL)
+ {
+ NIS_RES_STATUS (res) = NIS_BADNAME;
+@@ -587,7 +564,7 @@ nis_modify_entry (const_nis_name name, c
+ if (res == NULL)
+ return NULL;
+
+- ibreq = create_ib_request (name, flags);
++ ibreq = __create_ib_request (name, flags);
+ if (ibreq == NULL)
+ {
+ NIS_RES_STATUS (res) = NIS_BADNAME;
+@@ -646,7 +623,7 @@ nis_remove_entry (const_nis_name name, c
+ return res;
+ }
+
+- ibreq = create_ib_request (name, flags);
++ ibreq = __create_ib_request (name, flags);
+ if (ibreq == NULL)
+ {
+ NIS_RES_STATUS (res) = NIS_BADNAME;
+@@ -693,7 +670,7 @@ nis_first_entry (const_nis_name name)
+ return res;
+ }
+
+- ibreq = create_ib_request (name, 0);
++ ibreq = __create_ib_request (name, 0);
+ if (ibreq == NULL)
+ {
+ NIS_RES_STATUS (res) = NIS_BADNAME;
+@@ -730,7 +707,7 @@ nis_next_entry (const_nis_name name, con
+ return res;
+ }
+
+- ibreq = create_ib_request (name, 0);
++ ibreq = __create_ib_request (name, 0);
+ if (ibreq == NULL)
+ {
+ NIS_RES_STATUS (res) = NIS_BADNAME;
+--- libc/nis/nis_xdr.c 12 May 2006 02:39:20 -0000 1.11
++++ libc/nis/nis_xdr.c 20 May 2006 19:15:24 -0000 1.12
+@@ -308,6 +308,7 @@ _xdr_nis_result (XDR *xdrs, nis_result *
+ }
+ return res;
+ }
++libnsl_hidden_def (_xdr_nis_result)
+
+ bool_t
+ _xdr_ns_request (XDR *xdrs, ns_request *objp)
+@@ -357,6 +358,7 @@ _xdr_ib_request (XDR *xdrs, ib_request *
+ }
+ return res;
+ }
++libnsl_hidden_def (_xdr_ib_request)
+
+ bool_t
+ _xdr_ping_args (XDR *xdrs, ping_args *objp)
+--- libc/nis/nis_xdr.h 11 May 2006 20:35:47 -0000 1.4
++++ libc/nis/nis_xdr.h 20 May 2006 19:16:04 -0000 1.5
+@@ -30,9 +30,7 @@ extern bool_t _xdr_nis_server (XDR *, n
+ extern bool_t _xdr_directory_obj (XDR *, directory_obj*);
+ extern bool_t _xdr_nis_object (XDR *, nis_object*);
+ extern bool_t _xdr_nis_error (XDR *, nis_error*);
+-extern bool_t _xdr_nis_result (XDR *, nis_result*);
+ extern bool_t _xdr_ns_request (XDR *, ns_request*);
+-extern bool_t _xdr_ib_request (XDR *, ib_request*);
+ extern bool_t _xdr_ping_args (XDR *, ping_args*);
+ extern bool_t _xdr_cp_result (XDR *, cp_result*);
+ extern bool_t _xdr_nis_tag (XDR *, nis_tag*);
+@@ -42,4 +40,9 @@ extern bool_t _xdr_fd_result (XDR *, fd
+
+ __END_DECLS
+
++extern bool_t _xdr_ib_request (XDR *, ib_request*);
++libnsl_hidden_proto (_xdr_ib_request)
++extern bool_t _xdr_nis_result (XDR *, nis_result*);
++libnsl_hidden_proto (_xdr_nis_result)
++
+ #endif
+--- libc/nis/nisplus-parser.h 29 Apr 2006 20:16:35 -0000 1.6
++++ libc/nis/nisplus-parser.h 20 May 2006 19:17:04 -0000 1.7
+@@ -24,15 +24,12 @@
+ #include <grp.h>
+ #include <shadow.h>
+
+-extern int _nss_nisplus_parse_pwent (nis_result *result, size_t entry,
+- struct passwd *pw, char *buffer,
+- size_t buflen, int *errnop);
+-extern int _nss_nisplus_parse_pwent_chk (nis_result *result, struct passwd *pw,
+- char *buffer, size_t buflen,
+- int *errnop);
+-extern int _nss_nisplus_parse_grent (nis_result *result, u_long entry,
+- struct group *gr, char *buffer,
+- size_t buflen, int *errnop);
++extern int _nss_nisplus_parse_pwent (nis_result *result, struct passwd *pw,
++ char *buffer, size_t buflen, int *errnop);
++
++extern int _nss_nisplus_parse_grent (nis_result *result, struct group *gr,
++ char *buffer, size_t buflen, int *errnop);
++
+ extern int _nss_nisplus_parse_spent (nis_result *result, struct spwd *sp,
+ char *buffer, size_t buflen, int *errnop);
+
+--- libc/nis/nss_nisplus/nisplus-grp.c 25 Mar 2006 20:59:19 -0000 1.19
++++ libc/nis/nss_nisplus/nisplus-grp.c 20 May 2006 19:20:19 -0000 1.20
+@@ -29,12 +29,23 @@
+
+ #include "nss-nisplus.h"
+ #include "nisplus-parser.h"
++#include <libnsl.h>
++#include <nis_intern.h>
++#include <nis_xdr.h>
+
+
+ __libc_lock_define_initialized (static, lock);
+
+-static nis_result *result;
+-static unsigned long next_entry;
++/* Connection information. */
++static ib_request *ibreq;
++static directory_obj *dir;
++static dir_binding bptr;
++static char *tablepath;
++static char *tableptr;
++/* Cursor. */
++static netobj cursor;
++
++
+ static nis_name tablename_val;
+ static size_t tablename_len;
+
+@@ -66,43 +77,57 @@ _nss_create_tablename (int *errnop)
+ return NSS_STATUS_SUCCESS;
+ }
+
+-static enum nss_status
+-internal_setgrent (void)
++
++static void
++internal_endgrent (void)
+ {
+- enum nss_status status;
++ __nisbind_destroy (&bptr);
++ memset (&bptr, '\0', sizeof (bptr));
+
+- if (result != NULL)
+- {
+- nis_freeresult (result);
+- result = NULL;
+- }
+- next_entry = 0;
++ nis_free_directory (dir);
++ dir = NULL;
++
++ nis_free_request (ibreq);
++ ibreq = NULL;
++
++ xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor);
++ memset (&cursor, '\0', sizeof (cursor));
++
++ free (tablepath);
++ tableptr = tablepath = NULL;
++}
++
++
++static enum nss_status
++internal_setgrent (int *errnop)
++{
++ enum nss_status status = NSS_STATUS_SUCCESS;
+
+ if (tablename_val == NULL)
+- {
+- int err;
+- if (_nss_create_tablename (&err) != NSS_STATUS_SUCCESS)
+- return NSS_STATUS_UNAVAIL;
+- }
++ status = _nss_create_tablename (errnop);
+
+- result = nis_list (tablename_val, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
+- if (result == NULL)
++ if (status == NSS_STATUS_SUCCESS)
+ {
+- status = NSS_STATUS_TRYAGAIN;
+- __set_errno (ENOMEM);
+- }
+- else
+- {
+- status = niserr2nss (result->status);
+- if (status != NSS_STATUS_SUCCESS)
++ ibreq = __create_ib_request (tablename_val, 0);
++ if (ibreq == NULL)
+ {
+- nis_freeresult (result);
+- result = NULL;
++ *errnop = errno;
++ return NSS_STATUS_TRYAGAIN;
++ }
++
++ nis_error retcode = __prepare_niscall (tablename_val, &dir, &bptr, 0);
++ if (retcode != NIS_SUCCESS)
++ {
++ nis_free_request (ibreq);
++ ibreq = NULL;
++ status = niserr2nss (retcode);
+ }
+ }
++
+ return status;
+ }
+
++
+ enum nss_status
+ _nss_nisplus_setgrent (int stayopen)
+ {
+@@ -110,60 +135,133 @@ _nss_nisplus_setgrent (int stayopen)
+
+ __libc_lock_lock (lock);
+
+- status = internal_setgrent ();
++ internal_endgrent ();
++
++ // XXX We need to be able to set errno. Pass in new parameter.
++ int err;
++ status = internal_setgrent (&err);
+
+ __libc_lock_unlock (lock);
+
+ return status;
+ }
+
++
+ enum nss_status
+ _nss_nisplus_endgrent (void)
+ {
+ __libc_lock_lock (lock);
+
+- if (result != NULL)
+- {
+- nis_freeresult (result);
+- result = NULL;
+- }
++ internal_endgrent ();
+
+ __libc_lock_unlock (lock);
+
+ return NSS_STATUS_SUCCESS;
+ }
+
++
+ static enum nss_status
+ internal_nisplus_getgrent_r (struct group *gr, char *buffer, size_t buflen,
+ int *errnop)
+ {
+- int parse_res;
+-
+- if (result == NULL)
+- {
+- enum nss_status status;
+-
+- status = internal_setgrent ();
+- if (result == NULL || status != NSS_STATUS_SUCCESS)
+- return status;
+- }
++ int parse_res = -1;
++ enum nss_status retval = NSS_STATUS_SUCCESS;
+
+ /* Get the next entry until we found a correct one. */
+ do
+ {
+- if (next_entry >= result->objects.objects_len)
+- return NSS_STATUS_NOTFOUND;
++ nis_error status;
++ nis_result result;
++ memset (&result, '\0', sizeof (result));
++
++ if (cursor.n_bytes == NULL)
++ {
++ if (ibreq == NULL)
++ {
++ retval = internal_setgrent (errnop);
++ if (retval != NSS_STATUS_SUCCESS)
++ return retval;
++ }
++
++ status = __do_niscall3 (&bptr, NIS_IBFIRST,
++ (xdrproc_t) _xdr_ib_request,
++ (caddr_t) ibreq,
++ (xdrproc_t) _xdr_nis_result,
++ (caddr_t) &result,
++ 0, NULL);
++ }
++ else
++ {
++ ibreq->ibr_cookie.n_bytes = cursor.n_bytes;
++ ibreq->ibr_cookie.n_len = cursor.n_len;
++
++ status = __do_niscall3 (&bptr, NIS_IBNEXT,
++ (xdrproc_t) _xdr_ib_request,
++ (caddr_t) ibreq,
++ (xdrproc_t) _xdr_nis_result,
++ (caddr_t) &result,
++ 0, NULL);
+
+- parse_res = _nss_nisplus_parse_grent (result, next_entry, gr,
++ ibreq->ibr_cookie.n_bytes = NULL;
++ ibreq->ibr_cookie.n_len = 0;
++ }
++
++ if (status != NIS_SUCCESS)
++ return niserr2nss (status);
++
++ if (NIS_RES_STATUS (&result) == NIS_NOTFOUND)
++ {
++ /* No more entries on this server. This means we have to go
++ to the next server on the path. */
++ status = __follow_path (&tablepath, &tableptr, ibreq, &bptr);
++ if (status != NIS_SUCCESS)
++ return niserr2nss (status);
++
++ directory_obj *newdir = NULL;
++ dir_binding newbptr;
++ status = __prepare_niscall (ibreq->ibr_name, &newdir, &newbptr, 0);
++ if (status != NIS_SUCCESS)
++ return niserr2nss (status);
++
++ nis_free_directory (dir);
++ dir = newdir;
++ __nisbind_destroy (&bptr);
++ bptr = newbptr;
++
++ xdr_free ((xdrproc_t) xdr_netobj, (char *) &result.cookie);
++ result.cookie.n_bytes = NULL;
++ result.cookie.n_len = 0;
++ parse_res = 0;
++ goto next;
++ }
++ else if (NIS_RES_STATUS (&result) != NIS_SUCCESS)
++ return niserr2nss (NIS_RES_STATUS (&result));
++
++ parse_res = _nss_nisplus_parse_grent (&result, gr,
+ buffer, buflen, errnop);
+- if (parse_res == -1)
+- return NSS_STATUS_TRYAGAIN;
++ if (__builtin_expect (parse_res == -1, 0))
++ {
++ *errnop = ERANGE;
++ retval = NSS_STATUS_TRYAGAIN;
++ goto freeres;
++ }
+
+- ++next_entry;
++ next:
++ /* Free the old cursor. */
++ xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor);
++ /* Remember the new one. */
++ cursor.n_bytes = result.cookie.n_bytes;
++ cursor.n_len = result.cookie.n_len;
++ /* Free the result structure. NB: we do not remove the cookie. */
++ result.cookie.n_bytes = NULL;
++ result.cookie.n_len = 0;
++ freeres:
++ xdr_free ((xdrproc_t) _xdr_nis_result, (char *) &result);
++ memset (&result, '\0', sizeof (result));
+ }
+ while (!parse_res);
+
+- return NSS_STATUS_SUCCESS;
++ return retval;
+ }
+
+ enum nss_status
+@@ -227,7 +325,7 @@ _nss_nisplus_getgrnam_r (const char *nam
+ return status;
+ }
+
+- parse_res = _nss_nisplus_parse_grent (result, 0, gr, buffer, buflen, errnop);
++ parse_res = _nss_nisplus_parse_grent (result, gr, buffer, buflen, errnop);
+ nis_freeresult (result);
+ if (__builtin_expect (parse_res < 1, 0))
+ {
+@@ -288,7 +386,7 @@ _nss_nisplus_getgrgid_r (const gid_t gid
+ return status;
+ }
+
+- parse_res = _nss_nisplus_parse_grent (result, 0, gr, buffer, buflen, errnop);
++ parse_res = _nss_nisplus_parse_grent (result, gr, buffer, buflen, errnop);
+
+ nis_freeresult (result);
+ if (__builtin_expect (parse_res < 1, 0))
+--- libc/nis/nss_nisplus/nisplus-parser.c 30 Apr 2006 07:00:12 -0000 1.16
++++ libc/nis/nss_nisplus/nisplus-parser.c 20 May 2006 19:17:59 -0000 1.17
+@@ -31,10 +31,16 @@
+ #define NISENTRYLEN(idx, col, res) \
+ (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
+
++#define NISOBJVAL(col, obj) \
++ ((obj)->EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
++
++#define NISOBJLEN(col, obj) \
++ ((obj)->EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
++
+
+ int
+-_nss_nisplus_parse_pwent_chk (nis_result *result, struct passwd *pw,
+- char *buffer, size_t buflen, int *errnop)
++_nss_nisplus_parse_pwent (nis_result *result, struct passwd *pw,
++ char *buffer, size_t buflen, int *errnop)
+ {
+ if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
+ || NIS_RES_NUMOBJ (result) != 1
+@@ -43,19 +49,12 @@ _nss_nisplus_parse_pwent_chk (nis_result
+ || NIS_RES_OBJECT (result)->EN_data.en_cols.en_cols_len < 7)
+ return 0;
+
+- return _nss_nisplus_parse_pwent (result, 0, pw, buffer, buflen, errnop);
+-}
+-
+-
+-int
+-_nss_nisplus_parse_pwent (nis_result *result, size_t entry, struct passwd *pw,
+- char *buffer, size_t buflen, int *errnop)
+-{
++ nis_object *obj = NIS_RES_OBJECT (result);
+ char *first_unused = buffer;
+ size_t room_left = buflen;
+ size_t len;
+
+- if (NISENTRYLEN (entry, 0, result) >= room_left)
++ if (NISOBJLEN (0, obj) >= room_left)
+ {
+ /* The line is too long for our buffer. */
+ no_more_room:
+@@ -63,9 +62,8 @@ _nss_nisplus_parse_pwent (nis_result *re
+ return -1;
+ }
+
+- strncpy (first_unused, NISENTRYVAL (entry, 0, result),
+- NISENTRYLEN (entry, 0, result));
+- first_unused[NISENTRYLEN (entry, 0, result)] = '\0';
++ strncpy (first_unused, NISOBJVAL (0, obj), NISOBJLEN (0, obj));
++ first_unused[NISOBJLEN (0, obj)] = '\0';
+ len = strlen (first_unused);
+ if (len == 0) /* No name ? Should never happen, database is corrupt */
+ return 0;
+@@ -73,19 +71,18 @@ _nss_nisplus_parse_pwent (nis_result *re
+ room_left -= len + 1;
+ first_unused += len + 1;
+
+- if (NISENTRYLEN (entry, 1, result) >= room_left)
++ if (NISOBJLEN (1, obj) >= room_left)
+ goto no_more_room;
+
+- strncpy (first_unused, NISENTRYVAL (entry, 1, result),
+- NISENTRYLEN (entry, 1, result));
+- first_unused[NISENTRYLEN (entry, 1, result)] = '\0';
++ strncpy (first_unused, NISOBJVAL (1, obj), NISOBJLEN (1, obj));
++ first_unused[NISOBJLEN (1, obj)] = '\0';
+ pw->pw_passwd = first_unused;
+ len = strlen (first_unused);
+ room_left -= len + 1;
+ first_unused += len + 1;
+
+- char *numstr = NISENTRYVAL (entry, 2, result);
+- len = NISENTRYLEN (entry, 2, result);
++ char *numstr = NISOBJVAL (2, obj);
++ len = NISOBJLEN (2, obj);
+ if (len == 0 && numstr[len - 1] != '\0')
+ {
+ if (len >= room_left)
+@@ -100,8 +97,8 @@ _nss_nisplus_parse_pwent (nis_result *re
+ return 0;
+ pw->pw_uid = strtoul (numstr, NULL, 10);
+
+- numstr = NISENTRYVAL (entry, 3, result);
+- len = NISENTRYLEN (entry, 3, result);
++ numstr = NISOBJVAL (3, obj);
++ len = NISOBJLEN (3, obj);
+ if (len == 0 && numstr[len - 1] != '\0')
+ {
+ if (len >= room_left)
+@@ -116,34 +113,31 @@ _nss_nisplus_parse_pwent (nis_result *re
+ return 0;
+ pw->pw_gid = strtoul (numstr, NULL, 10);
+
+- if (NISENTRYLEN(entry, 4, result) >= room_left)
++ if (NISOBJLEN(4, obj) >= room_left)
+ goto no_more_room;
+
+- strncpy (first_unused, NISENTRYVAL (entry, 4, result),
+- NISENTRYLEN (entry, 4, result));
+- first_unused[NISENTRYLEN (entry, 4, result)] = '\0';
++ strncpy (first_unused, NISOBJVAL (4, obj), NISOBJLEN (4, obj));
++ first_unused[NISOBJLEN (4, obj)] = '\0';
+ pw->pw_gecos = first_unused;
+ len = strlen (first_unused);
+ room_left -= len + 1;
+ first_unused += len + 1;
+
+- if (NISENTRYLEN (entry, 5, result) >= room_left)
++ if (NISOBJLEN (5, obj) >= room_left)
+ goto no_more_room;
+
+- strncpy (first_unused, NISENTRYVAL (entry, 5, result),
+- NISENTRYLEN (entry, 5, result));
+- first_unused[NISENTRYLEN (entry, 5, result)] = '\0';
++ strncpy (first_unused, NISOBJVAL (5, obj), NISOBJLEN (5, obj));
++ first_unused[NISOBJLEN (5, obj)] = '\0';
+ pw->pw_dir = first_unused;
+ len = strlen (first_unused);
+ room_left -= len + 1;
+ first_unused += len + 1;
+
+- if (NISENTRYLEN (entry, 6, result) >= room_left)
++ if (NISOBJLEN (6, obj) >= room_left)
+ goto no_more_room;
+
+- strncpy (first_unused, NISENTRYVAL (entry, 6, result),
+- NISENTRYLEN (entry, 6, result));
+- first_unused[NISENTRYLEN (entry, 6, result)] = '\0';
++ strncpy (first_unused, NISOBJVAL (6, obj), NISOBJLEN (6, obj));
++ first_unused[NISOBJLEN (6, obj)] = '\0';
+ pw->pw_shell = first_unused;
+ len = strlen (first_unused);
+ room_left -= len + 1;
+@@ -154,26 +148,23 @@ _nss_nisplus_parse_pwent (nis_result *re
+
+
+ int
+-_nss_nisplus_parse_grent (nis_result *result, u_long entry, struct group *gr,
++_nss_nisplus_parse_grent (nis_result *result, struct group *gr,
+ char *buffer, size_t buflen, int *errnop)
+ {
++ if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
++ || __type_of(NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
++ || strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type, "group_tbl") != 0
++ || NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 4)
++ return 0;
++
++ nis_object *obj = NIS_RES_OBJECT (result);
+ char *first_unused = buffer;
+ size_t room_left = buflen;
+ char *line;
+ int count;
+ size_t len;
+
+- if (result == NULL)
+- return 0;
+-
+- if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
+- || __type_of(NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
+- || strcmp (NIS_RES_OBJECT (result)[entry].EN_data.en_type,
+- "group_tbl") != 0
+- || NIS_RES_OBJECT (result)[entry].EN_data.en_cols.en_cols_len < 4)
+- return 0;
+-
+- if (NISENTRYLEN (entry, 0, result) >= room_left)
++ if (NISOBJLEN (0, obj) >= room_left)
+ {
+ /* The line is too long for our buffer. */
+ no_more_room:
+@@ -181,9 +172,8 @@ _nss_nisplus_parse_grent (nis_result *re
+ return -1;
+ }
+
+- strncpy (first_unused, NISENTRYVAL (entry, 0, result),
+- NISENTRYLEN (entry, 0, result));
+- first_unused[NISENTRYLEN (entry, 0, result)] = '\0';
++ strncpy (first_unused, NISOBJVAL (0, obj), NISOBJLEN (0, obj));
++ first_unused[NISOBJLEN (0, obj)] = '\0';
+ len = strlen (first_unused);
+ if (len == 0) /* group table is corrupt */
+ return 0;
+@@ -191,20 +181,19 @@ _nss_nisplus_parse_grent (nis_result *re
+ room_left -= len + 1;
+ first_unused += len + 1;
+
+- if (NISENTRYLEN (entry, 1, result) >= room_left)
++ if (NISOBJLEN (1, obj) >= room_left)
+ goto no_more_room;
+
+- strncpy (first_unused, NISENTRYVAL (entry, 1, result),
+- NISENTRYLEN (entry, 1, result));
+- first_unused[NISENTRYLEN (entry, 1, result)] = '\0';
++ strncpy (first_unused, NISOBJVAL (1, obj), NISOBJLEN (1, obj));
++ first_unused[NISOBJLEN (1, obj)] = '\0';
+ gr->gr_passwd = first_unused;
+ len = strlen (first_unused);
+ room_left -= len + 1;
+ first_unused += len + 1;
+
+- char *numstr = NISENTRYVAL (entry, 2, result);
+- len = NISENTRYLEN (entry, 2, result);
+- if (len == 0 && numstr[len - 1] != '\0')
++ char *numstr = NISOBJVAL (2, obj);
++ len = NISOBJLEN (2, obj);
++ if (len == 0 || numstr[len - 1] != '\0')
+ {
+ if (len >= room_left)
+ goto no_more_room;
+@@ -218,12 +207,11 @@ _nss_nisplus_parse_grent (nis_result *re
+ return 0;
+ gr->gr_gid = strtoul (numstr, NULL, 10);
+
+- if (NISENTRYLEN (entry, 3, result) >= room_left)
++ if (NISOBJLEN (3, obj) >= room_left)
+ goto no_more_room;
+
+- strncpy (first_unused, NISENTRYVAL (entry, 3, result),
+- NISENTRYLEN (entry, 3, result));
+- first_unused[NISENTRYLEN (entry, 3, result)] = '\0';
++ strncpy (first_unused, NISOBJVAL (3, obj), NISOBJLEN (3, obj));
++ first_unused[NISOBJLEN (3, obj)] = '\0';
+ line = first_unused;
+ len = strlen (line);
+ room_left -= len + 1;
+--- libc/nis/nss_nisplus/nisplus-pwd.c 29 Apr 2006 20:19:09 -0000 1.22
++++ libc/nis/nss_nisplus/nisplus-pwd.c 20 May 2006 19:20:19 -0000 1.23
+@@ -29,16 +29,21 @@
+ #include "nss-nisplus.h"
+ #include "nisplus-parser.h"
+ #include <libnsl.h>
++#include <nis_intern.h>
++#include <nis_xdr.h>
+
+
+ __libc_lock_define_initialized (static, lock)
+
+-/* Previous result of iteration. */
+-static nis_result *result;
++/* Connection information. */
++static ib_request *ibreq;
++static directory_obj *dir;
++static dir_binding bptr;
++static char *tablepath;
++static char *tableptr;
++/* Cursor. */
++static netobj cursor;
+
+-/* All results of batch table load. */
+-static nis_result *cached_results;
+-static size_t cached_results_iter;
+
+ nis_name pwd_tablename_val attribute_hidden;
+ size_t pwd_tablename_len attribute_hidden;
+@@ -80,50 +85,48 @@ _nss_pwd_create_tablename (int *errnop)
+ static void
+ internal_nisplus_endpwent (void)
+ {
+- if (cached_results != NULL)
+- {
+- nis_freeresult (cached_results);
+- cached_results = NULL;
+- cached_results_iter = 0;
+- }
++ __nisbind_destroy (&bptr);
++ memset (&bptr, '\0', sizeof (bptr));
+
+- if (result != NULL)
+- {
+- nis_freeresult (result);
+- result = NULL;
+- }
++ nis_free_directory (dir);
++ dir = NULL;
++
++ nis_free_request (ibreq);
++ ibreq = NULL;
++
++ xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor);
++ memset (&cursor, '\0', sizeof (cursor));
++
++ free (tablepath);
++ tableptr = tablepath = NULL;
+ }
+
+
+ static enum nss_status
+ internal_nisplus_setpwent (int *errnop)
+ {
+- enum nss_status status;
++ enum nss_status status = NSS_STATUS_SUCCESS;
+
+- cached_results = nis_list (pwd_tablename_val, FOLLOW_PATH | FOLLOW_LINKS,
+- NULL, NULL);
++ if (pwd_tablename_val == NULL)
++ status = _nss_pwd_create_tablename (errnop);
+
+- if (cached_results == NULL)
++ if (status == NSS_STATUS_SUCCESS)
+ {
+- *errnop = errno;
+- status = NSS_STATUS_TRYAGAIN;
+- }
+- else if (__builtin_expect ((status = niserr2nss (cached_results->status))
+- != NSS_STATUS_SUCCESS, 0))
+- {
+- nis_freeresult (cached_results);
+- cached_results = NULL;
+- }
+- else if (__builtin_expect (__type_of (NIS_RES_OBJECT (cached_results))
+- != NIS_ENTRY_OBJ
+- || strcmp (NIS_RES_OBJECT (cached_results)->EN_data.en_type,
+- "passwd_tbl") != 0
+- || NIS_RES_OBJECT (cached_results)->EN_data.en_cols.en_cols_len < 7,
+- 0))
+- {
+- nis_freeresult (cached_results);
+- cached_results = NULL;
+- status = NSS_STATUS_NOTFOUND;
++ ibreq = __create_ib_request (pwd_tablename_val, 0);
++ if (ibreq == NULL)
++ {
++ *errnop = errno;
++ return NSS_STATUS_TRYAGAIN;
++ }
++
++ nis_error retcode = __prepare_niscall (pwd_tablename_val, &dir,
++ &bptr, 0);
++ if (retcode != NIS_SUCCESS)
++ {
++ nis_free_request (ibreq);
++ ibreq = NULL;
++ status = niserr2nss (retcode);
++ }
+ }
+
+ return status;
+@@ -133,26 +136,15 @@ internal_nisplus_setpwent (int *errnop)
+ enum nss_status
+ _nss_nisplus_setpwent (int stayopen)
+ {
+- enum nss_status status = NSS_STATUS_SUCCESS;
++ enum nss_status status;
+
+ __libc_lock_lock (lock);
+
+ internal_nisplus_endpwent ();
+
+- if (pwd_tablename_val == NULL)
+- {
+- // XXX We need to be able to set errno. Pass in new parameter.
+- int err;
+- status = _nss_pwd_create_tablename (&err);
+- }
+-
+- if (status == NSS_STATUS_SUCCESS
+- && (_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ))
+- {
+- // XXX We need to be able to set errno. Pass in new parameter.
+- int err;
+- status = internal_nisplus_setpwent (&err);
+- }
++ // XXX We need to be able to set errno. Pass in new parameter.
++ int err;
++ status = internal_nisplus_setpwent (&err);
+
+ __libc_lock_unlock (lock);
+
+@@ -178,98 +170,104 @@ internal_nisplus_getpwent_r (struct pass
+ int *errnop)
+ {
+ int parse_res = -1;
+- nis_result *saved_res = NULL;
++ enum nss_status retval = NSS_STATUS_SUCCESS;
+
+ /* Get the next entry until we found a correct one. */
+ do
+ {
+- if (cached_results != NULL)
++ nis_error status;
++ nis_result result;
++ memset (&result, '\0', sizeof (result));
++
++ if (cursor.n_bytes == NULL)
+ {
+- handle_batch_read:
+- /* See whether we reported the last problem. */
+- if (cached_results_iter >= NIS_RES_NUMOBJ (cached_results))
+- return NSS_STATUS_NOTFOUND;
+-
+- parse_res = _nss_nisplus_parse_pwent (cached_results,
+- cached_results_iter, pw,
+- buffer, buflen, errnop);
++ if (ibreq == NULL)
++ {
++ retval = internal_nisplus_setpwent (errnop);
++ if (retval != NSS_STATUS_SUCCESS)
++ return retval;
++ }
++
++ status = __do_niscall3 (&bptr, NIS_IBFIRST,
++ (xdrproc_t) _xdr_ib_request,
++ (caddr_t) ibreq,
++ (xdrproc_t) _xdr_nis_result,
++ (caddr_t) &result,
++ 0, NULL);
+ }
+ else
+ {
+- if (result == NULL)
+- {
+- if (pwd_tablename_val == NULL)
+- {
+- enum nss_status status = _nss_pwd_create_tablename (errnop);
+-
+- if (status != NSS_STATUS_SUCCESS)
+- return status;
+- }
+-
+- /* Determine whether we should instead read all entries at
+- once. */
+- if (_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ)
+- {
+- enum nss_status status = internal_nisplus_setpwent (errnop);
+-
+- if (status == NSS_STATUS_SUCCESS && cached_results != NULL)
+- goto handle_batch_read;
+- }
+-
+- saved_res = NULL;
+-
+- result = nis_first_entry (pwd_tablename_val);
+- if (result == NULL)
+- {
+- *errnop = errno;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+- return niserr2nss (result->status);
+- }
+- else
+- {
+- saved_res = result;
+- result = nis_next_entry (pwd_tablename_val, &result->cookie);
+- if (result == NULL)
+- {
+- *errnop = errno;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+- {
+- nis_freeresult (saved_res);
+- return niserr2nss (result->status);
+- }
+- }
++ ibreq->ibr_cookie.n_bytes = cursor.n_bytes;
++ ibreq->ibr_cookie.n_len = cursor.n_len;
+
+- parse_res = _nss_nisplus_parse_pwent_chk (result, pw, buffer,
+- buflen, errnop);
++ status = __do_niscall3 (&bptr, NIS_IBNEXT,
++ (xdrproc_t) _xdr_ib_request,
++ (caddr_t) ibreq,
++ (xdrproc_t) _xdr_nis_result,
++ (caddr_t) &result,
++ 0, NULL);
++
++ ibreq->ibr_cookie.n_bytes = NULL;
++ ibreq->ibr_cookie.n_len = 0;
++ }
++
++ if (status != NIS_SUCCESS)
++ return niserr2nss (status);
++
++ if (NIS_RES_STATUS (&result) == NIS_NOTFOUND)
++ {
++ /* No more entries on this server. This means we have to go
++ to the next server on the path. */
++ status = __follow_path (&tablepath, &tableptr, ibreq, &bptr);
++ if (status != NIS_SUCCESS)
++ return niserr2nss (status);
++
++ directory_obj *newdir = NULL;
++ dir_binding newbptr;
++ status = __prepare_niscall (ibreq->ibr_name, &newdir, &newbptr, 0);
++ if (status != NIS_SUCCESS)
++ return niserr2nss (status);
++
++ nis_free_directory (dir);
++ dir = newdir;
++ __nisbind_destroy (&bptr);
++ bptr = newbptr;
++
++ xdr_free ((xdrproc_t) xdr_netobj, (char *) &result.cookie);
++ result.cookie.n_bytes = NULL;
++ result.cookie.n_len = 0;
++ parse_res = 0;
++ goto next;
+ }
++ else if (NIS_RES_STATUS (&result) != NIS_SUCCESS)
++ return niserr2nss (NIS_RES_STATUS (&result));
++
++ parse_res = _nss_nisplus_parse_pwent (&result, pw, buffer,
++ buflen, errnop);
+
+ if (__builtin_expect (parse_res == -1, 0))
+ {
+- if (cached_results == NULL)
+- {
+- nis_freeresult (result);
+- result = saved_res;
+- }
+ *errnop = ERANGE;
+- return NSS_STATUS_TRYAGAIN;
++ retval = NSS_STATUS_TRYAGAIN;
++ goto freeres;
+ }
+
+- if (cached_results != NULL)
+- ++cached_results_iter;
+- else
+- if (saved_res)
+- {
+- nis_freeresult (saved_res);
+- saved_res = NULL;
+- }
++ next:
++ /* Free the old cursor. */
++ xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor);
++ /* Remember the new one. */
++ cursor.n_bytes = result.cookie.n_bytes;
++ cursor.n_len = result.cookie.n_len;
++ /* Free the result structure. NB: we do not remove the cookie. */
++ result.cookie.n_bytes = NULL;
++ result.cookie.n_len = 0;
++ freeres:
++ xdr_free ((xdrproc_t) _xdr_nis_result, (char *) &result);
++ memset (&result, '\0', sizeof (result));
+ }
+ while (!parse_res);
+
+- return NSS_STATUS_SUCCESS;
++ return retval;
+ }
+
+ enum nss_status
+@@ -331,8 +329,7 @@ _nss_nisplus_getpwnam_r (const char *nam
+ return status;
+ }
+
+- parse_res = _nss_nisplus_parse_pwent_chk (result, pw, buffer, buflen,
+- errnop);
++ parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop);
+
+ nis_freeresult (result);
+
+@@ -391,8 +388,7 @@ _nss_nisplus_getpwuid_r (const uid_t uid
+ return status;
+ }
+
+- parse_res = _nss_nisplus_parse_pwent_chk (result, pw, buffer, buflen,
+- errnop);
++ parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop);
+
+ nis_freeresult (result);
+
--- /dev/null
+2006-03-24 Jakub Jelinek <jakub@redhat.com>
+
+ * nis/nss_nisplus/nisplus-proto.c (_nss_create_tablename): Check the
+ return value of malloc rather than the static var again.
+ * nis/nss_nisplus/nisplus-grp.c (_nss_create_tablename): Likewise.
+ * nis/nss_nisplus/nisplus-network.c (_nss_create_tablename): Likewise.
+ * nis/nss_nisplus/nisplus-ethers.c (_nss_create_tablename): Likewise.
+ * nis/nss_nisplus/nisplus-rpc.c (_nss_create_tablename): Likewise.
+ * nis/nss_nisplus/nisplus-service.c (_nss_create_tablename): Likewise.
+ * nis/nss_nisplus/nisplus-hosts.c (_nss_create_tablename): Likewise.
+ * nis/nss_nisplus/nisplus-alias.c (_nss_create_tablename): Likewise.
+ * nis/nss_nisplus/nisplus-pwd.c (_nss_pwd_create_tablename): Likewise.
+
+2006-02-22 Jakub Jelinek <jakub@redhat.com>
+
+ * nis/ypclnt.c (yperr_string, ypbinderr_string): Add N_()
+ around string literals.
+
+2005-12-08 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nis_call.c (inetstr2int): Optimize.
+
+2005-12-08 Jakub Jelinek <jakub@redhat.com>
+
+ * nis/nis_call.c (__nisbind_create): Remove __nisbind_destroy,
+ ->clnt cannot be != NULL.
+ (__do_niscall): No need to use __nisbind_destroy, __nisbind_next
+ did it.
+ (__nisbind_connect): use_auth is already TRUE, otherwise we would
+ not be here.
+
+ * nis/nis_lookup.c (nis_lookup): Remove unnecessary
+ __nisbind_destroy calls. __nisbind_next does all that.
+
+ * nis/ypclnt.c (yp_update): Before trying default authentication,
+ free DES descriptor.
+
+2005-12-07 Jakub Jelinek <jakub@redhat.com>
+
+ * nis/nis_table.c (nis_list): Fix memory handling in error case.
+
+2005-12-07 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nis_table.c (nis_list): Remove have_tablepath, just use the
+ pointer value itself.
+
+ * sunrpc/auth_des.c (authdes_pk_create): If conversation key
+ cannot be created, free memory.
+ Reported by rprasad@vmware.com.
+
+2005-12-03 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nis_table.c (nis_list): Optimize freeing and reallocation of
+ result record.
+
+ * nis/nss_nisplus/nisplus-network.c (_nss_nisplus_getnetbyaddr_r):
+ Better sized buffers. Correct error case handling.
+ * nis/nis_error.c (nis_sperror_r): Let snprintf determine whether
+ there is an overflow.
+ * nis/nss_nisplus/nisplus-service.c: Fix locking to use
+ _nss_create_tablename. Avoid unnecessary copying, remove
+ unnecessary variables, general cleanup.
+ * nis/nss_nisplus/nisplus-rpc.c: Likewise.
+ * nis/nss_nisplus/nisplus-proto.c: Likewise..
+ * nis/nss_nisplus/nisplus-network.c: Fix locking to use
+ _nss_create_tablename. Avoid unnecessary copying, general cleanup.
+ * nis/nss_nisplus/nisplus-hosts.c (_nss_nisplus_getipnodebyname_r):
+ Removed.
+ Fix locking to use _nss_create_tablename. Avoid unnecessary copying,
+ general cleanup.
+ * nis/nss_nisplus/nisplus-ethers.c (_nss_nisplus_getntohost_r):
+ Correctly construct request.
+ Fix locking to use _nss_create_tablename. Avoid unnecessary copying,
+ general cleanup.
+ * nis/nss_nisplus/nisplus-alias.c: Fix locking to use
+ _nss_create_tablename. Avoid unnecessary copying, general cleanup.
+ * nis/nss_nisplus/nisplus-netgrp.c (_nss_nisplus_setnetgrent):
+ Rewrite to use snprintf.
+ * nis/nss_nisplus/nisplus-publickey.c (_nss_nisplus_netname2user):
+ Likewise.
+
+2005-12-02 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nss_nisplus/nisplus-pwd.c (_nss_pwd_create_tablename):
+ Renamed from _nss_create_tablename. Export from file (but not DSO).
+ (pwd_tablename_val): Renamed from tablename_val, mark hidden.
+ (pwd_tablename_len): Renamed from tablename_len, mark hidden.
+ Change all users.
+ * nis/nss_nisplus/nisplus-spwd.c (_nss_create_tablename): Removed.
+ Use _nss_pwd_create_tablename now. Use pwd_tablename_val and
+ pwd_tablename_len. Remove unnecessary variables, general cleanup.
+
+ * nis/nss_nisplus/nisplus-pwd.c: Fix locking to use
+ _nss_create_tablename. Avoid unnecessary copying, remove
+ unnecessary variables, general cleanup.
+ * nis/nss_nisplus/nisplus-grp.c: Likewise.
+
+2005-11-27 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nis_table.c (nis_list): Add more free calls in error cases.
+
+2005-11-26 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nis_lookup.c (nis_lookup): Mark RPCTIMEOUT as const. Pretty
+ printing.
+
+ * nis/nis_table.c (__create_ib_request): Use strdupa instead of
+ variable size array.
+ (RPCTIMEOUT): Mark as const.
+
+ * nis/ypclnt.c (yp_bind_ypbindprog): Initialize clnt_saddr by hand.
+ (ypdomainname): Renamed from __ypdomainname. No need for initializer.
+ (ypbindlist): Renamed from __ypbindlist.
+ (yperr_string): Reduce size of function by using only one gettext call.
+ (ypbinderr_string): Likewise.
+ (yp_match): Free response in case memory for return value cannot be
+ allocated.
+ (yp_first): Likewise.
+ (yp_next): Likewise.
+ (do_ypcall_tr): New function which translates error codes as well.
+ (yp_match, yp_next, yp_master, yp_order, yp_maplist): Use it.
+ (yp_all): Correct test for invalid parameter.
+ Pretty printing.
+ (RPCTIMEOUT, UDPTIMEOUT): Mark as const.
+
+--- libc/nis/nis_call.c 26 Oct 2004 01:14:11 -0000 1.32
++++ libc/nis/nis_call.c 9 Dec 2005 06:47:59 -0000 1.36
+@@ -40,25 +40,16 @@ extern u_short __pmap_getnisport (struct
+ unsigned long
+ inetstr2int (const char *str)
+ {
+- char buffer[strlen (str) + 3];
+- size_t buflen;
+- size_t i, j;
+-
+- buflen = stpcpy (buffer, str) - buffer;
+-
+- j = 0;
+- for (i = 0; i < buflen; ++i)
+- if (buffer[i] == '.')
++ size_t j = 0;
++ for (size_t i = 0; str[i] != '\0'; ++i)
++ if (str[i] == '.' && ++j == 4)
+ {
+- ++j;
+- if (j == 4)
+- {
+- buffer[i] = '\0';
+- break;
+- }
++ char buffer[i + 1];
++ buffer[i] = '\0';
++ return inet_addr (memcpy (buffer, str, i));
+ }
+
+- return inet_addr (buffer);
++ return inet_addr (str);
+ }
+
+ void
+@@ -179,7 +170,6 @@ __nisbind_connect (dir_binding *dbp)
+ }
+ else
+ dbp->clnt->cl_auth = authunix_create_default ();
+- dbp->use_auth = TRUE;
+ }
+
+ return NIS_SUCCESS;
+@@ -215,10 +205,7 @@ __nisbind_create (dir_binding *dbp, cons
+
+ dbp->class = -1;
+ if (__nis_findfastest (dbp) < 1)
+- {
+- __nisbind_destroy (dbp);
+- return NIS_NAMEUNREACHABLE;
+- }
++ return NIS_NAMEUNREACHABLE;
+
+ return NIS_SUCCESS;
+ }
+@@ -585,7 +572,6 @@ __do_niscall (const_nis_name name, u_lon
+ if (__nisbind_next (&bptr) != NIS_SUCCESS)
+ {
+ nis_free_directory (dir);
+- __nisbind_destroy (&bptr);
+ return NIS_NAMEUNREACHABLE;
+ }
+ }
+--- libc/nis/nis_error.c 24 Oct 2004 20:28:28 -0000 1.11
++++ libc/nis/nis_error.c 3 Dec 2005 22:15:00 -0000 1.12
+@@ -102,26 +102,21 @@ char *
+ nis_sperror_r (const nis_error status, const char *label,
+ char *buffer, size_t buflen)
+ {
+- const char *cptr;
+-
+- cptr = nis_sperrno (status);
+-
+- if ((strlen (cptr) + strlen (label) + 3) > buflen)
++ if (snprintf (buffer, buflen, "%s: %s", label, nis_sperrno (status))
++ >= buflen)
+ {
+ errno = ERANGE;
+ return NULL;
+ }
+
+- sprintf (buffer, "%s: %s", label, cptr);
+-
+- return buffer;
++ return buffer;
+ }
+ libnsl_hidden_def (nis_sperror_r)
+
+ char *
+ nis_sperror (const nis_error status, const char *label)
+ {
+- static char buffer[NIS_MAXNAMELEN +1];
++ static char buffer[NIS_MAXNAMELEN + 1];
+
+ return nis_sperror_r (status, label, buffer, sizeof (buffer));
+ }
+--- libc/nis/nis_lookup.c 24 Oct 2004 20:28:28 -0000 1.14
++++ libc/nis/nis_lookup.c 8 Dec 2005 20:19:11 -0000 1.16
+@@ -81,7 +81,6 @@ nis_lookup (const_nis_name name, const u
+ {
+ if (__nisbind_next (&bptr) != NIS_SUCCESS)
+ {
+- __nisbind_destroy (&bptr);
+ nis_free_directory (dir);
+ NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
+ return res;
+@@ -90,7 +89,7 @@ nis_lookup (const_nis_name name, const u
+
+ do
+ {
+- static struct timeval RPCTIMEOUT = {10, 0};
++ static const struct timeval RPCTIMEOUT = {10, 0};
+ enum clnt_stat result;
+
+ again:
+@@ -107,8 +106,8 @@ nis_lookup (const_nis_name name, const u
+
+ if (NIS_RES_STATUS (res) == NIS_SUCCESS)
+ {
+- if (__type_of(NIS_RES_OBJECT (res)) == NIS_LINK_OBJ &&
+- flags & FOLLOW_LINKS) /* We are following links */
++ if (__type_of(NIS_RES_OBJECT (res)) == NIS_LINK_OBJ
++ && (flags & FOLLOW_LINKS)) /* We are following links */
+ {
+ if (count_links)
+ free (req.ns_name);
+@@ -137,16 +136,17 @@ nis_lookup (const_nis_name name, const u
+ }
+ }
+ else
+- if ((NIS_RES_STATUS (res) == NIS_SYSTEMERROR) ||
+- (NIS_RES_STATUS (res) == NIS_NOSUCHNAME) ||
+- (NIS_RES_STATUS (res) == NIS_NOT_ME))
++ if (NIS_RES_STATUS (res) == NIS_SYSTEMERROR
++ || NIS_RES_STATUS (res) == NIS_NOSUCHNAME
++ || NIS_RES_STATUS (res) == NIS_NOT_ME)
+ {
+ if (link_first_try)
+ {
+ __nisbind_destroy (&bptr);
+ nis_free_directory (dir);
+
+- if (__nisfind_server (req.ns_name, &dir) != NIS_SUCCESS)
++ if (__nisfind_server (req.ns_name, &dir)
++ != NIS_SUCCESS)
+ return res;
+
+ if (__nisbind_create (&bptr,
+@@ -166,7 +166,6 @@ nis_lookup (const_nis_name name, const u
+ {
+ if (__nisbind_next (&bptr) != NIS_SUCCESS)
+ {
+- __nisbind_destroy (&bptr);
+ nis_free_directory (dir);
+ return res;
+ }
+--- libc/nis/nis_table.c 29 Apr 2005 09:16:12 -0000 1.24
++++ libc/nis/nis_table.c 8 Dec 2005 04:11:05 -0000 1.30
+@@ -27,11 +27,9 @@
+ static struct ib_request *
+ __create_ib_request (const_nis_name name, unsigned int flags)
+ {
+- struct ib_request *ibreq = calloc (1, sizeof (ib_request));
+- char buf[strlen (name) + 1];
++ struct ib_request *ibreq = calloc (1, sizeof (struct ib_request));
+ nis_attr *search_val = NULL;
+ size_t search_len = 0;
+- char *cptr;
+ size_t size = 0;
+
+ if (ibreq == NULL)
+@@ -39,7 +37,7 @@ __create_ib_request (const_nis_name name
+
+ ibreq->ibr_flags = flags;
+
+- cptr = strcpy (buf, name);
++ char *cptr = strdupa (name);
+
+ /* Not of "[key=value,key=value,...],foo.." format? */
+ if (cptr[0] != '[')
+@@ -49,8 +47,8 @@ __create_ib_request (const_nis_name name
+ ibreq->ibr_name = strchr (cptr, ']');
+ if (ibreq->ibr_name == NULL || ibreq->ibr_name[1] != ',')
+ {
+- ibreq->ibr_name = NULL; /* Or the xdr_* functions will dump */
+- nis_free_request (ibreq);
++ /* The object has not really been built yet so we use free. */
++ free (ibreq);
+ return NULL;
+ }
+
+@@ -120,17 +118,16 @@ __create_ib_request (const_nis_name name
+ return ibreq;
+ }
+
+-static struct timeval RPCTIMEOUT = {10, 0};
++static const struct timeval RPCTIMEOUT = {10, 0};
+
+ static char *
+ __get_tablepath (char *name, dir_binding *bptr)
+ {
+ enum clnt_stat result;
+- nis_result *res = calloc (1, sizeof (nis_result));
++ nis_result res;
+ struct ns_request req;
+
+- if (res == NULL)
+- return NULL;
++ memset (&res, '\0', sizeof (res));
+
+ req.ns_name = name;
+ req.ns_object.ns_object_len = 0;
+@@ -138,20 +135,16 @@ __get_tablepath (char *name, dir_binding
+
+ result = clnt_call (bptr->clnt, NIS_LOOKUP, (xdrproc_t) _xdr_ns_request,
+ (caddr_t) &req, (xdrproc_t) _xdr_nis_result,
+- (caddr_t) res, RPCTIMEOUT);
++ (caddr_t) &res, RPCTIMEOUT);
+
+- if (result == RPC_SUCCESS && NIS_RES_STATUS (res) == NIS_SUCCESS &&
+- __type_of (NIS_RES_OBJECT (res)) == NIS_TABLE_OBJ)
+- {
+- char *cptr = strdup (NIS_RES_OBJECT (res)->TA_data.ta_path);
+- nis_freeresult (res);
+- return cptr;
+- }
++ const char *cptr;
++ if (result == RPC_SUCCESS && NIS_RES_STATUS (&res) == NIS_SUCCESS
++ && __type_of (NIS_RES_OBJECT (&res)) == NIS_TABLE_OBJ)
++ cptr = NIS_RES_OBJECT (&res)->TA_data.ta_path;
+ else
+- {
+- nis_freeresult (res);
+- return strdup ("");
+- }
++ cptr = "";
++
++ return strdup (cptr);
+ }
+
+ nis_result *
+@@ -171,8 +164,8 @@ nis_list (const_nis_name name, unsigned
+ nis_name namebuf[2] = {NULL, NULL};
+ int name_nr = 0;
+ nis_cb *cb = NULL;
+- char *tableptr, *tablepath = NULL;
+- int have_tablepath = 0;
++ char *tableptr;
++ char *tablepath = NULL;
+ int first_try = 0; /* Do we try the old binding at first ? */
+
+ if (res == NULL)
+@@ -205,6 +198,7 @@ nis_list (const_nis_name name, unsigned
+ ibreq->ibr_name = strdup (names[name_nr]);
+ if (ibreq->ibr_name == NULL)
+ {
++ nis_freenames (names);
+ nis_free_request (ibreq);
+ NIS_RES_STATUS (res) = NIS_NOMEMORY;
+ return res;
+@@ -227,30 +221,24 @@ nis_list (const_nis_name name, unsigned
+
+ status = __nisfind_server (ibreq->ibr_name, &dir);
+ if (status != NIS_SUCCESS)
+- {
+- nis_free_request (ibreq);
++ {
+ NIS_RES_STATUS (res) = status;
+- return res;
+- }
++ goto fail3;
++ }
+
+ status = __nisbind_create (&bptr, dir->do_servers.do_servers_val,
+- dir->do_servers.do_servers_len, flags);
++ dir->do_servers.do_servers_len, flags);
+ if (status != NIS_SUCCESS)
+ {
+- nis_free_request (ibreq);
+ NIS_RES_STATUS (res) = status;
+- nis_free_directory (dir);
+- return res;
++ goto fail2;
+ }
+
+ while (__nisbind_connect (&bptr) != NIS_SUCCESS)
+ if (__nisbind_next (&bptr) != NIS_SUCCESS)
+ {
+- __nisbind_destroy (&bptr);
+- nis_free_directory (dir);
+- nis_free_request (ibreq);
+ NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
+- return res;
++ goto fail;
+ }
+
+ if (callback != NULL)
+@@ -274,8 +262,8 @@ nis_list (const_nis_name name, unsigned
+ case NIS_PARTIAL:
+ case NIS_SUCCESS:
+ case NIS_S_SUCCESS:
+- if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ &&
+- flags & FOLLOW_LINKS) /* We are following links. */
++ if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ
++ && (flags & FOLLOW_LINKS)) /* We are following links. */
+ {
+ free (ibreq->ibr_name);
+ ibreq->ibr_name = NULL;
+@@ -291,8 +279,22 @@ nis_list (const_nis_name name, unsigned
+ strdup (NIS_RES_OBJECT (res)->LI_data.li_name);
+ if (ibreq->ibr_name == NULL)
+ {
+- nis_free_request (ibreq);
+ NIS_RES_STATUS (res) = NIS_NOMEMORY;
++ fail:
++ __nisbind_destroy (&bptr);
++ fail2:
++ nis_free_directory (dir);
++ fail3:
++ free (tablepath);
++ if (cb)
++ {
++ __nis_destroy_callback (cb);
++ ibreq->ibr_cbhost.ibr_cbhost_len = 0;
++ ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
++ }
++ if (names != namebuf)
++ nis_freenames (names);
++ nis_free_request (ibreq);
+ return res;
+ }
+ if (NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len)
+@@ -303,27 +305,30 @@ nis_list (const_nis_name name, unsigned
+ ibreq->ibr_srch.ibr_srch_val =
+ NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_val;
+ }
++ /* The following is a non-obvious optimization. A
++ nis_freeresult call would call xdr_free as the
++ following code. But it also would unnecessarily
++ free the result structure. We avoid this here
++ along with the necessary tests. */
++#if 1
++ xdr_free ((xdrproc_t) _xdr_nis_result, (char *)res);
++ memset (res, '\0', sizeof (*res));
++#else
+ nis_freeresult (res);
+ res = calloc (1, sizeof (nis_result));
+ if (res == NULL)
+- {
+- if (have_tablepath)
+- free (tablepath);
+- __nisbind_destroy (&bptr);
+- nis_free_directory (dir);
+- return NULL;
+- }
++ goto fail;
++#endif
+ first_try = 1; /* Try at first the old binding */
+ goto again;
+ }
+- else if ((flags & FOLLOW_PATH) &&
+- NIS_RES_STATUS (res) == NIS_PARTIAL)
++ else if ((flags & FOLLOW_PATH)
++ && NIS_RES_STATUS (res) == NIS_PARTIAL)
+ {
+- if (!have_tablepath)
++ if (tablepath == NULL)
+ {
+ tablepath = __get_tablepath (ibreq->ibr_name, &bptr);
+ tableptr = tablepath;
+- have_tablepath = 1;
+ }
+ if (tableptr == NULL)
+ {
+@@ -337,27 +342,37 @@ nis_list (const_nis_name name, unsigned
+ ibreq->ibr_name = strdup ("");
+ if (ibreq->ibr_name == NULL)
+ {
+- nis_free_request (ibreq);
+ NIS_RES_STATUS (res) = NIS_NOMEMORY;
+- return res;
++ goto fail;
+ }
+ ++done;
+ }
+ else
+ {
+ ibreq->ibr_name = strdup (ibreq->ibr_name);
++ /* The following is a non-obvious optimization. A
++ nis_freeresult call would call xdr_free as the
++ following code. But it also would unnecessarily
++ free the result structure. We avoid this here
++ along with the necessary tests. */
++#if 1
++ xdr_free ((xdrproc_t) _xdr_nis_result, (char *)res);
++ memset (res, '\0', sizeof (*res));
++ if (ibreq->ibr_name == NULL)
++ {
++ NIS_RES_STATUS (res) = NIS_NOMEMORY;
++ goto fail;
++ }
++#else
+ nis_freeresult (res);
+ res = calloc (1, sizeof (nis_result));
+ if (res == NULL || ibreq->ibr_name == NULL)
+ {
+ free (res);
+- nis_free_request (ibreq);
+- if (have_tablepath)
+- free (tablepath);
+- __nisbind_destroy (&bptr);
+- nis_free_directory (dir);
+- return NULL;
++ res = NULL;
++ goto fail;
+ }
++#endif
+ first_try = 1;
+ goto again;
+ }
+@@ -375,11 +390,10 @@ nis_list (const_nis_name name, unsigned
+ ++done;
+ else
+ {
+- if (!have_tablepath)
++ if (tablepath == NULL)
+ {
+ tablepath = __get_tablepath (ibreq->ibr_name, &bptr);
+ tableptr = tablepath;
+- have_tablepath = 1;
+ }
+ if (tableptr == NULL)
+ {
+@@ -397,9 +411,8 @@ nis_list (const_nis_name name, unsigned
+ ibreq->ibr_name = strdup (ibreq->ibr_name);
+ if (ibreq->ibr_name == NULL)
+ {
+- nis_free_request (ibreq);
+ NIS_RES_STATUS (res) = NIS_NOMEMORY;
+- return res;
++ goto fail;
+ }
+ }
+ }
+@@ -448,9 +461,8 @@ nis_list (const_nis_name name, unsigned
+ ibreq->ibr_name = strdup (names[name_nr]);
+ if (ibreq->ibr_name == NULL)
+ {
+- nis_free_request (ibreq);
+ NIS_RES_STATUS (res) = NIS_NOMEMORY;
+- return res;
++ goto fail;
+ }
+ first_try = 1; /* Try old binding at first */
+ goto again;
+@@ -464,12 +476,15 @@ nis_list (const_nis_name name, unsigned
+ __nis_destroy_callback (cb);
+ ibreq->ibr_cbhost.ibr_cbhost_len = 0;
+ ibreq->ibr_cbhost.ibr_cbhost_val = NULL;
++ cb = NULL;
+ }
+
+ __nisbind_destroy (&bptr);
+ nis_free_directory (dir);
+ }
+
++ free (tablepath);
++
+ if (names != namebuf)
+ nis_freenames (names);
+
+--- libc/nis/ypclnt.c 25 Nov 2005 16:04:44 -0000 1.52
++++ libc/nis/ypclnt.c 8 Dec 2005 15:39:16 -0000 1.55
+@@ -46,12 +46,12 @@ struct dom_binding
+ };
+ typedef struct dom_binding dom_binding;
+
+-static struct timeval RPCTIMEOUT = {25, 0};
+-static struct timeval UDPTIMEOUT = {5, 0};
++static const struct timeval RPCTIMEOUT = {25, 0};
++static const struct timeval UDPTIMEOUT = {5, 0};
+ static int const MAXTRIES = 2;
+-static char __ypdomainname[NIS_MAXNAMELEN + 1] = "\0";
++static char ypdomainname[NIS_MAXNAMELEN + 1];
+ __libc_lock_define_initialized (static, ypbindlist_lock)
+-static dom_binding *__ypbindlist = NULL;
++static dom_binding *ypbindlist = NULL;
+
+
+ static void
+@@ -111,8 +111,8 @@ yp_bind_ypbindprog (const char *domain,
+ int clnt_sock;
+ CLIENT *client;
+
+- memset (&clnt_saddr, '\0', sizeof clnt_saddr);
+ clnt_saddr.sin_family = AF_INET;
++ clnt_saddr.sin_port = 0;
+ clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+ clnt_sock = RPC_ANYSOCK;
+ client = clnttcp_create (&clnt_saddr, YPBINDPROG, YPBINDVERS,
+@@ -142,7 +142,7 @@ yp_bind_ypbindprog (const char *domain,
+
+ if (ypbr.ypbind_status != YPBIND_SUCC_VAL)
+ {
+- fprintf (stderr, _("YPBINDPROC_DOMAIN: %s\n"),
++ fprintf (stderr, "YPBINDPROC_DOMAIN: %s\n",
+ ypbinderr_string (ypbr.ypbind_resp_u.ypbind_error));
+ return YPERR_DOMAIN;
+ }
+@@ -225,7 +225,7 @@ yp_bind (const char *indomain)
+
+ __libc_lock_lock (ypbindlist_lock);
+
+- status = __yp_bind (indomain, &__ypbindlist);
++ status = __yp_bind (indomain, &ypbindlist);
+
+ __libc_lock_unlock (ypbindlist_lock);
+
+@@ -239,7 +239,7 @@ yp_unbind_locked (const char *indomain)
+ dom_binding *ydbptr, *ydbptr2;
+
+ ydbptr2 = NULL;
+- ydbptr = __ypbindlist;
++ ydbptr = ypbindlist;
+
+ while (ydbptr != NULL)
+ {
+@@ -249,7 +249,7 @@ yp_unbind_locked (const char *indomain)
+
+ work = ydbptr;
+ if (ydbptr2 == NULL)
+- __ypbindlist = __ypbindlist->dom_pnext;
++ ypbindlist = ypbindlist->dom_pnext;
+ else
+ ydbptr2 = ydbptr->dom_pnext;
+ __yp_unbind (work);
+@@ -306,7 +306,7 @@ do_ypcall (const char *domain, u_long pr
+ status = YPERR_YPERR;
+
+ __libc_lock_lock (ypbindlist_lock);
+- ydb = __ypbindlist;
++ ydb = ypbindlist;
+ while (ydb != NULL)
+ {
+ if (strcmp (domain, ydb->dom_domain) == 0)
+@@ -365,6 +365,21 @@ do_ypcall (const char *domain, u_long pr
+ return status;
+ }
+
++/* Like do_ypcall, but translate the status value if necessary. */
++static int
++do_ypcall_tr (const char *domain, u_long prog, xdrproc_t xargs,
++ caddr_t req, xdrproc_t xres, caddr_t resp)
++{
++ int status = do_ypcall (domain, prog, xargs, req, xres, resp);
++ if (status == YPERR_SUCCESS)
++ /* We cast to ypresp_val although the pointer could also be of
++ type ypresp_key_val or ypresp_master or ypresp_order or
++ ypresp_maplist. But the stat element is in a common prefix so
++ this does not matter. */
++ status = ypprot_err (((struct ypresp_val *) resp)->stat);
++ return status;
++}
++
+
+ __libc_lock_define_initialized (static, domainname_lock)
+
+@@ -376,21 +391,21 @@ yp_get_default_domain (char **outdomain)
+
+ __libc_lock_lock (domainname_lock);
+
+- if (__ypdomainname[0] == '\0')
++ if (ypdomainname[0] == '\0')
+ {
+- if (getdomainname (__ypdomainname, NIS_MAXNAMELEN))
++ if (getdomainname (ypdomainname, NIS_MAXNAMELEN))
+ result = YPERR_NODOM;
+- else if (strcmp (__ypdomainname, "(none)") == 0)
++ else if (strcmp (ypdomainname, "(none)") == 0)
+ {
+ /* If domainname is not set, some systems will return "(none)" */
+- __ypdomainname[0] = '\0';
++ ypdomainname[0] = '\0';
+ result = YPERR_NODOM;
+ }
+ else
+- *outdomain = __ypdomainname;
++ *outdomain = ypdomainname;
+ }
+ else
+- *outdomain = __ypdomainname;
++ *outdomain = ypdomainname;
+
+ __libc_lock_unlock (domainname_lock);
+
+@@ -403,14 +418,14 @@ __yp_check (char **domain)
+ {
+ char *unused;
+
+- if (__ypdomainname[0] == '\0')
++ if (ypdomainname[0] == '\0')
+ if (yp_get_default_domain (&unused))
+ return 0;
+
+ if (domain)
+- *domain = __ypdomainname;
++ *domain = ypdomainname;
+
+- if (yp_bind (__ypdomainname) == 0)
++ if (yp_bind (ypdomainname) == 0)
+ return 1;
+ return 0;
+ }
+@@ -437,25 +452,26 @@ yp_match (const char *indomain, const ch
+ *outvallen = 0;
+ memset (&resp, '\0', sizeof (resp));
+
+- result = do_ypcall (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
+- (caddr_t) & req, (xdrproc_t) xdr_ypresp_val,
+- (caddr_t) & resp);
++ result = do_ypcall_tr (indomain, YPPROC_MATCH, (xdrproc_t) xdr_ypreq_key,
++ (caddr_t) &req, (xdrproc_t) xdr_ypresp_val,
++ (caddr_t) &resp);
+
+ if (result != YPERR_SUCCESS)
+ return result;
+- if (resp.stat != YP_TRUE)
+- return ypprot_err (resp.stat);
+
+ *outvallen = resp.val.valdat_len;
+ *outval = malloc (*outvallen + 1);
+- if (__builtin_expect (*outval == NULL, 0))
+- return YPERR_RESRC;
+- memcpy (*outval, resp.val.valdat_val, *outvallen);
+- (*outval)[*outvallen] = '\0';
++ int status = YPERR_RESRC;
++ if (__builtin_expect (*outval != NULL, 1))
++ {
++ memcpy (*outval, resp.val.valdat_val, *outvallen);
++ (*outval)[*outvallen] = '\0';
++ status = YPERR_SUCCESS;
++ }
+
+ xdr_free ((xdrproc_t) xdr_ypresp_val, (char *) &resp);
+
+- return YPERR_SUCCESS;
++ return status;
+ }
+
+ int
+@@ -478,30 +494,38 @@ yp_first (const char *indomain, const ch
+ memset (&resp, '\0', sizeof (resp));
+
+ result = do_ypcall (indomain, YPPROC_FIRST, (xdrproc_t) xdr_ypreq_nokey,
+- (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
+- (caddr_t) & resp);
++ (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
++ (caddr_t) &resp);
+
+ if (result != RPC_SUCCESS)
+ return YPERR_RPC;
+ if (resp.stat != YP_TRUE)
+ return ypprot_err (resp.stat);
+
+- *outkeylen = resp.key.keydat_len;
+- *outkey = malloc (*outkeylen + 1);
+- if (__builtin_expect (*outkey == NULL, 0))
+- return YPERR_RESRC;
+- memcpy (*outkey, resp.key.keydat_val, *outkeylen);
+- (*outkey)[*outkeylen] = '\0';
+- *outvallen = resp.val.valdat_len;
+- *outval = malloc (*outvallen + 1);
+- if (__builtin_expect (*outval == NULL, 0))
+- return YPERR_RESRC;
+- memcpy (*outval, resp.val.valdat_val, *outvallen);
+- (*outval)[*outvallen] = '\0';
++ int status;
++ if (__builtin_expect ((*outkey = malloc (resp.key.keydat_len + 1)) != NULL
++ && (*outval = malloc (resp.val.valdat_len
++ + 1)) != NULL, 1))
++ {
++ *outkeylen = resp.key.keydat_len;
++ memcpy (*outkey, resp.key.keydat_val, *outkeylen);
++ (*outkey)[*outkeylen] = '\0';
++
++ *outvallen = resp.val.valdat_len;
++ memcpy (*outval, resp.val.valdat_val, *outvallen);
++ (*outval)[*outvallen] = '\0';
++
++ status = YPERR_SUCCESS;
++ }
++ else
++ {
++ free (*outkey);
++ status = YPERR_RESRC;
++ }
+
+ xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
+
+- return YPERR_SUCCESS;
++ return status;
+ }
+
+ int
+@@ -527,31 +551,37 @@ yp_next (const char *indomain, const cha
+ *outkeylen = *outvallen = 0;
+ memset (&resp, '\0', sizeof (resp));
+
+- result = do_ypcall (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
+- (caddr_t) & req, (xdrproc_t) xdr_ypresp_key_val,
+- (caddr_t) & resp);
++ result = do_ypcall_tr (indomain, YPPROC_NEXT, (xdrproc_t) xdr_ypreq_key,
++ (caddr_t) &req, (xdrproc_t) xdr_ypresp_key_val,
++ (caddr_t) &resp);
+
+ if (result != YPERR_SUCCESS)
+ return result;
+- if (resp.stat != YP_TRUE)
+- return ypprot_err (resp.stat);
+
+- *outkeylen = resp.key.keydat_len;
+- *outkey = malloc (*outkeylen + 1);
+- if (__builtin_expect (*outkey == NULL, 0))
+- return YPERR_RESRC;
+- memcpy (*outkey, resp.key.keydat_val, *outkeylen);
+- (*outkey)[*outkeylen] = '\0';
+- *outvallen = resp.val.valdat_len;
+- *outval = malloc (*outvallen + 1);
+- if (__builtin_expect (*outval == NULL, 0))
+- return YPERR_RESRC;
+- memcpy (*outval, resp.val.valdat_val, *outvallen);
+- (*outval)[*outvallen] = '\0';
++ int status;
++ if (__builtin_expect ((*outkey = malloc (resp.key.keydat_len + 1)) != NULL
++ && (*outval = malloc (resp.val.valdat_len
++ + 1)) != NULL, 1))
++ {
++ *outkeylen = resp.key.keydat_len;
++ memcpy (*outkey, resp.key.keydat_val, *outkeylen);
++ (*outkey)[*outkeylen] = '\0';
++
++ *outvallen = resp.val.valdat_len;
++ memcpy (*outval, resp.val.valdat_val, *outvallen);
++ (*outval)[*outvallen] = '\0';
++
++ status = YPERR_SUCCESS;
++ }
++ else
++ {
++ free (*outkey);
++ status = YPERR_RESRC;
++ }
+
+ xdr_free ((xdrproc_t) xdr_ypresp_key_val, (char *) &resp);
+
+- return YPERR_SUCCESS;
++ return status;
+ }
+
+ int
+@@ -570,13 +600,12 @@ yp_master (const char *indomain, const c
+
+ memset (&resp, '\0', sizeof (ypresp_master));
+
+- result = do_ypcall (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
+- (caddr_t) & req, (xdrproc_t) xdr_ypresp_master, (caddr_t) & resp);
++ result = do_ypcall_tr (indomain, YPPROC_MASTER, (xdrproc_t) xdr_ypreq_nokey,
++ (caddr_t) &req, (xdrproc_t) xdr_ypresp_master,
++ (caddr_t) &resp);
+
+ if (result != YPERR_SUCCESS)
+ return result;
+- if (resp.stat != YP_TRUE)
+- return ypprot_err (resp.stat);
+
+ *outname = strdup (resp.peer);
+ xdr_free ((xdrproc_t) xdr_ypresp_master, (char *) &resp);
+@@ -601,18 +630,17 @@ yp_order (const char *indomain, const ch
+
+ memset (&resp, '\0', sizeof (resp));
+
+- result = do_ypcall (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
+- (caddr_t) & req, (xdrproc_t) xdr_ypresp_order, (caddr_t) & resp);
++ result = do_ypcall_tr (indomain, YPPROC_ORDER, (xdrproc_t) xdr_ypreq_nokey,
++ (caddr_t) &req, (xdrproc_t) xdr_ypresp_order,
++ (caddr_t) &resp);
+
+- if (result != YPERR_SUCCESS)
++ if (result == YPERR_SUCCESS)
+ return result;
+- if (resp.stat != YP_TRUE)
+- return ypprot_err (resp.stat);
+
+ *outorder = resp.ordernum;
+ xdr_free ((xdrproc_t) xdr_ypresp_order, (char *) &resp);
+
+- return YPERR_SUCCESS;
++ return result;
+ }
+
+ struct ypresp_all_data
+@@ -694,8 +722,8 @@ yp_all (const char *indomain, const char
+ int clnt_sock;
+ int saved_errno = errno;
+
+- if (indomain == NULL || indomain[0] == '\0' ||
+- inmap == NULL || inmap == '\0')
++ if (indomain == NULL || indomain[0] == '\0'
++ || inmap == NULL || inmap[0] == '\0')
+ return YPERR_BADARGS;
+
+ try = 0;
+@@ -733,9 +761,9 @@ yp_all (const char *indomain, const char
+ (caddr_t) &req, (xdrproc_t) __xdr_ypresp_all,
+ (caddr_t) &data, RPCTIMEOUT);
+
+- if (result != RPC_SUCCESS)
++ if (__builtin_expect (result != RPC_SUCCESS, 0))
+ {
+- /* Print the error message only on the last try */
++ /* Print the error message only on the last try. */
+ if (try == MAXTRIES - 1)
+ clnt_perror (clnt, "yp_all: clnt_call");
+ res = YPERR_RPC;
+@@ -759,6 +787,7 @@ yp_all (const char *indomain, const char
+ }
+
+ int
++
+ yp_maplist (const char *indomain, struct ypmaplist **outmaplist)
+ {
+ struct ypresp_maplist resp;
+@@ -769,62 +798,82 @@ yp_maplist (const char *indomain, struct
+
+ memset (&resp, '\0', sizeof (resp));
+
+- result = do_ypcall (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
+- (caddr_t) & indomain, (xdrproc_t) xdr_ypresp_maplist, (caddr_t) & resp);
+-
+- if (result != YPERR_SUCCESS)
+- return result;
+- if (resp.stat != YP_TRUE)
+- return ypprot_err (resp.stat);
+-
+- *outmaplist = resp.maps;
+- /* We give the list not free, this will be done by ypserv
+- xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
++ result = do_ypcall_tr (indomain, YPPROC_MAPLIST, (xdrproc_t) xdr_domainname,
++ (caddr_t) &indomain, (xdrproc_t) xdr_ypresp_maplist,
++ (caddr_t) &resp);
++
++ if (__builtin_expect (result == YPERR_SUCCESS, 1))
++ {
++ *outmaplist = resp.maps;
++ /* We don't free the list, this will be done by ypserv
++ xdr_free((xdrproc_t)xdr_ypresp_maplist, (char *)&resp); */
++ }
+
+- return YPERR_SUCCESS;
++ return result;
+ }
+
+ const char *
+ yperr_string (const int error)
+ {
++ const char *str;
+ switch (error)
+ {
+ case YPERR_SUCCESS:
+- return _("Success");
++ str = N_("Success");
++ break;
+ case YPERR_BADARGS:
+- return _("Request arguments bad");
++ str = N_("Request arguments bad");
++ break;
+ case YPERR_RPC:
+- return _("RPC failure on NIS operation");
++ str = N_("RPC failure on NIS operation");
++ break;
+ case YPERR_DOMAIN:
+- return _("Can't bind to server which serves this domain");
++ str = N_("Can't bind to server which serves this domain");
++ break;
+ case YPERR_MAP:
+- return _("No such map in server's domain");
++ str = N_("No such map in server's domain");
++ break;
+ case YPERR_KEY:
+- return _("No such key in map");
++ str = N_("No such key in map");
++ break;
+ case YPERR_YPERR:
+- return _("Internal NIS error");
++ str = N_("Internal NIS error");
++ break;
+ case YPERR_RESRC:
+- return _("Local resource allocation failure");
++ str = N_("Local resource allocation failure");
++ break;
+ case YPERR_NOMORE:
+- return _("No more records in map database");
++ str = N_("No more records in map database");
++ break;
+ case YPERR_PMAP:
+- return _("Can't communicate with portmapper");
++ str = N_("Can't communicate with portmapper");
++ break;
+ case YPERR_YPBIND:
+- return _("Can't communicate with ypbind");
++ str = N_("Can't communicate with ypbind");
++ break;
+ case YPERR_YPSERV:
+- return _("Can't communicate with ypserv");
++ str = N_("Can't communicate with ypserv");
++ break;
+ case YPERR_NODOM:
+- return _("Local domain name not set");
++ str = N_("Local domain name not set");
++ break;
+ case YPERR_BADDB:
+- return _("NIS map database is bad");
++ str = N_("NIS map database is bad");
++ break;
+ case YPERR_VERS:
+- return _("NIS client/server version mismatch - can't supply service");
++ str = N_("NIS client/server version mismatch - can't supply service");
++ break;
+ case YPERR_ACCESS:
+- return _("Permission denied");
++ str = N_("Permission denied");
++ break;
+ case YPERR_BUSY:
+- return _("Database is busy");
++ str = N_("Database is busy");
++ break;
++ default:
++ str = N_("Unknown NIS error code");
++ break;
+ }
+- return _("Unknown NIS error code");
++ return _(str);
+ }
+
+ static const int8_t yp_2_yperr[] =
+@@ -854,19 +903,26 @@ libnsl_hidden_def (ypprot_err)
+ const char *
+ ypbinderr_string (const int error)
+ {
++ const char *str;
+ switch (error)
+ {
+ case 0:
+- return _("Success");
++ str = N_("Success");
++ break;
+ case YPBIND_ERR_ERR:
+- return _("Internal ypbind error");
++ str = N_("Internal ypbind error");
++ break;
+ case YPBIND_ERR_NOSERV:
+- return _("Domain not bound");
++ str = N_("Domain not bound");
++ break;
+ case YPBIND_ERR_RESC:
+- return _("System resource allocation failure");
++ str = N_("System resource allocation failure");
++ break;
+ default:
+- return _("Unknown ypbind error");
++ str = N_("Unknown ypbind error");
++ break;
+ }
++ return _(str);
+ }
+ libnsl_hidden_def (ypbinderr_string)
+
+@@ -948,6 +1004,7 @@ again:
+ {
+ if (clnt->cl_auth->ah_cred.oa_flavor == AUTH_DES)
+ {
++ auth_destroy (clnt->cl_auth);
+ clnt->cl_auth = authunix_create_default ();
+ goto again;
+ }
+--- libc/nis/nss_nisplus/nisplus-alias.c 25 Sep 2003 19:44:20 -0000 1.16
++++ libc/nis/nss_nisplus/nisplus-alias.c 3 Dec 2005 17:01:45 -0000 1.17
+@@ -17,6 +17,7 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
++#include <atomic.h>
+ #include <nss.h>
+ #include <errno.h>
+ #include <ctype.h>
+@@ -32,7 +33,7 @@ __libc_lock_define_initialized (static,
+ static nis_result *result;
+ static u_long next_entry;
+ static nis_name tablename_val;
+-static u_long tablename_len;
++static size_t tablename_len;
+
+ #define NISENTRYVAL(idx,col,res) \
+ ((res)->objects.objects_val[(idx)].EN_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val)
+@@ -45,19 +46,26 @@ _nss_create_tablename (int *errnop)
+ {
+ if (tablename_val == NULL)
+ {
+- char buf [40 + strlen (nis_local_directory ())];
+- char *p;
++ const char *local_dir = nis_local_directory ();
++ size_t local_dir_len = strlen (local_dir);
++ static const char prefix[] = "mail_aliases.org_dir.";
+
+- p = __stpcpy (buf, "mail_aliases.org_dir.");
+- p = __stpcpy (p, nis_local_directory ());
+- tablename_val = __strdup (buf);
+- if (tablename_val == NULL)
++ char *p = malloc (sizeof (prefix) + local_dir_len);
++ if (p == NULL)
+ {
+ *errnop = errno;
+ return NSS_STATUS_TRYAGAIN;
+ }
+- tablename_len = strlen (tablename_val);
++
++ memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
++
++ tablename_len = sizeof (prefix) - 1 + local_dir_len;
++
++ atomic_write_barrier ();
++
++ tablename_val = p;
+ }
++
+ return NSS_STATUS_SUCCESS;
+ }
+
+@@ -75,81 +83,73 @@ _nss_nisplus_parse_aliasent (nis_result
+ "mail_aliases") != 0
+ || result->objects.objects_val[entry].EN_data.en_cols.en_cols_len < 2)
+ return 0;
+- else
++
++ char *first_unused = buffer + NISENTRYLEN (0, 1, result) + 1;
++ size_t room_left = (buflen - (buflen % __alignof__ (char *))
++ - NISENTRYLEN (0, 1, result) - 2);
++
++ if (NISENTRYLEN (entry, 1, result) >= buflen)
+ {
+- char *first_unused = buffer + NISENTRYLEN (0, 1, result) + 1;
+- size_t room_left =
+- buflen - (buflen % __alignof__ (char *)) -
+- NISENTRYLEN (0, 1, result) - 2;
+- char *line;
+- char *cp;
++ /* The line is too long for our buffer. */
++ no_more_room:
++ *errnop = ERANGE;
++ return -1;
++ }
+
+- if (NISENTRYLEN (entry, 1, result) >= buflen)
+- {
+- /* The line is too long for our buffer. */
+- no_more_room:
+- *errnop = ERANGE;
+- return -1;
+- }
+- else
+- {
+- cp = __stpncpy (buffer, NISENTRYVAL (entry, 1, result),
+- NISENTRYLEN (entry, 1, result));
+- *cp = '\0';
+- }
++ char *cp = __stpncpy (buffer, NISENTRYVAL (entry, 1, result),
++ NISENTRYLEN (entry, 1, result));
++ *cp = '\0';
++
++ if (NISENTRYLEN(entry, 0, result) >= room_left)
++ goto no_more_room;
++
++ alias->alias_local = 0;
++ alias->alias_members_len = 0;
++ *first_unused = '\0';
++ ++first_unused;
++ cp = __stpncpy (first_unused, NISENTRYVAL (entry, 0, result),
++ NISENTRYLEN (entry, 0, result));
++ *cp = '\0';
++ alias->alias_name = first_unused;
++
++ /* Terminate the line for any case. */
++ cp = strpbrk (alias->alias_name, "#\n");
++ if (cp != NULL)
++ *cp = '\0';
++
++ first_unused += strlen (alias->alias_name) +1;
++ /* Adjust the pointer so it is aligned for
++ storing pointers. */
++ first_unused += __alignof__ (char *) - 1;
++ first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
++ alias->alias_members = (char **) first_unused;
+
+- if (NISENTRYLEN(entry, 0, result) >= room_left)
+- goto no_more_room;
++ char *line = buffer;
++ while (*line != '\0')
++ {
++ /* Skip leading blanks. */
++ while (isspace (*line))
++ ++line;
++
++ if (*line == '\0')
++ break;
+
+- alias->alias_local = 0;
+- alias->alias_members_len = 0;
+- *first_unused = '\0';
+- ++first_unused;
+- cp = __stpncpy (first_unused, NISENTRYVAL (entry, 0, result),
+- NISENTRYLEN (entry, 0, result));
+- *cp = '\0';
+- alias->alias_name = first_unused;
+-
+- /* Terminate the line for any case. */
+- cp = strpbrk (alias->alias_name, "#\n");
+- if (cp != NULL)
+- *cp = '\0';
+-
+- first_unused += strlen (alias->alias_name) +1;
+- /* Adjust the pointer so it is aligned for
+- storing pointers. */
+- first_unused += __alignof__ (char *) - 1;
+- first_unused -= ((first_unused - (char *) 0) % __alignof__ (char *));
+- alias->alias_members = (char **) first_unused;
++ if (room_left < sizeof (char *))
++ goto no_more_room;
++ room_left -= sizeof (char *);
++ alias->alias_members[alias->alias_members_len] = line;
+
+- line = buffer;
++ while (*line != '\0' && *line != ',')
++ ++line;
+
+- while (*line != '\0')
++ if (line != alias->alias_members[alias->alias_members_len])
+ {
+- /* Skip leading blanks. */
+- while (isspace (*line))
+- ++line;
+-
+- if (*line == '\0')
+- break;
+-
+- if (room_left < sizeof (char *))
+- goto no_more_room;
+- room_left -= sizeof (char *);
+- alias->alias_members[alias->alias_members_len] = line;
+-
+- while (*line != '\0' && *line != ',')
+- ++line;
+-
+- if (line != alias->alias_members[alias->alias_members_len])
+- {
+- *line++ = '\0';
+- alias->alias_members_len++;
+- }
++ *line++ = '\0';
++ alias->alias_members_len++;
+ }
+-
+- return alias->alias_members_len == 0 ? 0 : 1;
+ }
++
++ return alias->alias_members_len == 0 ? 0 : 1;
+ }
+
+ static enum nss_status
+@@ -158,9 +158,11 @@ internal_setaliasent (void)
+ enum nss_status status;
+ int err;
+
+- if (result)
+- nis_freeresult (result);
+- result = NULL;
++ if (result != NULL)
++ {
++ nis_freeresult (result);
++ result = NULL;
++ }
+
+ if (_nss_create_tablename (&err) != NSS_STATUS_SUCCESS)
+ return NSS_STATUS_UNAVAIL;
+@@ -203,9 +205,11 @@ _nss_nisplus_endaliasent (void)
+ {
+ __libc_lock_lock (lock);
+
+- if (result)
+- nis_freeresult (result);
+- result = NULL;
++ if (result != NULL)
++ {
++ nis_freeresult (result);
++ result = NULL;
++ }
+ next_entry = 0;
+
+ __libc_lock_unlock (lock);
+@@ -240,7 +244,8 @@ internal_nisplus_getaliasent_r (struct a
+ return NSS_STATUS_TRYAGAIN;
+
+ ++next_entry;
+- } while (!parse_res);
++ }
++ while (!parse_res);
+
+ return NSS_STATUS_SUCCESS;
+ }
+@@ -268,7 +273,12 @@ _nss_nisplus_getaliasbyname_r (const cha
+
+ if (tablename_val == NULL)
+ {
++ __libc_lock_lock (lock);
++
+ enum nss_status status = _nss_create_tablename (errnop);
++
++ __libc_lock_unlock (lock);
++
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+ }
+@@ -278,35 +288,34 @@ _nss_nisplus_getaliasbyname_r (const cha
+ *errnop = EINVAL;
+ return NSS_STATUS_UNAVAIL;
+ }
+- else
+- {
+- nis_result *result;
+- char buf[strlen (name) + 30 + tablename_len];
+- int olderr = errno;
+
+- sprintf (buf, "[name=%s],%s", name, tablename_val);
++ char buf[strlen (name) + 9 + tablename_len];
++ int olderr = errno;
+
+- result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++ snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
+
+- if (result == NULL)
+- {
+- *errnop = ENOMEM;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+- return niserr2nss (result->status);
++ nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+
+- parse_res = _nss_nisplus_parse_aliasent (result, 0, alias,
+- buffer, buflen, errnop);
+- if (parse_res < 1)
+- {
+- __set_errno (olderr);
++ if (result == NULL)
++ {
++ *errnop = ENOMEM;
++ return NSS_STATUS_TRYAGAIN;
++ }
+
+- if (parse_res == -1)
+- return NSS_STATUS_TRYAGAIN;
+- else
+- return NSS_STATUS_NOTFOUND;
+- }
+- return NSS_STATUS_SUCCESS;
++ if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
++ return niserr2nss (result->status);
++
++ parse_res = _nss_nisplus_parse_aliasent (result, 0, alias,
++ buffer, buflen, errnop);
++ if (__builtin_expect (parse_res < 1, 0))
++ {
++ __set_errno (olderr);
++
++ if (parse_res == -1)
++ return NSS_STATUS_TRYAGAIN;
++ else
++ return NSS_STATUS_NOTFOUND;
+ }
++
++ return NSS_STATUS_SUCCESS;
+ }
+--- libc/nis/nss_nisplus/nisplus-ethers.c 25 Sep 2003 19:44:20 -0000 1.19
++++ libc/nis/nss_nisplus/nisplus-ethers.c 3 Dec 2005 21:45:55 -0000 1.21
+@@ -17,15 +17,17 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+-#include <nss.h>
+-#include <errno.h>
++#include <atomic.h>
+ #include <ctype.h>
+-#include <string.h>
+-#include <bits/libc-lock.h>
++#include <errno.h>
++#include <inttypes.h>
+ #include <netdb.h>
++#include <nss.h>
++#include <string.h>
+ #include <netinet/ether.h>
+-#include <rpcsvc/nis.h>
+ #include <netinet/if_ether.h>
++#include <rpcsvc/nis.h>
++#include <bits/libc-lock.h>
+
+ #include "nss-nisplus.h"
+
+@@ -70,7 +72,14 @@ _nss_nisplus_parse_etherent (nis_result
+ room_left -= (NISENTRYLEN (0, 0, result) +1);
+ ether->e_name = p;
+
+- ether->e_addr = *ether_aton (NISENTRYVAL (0, 1, result));
++ struct ether_addr *ea = ether_aton (NISENTRYVAL (0, 1, result));
++ if (ea == NULL)
++ {
++ *errnop = EINVAL;
++ return -2;
++ }
++
++ ether->e_addr = *ea;
+
+ return 1;
+ }
+@@ -80,18 +89,24 @@ _nss_create_tablename (int *errnop)
+ {
+ if (tablename_val == NULL)
+ {
+- char buf [40 + strlen (nis_local_directory ())];
+- char *p;
++ const char *local_dir = nis_local_directory ();
++ size_t local_dir_len = strlen (local_dir);
++ static const char prefix[] = "ethers.org_dir.";
+
+- p = __stpcpy (buf, "ethers.org_dir.");
+- p = __stpcpy (p, nis_local_directory ());
+- tablename_val = __strdup (buf);
+- if (tablename_val == NULL)
++ char *p = malloc (sizeof (prefix) + local_dir_len);
++ if (p == NULL)
+ {
+ *errnop = errno;
+ return NSS_STATUS_TRYAGAIN;
+ }
+- tablename_len = strlen (tablename_val);
++
++ memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
++
++ tablename_len = sizeof (prefix) - 1 + local_dir_len;
++
++ atomic_write_barrier ();
++
++ tablename_val = p;
+ }
+ return NSS_STATUS_SUCCESS;
+ }
+@@ -107,9 +122,11 @@ _nss_nisplus_setetherent (int stayopen)
+
+ __libc_lock_lock (lock);
+
+- if (result)
+- nis_freeresult (result);
+- result = NULL;
++ if (result != NULL)
++ {
++ nis_freeresult (result);
++ result = NULL;
++ }
+
+ if (_nss_create_tablename (&err) != NSS_STATUS_SUCCESS)
+ status = NSS_STATUS_UNAVAIL;
+@@ -124,9 +141,11 @@ _nss_nisplus_endetherent (void)
+ {
+ __libc_lock_lock (lock);
+
+- if (result)
+- nis_freeresult (result);
+- result = NULL;
++ if (result != NULL)
++ {
++ nis_freeresult (result);
++ result = NULL;
++ }
+
+ __libc_lock_unlock (lock);
+
+@@ -137,8 +156,6 @@ static enum nss_status
+ internal_nisplus_getetherent_r (struct etherent *ether, char *buffer,
+ size_t buflen, int *errnop)
+ {
+- int parse_res;
+-
+ if (tablename_val == NULL)
+ {
+ enum nss_status status = _nss_create_tablename (errnop);
+@@ -148,6 +165,7 @@ internal_nisplus_getetherent_r (struct e
+ }
+
+ /* Get the next entry until we found a correct one. */
++ int parse_res;
+ do
+ {
+ nis_result *saved_result;
+@@ -161,11 +179,8 @@ internal_nisplus_getetherent_r (struct e
+ }
+ else
+ {
+- nis_result *res2;
+-
+- res2 = nis_next_entry(tablename_val, &result->cookie);
+ saved_result = result;
+- result = res2;
++ result = nis_next_entry (tablename_val, &result->cookie);
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ {
+ nis_freeresult (saved_result);
+@@ -178,17 +193,15 @@ internal_nisplus_getetherent_r (struct e
+ if (parse_res == -1)
+ {
+ nis_freeresult (result);
+- *errnop = ERANGE;
+ result = saved_result;
+ return NSS_STATUS_TRYAGAIN;
+ }
+- else
+- {
+- if (saved_result != NULL)
+- nis_freeresult (saved_result);
+- }
+
+- } while (!parse_res);
++ if (saved_result != NULL)
++ nis_freeresult (saved_result);
++
++ }
++ while (!parse_res);
+
+ return NSS_STATUS_SUCCESS;
+ }
+@@ -212,8 +225,6 @@ enum nss_status
+ _nss_nisplus_gethostton_r (const char *name, struct etherent *eth,
+ char *buffer, size_t buflen, int *errnop)
+ {
+- int parse_res;
+-
+ if (tablename_val == NULL)
+ {
+ enum nss_status status = _nss_create_tablename (errnop);
+@@ -227,56 +238,57 @@ _nss_nisplus_gethostton_r (const char *n
+ *errnop = EINVAL;
+ return NSS_STATUS_UNAVAIL;
+ }
+- else
+- {
+- nis_result *result;
+- char buf[strlen (name) + 40 + tablename_len];
+- int olderr = errno;
+
+- sprintf (buf, "[name=%s],%s", name, tablename_val);
++ char buf[strlen (name) + 9 + tablename_len];
++ int olderr = errno;
+
+- result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++ snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
+
+- if (result == NULL)
+- {
+- *errnop = ENOMEM;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+- {
+- enum nss_status status = niserr2nss (result->status);
+- nis_freeresult (result);
+- return status;
+- }
++ nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++
++ if (result == NULL)
++ {
++ *errnop = ENOMEM;
++ return NSS_STATUS_TRYAGAIN;
++ }
++
++ if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
++ {
++ enum nss_status status = niserr2nss (result->status);
++ nis_freeresult (result);
++ return status;
++ }
+
+- parse_res = _nss_nisplus_parse_etherent (result, eth, buffer,
++ int parse_res = _nss_nisplus_parse_etherent (result, eth, buffer,
+ buflen, errnop);
+- if (parse_res < 1)
+- {
+- __set_errno (olderr);
++ if (__builtin_expect (parse_res < 1, 0))
++ {
++ __set_errno (olderr);
+
+- if (parse_res == -1)
+- {
+- nis_freeresult (result);
+- *errnop = ERANGE;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- else
+- return NSS_STATUS_NOTFOUND;
++ if (parse_res == -1)
++ {
++ nis_freeresult (result);
++ return NSS_STATUS_TRYAGAIN;
+ }
+- return NSS_STATUS_SUCCESS;
++ else
++ return NSS_STATUS_NOTFOUND;
+ }
++
++ return NSS_STATUS_SUCCESS;
+ }
+
+ enum nss_status
+-_nss_nisplus_getntohost_r (const struct ether_addr *addr,
+- struct etherent *eth,
++_nss_nisplus_getntohost_r (const struct ether_addr *addr, struct etherent *eth,
+ char *buffer, size_t buflen, int *errnop)
+ {
+ if (tablename_val == NULL)
+ {
++ __libc_lock_lock (lock);
++
+ enum nss_status status = _nss_create_tablename (errnop);
+
++ __libc_lock_unlock (lock);
++
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+ }
+@@ -286,44 +298,44 @@ _nss_nisplus_getntohost_r (const struct
+ *errnop = EINVAL;
+ return NSS_STATUS_UNAVAIL;
+ }
+- else
++
++ char buf[26 + tablename_len];
++
++ snprintf (buf, sizeof (buf),
++ "[addr=%" PRIx8 ":%" PRIx8 ":%" PRIx8 ":%" PRIx8 ":%" PRIx8
++ ":%" PRIx8 "],%s",
++ addr->ether_addr_octet[0], addr->ether_addr_octet[1],
++ addr->ether_addr_octet[2], addr->ether_addr_octet[3],
++ addr->ether_addr_octet[4], addr->ether_addr_octet[5],
++ tablename_val);
++
++ nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++
++ if (result == NULL)
+ {
+- int parse_res;
+- nis_result *result;
+- char buf[255 + tablename_len];
+-
+- sprintf (buf, "[addr=%x:%x:%x:%x:%x:%x],ethers.org_dir",
+- addr->ether_addr_octet[0], addr->ether_addr_octet[1],
+- addr->ether_addr_octet[2], addr->ether_addr_octet[3],
+- addr->ether_addr_octet[4], addr->ether_addr_octet[5]);
++ *errnop = ENOMEM;
++ return NSS_STATUS_TRYAGAIN;
++ }
+
+- result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++ if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
++ {
++ enum nss_status status = niserr2nss (result->status);
++ nis_freeresult (result);
++ return status;
++ }
+
+- if (result == NULL)
+- {
+- *errnop = ENOMEM;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
++ int parse_res = _nss_nisplus_parse_etherent (result, eth, buffer,
++ buflen, errnop);
++ if (__builtin_expect (parse_res < 1, 0))
++ {
++ if (parse_res == -1)
+ {
+- enum nss_status status = niserr2nss (result->status);
+ nis_freeresult (result);
+- return status;
++ return NSS_STATUS_TRYAGAIN;
+ }
+
+- parse_res = _nss_nisplus_parse_etherent (result, eth, buffer,
+- buflen, errnop);
+- if (parse_res < 1)
+- {
+- if (parse_res == -1)
+- {
+- nis_freeresult (result);
+- *errnop = ERANGE;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- else
+- return NSS_STATUS_NOTFOUND;
+- }
+- return NSS_STATUS_SUCCESS;
++ return NSS_STATUS_NOTFOUND;
+ }
++
++ return NSS_STATUS_SUCCESS;
+ }
+--- libc/nis/nss_nisplus/nisplus-grp.c 25 Sep 2003 19:44:20 -0000 1.16
++++ libc/nis/nss_nisplus/nisplus-grp.c 3 Dec 2005 05:04:16 -0000 1.18
+@@ -17,6 +17,7 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
++#include <atomic.h>
+ #include <nss.h>
+ #include <grp.h>
+ #include <ctype.h>
+@@ -28,31 +29,39 @@
+ #include "nss-nisplus.h"
+ #include "nisplus-parser.h"
+
++
+ __libc_lock_define_initialized (static, lock);
+
+ static nis_result *result;
+ static unsigned long next_entry;
+ static nis_name tablename_val;
+-static u_long tablename_len;
++static size_t tablename_len;
+
+ static enum nss_status
+ _nss_create_tablename (int *errnop)
+ {
+ if (tablename_val == NULL)
+ {
+- char buf [40 + strlen (nis_local_directory ())];
+- char *p;
++ const char *local_dir = nis_local_directory ();
++ size_t local_dir_len = strlen (local_dir);
++ static const char prefix[] = "group.org_dir.";
+
+- p = __stpcpy (buf, "group.org_dir.");
+- p = __stpcpy (p, nis_local_directory ());
+- tablename_val = __strdup (buf);
+- if (tablename_val == NULL)
++ char *p = malloc (sizeof (prefix) + local_dir_len);
++ if (p == NULL)
+ {
+ *errnop = errno;
+ return NSS_STATUS_TRYAGAIN;
+ }
+- tablename_len = strlen (tablename_val);
++
++ memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
++
++ tablename_len = sizeof (prefix) - 1 + local_dir_len;
++
++ atomic_write_barrier ();
++
++ tablename_val = p;
+ }
++
+ return NSS_STATUS_SUCCESS;
+ }
+
+@@ -60,16 +69,20 @@ static enum nss_status
+ internal_setgrent (void)
+ {
+ enum nss_status status;
+- int err;
+
+- if (result)
+- nis_freeresult (result);
+- result = NULL;
++ if (result != NULL)
++ {
++ nis_freeresult (result);
++ result = NULL;
++ }
+ next_entry = 0;
+
+ if (tablename_val == NULL)
+- if (_nss_create_tablename (&err) != NSS_STATUS_SUCCESS)
+- return NSS_STATUS_UNAVAIL;
++ {
++ int err;
++ if (_nss_create_tablename (&err) != NSS_STATUS_SUCCESS)
++ return NSS_STATUS_UNAVAIL;
++ }
+
+ result = nis_list (tablename_val, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
+ if (result == NULL)
+@@ -108,9 +121,11 @@ _nss_nisplus_endgrent (void)
+ {
+ __libc_lock_lock (lock);
+
+- if (result)
+- nis_freeresult (result);
+- result = NULL;
++ if (result != NULL)
++ {
++ nis_freeresult (result);
++ result = NULL;
++ }
+
+ __libc_lock_unlock (lock);
+
+@@ -173,8 +188,12 @@ _nss_nisplus_getgrnam_r (const char *nam
+
+ if (tablename_val == NULL)
+ {
++ __libc_lock_lock (lock);
++
+ enum nss_status status = _nss_create_tablename (errnop);
+
++ __libc_lock_unlock (lock);
++
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+ }
+@@ -184,47 +203,46 @@ _nss_nisplus_getgrnam_r (const char *nam
+ *errnop = EINVAL;
+ return NSS_STATUS_NOTFOUND;
+ }
+- else
++
++ nis_result *result;
++ char buf[strlen (name) + 9 + tablename_len];
++ int olderr = errno;
++
++ snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
++
++ result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
++
++ if (result == NULL)
+ {
+- nis_result *result;
+- char buf[strlen (name) + 24 + tablename_len];
+- int olderr = errno;
++ *errnop = ENOMEM;
++ return NSS_STATUS_TRYAGAIN;
++ }
+
+- sprintf (buf, "[name=%s],%s", name, tablename_val);
++ if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
++ {
++ enum nss_status status = niserr2nss (result->status);
+
+- result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
++ nis_freeresult (result);
++ return status;
++ }
+
+- if (result == NULL)
++ parse_res = _nss_nisplus_parse_grent (result, 0, gr, buffer, buflen, errnop);
++ nis_freeresult (result);
++ if (__builtin_expect (parse_res < 1, 0))
++ {
++ if (parse_res == -1)
+ {
+- *errnop = ENOMEM;
++ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+- if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
++ else
+ {
+- enum nss_status status = niserr2nss (result->status);
+-
+- nis_freeresult (result);
+- return status;
+- }
+-
+- parse_res = _nss_nisplus_parse_grent (result, 0, gr, buffer, buflen,
+- errnop);
+- nis_freeresult (result);
+- if (parse_res < 1)
+- {
+- if (parse_res == -1)
+- {
+- *errnop = ERANGE;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- else
+- {
+- __set_errno (olderr);
+- return NSS_STATUS_NOTFOUND;
+- }
++ __set_errno (olderr);
++ return NSS_STATUS_NOTFOUND;
+ }
+- return NSS_STATUS_SUCCESS;
+ }
++
++ return NSS_STATUS_SUCCESS;
+ }
+
+ enum nss_status
+@@ -233,53 +251,57 @@ _nss_nisplus_getgrgid_r (const gid_t gid
+ {
+ if (tablename_val == NULL)
+ {
++ __libc_lock_lock (lock);
++
+ enum nss_status status = _nss_create_tablename (errnop);
+
++ __libc_lock_unlock (lock);
++
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+ }
+
+- {
+- int parse_res;
+- nis_result *result;
+- char buf[36 + tablename_len];
+- int olderr = errno;
+-
+- sprintf (buf, "[gid=%lu],%s", (unsigned long int) gid, tablename_val);
+-
+- result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+-
+- if (result == NULL)
+- {
+- *errnop = ENOMEM;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+- {
+- enum nss_status status = niserr2nss (result->status);
++ int parse_res;
++ nis_result *result;
++ char buf[8 + 3 * sizeof (unsigned long int) + tablename_len];
++ int olderr = errno;
+
+- __set_errno (olderr);
++ snprintf (buf, sizeof (buf), "[gid=%lu],%s",
++ (unsigned long int) gid, tablename_val);
+
+- nis_freeresult (result);
+- return status;
+- }
++ result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++
++ if (result == NULL)
++ {
++ *errnop = ENOMEM;
++ return NSS_STATUS_TRYAGAIN;
++ }
+
+- parse_res = _nss_nisplus_parse_grent (result, 0, gr, buffer, buflen,
+- errnop);
++ if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
++ {
++ enum nss_status status = niserr2nss (result->status);
+
+- nis_freeresult (result);
+- if (parse_res < 1)
+- {
+- __set_errno (olderr);
+-
+- if (parse_res == -1)
+- {
+- *errnop = ERANGE;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- else
+- return NSS_STATUS_NOTFOUND;
+- }
+- return NSS_STATUS_SUCCESS;
+- }
++ __set_errno (olderr);
++
++ nis_freeresult (result);
++ return status;
++ }
++
++ parse_res = _nss_nisplus_parse_grent (result, 0, gr, buffer, buflen, errnop);
++
++ nis_freeresult (result);
++ if (__builtin_expect (parse_res < 1, 0))
++ {
++ __set_errno (olderr);
++
++ if (parse_res == -1)
++ {
++ *errnop = ERANGE;
++ return NSS_STATUS_TRYAGAIN;
++ }
++ else
++ return NSS_STATUS_NOTFOUND;
++ }
++
++ return NSS_STATUS_SUCCESS;
+ }
+--- libc/nis/nss_nisplus/nisplus-hosts.c 25 Sep 2003 19:44:20 -0000 1.27
++++ libc/nis/nss_nisplus/nisplus-hosts.c 3 Dec 2005 17:47:33 -0000 1.28
+@@ -17,15 +17,16 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+-#include <nss.h>
+-#include <netdb.h>
+-#include <errno.h>
++#include <atomic.h>
+ #include <ctype.h>
++#include <errno.h>
++#include <netdb.h>
++#include <nss.h>
+ #include <string.h>
+-#include <netinet/in.h>
+ #include <arpa/inet.h>
+-#include <bits/libc-lock.h>
++#include <netinet/in.h>
+ #include <rpcsvc/nis.h>
++#include <bits/libc-lock.h>
+
+ #include "nss-nisplus.h"
+
+@@ -180,19 +181,26 @@ _nss_create_tablename (int *errnop)
+ {
+ if (tablename_val == NULL)
+ {
+- char buf [40 + strlen (nis_local_directory ())];
+- char *p;
++ const char *local_dir = nis_local_directory ();
++ size_t local_dir_len = strlen (local_dir);
++ static const char prefix[] = "hosts.org_dir.";
+
+- p = __stpcpy (buf, "hosts.org_dir.");
+- p = __stpcpy (p, nis_local_directory ());
+- tablename_val = __strdup (buf);
+- if (tablename_val == NULL)
++ char *p = malloc (sizeof (prefix) + local_dir_len);
++ if (p == NULL)
+ {
+ *errnop = errno;
+ return NSS_STATUS_TRYAGAIN;
+ }
+- tablename_len = strlen (tablename_val);
++
++ memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
++
++ tablename_len = sizeof (prefix) - 1 + local_dir_len;
++
++ atomic_write_barrier ();
++
++ tablename_val = p;
+ }
++
+ return NSS_STATUS_SUCCESS;
+ }
+
+@@ -204,9 +212,11 @@ _nss_nisplus_sethostent (int stayopen)
+
+ __libc_lock_lock (lock);
+
+- if (result)
+- nis_freeresult (result);
+- result = NULL;
++ if (result != NULL)
++ {
++ nis_freeresult (result);
++ result = NULL;
++ }
+
+ if (tablename_val == NULL)
+ status = _nss_create_tablename (&err);
+@@ -221,9 +231,11 @@ _nss_nisplus_endhostent (void)
+ {
+ __libc_lock_lock (lock);
+
+- if (result)
+- nis_freeresult (result);
+- result = NULL;
++ if (result != NULL)
++ {
++ nis_freeresult (result);
++ result = NULL;
++ }
+
+ __libc_lock_unlock (lock);
+
+@@ -335,8 +347,12 @@ internal_gethostbyname2_r (const char *n
+
+ if (tablename_val == NULL)
+ {
++ __libc_lock_lock (lock);
++
+ enum nss_status status = _nss_create_tablename (errnop);
+
++ __libc_lock_unlock (lock);
++
+ if (status != NSS_STATUS_SUCCESS)
+ {
+ *herrnop = NETDB_INTERNAL;
+@@ -350,75 +366,81 @@ internal_gethostbyname2_r (const char *n
+ *herrnop = NETDB_INTERNAL;
+ return NSS_STATUS_NOTFOUND;
+ }
+- else
+- {
+- nis_result *result;
+- char buf[strlen (name) + 255 + tablename_len];
+- int olderr = errno;
+-
+- /* Search at first in the alias list, and use the correct name
+- for the next search */
+- sprintf (buf, "[name=%s],%s", name, tablename_val);
+- result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+-
+- if (result != NULL)
+- {
+- /* If we do not find it, try it as original name. But if the
+- database is correct, we should find it in the first case, too */
+- if ((result->status != NIS_SUCCESS
+- && result->status != NIS_S_SUCCESS)
+- || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
+- || strcmp (result->objects.objects_val->EN_data.en_type,
+- "hosts_tbl") != 0
+- || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3)
+- sprintf (buf, "[cname=%s],%s", name, tablename_val);
+- else
+- sprintf (buf, "[cname=%s],%s", NISENTRYVAL(0, 0, result),
+- tablename_val);
+-
+- nis_freeresult (result);
+- result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+- }
+
+- if (result == NULL)
++ nis_result *result;
++ char buf[strlen (name) + 10 + tablename_len];
++ int olderr = errno;
++
++ /* Search at first in the alias list, and use the correct name
++ for the next search. */
++ snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
++ result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++
++ if (result != NULL)
++ {
++ char *bufptr = buf;
++
++ /* If we did not find it, try it as original name. But if the
++ database is correct, we should find it in the first case, too. */
++ if ((result->status != NIS_SUCCESS
++ && result->status != NIS_S_SUCCESS)
++ || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
++ || strcmp (result->objects.objects_val->EN_data.en_type,
++ "hosts_tbl") != 0
++ || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3)
++ snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val);
++ else
+ {
+- *errnop = ENOMEM;
+- return NSS_STATUS_TRYAGAIN;
++ /* We need to allocate a new buffer since there is no
++ guarantee the returned name has a length limit. */
++ const char *entryval = NISENTRYVAL(0, 0, result);
++ size_t buflen = strlen (entryval) + 10 + tablename_len;
++ bufptr = alloca (buflen);
++ snprintf (bufptr, buflen, "[cname=%s],%s",
++ entryval, tablename_val);
+ }
+- retval = niserr2nss (result->status);
+- if (retval != NSS_STATUS_SUCCESS)
+- {
+- if (retval == NSS_STATUS_TRYAGAIN)
+- {
+- *errnop = errno;
+- *herrnop = NETDB_INTERNAL;
+- }
+- else
+- __set_errno (olderr);
+- nis_freeresult (result);
+- return retval;
+- }
+-
+- parse_res = _nss_nisplus_parse_hostent (result, af, host, buffer,
+- buflen, errnop, flags);
+
+ nis_freeresult (result);
++ result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++ }
+
+- if (parse_res > 0)
+- return NSS_STATUS_SUCCESS;
++ if (result == NULL)
++ {
++ *errnop = ENOMEM;
++ return NSS_STATUS_TRYAGAIN;
++ }
+
+- *herrnop = NETDB_INTERNAL;
+- if (parse_res == -1)
++ retval = niserr2nss (result->status);
++ if (__builtin_expect (retval != NSS_STATUS_SUCCESS, 0))
++ {
++ if (retval == NSS_STATUS_TRYAGAIN)
+ {
+- *errnop = ERANGE;
+- return NSS_STATUS_TRYAGAIN;
++ *errnop = errno;
++ *herrnop = NETDB_INTERNAL;
+ }
+ else
+- {
+- __set_errno (olderr);
+- return NSS_STATUS_NOTFOUND;
+- }
++ __set_errno (olderr);
++ nis_freeresult (result);
++ return retval;
++ }
++
++ parse_res = _nss_nisplus_parse_hostent (result, af, host, buffer,
++ buflen, errnop, flags);
++
++ nis_freeresult (result);
++
++ if (parse_res > 0)
++ return NSS_STATUS_SUCCESS;
++
++ *herrnop = NETDB_INTERNAL;
++ if (parse_res == -1)
++ {
++ *errnop = ERANGE;
++ return NSS_STATUS_TRYAGAIN;
+ }
++
++ __set_errno (olderr);
++ return NSS_STATUS_NOTFOUND;
+ }
+
+ enum nss_status
+@@ -431,17 +453,6 @@ _nss_nisplus_gethostbyname2_r (const cha
+ ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0));
+ }
+
+-#if 0
+-enum nss_status
+-_nss_nisplus_getipnodebyname_r (const char *name, int af, int flags,
+- struct hostent *result, char *buffer,
+- size_t buflen, int *errnop, int *herrnop)
+-{
+- return internal_gethostbyname2_r (name, af, result, buffer, buflen,
+- errnop, herrnop, flags);
+-}
+-#endif
+-
+ enum nss_status
+ _nss_nisplus_gethostbyname_r (const char *name, struct hostent *host,
+ char *buffer, size_t buflen, int *errnop,
+@@ -469,62 +480,63 @@ _nss_nisplus_gethostbyaddr_r (const void
+ {
+ if (tablename_val == NULL)
+ {
++ __libc_lock_lock (lock);
++
+ enum nss_status status = _nss_create_tablename (errnop);
+
++ __libc_lock_unlock (lock);
++
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+ }
+
+ if (addr == NULL)
+ return NSS_STATUS_NOTFOUND;
+- else
++
++ char buf[24 + tablename_len];
++ int retval, parse_res;
++ int olderr = errno;
++
++ snprintf (buf, sizeof (buf), "[addr=%s],%s",
++ inet_ntoa (*(const struct in_addr *) addr), tablename_val);
++ nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++
++ if (result == NULL)
+ {
+- nis_result *result;
+- char buf[255 + tablename_len];
+- int retval, parse_res;
+- int olderr = errno;
+-
+- sprintf (buf, "[addr=%s],%s",
+- inet_ntoa (*(const struct in_addr *) addr), tablename_val);
+- result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++ __set_errno (ENOMEM);
++ return NSS_STATUS_TRYAGAIN;
++ }
+
+- if (result == NULL)
++ retval = niserr2nss (result->status);
++ if (__builtin_expect (retval != NSS_STATUS_SUCCESS, 0))
++ {
++ if (retval == NSS_STATUS_TRYAGAIN)
+ {
+- __set_errno (ENOMEM);
+- return NSS_STATUS_TRYAGAIN;
++ *errnop = errno;
++ *herrnop = NETDB_INTERNAL;
+ }
+- retval = niserr2nss (result->status);
+- if (retval != NSS_STATUS_SUCCESS)
+- {
+- if (retval == NSS_STATUS_TRYAGAIN)
+- {
+- *errnop = errno;
+- *herrnop = NETDB_INTERNAL;
+- }
+- else
+- __set_errno (olderr);
+- nis_freeresult (result);
+- return retval;
+- }
+-
+- parse_res = _nss_nisplus_parse_hostent (result, af, host,
+- buffer, buflen, errnop,
+- ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0));
++ else
++ __set_errno (olderr);
+ nis_freeresult (result);
++ return retval;
++ }
+
+- if (parse_res > 0)
+- return NSS_STATUS_SUCCESS;
++ parse_res = _nss_nisplus_parse_hostent (result, af, host,
++ buffer, buflen, errnop,
++ ((_res.options & RES_USE_INET6)
++ ? AI_V4MAPPED : 0));
++ nis_freeresult (result);
+
+- *herrnop = NETDB_INTERNAL;
+- if (parse_res == -1)
+- {
+- *errnop = ERANGE;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- else
+- {
+- __set_errno (olderr);
+- return NSS_STATUS_NOTFOUND;
+- }
++ if (parse_res > 0)
++ return NSS_STATUS_SUCCESS;
++
++ *herrnop = NETDB_INTERNAL;
++ if (parse_res == -1)
++ {
++ *errnop = ERANGE;
++ return NSS_STATUS_TRYAGAIN;
+ }
++
++ __set_errno (olderr);
++ return NSS_STATUS_NOTFOUND;
+ }
+--- libc/nis/nss_nisplus/nisplus-netgrp.c 10 Sep 2005 03:18:49 -0000 1.15
++++ libc/nis/nss_nisplus/nisplus-netgrp.c 3 Dec 2005 22:11:34 -0000 1.16
+@@ -150,15 +150,14 @@ internal_endnetgrent (struct __netgrent
+ enum nss_status
+ _nss_nisplus_setnetgrent (const char *group, struct __netgrent *netgrp)
+ {
+- enum nss_status status;
+- char buf[strlen (group) + 30];
++ char buf[strlen (group) + 25];
+
+ if (group == NULL || group[0] == '\0')
+ return NSS_STATUS_UNAVAIL;
+
+- status = NSS_STATUS_SUCCESS;
++ enum nss_status status = NSS_STATUS_SUCCESS;
+
+- sprintf (buf, "[name=%s],netgroup.org_dir", group);
++ snprintf (buf, sizeof (buf), "[name=%s],netgroup.org_dir", group);
+
+ netgrp->data = (char *) nis_list (buf, EXPAND_NAME, NULL, NULL);
+
+--- libc/nis/nss_nisplus/nisplus-network.c 25 Sep 2003 19:44:20 -0000 1.19
++++ libc/nis/nss_nisplus/nisplus-network.c 3 Dec 2005 22:35:12 -0000 1.21
+@@ -17,15 +17,16 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+-#include <nss.h>
+-#include <netdb.h>
+-#include <errno.h>
++#include <atomic.h>
+ #include <ctype.h>
++#include <errno.h>
++#include <netdb.h>
++#include <nss.h>
+ #include <stdint.h>
+ #include <string.h>
+ #include <arpa/inet.h>
+-#include <bits/libc-lock.h>
+ #include <rpcsvc/nis.h>
++#include <bits/libc-lock.h>
+
+ #include "nss-nisplus.h"
+
+@@ -44,12 +45,10 @@ static u_long tablename_len;
+
+ static int
+ _nss_nisplus_parse_netent (nis_result *result, struct netent *network,
+- char *buffer, size_t buflen, int *errnop)
++ char *buffer, size_t buflen, int *errnop)
+ {
+ char *first_unused = buffer;
+ size_t room_left = buflen;
+- unsigned int i;
+- char *p, *line;
+
+ if (result == NULL)
+ return 0;
+@@ -61,7 +60,7 @@ _nss_nisplus_parse_netent (nis_result *r
+ || result->objects.objects_val[0].EN_data.en_cols.en_cols_len < 3)
+ return 0;
+
+- if (NISENTRYLEN(0, 0, result) >= room_left)
++ if (NISENTRYLEN (0, 0, result) >= room_left)
+ {
+ /* The line is too long for our buffer. */
+ no_more_room:
+@@ -69,7 +68,7 @@ _nss_nisplus_parse_netent (nis_result *r
+ return -1;
+ }
+
+- strncpy (first_unused, NISENTRYVAL(0, 0, result),
++ strncpy (first_unused, NISENTRYVAL (0, 0, result),
+ NISENTRYLEN (0, 0, result));
+ first_unused[NISENTRYLEN (0, 0, result)] = '\0';
+ network->n_name = first_unused;
+@@ -77,10 +76,10 @@ _nss_nisplus_parse_netent (nis_result *r
+ first_unused += strlen (first_unused) +1;
+ network->n_addrtype = 0;
+ network->n_net = inet_network (NISENTRYVAL (0, 2, result));
+- p = first_unused;
++ char *p = first_unused;
+
+- line = p;
+- for (i = 0; i < result->objects.objects_len; ++i)
++ char *line = p;
++ for (unsigned int i = 0; i < result->objects.objects_len; ++i)
+ {
+ if (strcmp (NISENTRYVAL (i, 1, result), network->n_name) != 0)
+ {
+@@ -107,12 +106,12 @@ _nss_nisplus_parse_netent (nis_result *r
+ room_left -= (2 * sizeof (char *));
+ network->n_aliases[0] = NULL;
+
+- i = 0;
++ unsigned int i = 0;
+ while (*line != '\0')
+ {
+ /* Skip leading blanks. */
+ while (isspace (*line))
+- line++;
++ ++line;
+
+ if (*line == '\0')
+ break;
+@@ -133,7 +132,7 @@ _nss_nisplus_parse_netent (nis_result *r
+ ++i;
+ }
+ else
+- network->n_aliases[i+1] = NULL;
++ network->n_aliases[i + 1] = NULL;
+ }
+
+ return 1;
+@@ -144,19 +143,26 @@ _nss_create_tablename (int *errnop)
+ {
+ if (tablename_val == NULL)
+ {
+- char buf [40 + strlen (nis_local_directory ())];
+- char *p;
++ const char *local_dir = nis_local_directory ();
++ size_t local_dir_len = strlen (local_dir);
++ static const char prefix[] = "networks.org_dir.";
+
+- p = __stpcpy (buf, "networks.org_dir.");
+- p = __stpcpy (p, nis_local_directory ());
+- tablename_val = __strdup (buf);
+- if (tablename_val == NULL)
++ char *p = malloc (sizeof (prefix) + local_dir_len);
++ if (p == NULL)
+ {
+ *errnop = errno;
+ return NSS_STATUS_TRYAGAIN;
+ }
+- tablename_len = strlen (tablename_val);
++
++ memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
++
++ tablename_len = sizeof (prefix) - 1 + local_dir_len;
++
++ atomic_write_barrier ();
++
++ tablename_val = p;
+ }
++
+ return NSS_STATUS_SUCCESS;
+ }
+
+@@ -164,16 +170,20 @@ enum nss_status
+ _nss_nisplus_setnetent (int stayopen)
+ {
+ enum nss_status status = NSS_STATUS_SUCCESS;
+- int err;
+
+ __libc_lock_lock (lock);
+
+- if (result)
+- nis_freeresult (result);
+- result = NULL;
++ if (result != NULL)
++ {
++ nis_freeresult (result);
++ result = NULL;
++ }
+
+ if (tablename_val == NULL)
+- status = _nss_create_tablename (&err);
++ {
++ int err;
++ status = _nss_create_tablename (&err);
++ }
+
+ __libc_lock_unlock (lock);
+
+@@ -185,9 +195,11 @@ _nss_nisplus_endnetent (void)
+ {
+ __libc_lock_lock (lock);
+
+- if (result)
+- nis_freeresult (result);
+- result = NULL;
++ if (result != NULL)
++ {
++ nis_freeresult (result);
++ result = NULL;
++ }
+
+ __libc_lock_unlock (lock);
+
+@@ -220,9 +232,7 @@ internal_nisplus_getnetent_r (struct net
+ result = nis_first_entry (tablename_val);
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ {
+- int retval;
+-
+- retval = niserr2nss (result->status);
++ int retval = niserr2nss (result->status);
+ nis_freeresult (result);
+ result = NULL;
+ if (retval == NSS_STATUS_TRYAGAIN)
+@@ -237,16 +247,12 @@ internal_nisplus_getnetent_r (struct net
+ }
+ else
+ {
+- nis_result *res;
+-
+- res = nis_next_entry (tablename_val, &result->cookie);
++ nis_result *res = nis_next_entry (tablename_val, &result->cookie);
+ saved_res = result;
+ result = res;
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ {
+- int retval;
+-
+- retval = niserr2nss (result->status);
++ int retval = niserr2nss (result->status);
+ nis_freeresult (result);
+ result = saved_res;
+ if (retval == NSS_STATUS_TRYAGAIN)
+@@ -266,7 +272,8 @@ internal_nisplus_getnetent_r (struct net
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- } while (!parse_res);
++ }
++ while (!parse_res);
+
+ return NSS_STATUS_SUCCESS;
+ }
+@@ -296,8 +303,12 @@ _nss_nisplus_getnetbyname_r (const char
+
+ if (tablename_val == NULL)
+ {
++ __libc_lock_lock (lock);
++
+ enum nss_status status = _nss_create_tablename (errnop);
+
++ __libc_lock_unlock (lock);
++
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+ }
+@@ -308,76 +319,82 @@ _nss_nisplus_getnetbyname_r (const char
+ *herrnop = NETDB_INTERNAL;
+ return NSS_STATUS_UNAVAIL;
+ }
+- else
+- {
+- nis_result *result;
+- char buf[strlen (name) + 255 + tablename_len];
+- int olderr = errno;
+-
+- /* Search at first in the alias list, and use the correct name
+- for the next search */
+- sprintf (buf, "[name=%s],%s", name, tablename_val);
+- result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
+
+- if (result != NULL)
+- {
+- /* If we do not find it, try it as original name. But if the
+- database is correct, we should find it in the first case, too */
+- if ((result->status != NIS_SUCCESS
+- && result->status != NIS_S_SUCCESS)
+- || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
+- || strcmp (result->objects.objects_val[0].EN_data.en_type,
+- "networks_tbl") != 0
+- || (result->objects.objects_val[0].EN_data.en_cols.en_cols_len
+- < 3))
+- sprintf (buf, "[cname=%s],%s", name, tablename_val);
+- else
+- sprintf (buf, "[cname=%s],%s", NISENTRYVAL (0, 0, result),
+- tablename_val);
++ nis_result *result;
++ char buf[strlen (name) + 10 + tablename_len];
++ int olderr = errno;
++
++ /* Search at first in the alias list, and use the correct name
++ for the next search */
++ snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
++ result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
+
+- nis_freeresult (result);
+- result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
+- }
++ if (result != NULL)
++ {
++ char *bufptr = buf;
+
+- if (result == NULL)
+- {
+- __set_errno (ENOMEM);
+- return NSS_STATUS_TRYAGAIN;
+- }
+- retval = niserr2nss (result->status);
+- if (retval != NSS_STATUS_SUCCESS)
++ /* If we do not find it, try it as original name. But if the
++ database is correct, we should find it in the first case, too */
++ if ((result->status != NIS_SUCCESS
++ && result->status != NIS_S_SUCCESS)
++ || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
++ || strcmp (result->objects.objects_val[0].EN_data.en_type,
++ "networks_tbl") != 0
++ || (result->objects.objects_val[0].EN_data.en_cols.en_cols_len
++ < 3))
++ snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val);
++ else
+ {
+- if (retval == NSS_STATUS_TRYAGAIN)
+- {
+- *errnop = errno;
+- *herrnop = NETDB_INTERNAL;
+- }
+- else
+- __set_errno (olderr);
+- nis_freeresult (result);
+- return retval;
++ /* We need to allocate a new buffer since there is no
++ guarantee the returned name has a length limit. */
++ const char *entryval = NISENTRYVAL (0, 0, result);
++ size_t buflen = strlen (entryval) + 10 + tablename_len;
++ bufptr = alloca (buflen);
++ snprintf (bufptr, buflen, "[cname=%s],%s",
++ entryval, tablename_val);
+ }
+
+- parse_res = _nss_nisplus_parse_netent (result, network, buffer, buflen,
+- errnop);
+-
+ nis_freeresult (result);
++ result = nis_list (bufptr, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
++ }
+
+- if (parse_res > 0)
+- return NSS_STATUS_SUCCESS;
++ if (result == NULL)
++ {
++ __set_errno (ENOMEM);
++ return NSS_STATUS_TRYAGAIN;
++ }
+
+- *herrnop = NETDB_INTERNAL;
+- if (parse_res == -1)
++ retval = niserr2nss (result->status);
++ if (__builtin_expect (retval != NSS_STATUS_SUCCESS, 0))
++ {
++ if (retval == NSS_STATUS_TRYAGAIN)
+ {
+- *errnop = ERANGE;
+- return NSS_STATUS_TRYAGAIN;
++ *errnop = errno;
++ *herrnop = NETDB_INTERNAL;
+ }
+ else
+- {
+- __set_errno (olderr);
+- return NSS_STATUS_NOTFOUND;
+- }
++ __set_errno (olderr);
++ nis_freeresult (result);
++ return retval;
++ }
++
++ parse_res = _nss_nisplus_parse_netent (result, network, buffer, buflen,
++ errnop);
++
++ nis_freeresult (result);
++
++ if (parse_res > 0)
++ return NSS_STATUS_SUCCESS;
++
++ *herrnop = NETDB_INTERNAL;
++ if (parse_res == -1)
++ {
++ *errnop = ERANGE;
++ return NSS_STATUS_TRYAGAIN;
+ }
++
++ __set_errno (olderr);
++ return NSS_STATUS_NOTFOUND;
+ }
+
+ /* XXX type is ignored, SUN's NIS+ table doesn't support it */
+@@ -388,39 +405,39 @@ _nss_nisplus_getnetbyaddr_r (uint32_t ad
+ {
+ if (tablename_val == NULL)
+ {
++ __libc_lock_lock (lock);
++
+ enum nss_status status = _nss_create_tablename (errnop);
+
++ __libc_lock_unlock (lock);
++
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+ }
+
+ {
+- int parse_res, retval;
+- nis_result *result;
+- char buf[1024 + tablename_len];
+- struct in_addr in;
+- char buf2[256];
+- int b2len;
++ char buf[27 + tablename_len];
++ char buf2[18];
+ int olderr = errno;
+
+- in = inet_makeaddr (addr, 0);
++ struct in_addr in = inet_makeaddr (addr, 0);
+ strcpy (buf2, inet_ntoa (in));
+- b2len = strlen (buf2);
++ size_t b2len = strlen (buf2);
+
+ while (1)
+ {
+- sprintf (buf, "[addr=%s],%s", buf2, tablename_val);
+- result = nis_list (buf, EXPAND_NAME, NULL, NULL);
++ snprintf (buf, sizeof (buf), "[addr=%s],%s", buf2, tablename_val);
++ nis_result *result = nis_list (buf, EXPAND_NAME, NULL, NULL);
+
+ if (result == NULL)
+ {
+ __set_errno (ENOMEM);
+ return NSS_STATUS_TRYAGAIN;
+ }
+- retval = niserr2nss (result->status);
+- if (retval != NSS_STATUS_SUCCESS)
++ enum nss_status retval = niserr2nss (result->status);
++ if (__builtin_expect (retval != NSS_STATUS_SUCCESS, 0))
+ {
+- if (buf2[b2len -2] == '.' && buf2[b2len -1] == '0')
++ if (b2len > 2 && buf2[b2len - 2] == '.' && buf2[b2len - 1] == '0')
+ {
+ /* Try again, but with trailing dot(s)
+ removed (one by one) */
+@@ -428,8 +445,6 @@ _nss_nisplus_getnetbyaddr_r (uint32_t ad
+ b2len -= 2;
+ continue;
+ }
+- else
+- return NSS_STATUS_NOTFOUND;
+
+ if (retval == NSS_STATUS_TRYAGAIN)
+ {
+@@ -442,8 +457,8 @@ _nss_nisplus_getnetbyaddr_r (uint32_t ad
+ return retval;
+ }
+
+- parse_res = _nss_nisplus_parse_netent (result, network, buffer,
+- buflen, errnop);
++ int parse_res = _nss_nisplus_parse_netent (result, network, buffer,
++ buflen, errnop);
+
+ nis_freeresult (result);
+
+--- libc/nis/nss_nisplus/nisplus-proto.c 25 Sep 2003 19:44:20 -0000 1.19
++++ libc/nis/nss_nisplus/nisplus-proto.c 3 Dec 2005 19:33:09 -0000 1.20
+@@ -17,13 +17,14 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+-#include <nss.h>
+-#include <errno.h>
++#include <atomic.h>
+ #include <ctype.h>
++#include <errno.h>
+ #include <netdb.h>
++#include <nss.h>
+ #include <string.h>
+-#include <bits/libc-lock.h>
+ #include <rpcsvc/nis.h>
++#include <bits/libc-lock.h>
+
+ #include "nss-nisplus.h"
+
+@@ -141,19 +142,26 @@ _nss_create_tablename (int *errnop)
+ {
+ if (tablename_val == NULL)
+ {
+- char buf [40 + strlen (nis_local_directory ())];
+- char *p;
++ const char *local_dir = nis_local_directory ();
++ size_t local_dir_len = strlen (local_dir);
++ static const char prefix[] = "protocols.org_dir.";
+
+- p = __stpcpy (buf, "protocols.org_dir.");
+- p = __stpcpy (p, nis_local_directory ());
+- tablename_val = __strdup (buf);
+- if (tablename_val == NULL)
++ char *p = malloc (sizeof (prefix) + local_dir_len);
++ if (p == NULL)
+ {
+ *errnop = errno;
+ return NSS_STATUS_TRYAGAIN;
+ }
+- tablename_len = strlen (tablename_val);
++
++ memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
++
++ tablename_len = sizeof (prefix) - 1 + local_dir_len;
++
++ atomic_write_barrier ();
++
++ tablename_val = p;
+ }
++
+ return NSS_STATUS_SUCCESS;
+ }
+
+@@ -164,9 +172,11 @@ _nss_nisplus_setprotoent (int stayopen)
+
+ __libc_lock_lock (lock);
+
+- if (result)
+- nis_freeresult (result);
+- result = NULL;
++ if (result != NULL)
++ {
++ nis_freeresult (result);
++ result = NULL;
++ }
+
+ if (tablename_val == NULL)
+ {
+@@ -184,9 +194,11 @@ _nss_nisplus_endprotoent (void)
+ {
+ __libc_lock_lock (lock);
+
+- if (result)
+- nis_freeresult (result);
+- result = NULL;
++ if (result != NULL)
++ {
++ nis_freeresult (result);
++ result = NULL;
++ }
+
+ __libc_lock_unlock (lock);
+
+@@ -221,11 +233,8 @@ internal_nisplus_getprotoent_r (struct p
+ }
+ else
+ {
+- nis_result *res;
+-
+ saved_res = result;
+- res = nis_next_entry (tablename_val, &result->cookie);
+- result = res;
++ result = nis_next_entry (tablename_val, &result->cookie);
+
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ {
+@@ -277,79 +286,91 @@ _nss_nisplus_getprotobyname_r (const cha
+
+ if (tablename_val == NULL)
+ {
++ __libc_lock_lock (lock);
++
+ enum nss_status status = _nss_create_tablename (errnop);
+
++ __libc_lock_unlock (lock);
++
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+ }
+
+ if (name == NULL)
+ return NSS_STATUS_NOTFOUND;
+- else
+- {
+- nis_result *result;
+- char buf[strlen (name) + 255 + tablename_len];
+- int olderr = errno;
+-
+- /* Search at first in the alias list, and use the correct name
+- for the next search */
+- sprintf (buf, "[name=%s],%s", name, tablename_val);
+- result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+
+- if (result != NULL)
+- {
+- /* If we do not find it, try it as original name. But if the
+- database is correct, we should find it in the first case, too */
+- if ((result->status != NIS_SUCCESS
+- && result->status != NIS_S_SUCCESS)
+- || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
+- || strcmp (result->objects.objects_val->EN_data.en_type,
+- "protocols_tbl") != 0
+- || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3)
+- sprintf (buf, "[cname=%s],%s", name, tablename_val);
+- else
+- sprintf (buf, "[cname=%s],%s", NISENTRYVAL (0, 0, result),
+- tablename_val);
++ char buf[strlen (name) + 10 + tablename_len];
++ int olderr = errno;
+
+- nis_freeresult (result);
+- result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+- }
++ /* Search at first in the alias list, and use the correct name
++ for the next search */
++ snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
++ nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+
+- if (result == NULL)
++ if (result != NULL)
++ {
++ char *bufptr = buf;
++
++ /* If we did not find it, try it as original name. But if the
++ database is correct, we should find it in the first case, too */
++ if ((result->status != NIS_SUCCESS
++ && result->status != NIS_S_SUCCESS)
++ || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
++ || strcmp (result->objects.objects_val->EN_data.en_type,
++ "protocols_tbl") != 0
++ || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3)
++ snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val);
++ else
+ {
+- __set_errno (ENOMEM);
+- return NSS_STATUS_TRYAGAIN;
++ /* We need to allocate a new buffer since there is no
++ guarantee the returned name has a length limit. */
++ const char *entryval = NISENTRYVAL (0, 0, result);
++ size_t buflen = strlen (entryval) + 10 + tablename_len;
++ bufptr = alloca (buflen);
++ snprintf (bufptr, buflen, "[cname=%s],%s",
++ entryval, tablename_val);
+ }
+- if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+- {
+- enum nss_status status = niserr2nss (result->status);
+
+- __set_errno (olderr);
++ nis_freeresult (result);
++ result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++ }
+
+- nis_freeresult (result);
+- return status;
+- }
++ if (result == NULL)
++ {
++ __set_errno (ENOMEM);
++ return NSS_STATUS_TRYAGAIN;
++ }
+
+- parse_res = _nss_nisplus_parse_protoent (result, proto, buffer, buflen,
+- errnop);
++ if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
++ {
++ enum nss_status status = niserr2nss (result->status);
++
++ __set_errno (olderr);
+
+ nis_freeresult (result);
++ return status;
++ }
+
+- if (parse_res < 1)
++ parse_res = _nss_nisplus_parse_protoent (result, proto, buffer, buflen,
++ errnop);
++
++ nis_freeresult (result);
++
++ if (parse_res < 1)
++ {
++ if (parse_res == -1)
+ {
+- if (parse_res == -1)
+- {
+- *errnop = ERANGE;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- else
+- {
+- __set_errno (olderr);
+- return NSS_STATUS_NOTFOUND;
+- }
++ *errnop = ERANGE;
++ return NSS_STATUS_TRYAGAIN;
++ }
++ else
++ {
++ __set_errno (olderr);
++ return NSS_STATUS_NOTFOUND;
+ }
+- return NSS_STATUS_SUCCESS;
+ }
++
++ return NSS_STATUS_SUCCESS;
+ }
+
+ enum nss_status
+@@ -358,55 +379,57 @@ _nss_nisplus_getprotobynumber_r (const i
+ {
+ if (tablename_val == NULL)
+ {
++ __libc_lock_lock (lock);
++
+ enum nss_status status = _nss_create_tablename (errnop);
+
++ __libc_lock_unlock (lock);
++
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+ }
+
+- {
+- int parse_res;
+- nis_result *result;
+- char buf[46 + tablename_len];
+- int olderr = errno;
+-
+- sprintf (buf, "[number=%d],%s", number, tablename_val);
+-
+- result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
+-
+- if (result == NULL)
+- {
+- __set_errno (ENOMEM);
+- return NSS_STATUS_TRYAGAIN;
+- }
+- if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+- {
+- enum nss_status status = niserr2nss (result->status);
++ char buf[12 + 3 * sizeof (number) + tablename_len];
++ int olderr = errno;
+
+- __set_errno (olderr);
++ snprintf (buf, sizeof (buf), "[number=%d],%s", number, tablename_val);
+
+- nis_freeresult (result);
+- return status;
+- }
++ nis_result *result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
+
+- parse_res = _nss_nisplus_parse_protoent (result, proto, buffer, buflen,
+- errnop);
++ if (result == NULL)
++ {
++ __set_errno (ENOMEM);
++ return NSS_STATUS_TRYAGAIN;
++ }
+
+- nis_freeresult (result);
++ if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
++ {
++ enum nss_status status = niserr2nss (result->status);
++
++ __set_errno (olderr);
++
++ nis_freeresult (result);
++ return status;
++ }
+
+- if (parse_res < 1)
+- {
+- if (parse_res == -1)
+- {
+- *errnop = ERANGE;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- else
+- {
+- __set_errno (olderr);
+- return NSS_STATUS_NOTFOUND;
+- }
+- }
+- return NSS_STATUS_SUCCESS;
+- }
++ int parse_res = _nss_nisplus_parse_protoent (result, proto, buffer, buflen,
++ errnop);
++
++ nis_freeresult (result);
++
++ if (parse_res < 1)
++ {
++ if (parse_res == -1)
++ {
++ *errnop = ERANGE;
++ return NSS_STATUS_TRYAGAIN;
++ }
++ else
++ {
++ __set_errno (olderr);
++ return NSS_STATUS_NOTFOUND;
++ }
++ }
++
++ return NSS_STATUS_SUCCESS;
+ }
+--- libc/nis/nss_nisplus/nisplus-publickey.c 25 Sep 2003 19:44:20 -0000 1.16
++++ libc/nis/nss_nisplus/nisplus-publickey.c 3 Dec 2005 22:08:17 -0000 1.17
+@@ -37,7 +37,7 @@ _nss_nisplus_getpublickey (const char *n
+ {
+ nis_result *res;
+ enum nss_status retval;
+- char buf[NIS_MAXNAMELEN+2];
++ char buf[NIS_MAXNAMELEN + 2];
+ size_t slen;
+ char *domain, *cptr;
+ int len;
+@@ -120,7 +120,7 @@ _nss_nisplus_getsecretkey (const char *n
+ {
+ nis_result *res;
+ enum nss_status retval;
+- char buf[NIS_MAXNAMELEN+2];
++ char buf[NIS_MAXNAMELEN + 2];
+ size_t slen;
+ char *domain, *cptr;
+ int len;
+@@ -154,7 +154,7 @@ _nss_nisplus_getsecretkey (const char *n
+ buf[slen] = '\0';
+ }
+
+- res = nis_list (buf, USE_DGRAM+NO_AUTHINFO+FOLLOW_LINKS+FOLLOW_PATH,
++ res = nis_list (buf, USE_DGRAM | NO_AUTHINFO | FOLLOW_LINKS | FOLLOW_PATH,
+ NULL, NULL);
+
+ if (res == NULL)
+@@ -242,9 +242,9 @@ _nss_nisplus_netname2user (char netname[
+ {
+ char *domain;
+ nis_result *res;
+- char sname[NIS_MAXNAMELEN+2]; /* search criteria + table name */
++ char sname[NIS_MAXNAMELEN + 2]; /* search criteria + table name */
+ size_t slen;
+- char principal[NIS_MAXNAMELEN+1];
++ char principal[NIS_MAXNAMELEN + 1];
+ int len;
+
+ /* 1. Get home domain of user. */
+@@ -255,10 +255,6 @@ _nss_nisplus_netname2user (char netname[
+ ++domain; /* skip '@' */
+
+ /* 2. Get user's nisplus principal name. */
+- if ((strlen (netname) + strlen (domain)+45) >
+- (size_t) NIS_MAXNAMELEN)
+- return NSS_STATUS_UNAVAIL;
+-
+ slen = snprintf (sname, NIS_MAXNAMELEN,
+ "[auth_name=%s,auth_type=DES],cred.org_dir.%s",
+ netname, domain);
+@@ -339,8 +335,9 @@ _nss_nisplus_netname2user (char netname[
+ return NSS_STATUS_UNAVAIL;
+ }
+
+- slen = sprintf (sname, "[cname=%s,auth_type=LOCAL],cred.org_dir.%s",
+- principal, domain);
++ slen = snprintf (sname, sizeof (sname),
++ "[cname=%s,auth_type=LOCAL],cred.org_dir.%s",
++ principal, domain);
+
+ if (sname[slen - 1] != '.')
+ {
+--- libc/nis/nss_nisplus/nisplus-pwd.c 25 Sep 2003 19:44:20 -0000 1.17
++++ libc/nis/nss_nisplus/nisplus-pwd.c 3 Dec 2005 20:39:34 -0000 1.20
+@@ -17,6 +17,7 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
++#include <atomic.h>
+ #include <nss.h>
+ #include <errno.h>
+ #include <pwd.h>
+@@ -30,27 +31,39 @@
+ __libc_lock_define_initialized (static, lock)
+
+ static nis_result *result;
+-static nis_name tablename_val;
+-static u_long tablename_len;
++nis_name pwd_tablename_val attribute_hidden;
++size_t pwd_tablename_len attribute_hidden;
+
+-static enum nss_status
+-_nss_create_tablename (int *errnop)
++enum nss_status
++_nss_pwd_create_tablename (int *errnop)
+ {
+- if (tablename_val == NULL)
++ if (pwd_tablename_val == NULL)
+ {
+- char buf [40 + strlen (nis_local_directory ())];
+- char *p;
++ const char *local_dir = nis_local_directory ();
++ size_t local_dir_len = strlen (local_dir);
++ static const char prefix[] = "passwd.org_dir.";
+
+- p = __stpcpy (buf, "passwd.org_dir.");
+- p = __stpcpy (p, nis_local_directory ());
+- tablename_val = __strdup (buf);
+- if (tablename_val == NULL)
++ char *p = malloc (sizeof (prefix) + local_dir_len);
++ if (p == NULL)
+ {
+ *errnop = errno;
+ return NSS_STATUS_TRYAGAIN;
+ }
+- tablename_len = strlen (tablename_val);
++
++ memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
++
++ pwd_tablename_len = sizeof (prefix) - 1 + local_dir_len;
++
++ atomic_write_barrier ();
++
++ if (atomic_compare_and_exchange_bool_acq (&pwd_tablename_val, p, NULL))
++ {
++ /* Another thread already installed the value. */
++ free (p);
++ pwd_tablename_len = strlen (pwd_tablename_val);
++ }
+ }
++
+ return NSS_STATUS_SUCCESS;
+ }
+
+@@ -59,16 +72,20 @@ enum nss_status
+ _nss_nisplus_setpwent (int stayopen)
+ {
+ enum nss_status status = NSS_STATUS_SUCCESS;
+- int err;
+
+ __libc_lock_lock (lock);
+
+- if (result)
+- nis_freeresult (result);
+- result = NULL;
++ if (result != NULL)
++ {
++ nis_freeresult (result);
++ result = NULL;
++ }
+
+- if (tablename_val == NULL)
+- status = _nss_create_tablename (&err);
++ if (pwd_tablename_val == NULL)
++ {
++ int err;
++ status = _nss_pwd_create_tablename (&err);
++ }
+
+ __libc_lock_unlock (lock);
+
+@@ -80,9 +97,11 @@ _nss_nisplus_endpwent (void)
+ {
+ __libc_lock_lock (lock);
+
+- if (result)
+- nis_freeresult (result);
+- result = NULL;
++ if (result != NULL)
++ {
++ nis_freeresult (result);
++ result = NULL;
++ }
+
+ __libc_lock_unlock (lock);
+
+@@ -103,25 +122,22 @@ internal_nisplus_getpwent_r (struct pass
+ if (result == NULL)
+ {
+ saved_res = NULL;
+- if (tablename_val == NULL)
++ if (pwd_tablename_val == NULL)
+ {
+- enum nss_status status = _nss_create_tablename (errnop);
++ enum nss_status status = _nss_pwd_create_tablename (errnop);
+
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+ }
+
+- result = nis_first_entry (tablename_val);
++ result = nis_first_entry (pwd_tablename_val);
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ return niserr2nss (result->status);
+ }
+ else
+ {
+- nis_result *res;
+-
+ saved_res = result;
+- res = nis_next_entry (tablename_val, &result->cookie);
+- result = res;
++ result = nis_next_entry (pwd_tablename_val, &result->cookie);
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ {
+ nis_freeresult (saved_res);
+@@ -131,19 +147,18 @@ internal_nisplus_getpwent_r (struct pass
+
+ parse_res = _nss_nisplus_parse_pwent (result, pw, buffer,
+ buflen, errnop);
+- if (parse_res == -1)
++ if (__builtin_expect (parse_res == -1, 0))
+ {
+ nis_freeresult (result);
+ result = saved_res;
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+- else
+- {
+- if (saved_res)
+- nis_freeresult (saved_res);
+- }
+- } while (!parse_res);
++
++ if (saved_res)
++ nis_freeresult (saved_res);
++ }
++ while (!parse_res);
+
+ return NSS_STATUS_SUCCESS;
+ }
+@@ -169,9 +184,9 @@ _nss_nisplus_getpwnam_r (const char *nam
+ {
+ int parse_res;
+
+- if (tablename_val == NULL)
++ if (pwd_tablename_val == NULL)
+ {
+- enum nss_status status = _nss_create_tablename (errnop);
++ enum nss_status status = _nss_pwd_create_tablename (errnop);
+
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+@@ -182,107 +197,107 @@ _nss_nisplus_getpwnam_r (const char *nam
+ *errnop = EINVAL;
+ return NSS_STATUS_UNAVAIL;
+ }
+- else
+- {
+- nis_result *result;
+- char buf[strlen (name) + 24 + tablename_len];
+- int olderr = errno;
+
+- sprintf (buf, "[name=%s],%s", name, tablename_val);
++ nis_result *result;
++ char buf[strlen (name) + 9 + pwd_tablename_len];
++ int olderr = errno;
+
+- result = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++ snprintf (buf, sizeof (buf), "[name=%s],%s", name, pwd_tablename_val);
+
+- if (result == NULL)
+- {
+- *errnop = ENOMEM;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+- {
+- enum nss_status status = niserr2nss (result->status);
++ result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+
+- __set_errno (olderr);
++ if (result == NULL)
++ {
++ *errnop = ENOMEM;
++ return NSS_STATUS_TRYAGAIN;
++ }
+
+- nis_freeresult (result);
+- return status;
+- }
++ if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
++ {
++ enum nss_status status = niserr2nss (result->status);
+
+- parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen,
+- errnop);
++ __set_errno (olderr);
+
+ nis_freeresult (result);
++ return status;
++ }
++
++ parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop);
++
++ nis_freeresult (result);
+
+- if (parse_res < 1)
++ if (__builtin_expect (parse_res < 1, 0))
++ {
++ if (parse_res == -1)
+ {
+- if (parse_res == -1)
+- {
+- *errnop = ERANGE;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- else
+- {
+- __set_errno (olderr);
+- return NSS_STATUS_NOTFOUND;
+- }
++ *errnop = ERANGE;
++ return NSS_STATUS_TRYAGAIN;
++ }
++ else
++ {
++ __set_errno (olderr);
++ return NSS_STATUS_NOTFOUND;
+ }
+- return NSS_STATUS_SUCCESS;
+ }
++
++ return NSS_STATUS_SUCCESS;
+ }
+
+ enum nss_status
+ _nss_nisplus_getpwuid_r (const uid_t uid, struct passwd *pw,
+ char *buffer, size_t buflen, int *errnop)
+ {
+- if (tablename_val == NULL)
++ if (pwd_tablename_val == NULL)
+ {
+- enum nss_status status = _nss_create_tablename (errnop);
++ enum nss_status status = _nss_pwd_create_tablename (errnop);
+
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+ }
+
+- {
+- int parse_res;
+- nis_result *result;
+- char buf[100 + tablename_len];
+- int olderr = errno;
+-
+- sprintf (buf, "[uid=%lu],%s", (unsigned long int) uid, tablename_val);
+-
+- result = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+-
+- if (result == NULL)
+- {
+- *errnop = ENOMEM;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+- {
+- enum nss_status status = niserr2nss (result->status);
++ int parse_res;
++ nis_result *result;
++ char buf[8 + 3 * sizeof (unsigned long int) + pwd_tablename_len];
++ int olderr = errno;
+
+- __set_errno (olderr);
++ snprintf (buf, sizeof (buf), "[uid=%lu],%s",
++ (unsigned long int) uid, pwd_tablename_val);
+
+- nis_freeresult (result);
+- return status;
+- }
++ result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++
++ if (result == NULL)
++ {
++ *errnop = ENOMEM;
++ return NSS_STATUS_TRYAGAIN;
++ }
+
+- parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop);
++ if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
++ {
++ enum nss_status status = niserr2nss (result->status);
++
++ __set_errno (olderr);
++
++ nis_freeresult (result);
++ return status;
++ }
+
+- nis_freeresult (result);
++ parse_res = _nss_nisplus_parse_pwent (result, pw, buffer, buflen, errnop);
+
+- if (parse_res < 1)
+- {
+- if (parse_res == -1)
+- {
+- *errnop = ERANGE;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- else
+- {
+- __set_errno (olderr);
+- return NSS_STATUS_NOTFOUND;
+- }
+- }
+- return NSS_STATUS_SUCCESS;
+- }
++ nis_freeresult (result);
++
++ if (__builtin_expect (parse_res < 1, 0))
++ {
++ if (parse_res == -1)
++ {
++ *errnop = ERANGE;
++ return NSS_STATUS_TRYAGAIN;
++ }
++ else
++ {
++ __set_errno (olderr);
++ return NSS_STATUS_NOTFOUND;
++ }
++ }
++
++ return NSS_STATUS_SUCCESS;
+ }
+--- libc/nis/nss_nisplus/nisplus-rpc.c 25 Sep 2003 19:44:20 -0000 1.19
++++ libc/nis/nss_nisplus/nisplus-rpc.c 3 Dec 2005 19:54:38 -0000 1.20
+@@ -17,13 +17,14 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+-#include <nss.h>
+-#include <errno.h>
++#include <atomic.h>
+ #include <ctype.h>
++#include <errno.h>
++#include <nss.h>
+ #include <string.h>
+-#include <bits/libc-lock.h>
+ #include <rpc/netdb.h>
+ #include <rpcsvc/nis.h>
++#include <bits/libc-lock.h>
+
+ #include "nss-nisplus.h"
+
+@@ -138,19 +139,26 @@ _nss_create_tablename (int *errnop)
+ {
+ if (tablename_val == NULL)
+ {
+- char buf [40 + strlen (nis_local_directory ())];
+- char *p;
++ const char *local_dir = nis_local_directory ();
++ size_t local_dir_len = strlen (local_dir);
++ static const char prefix[] = "rpc.org_dir.";
+
+- p = __stpcpy (buf, "rpc.org_dir.");
+- p = __stpcpy (p, nis_local_directory ());
+- tablename_val = __strdup (buf);
+- if (tablename_val == NULL)
++ char *p = malloc (sizeof (prefix) + local_dir_len);
++ if (p == NULL)
+ {
+ *errnop = errno;
+ return NSS_STATUS_TRYAGAIN;
+ }
+- tablename_len = strlen (tablename_val);
++
++ memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
++
++ tablename_len = sizeof (prefix) - 1 + local_dir_len;
++
++ atomic_write_barrier ();
++
++ tablename_val = p;
+ }
++
+ return NSS_STATUS_SUCCESS;
+ }
+
+@@ -159,16 +167,20 @@ enum nss_status
+ _nss_nisplus_setrpcent (int stayopen)
+ {
+ enum nss_status status = NSS_STATUS_SUCCESS;
+- int err;
+
+ __libc_lock_lock (lock);
+
+- if (result)
+- nis_freeresult (result);
+- result = NULL;
++ if (result != NULL)
++ {
++ nis_freeresult (result);
++ result = NULL;
++ }
+
+ if (tablename_val == NULL)
+- status = _nss_create_tablename (&err);
++ {
++ int err;
++ status = _nss_create_tablename (&err);
++ }
+
+ __libc_lock_unlock (lock);
+
+@@ -180,9 +192,11 @@ _nss_nisplus_endrpcent (void)
+ {
+ __libc_lock_lock (lock);
+
+- if (result)
+- nis_freeresult (result);
+- result = NULL;
++ if (result != NULL)
++ {
++ nis_freeresult (result);
++ result = NULL;
++ }
+
+ __libc_lock_unlock (lock);
+
+@@ -217,11 +231,8 @@ internal_nisplus_getrpcent_r (struct rpc
+ }
+ else
+ {
+- nis_result *res;
+-
+ saved_res = result;
+- res = nis_next_entry (tablename_val, &result->cookie);
+- result = res;
++ result = nis_next_entry (tablename_val, &result->cookie);
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ {
+ nis_freeresult (saved_res);
+@@ -243,7 +254,8 @@ internal_nisplus_getrpcent_r (struct rpc
+ if (saved_res)
+ nis_freeresult (saved_res);
+ }
+- } while (!parse_res);
++ }
++ while (!parse_res);
+
+ return NSS_STATUS_SUCCESS;
+ }
+@@ -271,77 +283,89 @@ _nss_nisplus_getrpcbyname_r (const char
+
+ if (tablename_val == NULL)
+ {
++ __libc_lock_lock (lock);
++
+ enum nss_status status = _nss_create_tablename (errnop);
+
++ __libc_lock_unlock (lock);
++
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+ }
+
+ if (name == NULL)
+ return NSS_STATUS_NOTFOUND;
+- else
+- {
+- nis_result *result;
+- char buf[strlen (name) + 255 + tablename_len];
+- int olderr = errno;
+-
+- /* Search at first in the alias list, and use the correct name
+- for the next search */
+- sprintf (buf, "[name=%s],%s", name, tablename_val);
+- result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+
+- if (result != NULL)
+- {
+- /* If we do not find it, try it as original name. But if the
+- database is correct, we should find it in the first case, too */
+- if ((result->status != NIS_SUCCESS
+- && result->status != NIS_S_SUCCESS)
+- || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
+- || strcmp (result->objects.objects_val->EN_data.en_type,
+- "rpc_tbl") != 0
+- || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3)
+- sprintf (buf, "[cname=%s],%s", name, tablename_val);
+- else
+- sprintf (buf, "[cname=%s],%s", NISENTRYVAL (0, 0, result),
+- tablename_val);
++ char buf[strlen (name) + 10 + tablename_len];
++ int olderr = errno;
+
+- nis_freeresult (result);
+- result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS , NULL, NULL);
+- }
++ /* Search at first in the alias list, and use the correct name
++ for the next search */
++ snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
++ nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+
+- if (result == NULL)
++ if (result != NULL)
++ {
++ char *bufptr = buf;
++
++ /* If we did not find it, try it as original name. But if the
++ database is correct, we should find it in the first case, too */
++ if ((result->status != NIS_SUCCESS
++ && result->status != NIS_S_SUCCESS)
++ || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
++ || strcmp (result->objects.objects_val->EN_data.en_type,
++ "rpc_tbl") != 0
++ || result->objects.objects_val->EN_data.en_cols.en_cols_len < 3)
++ snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val);
++ else
+ {
+- *errnop = ENOMEM;
+- return NSS_STATUS_TRYAGAIN;
++ /* We need to allocate a new buffer since there is no
++ guarantee the returned name has a length limit. */
++ const char *entryval = NISENTRYVAL (0, 0, result);
++ size_t buflen = strlen (entryval) + 10 + tablename_len;
++ bufptr = alloca (buflen);
++ snprintf (bufptr, buflen, "[cname=%s],%s",
++ entryval, tablename_val);
+ }
+- if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+- {
+- enum nss_status status = niserr2nss (result->status);
+
+- __set_errno (olderr);
++ nis_freeresult (result);
++ result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS , NULL, NULL);
++ }
+
+- nis_freeresult (result);
+- return status;
+- }
++ if (result == NULL)
++ {
++ *errnop = ENOMEM;
++ return NSS_STATUS_TRYAGAIN;
++ }
+
+- parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen,
+- errnop);
++ if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
++ {
++ enum nss_status status = niserr2nss (result->status);
++
++ __set_errno (olderr);
+
+ nis_freeresult (result);
++ return status;
++ }
+
+- if (parse_res < 1)
+- {
+- if (parse_res == -1)
+- {
+- *errnop = ERANGE;
+- return NSS_STATUS_TRYAGAIN;
+- }
++ parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen,
++ errnop);
+
+- __set_errno (olderr);
+- return NSS_STATUS_NOTFOUND;
++ nis_freeresult (result);
++
++ if (parse_res < 1)
++ {
++ if (parse_res == -1)
++ {
++ *errnop = ERANGE;
++ return NSS_STATUS_TRYAGAIN;
+ }
+- return NSS_STATUS_SUCCESS;
++
++ __set_errno (olderr);
++ return NSS_STATUS_NOTFOUND;
+ }
++
++ return NSS_STATUS_SUCCESS;
+ }
+
+ enum nss_status
+@@ -350,55 +374,57 @@ _nss_nisplus_getrpcbynumber_r (const int
+ {
+ if (tablename_val == NULL)
+ {
++ __libc_lock_lock (lock);
++
+ enum nss_status status = _nss_create_tablename (errnop);
+
++ __libc_lock_unlock (lock);
++
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+ }
+
+- {
+- int parse_res;
+- nis_result *result;
+- char buf[100 + tablename_len];
+- int olderr = errno;
+-
+- sprintf (buf, "[number=%d],%s", number, tablename_val);
+-
+- result = nis_list(buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
+-
+- if (result == NULL)
+- {
+- *errnop = ENOMEM;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+- {
+- enum nss_status status = niserr2nss (result->status);
++ char buf[12 + 3 * sizeof (number) + tablename_len];
++ int olderr = errno;
+
+- __set_errno (olderr);
++ snprintf (buf, sizeof (buf), "[number=%d],%s", number, tablename_val);
+
+- nis_freeresult (result);
+- return status;
+- }
++ nis_result *result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
++
++ if (result == NULL)
++ {
++ *errnop = ENOMEM;
++ return NSS_STATUS_TRYAGAIN;
++ }
++
++ if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
++ {
++ enum nss_status status = niserr2nss (result->status);
+
+- parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen,
+- errnop);
++ __set_errno (olderr);
++
++ nis_freeresult (result);
++ return status;
++ }
+
+- nis_freeresult (result);
++ int parse_res = _nss_nisplus_parse_rpcent (result, rpc, buffer, buflen,
++ errnop);
++
++ nis_freeresult (result);
++
++ if (parse_res < 1)
++ {
++ if (parse_res == -1)
++ {
++ *errnop = ERANGE;
++ return NSS_STATUS_TRYAGAIN;
++ }
++ else
++ {
++ __set_errno (olderr);
++ return NSS_STATUS_NOTFOUND;
++ }
++ }
+
+- if (parse_res < 1)
+- {
+- if (parse_res == -1)
+- {
+- *errnop = ERANGE;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- else
+- {
+- __set_errno (olderr);
+- return NSS_STATUS_NOTFOUND;
+- }
+- }
+- return NSS_STATUS_SUCCESS;
+- }
++ return NSS_STATUS_SUCCESS;
+ }
+--- libc/nis/nss_nisplus/nisplus-service.c 25 Sep 2003 19:44:20 -0000 1.21
++++ libc/nis/nss_nisplus/nisplus-service.c 3 Dec 2005 20:11:34 -0000 1.22
+@@ -17,13 +17,14 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+-#include <nss.h>
+-#include <errno.h>
++#include <atomic.h>
+ #include <ctype.h>
++#include <errno.h>
+ #include <netdb.h>
++#include <nss.h>
+ #include <string.h>
+-#include <bits/libc-lock.h>
+ #include <rpcsvc/nis.h>
++#include <bits/libc-lock.h>
+
+ #include "nss-nisplus.h"
+
+@@ -45,8 +46,6 @@ _nss_nisplus_parse_servent (nis_result *
+ {
+ char *first_unused = buffer;
+ size_t room_left = buflen;
+- unsigned int i;
+- char *p, *line;
+
+ if (result == NULL)
+ return 0;
+@@ -81,10 +80,10 @@ _nss_nisplus_parse_servent (nis_result *
+ first_unused += strlen (first_unused) + 1;
+
+ serv->s_port = htons (atoi (NISENTRYVAL (0, 3, result)));
+- p = first_unused;
++ char *p = first_unused;
+
+- line = p;
+- for (i = 0; i < result->objects.objects_len; ++i)
++ char *line = p;
++ for (unsigned int i = 0; i < result->objects.objects_len; ++i)
+ {
+ if (strcmp (NISENTRYVAL (i, 1, result), serv->s_name) != 0)
+ {
+@@ -110,7 +109,7 @@ _nss_nisplus_parse_servent (nis_result *
+ room_left -= (sizeof (char *));
+ serv->s_aliases[0] = NULL;
+
+- i = 0;
++ unsigned int i = 0;
+ while (*line != '\0')
+ {
+ /* Skip leading blanks. */
+@@ -147,19 +146,26 @@ _nss_create_tablename (int *errnop)
+ {
+ if (tablename_val == NULL)
+ {
+- char buf [40 + strlen (nis_local_directory ())];
+- char *p;
++ const char *local_dir = nis_local_directory ();
++ size_t local_dir_len = strlen (local_dir);
++ static const char prefix[] = "services.org_dir.";
+
+- p = __stpcpy (buf, "services.org_dir.");
+- p = __stpcpy (p, nis_local_directory ());
+- tablename_val = __strdup (buf);
+- if (tablename_val == NULL)
++ char *p = malloc (sizeof (prefix) + local_dir_len);
++ if (p == NULL)
+ {
+ *errnop = errno;
+ return NSS_STATUS_TRYAGAIN;
+ }
+- tablename_len = strlen (tablename_val);
++
++ memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
++
++ tablename_len = sizeof (prefix) - 1 + local_dir_len;
++
++ atomic_write_barrier ();
++
++ tablename_val = p;
+ }
++
+ return NSS_STATUS_SUCCESS;
+ }
+
+@@ -172,9 +178,11 @@ _nss_nisplus_setservent (int stayopen)
+
+ __libc_lock_lock (lock);
+
+- if (result)
+- nis_freeresult (result);
+- result = NULL;
++ if (result != NULL)
++ {
++ nis_freeresult (result);
++ result = NULL;
++ }
+
+ if (tablename_val == NULL)
+ status = _nss_create_tablename (&err);
+@@ -189,9 +197,11 @@ _nss_nisplus_endservent (void)
+ {
+ __libc_lock_lock (lock);
+
+- if (result)
+- nis_freeresult (result);
+- result = NULL;
++ if (result != NULL)
++ {
++ nis_freeresult (result);
++ result = NULL;
++ }
+
+ __libc_lock_unlock (lock);
+
+@@ -226,11 +236,8 @@ internal_nisplus_getservent_r (struct se
+ }
+ else
+ {
+- nis_result *res;
+-
+ saved_res = result;
+- res = nis_next_entry (tablename_val, &result->cookie);
+- result = res;
++ result = nis_next_entry (tablename_val, &result->cookie);
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ {
+ nis_freeresult (saved_res);
+@@ -240,7 +247,7 @@ internal_nisplus_getservent_r (struct se
+
+ parse_res = _nss_nisplus_parse_servent (result, serv, buffer,
+ buflen, errnop);
+- if (parse_res == -1)
++ if (__builtin_expect (parse_res == -1, 0))
+ {
+ nis_freeresult (result);
+ result = saved_res;
+@@ -262,11 +269,9 @@ enum nss_status
+ _nss_nisplus_getservent_r (struct servent *result, char *buffer,
+ size_t buflen, int *errnop)
+ {
+- int status;
+-
+ __libc_lock_lock (lock);
+
+- status = internal_nisplus_getservent_r (result, buffer, buflen, errnop);
++ int status = internal_nisplus_getservent_r (result, buffer, buflen, errnop);
+
+ __libc_lock_unlock (lock);
+
+@@ -278,12 +283,14 @@ _nss_nisplus_getservbyname_r (const char
+ struct servent *serv,
+ char *buffer, size_t buflen, int *errnop)
+ {
+- int parse_res;
+-
+ if (tablename_val == NULL)
+ {
++ __libc_lock_lock (lock);
++
+ enum nss_status status = _nss_create_tablename (errnop);
+
++ __libc_lock_unlock (lock);
++
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+ }
+@@ -293,72 +300,82 @@ _nss_nisplus_getservbyname_r (const char
+ *errnop = EINVAL;
+ return NSS_STATUS_NOTFOUND;
+ }
+- else
+- {
+- nis_result *result;
+- char buf[strlen (name) + 255 + tablename_len];
+- int olderr = errno;
+-
+- /* Search at first in the alias list, and use the correct name
+- for the next search */
+- sprintf (buf, "[name=%s,proto=%s],%s", name, protocol,
+- tablename_val);
+- result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+
+- if (result != NULL)
++ size_t protocol_len = strlen (protocol);
++ char buf[strlen (name) + protocol_len + 17 + tablename_len];
++ int olderr = errno;
++
++ /* Search at first in the alias list, and use the correct name
++ for the next search */
++ snprintf (buf, sizeof (buf), "[name=%s,proto=%s],%s", name, protocol,
++ tablename_val);
++ nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++
++ if (result != NULL)
++ {
++ char *bufptr = buf;
++
++ /* If we did not find it, try it as original name. But if the
++ database is correct, we should find it in the first case, too */
++ if ((result->status != NIS_SUCCESS
++ && result->status != NIS_S_SUCCESS)
++ || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
++ || strcmp (result->objects.objects_val->EN_data.en_type,
++ "services_tbl") != 0
++ || result->objects.objects_val->EN_data.en_cols.en_cols_len < 4)
++ snprintf (buf, sizeof (buf), "[cname=%s,proto=%s],%s", name, protocol,
++ tablename_val);
++ else
+ {
+- /* If we do not find it, try it as original name. But if the
+- database is correct, we should find it in the first case, too */
+- if ((result->status != NIS_SUCCESS
+- && result->status != NIS_S_SUCCESS)
+- || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
+- || strcmp (result->objects.objects_val->EN_data.en_type,
+- "services_tbl") != 0
+- || result->objects.objects_val->EN_data.en_cols.en_cols_len < 4)
+- sprintf (buf, "[cname=%s,proto=%s],%s", name, protocol,
+- tablename_val);
+- else
+- sprintf (buf, "[cname=%s,proto=%s],%s",
+- NISENTRYVAL (0, 0, result), protocol, tablename_val);
+-
+- nis_freeresult (result);
+- result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++ /* We need to allocate a new buffer since there is no
++ guarantee the returned name has a length limit. */
++ const char *entryval = NISENTRYVAL(0, 0, result);
++ size_t buflen = (strlen (entryval) + protocol_len + 17
++ + tablename_len);
++ bufptr = alloca (buflen);
++ snprintf (bufptr, buflen, "[cname=%s,proto=%s],%s",
++ entryval, protocol, tablename_val);
+ }
+
+- if (result == NULL)
+- {
+- *errnop = ENOMEM;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+- {
+- enum nss_status status = niserr2nss (result->status);
++ nis_freeresult (result);
++ result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++ }
+
+- __set_errno (olderr);
++ if (result == NULL)
++ {
++ *errnop = ENOMEM;
++ return NSS_STATUS_TRYAGAIN;
++ }
+
+- nis_freeresult (result);
+- return status;
+- }
++ if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
++ {
++ enum nss_status status = niserr2nss (result->status);
++
++ __set_errno (olderr);
+
+- parse_res = _nss_nisplus_parse_servent (result, serv, buffer, buflen,
+- errnop);
+ nis_freeresult (result);
++ return status;
++ }
+
+- if (parse_res < 1)
++ int parse_res = _nss_nisplus_parse_servent (result, serv, buffer, buflen,
++ errnop);
++ nis_freeresult (result);
++
++ if (__builtin_expect (parse_res < 1, 0))
++ {
++ if (parse_res == -1)
+ {
+- if (parse_res == -1)
+- {
+- *errnop = ERANGE;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- else
+- {
+- __set_errno (olderr);
+- return NSS_STATUS_NOTFOUND;
+- }
++ *errnop = ERANGE;
++ return NSS_STATUS_TRYAGAIN;
++ }
++ else
++ {
++ __set_errno (olderr);
++ return NSS_STATUS_NOTFOUND;
+ }
+- return NSS_STATUS_SUCCESS;
+ }
++
++ return NSS_STATUS_SUCCESS;
+ }
+
+ enum nss_status
+@@ -368,8 +385,12 @@ _nss_nisplus_getservbyport_r (const int
+ {
+ if (tablename_val == NULL)
+ {
++ __libc_lock_lock (lock);
++
+ enum nss_status status = _nss_create_tablename (errnop);
+
++ __libc_lock_unlock (lock);
++
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+ }
+@@ -379,50 +400,48 @@ _nss_nisplus_getservbyport_r (const int
+ *errnop = EINVAL;
+ return NSS_STATUS_NOTFOUND;
+ }
+- else
+- {
+- int parse_res;
+- nis_result *result;
+- char buf[60 + strlen (protocol) + tablename_len];
+- int olderr = errno;
+
+- sprintf (buf, "[port=%d,proto=%s],%s",
+- number, protocol, tablename_val);
++ char buf[17 + 3 * sizeof (int) + strlen (protocol) + tablename_len];
++ int olderr = errno;
+
+- result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++ snprintf (buf, sizeof (buf), "[port=%d,proto=%s],%s",
++ number, protocol, tablename_val);
+
+- if (result == NULL)
+- {
+- *errnop = ENOMEM;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+- {
+- enum nss_status status = niserr2nss (result->status);
++ nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+
+- __set_errno (olderr);
++ if (result == NULL)
++ {
++ *errnop = ENOMEM;
++ return NSS_STATUS_TRYAGAIN;
++ }
+
+- nis_freeresult (result);
+- return status;
+- }
++ if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
++ {
++ enum nss_status status = niserr2nss (result->status);
++
++ __set_errno (olderr);
+
+- parse_res = _nss_nisplus_parse_servent (result, serv, buffer, buflen,
+- errnop);
+ nis_freeresult (result);
++ return status;
++ }
++
++ int parse_res = _nss_nisplus_parse_servent (result, serv, buffer, buflen,
++ errnop);
++ nis_freeresult (result);
+
+- if (parse_res < 1)
++ if (__builtin_expect (parse_res < 1, 0))
++ {
++ if (parse_res == -1)
+ {
+- if (parse_res == -1)
+- {
+- *errnop = ERANGE;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- else
+- {
+- __set_errno (olderr);
+- return NSS_STATUS_NOTFOUND;
+- }
++ *errnop = ERANGE;
++ return NSS_STATUS_TRYAGAIN;
++ }
++ else
++ {
++ __set_errno (olderr);
++ return NSS_STATUS_NOTFOUND;
+ }
+- return NSS_STATUS_SUCCESS;
+ }
++
++ return NSS_STATUS_SUCCESS;
+ }
+--- libc/nis/nss_nisplus/nisplus-spwd.c 25 Sep 2003 19:44:20 -0000 1.17
++++ libc/nis/nss_nisplus/nisplus-spwd.c 3 Dec 2005 20:38:57 -0000 1.19
+@@ -30,29 +30,12 @@
+ __libc_lock_define_initialized (static, lock)
+
+ static nis_result *result;
+-static nis_name tablename_val;
+-static u_long tablename_len;
+
+-static enum nss_status
+-_nss_create_tablename (int *errnop)
+-{
+- if (tablename_val == NULL)
+- {
+- char buf [40 + strlen (nis_local_directory ())];
+- char *p;
++/* Defined in nisplus-pwd.c. */
++extern nis_name pwd_tablename_val attribute_hidden;
++extern size_t pwd_tablename_len attribute_hidden;
++extern enum nss_status _nss_pwd_create_tablename (int *errnop);
+
+- p = __stpcpy (buf, "passwd.org_dir.");
+- p = __stpcpy (p, nis_local_directory ());
+- tablename_val = __strdup (buf);
+- if (tablename_val == NULL)
+- {
+- *errnop = errno;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- tablename_len = strlen (tablename_val);
+- }
+- return NSS_STATUS_SUCCESS;
+-}
+
+ enum nss_status
+ _nss_nisplus_setspent (int stayopen)
+@@ -62,12 +45,14 @@ _nss_nisplus_setspent (int stayopen)
+
+ __libc_lock_lock (lock);
+
+- if (result)
+- nis_freeresult (result);
+- result = NULL;
++ if (result != NULL)
++ {
++ nis_freeresult (result);
++ result = NULL;
++ }
+
+- if (tablename_val == NULL)
+- status = _nss_create_tablename (&err);
++ if (pwd_tablename_val == NULL)
++ status = _nss_pwd_create_tablename (&err);
+
+ __libc_lock_unlock (lock);
+
+@@ -79,9 +64,11 @@ _nss_nisplus_endspent (void)
+ {
+ __libc_lock_lock (lock);
+
+- if (result)
+- nis_freeresult (result);
+- result = NULL;
++ if (result != NULL)
++ {
++ nis_freeresult (result);
++ result = NULL;
++ }
+
+ __libc_lock_unlock (lock);
+
+@@ -103,25 +90,22 @@ internal_nisplus_getspent_r (struct spwd
+ {
+ saved_res = NULL;
+
+- if (tablename_val == NULL)
++ if (pwd_tablename_val == NULL)
+ {
+- enum nss_status status = _nss_create_tablename (errnop);
++ enum nss_status status = _nss_pwd_create_tablename (errnop);
+
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+ }
+
+- result = nis_first_entry (tablename_val);
++ result = nis_first_entry (pwd_tablename_val);
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ return niserr2nss (result->status);
+ }
+ else
+ {
+- nis_result *res;
+-
+ saved_res = result;
+- res = nis_next_entry (tablename_val, &result->cookie);
+- result = res;
++ result = nis_next_entry (pwd_tablename_val, &result->cookie);
+ if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+ {
+ nis_freeresult (saved_res);
+@@ -131,19 +115,18 @@ internal_nisplus_getspent_r (struct spwd
+
+ parse_res = _nss_nisplus_parse_spent (result, sp, buffer,
+ buflen, errnop);
+- if (parse_res == -1)
++ if (__builtin_expect (parse_res == -1, 0))
+ {
+ nis_freeresult (result);
+ result = saved_res;
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+- else
+- {
+- if (saved_res)
+- nis_freeresult (saved_res);
+- }
+- } while (!parse_res);
++
++ if (saved_res != NULL)
++ nis_freeresult (saved_res);
++ }
++ while (!parse_res);
+
+ return NSS_STATUS_SUCCESS;
+ }
+@@ -169,9 +152,9 @@ _nss_nisplus_getspnam_r (const char *nam
+ {
+ int parse_res;
+
+- if (tablename_val == NULL)
++ if (pwd_tablename_val == NULL)
+ {
+- enum nss_status status = _nss_create_tablename (errnop);
++ enum nss_status status = _nss_pwd_create_tablename (errnop);
+
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+@@ -182,48 +165,47 @@ _nss_nisplus_getspnam_r (const char *nam
+ *errnop = EINVAL;
+ return NSS_STATUS_NOTFOUND;
+ }
+- else
+- {
+- nis_result *result;
+- char buf[strlen (name) + 24 + tablename_len];
+- int olderr = errno;
+
+- sprintf (buf, "[name=%s],%s", name, tablename_val);
++ nis_result *result;
++ char buf[strlen (name) + 9 + pwd_tablename_len];
++ int olderr = errno;
+
+- result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++ snprintf (buf, sizeof (buf), "[name=%s],%s", name, pwd_tablename_val);
+
+- if (result == NULL)
+- {
+- *errnop = ENOMEM;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
+- {
+- enum nss_status status = niserr2nss (result->status);
++ result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+
+- __set_errno (olderr);
++ if (result == NULL)
++ {
++ *errnop = ENOMEM;
++ return NSS_STATUS_TRYAGAIN;
++ }
+
+- nis_freeresult (result);
+- return status;
+- }
++ if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
++ {
++ enum nss_status status = niserr2nss (result->status);
++
++ __set_errno (olderr);
+
+- parse_res = _nss_nisplus_parse_spent (result, sp, buffer, buflen,
+- errnop);
+ nis_freeresult (result);
++ return status;
++ }
+
+- if (parse_res < 1)
++ parse_res = _nss_nisplus_parse_spent (result, sp, buffer, buflen, errnop);
++ nis_freeresult (result);
++
++ if (__builtin_expect (parse_res < 1, 0))
++ {
++ if (parse_res == -1)
+ {
+- if (parse_res == -1)
+- {
+- *errnop = ERANGE;
+- return NSS_STATUS_TRYAGAIN;
+- }
+- else
+- {
+- __set_errno (olderr);
+- return NSS_STATUS_NOTFOUND;
+- }
++ *errnop = ERANGE;
++ return NSS_STATUS_TRYAGAIN;
++ }
++ else
++ {
++ __set_errno (olderr);
++ return NSS_STATUS_NOTFOUND;
+ }
+- return NSS_STATUS_SUCCESS;
+ }
++
++ return NSS_STATUS_SUCCESS;
+ }
+--- libc/sunrpc/auth_des.c 17 Feb 2005 01:16:50 -0000 1.11
++++ libc/sunrpc/auth_des.c 7 Dec 2005 04:10:51 -0000 1.12
+@@ -174,7 +174,7 @@ authdes_pk_create (const char *servernam
+ if (key_gendes (&auth->ah_key) < 0)
+ {
+ debug ("authdes_create: unable to gen conversation key");
+- return NULL;
++ goto failed;
+ }
+ }
+ else
--- /dev/null
+2007-01-13 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nss_nis/nis-service.c (_nss_nis_getservbyname_r): Correct
+ computation of keylen.
+
+--- libc/nis/nss_nis/nis-service.c 19 Aug 2006 18:36:25 -0000 1.36
++++ libc/nis/nss_nis/nis-service.c 14 Jan 2007 04:30:39 -0000 1.37
+@@ -271,7 +271,7 @@ _nss_nis_getservbyname_r (const char *na
+
+ /* If the protocol is given, we could try if our NIS server knows
+ about services.byservicename map. If yes, we only need one query. */
+- size_t keylen = strlen (name) + 1 + (protocol ? strlen (protocol) : 0);
++ size_t keylen = strlen (name) + (protocol ? 1 + strlen (protocol) : 0);
+ char key[keylen + 1];
+
+ /* key is: "name/proto" */
--- /dev/null
+2005-10-28 Thorsten Kukuk <kukuk@suse.de>
+
+ * nis/nss_nis/nis-publickey.c (_nss_nis_getpublickey): Fix off
+ by one error.
+
+--- libc/nis/nss_nis/nis-publickey.c 26 Aug 2002 06:20:04 -0000 1.13
++++ libc/nis/nss_nis/nis-publickey.c 28 Oct 2005 22:38:59 -0000 1.14
+@@ -120,7 +120,7 @@ _nss_nis_getsecretkey (const char *netna
+
+ ++p;
+ strncpy (buf, p, 2 * (HEXKEYBYTES + 1));
+- buf[2 * (HEXKEYBYTES + 1)] = '\0';
++ buf[2 * HEXKEYBYTES + 1] = '\0';
+ if (!xdecrypt (buf, passwd))
+ return NSS_STATUS_SUCCESS;
+
--- /dev/null
+2005-08-15 Jakub Jelinek <jakub@redhat.com>
+
+ * nis/nis_subr.c (nis_leaf_of_r): Handle buflen == 0 correctly.
+
+--- libc/nis/nis_subr.c 30 Jul 2005 19:36:23 -0000 1.13
++++ libc/nis/nis_subr.c 16 Aug 2005 15:59:46 -0000 1.14
+@@ -39,7 +39,7 @@ nis_leaf_of_r (const_nis_name name, char
+ while (name[i] != '.' && name[i] != '\0')
+ i++;
+
+- if (i > buflen - 1)
++ if (i >= buflen)
+ {
+ __set_errno (ERANGE);
+ return NULL;
--- /dev/null
+2007-05-10 Ulrich Drepper <drepper@redhat.com>
+
+ * include/sys/cdefs.h: Redefine __nonnull so that test for
+ incorrect parameters in the libc code itself are not omitted.
+
+--- libc/include/sys/cdefs.h 18 Oct 2004 04:17:15 -0000 1.2
++++ libc/include/sys/cdefs.h 10 May 2007 20:15:11 -0000 1.3
+@@ -2,6 +2,12 @@
+
+ #include <misc/sys/cdefs.h>
+
++/* The compiler will optimize based on the knowledge the parameter is
++ not NULL. This will omit tests. A robust implementation cannot allow
++ this so when compiling glibc itself we ignore this attribute. */
++#undef __nonnull
++#define __nonnull(params)
++
+ extern void __chk_fail (void) __attribute__ ((__noreturn__));
+ libc_hidden_proto (__chk_fail)
+ rtld_hidden_proto (__chk_fail)
--- /dev/null
+2005-11-17 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/pthread/unwind-forcedunwind.c (pthread_cancel_init): Put
+ a write barrier before writing libgcc_s_getcfa.
+
+--- libc/nptl/sysdeps/pthread/unwind-forcedunwind.c 4 Sep 2003 05:41:57 -0000 1.1
++++ libc/nptl/sysdeps/pthread/unwind-forcedunwind.c 16 Nov 2005 23:31:28 -0000 1.2
+@@ -56,6 +56,10 @@ pthread_cancel_init (void)
+ libgcc_s_resume = resume;
+ libgcc_s_personality = personality;
+ libgcc_s_forcedunwind = forcedunwind;
++ /* Make sure libgcc_s_getcfa is written last. Otherwise,
++ pthread_cancel_init might return early even when the pointer the
++ caller is interested in is not initialized yet. */
++ atomic_write_barrier ();
+ libgcc_s_getcfa = getcfa;
+ }
+
--- /dev/null
+--- libc/sysdeps/unix/sysv/linux/dl-osinfo.h.jj 2002-12-10 09:09:24.000000000 -0500
++++ libc/sysdeps/unix/sysv/linux/dl-osinfo.h 2003-05-20 17:05:37.000000000 -0400
+@@ -22,6 +22,7 @@
+ #include <sys/sysctl.h>
+ #include <sys/utsname.h>
+ #include "kernel-features.h"
++#include <sysdep.h>
+
+ #ifndef MIN
+ # define MIN(a,b) (((a)<(b))?(a):(b))
+@@ -37,8 +38,29 @@ dl_fatal (const char *str)
+ _dl_dprintf (2, str);
+ _exit (1);
+ }
+-#endif
+
++static inline void
++__attribute__ ((always_inline))
++dl_redhat_nptl_check (const char *cp)
++{
++ cp = strchr (cp, 'n');
++ if (__builtin_expect (cp == NULL || cp[1] != 'p'
++ || cp[2] != 't' || cp[3] != 'l', 0)
++ && GLRO(dl_osversion) < 0x20545
++ && GLRO(dl_osversion) > 0x20413)
++ {
++#ifdef __NR_set_tid_address
++ INTERNAL_SYSCALL_DECL (err);
++ int ret;
++ ret = INTERNAL_SYSCALL (set_tid_address, err, 1, NULL);
++ if (INTERNAL_SYSCALL_ERROR_P (ret, err))
++#endif
++ GLRO(dl_osversion) = 0x20413;
++ }
++}
++#else
++#define dl_redhat_nptl_check(cp)
++#endif
+
+ #define DL_SYSDEP_OSCHECK(FATAL) \
+ do { \
+@@ -105,5 +127,6 @@ dl_fatal (const char *str)
+ FATAL ("FATAL: kernel too old\n"); \
+ \
+ GLRO(dl_osversion) = version; \
++ dl_redhat_nptl_check (cp); \
+ } \
+ } while (0)
--- /dev/null
+2006-04-08 Ulrich Drepper <drepper@redhat.com>
+
+ * init.c (sigcancel_handler): Compare with correct PID even if the
+ thread is in the middle of a fork call.
+ (sighandler_setxid): Likewise.
+ Reported by Suzuki K P <suzuki@in.ibm.com> .
+
+--- libc/nptl/init.c 28 Mar 2006 04:15:08 -0000 1.57
++++ libc/nptl/init.c 8 Apr 2006 20:26:31 -0000 1.58
+@@ -148,6 +148,14 @@ static const struct pthread_functions pt
+ static void
+ sigcancel_handler (int sig, siginfo_t *si, void *ctx)
+ {
++#ifdef __ASSUME_CORRECT_SI_PID
++ /* Determine the process ID. It might be negative if the thread is
++ in the middle of a fork() call. */
++ pid_t pid = THREAD_GETMEM (THREAD_SELF, pid);
++ if (__builtin_expect (pid < 0, 0))
++ pid = -pid;
++#endif
++
+ /* Safety check. It would be possible to call this function for
+ other signals and send a signal from another process. This is not
+ correct and might even be a security problem. Try to catch as
+@@ -156,7 +164,7 @@ sigcancel_handler (int sig, siginfo_t *s
+ #ifdef __ASSUME_CORRECT_SI_PID
+ /* Kernels before 2.5.75 stored the thread ID and not the process
+ ID in si_pid so we skip this test. */
+- || si->si_pid != THREAD_GETMEM (THREAD_SELF, pid)
++ || si->si_pid != pid
+ #endif
+ || si->si_code != SI_TKILL)
+ return;
+@@ -201,6 +209,14 @@ struct xid_command *__xidcmd attribute_h
+ static void
+ sighandler_setxid (int sig, siginfo_t *si, void *ctx)
+ {
++#ifdef __ASSUME_CORRECT_SI_PID
++ /* Determine the process ID. It might be negative if the thread is
++ in the middle of a fork() call. */
++ pid_t pid = THREAD_GETMEM (THREAD_SELF, pid);
++ if (__builtin_expect (pid < 0, 0))
++ pid = -pid;
++#endif
++
+ /* Safety check. It would be possible to call this function for
+ other signals and send a signal from another process. This is not
+ correct and might even be a security problem. Try to catch as
+@@ -209,7 +225,7 @@ sighandler_setxid (int sig, siginfo_t *s
+ #ifdef __ASSUME_CORRECT_SI_PID
+ /* Kernels before 2.5.75 stored the thread ID and not the process
+ ID in si_pid so we skip this test. */
+- || si->si_pid != THREAD_GETMEM (THREAD_SELF, pid)
++ || si->si_pid != pid
+ #endif
+ || si->si_code != SI_TKILL)
+ return;
--- /dev/null
+2006-07-31 Daniel Jacobowitz <dan@codesourcery.com>
+
+ * allocatestack.c (__reclaim_stacks): Reset the PID on cached stacks.
+ * Makefile (tests): Add tst-getpid3.
+ * tst-getpid3.c: New file.
+
+--- libc/nptl/Makefile 31 Jul 2006 05:58:25 -0000 1.182
++++ libc/nptl/Makefile 1 Aug 2006 06:05:02 -0000 1.183
+@@ -256,7 +256,7 @@ tests = tst-typesizes \
+ tst-backtrace1 \
+ tst-oddstacklimit \
+ tst-vfork1 tst-vfork2 tst-vfork1x tst-vfork2x \
+- tst-getpid1 tst-getpid2 \
++ tst-getpid1 tst-getpid2 tst-getpid3 \
+ tst-initializers1 $(patsubst %,tst-initializers1-%,c89 gnu89 c99 gnu99)
+ xtests = tst-setuid1 tst-setuid1-static
+
+--- libc/nptl/allocatestack.c 28 Mar 2006 04:14:00 -0000 1.62
++++ libc/nptl/allocatestack.c 1 Aug 2006 06:04:42 -0000 1.63
+@@ -758,6 +756,13 @@ __reclaim_stacks (void)
+ }
+ }
+
++ /* Reset the PIDs in any cached stacks. */
++ list_for_each (runp, &stack_cache)
++ {
++ struct pthread *curp = list_entry (runp, struct pthread, list);
++ curp->pid = self->pid;
++ }
++
+ /* Add the stack of all running threads to the cache. */
+ list_splice (&stack_used, &stack_cache);
+
+--- libc/nptl/tst-getpid3.c 1 Jan 1970 00:00:00 -0000
++++ libc/nptl/tst-getpid3.c 1 Aug 2006 06:04:02 -0000 1.1
+@@ -0,0 +1,114 @@
++#include <errno.h>
++#include <pthread.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include <sys/wait.h>
++
++
++static pid_t pid;
++
++static void *
++pid_thread (void *arg)
++{
++ if (pid != getpid ())
++ {
++ printf ("pid wrong in thread: should be %d, is %d\n",
++ (int) pid, (int) getpid ());
++ return (void *) 1L;
++ }
++
++ return NULL;
++}
++
++static int
++do_test (void)
++{
++ pid = getpid ();
++
++ pthread_t thr;
++ int ret = pthread_create (&thr, NULL, pid_thread, NULL);
++ if (ret)
++ {
++ printf ("pthread_create failed: %d\n", ret);
++ return 1;
++ }
++
++ void *thr_ret;
++ ret = pthread_join (thr, &thr_ret);
++ if (ret)
++ {
++ printf ("pthread_create failed: %d\n", ret);
++ return 1;
++ }
++ else if (thr_ret)
++ {
++ printf ("thread getpid failed\n");
++ return 1;
++ }
++
++ pid_t child = fork ();
++ if (child == -1)
++ {
++ printf ("fork failed: %m\n");
++ return 1;
++ }
++ else if (child == 0)
++ {
++ if (pid == getpid ())
++ {
++ puts ("pid did not change after fork");
++ exit (1);
++ }
++
++ pid = getpid ();
++ ret = pthread_create (&thr, NULL, pid_thread, NULL);
++ if (ret)
++ {
++ printf ("pthread_create failed: %d\n", ret);
++ return 1;
++ }
++
++ ret = pthread_join (thr, &thr_ret);
++ if (ret)
++ {
++ printf ("pthread_create failed: %d\n", ret);
++ return 1;
++ }
++ else if (thr_ret)
++ {
++ printf ("thread getpid failed\n");
++ return 1;
++ }
++
++ return 0;
++ }
++
++ int status;
++ if (TEMP_FAILURE_RETRY (waitpid (child, &status, 0)) != child)
++ {
++ puts ("waitpid failed");
++ kill (child, SIGKILL);
++ return 1;
++ }
++
++ if (!WIFEXITED (status))
++ {
++ if (WIFSIGNALED (status))
++ printf ("died from signal %s\n", strsignal (WTERMSIG (status)));
++ else
++ puts ("did not terminate correctly");
++ return 1;
++ }
++ if (WEXITSTATUS (status) != 0)
++ {
++ printf ("exit code %d\n", WEXITSTATUS (status));
++ return 1;
++ }
++
++ return 0;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
--- /dev/null
+2006-02-08 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/unix/sysv/linux/i386/lowlevellock.h (lll_futex_wait,
+ lll_wait_tid): Add "memory" clobber.
+
+--- libc/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h.jj 2004-03-24 01:35:18.000000000 -0500
++++ libc/nptl/sysdeps/unix/sysv/linux/i386/lowlevellock.h 2004-03-24 01:35:18.000000000 -0500
+@@ -75,7 +75,8 @@
+ : "=a" (__ignore) \
+ : "0" (SYS_futex), LLL_EBX_REG (futex), "S" (0), \
+ "c" (FUTEX_WAIT), "d" (_val), \
+- "i" (offsetof (tcbhead_t, sysinfo))); \
++ "i" (offsetof (tcbhead_t, sysinfo)) \
++ : "memory"); \
+ } while (0)
+
+
+@@ -330,7 +331,8 @@ extern int lll_unlock_wake_cb (int *__fu
+ : "=&a" (__ignore) \
+ : "i" (SYS_futex), LLL_EBX_REG (&tid), "S" (0), \
+ "c" (FUTEX_WAIT), "d" (_tid), \
+- "i" (offsetof (tcbhead_t, sysinfo))); \
++ "i" (offsetof (tcbhead_t, sysinfo)) \
++ : "memory"); \
+ } while (0)
+
+ extern int __lll_timedwait_tid (int *tid, const struct timespec *abstime)
--- /dev/null
+2006-09-27 Daniel Jacobowitz <dan@codesourcery.com>
+
+ [BZ #3270]
+ * allocatestack.c (setxid_mark_thread, setxid_unmark_thread): New.
+ (setxid_signal_thread): Return a successful signal indicator. Just
+ skip threads without SETXID_BITMASK.
+ (__nptl_setxid): Perform the operation in multiple
+ steps to avoid races with creation and terminations.
+ * init.c (sighandler_setxid): Adjust.
+
+diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
+index 67ea0c6..3c3585f 100644
+--- a/nptl/allocatestack.c
++++ b/nptl/allocatestack.c
+@@ -965,22 +965,53 @@ __find_thread_by_id (pid_t tid)
+
+ static void
+ internal_function
+-setxid_signal_thread (struct xid_command *cmdp, struct pthread *t)
++setxid_mark_thread (struct xid_command *cmdp, struct pthread *t)
+ {
+- if (! IS_DETACHED (t))
++ int ch;
++
++ /* Don't let the thread exit before the setxid handler runs. */
++ t->setxid_futex = 0;
++
++ do
+ {
+- int ch;
+- do
+- {
+- ch = t->cancelhandling;
++ ch = t->cancelhandling;
+
+- /* If the thread is exiting right now, ignore it. */
+- if ((ch & EXITING_BITMASK) != 0)
+- return;
+- }
+- while (atomic_compare_and_exchange_bool_acq (&t->cancelhandling,
+- ch | SETXID_BITMASK, ch));
++ /* If the thread is exiting right now, ignore it. */
++ if ((ch & EXITING_BITMASK) != 0)
++ return;
+ }
++ while (atomic_compare_and_exchange_bool_acq (&t->cancelhandling,
++ ch | SETXID_BITMASK, ch));
++}
++
++
++static void
++internal_function
++setxid_unmark_thread (struct xid_command *cmdp, struct pthread *t)
++{
++ int ch;
++
++ do
++ {
++ ch = t->cancelhandling;
++ if ((ch & SETXID_BITMASK) == 0)
++ return;
++ }
++ while (atomic_compare_and_exchange_bool_acq (&t->cancelhandling,
++ ch & ~SETXID_BITMASK, ch));
++
++ /* Release the futex just in case. */
++ t->setxid_futex = 1;
++ lll_futex_wake (&t->setxid_futex, 1);
++}
++
++
++static int
++internal_function
++setxid_signal_thread (struct xid_command *cmdp, struct pthread *t)
++{
++ if ((t->cancelhandling & SETXID_BITMASK) == 0)
++ return 0;
+
+ int val;
+ INTERNAL_SYSCALL_DECL (err);
+@@ -997,8 +1028,14 @@ setxid_signal_thread (struct xid_command *cmdp, struct pthread *t)
+ val = INTERNAL_SYSCALL (tkill, err, 2, t->tid, SIGSETXID);
+ #endif
+
++ /* If this failed, it must have had not started yet or else exited. */
+ if (!INTERNAL_SYSCALL_ERROR_P (val, err))
+- atomic_increment (&cmdp->cntr);
++ {
++ atomic_increment (&cmdp->cntr);
++ return 1;
++ }
++ else
++ return 0;
+ }
+
+
+@@ -1006,6 +1043,7 @@ int
+ attribute_hidden
+ __nptl_setxid (struct xid_command *cmdp)
+ {
++ int signalled;
+ int result;
+ lll_lock (stack_cache_lock);
+
+@@ -1022,7 +1060,7 @@ __nptl_setxid (struct xid_command *cmdp)
+ if (t == self)
+ continue;
+
+- setxid_signal_thread (cmdp, t);
++ setxid_mark_thread (cmdp, t);
+ }
+
+ /* Now the list with threads using user-allocated stacks. */
+@@ -1032,14 +1070,61 @@ __nptl_setxid (struct xid_command *cmdp)
+ if (t == self)
+ continue;
+
+- setxid_signal_thread (cmdp, t);
++ setxid_mark_thread (cmdp, t);
+ }
+
+- int cur = cmdp->cntr;
+- while (cur != 0)
++ /* Iterate until we don't succeed in signalling anyone. That means
++ we have gotten all running threads, and their children will be
++ automatically correct once started. */
++ do
+ {
+- lll_futex_wait (&cmdp->cntr, cur);
+- cur = cmdp->cntr;
++ signalled = 0;
++
++ list_for_each (runp, &stack_used)
++ {
++ struct pthread *t = list_entry (runp, struct pthread, list);
++ if (t == self)
++ continue;
++
++ signalled += setxid_signal_thread (cmdp, t);
++ }
++
++ list_for_each (runp, &__stack_user)
++ {
++ struct pthread *t = list_entry (runp, struct pthread, list);
++ if (t == self)
++ continue;
++
++ signalled += setxid_signal_thread (cmdp, t);
++ }
++
++ int cur = cmdp->cntr;
++ while (cur != 0)
++ {
++ lll_futex_wait (&cmdp->cntr, cur);
++ cur = cmdp->cntr;
++ }
++ }
++ while (signalled != 0);
++
++ /* Clean up flags, so that no thread blocks during exit waiting
++ for a signal which will never come. */
++ list_for_each (runp, &stack_used)
++ {
++ struct pthread *t = list_entry (runp, struct pthread, list);
++ if (t == self)
++ continue;
++
++ setxid_unmark_thread (cmdp, t);
++ }
++
++ list_for_each (runp, &__stack_user)
++ {
++ struct pthread *t = list_entry (runp, struct pthread, list);
++ if (t == self)
++ continue;
++
++ setxid_unmark_thread (cmdp, t);
+ }
+
+ /* This must be last, otherwise the current thread might not have
+diff --git a/nptl/init.c b/nptl/init.c
+index 5e9c250..851bab2 100644
+--- a/nptl/init.c
++++ b/nptl/init.c
+@@ -240,17 +240,23 @@ sighandler_setxid (int sig, siginfo_t *si, void *ctx)
+ INTERNAL_SYSCALL_NCS (__xidcmd->syscall_no, err, 3, __xidcmd->id[0],
+ __xidcmd->id[1], __xidcmd->id[2]);
+
+- if (atomic_decrement_val (&__xidcmd->cntr) == 0)
+- lll_futex_wake (&__xidcmd->cntr, 1);
+-
+ /* Reset the SETXID flag. */
+ struct pthread *self = THREAD_SELF;
+- int flags = THREAD_GETMEM (self, cancelhandling);
+- THREAD_SETMEM (self, cancelhandling, flags & ~SETXID_BITMASK);
++ int flags, newval;
++ do
++ {
++ flags = THREAD_GETMEM (self, cancelhandling);
++ newval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling,
++ flags & ~SETXID_BITMASK, flags);
++ }
++ while (flags != newval);
+
+ /* And release the futex. */
+ self->setxid_futex = 1;
+ lll_futex_wake (&self->setxid_futex, 1);
++
++ if (atomic_decrement_val (&__xidcmd->cntr) == 0)
++ lll_futex_wake (&__xidcmd->cntr, 1);
+ }
+
+
--- /dev/null
+2005-10-03 Jakub Jelinek <jakub@redhat.com>
+
+ * allocatestack.c (setxid_signal_thread): Add
+ INTERNAL_SYSCALL_DECL (err).
+
+2005-10-02 Jakub Jelinek <jakub@redhat.com>
+
+ * allocatestack.c (setxid_signal_thread): Need to use
+ atomic_compare_and_exchange_bool_acq.
+
+2005-10-01 Ulrich Drepper <drepper@redhat.com>
+ Jakub Jelinek <jakub@redhat.com>
+
+ * descr.h: Define SETXID_BIT and SETXID_BITMASK. Adjust
+ CANCEL_RESTMASK.
+ (struct pthread): Move specific_used field to avoid padding.
+ Add setxid_futex field.
+ * init.c (sighandler_setxid): Reset setxid flag and release the
+ setxid futex.
+ * allocatestack.c (setxid_signal_thread): New function. Broken
+ out of the bodies of the two loops in __nptl_setxid. For undetached
+ threads check whether they are exiting and if yes, don't send a signal.
+ (__nptl_setxid): Simplify loops by using setxid_signal_thread.
+ * pthread_create.c (start_thread): For undetached threads, check
+ whether setxid bit is set. If yes, wait until signal has been
+ processed.
+
+ * allocatestack.c (STACK_VARIABLES): Initialize them.
+ * pthread_create.c (__pthread_create_2_1): Initialize pd.
+
+--- libc/nptl/pthread_create.c 26 Jun 2005 17:45:44 -0000 1.43
++++ libc/nptl/pthread_create.c 1 Oct 2005 17:19:37 -0000 1.44
+@@ -314,6 +314,17 @@ start_thread (void *arg)
+ if (IS_DETACHED (pd))
+ /* Free the TCB. */
+ __free_tcb (pd);
++ else if (__builtin_expect (pd->cancelhandling & SETXID_BITMASK, 0))
++ {
++ /* Some other thread might call any of the setXid functions and expect
++ us to reply. In this case wait until we did that. */
++ do
++ lll_futex_wait (&pd->setxid_futex, 0);
++ while (pd->cancelhandling & SETXID_BITMASK);
++
++ /* Reset the value so that the stack can be reused. */
++ pd->setxid_futex = 0;
++ }
+
+ /* We cannot call '_exit' here. '_exit' will terminate the process.
+
+@@ -348,7 +359,7 @@ __pthread_create_2_1 (newthread, attr, s
+ {
+ STACK_VARIABLES;
+ const struct pthread_attr *iattr;
+- struct pthread *pd;
++ struct pthread *pd = NULL;
+ int err;
+
+ iattr = (struct pthread_attr *) attr;
+--- libc/nptl/descr.h 7 Jul 2005 06:07:13 -0000 1.26
++++ libc/nptl/descr.h 1 Oct 2005 17:19:00 -0000 1.27
+@@ -161,8 +161,11 @@ struct pthread
+ /* Bit set if thread terminated and TCB is freed. */
+ #define TERMINATED_BIT 5
+ #define TERMINATED_BITMASK 0x20
++ /* Bit set if thread is supposed to change XID. */
++#define SETXID_BIT 6
++#define SETXID_BITMASK 0x40
+ /* Mask for the rest. Helps the compiler to optimize. */
+-#define CANCEL_RESTMASK 0xffffffc0
++#define CANCEL_RESTMASK 0xffffff80
+
+ #define CANCEL_ENABLED_AND_CANCELED(value) \
+ (((value) & (CANCELSTATE_BITMASK | CANCELED_BITMASK | EXITING_BITMASK \
+@@ -185,12 +188,12 @@ struct pthread
+ void *data;
+ } specific_1stblock[PTHREAD_KEY_2NDLEVEL_SIZE];
+
+- /* Flag which is set when specific data is set. */
+- bool specific_used;
+-
+ /* Two-level array for the thread-specific data. */
+ struct pthread_key_data *specific[PTHREAD_KEY_1STLEVEL_SIZE];
+
++ /* Flag which is set when specific data is set. */
++ bool specific_used;
++
+ /* True if events must be reported. */
+ bool report_events;
+
+@@ -203,6 +206,9 @@ struct pthread
+ /* Lock to synchronize access to the descriptor. */
+ lll_lock_t lock;
+
++ /* Lock for synchronizing setxid calls. */
++ lll_lock_t setxid_futex;
++
+ #if HP_TIMING_AVAIL
+ /* Offset of the CPU clock at start thread start time. */
+ hp_timing_t cpuclock_offset;
+--- libc/nptl/init.c 28 Dec 2004 01:39:50 -0000 1.52
++++ libc/nptl/init.c 1 Oct 2005 17:18:11 -0000 1.53
+@@ -211,6 +211,15 @@ sighandler_setxid (int sig, siginfo_t *s
+
+ if (atomic_decrement_val (&__xidcmd->cntr) == 0)
+ lll_futex_wake (&__xidcmd->cntr, 1);
++
++ /* Reset the SETXID flag. */
++ struct pthread *self = THREAD_SELF;
++ int flags = THREAD_GETMEM (self, cancelhandling);
++ THREAD_SETMEM (self, cancelhandling, flags & ~SETXID_BITMASK);
++
++ /* And release the futex. */
++ self->setxid_futex = 1;
++ lll_futex_wake (&self->setxid_futex, 1);
+ }
+
+
+--- libc/nptl/allocatestack.c 6 Jan 2005 22:40:24 -0000 1.56
++++ libc/nptl/allocatestack.c 4 Oct 2005 00:40:01 -0000 1.59
+@@ -33,7 +34,7 @@
+ #ifndef NEED_SEPARATE_REGISTER_STACK
+
+ /* Most architectures have exactly one stack pointer. Some have more. */
+-# define STACK_VARIABLES void *stackaddr
++# define STACK_VARIABLES void *stackaddr = NULL
+
+ /* How to pass the values to the 'create_thread' function. */
+ # define STACK_VARIABLES_ARGS stackaddr
+@@ -52,7 +53,7 @@
+
+ /* We need two stacks. The kernel will place them but we have to tell
+ the kernel about the size of the reserved address space. */
+-# define STACK_VARIABLES void *stackaddr; size_t stacksize
++# define STACK_VARIABLES void *stackaddr = NULL; size_t stacksize = 0
+
+ /* How to pass the values to the 'create_thread' function. */
+ # define STACK_VARIABLES_ARGS stackaddr, stacksize
+@@ -817,6 +818,46 @@ __find_thread_by_id (pid_t tid)
+ }
+ #endif
+
++
++static void
++internal_function
++setxid_signal_thread (struct xid_command *cmdp, struct pthread *t)
++{
++ if (! IS_DETACHED (t))
++ {
++ int ch;
++ do
++ {
++ ch = t->cancelhandling;
++
++ /* If the thread is exiting right now, ignore it. */
++ if ((ch & EXITING_BITMASK) != 0)
++ return;
++ }
++ while (atomic_compare_and_exchange_bool_acq (&t->cancelhandling,
++ ch | SETXID_BITMASK, ch));
++ }
++
++ int val;
++ INTERNAL_SYSCALL_DECL (err);
++#if __ASSUME_TGKILL
++ val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid),
++ t->tid, SIGSETXID);
++#else
++# ifdef __NR_tgkill
++ val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid),
++ t->tid, SIGSETXID);
++ if (INTERNAL_SYSCALL_ERROR_P (val, err)
++ && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS)
++# endif
++ val = INTERNAL_SYSCALL (tkill, err, 2, t->tid, SIGSETXID);
++#endif
++
++ if (!INTERNAL_SYSCALL_ERROR_P (val, err))
++ atomic_increment (&cmdp->cntr);
++}
++
++
+ int
+ attribute_hidden
+ __nptl_setxid (struct xid_command *cmdp)
+@@ -827,8 +868,6 @@ __nptl_setxid (struct xid_command *cmdp)
+ __xidcmd = cmdp;
+ cmdp->cntr = 0;
+
+- INTERNAL_SYSCALL_DECL (err);
+-
+ struct pthread *self = THREAD_SELF;
+
+ /* Iterate over the list with system-allocated threads first. */
+@@ -836,54 +875,20 @@ __nptl_setxid (struct xid_command *cmdp)
+ list_for_each (runp, &stack_used)
+ {
+ struct pthread *t = list_entry (runp, struct pthread, list);
+- if (t != self)
+- {
+- int val;
+-#if __ASSUME_TGKILL
+- val = INTERNAL_SYSCALL (tgkill, err, 3,
+- THREAD_GETMEM (THREAD_SELF, pid),
+- t->tid, SIGSETXID);
+-#else
+-# ifdef __NR_tgkill
+- val = INTERNAL_SYSCALL (tgkill, err, 3,
+- THREAD_GETMEM (THREAD_SELF, pid),
+- t->tid, SIGSETXID);
+- if (INTERNAL_SYSCALL_ERROR_P (val, err)
+- && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS)
+-# endif
+- val = INTERNAL_SYSCALL (tkill, err, 2, t->tid, SIGSETXID);
+-#endif
++ if (t == self)
++ continue;
+
+- if (!INTERNAL_SYSCALL_ERROR_P (val, err))
+- atomic_increment (&cmdp->cntr);
+- }
++ setxid_signal_thread (cmdp, t);
+ }
+
+ /* Now the list with threads using user-allocated stacks. */
+ list_for_each (runp, &__stack_user)
+ {
+ struct pthread *t = list_entry (runp, struct pthread, list);
+- if (t != self)
+- {
+- int val;
+-#if __ASSUME_TGKILL
+- val = INTERNAL_SYSCALL (tgkill, err, 3,
+- THREAD_GETMEM (THREAD_SELF, pid),
+- t->tid, SIGSETXID);
+-#else
+-# ifdef __NR_tgkill
+- val = INTERNAL_SYSCALL (tgkill, err, 3,
+- THREAD_GETMEM (THREAD_SELF, pid),
+- t->tid, SIGSETXID);
+- if (INTERNAL_SYSCALL_ERROR_P (val, err)
+- && INTERNAL_SYSCALL_ERRNO (val, err) == ENOSYS)
+-# endif
+- val = INTERNAL_SYSCALL (tkill, err, 2, t->tid, SIGSETXID);
+-#endif
++ if (t == self)
++ continue;
+
+- if (!INTERNAL_SYSCALL_ERROR_P (val, err))
+- atomic_increment (&cmdp->cntr);
+- }
++ setxid_signal_thread (cmdp, t);
+ }
+
+ int cur = cmdp->cntr;
+@@ -895,6 +900,7 @@ __nptl_setxid (struct xid_command *cmdp)
+
+ /* This must be last, otherwise the current thread might not have
+ permissions to send SIGSETXID syscall to the other threads. */
++ INTERNAL_SYSCALL_DECL (err);
+ result = INTERNAL_SYSCALL_NCS (cmdp->syscall_no, err, 3,
+ cmdp->id[0], cmdp->id[1], cmdp->id[2]);
+ if (INTERNAL_SYSCALL_ERROR_P (result, err))
--- /dev/null
+2005-08-23 Ulrich Drepper <drepper@redhat.com>
+
+ * nscd/mem.c (mempool_alloc): Use posix_fallocate correctly.
+ * nscd/nscd.h: Temporarily define TEMP_FAILURE_RETRY_VAL here.
+
+ * nscd/aicache.c (addhstaiX): Use send with MSG_NOSIGNAL not write to
+ send reply.
+ * nscd/connections.c (writeall): Likewise.
+ (handle_request): Likewise.
+ * nscd/grpcache.c (cache_addgr): Likewise.
+ * nscd/hstcache.c (cache_addhst): Likewise.
+ * nscd/initgrcache.c (addinitgroupsX): Likewise.
+ * nscd/nscd.c (parse_opt): Likewise.
+ * nscd/nscd_stat.c (send_stats): Likewise.
+ (receive_print_stats): Likewise.
+ * nscd/pwdcache.c (cache_addpw): Likewise.
+
+--- libc/nscd/aicache.c 17 Mar 2005 09:43:42 -0000 1.7
++++ libc/nscd/aicache.c 23 Aug 2005 23:09:12 -0000 1.8
+@@ -399,7 +399,7 @@ addhstaiX (struct database_dyn *db, int
+ total = sizeof (notfound);
+
+ if (fd != -1)
+- TEMP_FAILURE_RETRY (write (fd, ¬found, total));
++ TEMP_FAILURE_RETRY (send (fd, ¬found, total, MSG_NOSIGNAL));
+
+ dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len);
+ /* If we cannot permanently store the result, so be it. */
+--- libc/nscd/connections.c 16 Aug 2005 18:07:46 -0000 1.75
++++ libc/nscd/connections.c 23 Aug 2005 23:12:00 -0000 1.76
+@@ -188,7 +187,7 @@ writeall (int fd, const void *buf, size_
+ ssize_t ret;
+ do
+ {
+- ret = TEMP_FAILURE_RETRY (write (fd, buf, n));
++ ret = TEMP_FAILURE_RETRY (send (fd, buf, n, MSG_NOSIGNAL));
+ if (ret <= 0)
+ break;
+ buf = (const char *) buf + ret;
+@@ -638,8 +645,9 @@ cannot create read-only descriptor for \
+
+ if ((TEMP_FAILURE_RETRY (write (fd, &head, sizeof (head)))
+ != sizeof (head))
+- || posix_fallocate (fd, 0, total) != 0
++ || (TEMP_FAILURE_RETRY_VAL (posix_fallocate (fd, 0, total))
++ != 0)
+ || (mem = mmap (NULL, total, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0)) == MAP_FAILED)
+ {
+ write_fail:
+@@ -901,8 +910,9 @@ cannot handle old request version %d; cu
+ if (!db->enabled)
+ {
+ /* No, sent the prepared record. */
+- if (TEMP_FAILURE_RETRY (write (fd, db->disabled_iov->iov_base,
+- db->disabled_iov->iov_len))
++ if (TEMP_FAILURE_RETRY (send (fd, db->disabled_iov->iov_base,
++ db->disabled_iov->iov_len,
++ MSG_NOSIGNAL))
+ != (ssize_t) db->disabled_iov->iov_len
+ && __builtin_expect (debug_level, 0) > 0)
+ {
+--- libc/nscd/grpcache.c 18 Jul 2005 21:05:40 -0000 1.39
++++ libc/nscd/grpcache.c 23 Aug 2005 23:12:43 -0000 1.40
+@@ -107,7 +107,8 @@ cache_addgr (struct database_dyn *db, in
+ case. */
+ total = sizeof (notfound);
+
+- written = TEMP_FAILURE_RETRY (write (fd, ¬found, total));
++ written = TEMP_FAILURE_RETRY (send (fd, ¬found, total,
++ MSG_NOSIGNAL));
+
+ dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len);
+ /* If we cannot permanently store the result, so be it. */
+--- libc/nscd/hstcache.c 22 Feb 2005 22:53:39 -0000 1.33
++++ libc/nscd/hstcache.c 23 Aug 2005 23:13:14 -0000 1.34
+@@ -115,7 +115,8 @@ cache_addhst (struct database_dyn *db, i
+ written = total = sizeof (notfound);
+
+ if (fd != -1)
+- written = TEMP_FAILURE_RETRY (write (fd, ¬found, total));
++ written = TEMP_FAILURE_RETRY (send (fd, ¬found, total,
++ MSG_NOSIGNAL));
+
+ dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len);
+ /* If we cannot permanently store the result, so be it. */
+--- libc/nscd/initgrcache.c 22 Feb 2005 22:47:45 -0000 1.3
++++ libc/nscd/initgrcache.c 23 Aug 2005 23:14:05 -0000 1.4
+@@ -188,7 +188,8 @@ addinitgroupsX (struct database_dyn *db,
+ /* We have no data. This means we send the standard reply for this
+ case. */
+ if (fd != -1)
+- written = TEMP_FAILURE_RETRY (write (fd, ¬found, total));
++ written = TEMP_FAILURE_RETRY (send (fd, ¬found, total,
++ MSG_NOSIGNAL));
+
+ dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len);
+ /* If we cannot permanently store the result, so be it. */
+--- libc/nscd/mem.c 8 Aug 2005 20:38:42 -0000 1.6
++++ libc/nscd/mem.c 23 Aug 2005 23:15:28 -0000 1.7
+@@ -490,7 +490,10 @@ mempool_alloc (struct database_dyn *db,
+ + new_data_size);
+
+ if ((!db->mmap_used
+- || posix_fallocate (db->wr_fd, oldtotal, newtotal) != 0)
++ || TEMP_FAILURE_RETRY_VAL (posix_fallocate (db->wr_fd,
++ oldtotal,
++ newtotal - oldtotal))
++ != 0)
+ /* Try to resize the mapping. Note: no MREMAP_MAYMOVE. */
+ && mremap (db->head, oldtotal, newtotal, 0) == 0)
+ {
+--- libc/nscd/nscd.c 19 Jul 2005 15:30:46 -0000 1.46
++++ libc/nscd/nscd.c 23 Aug 2005 23:16:20 -0000 1.47
+@@ -315,8 +315,9 @@ parse_opt (int key, char *arg, struct ar
+ req.version = NSCD_VERSION;
+ req.type = SHUTDOWN;
+ req.key_len = 0;
+- nbytes = TEMP_FAILURE_RETRY (write (sock, &req,
+- sizeof (request_header)));
++ nbytes = TEMP_FAILURE_RETRY (send (sock, &req,
++ sizeof (request_header),
++ MSG_NOSIGNAL));
+ close (sock);
+ exit (nbytes != sizeof (request_header) ? EXIT_FAILURE : EXIT_SUCCESS);
+ }
+--- libc/nscd/nscd.h 8 Aug 2005 18:54:44 -0000 1.22
++++ libc/nscd/nscd.h 23 Aug 2005 23:18:23 -0000 1.23
+@@ -241,4 +248,14 @@ extern void gc (struct database_dyn *db)
+ /* nscd_setup_thread.c */
+ extern void setup_thread (struct database_dyn *db);
+
++
++/* Special version of TEMP_FAILURE_RETRY for functions returning error
++ values. */
++#define TEMP_FAILURE_RETRY_VAL(expression) \
++ (__extension__ \
++ ({ long int __result; \
++ do __result = (long int) (expression); \
++ while (__result == EINTR); \
++ __result; }))
++
+ #endif /* nscd.h */
+--- libc/nscd/nscd_stat.c 9 Aug 2005 05:45:03 -0000 1.15
++++ libc/nscd/nscd_stat.c 23 Aug 2005 23:20:21 -0000 1.16
+@@ -133,7 +133,8 @@ send_stats (int fd, struct database_dyn
+ if (selinux_enabled)
+ nscd_avc_cache_stats (&data.cstats);
+
+- if (TEMP_FAILURE_RETRY (write (fd, &data, sizeof (data))) != sizeof (data))
++ if (TEMP_FAILURE_RETRY (send (fd, &data, sizeof (data), MSG_NOSIGNAL))
++ != sizeof (data))
+ {
+ char buf[256];
+ dbg_log (_("cannot write statistics: %s"),
+@@ -180,7 +181,8 @@ receive_print_stats (void)
+ req.version = NSCD_VERSION;
+ req.type = GETSTAT;
+ req.key_len = 0;
+- nbytes = TEMP_FAILURE_RETRY (write (fd, &req, sizeof (request_header)));
++ nbytes = TEMP_FAILURE_RETRY (send (fd, &req, sizeof (request_header),
++ MSG_NOSIGNAL));
+ if (nbytes != sizeof (request_header))
+ {
+ int err = errno;
+--- libc/nscd/pwdcache.c 22 Feb 2005 22:53:39 -0000 1.37
++++ libc/nscd/pwdcache.c 23 Aug 2005 23:21:02 -0000 1.38
+@@ -114,7 +114,8 @@ cache_addpw (struct database_dyn *db, in
+ written = total = sizeof (notfound);
+
+ if (fd != -1)
+- written = TEMP_FAILURE_RETRY (write (fd, ¬found, total));
++ written = TEMP_FAILURE_RETRY (send (fd, ¬found, total,
++ MSG_NOSIGNAL));
+
+ dataset = mempool_alloc (db, sizeof (struct dataset) + req->key_len);
+ /* If we cannot permanently store the result, so be it. */
--- /dev/null
+2005-09-20 Jakub Jelinek <jakub@redhat.com>
+
+ * nscd/dbg_log.c (init_logfile): Use fopen64 rather than fopen.
+
+--- libc/nscd/dbg_log.c 2 Oct 2004 21:38:53 -0000 1.7
++++ libc/nscd/dbg_log.c 20 Sep 2005 20:15:04 -0000 1.8
+@@ -44,7 +44,7 @@ init_logfile (void)
+ {
+ if (logfilename)
+ {
+- dbgout = fopen (logfilename, "a");
++ dbgout = fopen64 (logfilename, "a");
+ return dbgout == NULL ? 0 : 1;
+ }
+ return 1;
--- /dev/null
+2006-04-26 Jakub Jelinek <jakub@redhat.com>
+
+ * nscd/connections.c (sighup_handler): Only run prune_cache on
+ enabled databases.
+
+--- libc/nscd/connections.c.jj 2006-04-26 09:03:38.000000000 -0400
++++ libc/nscd/connections.c 2006-04-26 09:04:35.000000000 -0400
+@@ -687,13 +687,16 @@ finish_drop_privileges (void)
+ void
+ sighup_handler (int signum)
+ {
+- /* Prune the password database */
++ /* Prune the password database. */
++ if (dbs[pwddb].enabled)
+ prune_cache (&dbs[pwddb], LONG_MAX);
+
+- /* Prune the group database */
++ /* Prune the group database. */
++ if (dbs[grpdb].enabled)
+ prune_cache (&dbs[grpdb], LONG_MAX);
+
+- /* Prune the host database */
++ /* Prune the host database. */
++ if (dbs[hstdb].enabled)
+ prune_cache (&dbs[hstdb], LONG_MAX);
+ }
+
--- /dev/null
+2006-07-02 Jakub Jelinek <jakub@redhat.com>
+
+ * nscd/connections.c (sighup_pending): New variable.
+ (nscd_run): If sighup_pending, prune all 3 caches.
+ (sighup_handler): Don't prune caches here, rather just set
+ sighup_pending flag.
+
+--- libc/nscd/connections.c.jj 2006-07-02 11:47:20.000000000 +0200
++++ libc/nscd/connections.c 2006-07-02 12:57:22.000000000 +0200
+@@ -66,6 +67,7 @@ static gid_t *server_groups;
+ # define NGROUPS 32
+ #endif
+ static int server_ngroups;
++static volatile int sighup_pending;
+
+ static pthread_attr_t attr;
+
+@@ -1283,6 +1285,10 @@ nscd_run (void *p)
+ if (readylist == NULL && to == ETIMEDOUT)
+ {
+ --nready;
++
++ if (sighup_pending)
++ goto sighup_prune;
++
+ pthread_mutex_unlock (&readylist_lock);
+ goto only_prune;
+ }
+@@ -1292,6 +1298,34 @@ nscd_run (void *p)
+ pthread_cond_wait (&readylist_cond, &readylist_lock);
+ }
+
++ if (sighup_pending)
++ {
++ --nready;
++ pthread_cond_signal (&readylist_cond);
++ sighup_prune:
++ sighup_pending = 0;
++ pthread_mutex_unlock (&readylist_lock);
++
++ /* Prune the password database. */
++ if (dbs[pwddb].enabled)
++ prune_cache (&dbs[pwddb], LONG_MAX, -1);
++
++ /* Prune the group database. */
++ if (dbs[grpdb].enabled)
++ prune_cache (&dbs[grpdb], LONG_MAX, -1);
++
++ /* Prune the host database. */
++ if (dbs[hstdb].enabled)
++ prune_cache (&dbs[hstdb], LONG_MAX, -1);
++
++ /* Re-locking. */
++ pthread_mutex_lock (&readylist_lock);
++
++ /* One more thread available. */
++ ++nready;
++ continue;
++ }
++
+ struct fdlist *it = readylist->next;
+ if (readylist->next == readylist)
+ /* Just one entry on the list. */
+@@ -1902,16 +1936,5 @@ finish_drop_privileges (void)
+ void
+ sighup_handler (int signum)
+ {
+- /* Prune the password database. */
+- if (dbs[pwddb].enabled)
+- prune_cache (&dbs[pwddb], LONG_MAX, -1);
+-
+- /* Prune the group database. */
+- if (dbs[grpdb].enabled)
+- prune_cache (&dbs[grpdb], LONG_MAX, -1);
+-
+- /* Prune the host database. */
+- if (dbs[hstdb].enabled)
+- prune_cache (&dbs[hstdb], LONG_MAX, -1);
++ sighup_pending = 1;
+ }
+-
--- /dev/null
+2006-09-05 Jakub Jelinek <jakub@redhat.com>
+
+ * nscd/initgrcache.c (addinitgroupsX): Move any_success
+ decl before first goto out.
+
+2006-08-01 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2098]
+ * nscd/initgrcache.c (addinitgroupsX): Judge successful lookups by
+ status of NSS calls, not the number of returned entries.
+
+--- libc/nscd/initgrcache.c 6 Jan 2006 19:12:48 -0000 1.8
++++ libc/nscd/initgrcache.c 5 Sep 2006 14:35:00 -0000 1.10
+@@ -107,6 +107,7 @@ addinitgroupsX (struct database_dyn *db,
+
+ long int start = 0;
+ bool all_tryagain = true;
++ bool any_success = false;
+
+ /* This is temporary memory, we need not (ad must not) call
+ mempool_alloc. */
+@@ -158,6 +159,8 @@ addinitgroupsX (struct database_dyn *db,
+ if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN)
+ __libc_fatal ("illegal status in internal_getgrouplist");
+
++ any_success |= status == NSS_STATUS_SUCCESS;
++
+ if (status != NSS_STATUS_SUCCESS
+ && nss_next_action (nip, status) == NSS_ACTION_RETURN)
+ break;
+@@ -171,7 +174,7 @@ addinitgroupsX (struct database_dyn *db,
+ ssize_t total;
+ ssize_t written;
+ out:
+- if (start == 0)
++ if (!any_success)
+ {
+ /* Nothing found. Create a negative result record. */
+ written = total = sizeof (notfound);
--- /dev/null
+2006-04-27 Jakub Jelinek <jakub@redhat.com>
+
+ * nscd/nscd.conf: Fix a typo.
+
+2006-04-26 Ulrich Drepper <drepper@redhat.com>
+
+ * nscd/nscd.h (struct database_dyn): Add propagate field.
+ * nscd/nscd_conf.c (nscd_parse_file): Parse auto-propagate lines.
+ * nscd/nscd.conf: Add auto-propagate lines.
+ * nscd/connections.c (dbs): Initialize .propagate fields.
+ * nscd/grpcache.c (cache_addgr): Do not add ID entry for name lookups
+ and vice versa if propagation is disabled for the database.
+ * nscd/pwdcache.c (cache_addpw): Likewise.
+
+--- libc/nscd/connections.c 26 Apr 2006 16:26:17 -0000 1.84
++++ libc/nscd/connections.c 26 Apr 2006 17:28:50 -0000 1.85
+@@ -103,6 +103,7 @@ struct database_dyn dbs[lastdb] =
+ .enabled = 0,
+ .check_file = 1,
+ .persistent = 0,
++ .propagate = 1,
+ .shared = 0,
+ .max_db_size = DEFAULT_MAX_DB_SIZE,
+ .filename = "/etc/passwd",
+@@ -119,6 +120,7 @@ struct database_dyn dbs[lastdb] =
+ .enabled = 0,
+ .check_file = 1,
+ .persistent = 0,
++ .propagate = 1,
+ .shared = 0,
+ .max_db_size = DEFAULT_MAX_DB_SIZE,
+ .filename = "/etc/group",
+@@ -135,6 +137,7 @@ struct database_dyn dbs[lastdb] =
+ .enabled = 0,
+ .check_file = 1,
+ .persistent = 0,
++ .propagate = 0, /* Not used. */
+ .shared = 0,
+ .max_db_size = DEFAULT_MAX_DB_SIZE,
+ .filename = "/etc/hosts",
+--- libc/nscd/grpcache.c 6 Jan 2006 19:12:48 -0000 1.45
++++ libc/nscd/grpcache.c 26 Apr 2006 17:25:07 -0000 1.46
+@@ -342,10 +342,10 @@ cache_addgr (struct database_dyn *db, in
+ marked with FIRST first. Otherwise we end up with
+ dangling "pointers" in case a latter hash entry cannot be
+ added. */
+- bool first = req->type == GETGRBYNAME;
++ bool first = true;
+
+ /* If the request was by GID, add that entry first. */
+- if (req->type != GETGRBYNAME)
++ if (req->type == GETGRBYGID)
+ {
+ if (cache_add (GETGRBYGID, cp, key_offset, &dataset->head, true,
+ db, owner) < 0)
+@@ -355,12 +355,14 @@ cache_addgr (struct database_dyn *db, in
+ dataset->head.usable = false;
+ goto out;
+ }
++
++ first = false;
+ }
+ /* If the key is different from the name add a separate entry. */
+ else if (strcmp (key_copy, gr_name) != 0)
+ {
+ if (cache_add (GETGRBYNAME, key_copy, key_len + 1,
+- &dataset->head, first, db, owner) < 0)
++ &dataset->head, true, db, owner) < 0)
+ {
+ /* Could not allocate memory. Make sure the data gets
+ discarded. */
+@@ -372,11 +374,13 @@ cache_addgr (struct database_dyn *db, in
+ }
+
+ /* We have to add the value for both, byname and byuid. */
+- if (__builtin_expect (cache_add (GETGRBYNAME, gr_name, gr_name_len,
+- &dataset->head, first, db, owner)
+- == 0, 1))
++ if ((req->type == GETGRBYNAME || db->propagate)
++ && __builtin_expect (cache_add (GETGRBYNAME, gr_name,
++ gr_name_len,
++ &dataset->head, first, db, owner)
++ == 0, 1))
+ {
+- if (req->type == GETGRBYNAME)
++ if (req->type == GETGRBYNAME && db->propagate)
+ (void) cache_add (GETGRBYGID, cp, key_offset, &dataset->head,
+ req->type != GETGRBYNAME, db, owner);
+ }
+--- libc/nscd/nscd.conf 23 Aug 2005 23:17:32 -0000 1.11
++++ libc/nscd/nscd.conf 26 Apr 2006 17:27:03 -0000 1.13
+@@ -23,7 +23,8 @@
+ # check-files <service> <yes|no>
+ # persistent <service> <yes|no>
+ # shared <service> <yes|no>
+ # max-db-size <service> <number bytes>
++# auto-propagate <service> <yes|no>
+ #
+ # Currently supported cache names (services): passwd, group, hosts
+ #
+@@ -47,6 +48,7 @@
+ persistent passwd yes
+ shared passwd yes
+ max-db-size passwd 33554432
++ auto-propagate passwd yes
+
+ enable-cache group yes
+ positive-time-to-live group 3600
+@@ -56,6 +58,7 @@
+ persistent group yes
+ shared group yes
+ max-db-size group 33554432
++ auto-propagate group yes
+
+ enable-cache hosts yes
+ positive-time-to-live hosts 3600
+--- libc/nscd/nscd.h 30 Dec 2005 16:51:19 -0000 1.24
++++ libc/nscd/nscd.h 26 Apr 2006 17:25:43 -0000 1.25
+@@ -63,6 +63,7 @@ struct database_dyn
+ int check_file;
+ int persistent;
+ int shared;
++ int propagate;
+ size_t max_db_size;
+ const char *filename;
+ const char *db_filename;
+--- libc/nscd/nscd_conf.c 7 Dec 2005 05:47:27 -0000 1.19
++++ libc/nscd/nscd_conf.c 26 Apr 2006 17:26:24 -0000 1.20
+@@ -182,6 +182,20 @@ nscd_parse_file (const char *fname, stru
+ if (cnt == lastdb)
+ dbg_log ("database %s is not supported\n", arg1);
+ }
++ else if (strcmp (entry, "auto-propagate") == 0)
++ {
++ for (cnt = 0; cnt < lastdb; ++cnt)
++ if (strcmp (arg1, dbnames[cnt]) == 0)
++ {
++ if (strcmp (arg2, "no") == 0)
++ dbs[cnt].propagate = 0;
++ else if (strcmp (arg2, "yes") == 0)
++ dbs[cnt].propagate = 1;
++ break;
++ }
++ if (cnt == lastdb)
++ dbg_log ("database %s is not supported\n", arg1);
++ }
+ else if (strcmp (entry, "logfile") == 0)
+ set_logfile (arg1);
+ else if (strcmp (entry, "debug-level") == 0)
+--- libc/nscd/pwdcache.c 6 Jan 2006 19:12:48 -0000 1.43
++++ libc/nscd/pwdcache.c 26 Apr 2006 17:27:51 -0000 1.44
+@@ -338,10 +338,10 @@ cache_addpw (struct database_dyn *db, in
+ marked with FIRST first. Otherwise we end up with
+ dangling "pointers" in case a latter hash entry cannot be
+ added. */
+- bool first = req->type == GETPWBYNAME;
++ bool first = true;
+
+ /* If the request was by UID, add that entry first. */
+- if (req->type != GETPWBYNAME)
++ if (req->type == GETPWBYUID)
+ {
+ if (cache_add (GETPWBYUID, cp, key_offset, &dataset->head, true,
+ db, owner) < 0)
+@@ -351,12 +351,14 @@ cache_addpw (struct database_dyn *db, in
+ dataset->head.usable = false;
+ goto out;
+ }
++
++ first = false;
+ }
+ /* If the key is different from the name add a separate entry. */
+ else if (strcmp (key_copy, dataset->strdata) != 0)
+ {
+ if (cache_add (GETPWBYNAME, key_copy, key_len + 1,
+- &dataset->head, first, db, owner) < 0)
++ &dataset->head, true, db, owner) < 0)
+ {
+ /* Could not allocate memory. Make sure the data gets
+ discarded. */
+@@ -368,11 +370,12 @@ cache_addpw (struct database_dyn *db, in
+ }
+
+ /* We have to add the value for both, byname and byuid. */
+- if (__builtin_expect (cache_add (GETPWBYNAME, dataset->strdata,
+- pw_name_len, &dataset->head, first,
+- db, owner) == 0, 1))
++ if ((req->type == GETPWBYNAME || db->propagate)
++ && __builtin_expect (cache_add (GETPWBYNAME, dataset->strdata,
++ pw_name_len, &dataset->head,
++ first, db, owner) == 0, 1))
+ {
+- if (req->type == GETPWBYNAME)
++ if (req->type == GETPWBYNAME && db->propagate)
+ (void) cache_add (GETPWBYUID, cp, key_offset, &dataset->head,
+ req->type != GETPWBYNAME, db, owner);
+ }
--- /dev/null
+2005-08-08 Ulrich Drepper <drepper@redhat.com>
+ Jakub Jelinek <jakub@redhat.com>
+
+ * nscd/mem.c (BLOCK_ALIGN_LOG, BLOCK_ALIGN, BLOCK_ALIGN_M1): Move
+ definitions to...
+ * nscd/nscd.h (BLOCK_ALIGN_LOG, BLOCK_ALIGN, BLOCK_ALIGN_M1): ...here.
+ * nscd/connections.c (usekey): New enum.
+ (check_use, verify_persistent_db): New functions.
+ (nscd_init): If persistent database is corrupted, unlink it and
+ recreate rather than falling back to non-persistent database.
+ Call verify_persistent_db. Avoid overflows in total computation.
+
+--- libc/nscd/connections.c 18 Jul 2005 22:25:16 -0000 1.70
++++ libc/nscd/connections.c 8 Aug 2005 18:56:17 -0000 1.71
+@@ -199,6 +199,210 @@ writeall (int fd, const void *buf, size_
+ }
+
+
++enum usekey
++ {
++ use_not = 0,
++ /* The following three are not really used, they are symbolic constants. */
++ use_first = 16,
++ use_begin = 32,
++ use_end = 64,
++
++ use_he = 1,
++ use_he_begin = use_he | use_begin,
++ use_he_end = use_he | use_end,
++#if SEPARATE_KEY
++ use_key = 2,
++ use_key_begin = use_key | use_begin,
++ use_key_end = use_key | use_end,
++ use_key_first = use_key_begin | use_first,
++#endif
++ use_data = 3,
++ use_data_begin = use_data | use_begin,
++ use_data_end = use_data | use_end,
++ use_data_first = use_data_begin | use_first
++ };
++
++
++static int
++check_use (const char *data, nscd_ssize_t first_free, uint8_t *usemap,
++ enum usekey use, ref_t start, size_t len)
++{
++ assert (len >= 2);
++
++ if (start > first_free || start + len > first_free
++ || (start & BLOCK_ALIGN_M1))
++ return 0;
++
++ if (usemap[start] == use_not)
++ {
++ /* Add the start marker. */
++ usemap[start] = use | use_begin;
++ use &= ~use_first;
++
++ while (--len > 0)
++ if (usemap[++start] != use_not)
++ return 0;
++ else
++ usemap[start] = use;
++
++ /* Add the end marker. */
++ usemap[start] = use | use_end;
++ }
++ else if ((usemap[start] & ~use_first) == ((use | use_begin) & ~use_first))
++ {
++ /* Hash entries can't be shared. */
++ if (use == use_he)
++ return 0;
++
++ usemap[start] |= (use & use_first);
++ use &= ~use_first;
++
++ while (--len > 1)
++ if (usemap[++start] != use)
++ return 0;
++
++ if (usemap[++start] != (use | use_end))
++ return 0;
++ }
++ else
++ /* Points to a wrong object or somewhere in the middle. */
++ return 0;
++
++ return 1;
++}
++
++
++/* Verify data in persistent database. */
++static int
++verify_persistent_db (void *mem, struct database_pers_head *readhead, int dbnr)
++{
++ assert (dbnr == pwddb || dbnr == grpdb || dbnr == hstdb);
++
++ time_t now = time (NULL);
++
++ struct database_pers_head *head = mem;
++ struct database_pers_head head_copy = *head;
++
++ /* Check that the header that was read matches the head in the database. */
++ if (readhead != NULL && memcmp (head, readhead, sizeof (*head)) != 0)
++ return 0;
++
++ /* First some easy tests: make sure the database header is sane. */
++ if (head->version != DB_VERSION
++ || head->header_size != sizeof (*head)
++ /* We allow a timestamp to be one hour ahead of the current time.
++ This should cover daylight saving time changes. */
++ || head->timestamp > now + 60 * 60 + 60
++ || (head->gc_cycle & 1)
++ || (size_t) head->module > INT32_MAX / sizeof (ref_t)
++ || (size_t) head->data_size > INT32_MAX - head->module * sizeof (ref_t)
++ || head->first_free < 0
++ || head->first_free > head->data_size
++ || (head->first_free & BLOCK_ALIGN_M1) != 0
++ || head->maxnentries < 0
++ || head->maxnsearched < 0)
++ return 0;
++
++ uint8_t *usemap = calloc (head->first_free, 1);
++ if (usemap == NULL)
++ return 0;
++
++ const char *data = (char *) &head->array[roundup (head->module,
++ ALIGN / sizeof (ref_t))];
++
++ nscd_ssize_t he_cnt = 0;
++ for (nscd_ssize_t cnt = 0; cnt < head->module; ++cnt)
++ {
++ ref_t work = head->array[cnt];
++
++ while (work != ENDREF)
++ {
++ if (! check_use (data, head->first_free, usemap, use_he, work,
++ sizeof (struct hashentry)))
++ goto fail;
++
++ /* Now we know we can dereference the record. */
++ struct hashentry *here = (struct hashentry *) (data + work);
++
++ ++he_cnt;
++
++ /* Make sure the record is for this type of service. */
++ if (here->type >= LASTREQ
++ || serv2db[here->type] != &dbs[dbnr])
++ goto fail;
++
++ /* Validate boolean field value. */
++ if (here->first != false && here->first != true)
++ goto fail;
++
++ if (here->len < 0)
++ goto fail;
++
++ /* Now the data. */
++ if (here->packet < 0
++ || here->packet > head->first_free
++ || here->packet + sizeof (struct datahead) > head->first_free)
++ goto fail;
++
++ struct datahead *dh = (struct datahead *) (data + here->packet);
++
++ if (! check_use (data, head->first_free, usemap,
++ use_data | (here->first ? use_first : 0),
++ here->packet, dh->allocsize))
++ goto fail;
++
++ if (dh->allocsize < sizeof (struct datahead)
++ || dh->recsize > dh->allocsize
++ || (dh->notfound != false && dh->notfound != true)
++ || (dh->usable != false && dh->usable != true))
++ goto fail;
++
++ if (here->key < here->packet + sizeof (struct datahead)
++ || here->key > here->packet + dh->allocsize
++ || here->key + here->len > here->packet + dh->allocsize)
++ {
++#if SEPARATE_KEY
++ /* If keys can appear outside of data, this should be done
++ instead. But gc doesn't mark the data in that case. */
++ if (! check_use (data, head->first_free, usemap,
++ use_key | (here->first ? use_first : 0),
++ here->key, here->len))
++#endif
++ goto fail;
++ }
++
++ work = here->next;
++ }
++ }
++
++ if (he_cnt != head->nentries)
++ goto fail;
++
++ /* See if all data and keys had at least one reference from
++ he->first == true hashentry. */
++ for (ref_t idx = 0; idx < head->first_free; ++idx)
++ {
++#if SEPARATE_KEY
++ if (usemap[idx] == use_key_begin)
++ goto fail;
++#endif
++ if (usemap[idx] == use_data_begin)
++ goto fail;
++ }
++
++ /* Finally, make sure the database hasn't changed since the first test. */
++ if (memcmp (mem, &head_copy, sizeof (*head)) != 0)
++ goto fail;
++
++ free (usemap);
++ return 1;
++
++fail:
++ free (usemap);
++ return 0;
++}
++
++
+ /* Initialize database information structures. */
+ void
+ nscd_init (void)
+@@ -242,7 +446,7 @@ nscd_init (void)
+ fail_db:
+ dbg_log (_("invalid persistent database file \"%s\": %s"),
+ dbs[cnt].db_filename, strerror (errno));
+- dbs[cnt].persistent = 0;
++ unlink (dbs[cnt].db_filename);
+ }
+ else if (head.module == 0 && head.data_size == 0)
+ {
+@@ -255,22 +459,31 @@ nscd_init (void)
+ dbg_log (_("invalid persistent database file \"%s\": %s"),
+ dbs[cnt].db_filename,
+ _("header size does not match"));
+- dbs[cnt].persistent = 0;
++ unlink (dbs[cnt].db_filename);
+ }
+ else if ((total = (sizeof (head)
+ + roundup (head.module * sizeof (ref_t),
+ ALIGN)
+ + head.data_size))
+- > st.st_size)
++ > st.st_size
++ || total < sizeof (head))
+ {
+ dbg_log (_("invalid persistent database file \"%s\": %s"),
+ dbs[cnt].db_filename,
+ _("file size does not match"));
+- dbs[cnt].persistent = 0;
++ unlink (dbs[cnt].db_filename);
+ }
+ else if ((mem = mmap (NULL, total, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0)) == MAP_FAILED)
+ goto fail_db;
++ else if (!verify_persistent_db (mem, &head, cnt))
++ {
++ munmap (mem, total);
++ dbg_log (_("invalid persistent database file \"%s\": %s"),
++ dbs[cnt].db_filename,
++ _("verification failed"));
++ unlink (dbs[cnt].db_filename);
++ }
+ else
+ {
+ /* Success. We have the database. */
+--- libc/nscd/mem.c 7 Aug 2005 21:16:45 -0000 1.4
++++ libc/nscd/mem.c 8 Aug 2005 18:55:26 -0000 1.5
+@@ -34,12 +34,6 @@
+ #include "nscd.h"
+
+
+-/* Maximum alignment requirement we will encounter. */
+-#define BLOCK_ALIGN_LOG 3
+-#define BLOCK_ALIGN (1 << BLOCK_ALIGN_LOG)
+-#define BLOCK_ALIGN_M1 (BLOCK_ALIGN - 1)
+-
+-
+ static int
+ sort_he (const void *p1, const void *p2)
+ {
+--- libc/nscd/nscd.h 15 Oct 2004 21:13:19 -0000 1.21
++++ libc/nscd/nscd.h 8 Aug 2005 18:54:44 -0000 1.22
+@@ -94,6 +94,11 @@ struct database_dyn
+ /* Path used when not using persistent storage. */
+ #define _PATH_NSCD_XYZ_DB_TMP "/var/run/nscd/dbXXXXXX"
+
++/* Maximum alignment requirement we will encounter. */
++#define BLOCK_ALIGN_LOG 3
++#define BLOCK_ALIGN (1 << BLOCK_ALIGN_LOG)
++#define BLOCK_ALIGN_M1 (BLOCK_ALIGN - 1)
++
+
+ /* Global variables. */
+ extern struct database_dyn dbs[lastdb];
--- /dev/null
+2005-08-16 Ulrich Drepper <drepper@redhat.com>
+
+ * nscd/cache.c (prune_cache): Add more debug output. Only for
+ debug level 3 and higher and very verbose.
+
+--- libc/nscd/cache.c 16 Aug 2005 18:08:41 -0000 1.22
++++ libc/nscd/cache.c 16 Aug 2005 22:46:16 -0000 1.23
+@@ -21,6 +21,7 @@
+ #include <atomic.h>
+ #include <errno.h>
+ #include <error.h>
++#include <inttypes.h>
+ #include <limits.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -238,6 +239,10 @@ prune_cache (struct database_dyn *table,
+ char *const data = table->data;
+ bool any = false;
+
++ if (__builtin_expect (debug_level > 2, 0))
++ dbg_log (_("pruning %s cache; time %ld"),
++ dbnames[table - dbs], (long int) now);
++
+ do
+ {
+ ref_t run = table->head->array[--cnt];
+@@ -247,6 +252,25 @@ prune_cache (struct database_dyn *table,
+ struct hashentry *runp = (struct hashentry *) (data + run);
+ struct datahead *dh = (struct datahead *) (data + runp->packet);
+
++ /* Some debug support. */
++ if (__builtin_expect (debug_level > 2, 0))
++ {
++ char buf[INET6_ADDRSTRLEN];
++ const char *str;
++
++ if (runp->type == GETHOSTBYADDR || runp->type == GETHOSTBYADDRv6)
++ {
++ inet_ntop (runp->type == GETHOSTBYADDR ? AF_INET : AF_INET6,
++ data + runp->key, buf, sizeof (buf));
++ str = buf;
++ }
++ else
++ str = data + runp->key;
++
++ dbg_log (_("considering %s entry \"%s\", timeout %" PRIu64),
++ serv2str[runp->type], str, dh->timeout);
++ }
++
+ /* Check whether the entry timed out. */
+ if (dh->timeout < now)
+ {
--- /dev/null
+2005-08-08 Ulrich Drepper <drepper@redhat.com>
+
+ * nscd/mem.c (mempool_alloc): Use posix_fallocate instead of ftruncate.
+ * nscd/connections.c (nscd_init): Likewise.
+
+--- libc/nscd/connections.c 8 Aug 2005 18:56:17 -0000 1.71
++++ libc/nscd/connections.c 8 Aug 2005 20:40:53 -0000 1.72
+@@ -638,7 +638,7 @@ cannot create read-only descriptor for \
+
+ if ((TEMP_FAILURE_RETRY (write (fd, &head, sizeof (head)))
+ != sizeof (head))
+- || ftruncate (fd, total) != 0
++ || posix_fallocate (fd, 0, total) != 0
+ || (mem = mmap (NULL, total, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0)) == MAP_FAILED)
+ {
+--- libc/nscd/mem.c 8 Aug 2005 18:55:26 -0000 1.5
++++ libc/nscd/mem.c 8 Aug 2005 20:38:42 -0000 1.6
+@@ -21,6 +21,7 @@
+ #include <assert.h>
+ #include <errno.h>
+ #include <error.h>
++#include <fcntl.h>
+ #include <inttypes.h>
+ #include <libintl.h>
+ #include <limits.h>
+@@ -488,7 +489,8 @@ mempool_alloc (struct database_dyn *db,
+ + db->head->module * sizeof (ref_t)
+ + new_data_size);
+
+- if ((!db->mmap_used || ftruncate (db->wr_fd, newtotal) != 0)
++ if ((!db->mmap_used
++ || posix_fallocate (db->wr_fd, oldtotal, newtotal) != 0)
+ /* Try to resize the mapping. Note: no MREMAP_MAYMOVE. */
+ && mremap (db->head, oldtotal, newtotal, 0) == 0)
+ {
--- /dev/null
+2005-09-22 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #1363]
+ * nscd/nscd_getpw_r.c (nscd_getpw_r): Remove incorrectly C&Ped
+ free call in code handling detection of GC runs.
+
+--- libc/nscd/nscd_getpw_r.c 22 Feb 2005 22:47:45 -0000 1.30
++++ libc/nscd/nscd_getpw_r.c 22 Sep 2005 14:35:11 -0000 1.31
+@@ -227,8 +227,6 @@ nscd_getpw_r (const char *key, size_t ke
+ mapped = NO_MAPPING;
+ }
+
+- free (resultbuf);
+-
+ goto retry;
+ }
+
--- /dev/null
+2005-11-19 Ulrich Drepper <drepper@redhat.com>
+
+ * nscd/nscd_gethst_r.c (nscd_gethst_r): Avoid unnecesary read call
+ if there are no aliases.
+
+--- libc/nscd/nscd_gethst_r.c 22 Feb 2005 22:47:45 -0000 1.32
++++ libc/nscd/nscd_gethst_r.c 19 Nov 2005 17:09:03 -0000 1.33
+@@ -328,8 +328,9 @@ nscd_gethst_r (const char *key, size_t k
+ /* And finally read the aliases. */
+ if (addr_list == NULL)
+ {
+- if ((size_t) __readall (sock, resultbuf->h_aliases[0], total_len)
+- == total_len)
++ if (total_len == 0
++ || ((size_t) __readall (sock, resultbuf->h_aliases[0], total_len)
++ == total_len))
+ {
+ retval = 0;
+ *result = resultbuf;
--- /dev/null
+2005-08-23 Ulrich Drepper <drepper@redhat.com>
+
+ * nscd/connection.c (DEFAULT_DATASIZE_PER_BUCKET): Move to nscd.h.
+ (dbs): Initialize max_db_size fields.
+ (nscd_init): When mapping the database, use max_db_size as the
+ mapping size even if it is bigger than the file size.
+ * nscd/mem.c (mempool_alloc): When resizing the file make sure the
+ limit in max_db_size is not exceeded. Don't use mremap, just
+ posix_fallocate is enough (according to Linus). Use posix_fallocate
+ correctly.
+ * nscd/nscd.conf: Add max-db-size parameters.
+ * nscd/nscd.h (struct database_dyn): Add max_db_size field.
+ Define DEFAULT_MAX_DB_SIZE and DEFAULT_DATASIZE_PER_BUCKET.
+ Temporarily define TEMP_FAILURE_RETRY_VAL here.
+ * nscd/nscd_conf.c (nscd_parse_file): Parse max-db-size parameter
+ and add sanity checks for it.
+
+--- libc/nscd/mem.c 8 Aug 2005 20:38:42 -0000 1.6
++++ libc/nscd/mem.c 23 Aug 2005 23:15:28 -0000 1.7
+@@ -481,21 +481,26 @@ mempool_alloc (struct database_dyn *db,
+ if (! tried_resize)
+ {
+ /* Try to resize the database. Grow size of 1/8th. */
+- size_t new_data_size = db->head->data_size + db->head->data_size / 8;
++ size_t new_data_size = (db->head->data_size
++ + MAX (2 * len, db->head->data_size / 8));
+ size_t oldtotal = (sizeof (struct database_pers_head)
+ + db->head->module * sizeof (ref_t)
+ + db->head->data_size);
+ size_t newtotal = (sizeof (struct database_pers_head)
+ + db->head->module * sizeof (ref_t)
+ + new_data_size);
++ if (newtotal > db->max_db_size)
++ {
++ new_data_size -= newtotal - db->max_db_size;
++ newtotal = db->max_db_size;
++ }
+
+- if ((!db->mmap_used
+- || TEMP_FAILURE_RETRY_VAL (posix_fallocate (db->wr_fd,
+- oldtotal,
+- newtotal - oldtotal))
+- != 0)
+- /* Try to resize the mapping. Note: no MREMAP_MAYMOVE. */
+- && mremap (db->head, oldtotal, newtotal, 0) == 0)
++ if (db->mmap_used && newtotal > oldtotal
++ /* We only have to adjust the file size. The new pages
++ become magically available. */
++ && TEMP_FAILURE_RETRY_VAL (posix_fallocate (db->wr_fd, oldtotal,
++ newtotal
++ - oldtotal)) == 0)
+ {
+ db->head->data_size = new_data_size;
+ tried_resize = true;
+--- libc/nscd/nscd.conf 3 Oct 2004 21:09:23 -0000 1.10
++++ libc/nscd/nscd.conf 23 Aug 2005 23:17:32 -0000 1.11
+@@ -23,6 +23,7 @@
+ # check-files <service> <yes|no>
+ # persistent <service> <yes|no>
+ # shared <service> <yes|no>
++# max-db-size <service> <number bytes>
+ #
+ # Currently supported cache names (services): passwd, group, hosts
+ #
+@@ -45,6 +46,7 @@
+ check-files passwd yes
+ persistent passwd yes
+ shared passwd yes
++ max-db-size passwd 33554432
+
+ enable-cache group yes
+ positive-time-to-live group 3600
+@@ -53,6 +55,7 @@
+ check-files group yes
+ persistent group yes
+ shared group yes
++ max-db-size group 33554432
+
+ enable-cache hosts yes
+ positive-time-to-live hosts 3600
+@@ -61,3 +64,4 @@
+ check-files hosts yes
+ persistent hosts yes
+ shared hosts yes
++ max-db-size hosts 33554432
+--- libc/nscd/nscd.h 8 Aug 2005 18:54:44 -0000 1.22
++++ libc/nscd/nscd.h 23 Aug 2005 23:18:23 -0000 1.23
+@@ -63,6 +63,7 @@ struct database_dyn
+ int check_file;
+ int persistent;
+ int shared;
++ size_t max_db_size;
+ const char *filename;
+ const char *db_filename;
+ time_t file_mtime;
+@@ -99,6 +100,12 @@ struct database_dyn
+ #define BLOCK_ALIGN (1 << BLOCK_ALIGN_LOG)
+ #define BLOCK_ALIGN_M1 (BLOCK_ALIGN - 1)
+
++/* Default value for the maximum size of the database files. */
++#define DEFAULT_MAX_DB_SIZE (32 * 1024 * 1024)
++
++/* Number of bytes of data we initially reserve for each hash table bucket. */
++#define DEFAULT_DATASIZE_PER_BUCKET 1024
++
+
+ /* Global variables. */
+ extern struct database_dyn dbs[lastdb];
+--- libc/nscd/nscd_conf.c 3 Oct 2004 21:10:35 -0000 1.16
++++ libc/nscd/nscd_conf.c 23 Aug 2005 23:19:14 -0000 1.17
+@@ -171,6 +171,17 @@ nscd_parse_file (const char *fname, stru
+ if (cnt == lastdb)
+ dbg_log ("database %s is not supported\n", arg1);
+ }
++ else if (strcmp (entry, "max-db-size") == 0)
++ {
++ for (cnt = 0; cnt < lastdb; ++cnt)
++ if (strcmp (arg1, dbnames[cnt]) == 0)
++ {
++ dbs[cnt].max_db_size = atol (arg2);
++ break;
++ }
++ if (cnt == lastdb)
++ dbg_log ("database %s is not supported\n", arg1);
++ }
+ else if (strcmp (entry, "logfile") == 0)
+ set_logfile (arg1);
+ else if (strcmp (entry, "debug-level") == 0)
+@@ -293,6 +304,22 @@ cannot get current working directory: %s
+ if (max_nthreads < nthreads)
+ max_nthreads = nthreads;
+
++ for (cnt = 0; cnt < lastdb; ++cnt)
++ {
++ size_t datasize = (sizeof (struct database_pers_head)
++ + roundup (dbs[cnt].suggested_module
++ * sizeof (ref_t), ALIGN)
++ + (dbs[cnt].suggested_module
++ * DEFAULT_DATASIZE_PER_BUCKET));
++ if (datasize > dbs[cnt].max_db_size)
++ {
++ dbg_log (_("maximum file size for %s database too small"),
++ dbnames[cnt]);
++ dbs[cnt].max_db_size = datasize;
++ }
++
++ }
++
+ /* Free the buffer. */
+ free (line);
+ /* Close configuration file. */
+--- libc/nscd/connections.c 16 Aug 2005 18:07:46 -0000 1.75
++++ libc/nscd/connections.c 23 Aug 2005 23:12:00 -0000 1.76
+@@ -50,10 +50,6 @@
+ #include "selinux.h"
+
+
+-/* Number of bytes of data we initially reserve for each hash table bucket. */
+-#define DEFAULT_DATASIZE_PER_BUCKET 1024
+-
+-
+ /* Wrapper functions with error checking for standard functions. */
+ extern void *xmalloc (size_t n);
+ extern void *xcalloc (size_t n, size_t s);
+@@ -107,6 +103,7 @@ struct database_dyn dbs[lastdb] =
+ .persistent = 0,
+ .propagate = 1,
+ .shared = 0,
++ .max_db_size = DEFAULT_MAX_DB_SIZE,
+ .filename = "/etc/passwd",
+ .db_filename = _PATH_NSCD_PASSWD_DB,
+ .disabled_iov = &pwd_iov_disabled,
+@@ -123,6 +120,7 @@ struct database_dyn dbs[lastdb] =
+ .persistent = 0,
+ .propagate = 1,
+ .shared = 0,
++ .max_db_size = DEFAULT_MAX_DB_SIZE,
+ .filename = "/etc/group",
+ .db_filename = _PATH_NSCD_GROUP_DB,
+ .disabled_iov = &grp_iov_disabled,
+@@ -139,6 +137,7 @@ struct database_dyn dbs[lastdb] =
+ .persistent = 0,
+ .propagate = 0, /* Not used. */
+ .shared = 0,
++ .max_db_size = DEFAULT_MAX_DB_SIZE,
+ .filename = "/etc/hosts",
+ .db_filename = _PATH_NSCD_HOSTS_DB,
+ .disabled_iov = &hst_iov_disabled,
+@@ -478,8 +477,16 @@ nscd_init (void)
+ _("file size does not match"));
+ unlink (dbs[cnt].db_filename);
+ }
+- else if ((mem = mmap (NULL, total, PROT_READ | PROT_WRITE,
+- MAP_SHARED, fd, 0)) == MAP_FAILED)
++ /* Note we map with the maximum size allowed for the
++ database. This is likely much larger than the
++ actual file size. This is OK on most OSes since
++ extensions of the underlying file will
++ automatically translate more pages available for
++ memory access. */
++ else if ((mem = mmap (NULL, dbs[cnt].max_db_size,
++ PROT_READ | PROT_WRITE,
++ MAP_SHARED, fd, 0))
++ == MAP_FAILED)
+ goto fail_db;
+ else if (!verify_persistent_db (mem, &head, cnt))
+ {
+@@ -642,7 +649,8 @@ cannot create read-only descriptor for \
+ != sizeof (head))
+ || (TEMP_FAILURE_RETRY_VAL (posix_fallocate (fd, 0, total))
+ != 0)
+- || (mem = mmap (NULL, total, PROT_READ | PROT_WRITE,
++ || (mem = mmap (NULL, dbs[cnt].max_db_size,
++ PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0)) == MAP_FAILED)
+ {
+ unlink (dbs[cnt].db_filename);
--- /dev/null
+2005-08-08 Ulrich Drepper <drepper@redhat.com>
+
+ * nscd/cache.c (cache_add): Commit hash table and header to disk.
+
+--- libc/nscd/cache.c 30 Sep 2004 02:20:53 -0000 1.20
++++ libc/nscd/cache.c 8 Aug 2005 20:58:35 -0000 1.21
+@@ -169,6 +169,12 @@ cache_add (int type, const void *key, si
+ if (nentries > table->head->maxnentries)
+ table->head->maxnentries = nentries;
+
++ if (table->persistent)
++ // XXX async OK?
++ msync ((void *) table->head,
++ (char *) &table->head->array[hash] - (char *) table->head
++ + sizeof (ref_t), MS_ASYNC);
++
+ return 0;
+ }
+
--- /dev/null
+2006-04-27 Ulrich Drepper <drepper@redhat.com>
+
+ * nscd/connections.c (restart): If we want to switch back to the
+ old ID use setresuid and setresgid.
+ (finish_drop_privileges): Likewise.
+
+--- libc/nscd/connections.c 26 Apr 2006 17:28:50 -0000 1.85
++++ libc/nscd/connections.c 27 Apr 2006 20:33:32 -0000 1.87
+@@ -1124,7 +1124,7 @@ cannot open /proc/self/cmdline: %s; disa
+ /* Second, change back to the old user if we changed it. */
+ if (server_user != NULL)
+ {
+- if (setuid (old_uid) != 0)
++ if (setresuid (old_uid, old_uid, old_uid) != 0)
+ {
+ dbg_log (_("\
+ cannot change to old UID: %s; disabling paranoia mode"),
+@@ -1134,7 +1134,7 @@ cannot change to old UID: %s; disabling
+ return;
+ }
+
+- if (setgid (old_gid) != 0)
++ if (setresgid (old_gid, old_gid, old_gid) != 0)
+ {
+ dbg_log (_("\
+ cannot change to old GID: %s; disabling paranoia mode"),
+@@ -1853,14 +1853,23 @@ finish_drop_privileges (void)
+ error (EXIT_FAILURE, errno, _("setgroups failed"));
+ }
+
+- if (setgid (server_gid) == -1)
++ int res;
++ if (paranoia)
++ res = setresgid (server_gid, server_gid, old_gid);
++ else
++ res = setgid (server_gid);
++ if (res == -1)
+ {
+ dbg_log (_("Failed to run nscd as user '%s'"), server_user);
+ perror ("setgid");
+ exit (1);
+ }
+
+- if (setuid (server_uid) == -1)
++ if (paranoia)
++ res = setresuid (server_uid, server_uid, old_uid);
++ else
++ res = setuid (server_uid);
++ if (res == -1)
+ {
+ dbg_log (_("Failed to run nscd as user '%s'"), server_user);
+ perror ("setuid");
--- /dev/null
+2005-08-16 Ulrich Drepper <drepper@redhat.com>
+
+ * nscd/cache.c (prune_cache): Use stat64 not stat.
+ * nscd/connections.c (nscd_init): Likewise.
+
+--- libc/nscd/cache.c 8 Aug 2005 20:58:35 -0000 1.21
++++ libc/nscd/cache.c 16 Aug 2005 18:08:41 -0000 1.22
+@@ -203,9 +203,9 @@ prune_cache (struct database_dyn *table,
+ the entries also in this case. */
+ if (table->check_file)
+ {
+- struct stat st;
++ struct stat64 st;
+
+- if (stat (table->filename, &st) < 0)
++ if (stat64 (table->filename, &st) < 0)
+ {
+ char buf[128];
+ /* We cannot stat() the file, disable file checking if the
+--- libc/nscd/connections.c 9 Aug 2005 06:16:13 -0000 1.74
++++ libc/nscd/connections.c 16 Aug 2005 18:07:46 -0000 1.75
+@@ -710,9 +710,9 @@ cannot set socket to close on exec: %s;
+ if (dbs[cnt].check_file)
+ {
+ /* We need the modification date of the file. */
+- struct stat st;
++ struct stat64 st;
+
+- if (stat (dbs[cnt].filename, &st) < 0)
++ if (stat64 (dbs[cnt].filename, &st) < 0)
+ {
+ /* We cannot stat() the file, disable file checking. */
+ dbg_log (_("cannot stat() file `%s': %s"),
--- /dev/null
+2005-08-08 Ulrich Drepper <drepper@redhat.com>
+
+ * nscd/nscd_stat.c (receive_print_stats): Really print values of
+ thread number, paranoia, and restart interval the server is using.
+
+--- libc/nscd/nscd_stat.c 26 Jun 2005 18:26:28 -0000 1.14
++++ libc/nscd/nscd_stat.c 9 Aug 2005 05:45:03 -0000 1.15
+@@ -75,6 +75,10 @@ struct statdata
+ int debug_level;
+ time_t runtime;
+ unsigned long int client_queued;
++ int nthreads;
++ int max_nthreads;
++ int paranoia;
++ time_t restart_interval;
+ int ndbs;
+ struct dbstat dbs[lastdb];
+ #ifdef HAVE_SELINUX
+@@ -93,6 +97,10 @@ send_stats (int fd, struct database_dyn
+ data.debug_level = debug_level;
+ data.runtime = time (NULL) - start_time;
+ data.client_queued = client_queued;
++ data.nthreads = nthreads;
++ data.max_nthreads = max_nthreads;
++ data.paranoia = paranoia;
++ data.restart_interval = restart_interval;
+ data.ndbs = lastdb;
+
+ for (cnt = 0; cnt < lastdb; ++cnt)
+@@ -230,8 +238,9 @@ receive_print_stats (void)
+ "%15lu number of times clients had to wait\n"
+ "%15s paranoia mode enabled\n"
+ "%15lu restart internal\n"),
+- nthreads, max_nthreads, data.client_queued,
+- paranoia ? yesstr : nostr, (unsigned long int) restart_interval);
++ data.nthreads, data.max_nthreads, data.client_queued,
++ data.paranoia ? yesstr : nostr,
++ (unsigned long int) data.restart_interval);
+
+ for (i = 0; i < lastdb; ++i)
+ {
--- /dev/null
+--- libc/fedora/nsswitch.conf.jj 2004-09-22 21:17:12.000000000 -0400
++++ libc/fedora/nsswitch.conf 2005-07-04 12:20:44.000000000 -0400
+@@ -12,13 +12,14 @@
+ #
+ # Legal entries are:
+ #
+-# nisplus or nis+ Use NIS+ (NIS version 3)
+ # nis or yp Use NIS (NIS version 2), also called YP
+ # dns Use DNS (Domain Name Service)
+ # files Use the local files
+ # db Use the local database (.db) files
+ # compat Use NIS on compat mode
+ # hesiod Use Hesiod for user lookups
++# ldap Use LDAP (only if nss_ldap is installed)
++# nisplus or nis+ Use NIS+ (NIS version 3), unsupported
+ # [NOTFOUND=return] Stop searching if not found so far
+ #
+
+@@ -26,38 +27,32 @@
+ # looked up first in the databases
+ #
+ # Example:
+-#passwd: db files nisplus nis
+-#shadow: db files nisplus nis
+-#group: db files nisplus nis
++#passwd: db files ldap nis
++#shadow: db files ldap nis
++#group: db files ldap nis
+
+ passwd: files
+ shadow: files
+ group: files
+
+-#hosts: db files nisplus nis dns
++#hosts: db files ldap nis dns
+ hosts: files dns
+
+-# Example - obey only what nisplus tells us...
+-#services: nisplus [NOTFOUND=return] files
+-#networks: nisplus [NOTFOUND=return] files
+-#protocols: nisplus [NOTFOUND=return] files
+-#rpc: nisplus [NOTFOUND=return] files
+-#ethers: nisplus [NOTFOUND=return] files
+-#netmasks: nisplus [NOTFOUND=return] files
+-
+-bootparams: nisplus [NOTFOUND=return] files
++# Example - obey only what ldap tells us...
++#services: ldap [NOTFOUND=return] files
++#networks: ldap [NOTFOUND=return] files
++#protocols: ldap [NOTFOUND=return] files
++#rpc: ldap [NOTFOUND=return] files
++#ethers: ldap [NOTFOUND=return] files
+
++bootparams: files
+ ethers: files
+ netmasks: files
+ networks: files
+ protocols: files
+ rpc: files
+ services: files
+-
+-netgroup: nisplus
+-
+-publickey: nisplus
+-
+-automount: files nisplus
+-aliases: files nisplus
+-
++netgroup: files
++publickey: files
++automount: files
++aliases: files
--- /dev/null
+2005-09-12 Roland McGrath <roland@redhat.com>
+
+ [BZ #1331]
+ * malloc/obstack.h [!__STDC__] (obstack_int_grow_fast): Fix misnamed
+ macro argument.
+ Reported by Matej Vela <vela@debian.org>.
+
+--- libc/malloc/obstack.h 29 Jun 2004 16:15:03 -0000 1.20
++++ libc/malloc/obstack.h 12 Sep 2005 19:56:23 -0000 1.21
+@@ -446,7 +447,7 @@ __extension__ \
+ (((const void **) ((h)->next_free += sizeof (void *)))[-1] = (aptr))
+
+ # define obstack_int_grow_fast(h,aint) \
+- (((int *) ((h)->next_free += sizeof (int)))[-1] = (aptr))
++ (((int *) ((h)->next_free += sizeof (int)))[-1] = (aint))
+
+ # define obstack_blank(h,length) \
+ ( (h)->temp = (length), \
--- /dev/null
+--- libc/sysdeps/unix/sysv/linux/powerpc/kernel-features.h.jj 2003-01-30 05:24:37.000000000 -0500
++++ libc/sysdeps/unix/sysv/linux/powerpc/kernel-features.h 2003-09-23 18:28:07.000000000 -0400
+@@ -0,0 +1,15 @@
++/* In RHEL3, we can assume the shipped kernel, which is 2.4.21. */
++#include_next <kernel-features.h>
++
++#if !defined __ASSUME_NEW_PRCTL_SYSCALL && defined __powerpc__
++# define __ASSUME_NEW_PRCTL_SYSCALL 1
++#endif
++
++#if !defined __ASSUME_FIXED_CLONE_SYSCALL && defined __powerpc__ \
++ && !defined __powerpc64__
++# define __ASSUME_FIXED_CLONE_SYSCALL 1
++#endif
++
++#if !defined __ASSUME_NEW_RT_SIGRETURN_SYSCALL && defined __powerpc64__
++# define __ASSUME_NEW_RT_SIGRETURN_SYSCALL 1
++#endif
--- /dev/null
+2006-02-03 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/powerpc/fpu/bits/fenvinline.h (fegetround): Make asm
+ volatile.
+
+--- libc/sysdeps/powerpc/fpu/bits/fenvinline.h 6 Jul 2001 04:56:02 -0000 1.3
++++ libc/sysdeps/powerpc/fpu/bits/fenvinline.h 3 Feb 2006 22:28:37 -0000 1.4
+@@ -22,8 +23,9 @@
+ /* Inline definition for fegetround. */
+ # define fegetround() \
+ (__extension__ ({ int __fegetround_result; \
+- __asm__ ("mcrfs 7,7 ; mfcr %0" \
+- : "=r"(__fegetround_result) : : "cr7"); \
++ __asm__ __volatile__ \
++ ("mcrfs 7,7 ; mfcr %0" \
++ : "=r"(__fegetround_result) : : "cr7"); \
+ __fegetround_result & 3; }))
+
+ /* The weird 'i#*X' constraints on the following suppress a gcc
--- /dev/null
+2006-09-16 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/powerpc/powerpc32/register-dump.h (register_dump): Don't
+ write '\0' to the fd.
+ * sysdeps/mach/hurd/powerpc/register-dump.h (register_dump): Likewise.
+ * sysdeps/powerpc/powerpc64/register-dump.h (register_dump): Likewise.
+ Change regs to unsigned long pointer from unsigned int, fix fscr
+ offset.
+
+--- libc/sysdeps/powerpc/powerpc32/register-dump.h 5 Sep 2002 08:25:50 -0000 1.1
++++ libc/sysdeps/powerpc/powerpc32/register-dump.h 17 Sep 2006 15:53:05 -0000 1.2
+@@ -113,7 +113,7 @@ register_dump (int fd, struct sigcontext
+ }
+
+ /* Write the output. */
+- write (fd, buffer, sizeof(buffer));
++ write (fd, buffer, sizeof(buffer) - 1);
+ }
+
+
+--- libc/sysdeps/powerpc/powerpc64/register-dump.h 17 Sep 2002 23:50:02 -0000 1.1
++++ libc/sysdeps/powerpc/powerpc64/register-dump.h 17 Sep 2006 15:53:33 -0000 1.2
+@@ -34,7 +34,7 @@ gr16-19: 000000000000010% 00000000000001
+ gr20-23: 000000000000014% 000000000000015% 000000000000016% 000000000000017%\n\
+ gr24-27: 000000000000018% 000000000000019% 00000000000001a% 00000000000001b%\n\
+ gr28-31: 00000000000001c% 00000000000001d% 00000000000001e% 00000000000001f%\n\
+-fscr=0000071%\n\
++fscr=000000000000050%\n\
+ fp0-3: 000000000000030% 000000000000031% 000000000000032% 000000000000033%\n\
+ fp4-7: 000000000000034% 000000000000035% 000000000000036% 000000000000037%\n\
+ fp8-11: 000000000000038% 000000000000038% 00000000000003a% 00000000000003b%\n\
+@@ -104,7 +104,7 @@ register_dump (int fd, struct sigcontext
+ char buffer[sizeof(dumpform)];
+ char *bufferpos;
+ unsigned regno;
+- unsigned *regs = (unsigned *)(ctx->regs);
++ unsigned long *regs = (unsigned long *)(ctx->regs);
+
+ memcpy(buffer, dumpform, sizeof(dumpform));
+
+@@ -117,7 +117,7 @@ register_dump (int fd, struct sigcontext
+ }
+
+ /* Write the output. */
+- write (fd, buffer, sizeof(buffer));
++ write (fd, buffer, sizeof(buffer) - 1);
+ }
+
+
--- /dev/null
+2005-11-17 Steven Munroe <sjmunroe@us.ibm.com>
+
+ [BZ #1877]
+ * string/test-strncmp.c (do_test_limit): Handle zero length and
+ non-zero align values.
+ (test_main): Correct do_test_limit tests for 64-bit.
+
+2005-11-17 Steven Munroe <sjmunroe@us.ibm.com>
+
+ [BZ #1877]
+ * string/test-strncmp.c (do_test_limit): New function.
+ (do_test) Add cast to eliminate compiler warnings.
+ (do_random_tests) Add cast to eliminate compiler warnings.
+ (test_main) Add do_test_limit tests.
+ * sysdeps/powerpc/powerpc32/strncmp.S: Test length before unaligned
+ load.
+ * sysdeps/powerpc/powerpc64/strncmp.S: Likewise.
+
+--- libc/string/test-strncmp.c 17 Apr 2003 17:37:24 -0000 1.5
++++ libc/string/test-strncmp.c 18 Nov 2005 00:11:55 -0000 1.7
+@@ -86,6 +86,65 @@ do_one_test (impl_t *impl, const char *s
+ }
+
+ static void
++do_test_limit (size_t align1, size_t align2, size_t len, size_t n, int max_char,
++ int exp_result)
++{
++ size_t i, align_n;
++ char *s1, *s2;
++
++ if (n == 0)
++ {
++ s1 = (char*)(buf1 + page_size);
++ s2 = (char*)(buf2 + page_size);
++ if (HP_TIMING_AVAIL)
++ printf ("Length %4zd/%4zd:", len, n);
++
++ FOR_EACH_IMPL (impl, 0)
++ do_one_test (impl, s1, s2, n, 0);
++
++ if (HP_TIMING_AVAIL)
++ putchar ('\n');
++
++ return;
++ }
++
++ align1 &= 15;
++ align2 &= 15;
++ align_n = (page_size - n) & 15;
++
++ s1 = (char*)(buf1 + page_size - n);
++ s2 = (char*)(buf2 + page_size - n);
++
++ if (align1 < align_n)
++ s1 -= (align_n - align1);
++
++ if (align2 < align_n)
++ s2 -= (align_n - align2);
++
++ for (i = 0; i < n; i++)
++ s1[i] = s2[i] = 1 + 23 * i % max_char;
++
++ if (len < n)
++ {
++ s1[len] = 0;
++ s2[len] = 0;
++ if (exp_result < 0)
++ s2[len] = 32;
++ else if (exp_result > 0)
++ s1[len] = 64;
++ }
++
++ if (HP_TIMING_AVAIL)
++ printf ("Length %4zd/%4zd, alignment %2zd/%2zd:", len, n, align1, align2);
++
++ FOR_EACH_IMPL (impl, 0)
++ do_one_test (impl, s1, s2, n, exp_result);
++
++ if (HP_TIMING_AVAIL)
++ putchar ('\n');
++}
++
++static void
+ do_test (size_t align1, size_t align2, size_t len, size_t n, int max_char,
+ int exp_result)
+ {
+@@ -103,8 +162,8 @@ do_test (size_t align1, size_t align2, s
+ if (align2 + n + 1 >= page_size)
+ return;
+
+- s1 = buf1 + align1;
+- s2 = buf2 + align2;
++ s1 = (char*)(buf1 + align1);
++ s2 = (char*)(buf2 + align2);
+
+ for (i = 0; i < n; i++)
+ s1[i] = s2[i] = 1 + 23 * i % max_char;
+@@ -124,7 +183,7 @@ do_test (size_t align1, size_t align2, s
+ printf ("Length %4zd/%4zd, alignment %2zd/%2zd:", len, n, align1, align2);
+
+ FOR_EACH_IMPL (impl, 0)
+- do_one_test (impl, s1, s2, n, exp_result);
++ do_one_test (impl, (char*)s1, (char*)s2, n, exp_result);
+
+ if (HP_TIMING_AVAIL)
+ putchar ('\n');
+@@ -208,7 +267,7 @@ do_random_tests (void)
+
+ FOR_EACH_IMPL (impl, 1)
+ {
+- r = CALL (impl, p1 + align1, p2 + align2, size);
++ r = CALL (impl, (char*)(p1 + align1), (char*)(p2 + align2), size);
+ /* Test whether on 64-bit architectures where ABI requires
+ callee to promote has the promotion been done. */
+ asm ("" : "=g" (r) : "0" (r));
+@@ -271,6 +330,24 @@ test_main (void)
+ do_test (2 * i, i, 8 << i, 16 << i, 255, 0);
+ do_test (2 * i, i, 8 << i, 16 << i, 255, 1);
+ }
++
++ do_test_limit (0, 0, 0, 0, 127, 0);
++ do_test_limit (4, 0, 21, 20, 127, 0);
++ do_test_limit (0, 4, 21, 20, 127, 0);
++ do_test_limit (8, 0, 25, 24, 127, 0);
++ do_test_limit (0, 8, 25, 24, 127, 0);
++
++ for (i = 0; i < 8; ++i)
++ {
++ do_test_limit (0, 0, 17 - i, 16 - i, 127, 0);
++ do_test_limit (0, 0, 17 - i, 16 - i, 255, 0);
++ do_test_limit (0, 0, 15 - i, 16 - i, 127, 0);
++ do_test_limit (0, 0, 15 - i, 16 - i, 127, 1);
++ do_test_limit (0, 0, 15 - i, 16 - i, 127, -1);
++ do_test_limit (0, 0, 15 - i, 16 - i, 255, 0);
++ do_test_limit (0, 0, 15 - i, 16 - i, 255, 1);
++ do_test_limit (0, 0, 15 - i, 16 - i, 255, -1);
++ }
+
+ do_random_tests ();
+ return ret;
+--- libc/sysdeps/powerpc/powerpc32/strncmp.S 3 Nov 2003 17:38:35 -0000 1.1
++++ libc/sysdeps/powerpc/powerpc32/strncmp.S 17 Nov 2005 21:14:37 -0000 1.2
+@@ -47,6 +47,7 @@ EALIGN (BP_SYM(strncmp), 4, 0)
+ lis r7F7F, 0x7f7f
+ dcbt 0,rSTR2
+ clrlwi. rTMP, rTMP, 30
++ cmplwi cr1, rN, 0
+ lis rFEFE, -0x101
+ bne L(unaligned)
+ /* We are word alligned so set up for two loops. first a word
+@@ -54,7 +55,8 @@ EALIGN (BP_SYM(strncmp), 4, 0)
+ srwi. rTMP, rN, 2
+ clrlwi rN, rN, 30
+ addi rFEFE, rFEFE, -0x101
+- addi r7F7F, r7F7F, 0x7f7f
++ addi r7F7F, r7F7F, 0x7f7f
++ cmplwi cr1, rN, 0
+ beq L(unaligned)
+
+ mtctr rTMP /* Power4 wants mtctr 1st in dispatch group. */
+@@ -122,16 +124,19 @@ L(tail):
+ addi rSTR1, rSTR1, 4
+ bne- cr1, L(different)
+ addi rSTR2, rSTR2, 4
++ cmplwi cr1, rN, 0
+ L(unaligned):
+ mtctr rN /* Power4 wants mtctr 1st in dispatch group */
+- cmpwi rN,0
+- lbz rWORD1, 0(rSTR1)
+- lbz rWORD2, 0(rSTR2)
+- bgt L(u1)
++ bgt cr1, L(uz)
+ L(ux):
+ li rRTN, 0
+ blr
+-
++ .align 4
++L(uz):
++ lbz rWORD1, 0(rSTR1)
++ lbz rWORD2, 0(rSTR2)
++ nop
++ b L(u1)
+ L(u0):
+ lbzu rWORD2, 1(rSTR2)
+ L(u1):
+--- libc/sysdeps/powerpc/powerpc64/strncmp.S 6 Oct 2004 22:08:54 -0000 1.2
++++ libc/sysdeps/powerpc/powerpc64/strncmp.S 17 Nov 2005 21:14:37 -0000 1.3
+@@ -48,6 +48,7 @@ EALIGN (BP_SYM(strncmp), 4, 0)
+ lis r7F7F, 0x7f7f
+ dcbt 0,rSTR2
+ clrldi. rTMP, rTMP, 61
++ cmpldi cr1, rN, 0
+ lis rFEFE, -0x101
+ bne L(unaligned)
+ /* We are doubleword alligned so set up for two loops. first a double word
+@@ -55,7 +56,8 @@ EALIGN (BP_SYM(strncmp), 4, 0)
+ srdi. rTMP, rN, 3
+ clrldi rN, rN, 61
+ addi rFEFE, rFEFE, -0x101
+- addi r7F7F, r7F7F, 0x7f7f
++ addi r7F7F, r7F7F, 0x7f7f
++ cmpldi cr1, rN, 0
+ beq L(unaligned)
+
+ mtctr rTMP /* Power4 wants mtctr 1st in dispatch group. */
+@@ -126,16 +128,19 @@ L(tail):
+ addi rSTR1, rSTR1, 8
+ bne- cr1, L(different)
+ addi rSTR2, rSTR2, 8
++ cmpldi cr1, rN, 0
+ L(unaligned):
+ mtctr rN /* Power4 wants mtctr 1st in dispatch group */
+- cmpdi rN,0
+- lbz rWORD1, 0(rSTR1)
+- lbz rWORD2, 0(rSTR2)
+- bgt L(u1)
++ bgt cr1, L(uz)
+ L(ux):
+ li rRTN, 0
+ blr
+-
++ .align 4
++L(uz):
++ lbz rWORD1, 0(rSTR1)
++ lbz rWORD2, 0(rSTR2)
++ nop
++ b L(u1)
+ L(u0):
+ lbzu rWORD2, 1(rSTR2)
+ L(u1):
--- /dev/null
+2006-10-02 Ulrich Drepper <drepper@redhat.com>
+
+ * elf/rtld.c (dl_main): Don't use prelinking if LD_DYNAMIC_WEAK is
+ used.
+
+--- libc/elf/rtld.c 29 Sep 2006 16:56:15 -0000 1.363
++++ libc/elf/rtld.c 2 Oct 2006 18:24:37 -0000 1.364
+@@ -2087,7 +2087,8 @@ ERROR: ld.so: object '%s' cannot be load
+ }
+
+ if (main_map->l_info[ADDRIDX (DT_GNU_LIBLIST)]
+- && ! __builtin_expect (GLRO(dl_profile) != NULL, 0))
++ && ! __builtin_expect (GLRO(dl_profile) != NULL, 0)
++ && ! __builtin_expect (GLRO(dl_dynamic_weak), 0))
+ {
+ ElfW(Lib) *liblist, *liblistend;
+ struct link_map **r_list, **r_listend, *l;
--- /dev/null
+2007-05-06 Ulrich Drepper <drepper@redhat.com>
+
+ * stdio-common/vfprintf.c (process_string_arg): Optimize
+ ridiculous precision in wide char code printing multi-byte string.
+ Reported by Jim Meyering <jim@meyering.net>.
+
+--- libc/stdio-common/vfprintf.c 5 May 2007 04:41:35 -0000 1.138
++++ libc/stdio-common/vfprintf.c 7 May 2007 03:43:55 -0000 1.139
+@@ -1026,10 +1026,11 @@ vfprintf (FILE *s, const CHAR_T *format,
+ const char *mbs = (const char *) string; \
+ mbstate_t mbstate; \
+ \
+- len = prec != -1 ? (size_t) prec : strlen (mbs); \
++ len = prec != -1 ? __strnlen (mbs, (size_t) prec) : strlen (mbs); \
+ \
+ /* Allocate dynamically an array which definitely is long \
+- enough for the wide character version. */ \
++ enough for the wide character version. Each byte in the \
++ multi-byte string can produce at most one wide character. */ \
+ if (__libc_use_alloca (len * sizeof (wchar_t))) \
+ string = (CHAR_T *) alloca (len * sizeof (wchar_t)); \
+ else if ((string = (CHAR_T *) malloc (len * sizeof (wchar_t))) \
--- /dev/null
+2007-06-22 Jakub Jelinek <jakub@redhat.com>
+
+ * pthread_getattr_np.c (pthread_getattr_np): Clear cpuset and
+ cpusetsize if pthread_getaffinity_np failed with ENOSYS.
+
+--- libc/nptl/pthread_getattr_np.c 30 May 2007 04:42:57 -0000 1.13
++++ libc/nptl/pthread_getattr_np.c 22 Jun 2007 22:13:52 -0000 1.14
+@@ -164,8 +164,12 @@ pthread_getattr_np (thread_id, attr)
+ {
+ free (cpuset);
+ if (ret == ENOSYS)
+- /* There is no such functionality. */
+- ret = 0;
++ {
++ /* There is no such functionality. */
++ ret = 0;
++ iattr->cpuset = NULL;
++ iattr->cpusetsize = 0;
++ }
+ }
+ }
+
--- /dev/null
+--- libc/sysdeps/unix/sysv/linux/sys/quota.h 2005-10-17 10:03:21.000000000 +0200
++++ libc/sysdeps/unix/sysv/linux/sys/quota.h 2005-11-17 11:39:51.000000000 +0100
+@@ -42,10 +42,10 @@
+
+ /*
+ * Select between different incompatible quota versions.
+- * Default to the version used by Linux kernel version 2.4.22
+- * or later. */
++ * Default to the version used by Linux kernel version 2.4.21
++ * or earlier (in RHEL version 1 is AS2.1, version 2 is RHEL3 and later). */
+ #ifndef _LINUX_QUOTA_VERSION
+-# define _LINUX_QUOTA_VERSION 2
++# define _LINUX_QUOTA_VERSION 1
+ #endif
+
+ /*
--- /dev/null
+2005-10-17 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/unix/sysv/linux/readonly-area.c (__readonly_area): Also
+ allow EACCES errors when opening /proc for now.
+
+2005-10-06 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/unix/sysv/linux/readonly-area.c: Allow fopen to fail because
+ the file does not exist.
+
+--- libc/sysdeps/unix/sysv/linux/readonly-area.c 2004/10/18 04:17:11 1.1
++++ libc/sysdeps/unix/sysv/linux/readonly-area.c 2005/10/17 15:51:01 1.4
+@@ -16,6 +16,7 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
++#include <errno.h>
+ #include <stdint.h>
+ #include <stdio.h>
+ #include <stdio_ext.h>
+@@ -33,10 +34,19 @@
+
+ FILE *fp = fopen ("/proc/self/maps", "rc");
+ if (fp == NULL)
+- /* We don't know. Returning 1 here means that programs using %n
+- and -D_FORTIFY_SOURCE=2 will work even when /proc is not mounted,
+- but will allow %n even in writable areas. */
+- return 1;
++ {
++ /* It is the system administrator's choice to not have /proc
++ available to this process (e.g., because it runs in a chroot
++ environment. Don't fail in this case. */
++ if (errno == ENOENT
++ /* The kernel has a bug in that a process is denied access
++ to the /proc filesystem if it is set[ug]id. There has
++ been no willingness to change this in the kernel so
++ far. */
++ || errno == EACCES)
++ return 1;
++ return -1;
++ }
+
+ /* We need no locking. */
+ __fsetlocking (fp, FSETLOCKING_BYCALLER);
--- /dev/null
+2005-09-06 Ulrich Drepper <drepper@redhat.com>
+
+ * include/regex.h: Remove use of _RE_ARGS.
+
+2005-08-20 Paul Eggert <eggert@cs.ucla.edu>
+
+ * posix/regex.h (_RE_ARGS): Remove. No longer needed, since we assume
+ C89 or better. All uses removed.
+
+--- libc/posix/regex.h 18 Aug 2005 06:42:25 -0000 1.34
++++ libc/posix/regex.h 6 Sep 2005 18:17:56 -0000 1.35
+@@ -452,38 +452,21 @@ typedef struct
+ \f
+ /* Declarations for routines. */
+
+-/* To avoid duplicating every routine declaration -- once with a
+- prototype (if we are ANSI), and once without (if we aren't) -- we
+- use the following macro to declare argument types. This
+- unfortunately clutters up the declarations a bit, but I think it's
+- worth it. */
+-
+-#if __STDC__
+-
+-# define _RE_ARGS(args) args
+-
+-#else /* not __STDC__ */
+-
+-# define _RE_ARGS(args) ()
+-
+-#endif /* not __STDC__ */
+-
+ /* Sets the current default syntax to SYNTAX, and return the old syntax.
+ You can also simply assign to the `re_syntax_options' variable. */
+-extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
++extern reg_syntax_t re_set_syntax (reg_syntax_t syntax);
+
+ /* Compile the regular expression PATTERN, with length LENGTH
+ and syntax given by the global `re_syntax_options', into the buffer
+ BUFFER. Return NULL if successful, and an error string if not. */
+-extern const char *re_compile_pattern
+- _RE_ARGS ((const char *pattern, size_t length,
+- struct re_pattern_buffer *buffer));
++extern const char *re_compile_pattern (const char *pattern, size_t length,
++ struct re_pattern_buffer *buffer);
+
+
+ /* Compile a fastmap for the compiled pattern in BUFFER; used to
+ accelerate searches. Return 0 if successful and -2 if was an
+ internal error. */
+-extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
++extern int re_compile_fastmap (struct re_pattern_buffer *buffer);
+
+
+ /* Search in the string STRING (with length LENGTH) for the pattern
+@@ -491,31 +474,29 @@ extern int re_compile_fastmap _RE_ARGS (
+ characters. Return the starting position of the match, -1 for no
+ match, or -2 for an internal error. Also return register
+ information in REGS (if REGS and BUFFER->no_sub are nonzero). */
+-extern int re_search
+- _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+- int length, int start, int range, struct re_registers *regs));
++extern int re_search (struct re_pattern_buffer *buffer, const char *string,
++ int length, int start, int range,
++ struct re_registers *regs);
+
+
+ /* Like `re_search', but search in the concatenation of STRING1 and
+ STRING2. Also, stop searching at index START + STOP. */
+-extern int re_search_2
+- _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+- int length1, const char *string2, int length2,
+- int start, int range, struct re_registers *regs, int stop));
++extern int re_search_2 (struct re_pattern_buffer *buffer, const char *string1,
++ int length1, const char *string2, int length2,
++ int start, int range, struct re_registers *regs,
++ int stop);
+
+
+ /* Like `re_search', but return how many characters in STRING the regexp
+ in BUFFER matched, starting at position START. */
+-extern int re_match
+- _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+- int length, int start, struct re_registers *regs));
++extern int re_match (struct re_pattern_buffer *buffer, const char *string,
++ int length, int start, struct re_registers *regs);
+
+
+ /* Relates to `re_match' as `re_search_2' relates to `re_search'. */
+-extern int re_match_2
+- _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+- int length1, const char *string2, int length2,
+- int start, struct re_registers *regs, int stop));
++extern int re_match_2 (struct re_pattern_buffer *buffer, const char *string1,
++ int length1, const char *string2, int length2,
++ int start, struct re_registers *regs, int stop);
+
+
+ /* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+@@ -530,15 +511,15 @@ extern int re_match_2
+ Unless this function is called, the first search or match using
+ PATTERN_BUFFER will allocate its own register data, without
+ freeing the old data. */
+-extern void re_set_registers
+- _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
+- unsigned num_regs, regoff_t *starts, regoff_t *ends));
++extern void re_set_registers (struct re_pattern_buffer *buffer,
++ struct re_registers *regs, unsigned num_regs,
++ regoff_t *starts, regoff_t *ends);
+
+ #if defined _REGEX_RE_COMP || defined _LIBC
+ # ifndef _CRAY
+ /* 4.2 bsd compatibility. */
+-extern char *re_comp _RE_ARGS ((const char *));
+-extern int re_exec _RE_ARGS ((const char *));
++extern char *re_comp (const char *);
++extern int re_exec (const char *);
+ # endif
+ #endif
+
+@@ -563,19 +544,19 @@ extern int re_exec _RE_ARGS ((const char
+ #endif
+
+ /* POSIX compatibility. */
+-extern int regcomp _RE_ARGS ((regex_t *__restrict __preg,
+- const char *__restrict __pattern,
+- int __cflags));
+-
+-extern int regexec _RE_ARGS ((const regex_t *__restrict __preg,
+- const char *__restrict __string, size_t __nmatch,
+- regmatch_t __pmatch[__restrict_arr],
+- int __eflags));
++extern int regcomp (regex_t *__restrict __preg,
++ const char *__restrict __pattern,
++ int __cflags);
++
++extern int regexec (const regex_t *__restrict __preg,
++ const char *__restrict __string, size_t __nmatch,
++ regmatch_t __pmatch[__restrict_arr],
++ int __eflags);
+
+-extern size_t regerror _RE_ARGS ((int __errcode, const regex_t *__preg,
+- char *__errbuf, size_t __errbuf_size));
++extern size_t regerror (int __errcode, const regex_t *__preg,
++ char *__errbuf, size_t __errbuf_size);
+
+-extern void regfree _RE_ARGS ((regex_t *__preg));
++extern void regfree (regex_t *__preg);
+
+
+ #ifdef __cplusplus
+--- libc/include/regex.h 8 Dec 1998 13:10:59 -0000 1.2
++++ libc/include/regex.h 6 Sep 2005 20:37:50 -0000 1.3
+@@ -2,45 +2,42 @@
+ #include <posix/regex.h>
+
+ /* Document internal interfaces. */
+-extern reg_syntax_t __re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
++extern reg_syntax_t __re_set_syntax (reg_syntax_t syntax);
+
+-extern const char *__re_compile_pattern
+- _RE_ARGS ((const char *pattern, size_t length,
+- struct re_pattern_buffer *buffer));
++extern const char *__re_compile_pattern (const char *pattern, size_t length,
++ struct re_pattern_buffer *buffer);
+
+-extern int __re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
++extern int __re_compile_fastmap (struct re_pattern_buffer *buffer);
+
+-extern int __re_search
+- _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+- int length, int start, int range, struct re_registers *regs));
++extern int __re_search (struct re_pattern_buffer *buffer, const char *string,
++ int length, int start, int range,
++ struct re_registers *regs);
+
+ extern int __re_search_2
+- _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+- int length1, const char *string2, int length2,
+- int start, int range, struct re_registers *regs, int stop));
++ (struct re_pattern_buffer *buffer, const char *string1,
++ int length1, const char *string2, int length2,
++ int start, int range, struct re_registers *regs, int stop);
+
+ extern int __re_match
+- _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+- int length, int start, struct re_registers *regs));
++ (struct re_pattern_buffer *buffer, const char *string,
++ int length, int start, struct re_registers *regs);
+
+ extern int __re_match_2
+- _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+- int length1, const char *string2, int length2,
+- int start, struct re_registers *regs, int stop));
++ (struct re_pattern_buffer *buffer, const char *string1,
++ int length1, const char *string2, int length2,
++ int start, struct re_registers *regs, int stop);
+
+ extern void __re_set_registers
+- _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
+- unsigned num_regs, regoff_t *starts, regoff_t *ends));
++ (struct re_pattern_buffer *buffer, struct re_registers *regs,
++ unsigned num_regs, regoff_t *starts, regoff_t *ends);
+
+-extern int __regcomp _RE_ARGS ((regex_t *__preg, const char *__pattern,
+- int __cflags));
++extern int __regcomp (regex_t *__preg, const char *__pattern, int __cflags);
+
+-extern int __regexec _RE_ARGS ((const regex_t *__preg,
+- const char *__string, size_t __nmatch,
+- regmatch_t __pmatch[], int __eflags));
++extern int __regexec (const regex_t *__preg, const char *__string,
++ size_t __nmatch, regmatch_t __pmatch[], int __eflags);
+
+-extern size_t __regerror _RE_ARGS ((int __errcode, const regex_t *__preg,
+- char *__errbuf, size_t __errbuf_size));
++extern size_t __regerror (int __errcode, const regex_t *__preg,
++ char *__errbuf, size_t __errbuf_size);
+
+-extern void __regfree _RE_ARGS ((regex_t *__preg));
++extern void __regfree (regex_t *__preg);
+ #endif
--- /dev/null
+2005-08-21 Ulrich Drepper <drepper@redhat.com>
+
+ * resolv/res_send.c (send_vc): Pass correct sockaddr size to connect.
+
+--- libc/resolv/res_send.c 8 Jul 2005 06:49:08 -0000 1.42
++++ libc/resolv/res_send.c 21 Aug 2005 23:07:10 -0000 1.43
+@@ -654,7 +654,9 @@ send_vc(res_state statp,
+ }
+ __set_errno (0);
+ if (connect(statp->_vcsock, (struct sockaddr *)nsap,
+- sizeof *nsap) < 0) {
++ nsap->sin6_family == AF_INET
++ ? sizeof (struct sockaddr_in)
++ : sizeof (struct sockaddr_in6)) < 0) {
+ *terrno = errno;
+ Aerror(statp, stderr, "connect/vc", errno,
+ (struct sockaddr *) nsap);
--- /dev/null
+2006-02-28 Roland McGrath <roland@redhat.com>
+
+ * libio/genops.c: Include <sched.h> for __sched_yield decl.
+
+2006-02-23 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/generic/sched_yield.c (__sched_yield): Add libc_hidden_def.
+ * sysdeps/mach/sched_yield.c (__sched_yield): Likewise.
+
+2006-01-14 Jakub Jelinek <jakub@redhat.com>
+
+ * libio/libio.h (_IO_vfscanf, _IO_vfprintf): Remove __THROW.
+ (_IO_vfwscanf, _IO_vfwprintf): Likewise.
+ * libio/libioP.h (_IO_vdprintf): Likewise.
+
+2006-01-11 Ulrich Drepper <drepper@redhat.com>
+
+ * libio/memstream.c (_IO_mem_finish): Fix potential memory leak if
+ realloc fails.
+
+ * include/sched.h: Add libc_hidden_proto for __sched_yield.
+
+ * libio/genops.c (_IO_unbuffer_write): Give concurrently running
+ threads the chance to work correctly by trying to lock the stream.
+ If this does not work, proceed without locking.
+
+2006-01-10 Ulrich Drepper <drepper@redhat.com>
+
+ * libio/genops.c (_IO_unbuffer_write): Don't always free the
+ buffer. This is not necessary except in debug mode. If we don't
+ free the buffer but the FILE structure to a list.
+ (buffer_free): New function. Free buffers or tell _IO_unbuffer_write
+ to do so.
+ * libio/libio.h (struct _IO_FILE): Add new members to keep track
+ of which buffers have to be freed.
+
+--- libc/libio/genops.c 14 Sep 2004 04:24:44 -0000
++++ libc/libio/genops.c 11 Jan 2006 08:09:39 -0000
+@@ -34,5 +34,8 @@
+ #endif
+ #include <string.h>
++#ifdef _LIBC
++#include <sched.h>
++#endif
+
+ #ifdef _IO_MTSAFE_IO
+ static _IO_lock_t list_all_lock = _IO_lock_initializer;
+@@ -657,6 +658,7 @@ _IO_no_init (fp, flags, orientation, wd,
+ fp->_wide_data->_wide_vtable = jmp;
+ }
+ #endif
++ fp->_freeres_list = NULL;
+ }
+
+ int
+@@ -914,10 +916,27 @@ INTDEF(_IO_flush_all_linebuffered)
+ weak_alias (_IO_flush_all_linebuffered, _flushlbf)
+ #endif
+
++
++/* The following is a bit tricky. In general, we want to unbuffer the
++ streams so that all output which follows is seen. If we are not
++ looking for memory leaks it does not make much sense to free the
++ actual buffer because this will happen anyway once the program
++ terminated. If we do want to look for memory leaks we have to free
++ the buffers. Whether something is freed is determined by the
++ function sin the libc_freeres section. Those are called as part of
++ the atexit routine, just like _IO_cleanup. The problem is we do
++ not know whether the freeres code is called first or _IO_cleanup.
++ if the former is the case, we set the DEALLOC_BUFFER variable to
++ true and _IO_unbuffer_write will take care of the rest. If
++ _IO_unbuffer_write is called first we add the streams to a list
++ which the freeres function later can walk through. */
+ static void _IO_unbuffer_write (void);
+
++static bool dealloc_buffers;
++static _IO_FILE *freeres_list;
++
+ static void
+-_IO_unbuffer_write ()
++_IO_unbuffer_write (void)
+ {
+ struct _IO_FILE *fp;
+ for (fp = (_IO_FILE *) INTUSE(_IO_list_all); fp; fp = fp->_chain)
+@@ -927,7 +946,32 @@ _IO_unbuffer_write ()
+ || (fp->_flags & _IO_IS_APPENDING))
+ /* Iff stream is un-orientated, it wasn't used. */
+ && fp->_mode != 0)
+- _IO_SETBUF (fp, NULL, 0);
++ {
++ int cnt;
++#define MAXTRIES 2
++ for (cnt = 0; cnt < MAXTRIES; ++cnt)
++ if (_IO_lock_trylock (*fp->_lock) == 0)
++ break;
++ else
++ /* Give the other thread time to finish up its use of the
++ stream. */
++ __sched_yield ();
++
++ if (! dealloc_buffers && !(fp->_flags & _IO_USER_BUF))
++ {
++ fp->_flags |= _IO_USER_BUF;
++
++ fp->_freeres_list = freeres_list;
++ freeres_list = fp;
++ fp->_freeres_buf = fp->_IO_buf_base;
++ fp->_freeres_size = _IO_blen (fp);
++ }
++
++ _IO_SETBUF (fp, NULL, 0);
++
++ if (cnt < MAXTRIES)
++ _IO_lock_unlock (*fp->_lock);
++ }
+
+ /* Make sure that never again the wide char functions can be
+ used. */
+@@ -935,11 +979,25 @@ _IO_unbuffer_write ()
+ }
+ }
+
++
++libc_freeres_fn (buffer_free)
++{
++ dealloc_buffers = true;
++
++ while (freeres_list != NULL)
++ {
++ FREE_BUF (freeres_list->_freeres_buf, freeres_list->_freeres_size);
++
++ freeres_list = freeres_list->_freeres_list;
++ }
++}
++
++
+ int
+ _IO_cleanup ()
+ {
+ /* We do *not* want locking. Some threads might use streams but
+- that is there problem, we flush them underneath them. */
++ that is their problem, we flush them underneath them. */
+ int result = _IO_flush_all_lockp (0);
+
+ /* We currently don't have a reliable mechanism for making sure that
+--- libc/libio/libio.h 17 Feb 2005 01:16:15 -0000 1.61
++++ libc/libio/libio.h 11 Jan 2006 07:47:46 -0000 1.63
+@@ -317,13 +317,19 @@ struct _IO_FILE_complete
+ /* Wide character stream stuff. */
+ struct _IO_codecvt *_codecvt;
+ struct _IO_wide_data *_wide_data;
++ struct _IO_FILE *_freeres_list;
++ void *_freeres_buf;
++ size_t _freeres_size;
+ # else
+ void *__pad1;
+ void *__pad2;
++ void *__pad3;
++ void *__pad4;
++ size_t __pad5;
+ # endif
+ int _mode;
+ /* Make sure we don't get into trouble again. */
+- char _unused2[15 * sizeof (int) - 2 * sizeof (void *)];
++ char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
+ #endif
+ };
+
+@@ -472,9 +478,9 @@ extern int _IO_ftrylockfile (_IO_FILE *)
+ #endif /* !_IO_MTSAFE_IO */
+
+ extern int _IO_vfscanf (_IO_FILE * __restrict, const char * __restrict,
+- _IO_va_list, int *__restrict) __THROW;
++ _IO_va_list, int *__restrict);
+ extern int _IO_vfprintf (_IO_FILE *__restrict, const char *__restrict,
+- _IO_va_list) __THROW;
++ _IO_va_list);
+ extern _IO_ssize_t _IO_padn (_IO_FILE *, int, _IO_ssize_t) __THROW;
+ extern _IO_size_t _IO_sgetn (_IO_FILE *, void *, _IO_size_t) __THROW;
+
+@@ -521,8 +527,8 @@ weak_extern (_IO_stdin_used);
+ # endif
+
+ extern int _IO_vfwscanf (_IO_FILE * __restrict, const wchar_t * __restrict,
+- _IO_va_list, int *__restrict) __THROW;
++ _IO_va_list, int *__restrict);
+ extern int _IO_vfwprintf (_IO_FILE *__restrict, const wchar_t *__restrict,
+- _IO_va_list) __THROW;
++ _IO_va_list);
+ extern _IO_ssize_t _IO_wpadn (_IO_FILE *, wint_t, _IO_ssize_t) __THROW;
+ extern void _IO_free_wbackup_area (_IO_FILE *) __THROW;
+ #endif
+--- libc/libio/memstream.c 14 Sep 2004 04:24:45 -0000 1.23
++++ libc/libio/memstream.c 11 Jan 2006 17:46:36 -0000 1.24
+@@ -140,9 +140,9 @@ _IO_mem_finish (fp, dummy)
+ {
+ (*mp->bufloc)[fp->_IO_write_ptr - fp->_IO_write_base] = '\0';
+ *mp->sizeloc = fp->_IO_write_ptr - fp->_IO_write_base;
+- }
+
+- fp->_IO_buf_base = NULL;
++ fp->_IO_buf_base = NULL;
++ }
+
+- INTUSE(_IO_default_finish) (fp, 0);
++ _IO_str_finish (fp, 0);
+ }
+--- libc/libio/libioP.h 19 Dec 2005 03:32:08 -0000 1.74
++++ libc/libio/libioP.h 14 Jan 2006 12:09:46 -0000 1.75
+@@ -649,7 +652,7 @@ extern void _IO_wstr_finish (_IO_FILE *,
+
+ extern int _IO_vasprintf (char **result_ptr, __const char *format,
+ _IO_va_list args) __THROW;
+-extern int _IO_vdprintf (int d, __const char *format, _IO_va_list arg) __THROW;
++extern int _IO_vdprintf (int d, __const char *format, _IO_va_list arg);
+ extern int _IO_vsnprintf (char *string, _IO_size_t maxlen,
+ __const char *format, _IO_va_list args) __THROW;
+
+--- libc/include/sched.h 3 Mar 2003 21:32:45 -0000 1.11
++++ libc/include/sched.h 11 Jan 2006 17:45:18 -0000 1.12
+@@ -10,6 +10,7 @@ extern int __sched_setscheduler (__pid_t
+ libc_hidden_proto (__sched_setscheduler)
+ extern int __sched_getscheduler (__pid_t __pid);
+ extern int __sched_yield (void);
++libc_hidden_proto (__sched_yield)
+ extern int __sched_get_priority_max (int __algorithm);
+ extern int __sched_get_priority_min (int __algorithm);
+ extern int __sched_rr_get_interval (__pid_t __pid, struct timespec *__t);
+--- libc/sysdeps/generic/sched_yield.c 14 Dec 2005 10:39:15 -0000 1.1
++++ libc/sysdeps/generic/sched_yield.c 23 Feb 2006 22:32:34 -0000 1.2
+@@ -28,6 +28,7 @@ __sched_yield (void)
+ return -1;
+ }
+ stub_warning (sched_yield)
++libc_hidden_def (__sched_yield)
+
+ weak_alias (__sched_yield, sched_yield)
+ #include <stub-tag.h>
+--- libc/sysdeps/mach/sched_yield.c 6 Jul 2001 04:55:56 -0000 1.2
++++ libc/sysdeps/mach/sched_yield.c 23 Feb 2006 22:32:37 -0000 1.3
+@@ -28,4 +28,5 @@ __sched_yield (void)
+ (void) __swtch ();
+ return 0;
+ }
++libc_hidden_def (__sched_yield)
+ weak_alias (__sched_yield, sched_yield)
--- /dev/null
+2007-03-22 Jakub Jelinek <jakub@redhat.com>
+
+ * config.h.in (HAVE_LIBCAP): Add.
+ * nscd/selinux.h: Include sys/capability.h rather than non-existent
+ sys/capabilities.h.
+ * nscd/selinux.c (preserve_capabilities): Use cap_free instead of
+ free_caps. Cast away const from 4th cap_set_flag argument.
+
+2006-04-26 James Antill <james.antill@redhat.com>
+ Ulrich Drepper <drepper@redhat.com>
+
+ * config.make.in: Add have-libcap.
+ * configure.in: Check for libcap.
+ * nscd/Makefile (selinux-LIBS): Add -lcap if possible.
+ * nscd/connections.c (finish_drop_privileges): When libcap is available
+ call preserve_capabilities and install_real_capabilities.
+ * nscd/selinux.c: Define preserve_capabilities and
+ install_real_capabilities.
+ * nscd/selinux.h: Declare preserve_capabilities and
+ install_real_capabilities.
+
+--- libc/configure.in 1 Mar 2006 09:17:40 -0000 1.459
++++ libc/configure.in 26 Apr 2006 16:23:49 -0000 1.460
+@@ -1982,6 +1982,13 @@ if test "x$have_selinux" = xyes; then
+ AC_DEFINE(HAVE_LIBAUDIT, 1, [SELinux libaudit support])
+ fi
+ AC_SUBST(have_libaudit)
++
++ # See if we have the libcap library
++ AC_CHECK_LIB(cap, cap_init, have_libcap=yes, have_libcap=no)
++ if test "x$have_libcap" = xyes; then
++ AC_DEFINE(HAVE_LIBCAP, 1, [SELinux libcap support])
++ fi
++ AC_SUBST(have_libcap)
+ fi
+ AC_SUBST(have_selinux)
+
+--- libc/config.make.in 28 Feb 2006 07:05:38 -0000 1.117
++++ libc/config.make.in 26 Apr 2006 16:22:38 -0000 1.118
+@@ -61,6 +61,7 @@ have-fpie = @libc_cv_fpie@
+ have-ssp = @libc_cv_ssp@
+ have-selinux = @have_selinux@
+ have-libaudit = @have_libaudit@
++have-libcap = @have_libcap@
+ have-cc-with-libunwind = @libc_cv_cc_with_libunwind@
+ fno-unit-at-a-time = @fno_unit_at_a_time@
+ bind-now = @bindnow@
+--- libc/configure 1 Mar 2006 09:17:40 -0000 1.449
++++ libc/configure 26 Apr 2006 16:13:55 -0000 1.450
+@@ -313,7 +313,7 @@ ac_includes_default="\
+ # include <unistd.h>
+ #endif"
+
+-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS with_fp with_cvs enable_check_abi oldest_abi bindnow force_install all_warnings build build_cpu build_vendor build_os host host_cpu host_vendor host_os subdirs add_ons base_machine sysnames INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC OBJEXT BUILD_CC cross_compiling CPP CXX CXXFLAGS ac_ct_CXX AR OBJDUMP RANLIB ac_ct_RANLIB MIG AS LD PWD_P MAKE MSGFMT MAKEINFO SED AUTOCONF SYSINCLUDES libc_cv_gcc_static_libgcc BASH libc_cv_have_bash2 KSH libc_cv_have_ksh AWK PERL INSTALL_INFO BISON VERSIONING libc_cv_asm_protected_directive libc_cv_initfinit_array libc_cv_cc_with_libunwind libc_cv_z_nodelete libc_cv_z_nodlopen libc_cv_z_initfirst libc_cv_z_relro libc_cv_Bgroup libc_cv_libgcc_s_suffix libc_cv_as_needed ASFLAGS_config libc_cv_z_combreloc libc_cv_z_execstack libc_cv_fpie fno_unit_at_a_time libc_cv_have_initfini libc_cv_cpp_asm_debuginfo no_whole_archive exceptions LIBGD have_libaudit have_selinux EGREP sizeof_long_double libc_cv_gcc_unwind_find_fde uname_sysname uname_release uname_version old_glibc_headers libc_cv_slibdir libc_cv_localedir libc_cv_sysconfdir libc_cv_rootsbindir libc_cv_forced_unwind use_ldconfig ldd_rewrite_script gnu_ld gnu_as elf xcoff static shared pic_default profile omitfp bounded static_nss nopic_initfini DEFINES linux_doors mach_interface_list VERSION RELEASE LIBOBJS LTLIBOBJS'
++ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS with_fp with_cvs enable_check_abi oldest_abi bindnow force_install all_warnings build build_cpu build_vendor build_os host host_cpu host_vendor host_os subdirs add_ons base_machine sysnames INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC OBJEXT BUILD_CC cross_compiling CPP CXX CXXFLAGS ac_ct_CXX AR OBJDUMP RANLIB ac_ct_RANLIB MIG AS LD PWD_P MAKE MSGFMT MAKEINFO SED AUTOCONF SYSINCLUDES libc_cv_gcc_static_libgcc BASH libc_cv_have_bash2 KSH libc_cv_have_ksh AWK PERL INSTALL_INFO BISON VERSIONING libc_cv_asm_protected_directive libc_cv_initfinit_array libc_cv_cc_with_libunwind libc_cv_z_nodelete libc_cv_z_nodlopen libc_cv_z_initfirst libc_cv_z_relro libc_cv_Bgroup libc_cv_libgcc_s_suffix libc_cv_as_needed ASFLAGS_config libc_cv_z_combreloc libc_cv_z_execstack libc_cv_fpie fno_unit_at_a_time libc_cv_have_initfini libc_cv_cpp_asm_debuginfo no_whole_archive exceptions LIBGD have_libaudit have_libcap have_selinux EGREP sizeof_long_double libc_cv_gcc_unwind_find_fde uname_sysname uname_release uname_version old_glibc_headers libc_cv_slibdir libc_cv_localedir libc_cv_sysconfdir libc_cv_rootsbindir libc_cv_forced_unwind use_ldconfig ldd_rewrite_script gnu_ld gnu_as elf xcoff static shared pic_default profile omitfp bounded static_nss nopic_initfini DEFINES linux_doors mach_interface_list VERSION RELEASE LIBOBJS LTLIBOBJS'
+ ac_subst_files=''
+
+ # Initialize some variables set by options.
+@@ -6855,6 +6855,86 @@ _ACEOF
+
+ fi
+
++
++ # See if we have the libcap library
++ echo "$as_me:$LINENO: checking for cap_init in -lcap" >&5
++echo $ECHO_N "checking for cap_init in -lcap... $ECHO_C" >&6
++if test "${ac_cv_lib_cap_cap_init+set}" = set; then
++ echo $ECHO_N "(cached) $ECHO_C" >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-lcap $LIBS"
++cat >conftest.$ac_ext <<_ACEOF
++/* confdefs.h. */
++_ACEOF
++cat confdefs.h >>conftest.$ac_ext
++cat >>conftest.$ac_ext <<_ACEOF
++/* end confdefs.h. */
++
++/* Override any gcc2 internal prototype to avoid an error. */
++#ifdef __cplusplus
++extern "C"
++#endif
++/* We use char because int might match the return type of a gcc2
++ builtin and then its argument prototype would still apply. */
++char cap_init ();
++int
++main ()
++{
++cap_init ();
++ ;
++ return 0;
++}
++_ACEOF
++rm -f conftest.$ac_objext conftest$ac_exeext
++if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
++ (eval $ac_link) 2>conftest.er1
++ ac_status=$?
++ grep -v '^ *+' conftest.er1 >conftest.err
++ rm -f conftest.er1
++ cat conftest.err >&5
++ echo "$as_me:$LINENO: \$? = $ac_status" >&5
++ (exit $ac_status); } &&
++ { ac_try='test -z "$ac_c_werror_flag"
++ || test ! -s conftest.err'
++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
++ (eval $ac_try) 2>&5
++ ac_status=$?
++ echo "$as_me:$LINENO: \$? = $ac_status" >&5
++ (exit $ac_status); }; } &&
++ { ac_try='test -s conftest$ac_exeext'
++ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
++ (eval $ac_try) 2>&5
++ ac_status=$?
++ echo "$as_me:$LINENO: \$? = $ac_status" >&5
++ (exit $ac_status); }; }; then
++ ac_cv_lib_cap_cap_init=yes
++else
++ echo "$as_me: failed program was:" >&5
++sed 's/^/| /' conftest.$ac_ext >&5
++
++ac_cv_lib_cap_cap_init=no
++fi
++rm -f conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++echo "$as_me:$LINENO: result: $ac_cv_lib_cap_cap_init" >&5
++echo "${ECHO_T}$ac_cv_lib_cap_cap_init" >&6
++if test $ac_cv_lib_cap_cap_init = yes; then
++ have_libcap=yes
++else
++ have_libcap=no
++fi
++
++ if test "x$have_libcap" = xyes; then
++
++cat >>confdefs.h <<\_ACEOF
++#define HAVE_LIBCAP 1
++_ACEOF
++
++ fi
++
+ fi
+
+
+@@ -8475,6 +8555,7 @@ s,@no_whole_archive@,$no_whole_archive,;
+ s,@exceptions@,$exceptions,;t t
+ s,@LIBGD@,$LIBGD,;t t
+ s,@have_libaudit@,$have_libaudit,;t t
++s,@have_libcap@,$have_libcap,;t t
+ s,@have_selinux@,$have_selinux,;t t
+ s,@EGREP@,$EGREP,;t t
+ s,@sizeof_long_double@,$sizeof_long_double,;t t
+--- libc/nscd/Makefile 4 Apr 2006 07:32:46 -0000 1.49
++++ libc/nscd/Makefile 26 Apr 2006 16:24:22 -0000 1.50
+@@ -55,10 +55,13 @@ all-nscd-modules := $(nscd-modules) seli
+ ifeq (yes,$(have-selinux))
+ ifeq (yes,$(have-libaudit))
+ libaudit = -laudit
++ifeq (yes,$(have-libcap))
++libcap = -lcap
++endif
+ endif
+
+ nscd-modules += selinux
+-selinux-LIBS := -lselinux $(libaudit)
++selinux-LIBS := -lselinux $(libaudit) $(libcap)
+ endif
+
+ LDLIBS-nscd = $(selinux-LIBS)
+--- libc/nscd/connections.c 1 Apr 2006 18:49:53 -0000 1.83
++++ libc/nscd/connections.c 26 Apr 2006 16:26:17 -0000 1.84
+@@ -1859,6 +1859,11 @@ begin_drop_privileges (void)
+ static void
+ finish_drop_privileges (void)
+ {
++#if defined HAVE_LIBAUDIT && defined HAVE_LIBCAP
++ /* We need to preserve the capabilities to connect to the audit daemon. */
++ cap_t new_caps = preserve_capabilities ();
++#endif
++
+ if (setgroups (server_ngroups, server_groups) == -1)
+ {
+ dbg_log (_("Failed to run nscd as user '%s'"), server_user);
+@@ -1878,4 +1883,9 @@ finish_drop_privileges (void)
+ perror ("setuid");
+ exit (4);
+ }
++
++#if defined HAVE_LIBAUDIT && defined HAVE_LIBCAP
++ /* Remove the temporary capabilities. */
++ install_real_capabilities (new_caps);
++#endif
+ }
+--- libc/nscd/selinux.c 22 Feb 2006 07:30:04 -0000 1.7
++++ libc/nscd/selinux.c 26 Mar 2007 20:40:37 -0000 1.11
+@@ -27,6 +27,7 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <syslog.h>
++#include <sys/prctl.h>
+ #include <selinux/av_permissions.h>
+ #include <selinux/avc.h>
+ #include <selinux/flask.h>
+@@ -129,6 +130,94 @@ audit_init (void)
+ if (audit_fd < 0)
+ dbg_log (_("Failed opening connection to the audit subsystem"));
+ }
++
++
++# ifdef HAVE_LIBCAP
++static const cap_value_t new_cap_list[] =
++ { CAP_AUDIT_WRITE };
++# define nnew_cap_list (sizeof (new_cap_list) / sizeof (new_cap_list[0]))
++static const cap_value_t tmp_cap_list[] =
++ { CAP_AUDIT_WRITE, CAP_SETUID, CAP_SETGID };
++# define ntmp_cap_list (sizeof (tmp_cap_list) / sizeof (tmp_cap_list[0]))
++
++cap_t
++preserve_capabilities (void)
++{
++ if (getuid () != 0)
++ /* Not root, then we cannot preserve anything. */
++ return NULL;
++
++ if (prctl (PR_SET_KEEPCAPS, 1) == -1)
++ {
++ dbg_log (_("Failed to set keep-capabilities"));
++ error (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed"));
++ /* NOTREACHED */
++ }
++
++ cap_t tmp_caps = cap_init ();
++ cap_t new_caps;
++ if (tmp_caps != NULL)
++ new_caps = cap_init ();
++
++ if (tmp_caps == NULL || new_caps == NULL)
++ {
++ if (tmp_caps != NULL)
++ cap_free (tmp_caps);
++
++ dbg_log (_("Failed to initialize drop of capabilities"));
++ error (EXIT_FAILURE, 0, _("cap_init failed"));
++ }
++
++ /* There is no reason why these should not work. */
++ cap_set_flag (new_caps, CAP_PERMITTED, nnew_cap_list,
++ (cap_value_t *) new_cap_list, CAP_SET);
++ cap_set_flag (new_caps, CAP_EFFECTIVE, nnew_cap_list,
++ (cap_value_t *) new_cap_list, CAP_SET);
++
++ cap_set_flag (tmp_caps, CAP_PERMITTED, ntmp_cap_list,
++ (cap_value_t *) tmp_cap_list, CAP_SET);
++ cap_set_flag (tmp_caps, CAP_EFFECTIVE, ntmp_cap_list,
++ (cap_value_t *) tmp_cap_list, CAP_SET);
++
++ int res = cap_set_proc (tmp_caps);
++
++ cap_free (tmp_caps);
++
++ if (__builtin_expect (res != 0, 0))
++ {
++ cap_free (new_caps);
++ dbg_log (_("Failed to drop capabilities\n"));
++ error (EXIT_FAILURE, 0, _("cap_set_proc failed"));
++ }
++
++ return new_caps;
++}
++
++void
++install_real_capabilities (cap_t new_caps)
++{
++ /* If we have no capabilities there is nothing to do here. */
++ if (new_caps == NULL)
++ return;
++
++ if (cap_set_proc (new_caps))
++ {
++ cap_free (new_caps);
++ dbg_log (_("Failed to drop capabilities"));
++ error (EXIT_FAILURE, 0, _("cap_set_proc failed"));
++ /* NOTREACHED */
++ }
++
++ cap_free (new_caps);
++
++ if (prctl (PR_SET_KEEPCAPS, 0) == -1)
++ {
++ dbg_log (_("Failed to unset keep-capabilities"));
++ error (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed"));
++ /* NOTREACHED */
++ }
++}
++# endif /* HAVE_LIBCAP */
+ #endif /* HAVE_LIBAUDIT */
+
+ /* Determine if we are running on an SELinux kernel. Set selinux_enabled
+--- libc/nscd/selinux.h 16 Sep 2004 23:59:44 -0000 1.2
++++ libc/nscd/selinux.h 26 Mar 2007 20:40:21 -0000 1.4
+@@ -22,6 +22,9 @@
+ #define _SELINUX_H 1
+
+ #include "nscd.h"
++#ifdef HAVE_LIBCAP
++# include <sys/capability.h>
++#endif
+
+ #ifdef HAVE_SELINUX
+ /* Global variable to tell if the kernel has SELinux support. */
+@@ -42,6 +45,13 @@ extern int nscd_request_avc_has_perm (in
+ extern void nscd_avc_cache_stats (struct avc_cache_stats *cstats);
+ /* Display statistics on AVC usage. */
+ extern void nscd_avc_print_stats (struct avc_cache_stats *cstats);
++
++# ifdef HAVE_LIBCAP
++/* Preserve capabilities to connect to connnect to the audit daemon. */
++extern cap_t preserve_capabilities (void);
++/* Install final capabilities. */
++extern void install_real_capabilities (cap_t new_caps);
++# endif
+ #else
+ # define selinux_enabled 0
+ # define nscd_avc_init() (void) 0
+--- libc/config.h.in 28 Oct 2006 06:44:04 -0000 1.80
++++ libc/config.h.in 26 Mar 2007 20:40:08 -0000 1.81
+@@ -19,6 +19,9 @@
+ /* Defined if building with SELinux support & audit libs are detected. */
+ #undef HAVE_LIBAUDIT
+
++/* Defined if building with SELinux support & libcap libs are detected. */
++#undef HAVE_LIBCAP
++
+ /* Define if using XCOFF. Set by --with-xcoff. */
+ #undef HAVE_XCOFF
+
--- /dev/null
+2006-07-19 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/unix/sysv/linux/kaio_misc.c: Include atomic.h.
+ (kernel_callback): Ensure __return_value is updated before
+ __error_code is set.
+
+--- libc/rtkaio/sysdeps/unix/sysv/linux/kaio_misc.c.jj 2006-08-29 05:07:55.000000000 -0400
++++ libc/rtkaio/sysdeps/unix/sysv/linux/kaio_misc.c 2006-08-30 10:48:45.000000000 -0400
+@@ -27,6 +27,7 @@
+
+ #include <aio.h>
+ #include <assert.h>
++#include <atomic.h>
+ #include <errno.h>
+ #include <limits.h>
+ #include <pthread.h>
+@@ -381,14 +382,16 @@ static void
+ kernel_callback (kctx_t ctx, struct kiocb *kiocb, long res, long res2)
+ {
+ struct requestlist *req = (struct requestlist *)kiocb;
++ long errcode = 0;
+
+- req->aiocbp->aiocb.__error_code = 0;
+- req->aiocbp->aiocb.__return_value = res;
+ if (res < 0 && res > -1000)
+ {
+- req->aiocbp->aiocb.__error_code = -res;
+- req->aiocbp->aiocb.__return_value = -1;
++ errcode = -res;
++ res = -1;
+ }
++ req->aiocbp->aiocb.__return_value = res;
++ atomic_write_barrier ();
++ req->aiocbp->aiocb.__error_code = errcode;
+ __aio_notify (req);
+ assert (req->running == allocated);
+ req->running = done;
--- /dev/null
+2006-04-30 Ulrich Drepper <drepper@redhat.com>
+
+ * elf/ldd.bash.in: If --verify loop fails to find a dynamic linker
+ for the file don't just try the first one listed in RTLDLIST
+ again. We already have the status.
+
+--- libc/elf/ldd.bash.in 1 Apr 2006 20:16:17 -0000 1.36
++++ libc/elf/ldd.bash.in 30 Apr 2006 16:06:20 -0000 1.37
+@@ -154,6 +154,7 @@ for file do
+ test -x "$file" || echo 'ldd:' $"\
+ warning: you do not have execution permission for" "\`$file'" >&2
+ RTLD=
++ ret=1
+ for rtld in ${RTLDLIST}; do
+ if test -x $rtld; then
+ verify_out=`${rtld} --verify "$file"`
+@@ -163,12 +164,6 @@ warning: you do not have execution permi
+ esac
+ fi
+ done
+- if test -z "${RTLD}"; then
+- set ${RTLDLIST}
+- RTLD=$1
+- verify_out=`${RTLD} --verify "$file"`
+- ret=$?
+- fi
+ case $ret in
+ 0)
+ # If the program exits with exit code 5, it means the process has been
--- /dev/null
+2006-05-30 Jakub Jelinek <jakub@redhat.com>
+
+ * nscd/nscd.h (prune_cache): Add fd argument to prototype.
+ * nscd/nscd.c (parse_opt): Read response from INVALIDATE request
+ to make sure the database has been already invalidated.
+ * nscd/cache.c (prune_cache): Add fd argument. Write response to fd
+ after the cache has been invalidated. Use pthread_mutex_lock rather
+ than pthread_mutex_trylock if fd != -1.
+ * nscd/connections.c (invalidate_cache): Add fd argument, write
+ response to fd if not calling prune_cache, pass fd to prune_cache.
+ (handle_request): Adjust invalidate_cache caller.
+ (nscd_run): Pass -1 as fd to prune_cache.
+
+2006-05-29 Ulrich Drepper <drepper@redhat.com>
+
+ * nscd/nscd.h (struct database_dyn): Add prunelock field.
+ * nscd/cache.c (prune_cache): Take prunelock before starting the
+ work. Just return in case it is already taken.
+ * nscd/connections.c (dbs): Initialize .prunelock.
+
+--- libc/nscd/cache.c 7 Dec 2005 05:47:27 -0000 1.24
++++ libc/nscd/cache.c 30 May 2006 17:30:26 -0000 1.26
+@@ -190,13 +190,34 @@ cache_add (int type, const void *key, si
+ free the data structures since some hash table entries share the same
+ data. */
+ void
+-prune_cache (struct database_dyn *table, time_t now)
++prune_cache (struct database_dyn *table, time_t now, int fd)
+ {
+ size_t cnt = table->head->module;
+
+ /* If this table is not actually used don't do anything. */
+ if (cnt == 0)
+- return;
++ {
++ if (fd != -1)
++ {
++ /* Reply to the INVALIDATE initiator. */
++ int32_t resp = 0;
++ writeall (fd, &resp, sizeof (resp));
++ }
++ return;
++ }
++
++ /* This function can be called from the cleanup thread but also in
++ response to an invalidate command. Make sure only one thread is
++ running. When not serving INVALIDATE request, no need for the
++ second to wait around. */
++ if (fd == -1)
++ {
++ if (pthread_mutex_trylock (&table->prunelock) != 0)
++ /* The work is already being done. */
++ return;
++ }
++ else
++ pthread_mutex_lock (&table->prunelock);
+
+ /* If we check for the modification of the underlying file we invalidate
+ the entries also in this case. */
+@@ -367,6 +388,14 @@ prune_cache (struct database_dyn *table,
+ }
+ while (cnt > 0);
+
++ if (fd != -1)
++ {
++ /* Reply to the INVALIDATE initiator that the cache has been
++ invalidated. */
++ int32_t resp = 0;
++ writeall (fd, &resp, sizeof (resp));
++ }
++
+ if (first <= last)
+ {
+ struct hashentry *head = NULL;
+@@ -455,4 +484,6 @@ prune_cache (struct database_dyn *table,
+ /* Run garbage collection if any entry has been removed or replaced. */
+ if (any)
+ gc (table);
++
++ pthread_mutex_unlock (&table->prunelock);
+ }
+--- libc/nscd/connections.c 5 May 2006 06:11:54 -0000 1.55.2.24
++++ libc/nscd/connections.c 31 May 2006 15:10:34 -0000 1.55.2.25
+@@ -100,6 +100,7 @@ struct database_dyn dbs[lastdb] =
+ {
+ [pwddb] = {
+ .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
++ .prunelock = PTHREAD_MUTEX_INITIALIZER,
+ .enabled = 0,
+ .check_file = 1,
+ .persistent = 0,
+@@ -117,6 +118,7 @@ struct database_dyn dbs[lastdb] =
+ },
+ [grpdb] = {
+ .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
++ .prunelock = PTHREAD_MUTEX_INITIALIZER,
+ .enabled = 0,
+ .check_file = 1,
+ .persistent = 0,
+@@ -134,6 +136,7 @@ struct database_dyn dbs[lastdb] =
+ },
+ [hstdb] = {
+ .lock = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP,
++ .prunelock = PTHREAD_MUTEX_INITIALIZER,
+ .enabled = 0,
+ .check_file = 1,
+ .persistent = 0,
+@@ -813,9 +816,10 @@ close_sockets (void)
+
+
+ static void
+-invalidate_cache (char *key)
++invalidate_cache (char *key, int fd)
+ {
+ dbtype number;
++ int32_t resp;
+
+ if (strcmp (key, "passwd") == 0)
+ number = pwddb;
+@@ -829,10 +833,19 @@ invalidate_cache (char *key)
+ res_init ();
+ }
+ else
+- return;
++ {
++ resp = EINVAL;
++ writeall (fd, &resp, sizeof (resp));
++ return;
++ }
+
+ if (dbs[number].enabled)
+- prune_cache (&dbs[number], LONG_MAX);
++ prune_cache (&dbs[number], LONG_MAX, fd);
++ else
++ {
++ resp = 0;
++ writeall (fd, &resp, sizeof (resp));
++ }
+ }
+
+
+@@ -1089,7 +1102,7 @@ cannot handle old request version %d; cu
+ else if (uid == 0)
+ {
+ if (req->type == INVALIDATE)
+- invalidate_cache (key);
++ invalidate_cache (key, fd);
+ else
+ termination_handler (0);
+ }
+@@ -1435,7 +1448,7 @@ handle_request: request received (Versio
+ /* The pthread_cond_timedwait() call timed out. It is time
+ to clean up the cache. */
+ assert (my_number < lastdb);
+- prune_cache (&dbs[my_number], time (NULL));
++ prune_cache (&dbs[my_number], time (NULL), -1);
+
+ if (clock_gettime (timeout_clock, &prune_ts) == -1)
+ /* Should never happen. */
+@@ -1908,14 +1921,14 @@ sighup_handler (int signum)
+ {
+ /* Prune the password database. */
+ if (dbs[pwddb].enabled)
+- prune_cache (&dbs[pwddb], LONG_MAX);
++ prune_cache (&dbs[pwddb], LONG_MAX, -1);
+
+ /* Prune the group database. */
+ if (dbs[grpdb].enabled)
+- prune_cache (&dbs[grpdb], LONG_MAX);
++ prune_cache (&dbs[grpdb], LONG_MAX, -1);
+
+ /* Prune the host database. */
+ if (dbs[hstdb].enabled)
+- prune_cache (&dbs[hstdb], LONG_MAX);
++ prune_cache (&dbs[hstdb], LONG_MAX, -1);
+ }
+
+--- libc/nscd/nscd.c 6 Apr 2006 22:55:50 -0000 1.52
++++ libc/nscd/nscd.c 30 May 2006 17:29:36 -0000 1.53
+@@ -332,9 +332,6 @@ parse_opt (int key, char *arg, struct ar
+ exit (EXIT_FAILURE);
+
+ request_header req;
+- ssize_t nbytes;
+- struct iovec iov[2];
+-
+ if (strcmp (arg, "passwd") == 0)
+ req.key_len = sizeof "passwd";
+ else if (strcmp (arg, "group") == 0)
+@@ -347,17 +344,38 @@ parse_opt (int key, char *arg, struct ar
+ req.version = NSCD_VERSION;
+ req.type = INVALIDATE;
+
++ struct iovec iov[2];
+ iov[0].iov_base = &req;
+ iov[0].iov_len = sizeof (req);
+ iov[1].iov_base = arg;
+ iov[1].iov_len = req.key_len;
+
+- nbytes = TEMP_FAILURE_RETRY (writev (sock, iov, 2));
++ ssize_t nbytes = TEMP_FAILURE_RETRY (writev (sock, iov, 2));
++
++ if (nbytes != iov[0].iov_len + iov[1].iov_len)
++ {
++ int err = errno;
++ close (sock);
++ error (EXIT_FAILURE, err, _("write incomplete"));
++ }
++
++ /* Wait for ack. Older nscd just closed the socket when
++ prune_cache finished, silently ignore that. */
++ int32_t resp = 0;
++ nbytes = TEMP_FAILURE_RETRY (read (sock, &resp, sizeof (resp)));
++ if (nbytes != 0 && nbytes != sizeof (resp))
++ {
++ int err = errno;
++ close (sock);
++ error (EXIT_FAILURE, err, _("cannot read invalidate ACK"));
++ }
+
+ close (sock);
+
+- exit (nbytes != iov[0].iov_len + iov[1].iov_len
+- ? EXIT_FAILURE : EXIT_SUCCESS);
++ if (resp != 0)
++ error (EXIT_FAILURE, resp, _("invalidation failed"));
++
++ exit (0);
+ }
+
+ case 't':
+--- libc/nscd/nscd.h 30 Apr 2006 16:37:49 -0000 1.26
++++ libc/nscd/nscd.h 30 May 2006 17:28:53 -0000 1.28
+@@ -58,6 +58,7 @@ typedef enum
+ struct database_dyn
+ {
+ pthread_rwlock_t lock;
++ pthread_mutex_t prunelock;
+
+ int enabled;
+ int check_file;
+@@ -184,7 +185,7 @@ extern struct datahead *cache_search (re
+ extern int cache_add (int type, const void *key, size_t len,
+ struct datahead *packet, bool first,
+ struct database_dyn *table, uid_t owner);
+-extern void prune_cache (struct database_dyn *table, time_t now);
++extern void prune_cache (struct database_dyn *table, time_t now, int fd);
+
+ /* pwdcache.c */
+ extern void addpwbyname (struct database_dyn *db, int fd, request_header *req,
--- /dev/null
+2006-07-31 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nss_compat/compat-grp.c: Avoid unnecessary setgrent calls into
+ the backend NSS module. If backend setgrent call failed, don't have
+ internal_setgrent fail. Just remember this until it is needed.
+ * nis/nss_compat/compat-pwd.c: Likewise.
+ * nis/nss_compat/compat-spwd.c: Likewise.
+
+--- libc/nis/nss_compat/compat-grp.c 18 May 2006 14:51:05 -0000 1.31
++++ libc/nis/nss_compat/compat-grp.c 31 Jul 2006 23:33:04 -0000 1.32
+@@ -59,12 +59,13 @@ struct blacklist_t
+ struct ent_t
+ {
+ bool_t files;
++ enum nss_status setent_status;
+ FILE *stream;
+ struct blacklist_t blacklist;
+ };
+ typedef struct ent_t ent_t;
+
+-static ent_t ext_ent = {TRUE, NULL, {NULL, 0, 0}};
++static ent_t ext_ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }};
+
+ /* Protect global state against multiple changers. */
+ __libc_lock_define_initialized (static, lock)
+@@ -89,7 +90,7 @@ init_nss_interface (void)
+ }
+
+ static enum nss_status
+-internal_setgrent (ent_t *ent, int stayopen)
++internal_setgrent (ent_t *ent, int stayopen, int needent)
+ {
+ enum nss_status status = NSS_STATUS_SUCCESS;
+
+@@ -137,12 +138,8 @@ internal_setgrent (ent_t *ent, int stayo
+ else
+ rewind (ent->stream);
+
+- if (status == NSS_STATUS_SUCCESS && nss_setgrent)
+- {
+- status = nss_setgrent (stayopen);
+- if (status == NSS_STATUS_UNAVAIL)
+- status = NSS_STATUS_SUCCESS;
+- }
++ if (needent && status == NSS_STATUS_SUCCESS && nss_setgrent)
++ ent->setent_status = nss_setgrent (stayopen);
+
+ return status;
+ }
+@@ -158,7 +155,7 @@ _nss_compat_setgrent (int stayopen)
+ if (ni == NULL)
+ init_nss_interface ();
+
+- result = internal_setgrent (&ext_ent, stayopen);
++ result = internal_setgrent (&ext_ent, stayopen, 1);
+
+ __libc_lock_unlock (lock);
+
+@@ -212,6 +209,10 @@ getgrent_next_nss (struct group *result,
+ if (!nss_getgrent_r)
+ return NSS_STATUS_UNAVAIL;
+
++ /* If the setgrent call failed, say so. */
++ if (ent->setent_status != NSS_STATUS_SUCCESS)
++ return ent->setent_status;
++
+ do
+ {
+ enum nss_status status;
+@@ -363,7 +364,7 @@ _nss_compat_getgrent_r (struct group *gr
+ init_nss_interface ();
+
+ if (ext_ent.stream == NULL)
+- result = internal_setgrent (&ext_ent, 1);
++ result = internal_setgrent (&ext_ent, 1, 1);
+
+ if (result == NSS_STATUS_SUCCESS)
+ {
+@@ -485,7 +486,7 @@ enum nss_status
+ _nss_compat_getgrnam_r (const char *name, struct group *grp,
+ char *buffer, size_t buflen, int *errnop)
+ {
+- ent_t ent = {TRUE, NULL, {NULL, 0, 0}};
++ ent_t ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }};
+ enum nss_status result;
+
+ if (name[0] == '-' || name[0] == '+')
+@@ -498,7 +499,7 @@ _nss_compat_getgrnam_r (const char *name
+
+ __libc_lock_unlock (lock);
+
+- result = internal_setgrent (&ent, 0);
++ result = internal_setgrent (&ent, 0, 0);
+
+ if (result == NSS_STATUS_SUCCESS)
+ result = internal_getgrnam_r (name, grp, &ent, buffer, buflen, errnop);
+@@ -613,7 +614,7 @@ enum nss_status
+ _nss_compat_getgrgid_r (gid_t gid, struct group *grp,
+ char *buffer, size_t buflen, int *errnop)
+ {
+- ent_t ent = {TRUE, NULL, {NULL, 0, 0}};
++ ent_t ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }};
+ enum nss_status result;
+
+ __libc_lock_lock (lock);
+@@ -623,7 +624,7 @@ _nss_compat_getgrgid_r (gid_t gid, struc
+
+ __libc_lock_unlock (lock);
+
+- result = internal_setgrent (&ent, 0);
++ result = internal_setgrent (&ent, 0, 0);
+
+ if (result == NSS_STATUS_SUCCESS)
+ result = internal_getgrgid_r (gid, grp, &ent, buffer, buflen, errnop);
+--- libc/nis/nss_compat/compat-pwd.c 18 May 2006 14:51:05 -0000 1.36
++++ libc/nis/nss_compat/compat-pwd.c 31 Jul 2006 23:33:04 -0000 1.37
+@@ -62,9 +62,10 @@ struct blacklist_t
+
+ struct ent_t
+ {
+- bool_t netgroup;
+- bool_t first;
+- bool_t files;
++ bool netgroup;
++ bool first;
++ bool files;
++ enum nss_status setent_status;
+ FILE *stream;
+ struct blacklist_t blacklist;
+ struct passwd pwd;
+@@ -72,8 +73,9 @@ struct ent_t
+ };
+ typedef struct ent_t ent_t;
+
+-static ent_t ext_ent = {0, 0, TRUE, NULL, {NULL, 0, 0},
+- {NULL, NULL, 0, 0, NULL, NULL, NULL}};
++static ent_t ext_ent = { false, false, true, NSS_STATUS_SUCCESS, NULL,
++ { NULL, 0, 0 },
++ { NULL, NULL, 0, 0, NULL, NULL, NULL }};
+
+ /* Protect global state against multiple changers. */
+ __libc_lock_define_initialized (static, lock)
+@@ -202,12 +204,13 @@ copy_pwd_changes (struct passwd *dest, s
+ }
+
+ static enum nss_status
+-internal_setpwent (ent_t *ent, int stayopen)
++internal_setpwent (ent_t *ent, int stayopen, int needent)
+ {
+ enum nss_status status = NSS_STATUS_SUCCESS;
+
+- ent->first = ent->netgroup = FALSE;
+- ent->files = TRUE;
++ ent->first = ent->netgroup = false;
++ ent->files = true;
++ ent->setent_status = NSS_STATUS_SUCCESS;
+
+ /* If something was left over free it. */
+ if (ent->netgroup)
+@@ -257,12 +260,8 @@ internal_setpwent (ent_t *ent, int stayo
+
+ give_pwd_free (&ent->pwd);
+
+- if (status == NSS_STATUS_SUCCESS && nss_setpwent)
+- {
+- status = nss_setpwent (stayopen);
+- if (status == NSS_STATUS_UNAVAIL)
+- status = NSS_STATUS_SUCCESS;
+- }
++ if (needent && status == NSS_STATUS_SUCCESS && nss_setpwent)
++ ent->setent_status = nss_setpwent (stayopen);
+
+ return status;
+ }
+@@ -278,7 +277,7 @@ _nss_compat_setpwent (int stayopen)
+ if (ni == NULL)
+ init_nss_interface ();
+
+- result = internal_setpwent (&ext_ent, stayopen);
++ result = internal_setpwent (&ext_ent, stayopen, 1);
+
+ __libc_lock_unlock (lock);
+
+@@ -301,7 +300,7 @@ internal_endpwent (ent_t *ent)
+ if (ent->netgroup)
+ __internal_endnetgrent (&ent->netgrdata);
+
+- ent->first = ent->netgroup = FALSE;
++ ent->first = ent->netgroup = false;
+
+ if (ent->blacklist.data != NULL)
+ {
+@@ -348,17 +347,17 @@ getpwent_next_nss_netgr (const char *nam
+
+ if (yp_get_default_domain (&curdomain) != YPERR_SUCCESS)
+ {
+- ent->netgroup = FALSE;
+- ent->first = FALSE;
++ ent->netgroup = false;
++ ent->first = false;
+ give_pwd_free (&ent->pwd);
+ return NSS_STATUS_UNAVAIL;
+ }
+
+- if (ent->first == TRUE)
++ if (ent->first == true)
+ {
+ memset (&ent->netgrdata, 0, sizeof (struct __netgrent));
+ __internal_setnetgrent (group, &ent->netgrdata);
+- ent->first = FALSE;
++ ent->first = false;
+ }
+
+ while (1)
+@@ -427,6 +426,10 @@ getpwent_next_nss (struct passwd *result
+ if (!nss_getpwent_r)
+ return NSS_STATUS_UNAVAIL;
+
++ /* If the setpwent call failed, say so. */
++ if (ent->setent_status != NSS_STATUS_SUCCESS)
++ return ent->setent_status;
++
+ p2len = pwd_need_buflen (&ent->pwd);
+ if (p2len > buflen)
+ {
+@@ -437,7 +440,7 @@ getpwent_next_nss (struct passwd *result
+ buflen -= p2len;
+
+ if (ent->first)
+- ent->first = FALSE;
++ ent->first = false;
+
+ do
+ {
+@@ -570,8 +573,8 @@ getpwent_next_file (struct passwd *resul
+ {
+ enum nss_status status;
+
+- ent->netgroup = TRUE;
+- ent->first = TRUE;
++ ent->netgroup = true;
++ ent->first = true;
+ copy_pwd_changes (&ent->pwd, result, NULL, 0);
+
+ status = getpwent_next_nss_netgr (NULL, result, ent,
+@@ -626,8 +629,8 @@ getpwent_next_file (struct passwd *resul
+ /* +:... */
+ if (result->pw_name[0] == '+' && result->pw_name[1] == '\0')
+ {
+- ent->files = FALSE;
+- ent->first = TRUE;
++ ent->files = false;
++ ent->first = true;
+ copy_pwd_changes (&ent->pwd, result, NULL, 0);
+
+ return getpwent_next_nss (result, ent, buffer, buflen, errnop);
+@@ -675,7 +678,7 @@ _nss_compat_getpwent_r (struct passwd *p
+ init_nss_interface ();
+
+ if (ext_ent.stream == NULL)
+- result = internal_setpwent (&ext_ent, 1);
++ result = internal_setpwent (&ext_ent, 1, 1);
+
+ if (result == NSS_STATUS_SUCCESS)
+ result = internal_getpwent_r (pwd, &ext_ent, buffer, buflen, errnop);
+@@ -827,8 +830,8 @@ _nss_compat_getpwnam_r (const char *name
+ char *buffer, size_t buflen, int *errnop)
+ {
+ enum nss_status result;
+- ent_t ent = {0, 0, TRUE, NULL, {NULL, 0, 0},
+- {NULL, NULL, 0, 0, NULL, NULL, NULL}};
++ ent_t ent = { false, false, true, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 },
++ { NULL, NULL, 0, 0, NULL, NULL, NULL }};
+
+ if (name[0] == '-' || name[0] == '+')
+ return NSS_STATUS_NOTFOUND;
+@@ -840,7 +843,7 @@ _nss_compat_getpwnam_r (const char *name
+
+ __libc_lock_unlock (lock);
+
+- result = internal_setpwent (&ent, 0);
++ result = internal_setpwent (&ent, 0, 0);
+
+ if (result == NSS_STATUS_SUCCESS)
+ result = internal_getpwnam_r (name, pwd, &ent, buffer, buflen, errnop);
+@@ -1069,8 +1072,8 @@ _nss_compat_getpwuid_r (uid_t uid, struc
+ char *buffer, size_t buflen, int *errnop)
+ {
+ enum nss_status result;
+- ent_t ent = {0, 0, TRUE, NULL, {NULL, 0, 0},
+- {NULL, NULL, 0, 0, NULL, NULL, NULL}};
++ ent_t ent = { false, false, true, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 },
++ { NULL, NULL, 0, 0, NULL, NULL, NULL }};
+
+ __libc_lock_lock (lock);
+
+@@ -1079,7 +1082,7 @@ _nss_compat_getpwuid_r (uid_t uid, struc
+
+ __libc_lock_unlock (lock);
+
+- result = internal_setpwent (&ent, 0);
++ result = internal_setpwent (&ent, 0, 0);
+
+ if (result == NSS_STATUS_SUCCESS)
+ result = internal_getpwuid_r (uid, pwd, &ent, buffer, buflen, errnop);
+@@ -1136,7 +1139,7 @@ blacklist_store_name (const char *name,
+ return;
+ }
+
+-/* returns TRUE if ent->blacklist contains name, else FALSE */
++/* Returns TRUE if ent->blacklist contains name, else FALSE. */
+ static bool_t
+ in_blacklist (const char *name, int namelen, ent_t *ent)
+ {
+--- libc/nis/nss_compat/compat-spwd.c 18 May 2006 14:51:05 -0000 1.29
++++ libc/nis/nss_compat/compat-spwd.c 31 Jul 2006 23:33:04 -0000 1.30
+@@ -59,9 +59,10 @@ struct blacklist_t
+
+ struct ent_t
+ {
+- bool_t netgroup;
+- bool_t files;
+- bool_t first;
++ bool netgroup;
++ bool files;
++ bool first;
++ enum nss_status setent_status;
+ FILE *stream;
+ struct blacklist_t blacklist;
+ struct spwd pwd;
+@@ -69,8 +70,9 @@ struct ent_t
+ };
+ typedef struct ent_t ent_t;
+
+-static ent_t ext_ent = {0, TRUE, 0, NULL, {NULL, 0, 0},
+- {NULL, NULL, 0, 0, 0, 0, 0, 0, 0}};
++static ent_t ext_ent = { false, true, false, NSS_STATUS_SUCCESS, NULL,
++ { NULL, 0, 0},
++ { NULL, NULL, 0, 0, 0, 0, 0, 0, 0}};
+
+ /* Protect global state against multiple changers. */
+ __libc_lock_define_initialized (static, lock)
+@@ -161,7 +163,7 @@ internal_setspent (ent_t *ent, int stayo
+ enum nss_status status = NSS_STATUS_SUCCESS;
+
+ ent->first = ent->netgroup = 0;
+- ent->files = TRUE;
++ ent->files = true;
+
+ /* If something was left over free it. */
+ if (ent->netgroup)
+@@ -212,11 +214,7 @@ internal_setspent (ent_t *ent, int stayo
+ give_spwd_free (&ent->pwd);
+
+ if (status == NSS_STATUS_SUCCESS && nss_setspent)
+- {
+- status = nss_setspent (stayopen);
+- if (status == NSS_STATUS_UNAVAIL)
+- status = NSS_STATUS_SUCCESS;
+- }
++ ent->setent_status = nss_setspent (stayopen);
+
+ return status;
+ }
+@@ -255,8 +253,8 @@ internal_endspent (ent_t *ent)
+ if (ent->netgroup)
+ __internal_endnetgrent (&ent->netgrdata);
+
+- ent->first = ent->netgroup = FALSE;
+- ent->files = TRUE;
++ ent->first = ent->netgroup = false;
++ ent->files = true;
+
+ if (ent->blacklist.data != NULL)
+ {
+@@ -298,19 +296,23 @@ getspent_next_nss_netgr (const char *nam
+ if (!nss_getspnam_r)
+ return NSS_STATUS_UNAVAIL;
+
++ /* If the setpwent call failed, say so. */
++ if (ent->setent_status != NSS_STATUS_SUCCESS)
++ return ent->setent_status;
++
+ if (yp_get_default_domain (&curdomain) != YPERR_SUCCESS)
+ {
+- ent->netgroup = FALSE;
+- ent->first = FALSE;
++ ent->netgroup = false;
++ ent->first = false;
+ give_spwd_free (&ent->pwd);
+ return NSS_STATUS_UNAVAIL;
+ }
+
+- if (ent->first == TRUE)
++ if (ent->first == true)
+ {
+ memset (&ent->netgrdata, 0, sizeof (struct __netgrent));
+ __internal_setnetgrent (group, &ent->netgrdata);
+- ent->first = FALSE;
++ ent->first = false;
+ }
+
+ while (1)
+@@ -325,7 +327,7 @@ getspent_next_nss_netgr (const char *nam
+ if (status != 1)
+ {
+ __internal_endnetgrent (&ent->netgrdata);
+- ent->netgroup = FALSE;
++ ent->netgroup = false;
+ give_spwd_free (&ent->pwd);
+ return NSS_STATUS_RETURN;
+ }
+@@ -400,6 +402,7 @@ getspent_next_nss (struct spwd *result,
+ return NSS_STATUS_SUCCESS;
+ }
+
++
+ /* This function handle the +user entrys in /etc/shadow */
+ static enum nss_status
+ getspnam_plususer (const char *name, struct spwd *result, ent_t *ent,
+@@ -440,6 +443,7 @@ getspnam_plususer (const char *name, str
+ return NSS_STATUS_SUCCESS;
+ }
+
++
+ static enum nss_status
+ getspent_next_file (struct spwd *result, ent_t *ent,
+ char *buffer, size_t buflen, int *errnop)
+@@ -520,8 +524,8 @@ getspent_next_file (struct spwd *result,
+ {
+ int status;
+
+- ent->netgroup = TRUE;
+- ent->first = TRUE;
++ ent->netgroup = true;
++ ent->first = true;
+ copy_spwd_changes (&ent->pwd, result, NULL, 0);
+
+ status = getspent_next_nss_netgr (NULL, result, ent,
+@@ -577,8 +581,8 @@ getspent_next_file (struct spwd *result,
+ /* +:... */
+ if (result->sp_namp[0] == '+' && result->sp_namp[1] == '\0')
+ {
+- ent->files = FALSE;
+- ent->first = TRUE;
++ ent->files = false;
++ ent->first = true;
+ copy_spwd_changes (&ent->pwd, result, NULL, 0);
+
+ return getspent_next_nss (result, ent, buffer, buflen, errnop);
+@@ -613,6 +617,7 @@ internal_getspent_r (struct spwd *pw, en
+ return getspent_next_nss (pw, ent, buffer, buflen, errnop);
+ }
+
++
+ enum nss_status
+ _nss_compat_getspent_r (struct spwd *pwd, char *buffer, size_t buflen,
+ int *errnop)
+@@ -636,6 +641,7 @@ _nss_compat_getspent_r (struct spwd *pwd
+ return result;
+ }
+
++
+ /* Searches in /etc/passwd and the NIS/NIS+ map for a special user */
+ static enum nss_status
+ internal_getspnam_r (const char *name, struct spwd *result, ent_t *ent,
+@@ -778,13 +784,14 @@ internal_getspnam_r (const char *name, s
+ return NSS_STATUS_SUCCESS;
+ }
+
++
+ enum nss_status
+ _nss_compat_getspnam_r (const char *name, struct spwd *pwd,
+ char *buffer, size_t buflen, int *errnop)
+ {
+ enum nss_status result;
+- ent_t ent = {0, TRUE, 0, NULL, {NULL, 0, 0},
+- {NULL, NULL, 0, 0, 0, 0, 0, 0, 0}};
++ ent_t ent = { false, true, false, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0},
++ { NULL, NULL, 0, 0, 0, 0, 0, 0, 0}};
+
+ if (name[0] == '-' || name[0] == '+')
+ return NSS_STATUS_NOTFOUND;
+@@ -806,6 +813,7 @@ _nss_compat_getspnam_r (const char *name
+ return result;
+ }
+
++
+ /* Support routines for remembering -@netgroup and -user entries.
+ The names are stored in a single string with `|' as separator. */
+ static void
+@@ -852,6 +860,7 @@ blacklist_store_name (const char *name,
+ return;
+ }
+
++
+ /* Returns TRUE if ent->blacklist contains name, else FALSE. */
+ static bool_t
+ in_blacklist (const char *name, int namelen, ent_t *ent)
+@@ -860,7 +869,7 @@ in_blacklist (const char *name, int name
+ char *cp;
+
+ if (ent->blacklist.data == NULL)
+- return FALSE;
++ return false;
+
+ buf[0] = '|';
+ cp = stpcpy (&buf[1], name);
--- /dev/null
+2006-06-04 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/posix/spawni.c (__spawni): Use local_seteuid and
+ local_setegid instead of seteuid and setegid.
+ * sysdeps/generic/local-setxid.h: New file.
+ * sysdeps/unix/sysv/linux/local-setxid.h: New file.
+
+ * sysdeps/posix/spawni.c (__spawni): Use non-cancelable interfaces.
+
+--- libc/sysdeps/generic/local-setxid.h 1 Jan 1970 00:00:00 -0000
++++ libc/sysdeps/generic/local-setxid.h 4 Jun 2006 22:15:39 -0000 1.1
+@@ -0,0 +1,4 @@
++/* No special support. Fall back to the regular functions. */
++
++#define local_seteuid(id) seteuid (id)
++#define local_setegid(id) setegid (id)
+--- libc/sysdeps/posix/spawni.c 13 Sep 2005 18:41:48 -0000 1.7
++++ libc/sysdeps/posix/spawni.c 4 Jun 2006 22:16:05 -0000 1.9
+@@ -26,6 +26,7 @@
+ #include <unistd.h>
+ #include "spawn_int.h"
+ #include <not-cancel.h>
++#include <local-setxid.h>
+
+
+ /* The Unix standard contains a long explanation of the way to signal
+@@ -155,7 +156,8 @@ __spawni (pid_t *pid, const char *file,
+
+ /* Set the effective user and group IDs. */
+ if ((flags & POSIX_SPAWN_RESETIDS) != 0
+- && (seteuid (__getuid ()) != 0 || setegid (__getgid ()) != 0))
++ && (local_seteuid (__getuid ()) != 0
++ || local_setegid (__getgid ()) != 0))
+ _exit (SPAWN_ERROR);
+
+ /* Execute the file actions. */
+@@ -177,9 +179,10 @@ __spawni (pid_t *pid, const char *file,
+
+ case spawn_do_open:
+ {
+- int new_fd = __open64 (action->action.open_action.path,
+- action->action.open_action.oflag,
+- action->action.open_action.mode);
++ int new_fd = open_not_cancel (action->action.open_action.path,
++ action->action.open_action.oflag
++ | O_LARGEFILE,
++ action->action.open_action.mode);
+
+ if (new_fd == -1)
+ /* The `open' call failed. */
+@@ -193,7 +196,7 @@ __spawni (pid_t *pid, const char *file,
+ /* The `dup2' call failed. */
+ _exit (SPAWN_ERROR);
+
+- if (__close (new_fd) != 0)
++ if (close_not_cancel (new_fd) != 0)
+ /* The `close' call failed. */
+ _exit (SPAWN_ERROR);
+ }
+--- libc/sysdeps/unix/sysv/linux/local-setxid.h 1 Jan 1970 00:00:00 -0000
++++ libc/sysdeps/unix/sysv/linux/local-setxid.h 4 Jun 2006 22:15:39 -0000 1.1
+@@ -0,0 +1,23 @@
++/* SETxID functions which only have to change the local thread and
++ none of the possible other threads. */
++#include <kernel-features.h>
++#include <sysdep.h>
++
++/* If we can use the syscall directly, use it. */
++#if __ASSUME_32BITUIDS > 0 && defined __NR_setresuid32
++# define local_seteuid(id) INLINE_SYSCALL (setresuid32, 3, -1, id, -1)
++#elif __ASSUME_SETRESUID_SYSCALL > 0
++# define local_seteuid(id) INLINE_SYSCALL (setresuid, 3, -1, id, -1)
++#else
++# define local_seteuid(id) seteuid (id)
++#endif
++
++
++/* If we can use the syscall directly, use it. */
++#if __ASSUME_32BITUIDS > 0 && defined __NR_setresgid32
++# define local_setegid(id) INLINE_SYSCALL (setresgid32, 3, -1, id, -1)
++#elif __ASSUME_SETRESGID_SYSCALL > 0
++# define local_setegid(id) INLINE_SYSCALL (setresgid, 3, -1, id, -1)
++#else
++# define local_setegid(id) setegid (id)
++#endif
--- /dev/null
+2006-06-02 Jakub Jelinek <jakub@redhat.com>
+
+ * posix/regex_internal.c (re_string_skip_chars): If no character has
+ been converted at all, set *last_wc to WEOF. If mbrtowc failed, set wc
+ to the byte which couldn't be converted.
+ (re_string_reconstruct): Don't clear valid_raw_len before calling
+ re_string_skip_chars. If wc is WEOF after re_string_skip_chars, set
+ tip_context using re_string_context_at.
+ * posix/Makefile: Add rules to build and run bug-regex25 test.
+ * posix/bug-regex25.c: New test.
+
+--- libc/posix/Makefile 30 Apr 2006 20:16:28 -0000 1.190
++++ libc/posix/Makefile 4 Jun 2006 04:59:05 -0000 1.191
+@@ -81,7 +81,7 @@ tests := tstgetopt testfnm runtests run
+ bug-regex13 bug-regex14 bug-regex15 bug-regex16 \
+ bug-regex17 bug-regex18 bug-regex19 bug-regex20 \
+ bug-regex21 bug-regex22 bug-regex23 bug-regex24 \
+- tst-nice tst-nanosleep tst-regex2 \
++ bug-regex25 tst-nice tst-nanosleep tst-regex2 \
+ transbug tst-rxspencer tst-pcre tst-boost \
+ bug-ga1 tst-vfork1 tst-vfork2 tst-waitid \
+ tst-getaddrinfo2 bug-glob1 bug-glob2 tst-sysconf \
+@@ -188,6 +188,7 @@ bug-regex19-ENV = LOCPATH=$(common-objpf
+ bug-regex20-ENV = LOCPATH=$(common-objpfx)localedata
+ bug-regex22-ENV = LOCPATH=$(common-objpfx)localedata
+ bug-regex23-ENV = LOCPATH=$(common-objpfx)localedata
++bug-regex25-ENV = LOCPATH=$(common-objpfx)localedata
+ tst-rxspencer-ARGS = --utf8 rxspencer/tests
+ tst-rxspencer-ENV = LOCPATH=$(common-objpfx)localedata
+ tst-pcre-ARGS = PCRE.tests
+--- libc/posix/bug-regex25.c 1 Jan 1970 00:00:00 -0000
++++ libc/posix/bug-regex25.c 4 Jun 2006 04:58:35 -0000 1.1
+@@ -0,0 +1,57 @@
++/* Test re_search in multibyte locale other than UTF-8.
++ Copyright (C) 2006 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <locale.h>
++#include <regex.h>
++#include <stdio.h>
++#include <string.h>
++
++const char *str1 = "\xa3\xd8\xa3\xc9\xa3\xc9";
++const char *str2 = "\xa3\xd8\xa3\xc9";
++
++int
++main (void)
++{
++ setlocale (LC_ALL, "ja_JP.eucJP");
++
++ re_set_syntax (RE_SYNTAX_SED);
++
++ struct re_pattern_buffer re;
++ memset (&re, 0, sizeof (re));
++
++ struct re_registers regs;
++ memset (®s, 0, sizeof (regs));
++
++ re_compile_pattern ("$", 1, &re);
++
++ int ret = 0, r = re_search (&re, str1, 4, 0, 4, ®s);
++ if (r != 4)
++ {
++ printf ("First re_search returned %d\n", r);
++ ret = 1;
++ }
++ r = re_search (&re, str2, 4, 0, 4, ®s);
++ if (r != 4)
++ {
++ printf ("Second re_search returned %d\n", r);
++ ret = 1;
++ }
++ return ret;
++}
+--- libc/posix/regex_internal.c 15 Jan 2006 17:49:28 -0000 1.65
++++ libc/posix/regex_internal.c 4 Jun 2006 04:57:19 -0000 1.66
+@@ -497,7 +497,7 @@ re_string_skip_chars (pstr, new_raw_idx,
+ {
+ mbstate_t prev_st;
+ int rawbuf_idx, mbclen;
+- wchar_t wc = 0;
++ wchar_t wc = WEOF;
+
+ /* Skip the characters which are not necessary to check. */
+ for (rawbuf_idx = pstr->raw_mbs_idx + pstr->valid_raw_len;
+@@ -510,7 +510,11 @@ re_string_skip_chars (pstr, new_raw_idx,
+ remain_len, &pstr->cur_state);
+ if (BE (mbclen == (size_t) -2 || mbclen == (size_t) -1 || mbclen == 0, 0))
+ {
+- /* We treat these cases as a singlebyte character. */
++ /* We treat these cases as a single byte character. */
++ if (mbclen == 0 || remain_len == 0)
++ wc = L'\0';
++ else
++ wc = *(unsigned char *) (pstr->raw_mbs + rawbuf_idx);
+ mbclen = 1;
+ pstr->cur_state = prev_st;
+ }
+@@ -634,7 +638,6 @@ re_string_reconstruct (pstr, idx, eflags
+ }
+ #endif
+ pstr->valid_len = 0;
+- pstr->valid_raw_len = 0;
+ #ifdef RE_ENABLE_I18N
+ if (pstr->mb_cur_max > 1)
+ {
+@@ -683,6 +686,16 @@ re_string_reconstruct (pstr, idx, eflags
+
+ if (wc == WEOF)
+ pstr->valid_len = re_string_skip_chars (pstr, idx, &wc) - idx;
++ if (wc == WEOF)
++ pstr->tip_context
++ = re_string_context_at (pstr, pstr->valid_raw_len - 1, eflags);
++ else
++ pstr->tip_context = ((BE (pstr->word_ops_used != 0, 0)
++ && IS_WIDE_WORD_CHAR (wc))
++ ? CONTEXT_WORD
++ : ((IS_WIDE_NEWLINE (wc)
++ && pstr->newline_anchor)
++ ? CONTEXT_NEWLINE : 0));
+ if (BE (pstr->valid_len, 0))
+ {
+ for (wcs_idx = 0; wcs_idx < pstr->valid_len; ++wcs_idx)
+@@ -691,17 +704,12 @@ re_string_reconstruct (pstr, idx, eflags
+ memset (pstr->mbs, 255, pstr->valid_len);
+ }
+ pstr->valid_raw_len = pstr->valid_len;
+- pstr->tip_context = ((BE (pstr->word_ops_used != 0, 0)
+- && IS_WIDE_WORD_CHAR (wc))
+- ? CONTEXT_WORD
+- : ((IS_WIDE_NEWLINE (wc)
+- && pstr->newline_anchor)
+- ? CONTEXT_NEWLINE : 0));
+ }
+ else
+ #endif /* RE_ENABLE_I18N */
+ {
+ int c = pstr->raw_mbs[pstr->raw_mbs_idx + offset - 1];
++ pstr->valid_raw_len = 0;
+ if (pstr->trans)
+ c = pstr->trans[c];
+ pstr->tip_context = (bitset_contain (pstr->word_char, c)
--- /dev/null
+2006-06-22 Ulrich Drepper <drepper@redhat.com>
+
+ * intl/dcigettext.c (DCIGETTEXT): If _nl_find_msg returns -1 don't
+ look further, return original strings.
+ (_nl_find_msg): Do not return found translation if the conversion
+ failed. Either signal the string is unusable or that something went
+ wrong and the original should be used.
+
+--- libc/intl/dcigettext.c 15 May 2006 18:31:52 -0000 1.52
++++ libc/intl/dcigettext.c 22 Jun 2006 23:58:37 -0000 1.53
+@@ -581,6 +581,7 @@ DCIGETTEXT (domainname, msgid1, msgid2,
+ if (strcmp (single_locale, "C") == 0
+ || strcmp (single_locale, "POSIX") == 0)
+ {
++ no_translation:
+ FREE_BLOCKS (block_list);
+ __libc_rwlock_unlock (_nl_state_lock);
+ __set_errno (saved_errno);
+@@ -616,6 +617,12 @@ DCIGETTEXT (domainname, msgid1, msgid2,
+ }
+ }
+
++ /* Returning -1 means that some resource problem exists
++ (likely memory) and that the strings could not be
++ converted. Return the original strings. */
++ if (__builtin_expect (retval == (char *) -1, 0))
++ goto no_translation;
++
+ if (retval != NULL)
+ {
+ /* Found the translation of MSGID1 in domain DOMAIN:
+@@ -829,8 +836,9 @@ _nl_find_msg (domain_file, domainbinding
+ domain->conv_tab = (char **) -1;
+
+ if (__builtin_expect (domain->conv_tab == (char **) -1, 0))
+- /* Nothing we can do, no more memory. */
+- goto converted;
++ /* Nothing we can do, no more memory. We cannot use the
++ translation because it might be encoded incorrectly. */
++ return (char *) -1;
+
+ if (domain->conv_tab[act] == NULL)
+ {
+@@ -878,8 +886,10 @@ _nl_find_msg (domain_file, domainbinding
+
+ if (res != __GCONV_FULL_OUTPUT)
+ {
++ /* We should not use the translation at all, it
++ is incorrectly encoded. */
+ __libc_lock_unlock (lock);
+- goto converted;
++ return NULL;
+ }
+
+ inbuf = result;
+@@ -905,7 +915,7 @@ _nl_find_msg (domain_file, domainbinding
+ if (errno != E2BIG)
+ {
+ __libc_lock_unlock (lock);
+- goto converted;
++ return NULL;
+ }
+ # endif
+ # endif
+@@ -941,7 +951,7 @@ _nl_find_msg (domain_file, domainbinding
+ freemem = NULL;
+ freemem_size = 0;
+ __libc_lock_unlock (lock);
+- goto converted;
++ return (char *) -1;
+ }
+
+ # ifdef _LIBC
+@@ -979,7 +989,6 @@ _nl_find_msg (domain_file, domainbinding
+ resultlen = *(size_t *) domain->conv_tab[act];
+ }
+
+- converted:
+ /* The result string is converted. */
+
+ #endif /* _LIBC || HAVE_ICONV */
--- /dev/null
+2006-08-31 Jakub Jelinek <jakub@redhat.com>
+
+ * malloc/malloc.c (_int_malloc): Use full list insert and not
+ shortcut which assumes the list is empty for large requests
+ too.
+
+2006-08-26 Ulrich Drepper <drepper@redhat.com>
+
+ * malloc/malloc.c (_int_malloc): Fix test for large enough buffer
+ for early termination. When no unsorted block matches perfectly
+ and an exiting block has to be split, use full list insert and
+ not shortcut which assumes the list is empty.
+
+2006-08-19 Ulrich Drepper <drepper@redhat.com>
+
+ * malloc/malloc.c (_int_malloc): Limit number of unsorted blocks
+ to sort in each call.
+
+--- libc/malloc/malloc.c 9 Aug 2006 21:50:30 -0000
++++ libc/malloc/malloc.c 7 Sep 2006 16:06:02 -0000
+@@ -4055,6 +4096,8 @@ _int_malloc(mstate av, size_t bytes)
+
+ for(;;) {
+
++ int iters = 0;
++ bool any_larger = false;
+ while ( (victim = unsorted_chunks(av)->bk) != unsorted_chunks(av)) {
+ bck = victim->bk;
+ if (__builtin_expect (victim->size <= 2 * SIZE_SZ, 0)
+@@ -4150,6 +4193,12 @@ _int_malloc(mstate av, size_t bytes)
+ victim->fd = fwd;
+ fwd->bk = victim;
+ bck->fd = victim;
++
++ if (size >= nb + MINSIZE)
++ any_larger = true;
++#define MAX_ITERS 10000
++ if (++iters >= MAX_ITERS)
++ break;
+ }
+
+ /*
+@@ -4182,8 +4231,14 @@ _int_malloc(mstate av, size_t bytes)
+ /* Split */
+ else {
+ remainder = chunk_at_offset(victim, nb);
+- unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder;
+- remainder->bk = remainder->fd = unsorted_chunks(av);
++ /* We cannot assume the unsorted list is empty and therefore
++ have to perform a complete insert here. */
++ bck = unsorted_chunks(av);
++ fwd = bck->fd;
++ remainder->bk = bck;
++ remainder->fd = fwd;
++ bck->fd = remainder;
++ fwd->bk = remainder;
+ set_head(victim, nb | PREV_INUSE |
+ (av != &main_arena ? NON_MAIN_ARENA : 0));
+ set_head(remainder, remainder_size | PREV_INUSE);
+@@ -4268,8 +4323,15 @@ _int_malloc(mstate av, size_t bytes)
+ else {
+ remainder = chunk_at_offset(victim, nb);
+
+- unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder;
+- remainder->bk = remainder->fd = unsorted_chunks(av);
++ /* We cannot assume the unsorted list is empty and therefore
++ have to perform a complete insert here. */
++ bck = unsorted_chunks(av);
++ fwd = bck->fd;
++ remainder->bk = bck;
++ remainder->fd = fwd;
++ bck->fd = remainder;
++ fwd->bk = remainder;
++
+ /* advertise as last remainder */
+ if (in_smallbin_range(nb))
+ av->last_remainder = remainder;
--- /dev/null
+2006-07-26 Gavin Romig-Koch <gavin@redhat.com>
+
+ * stdlib/cxa_atexit.c (__new_exitfn_called): New variable.
+ (__new_exitfn): Bump it in every successful call.
+ * stdlib/cxa_finalize.c (__cxa_finalize): If destructor registered
+ more exit handlers, call them right away.
+ * stdlib/exit.h: Declare __new_exitfn_called.
+
+2006-07-25 Ulrich Drepper <drepper@redhat.com>
+
+ * stdlib/cxa_finalize.c (__cxa_finalize): Fix race condition when
+ calling registered handler.
+
+--- libc/stdlib/cxa_atexit.c 18 Dec 2005 17:30:24 -0000 1.7
++++ libc/stdlib/cxa_atexit.c 26 Jul 2006 07:24:45 -0000 1.8
+@@ -48,6 +48,7 @@ __libc_lock_define_initialized (static,
+
+ static struct exit_function_list initial;
+ struct exit_function_list *__exit_funcs = &initial;
++uint64_t __new_exitfn_called;
+
+ struct exit_function *
+ __new_exitfn (void)
+@@ -88,7 +89,10 @@ __new_exitfn (void)
+
+ /* Mark entry as used, but we don't know the flavor now. */
+ if (l != NULL)
+- l->fns[i].flavor = ef_us;
++ {
++ l->fns[i].flavor = ef_us;
++ ++__new_exitfn_called;
++ }
+
+ __libc_lock_unlock (lock);
+
+--- libc/stdlib/cxa_finalize.c 18 Dec 2005 17:31:14 -0000 1.9
++++ libc/stdlib/cxa_finalize.c 26 Jul 2006 07:25:44 -0000 1.12
+@@ -30,16 +30,33 @@ __cxa_finalize (void *d)
+ {
+ struct exit_function_list *funcs;
+
++ restart:
+ for (funcs = __exit_funcs; funcs; funcs = funcs->next)
+ {
+ struct exit_function *f;
+
+ for (f = &funcs->fns[funcs->idx - 1]; f >= &funcs->fns[0]; --f)
+- if ((d == NULL || d == f->func.cxa.dso_handle)
+- /* We don't want to run this cleanup more than once. */
+- && ! atomic_compare_and_exchange_bool_acq (&f->flavor, ef_free,
+- ef_cxa))
+- (*f->func.cxa.fn) (f->func.cxa.arg, 0);
++ {
++ void (*cxafn) (void *arg, int status);
++ void *cxaarg;
++
++ if ((d == NULL || d == f->func.cxa.dso_handle)
++ /* We don't want to run this cleanup more than once. */
++ && (cxafn = f->func.cxa.fn,
++ cxaarg = f->func.cxa.arg,
++ ! atomic_compare_and_exchange_bool_acq (&f->flavor, ef_free,
++ ef_cxa)))
++ {
++ uint64_t check = __new_exitfn_called;
++
++ cxafn (cxaarg, 0);
++
++ /* It is possible that that last exit function registered
++ more exit functions. Start the loop over. */
++ if (__builtin_expect (check != __new_exitfn_called, 0))
++ goto restart;
++ }
++ }
+ }
+
+ /* Remove the registered fork handlers. We do not have to
+--- libc/stdlib/exit.h 12 Mar 2002 18:47:24 -0000 1.10
++++ libc/stdlib/exit.h 26 Jul 2006 07:23:43 -0000 1.11
+@@ -19,6 +20,7 @@
+ #ifndef _EXIT_H
+ #define _EXIT_H 1
+
++#include <stdint.h>
+
+ enum
+ {
+@@ -59,5 +61,6 @@ struct exit_function_list
+ extern struct exit_function_list *__exit_funcs attribute_hidden;
+
+ extern struct exit_function *__new_exitfn (void);
++extern uint64_t __new_exitfn_called attribute_hidden;
+
+ #endif /* exit.h */
--- /dev/null
+2006-08-08 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/unix/sysv/linux/ia64/bits/fcntl.h (O_DIRECT): Protect with
+ __USE_GNU.
+
+--- libc/sysdeps/unix/sysv/linux/ia64/bits/fcntl.h 26 Jul 2006 01:27:05 -0000 1.14
++++ libc/sysdeps/unix/sysv/linux/ia64/bits/fcntl.h 8 Aug 2006 18:28:06 -0000 1.15
+@@ -43,9 +43,9 @@
+ #define O_SYNC 010000
+ #define O_FSYNC O_SYNC
+ #define O_ASYNC 020000
+-#define O_DIRECT 040000
+
+ #ifdef __USE_GNU
++# define O_DIRECT 040000
+ # define O_DIRECTORY 0200000 /* must be a directory */
+ # define O_NOFOLLOW 0400000 /* don't follow links */
+ # define O_NOATIME 01000000 /* Do not set atime. */
--- /dev/null
+2006-08-09 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/unix/nice.c (nice): Transform EACCES errno from setpriority
+ to EPERM.
+
+--- libc/sysdeps/unix/nice.c 28 Sep 2002 19:13:13 -0000 1.6
++++ libc/sysdeps/unix/nice.c 15 Aug 2006 05:24:45 -0000 1.7
+@@ -47,9 +47,11 @@ nice (int incr)
+ else if (prio >= PRIO_MAX)
+ prio = PRIO_MAX - 1;
+ result = setpriority (PRIO_PROCESS, 0, prio);
+- if (result != -1)
+- return getpriority (PRIO_PROCESS, 0);
+- else
+- return -1;
+-
++ if (result == -1)
++ {
++ if (errno == EACCES)
++ errno = EPERM;
++ return -1;
++ }
++ return getpriority (PRIO_PROCESS, 0);
+ }
--- /dev/null
+2006-09-06 Jakub Jelinek <jakub@redhat.com>
+
+ * posix/regex_internal.c (re_string_reconstruct): Handle
+ offset < pstr->valid_raw_len && pstr->offsets_needed case.
+ Ensure no bytes read before raw_mbs array. Pass a saved copy of
+ pstr->valid_len - 1 rather than pstr->valid_raw_len - 1 to
+ re_string_context_at.
+ * posix/Makefile: Add rules to build and run bug-regex26 test.
+ * posix/bug-regex26.c: New test.
+
+--- libc/posix/Makefile 2 Aug 2006 16:43:46 -0000 1.192
++++ libc/posix/Makefile 7 Sep 2006 13:50:05 -0000 1.193
+@@ -81,7 +81,7 @@ tests := tstgetopt testfnm runtests run
+ bug-regex13 bug-regex14 bug-regex15 bug-regex16 \
+ bug-regex17 bug-regex18 bug-regex19 bug-regex20 \
+ bug-regex21 bug-regex22 bug-regex23 bug-regex24 \
+- bug-regex25 tst-nice tst-nanosleep tst-regex2 \
++ bug-regex25 bug-regex26 tst-nice tst-nanosleep tst-regex2 \
+ transbug tst-rxspencer tst-pcre tst-boost \
+ bug-ga1 tst-vfork1 tst-vfork2 tst-waitid \
+ tst-getaddrinfo2 bug-glob1 bug-glob2 tst-sysconf \
+@@ -189,6 +189,7 @@ bug-regex20-ENV = LOCPATH=$(common-objpf
+ bug-regex22-ENV = LOCPATH=$(common-objpfx)localedata
+ bug-regex23-ENV = LOCPATH=$(common-objpfx)localedata
+ bug-regex25-ENV = LOCPATH=$(common-objpfx)localedata
++bug-regex26-ENV = LOCPATH=$(common-objpfx)localedata
+ tst-rxspencer-ARGS = --utf8 rxspencer/tests
+ tst-rxspencer-ENV = LOCPATH=$(common-objpfx)localedata
+ tst-pcre-ARGS = PCRE.tests
+--- libc/posix/bug-regex26.c 1 Jan 1970 00:00:00 -0000
++++ libc/posix/bug-regex26.c 7 Sep 2006 13:49:22 -0000 1.2
+@@ -0,0 +1,38 @@
++/* Test re_search with dotless i.
++ Copyright (C) 2006 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <locale.h>
++#include <regex.h>
++#include <string.h>
++
++int
++main (void)
++{
++ struct re_pattern_buffer r;
++ struct re_registers s;
++ setlocale (LC_ALL, "en_US.UTF-8");
++ memset (&r, 0, sizeof (r));
++ memset (&s, 0, sizeof (s));
++ re_set_syntax (RE_SYNTAX_GREP | RE_HAT_LISTS_NOT_NEWLINE | RE_ICASE);
++ re_compile_pattern ("insert into", 11, &r);
++ re_search (&r, "\xFF\0\x12\xA2\xAA\xC4\xB1,K\x12\xC4\xB1*\xACK",
++ 15, 0, 15, &s);
++ return 0;
++}
+--- libc/posix/regex_internal.c 4 Jun 2006 04:57:19 -0000 1.66
++++ libc/posix/regex_internal.c 7 Sep 2006 13:48:12 -0000 1.67
+@@ -601,34 +601,98 @@ re_string_reconstruct (pstr, idx, eflags
+
+ if (BE (offset != 0, 1))
+ {
+- /* Are the characters which are already checked remain? */
+- if (BE (offset < pstr->valid_raw_len, 1)
+-#ifdef RE_ENABLE_I18N
+- /* Handling this would enlarge the code too much.
+- Accept a slowdown in that case. */
+- && pstr->offsets_needed == 0
+-#endif
+- )
++ /* Should the already checked characters be kept? */
++ if (BE (offset < pstr->valid_raw_len, 1))
+ {
+ /* Yes, move them to the front of the buffer. */
+- pstr->tip_context = re_string_context_at (pstr, offset - 1, eflags);
+ #ifdef RE_ENABLE_I18N
+- if (pstr->mb_cur_max > 1)
+- memmove (pstr->wcs, pstr->wcs + offset,
+- (pstr->valid_len - offset) * sizeof (wint_t));
++ if (BE (pstr->offsets_needed, 0))
++ {
++ int low = 0, high = pstr->valid_len, mid;
++ do
++ {
++ mid = (high + low) / 2;
++ if (pstr->offsets[mid] > offset)
++ high = mid;
++ else if (pstr->offsets[mid] < offset)
++ low = mid + 1;
++ else
++ break;
++ }
++ while (low < high);
++ if (pstr->offsets[mid] < offset)
++ ++mid;
++ pstr->tip_context = re_string_context_at (pstr, mid - 1,
++ eflags);
++ /* This can be quite complicated, so handle specially
++ only the common and easy case where the character with
++ different length representation of lower and upper
++ case is present at or after offset. */
++ if (pstr->valid_len > offset
++ && mid == offset && pstr->offsets[mid] == offset)
++ {
++ memmove (pstr->wcs, pstr->wcs + offset,
++ (pstr->valid_len - offset) * sizeof (wint_t));
++ memmove (pstr->mbs, pstr->mbs + offset, pstr->valid_len - offset);
++ pstr->valid_len -= offset;
++ pstr->valid_raw_len -= offset;
++ for (low = 0; low < pstr->valid_len; low++)
++ pstr->offsets[low] = pstr->offsets[low + offset] - offset;
++ }
++ else
++ {
++ /* Otherwise, just find out how long the partial multibyte
++ character at offset is and fill it with WEOF/255. */
++ pstr->len = pstr->raw_len - idx + offset;
++ pstr->stop = pstr->raw_stop - idx + offset;
++ pstr->offsets_needed = 0;
++ while (mid > 0 && pstr->offsets[mid - 1] == offset)
++ --mid;
++ while (mid < pstr->valid_len)
++ if (pstr->wcs[mid] != WEOF)
++ break;
++ else
++ ++mid;
++ if (mid == pstr->valid_len)
++ pstr->valid_len = 0;
++ else
++ {
++ pstr->valid_len = pstr->offsets[mid] - offset;
++ if (pstr->valid_len)
++ {
++ for (low = 0; low < pstr->valid_len; ++low)
++ pstr->wcs[low] = WEOF;
++ memset (pstr->mbs, 255, pstr->valid_len);
++ }
++ }
++ pstr->valid_raw_len = pstr->valid_len;
++ }
++ }
++ else
++#endif
++ {
++ pstr->tip_context = re_string_context_at (pstr, offset - 1,
++ eflags);
++#ifdef RE_ENABLE_I18N
++ if (pstr->mb_cur_max > 1)
++ memmove (pstr->wcs, pstr->wcs + offset,
++ (pstr->valid_len - offset) * sizeof (wint_t));
+ #endif /* RE_ENABLE_I18N */
+- if (BE (pstr->mbs_allocated, 0))
+- memmove (pstr->mbs, pstr->mbs + offset,
+- pstr->valid_len - offset);
+- pstr->valid_len -= offset;
+- pstr->valid_raw_len -= offset;
++ if (BE (pstr->mbs_allocated, 0))
++ memmove (pstr->mbs, pstr->mbs + offset,
++ pstr->valid_len - offset);
++ pstr->valid_len -= offset;
++ pstr->valid_raw_len -= offset;
+ #if DEBUG
+- assert (pstr->valid_len > 0);
++ assert (pstr->valid_len > 0);
+ #endif
++ }
+ }
+ else
+ {
+ /* No, skip all characters until IDX. */
++ int prev_valid_len = pstr->valid_len;
++
+ #ifdef RE_ENABLE_I18N
+ if (BE (pstr->offsets_needed, 0))
+ {
+@@ -652,6 +716,8 @@ re_string_reconstruct (pstr, idx, eflags
+ byte other than 0x80 - 0xbf. */
+ raw = pstr->raw_mbs + pstr->raw_mbs_idx;
+ end = raw + (offset - pstr->mb_cur_max);
++ if (end < pstr->raw_mbs)
++ end = pstr->raw_mbs;
+ for (p = raw + offset - 1; p >= end; --p)
+ if ((*p & 0xc0) != 0x80)
+ {
+@@ -688,7 +754,7 @@ re_string_reconstruct (pstr, idx, eflags
+ pstr->valid_len = re_string_skip_chars (pstr, idx, &wc) - idx;
+ if (wc == WEOF)
+ pstr->tip_context
+- = re_string_context_at (pstr, pstr->valid_raw_len - 1, eflags);
++ = re_string_context_at (pstr, prev_valid_len - 1, eflags);
+ else
+ pstr->tip_context = ((BE (pstr->word_ops_used != 0, 0)
+ && IS_WIDE_WORD_CHAR (wc))
--- /dev/null
+2006-08-19 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nss_nis/nis-service.c (internal_nis_getservent_r): . If map
+ is empty simply return and use next service.
+ * nis/nss_nis/nis-rpc.c (internal_nis_getrpcent_r): Likewise.
+
+--- libc/nis/nss_nis/nis-rpc.c 29 Apr 2006 01:12:53 -0000 1.21
++++ libc/nis/nss_nis/nis-rpc.c 19 Aug 2006 18:35:44 -0000 1.22
+@@ -117,6 +117,10 @@ internal_nis_getrpcent_r (struct rpcent
+ if (intern->start == NULL)
+ internal_nis_setrpcent (intern);
+
++ if (intern->next == NULL)
++ /* Not one entry in the map. */
++ return NSS_STATUS_NOTFOUND;
++
+ /* Get the next entry until we found a correct one. */
+ do
+ {
+--- libc/nis/nss_nis/nis-service.c 9 May 2006 19:06:22 -0000 1.35
++++ libc/nis/nss_nis/nis-service.c 19 Aug 2006 18:36:25 -0000 1.36
+@@ -188,6 +188,10 @@ internal_nis_getservent_r (struct serven
+ if (intern.start == NULL)
+ internal_nis_setservent ();
+
++ if (intern.next == NULL)
++ /* Not one entry in the map. */
++ return NSS_STATUS_NOTFOUND;
++
+ /* Get the next entry until we found a correct one. */
+ do
+ {
--- /dev/null
+2007-03-15 Jakub Jelinek <jakub@redhat.com>
+
+ * locale/programs/ld-ctype.c (find_translit): Return NULL if ctype is
+ NULL.
+
+2006-08-28 Jakub Jelinek <jakub@redhat.com>
+
+ * locale/programs/ld-ctype.c (translit_flatten): Issue error
+ if other's ctype category was missing.
+ * locale/programs/ld-collate.c (collate_read): Return if
+ copy_locale's collate category is missing.
+
+2006-08-26 Ulrich Drepper <drepper@redhat.com>
+
+ * locale/programs/ld-ctype.c (ctype_read): Better patch for read
+ failure.
+
+2006-08-24 Ulrich Drepper <drepper@redhat.com>
+
+ * locale/programs/ld-ctype.c (ctype_read): If CTYPE is NULL, don't
+ do anything.
+
+--- libc/locale/programs/ld-collate.c 7 Dec 2005 05:47:27 -0000 1.107
++++ libc/locale/programs/ld-collate.c 28 Aug 2006 16:17:10 -0000 1.108
+@@ -2671,6 +2671,9 @@ collate_read (struct linereader *ldfile,
+ if (locfile_read (copy_locale, charmap) != 0)
+ goto skip_category;
+ }
++
++ if (copy_locale->categories[LC_COLLATE].collate == NULL)
++ return;
+ }
+
+ lr_ignore_rest (ldfile, 1);
+--- libc/locale/programs/ld-ctype.c 12 Aug 2006 20:19:14 -0000
++++ libc/locale/programs/ld-ctype.c 17 Mar 2007 16:52:21 -0000
+@@ -1866,6 +1866,9 @@ find_translit (struct localedef_t *local
+ assert (locale != NULL);
+ ctype = locale->categories[LC_CTYPE].ctype;
+
++ if (ctype == NULL)
++ return NULL;
++
+ if (ctype->translit != NULL)
+ result = find_translit2 (ctype, charmap, wch);
+
+@@ -2245,6 +2248,9 @@ ctype_read (struct linereader *ldfile, s
+ if (locfile_read (copy_locale, charmap) != 0)
+ goto skip_category;
+ }
++
++ if (copy_locale->categories[LC_CTYPE].ctype == NULL)
++ return;
+ }
+
+ lr_ignore_rest (ldfile, 1);
+@@ -3766,7 +3772,7 @@ translit_flatten (struct locale_ctype_t
+
+ other = find_locale (LC_CTYPE, copy_locale, copy_repertoire, charmap);
+
+- if (other == NULL)
++ if (other == NULL || other->categories[LC_CTYPE].ctype == NULL)
+ {
+ WITH_CUR_LOCALE (error (0, 0, _("\
+ %s: transliteration data from locale `%s' not available"),
--- /dev/null
+2006-08-24 Jakub Jelinek <jakub@redhat.com>
+
+ * malloc/malloc.c (sYSMALLOc): Avoid infinite loop if MMAP
+ keeps failing and heap growth or new heap creation isn't
+ successful either.
+ * malloc/tst-malloc.c (main): Add new tests.
+
+--- libc/malloc/malloc.c 9 Aug 2006 21:50:30 -0000 1.159
++++ libc/malloc/malloc.c 7 Sep 2006 16:06:02 -0000 1.168
+@@ -2851,6 +2862,7 @@ static Void_t* sYSMALLOc(nb, av) INTERNA
+ unsigned long sum; /* for updating stats */
+
+ size_t pagemask = mp_.pagesize - 1;
++ bool tried_mmap = false;
+
+
+ #if HAVE_MMAP
+@@ -2867,12 +2879,14 @@ static Void_t* sYSMALLOc(nb, av) INTERNA
+
+ char* mm; /* return value from mmap call*/
+
++ try_mmap:
+ /*
+ Round up size to nearest page. For mmapped chunks, the overhead
+ is one SIZE_SZ unit larger than for normal chunks, because there
+ is no following chunk whose prev_size field could be used.
+ */
+ size = (nb + SIZE_SZ + MALLOC_ALIGN_MASK + pagemask) & ~pagemask;
++ tried_mmap = true;
+
+ /* Don't try if size wraps around 0 */
+ if ((unsigned long)(size) > (unsigned long)(nb)) {
+@@ -2996,6 +3011,9 @@ static Void_t* sYSMALLOc(nb, av) INTERNA
+ set_foot(old_top, (old_size + 2*SIZE_SZ));
+ }
+ }
++ else if (!tried_mmap)
++ /* We can at least try to use to mmap memory. */
++ goto try_mmap;
+
+ } else { /* av == main_arena */
+
+--- libc/malloc/tst-malloc.c 6 Jul 2001 04:55:35 -0000 1.2
++++ libc/malloc/tst-malloc.c 24 Aug 2006 17:30:10 -0000 1.3
+@@ -33,7 +33,7 @@ merror (const char *msg)
+ int
+ main (void)
+ {
+- void *p;
++ void *p, *q;
+ int save;
+
+ errno = 0;
+@@ -64,5 +64,15 @@ main (void)
+ if (p != NULL)
+ merror ("realloc (p, 0) failed.");
+
++ p = malloc (513 * 1024);
++ if (p == NULL)
++ merror ("malloc (513K) failed.");
++
++ q = malloc (-512 * 1024);
++ if (q != NULL)
++ merror ("malloc (-512K) succeeded.");
++
++ free (p);
++
+ return errors != 0;
+ }
--- /dev/null
+2006-08-28 Jakub Jelinek <jakub@redhat.com>
+
+ * inet/getnameinfo.c (getnameinfo): For AF_INET, check errno
+ only if herrno is NETDB_INTERNAL. Handle errors other than
+ ERANGE outside of the loops, handle TRY_AGAIN.
+
+--- libc/inet/getnameinfo.c 6 Apr 2006 21:51:24 -0000 1.34
++++ libc/inet/getnameinfo.c 28 Aug 2006 16:23:18 -0000 1.35
+@@ -203,48 +203,40 @@ getnameinfo (const struct sockaddr *sa,
+ if (!(flags & NI_NUMERICHOST))
+ {
+ struct hostent *h = NULL;
++ if (sa->sa_family == AF_INET6)
++ {
++ while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in6 *) sa)->sin6_addr),
++ sizeof(struct in6_addr),
++ AF_INET6, &th, tmpbuf, tmpbuflen,
++ &h, &herrno))
++ if (herrno == NETDB_INTERNAL && errno == ERANGE)
++ tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
++ else
++ break;
++ }
++ else
++ {
++ while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in *)sa)->sin_addr),
++ sizeof(struct in_addr), AF_INET,
++ &th, tmpbuf, tmpbuflen,
++ &h, &herrno))
++ if (herrno == NETDB_INTERNAL && errno == ERANGE)
++ tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen);
++ else
++ break;
++ }
++
+ if (h == NULL)
+ {
+- if (sa->sa_family == AF_INET6)
++ if (herrno == NETDB_INTERNAL)
+ {
+- while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in6 *) sa)->sin6_addr),
+- sizeof(struct in6_addr),
+- AF_INET6, &th, tmpbuf, tmpbuflen,
+- &h, &herrno))
+- {
+- if (herrno == NETDB_INTERNAL)
+- {
+- if (errno == ERANGE)
+- tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
+- 2 * tmpbuflen);
+- else
+- {
+- __set_h_errno (herrno);
+- __set_errno (serrno);
+- return EAI_SYSTEM;
+- }
+- }
+- else
+- {
+- break;
+- }
+- }
++ __set_h_errno (herrno);
++ return EAI_SYSTEM;
+ }
+- else
++ if (herrno == TRY_AGAIN)
+ {
+- while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in *)sa)->sin_addr),
+- sizeof(struct in_addr), AF_INET,
+- &th, tmpbuf, tmpbuflen,
+- &h, &herrno))
+- {
+- if (errno == ERANGE)
+- tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
+- 2 * tmpbuflen);
+- else
+- {
+- break;
+- }
+- }
++ __set_h_errno (herrno);
++ return EAI_AGAIN;
+ }
+ }
+
+@@ -361,10 +353,7 @@ getnameinfo (const struct sockaddr *sa,
+ (const void *) &(((const struct sockaddr_in *) sa)->sin_addr),
+ host, hostlen);
+ if (c == NULL)
+- {
+- __set_errno (serrno);
+- return EAI_SYSTEM;
+- }
++ return EAI_SYSTEM;
+ }
+ ok = 1;
+ }
--- /dev/null
+2006-09-04 Jakub Jelinek <jakub@redhat.com>
+
+ * resolv/res_mkquery.c (res_nmkquery): Set hp->id to statp->id after
+ randomization rather than before.
+ * resolv/res_init.c (res_randomid): Don't call gettimeofday here.
+
+--- libc/resolv/res_init.c 1 Nov 2005 00:05:17 -0000 1.43
++++ libc/resolv/res_init.c 4 Sep 2006 17:59:54 -0000 1.44
+@@ -537,10 +537,7 @@ net_mask(in) /* XXX - should really use
+
+ u_int
+ res_randomid(void) {
+- struct timeval now;
+-
+- __gettimeofday(&now, NULL);
+- return (0xffff & (now.tv_sec ^ now.tv_usec ^ __getpid()));
++ return 0xffff & __getpid();
+ }
+ #ifdef _LIBC
+ libc_hidden_def (__res_randomid)
+--- libc/resolv/res_mkquery.c 6 May 2006 18:04:12 -0000 1.16
++++ libc/resolv/res_mkquery.c 4 Sep 2006 17:57:02 -0000 1.17
+@@ -124,10 +124,6 @@ res_nmkquery(res_state statp,
+ incremented by one after the initial randomization which
+ still predictable if the application does multiple
+ requests. */
+-#if 0
+- hp->id = htons(++statp->id);
+-#else
+- hp->id = htons(statp->id);
+ int randombits;
+ do
+ {
+@@ -141,7 +137,7 @@ res_nmkquery(res_state statp,
+ }
+ while ((randombits & 0xffff) == 0);
+ statp->id = (statp->id + randombits) & 0xffff;
+-#endif
++ hp->id = htons(statp->id);
+ hp->opcode = op;
+ hp->rd = (statp->options & RES_RECURSE) != 0;
+ hp->rcode = NOERROR;
--- /dev/null
+2006-10-10 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nis_subr.c (nis_getnames): Add trailing dot to NIS_PATH
+ components which lack them.
+
+ * nis/nis_subr.c (nis_getnames): Make sure that we always return
+ at least one entry consisting of the parameter concatenated with
+ the domain.
+
+--- libc/nis/nis_subr.c 16 Jun 2006 22:30:02 -0000 1.15
++++ libc/nis/nis_subr.c 11 Oct 2006 01:27:38 -0000 1.17
+@@ -251,13 +251,16 @@ nis_getnames (const_nis_name name)
+ {
+ char *p;
+
+- tmp = malloc (cplen + name_len + 2);
++ tmp = malloc (cplen + name_len + 3);
+ if (__builtin_expect (tmp == NULL, 0))
+ goto free_null;
+
+- p = __stpcpy (tmp, name);
++ p = __mempcpy (tmp, name, name_len);
+ *p++ = '.';
+- memcpy (p, cp, cplen + 1);
++ p = __mempcpy (p, cp, cplen);
++ if (p[-1] != '.')
++ *p++ = '.';
++ *p = '\0';
+ }
+
+ if (pos >= count)
+@@ -275,6 +278,13 @@ nis_getnames (const_nis_name name)
+ cp = __strtok_r (NULL, ":", &saveptr);
+ }
+
++ if (pos == 0
++ && __asprintf (&getnames[pos++], "%s%s%s%s",
++ name, name[name_len - 1] == '.' ? "" : ".",
++ local_domain,
++ local_domain[local_domain_len - 1] == '.' ? "" : ".") < 0)
++ goto free_null;
++
+ getnames[pos] = NULL;
+
+ return getnames;
--- /dev/null
+2006-09-19 Ulrich Drepper <drepper@redhat.com>
+
+ * elf/dl-close.c (_dl_close): If dependency is not unloaded make
+ sure no reference to the unloaded map's search list remains in the
+ dependency's scope.
+
+2006-09-16 Jakub Jelinek <jakub@redhat.com>
+
+ * elf/Makefile: Add rules to build and run unload7 test.
+ * elf/unload7.c: New test.
+ * elf/unload7mod1.c: New file.
+ * elf/unload7mod2.c: New file.
+
+--- libc/elf/Makefile 24 Aug 2006 20:19:45 -0000 1.314
++++ libc/elf/Makefile 19 Sep 2006 14:41:41 -0000 1.315
+@@ -87,6 +87,7 @@ distribute := rtld-Rules \
+ unload3mod1.c unload3mod2.c unload3mod3.c unload3mod4.c \
+ unload4mod1.c unload4mod2.c unload4mod3.c unload4mod4.c \
+ unload6mod1.c unload6mod2.c unload6mod3.c \
++ unload7mod1.c unload7mod2.c \
+ order2mod1.c order2mod2.c order2mod3.c order2mod4.c \
+ tst-leaks1.c
+
+@@ -160,7 +161,7 @@ tests += loadtest restest1 preloadtest l
+ tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-align \
+ tst-align2 $(tests-execstack-$(have-z-execstack)) tst-dlmodcount \
+ tst-dlopenrpath tst-deep1 tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
+- unload3 unload4 unload5 unload6 tst-global1 order2
++ unload3 unload4 unload5 unload6 unload7 tst-global1 order2
+ # reldep9
+ test-srcs = tst-pathopt
+ tests-vis-yes = vismain
+@@ -200,6 +201,7 @@ modules-names = testobj1 testobj2 testob
+ unload3mod1 unload3mod2 unload3mod3 unload3mod4 \
+ unload4mod1 unload4mod2 unload4mod3 unload4mod4 \
+ unload6mod1 unload6mod2 unload6mod3 \
++ unload7mod1 unload7mod2 \
+ order2mod1 order2mod2 order2mod3 order2mod4
+ ifeq (yes,$(have-initfini-array))
+ modules-names += tst-array2dep
+@@ -440,6 +442,8 @@ $(objpfx)unload4mod2.so: $(objpfx)unload
+ $(objpfx)unload6mod1.so: $(libdl)
+ $(objpfx)unload6mod2.so: $(libdl)
+ $(objpfx)unload6mod3.so: $(libdl)
++$(objpfx)unload7mod1.so: $(libdl)
++$(objpfx)unload7mod2.so: $(objpfx)unload7mod1.so
+
+ LDFLAGS-tst-tlsmod5.so = -nostdlib
+ LDFLAGS-tst-tlsmod6.so = -nostdlib
+@@ -712,6 +716,10 @@ $(objpfx)unload6: $(libdl)
+ $(objpfx)unload6.out: $(objpfx)unload6mod1.so $(objpfx)unload6mod2.so \
+ $(objpfx)unload6mod3.so
+
++$(objpfx)unload7: $(libdl)
++$(objpfx)unload7.out: $(objpfx)unload7mod1.so $(objpfx)unload7mod2.so
++unload7-ENV = MALLOC_PERTURB_=85
++
+ ifdef libdl
+ $(objpfx)tst-tls9-static: $(common-objpfx)dlfcn/libdl.a
+ $(objpfx)tst-tls9-static.out: $(objpfx)tst-tlsmod5.so $(objpfx)tst-tlsmod6.so
+--- libc/elf/dl-close.c 27 Apr 2005 01:32:01 -0000 1.116
++++ libc/elf/dl-close.c 19 Sep 2006 14:39:42 -0000 1.117
+@@ -330,7 +330,7 @@ _dl_close (void *_map)
+
+ for (cnt = 0; imap->l_scope[cnt] != NULL; ++cnt)
+ /* This relies on l_scope[] entries being always set either
+- to its own l_symbolic_searchlist address, or some other map's
++ to its own l_symbolic_searchlist address, or some map's
+ l_searchlist address. */
+ if (imap->l_scope[cnt] != &imap->l_symbolic_searchlist)
+ {
+@@ -347,6 +347,21 @@ _dl_close (void *_map)
+ }
+ }
+ }
++ else
++ {
++ unsigned int cnt = 0;
++ while (imap->l_scope[cnt] != NULL)
++ {
++ if (imap->l_scope[cnt] == &map->l_searchlist)
++ {
++ while ((imap->l_scope[cnt] = imap->l_scope[cnt + 1])
++ != NULL)
++ ++cnt;
++ break;
++ }
++ ++cnt;
++ }
++ }
+
+ /* The loader is gone, so mark the object as not having one.
+ Note: l_idx != -1 -> object will be removed. */
+--- libc/elf/unload7.c 1 Jan 1970 00:00:00 -0000
++++ libc/elf/unload7.c 19 Sep 2006 14:41:09 -0000 1.1
+@@ -0,0 +1,39 @@
++#include <dlfcn.h>
++#include <stdio.h>
++
++int
++main (void)
++{
++ void *h = dlopen ("$ORIGIN/unload7mod1.so", RTLD_LAZY);
++ if (h == NULL)
++ {
++ puts ("dlopen unload7mod1.so failed");
++ return 1;
++ }
++
++ int (*fn) (void);
++ fn = dlsym (h, "foo");
++ if (fn == NULL)
++ {
++ puts ("dlsym failed");
++ return 1;
++ }
++
++ int ret = 0;
++ if (fn () == 0)
++ ++ret;
++
++ void *h2 = dlopen ("$ORIGIN/unload7mod2.so", RTLD_LAZY);
++ if (h2 == NULL)
++ {
++ puts ("dlopen unload7mod2.so failed");
++ return 1;
++ }
++ dlclose (h2);
++
++ if (fn () == 0)
++ ++ret;
++
++ dlclose (h);
++ return ret;
++}
+--- libc/elf/unload7mod1.c 1 Jan 1970 00:00:00 -0000
++++ libc/elf/unload7mod1.c 19 Sep 2006 14:41:09 -0000 1.1
+@@ -0,0 +1,11 @@
++#include <dlfcn.h>
++#include <stdio.h>
++
++int
++foo (int i)
++{
++ if (dlsym (RTLD_DEFAULT, "unload7_nonexistent_symbol") == NULL)
++ return 1;
++ puts ("dlsym returned non-NULL");
++ return 0;
++}
+--- libc/elf/unload7mod2.c 1 Jan 1970 00:00:00 -0000
++++ libc/elf/unload7mod2.c 19 Sep 2006 14:41:09 -0000 1.1
+@@ -0,0 +1 @@
++int x;
--- /dev/null
+2006-10-02 Jakub Jelinek <jakub@redhat.com>
+
+ * nscd/mem.c (mempool_alloc): Round array size to 16 bytes
+ in oldtotal and newtotal calculation.
+ * nscd/nscd-client.h (struct mapped_database): Add datasize
+ field.
+ * nscd/nscd_helper.c (get_mapping): Initialize datasize field.
+ (__nscd_get_map_ref): Get a new mapping even if mapping's data_size
+ increased.
+ (__nscd_cache_search): Add checks to make sure we never reference
+ data beyond the current mapping.
+
+--- libc/nscd/mem.c 7 Dec 2005 05:47:27 -0000 1.8
++++ libc/nscd/mem.c 2 Oct 2006 16:31:11 -0000 1.9
+@@ -484,10 +484,10 @@ mempool_alloc (struct database_dyn *db,
+ size_t new_data_size = (db->head->data_size
+ + MAX (2 * len, db->head->data_size / 8));
+ size_t oldtotal = (sizeof (struct database_pers_head)
+- + db->head->module * sizeof (ref_t)
++ + roundup (db->head->module * sizeof (ref_t), ALIGN)
+ + db->head->data_size);
+ size_t newtotal = (sizeof (struct database_pers_head)
+- + db->head->module * sizeof (ref_t)
++ + roundup (db->head->module * sizeof (ref_t), ALIGN)
+ + new_data_size);
+ if (newtotal > db->max_db_size)
+ {
+--- libc/nscd/nscd-client.h 25 Apr 2006 23:48:55 -0000 1.22
++++ libc/nscd/nscd-client.h 2 Oct 2006 16:32:27 -0000 1.23
+@@ -258,6 +258,7 @@ struct mapped_database
+ const char *data;
+ size_t mapsize;
+ int counter; /* > 0 indicates it is usable. */
++ size_t datasize;
+ };
+ #define NO_MAPPING ((struct mapped_database *) -1l)
+
+--- libc/nscd/nscd_helper.c 25 Apr 2006 23:47:53 -0000 1.16
++++ libc/nscd/nscd_helper.c 2 Oct 2006 16:33:51 -0000 1.17
+@@ -290,6 +290,7 @@ get_mapping (request_type type, const ch
+ newp->data = ((char *) mapping + head.header_size
+ + roundup (head.module * sizeof (ref_t), ALIGN));
+ newp->mapsize = size;
++ newp->datasize = head.data_size;
+ /* Set counter to 1 to show it is usable. */
+ newp->counter = 1;
+
+@@ -340,7 +341,8 @@ __nscd_get_map_ref (request_type type, c
+ /* If not mapped or timestamp not updated, request new map. */
+ if (cur == NULL
+ || (cur->head->nscd_certainly_running == 0
+- && cur->head->timestamp + MAPPING_TIMEOUT < time (NULL)))
++ && cur->head->timestamp + MAPPING_TIMEOUT < time (NULL))
++ || cur->head->data_size > cur->datasize)
+ cur = get_mapping (type, name,
+ (struct mapped_database **) &mapptr->mapped);
+
+@@ -365,14 +367,18 @@ __nscd_cache_search (request_type type,
+ const struct mapped_database *mapped)
+ {
+ unsigned long int hash = __nis_hash (key, keylen) % mapped->head->module;
++ size_t datasize = mapped->datasize;
+
+ ref_t work = mapped->head->array[hash];
+- while (work != ENDREF)
++ while (work != ENDREF && work + sizeof (struct hashentry) <= datasize)
+ {
+ struct hashentry *here = (struct hashentry *) (mapped->data + work);
+
+- if (type == here->type && keylen == here->len
+- && memcmp (key, mapped->data + here->key, keylen) == 0)
++ if (type == here->type
++ && keylen == here->len
++ && here->key + here->len <= datasize
++ && memcmp (key, mapped->data + here->key, keylen) == 0
++ && here->packet + sizeof (struct datahead) <= datasize)
+ {
+ /* We found the entry. Increment the appropriate counter. */
+ const struct datahead *dh
+@@ -380,8 +386,7 @@ __nscd_cache_search (request_type type,
+
+ /* See whether we must ignore the entry or whether something
+ is wrong because garbage collection is in progress. */
+- if (dh->usable && ((char *) dh + dh->allocsize
+- <= (char *) mapped->head + mapped->mapsize))
++ if (dh->usable && here->packet + dh->allocsize <= datasize)
+ return dh;
+ }
+
--- /dev/null
+2006-10-06 Ulrich Drepper <drepper@redhat.com>
+
+ * nis/nis_table.c (nis_list): If __follow_path fails in the new
+ code, make sure the nis_freeresult call doesn't crash and that the
+ result is reported correctly.
+
+2006-09-27 Jakub Jelinek <jakub@redhat.com>
+
+ * nis/nis_table.c (nis_list): Handle FOLLOW_PATH | ALL_RESULTS
+ when callback is NULL.
+
+ * nis/Versions (libnss_nisplus): Add
+ _nss_nisplus_initgroups_dyn@@GLIBC_PRIVATE.
+ * nis/Makefile (libnss_nisplus-routines): Add nisplus-initgroups.
+ * nis/nss_nisplus/nisplus-grp.c (tablename_val, tablename_len,
+ _nss_create_tablename): Rename to...
+ (grp_tablename_val, grp_tablename_len, _nss_grp_create_tablename):
+ ... these. No longer static.
+ (internal_setgrent): Adjust users.
+ (_nss_nisplus_getgrnam_r, _nss_nisplus_getgrgid_r): Likewise.
+ Don't use locking around _nss_grp_create_tablename call.
+ * nis/nss_nisplus/nisplus-initgroups.c: New file.
+
+--- libc/nis/Makefile 14 Apr 2006 05:45:49 -0000 1.32
++++ libc/nis/Makefile 6 Oct 2006 17:47:31 -0000 1.33
+@@ -64,7 +64,7 @@ libnss_nis-routines := $(addprefix nis-,
+ libnss_nis-inhibit-o = $(filter-out .os,$(object-suffixes))
+
+ libnss_nisplus-routines := $(addprefix nisplus-,$(databases)) nisplus-parser \
+- nss-nisplus
++ nss-nisplus nisplus-initgroups
+ libnss_nisplus-inhibit-o = $(filter-out .os,$(object-suffixes))
+
+ include ../Rules
+--- libc/nis/Versions 20 May 2006 19:21:52 -0000 1.10
++++ libc/nis/Versions 6 Oct 2006 17:48:37 -0000 1.11
+@@ -125,6 +125,6 @@ libnss_nisplus {
+ _nss_nisplus_setetherent; _nss_nisplus_setgrent; _nss_nisplus_sethostent;
+ _nss_nisplus_setnetent; _nss_nisplus_setnetgrent; _nss_nisplus_setprotoent;
+ _nss_nisplus_setpwent; _nss_nisplus_setrpcent; _nss_nisplus_setservent;
+- _nss_nisplus_setspent;
++ _nss_nisplus_setspent; _nss_nisplus_initgroups_dyn;
+ }
+ }
+--- libc/nis/nis_table.c 7 Aug 2006 16:01:44 -0000 1.38
++++ libc/nis/nis_table.c 6 Oct 2006 20:31:59 -0000 1.40
+@@ -215,6 +215,7 @@ nis_list (const_nis_name name, unsigned
+ char *tableptr;
+ char *tablepath = NULL;
+ int first_try = 0; /* Do we try the old binding at first ? */
++ nis_result *allres = NULL;
+
+ if (res == NULL)
+ return NULL;
+@@ -223,6 +224,7 @@ nis_list (const_nis_name name, unsigned
+ {
+ status = NIS_BADNAME;
+ err_out:
++ nis_freeresult (allres);
+ memset (res, '\0', sizeof (nis_result));
+ NIS_RES_STATUS (res) = status;
+ return res;
+@@ -349,6 +351,7 @@ nis_list (const_nis_name name, unsigned
+ if (names != namebuf)
+ nis_freenames (names);
+ nis_free_request (ibreq);
++ nis_freeresult (allres);
+ return res;
+ }
+ if (NIS_RES_OBJECT (res)->LI_data.li_attrs.li_attrs_len)
+@@ -392,6 +395,57 @@ nis_list (const_nis_name name, unsigned
+ goto again;
+ }
+ }
++ else if ((flags & (FOLLOW_PATH | ALL_RESULTS))
++ == (FOLLOW_PATH | ALL_RESULTS))
++ {
++ if (allres == NULL)
++ {
++ allres = res;
++ res = malloc (sizeof (nis_result));
++ if (res == NULL)
++ {
++ res = allres;
++ allres = NULL;
++ NIS_RES_STATUS (res) = NIS_NOMEMORY;
++ goto fail;
++ }
++ NIS_RES_STATUS (res) = NIS_RES_STATUS (allres);
++ }
++ else
++ {
++ nis_object *objects_val
++ = realloc (NIS_RES_OBJECT (allres),
++ (NIS_RES_NUMOBJ (allres)
++ + NIS_RES_NUMOBJ (res))
++ * sizeof (nis_object));
++ if (objects_val == NULL)
++ {
++ NIS_RES_STATUS (res) = NIS_NOMEMORY;
++ goto fail;
++ }
++ NIS_RES_OBJECT (allres) = objects_val;
++ memcpy (NIS_RES_OBJECT (allres) + NIS_RES_NUMOBJ (allres),
++ NIS_RES_OBJECT (res),
++ NIS_RES_NUMOBJ (res) * sizeof (nis_object));
++ NIS_RES_NUMOBJ (allres) += NIS_RES_NUMOBJ (res);
++ NIS_RES_NUMOBJ (res) = 0;
++ free (NIS_RES_OBJECT (res));
++ NIS_RES_OBJECT (res) = NULL;
++ NIS_RES_STATUS (allres) = NIS_RES_STATUS (res);
++ xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res);
++ }
++ clnt_status = __follow_path (&tablepath, &tableptr, ibreq,
++ &bptr);
++ if (clnt_status != NIS_SUCCESS)
++ {
++ /* Prepare for the nis_freeresult call. */
++ memset (res, '\0', sizeof (*res));
++
++ if (clnt_status == NIS_NOMEMORY)
++ NIS_RES_STATUS (allres) = clnt_status;
++ ++done;
++ }
++ }
+ else
+ ++done;
+ break;
+@@ -485,6 +539,12 @@ nis_list (const_nis_name name, unsigned
+
+ nis_free_request (ibreq);
+
++ if (allres)
++ {
++ nis_freeresult (res);
++ return allres;
++ }
++
+ return res;
+ }
+ libnsl_hidden_def (nis_list)
+--- libc/nis/nss_nisplus/nisplus-grp.c 20 May 2006 19:20:19 -0000 1.20
++++ libc/nis/nss_nisplus/nisplus-grp.c 6 Oct 2006 17:46:31 -0000 1.21
+@@ -46,13 +46,13 @@ static char *tableptr;
+ static netobj cursor;
+
+
+-static nis_name tablename_val;
+-static size_t tablename_len;
++nis_name grp_tablename_val attribute_hidden;
++size_t grp_tablename_len attribute_hidden;
+
+-static enum nss_status
+-_nss_create_tablename (int *errnop)
++enum nss_status
++_nss_grp_create_tablename (int *errnop)
+ {
+- if (tablename_val == NULL)
++ if (grp_tablename_val == NULL)
+ {
+ const char *local_dir = nis_local_directory ();
+ size_t local_dir_len = strlen (local_dir);
+@@ -67,11 +67,16 @@ _nss_create_tablename (int *errnop)
+
+ memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
+
+- tablename_len = sizeof (prefix) - 1 + local_dir_len;
++ grp_tablename_len = sizeof (prefix) - 1 + local_dir_len;
+
+ atomic_write_barrier ();
+
+- tablename_val = p;
++ if (atomic_compare_and_exchange_bool_acq (&grp_tablename_val, p, NULL))
++ {
++ /* Another thread already installed the value. */
++ free (p);
++ grp_tablename_len = strlen (grp_tablename_val);
++ }
+ }
+
+ return NSS_STATUS_SUCCESS;
+@@ -103,19 +108,19 @@ internal_setgrent (int *errnop)
+ {
+ enum nss_status status = NSS_STATUS_SUCCESS;
+
+- if (tablename_val == NULL)
+- status = _nss_create_tablename (errnop);
++ if (grp_tablename_val == NULL)
++ status = _nss_grp_create_tablename (errnop);
+
+ if (status == NSS_STATUS_SUCCESS)
+ {
+- ibreq = __create_ib_request (tablename_val, 0);
++ ibreq = __create_ib_request (grp_tablename_val, 0);
+ if (ibreq == NULL)
+ {
+ *errnop = errno;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+- nis_error retcode = __prepare_niscall (tablename_val, &dir, &bptr, 0);
++ nis_error retcode = __prepare_niscall (grp_tablename_val, &dir, &bptr, 0);
+ if (retcode != NIS_SUCCESS)
+ {
+ nis_free_request (ibreq);
+@@ -285,13 +290,9 @@ _nss_nisplus_getgrnam_r (const char *nam
+ {
+ int parse_res;
+
+- if (tablename_val == NULL)
++ if (grp_tablename_val == NULL)
+ {
+- __libc_lock_lock (lock);
+-
+- enum nss_status status = _nss_create_tablename (errnop);
+-
+- __libc_lock_unlock (lock);
++ enum nss_status status = _nss_grp_create_tablename (errnop);
+
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+@@ -304,10 +305,10 @@ _nss_nisplus_getgrnam_r (const char *nam
+ }
+
+ nis_result *result;
+- char buf[strlen (name) + 9 + tablename_len];
++ char buf[strlen (name) + 9 + grp_tablename_len];
+ int olderr = errno;
+
+- snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
++ snprintf (buf, sizeof (buf), "[name=%s],%s", name, grp_tablename_val);
+
+ result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
+
+@@ -348,13 +349,9 @@ enum nss_status
+ _nss_nisplus_getgrgid_r (const gid_t gid, struct group *gr,
+ char *buffer, size_t buflen, int *errnop)
+ {
+- if (tablename_val == NULL)
++ if (grp_tablename_val == NULL)
+ {
+- __libc_lock_lock (lock);
+-
+- enum nss_status status = _nss_create_tablename (errnop);
+-
+- __libc_lock_unlock (lock);
++ enum nss_status status = _nss_grp_create_tablename (errnop);
+
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+@@ -362,11 +359,11 @@ _nss_nisplus_getgrgid_r (const gid_t gid
+
+ int parse_res;
+ nis_result *result;
+- char buf[8 + 3 * sizeof (unsigned long int) + tablename_len];
++ char buf[8 + 3 * sizeof (unsigned long int) + grp_tablename_len];
+ int olderr = errno;
+
+ snprintf (buf, sizeof (buf), "[gid=%lu],%s",
+- (unsigned long int) gid, tablename_val);
++ (unsigned long int) gid, grp_tablename_val);
+
+ result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
+
+--- libc/nis/nss_nisplus/nisplus-initgroups.c 1 Jan 1970 00:00:00 -0000
++++ libc/nis/nss_nisplus/nisplus-initgroups.c 6 Oct 2006 17:45:26 -0000 1.1
+@@ -0,0 +1,150 @@
++/* Copyright (C) 1997, 2001, 2002, 2003, 2005, 2006
++ Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <atomic.h>
++#include <nss.h>
++#include <grp.h>
++#include <ctype.h>
++#include <errno.h>
++#include <string.h>
++#include <bits/libc-lock.h>
++#include <rpcsvc/nis.h>
++
++#include "nss-nisplus.h"
++#include "nisplus-parser.h"
++#include <libnsl.h>
++#include <nis_intern.h>
++#include <nis_xdr.h>
++
++#define NISOBJVAL(col, obj) \
++ ((obj)->EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
++
++#define NISOBJLEN(col, obj) \
++ ((obj)->EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
++
++extern nis_name grp_tablename_val attribute_hidden;
++extern size_t grp_tablename_len attribute_hidden;
++extern enum nss_status _nss_grp_create_tablename (int *errnop);
++
++
++enum nss_status
++_nss_nisplus_initgroups_dyn (const char *user, gid_t group, long int *start,
++ long int *size, gid_t **groupsp, long int limit,
++ int *errnop)
++{
++ if (grp_tablename_val == NULL)
++ {
++ enum nss_status status = _nss_grp_create_tablename (errnop);
++
++ if (status != NSS_STATUS_SUCCESS)
++ return status;
++ }
++
++ nis_result *result;
++ char buf[strlen (user) + 12 + grp_tablename_len];
++
++ snprintf (buf, sizeof (buf), "[members=%s],%s", user, grp_tablename_val);
++
++ result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH | ALL_RESULTS, NULL, NULL);
++
++ if (result == NULL)
++ {
++ *errnop = ENOMEM;
++ return NSS_STATUS_TRYAGAIN;
++ }
++
++ if (__builtin_expect (niserr2nss (result->status) != NSS_STATUS_SUCCESS, 0))
++ {
++ enum nss_status status = niserr2nss (result->status);
++
++ nis_freeresult (result);
++ return status;
++ }
++
++ if (NIS_RES_NUMOBJ (result) == 0)
++ {
++ errout:
++ nis_freeresult (result);
++ return NSS_STATUS_NOTFOUND;
++ }
++
++ gid_t *groups = *groupsp;
++ nis_object *obj = NIS_RES_OBJECT (result);
++ for (unsigned int cnt = 0; cnt < NIS_RES_NUMOBJ (result); ++cnt, ++obj)
++ {
++ if (__type_of (obj) != NIS_ENTRY_OBJ
++ || strcmp (obj->EN_data.en_type, "group_tbl") != 0
++ || obj->EN_data.en_cols.en_cols_len < 4)
++ continue;
++
++ char *numstr = NISOBJVAL (2, obj);
++ size_t len = NISOBJLEN (2, obj);
++ if (len == 0 || numstr[0] == '\0')
++ continue;
++
++ gid_t gid;
++ char *endp;
++ if (__builtin_expect (numstr[len - 1] != '\0', 0))
++ {
++ char numstrbuf[len + 1];
++ memcpy (numstrbuf, numstr, len);
++ numstrbuf[len] = '\0';
++ gid = strtoul (numstrbuf, &endp, 10);
++ if (*endp)
++ continue;
++ }
++ else
++ {
++ gid = strtoul (numstr, &endp, 10);
++ if (*endp)
++ continue;
++ }
++
++ if (gid == group)
++ continue;
++
++ /* Insert this group. */
++ if (*start == *size)
++ {
++ /* Need a bigger buffer. */
++ long int newsize;
++
++ if (limit > 0 && *size == limit)
++ /* We reached the maximum. */
++ break;
++
++ if (limit <= 0)
++ newsize = 2 * *size;
++ else
++ newsize = MIN (limit, 2 * *size);
++
++ gid_t *newgroups = realloc (groups, newsize * sizeof (*groups));
++ if (newgroups == NULL)
++ goto errout;
++ *groupsp = groups = newgroups;
++ *size = newsize;
++ }
++
++ groups[*start] = gid;
++ *start += 1;
++ }
++
++ nis_freeresult (result);
++ return NSS_STATUS_SUCCESS;
++}
--- /dev/null
+2007-01-15 Jakub Jelinek <jakub@redhat.com>
+
+ * elf/dl-open.c (add_to_global): If the main searchlist is 256
+ entries or more, on each reallocation at least double the size
+ of the search list rather than growing it linearly.
+ (dl_open_worker): When changing from l_scope_mem to malloced
+ l_scope, start with 64 entries rather than 4.
+
+ * pthread_create.c (__pthread_create_2_1): On the first pthread_create
+ in a process make sure main search list can store at least 256
+ entries.
+
+--- libc/elf/dl-open.c 2006-08-31 08:53:29.000000000 +0200
++++ libc/elf/dl-open.c 2007-01-15 11:22:54.000000000 +0100
+@@ -125,14 +125,18 @@ add_to_global (struct link_map *new)
+ {
+ /* We have to extend the existing array of link maps in the
+ main map. */
++ size_t new_size = GL(dl_ns)[new->l_ns]._ns_global_scope_alloc;
++ if (new_size >= 256 && new_size > to_add + 8)
++ new_size *= 2;
++ else
++ new_size += to_add + 8;
+ new_global = (struct link_map **)
+ realloc (GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list,
+- ((GL(dl_ns)[new->l_ns]._ns_global_scope_alloc + to_add + 8)
+- * sizeof (struct link_map *)));
++ new_size * sizeof (struct link_map *));
+ if (new_global == NULL)
+ goto nomem;
+
+- GL(dl_ns)[new->l_ns]._ns_global_scope_alloc += to_add + 8;
++ GL(dl_ns)[new->l_ns]._ns_global_scope_alloc = new_size;
+ GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list = new_global;
+ }
+
+@@ -396,6 +401,10 @@ dl_open_worker (void *a)
+
+ if (imap->l_scope == imap->l_scope_mem)
+ {
++ /* Hack: try to minimize the number of realloc calls
++ when we don't have proper locking yet. */
++ new_size = 64;
++
+ newp = (struct r_scope_elem **)
+ malloc (new_size * sizeof (struct r_scope_elem *));
+ if (newp == NULL)
+--- libc/nptl/pthread_create.c 2006-09-07 11:04:05.000000000 +0200
++++ libc/nptl/pthread_create.c 2007-01-15 11:18:49.000000000 +0100
+@@ -462,6 +462,30 @@ __pthread_create_2_1 (newthread, attr, s
+ pd->flags = ((iattr->flags & ~(ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET))
+ | (self->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)));
+
++ /* Hack: realloc the main search list on the first pthread_create call
++ to minimize the number of global search scope reallocations.
++ Wastes at most 1KB on 32-bit and 2KB on 64-bit per process
++ which calls pthread_create. */
++ if (__builtin_expect (self->header.multiple_threads == 0, 0)
++ && GL(dl_ns)[0]._ns_main_searchlist
++ && GL(dl_ns)[0]._ns_main_searchlist->r_nlist < 256
++ && GL(dl_ns)[0]._ns_global_scope_alloc < 256)
++ {
++ struct link_map **new_global = (struct link_map **)
++ realloc (GL(dl_ns)[0]._ns_global_scope_alloc == 0
++ ? NULL : GL(dl_ns)[0]._ns_main_searchlist->r_list,
++ 256 * sizeof (struct link_map *));
++ if (new_global != NULL)
++ {
++ if (GL(dl_ns)[0]._ns_global_scope_alloc == 0)
++ memcpy (new_global, GL(dl_ns)[0]._ns_main_searchlist->r_list,
++ GL(dl_ns)[0]._ns_main_searchlist->r_nlist
++ * sizeof (struct link_map *));
++ GL(dl_ns)[0]._ns_global_scope_alloc = 256;
++ GL(dl_ns)[0]._ns_main_searchlist->r_list = new_global;
++ }
++ }
++
+ /* Initialize the field for the ID of the thread which is waiting
+ for us. This is a self-reference in case the thread is created
+ detached. */
--- /dev/null
+2006-10-17 Jakub Jelinek <jakub@redhat.com>
+
+ * sunrpc/xdr_mem.c (xdrmem_setpos): Don't compare addresses
+ as signed longs, check for x_base + pos overflow.
+ * sunrpc/Makefile (tests): Add tst-xdrmem2.
+ * sunrpc/tst-xdrmem2.c: New test.
+
+--- libc/sunrpc/xdr_mem.c 16 Dec 2002 10:25:27 -0000 1.15
++++ libc/sunrpc/xdr_mem.c 18 Oct 2006 19:25:01 -0000 1.16
+@@ -177,13 +177,15 @@ xdrmem_setpos (xdrs, pos)
+ {
+ caddr_t newaddr = xdrs->x_base + pos;
+ caddr_t lastaddr = xdrs->x_private + xdrs->x_handy;
++ size_t handy = lastaddr - newaddr;
+
+- if ((long) newaddr > (long) lastaddr
+- || (UINT_MAX < LONG_MAX
+- && (long) UINT_MAX < (long) lastaddr - (long) newaddr))
++ if (newaddr > lastaddr
++ || newaddr < xdrs->x_base
++ || handy != (u_int) handy)
+ return FALSE;
++
+ xdrs->x_private = newaddr;
+- xdrs->x_handy = (long) lastaddr - (long) newaddr;
++ xdrs->x_handy = (u_int) handy;
+ return TRUE;
+ }
+
+--- libc/sunrpc/Makefile 26 Jun 2005 18:24:19 -0000 1.84
++++ libc/sunrpc/Makefile 18 Oct 2006 19:25:38 -0000 1.85
+@@ -85,7 +85,7 @@ all: # Make this the default target; it
+
+ include ../Makeconfig
+
+-tests = tst-xdrmem
++tests = tst-xdrmem tst-xdrmem2
+ xtests := tst-getmyaddr
+
+ ifeq ($(have-thread-library),yes)
+--- libc/sunrpc/tst-xdrmem2.c 1 Jan 1970 00:00:00 -0000
++++ libc/sunrpc/tst-xdrmem2.c 18 Oct 2006 19:24:16 -0000 1.1
+@@ -0,0 +1,114 @@
++/* Copyright (C) 2006 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <limits.h>
++#include <stdio.h>
++#include <string.h>
++#include <rpc/rpc.h>
++#include <sys/mman.h>
++#include <unistd.h>
++
++static int
++do_test (void)
++{
++ XDR xdrs;
++ void *buf;
++ size_t ps = sysconf (_SC_PAGESIZE);
++ uintptr_t half = -1;
++ int v_int;
++ u_short v_u_short;
++
++ half = (half >> 1) & ~(uintptr_t) (ps - 1);
++ buf = mmap ((void *) half, 2 * ps, PROT_READ | PROT_WRITE,
++ MAP_PRIVATE | MAP_ANON, -1, 0);
++ if (buf == MAP_FAILED || buf != (void *) half)
++ {
++ puts ("Couldn't mmap 2 pages in the middle of address space");
++ return 0;
++ }
++
++ xdrmem_create (&xdrs, (char *) buf, 2 * ps, XDR_ENCODE);
++
++#define T(type, val) \
++ v_##type = val; \
++ if (! xdr_##type (&xdrs, &v_##type)) \
++ { \
++ puts ("encoding of " #type \
++ " " #val " failed"); \
++ return 1; \
++ }
++
++ T(int, 127)
++
++ u_int pos = xdr_getpos (&xdrs);
++
++ T(u_short, 31)
++
++ if (! xdr_setpos (&xdrs, pos))
++ {
++ puts ("xdr_setpos during encoding failed");
++ return 1;
++ }
++
++ T(u_short, 36)
++
++#undef T
++
++ xdr_destroy (&xdrs);
++
++ xdrmem_create (&xdrs, (char *) buf, 2 * ps, XDR_DECODE);
++
++#define T(type, val) \
++ v_##type = 0x15; \
++ if (! xdr_##type (&xdrs, &v_##type)) \
++ { \
++ puts ("decoding of " #type \
++ " " #val " failed"); \
++ return 1; \
++ } \
++ if (v_##type != val) \
++ { \
++ puts ("decoded value differs, " \
++ "type " #type " " #val); \
++ return 1; \
++ }
++
++ T(int, 127)
++
++ pos = xdr_getpos (&xdrs);
++
++ T(u_short, 36)
++
++ if (! xdr_setpos (&xdrs, pos))
++ {
++ puts ("xdr_setpos during encoding failed");
++ return 1;
++ }
++
++ T(u_short, 36)
++
++#undef T
++
++ xdr_destroy (&xdrs);
++
++ return 0;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
--- /dev/null
+2006-11-14 Jakub Jelinek <jakub@redhat.com>
+
+ * nss/nss_files/files-alias.c (get_next_alias): Set line back
+ to first_unused after parsing :include: file.
+
+--- libc/nss/nss_files/files-alias.c 1 Sep 2002 12:38:05 -0000 1.15
++++ libc/nss/nss_files/files-alias.c 15 Nov 2006 22:23:20 -0000 1.16
+@@ -298,8 +298,8 @@ get_next_alias (const char *match, struc
+ first_unused[room_left - 1] = '\0';
+ strncpy (first_unused, old_line, room_left);
+
+- if (old_line != NULL)
+- free (old_line);
++ free (old_line);
++ line = first_unused;
+
+ if (first_unused[room_left - 1] != '\0')
+ goto no_more_room;
--- /dev/null
+2006-12-09 Jakub Jelinek <jakub@redhat.com>
+
+ * misc/getusershell.c (initshells): Check for integer overflows.
+ Make strings buffer one bigger as fgets always succeeds when second
+ argument is 1. Don't use calloc for shells array. Disallow
+ / as shell.
+
+--- libc/misc/getusershell.c 15 May 2006 18:56:36 -0000 1.16
++++ libc/misc/getusershell.c 9 Dec 2006 22:25:00 -0000 1.17
+@@ -92,7 +92,7 @@ initshells()
+ register char **sp, *cp;
+ register FILE *fp;
+ struct stat64 statb;
+- int flen;
++ size_t flen;
+
+ if (shells != NULL)
+ free(shells);
+@@ -106,11 +106,15 @@ initshells()
+ (void)fclose(fp);
+ return (char **) okshells;
+ }
+- if ((strings = malloc((u_int)statb.st_size + 1)) == NULL) {
++ if (statb.st_size > ~(size_t)0 / sizeof (char *) * 3) {
++ (void)fclose(fp);
++ return (char **) okshells;
++ }
++ if ((strings = malloc(statb.st_size + 2)) == NULL) {
+ (void)fclose(fp);
+ return (char **) okshells;
+ }
+- shells = calloc((unsigned)statb.st_size / 3, sizeof (char *));
++ shells = malloc(statb.st_size / 3 * sizeof (char *));
+ if (shells == NULL) {
+ (void)fclose(fp);
+ free(strings);
+@@ -121,11 +125,11 @@ initshells()
+ __fsetlocking (fp, FSETLOCKING_BYCALLER);
+ sp = shells;
+ cp = strings;
+- flen = statb.st_size;
++ flen = statb.st_size + 2;
+ while (fgets_unlocked(cp, flen - (cp - strings), fp) != NULL) {
+ while (*cp != '#' && *cp != '/' && *cp != '\0')
+ cp++;
+- if (*cp == '#' || *cp == '\0')
++ if (*cp == '#' || *cp == '\0' || cp[1] == '\0')
+ continue;
+ *sp++ = cp;
+ while (!isspace(*cp) && *cp != '#' && *cp != '\0')
--- /dev/null
+2006-12-09 Jakub Jelinek <jakub@redhat.com>
+
+ * misc/mntent_r.c (__hasmntopt): Check p[optlen] even when p == rest.
+ Start searching for next comma at p rather than rest.
+ * misc/Makefile (tests): Add tst-mntent2.
+ * misc/tst-mntent2.c: New test.
+
+--- libc/misc/Makefile 17 Jun 2006 17:00:58 -0000 1.119
++++ libc/misc/Makefile 9 Dec 2006 22:06:40 -0000 1.120
+@@ -76,7 +76,7 @@ endif
+ gpl2lgpl := error.c error.h
+
+ tests := tst-dirname tst-tsearch tst-fdset tst-efgcvt tst-mntent tst-hsearch \
+- tst-error1 tst-insremque
++ tst-error1 tst-insremque tst-mntent2
+ ifeq (no,$(cross-compiling))
+ tests: $(objpfx)tst-error1-mem
+ endif
+--- libc/misc/mntent_r.c 17 Dec 2003 23:29:02 -0000 1.20
++++ libc/misc/mntent_r.c 9 Dec 2006 22:05:59 -0000 1.21
+@@ -278,14 +279,11 @@ __hasmntopt (const struct mntent *mnt, c
+
+ while ((p = strstr (rest, opt)) != NULL)
+ {
+- if (p == rest
+- || (p[-1] == ','
+- && (p[optlen] == '\0' ||
+- p[optlen] == '=' ||
+- p[optlen] == ',')))
++ if ((p == rest || p[-1] == ',')
++ && (p[optlen] == '\0' || p[optlen] == '=' || p[optlen] == ','))
+ return p;
+
+- rest = strchr (rest, ',');
++ rest = strchr (p, ',');
+ if (rest == NULL)
+ break;
+ ++rest;
+--- libc/misc/tst-mntent2.c 1 Jan 1970 00:00:00 -0000
++++ libc/misc/tst-mntent2.c 9 Dec 2006 22:06:27 -0000 1.1
+@@ -0,0 +1,41 @@
++#include <mntent.h>
++#include <stdio.h>
++#include <string.h>
++
++
++int
++main (void)
++{
++ int result = 0;
++ struct mntent mef;
++
++ mef.mnt_fsname = strdupa ("/dev/sdf6");
++ mef.mnt_dir = strdupa ("/some dir");
++ mef.mnt_type = strdupa ("ext3");
++ mef.mnt_opts = strdupa ("opt1,opt2,noopt=6,rw,norw,brw");
++ mef.mnt_freq = 1;
++ mef.mnt_passno = 2;
++
++#define TEST(opt, found) \
++ if (!!hasmntopt (&mef, (opt)) != (found)) \
++ { \
++ printf ("Option %s was %sfound\n", (opt), (found) ? "not " : ""); \
++ result = 1; \
++ }
++
++ TEST ("opt1", 1)
++ TEST ("opt2", 1)
++ TEST ("noopt", 1)
++ TEST ("rw", 1)
++ TEST ("norw", 1)
++ TEST ("brw", 1)
++ TEST ("opt", 0)
++ TEST ("oopt", 0)
++ TEST ("w", 0)
++ TEST ("r", 0)
++ TEST ("br", 0)
++ TEST ("nor", 0)
++ TEST ("or", 0)
++
++ return result;
++}
--- /dev/null
+2006-12-19 Jakub Jelinek <jakub@redhat.com>
+
+ * nss/getXXbyYY_r.c: Include atomic.h.
+ (INTERNAL (REENTRANT_NAME)): Write startp after start_fct,
+ add atomic_write_barrier () in between.
+
+--- libc/nss/getXXbyYY_r.c 16 Sep 2004 22:24:09 -0000 1.61
++++ libc/nss/getXXbyYY_r.c 19 Dec 2006 15:45:08 -0000 1.62
+@@ -18,6 +18,7 @@
+ 02111-1307 USA. */
+
+ #include <assert.h>
++#include <atomic.h>
+ #include <errno.h>
+ #include <stdbool.h>
+ #include "nsswitch.h"
+@@ -173,9 +174,6 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, L
+ startp = (service_user *) -1l;
+ else
+ {
+- startp = nip;
+- start_fct = fct.l;
+-
+ #ifdef NEED__RES
+ /* The resolver code will really be used so we have to
+ initialize it. */
+@@ -190,6 +188,11 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, L
+ if (!_res_hconf.initialized)
+ _res_hconf_init ();
+ #endif /* need _res_hconf */
++
++ start_fct = fct.l;
++ /* Make sure start_fct is written before startp. */
++ atomic_write_barrier ();
++ startp = nip;
+ }
+ }
+ else
--- /dev/null
+2006-12-22 Gavin Romig-Koch <gavin@redhat.com>
+
+ * nis/nss_compat/compat-grp.c (internal_getgrgid_r): Don't
+ blacklist the group till after we look it up.
+
+--- libc/nis/nss_compat/compat-grp.c 31 Jul 2006 23:33:04 -0000 1.32
++++ libc/nis/nss_compat/compat-grp.c 22 Dec 2006 20:26:11 -0000 1.33
+@@ -580,13 +580,17 @@ internal_getgrgid_r (gid_t gid, struct g
+ /* +group */
+ if (result->gr_name[0] == '+' && result->gr_name[1] != '\0')
+ {
++ /* Yes, no +1, see the memcpy call below. */
++ size_t len = strlen (result->gr_name);
++ char buf[len];
+ enum nss_status status;
+
+ /* Store the group in the blacklist for the "+" at the end of
+ /etc/group */
+- blacklist_store_name (&result->gr_name[1], ent);
++ memcpy (buf, &result->gr_name[1], len);
+ status = getgrnam_plusgroup (&result->gr_name[1], result, ent,
+ buffer, buflen, errnop);
++ blacklist_store_name (buf, ent);
+ if (status == NSS_STATUS_SUCCESS && result->gr_gid == gid)
+ break;
+ else
--- /dev/null
+2007-01-31 Jakub Jelinek <jakub@redhat.com>
+
+ * nscd/nscd-client.h (__nscd_cache_search): Remove const qualifier
+ from return value.
+ * nscd/nscd_helper.c: Include string.h.
+ (__nscd_cache_search): Remove const qualifier from return value.
+ On strict alignment architectures check hash entry and data head
+ alignment.
+ * nscd/nscd_getpw_r.c (nscd_getpw_r): Don't crash or fail because
+ mmapped data during GC cycle contains garbage. If
+ __nscd_drop_map_ref fails, decrement mapped->counter when returning
+ error or if retrying with NO_MAPPING, only __nscd_unmap if counter
+ dropped to 0.
+ * nscd/nscd_getgr_r.c (nscd_getgr_r): Likewise.
+ * nscd/nscd_initgroups.c (__nscd_getgrouplist): Likewise.
+ * nscd/nscd_gethst_r.c (nscd_gethst_r): Likewise.
+ * nscd/nscd_getai.c (__nscd_getai): Likewise.
+
+--- libc/nscd/nscd-client.h 14 Jan 2007 05:23:40 -0000 1.24
++++ libc/nscd/nscd-client.h 31 Jan 2007 09:14:21 -0000 1.25
+@@ -323,10 +323,10 @@ static inline int __nscd_drop_map_ref (s
+
+
+ /* Search the mapped database. */
+-extern const struct datahead *__nscd_cache_search (request_type type,
+- const char *key,
+- size_t keylen,
+- const struct mapped_database *mapped);
++extern struct datahead *__nscd_cache_search (request_type type,
++ const char *key,
++ size_t keylen,
++ const struct mapped_database *mapped);
+
+ /* Wrappers around read, readv and write that only read/write less than LEN
+ bytes on error or EOF. */
+--- libc/nscd/nscd_getai.c 15 May 2006 20:31:29 -0000 1.12
++++ libc/nscd/nscd_getai.c 31 Jan 2007 09:14:21 -0000 1.13
+@@ -42,6 +42,7 @@ __nscd_getai (const char *key, struct ns
+ {
+ size_t keylen = strlen (key) + 1;
+ int gc_cycle;
++ int nretries = 0;
+
+ /* If the mapping is available, try to search there instead of
+ communicating with the nscd. */
+@@ -50,49 +51,53 @@ __nscd_getai (const char *key, struct ns
+ &gc_cycle);
+
+ retry:;
+- const ai_response_header *ai_resp = NULL;
+ struct nscd_ai_result *resultbuf = NULL;
+ const char *recend = (const char *) ~UINTMAX_C (0);
+ char *respdata = NULL;
+ int retval = -1;
+ int sock = -1;
++ ai_response_header ai_resp;
+
+ if (mapped != NO_MAPPING)
+ {
+- const struct datahead *found = __nscd_cache_search (GETAI, key, keylen,
+- mapped);
++ struct datahead *found = __nscd_cache_search (GETAI, key, keylen,
++ mapped);
+ if (found != NULL)
+ {
+- ai_resp = &found->data[0].aidata;
+- respdata = (char *) (ai_resp + 1);
++ respdata = (char *) (&found->data[0].aidata + 1);
++ ai_resp = found->data[0].aidata;
+ recend = (const char *) found->data + found->recsize;
++ /* Now check if we can trust ai_resp fields. If GC is
++ in progress, it can contain anything. */
++ if (mapped->head->gc_cycle != gc_cycle)
++ {
++ retval = -2;
++ goto out;
++ }
+ }
+ }
+
+ /* If we do not have the cache mapped, try to get the data over the
+ socket. */
+- ai_response_header ai_resp_mem;
+- if (ai_resp == NULL)
++ if (respdata == NULL)
+ {
+- sock = __nscd_open_socket (key, keylen, GETAI, &ai_resp_mem,
+- sizeof (ai_resp_mem));
++ sock = __nscd_open_socket (key, keylen, GETAI, &ai_resp,
++ sizeof (ai_resp));
+ if (sock == -1)
+ {
+ /* nscd not running or wrong version. */
+ __nss_not_use_nscd_hosts = 1;
+ goto out;
+ }
+-
+- ai_resp = &ai_resp_mem;
+ }
+
+- if (ai_resp->found == 1)
++ if (ai_resp.found == 1)
+ {
+- size_t datalen = ai_resp->naddrs + ai_resp->addrslen + ai_resp->canonlen;
++ size_t datalen = ai_resp.naddrs + ai_resp.addrslen + ai_resp.canonlen;
+
+- /* This check is really only affects the case where the data
++ /* This check really only affects the case where the data
+ comes from the mapped cache. */
+- if ((char *) (ai_resp + 1) + datalen > recend)
++ if (respdata + datalen > recend)
+ {
+ assert (sock == -1);
+ goto out;
+@@ -108,10 +113,10 @@ __nscd_getai (const char *key, struct ns
+ }
+
+ /* Set up the data structure, including pointers. */
+- resultbuf->naddrs = ai_resp->naddrs;
++ resultbuf->naddrs = ai_resp.naddrs;
+ resultbuf->addrs = (char *) (resultbuf + 1);
+- resultbuf->family = (uint8_t *) (resultbuf->addrs + ai_resp->addrslen);
+- if (ai_resp->canonlen != 0)
++ resultbuf->family = (uint8_t *) (resultbuf->addrs + ai_resp.addrslen);
++ if (ai_resp.canonlen != 0)
+ resultbuf->canon = (char *) (resultbuf->family + resultbuf->naddrs);
+ else
+ resultbuf->canon = NULL;
+@@ -137,10 +142,13 @@ __nscd_getai (const char *key, struct ns
+
+ /* Try to detect corrupt databases. */
+ if (resultbuf->canon != NULL
+- && resultbuf->canon[ai_resp->canonlen - 1] != '\0')
++ && resultbuf->canon[ai_resp.canonlen - 1] != '\0')
+ /* We cannot use the database. */
+ {
+- free (resultbuf);
++ if (mapped->head->gc_cycle != gc_cycle)
++ retval = -2;
++ else
++ free (resultbuf);
+ goto out_close;
+ }
+
+@@ -150,7 +158,7 @@ __nscd_getai (const char *key, struct ns
+ }
+ else
+ {
+- if (__builtin_expect (ai_resp->found == -1, 0))
++ if (__builtin_expect (ai_resp.found == -1, 0))
+ {
+ /* The daemon does not cache this database. */
+ __nss_not_use_nscd_hosts = 1;
+@@ -158,7 +166,7 @@ __nscd_getai (const char *key, struct ns
+ }
+
+ /* Store the error number. */
+- *h_errnop = ai_resp->error;
++ *h_errnop = ai_resp.error;
+
+ /* The `errno' to some value != ERANGE. */
+ __set_errno (ENOENT);
+@@ -170,22 +178,25 @@ __nscd_getai (const char *key, struct ns
+ if (sock != -1)
+ close_not_cancel_no_status (sock);
+ out:
+- if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0 && retval != -1)
++ if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
+ {
+ /* When we come here this means there has been a GC cycle while we
+ were looking for the data. This means the data might have been
+ inconsistent. Retry if possible. */
+- if ((gc_cycle & 1) != 0)
++ if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
+ {
+ /* nscd is just running gc now. Disable using the mapping. */
+- __nscd_unmap (mapped);
++ if (atomic_decrement_val (&mapped->counter) == 0)
++ __nscd_unmap (mapped);
+ mapped = NO_MAPPING;
+ }
+
+- *result = NULL;
+- free (resultbuf);
+-
+- goto retry;
++ if (retval != -1)
++ {
++ *result = NULL;
++ free (resultbuf);
++ goto retry;
++ }
+ }
+
+ return retval;
+--- libc/nscd/nscd_getgr_r.c 15 May 2006 20:39:34 -0000 1.42
++++ libc/nscd/nscd_getgr_r.c 31 Jan 2007 09:14:21 -0000 1.43
+@@ -88,6 +89,7 @@ nscd_getgr_r (const char *key, size_t ke
+ struct group **result)
+ {
+ int gc_cycle;
++ int nretries = 0;
+ const uint32_t *len = NULL;
+ size_t lensize = 0;
+
+@@ -97,55 +99,59 @@ nscd_getgr_r (const char *key, size_t ke
+ &__gr_map_handle,
+ &gc_cycle);
+ retry:;
+- const gr_response_header *gr_resp = NULL;
+ const char *gr_name = NULL;
+ size_t gr_name_len = 0;
+ int retval = -1;
+ const char *recend = (const char *) ~UINTMAX_C (0);
++ gr_response_header gr_resp;
+
+ if (mapped != NO_MAPPING)
+ {
+- const struct datahead *found = __nscd_cache_search (type, key, keylen,
+- mapped);
++ struct datahead *found = __nscd_cache_search (type, key, keylen, mapped);
+ if (found != NULL)
+ {
+- gr_resp = &found->data[0].grdata;
+- len = (const uint32_t *) (gr_resp + 1);
+- /* The alignment is always sufficient. */
+- assert (((uintptr_t) len & (__alignof__ (*len) - 1)) == 0);
++ len = (const uint32_t *) (&found->data[0].grdata + 1);
++ gr_resp = found->data[0].grdata;
+ gr_name = ((const char *) len
+- + gr_resp->gr_mem_cnt * sizeof (uint32_t));
+- gr_name_len = gr_resp->gr_name_len + gr_resp->gr_passwd_len;
++ + gr_resp.gr_mem_cnt * sizeof (uint32_t));
++ gr_name_len = gr_resp.gr_name_len + gr_resp.gr_passwd_len;
+ recend = (const char *) found->data + found->recsize;
++ /* Now check if we can trust gr_resp fields. If GC is
++ in progress, it can contain anything. */
++ if (mapped->head->gc_cycle != gc_cycle)
++ {
++ retval = -2;
++ goto out;
++ }
++
++ /* The alignment is always sufficient, unless GC is in progress. */
++ assert (((uintptr_t) len & (__alignof__ (*len) - 1)) == 0);
+ }
+ }
+
+- gr_response_header gr_resp_mem;
+ int sock = -1;
+- if (gr_resp == NULL)
++ if (gr_name == NULL)
+ {
+- sock = __nscd_open_socket (key, keylen, type, &gr_resp_mem,
+- sizeof (gr_resp_mem));
++ sock = __nscd_open_socket (key, keylen, type, &gr_resp,
++ sizeof (gr_resp));
+ if (sock == -1)
+ {
+ __nss_not_use_nscd_group = 1;
+ goto out;
+ }
+-
+- gr_resp = &gr_resp_mem;
+ }
+
+ /* No value found so far. */
+ *result = NULL;
+
+- if (__builtin_expect (gr_resp->found == -1, 0))
++ if (__builtin_expect (gr_resp.found == -1, 0))
+ {
+ /* The daemon does not cache this database. */
+ __nss_not_use_nscd_group = 1;
+ goto out_close;
+ }
+
+- if (gr_resp->found == 1)
++ if (gr_resp.found == 1)
+ {
+ struct iovec vec[2];
+ char *p = buffer;
+@@ -157,8 +163,8 @@ nscd_getgr_r (const char *key, size_t ke
+ align the pointer. */
+ align = ((__alignof__ (char *) - (p - ((char *) 0)))
+ & (__alignof__ (char *) - 1));
+- total_len = (align + (1 + gr_resp->gr_mem_cnt) * sizeof (char *)
+- + gr_resp->gr_name_len + gr_resp->gr_passwd_len);
++ total_len = (align + (1 + gr_resp.gr_mem_cnt) * sizeof (char *)
++ + gr_resp.gr_name_len + gr_resp.gr_passwd_len);
+ if (__builtin_expect (buflen < total_len, 0))
+ {
+ no_room:
+@@ -170,16 +176,16 @@ nscd_getgr_r (const char *key, size_t ke
+
+ p += align;
+ resultbuf->gr_mem = (char **) p;
+- p += (1 + gr_resp->gr_mem_cnt) * sizeof (char *);
++ p += (1 + gr_resp.gr_mem_cnt) * sizeof (char *);
+
+ /* Set pointers for strings. */
+ resultbuf->gr_name = p;
+- p += gr_resp->gr_name_len;
++ p += gr_resp.gr_name_len;
+ resultbuf->gr_passwd = p;
+- p += gr_resp->gr_passwd_len;
++ p += gr_resp.gr_passwd_len;
+
+ /* Fill in what we know now. */
+- resultbuf->gr_gid = gr_resp->gr_gid;
++ resultbuf->gr_gid = gr_resp.gr_gid;
+
+ /* Read the length information, group name, and password. */
+ if (gr_name == NULL)
+@@ -187,17 +193,17 @@ nscd_getgr_r (const char *key, size_t ke
+ /* Allocate array to store lengths. */
+ if (lensize == 0)
+ {
+- lensize = gr_resp->gr_mem_cnt * sizeof (uint32_t);
++ lensize = gr_resp.gr_mem_cnt * sizeof (uint32_t);
+ len = (uint32_t *) alloca (lensize);
+ }
+- else if (gr_resp->gr_mem_cnt * sizeof (uint32_t) > lensize)
++ else if (gr_resp.gr_mem_cnt * sizeof (uint32_t) > lensize)
+ len = extend_alloca (len, lensize,
+- gr_resp->gr_mem_cnt * sizeof (uint32_t));
++ gr_resp.gr_mem_cnt * sizeof (uint32_t));
+
+ vec[0].iov_base = (void *) len;
+- vec[0].iov_len = gr_resp->gr_mem_cnt * sizeof (uint32_t);
++ vec[0].iov_len = gr_resp.gr_mem_cnt * sizeof (uint32_t);
+ vec[1].iov_base = resultbuf->gr_name;
+- vec[1].iov_len = gr_resp->gr_name_len + gr_resp->gr_passwd_len;
++ vec[1].iov_len = gr_resp.gr_name_len + gr_resp.gr_passwd_len;
+ total_len = vec[0].iov_len + vec[1].iov_len;
+
+ /* Get this data. */
+@@ -209,14 +215,14 @@ nscd_getgr_r (const char *key, size_t ke
+ /* We already have the data. Just copy the group name and
+ password. */
+ memcpy (resultbuf->gr_name, gr_name,
+- gr_resp->gr_name_len + gr_resp->gr_passwd_len);
++ gr_resp.gr_name_len + gr_resp.gr_passwd_len);
+
+ /* Clear the terminating entry. */
+- resultbuf->gr_mem[gr_resp->gr_mem_cnt] = NULL;
++ resultbuf->gr_mem[gr_resp.gr_mem_cnt] = NULL;
+
+ /* Prepare reading the group members. */
+ total_len = 0;
+- for (cnt = 0; cnt < gr_resp->gr_mem_cnt; ++cnt)
++ for (cnt = 0; cnt < gr_resp.gr_mem_cnt; ++cnt)
+ {
+ resultbuf->gr_mem[cnt] = p;
+ total_len += len[cnt];
+@@ -224,9 +230,25 @@ nscd_getgr_r (const char *key, size_t ke
+ }
+
+ if (__builtin_expect (gr_name + gr_name_len + total_len > recend, 0))
+- goto out_close;
++ {
++ /* len array might contain garbage during nscd GC cycle,
++ retry rather than fail in that case. */
++ if (gr_name != NULL && mapped->head->gc_cycle != gc_cycle)
++ retval = -2;
++ goto out_close;
++ }
+ if (__builtin_expect (total_len > buflen, 0))
+- goto no_room;
++ {
++ /* len array might contain garbage during nscd GC cycle,
++ retry rather than fail in that case. */
++ if (gr_name != NULL && mapped->head->gc_cycle != gc_cycle)
++ {
++ retval = -2;
++ goto out_close;
++ }
++ else
++ goto no_room;
++ }
+
+ retval = 0;
+ if (gr_name == NULL)
+@@ -248,14 +270,14 @@ nscd_getgr_r (const char *key, size_t ke
+
+ /* Try to detect corrupt databases. */
+ if (resultbuf->gr_name[gr_name_len - 1] != '\0'
+- || resultbuf->gr_passwd[gr_resp->gr_passwd_len - 1] != '\0'
+- || ({for (cnt = 0; cnt < gr_resp->gr_mem_cnt; ++cnt)
++ || resultbuf->gr_passwd[gr_resp.gr_passwd_len - 1] != '\0'
++ || ({for (cnt = 0; cnt < gr_resp.gr_mem_cnt; ++cnt)
+ if (resultbuf->gr_mem[cnt][len[cnt] - 1] != '\0')
+ break;
+- cnt < gr_resp->gr_mem_cnt; }))
++ cnt < gr_resp.gr_mem_cnt; }))
+ {
+ /* We cannot use the database. */
+- retval = -1;
++ retval = mapped->head->gc_cycle != gc_cycle ? -2 : -1;
+ goto out_close;
+ }
+
+@@ -274,19 +296,21 @@ nscd_getgr_r (const char *key, size_t ke
+ if (sock != -1)
+ close_not_cancel_no_status (sock);
+ out:
+- if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0 && retval != -1)
++ if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
+ {
+ /* When we come here this means there has been a GC cycle while we
+ were looking for the data. This means the data might have been
+ inconsistent. Retry if possible. */
+- if ((gc_cycle & 1) != 0)
++ if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
+ {
+ /* nscd is just running gc now. Disable using the mapping. */
+- __nscd_unmap (mapped);
++ if (atomic_decrement_val (&mapped->counter) == 0)
++ __nscd_unmap (mapped);
+ mapped = NO_MAPPING;
+ }
+
+- goto retry;
++ if (retval != -1)
++ goto retry;
+ }
+
+ return retval;
+--- libc/nscd/nscd_gethst_r.c 13 Jan 2007 07:30:16 -0000 1.35
++++ libc/nscd/nscd_gethst_r.c 31 Jan 2007 09:14:21 -0000 1.36
+@@ -118,7 +118,6 @@ nscd_gethst_r (const char *key, size_t k
+ &gc_cycle);
+
+ retry:;
+- const hst_response_header *hst_resp = NULL;
+ const char *h_name = NULL;
+ const uint32_t *aliases_len = NULL;
+ const char *addr_list = NULL;
+@@ -126,18 +125,27 @@ nscd_gethst_r (const char *key, size_t k
+ int retval = -1;
+ const char *recend = (const char *) ~UINTMAX_C (0);
+ int sock = -1;
++ hst_response_header hst_resp;
+ if (mapped != NO_MAPPING)
+ {
+- const struct datahead *found = __nscd_cache_search (type, key, keylen,
+- mapped);
++ /* No const qualifier, as it can change during garbage collection. */
++ struct datahead *found = __nscd_cache_search (type, key, keylen, mapped);
+ if (found != NULL)
+ {
+- hst_resp = &found->data[0].hstdata;
+- h_name = (char *) (hst_resp + 1);
+- aliases_len = (uint32_t *) (h_name + hst_resp->h_name_len);
++ h_name = (char *) (&found->data[0].hstdata + 1);
++ hst_resp = found->data[0].hstdata;
++ aliases_len = (uint32_t *) (h_name + hst_resp.h_name_len);
+ addr_list = ((char *) aliases_len
+- + hst_resp->h_aliases_cnt * sizeof (uint32_t));
+- addr_list_len = hst_resp->h_addr_list_cnt * INADDRSZ;
++ + hst_resp.h_aliases_cnt * sizeof (uint32_t));
++ addr_list_len = hst_resp.h_addr_list_cnt * INADDRSZ;
++ recend = (const char *) found->data + found->recsize;
++ /* Now check if we can trust hst_resp fields. If GC is
++ in progress, it can contain anything. */
++ if (mapped->head->gc_cycle != gc_cycle)
++ {
++ retval = -2;
++ goto out;
++ }
+
+ #ifndef _STRING_ARCH_unaligned
+ /* The aliases_len array in the mapped database might very
+@@ -147,51 +155,47 @@ nscd_gethst_r (const char *key, size_t k
+ if (((uintptr_t) aliases_len & (__alignof__ (*aliases_len) - 1))
+ != 0)
+ {
+- uint32_t *tmp = alloca (hst_resp->h_aliases_cnt
++ uint32_t *tmp = alloca (hst_resp.h_aliases_cnt
+ * sizeof (uint32_t));
+ aliases_len = memcpy (tmp, aliases_len,
+- hst_resp->h_aliases_cnt
++ hst_resp.h_aliases_cnt
+ * sizeof (uint32_t));
+ }
+ #endif
+ if (type != GETHOSTBYADDR && type != GETHOSTBYNAME)
+ {
+- if (hst_resp->h_length == INADDRSZ)
++ if (hst_resp.h_length == INADDRSZ)
+ addr_list += addr_list_len;
+- addr_list_len = hst_resp->h_addr_list_cnt * IN6ADDRSZ;
++ addr_list_len = hst_resp.h_addr_list_cnt * IN6ADDRSZ;
+ }
+- recend = (const char *) found->data + found->recsize;
+ if (__builtin_expect ((const char *) addr_list + addr_list_len
+ > recend, 0))
+- goto out_close;
++ goto out;
+ }
+ }
+
+- hst_response_header hst_resp_mem;
+- if (hst_resp == NULL)
++ if (h_name == NULL)
+ {
+- sock = __nscd_open_socket (key, keylen, type, &hst_resp_mem,
+- sizeof (hst_resp_mem));
++ sock = __nscd_open_socket (key, keylen, type, &hst_resp,
++ sizeof (hst_resp));
+ if (sock == -1)
+ {
+ __nss_not_use_nscd_hosts = 1;
+- goto out;;
++ goto out;
+ }
+-
+- hst_resp = &hst_resp_mem;
+ }
+
+ /* No value found so far. */
+ *result = NULL;
+
+- if (__builtin_expect (hst_resp->found == -1, 0))
++ if (__builtin_expect (hst_resp.found == -1, 0))
+ {
+ /* The daemon does not cache this database. */
+ __nss_not_use_nscd_hosts = 1;
+ goto out_close;
+ }
+
+- if (hst_resp->found == 1)
++ if (hst_resp.found == 1)
+ {
+ struct iovec vec[4];
+ char *cp = buffer;
+@@ -207,15 +211,15 @@ nscd_gethst_r (const char *key, size_t k
+ align the pointer and the base of the h_addr_list pointers. */
+ align1 = ((__alignof__ (char *) - (cp - ((char *) 0)))
+ & (__alignof__ (char *) - 1));
+- align2 = ((__alignof__ (char *) - ((cp + align1 + hst_resp->h_name_len)
++ align2 = ((__alignof__ (char *) - ((cp + align1 + hst_resp.h_name_len)
+ - ((char *) 0)))
+ & (__alignof__ (char *) - 1));
+- if (buflen < (align1 + hst_resp->h_name_len + align2
+- + ((hst_resp->h_aliases_cnt + hst_resp->h_addr_list_cnt
++ if (buflen < (align1 + hst_resp.h_name_len + align2
++ + ((hst_resp.h_aliases_cnt + hst_resp.h_addr_list_cnt
+ + 2)
+ * sizeof (char *))
+- + hst_resp->h_addr_list_cnt * (type == AF_INET
+- ? INADDRSZ : IN6ADDRSZ)))
++ + hst_resp.h_addr_list_cnt * (type == AF_INET
++ ? INADDRSZ : IN6ADDRSZ)))
+ {
+ no_room:
+ *h_errnop = NETDB_INTERNAL;
+@@ -227,12 +231,12 @@ nscd_gethst_r (const char *key, size_t k
+
+ /* Prepare the result as far as we can. */
+ resultbuf->h_aliases = (char **) cp;
+- cp += (hst_resp->h_aliases_cnt + 1) * sizeof (char *);
++ cp += (hst_resp.h_aliases_cnt + 1) * sizeof (char *);
+ resultbuf->h_addr_list = (char **) cp;
+- cp += (hst_resp->h_addr_list_cnt + 1) * sizeof (char *);
++ cp += (hst_resp.h_addr_list_cnt + 1) * sizeof (char *);
+
+ resultbuf->h_name = cp;
+- cp += hst_resp->h_name_len + align2;
++ cp += hst_resp.h_name_len + align2;
+
+ if (type == GETHOSTBYADDR || type == GETHOSTBYNAME)
+ {
+@@ -244,7 +248,7 @@ nscd_gethst_r (const char *key, size_t k
+ resultbuf->h_addrtype = AF_INET6;
+ resultbuf->h_length = IN6ADDRSZ;
+ }
+- for (cnt = 0; cnt < hst_resp->h_addr_list_cnt; ++cnt)
++ for (cnt = 0; cnt < hst_resp.h_addr_list_cnt; ++cnt)
+ {
+ resultbuf->h_addr_list[cnt] = cp;
+ cp += resultbuf->h_length;
+@@ -254,47 +258,47 @@ nscd_gethst_r (const char *key, size_t k
+ if (h_name == NULL)
+ {
+ vec[0].iov_base = resultbuf->h_name;
+- vec[0].iov_len = hst_resp->h_name_len;
+- total_len = hst_resp->h_name_len;
++ vec[0].iov_len = hst_resp.h_name_len;
++ total_len = hst_resp.h_name_len;
+ n = 1;
+
+- if (hst_resp->h_aliases_cnt > 0)
++ if (hst_resp.h_aliases_cnt > 0)
+ {
+- aliases_len = alloca (hst_resp->h_aliases_cnt
++ aliases_len = alloca (hst_resp.h_aliases_cnt
+ * sizeof (uint32_t));
+ vec[n].iov_base = (void *) aliases_len;
+- vec[n].iov_len = hst_resp->h_aliases_cnt * sizeof (uint32_t);
++ vec[n].iov_len = hst_resp.h_aliases_cnt * sizeof (uint32_t);
+
+- total_len += hst_resp->h_aliases_cnt * sizeof (uint32_t);
++ total_len += hst_resp.h_aliases_cnt * sizeof (uint32_t);
+ ++n;
+ }
+
+ if (type == GETHOSTBYADDR || type == GETHOSTBYNAME)
+ {
+ vec[n].iov_base = resultbuf->h_addr_list[0];
+- vec[n].iov_len = hst_resp->h_addr_list_cnt * INADDRSZ;
++ vec[n].iov_len = hst_resp.h_addr_list_cnt * INADDRSZ;
+
+- total_len += hst_resp->h_addr_list_cnt * INADDRSZ;
++ total_len += hst_resp.h_addr_list_cnt * INADDRSZ;
+
+ ++n;
+ }
+ else
+ {
+- if (hst_resp->h_length == INADDRSZ)
++ if (hst_resp.h_length == INADDRSZ)
+ {
+- ignore = alloca (hst_resp->h_addr_list_cnt * INADDRSZ);
++ ignore = alloca (hst_resp.h_addr_list_cnt * INADDRSZ);
+ vec[n].iov_base = ignore;
+- vec[n].iov_len = hst_resp->h_addr_list_cnt * INADDRSZ;
++ vec[n].iov_len = hst_resp.h_addr_list_cnt * INADDRSZ;
+
+- total_len += hst_resp->h_addr_list_cnt * INADDRSZ;
++ total_len += hst_resp.h_addr_list_cnt * INADDRSZ;
+
+ ++n;
+ }
+
+ vec[n].iov_base = resultbuf->h_addr_list[0];
+- vec[n].iov_len = hst_resp->h_addr_list_cnt * IN6ADDRSZ;
++ vec[n].iov_len = hst_resp.h_addr_list_cnt * IN6ADDRSZ;
+
+- total_len += hst_resp->h_addr_list_cnt * IN6ADDRSZ;
++ total_len += hst_resp.h_addr_list_cnt * IN6ADDRSZ;
+
+ ++n;
+ }
+@@ -304,13 +308,13 @@ nscd_gethst_r (const char *key, size_t k
+ }
+ else
+ {
+- memcpy (resultbuf->h_name, h_name, hst_resp->h_name_len);
++ memcpy (resultbuf->h_name, h_name, hst_resp.h_name_len);
+ memcpy (resultbuf->h_addr_list[0], addr_list, addr_list_len);
+ }
+
+ /* Now we also can read the aliases. */
+ total_len = 0;
+- for (cnt = 0; cnt < hst_resp->h_aliases_cnt; ++cnt)
++ for (cnt = 0; cnt < hst_resp.h_aliases_cnt; ++cnt)
+ {
+ resultbuf->h_aliases[cnt] = cp;
+ cp += aliases_len[cnt];
+@@ -320,10 +324,25 @@ nscd_gethst_r (const char *key, size_t k
+
+ if (__builtin_expect ((const char *) addr_list + addr_list_len
+ + total_len > recend, 0))
+- goto out_close;
++ {
++ /* aliases_len array might contain garbage during nscd GC cycle,
++ retry rather than fail in that case. */
++ if (addr_list != NULL && mapped->head->gc_cycle != gc_cycle)
++ retval = -2;
++ goto out_close;
++ }
+ /* See whether this would exceed the buffer capacity. */
+ if (__builtin_expect (cp > buffer + buflen, 0))
+- goto no_room;
++ {
++ /* aliases_len array might contain garbage during nscd GC cycle,
++ retry rather than fail in that case. */
++ if (addr_list != NULL && mapped->head->gc_cycle != gc_cycle)
++ {
++ retval = -2;
++ goto out_close;
++ }
++ goto no_room;
++ }
+
+ /* And finally read the aliases. */
+ if (addr_list == NULL)
+@@ -342,14 +361,18 @@ nscd_gethst_r (const char *key, size_t k
+ (const char *) addr_list + addr_list_len, total_len);
+
+ /* Try to detect corrupt databases. */
+- if (resultbuf->h_name[hst_resp->h_name_len - 1] != '\0'
+- || ({for (cnt = 0; cnt < hst_resp->h_aliases_cnt; ++cnt)
++ if (resultbuf->h_name[hst_resp.h_name_len - 1] != '\0'
++ || ({for (cnt = 0; cnt < hst_resp.h_aliases_cnt; ++cnt)
+ if (resultbuf->h_aliases[cnt][aliases_len[cnt] - 1]
+ != '\0')
+ break;
+- cnt < hst_resp->h_aliases_cnt; }))
+- /* We cannot use the database. */
+- goto out_close;
++ cnt < hst_resp.h_aliases_cnt; }))
++ {
++ /* We cannot use the database. */
++ if (mapped->head->gc_cycle != gc_cycle)
++ retval = -2;
++ goto out_close;
++ }
+
+ retval = 0;
+ *result = resultbuf;
+@@ -358,7 +381,7 @@ nscd_gethst_r (const char *key, size_t k
+ else
+ {
+ /* Store the error number. */
+- *h_errnop = hst_resp->error;
++ *h_errnop = hst_resp.error;
+
+ /* The `errno' to some value != ERANGE. */
+ __set_errno (ENOENT);
+@@ -370,19 +393,21 @@ nscd_gethst_r (const char *key, size_t k
+ if (sock != -1)
+ close_not_cancel_no_status (sock);
+ out:
+- if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0 && retval != -1)
++ if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
+ {
+ /* When we come here this means there has been a GC cycle while we
+ were looking for the data. This means the data might have been
+ inconsistent. Retry if possible. */
+- if ((gc_cycle & 1) != 0 || ++nretries == 5)
++ if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
+ {
+ /* nscd is just running gc now. Disable using the mapping. */
+- __nscd_unmap (mapped);
++ if (atomic_decrement_val (&mapped->counter) == 0)
++ __nscd_unmap (mapped);
+ mapped = NO_MAPPING;
+ }
+
+- goto retry;
++ if (retval != -1)
++ goto retry;
+ }
+
+ return retval;
+--- libc/nscd/nscd_getpw_r.c 22 Sep 2005 14:35:11 -0000 1.31
++++ libc/nscd/nscd_getpw_r.c 31 Jan 2007 09:14:21 -0000 1.32
+@@ -88,76 +89,81 @@ nscd_getpw_r (const char *key, size_t ke
+ struct passwd **result)
+ {
+ int gc_cycle;
++ int nretries = 0;
++
+ /* If the mapping is available, try to search there instead of
+ communicating with the nscd. */
+ struct mapped_database *mapped;
+ mapped = __nscd_get_map_ref (GETFDPW, "passwd", &map_handle, &gc_cycle);
+
+ retry:;
+- const pw_response_header *pw_resp = NULL;
+ const char *pw_name = NULL;
+ int retval = -1;
+ const char *recend = (const char *) ~UINTMAX_C (0);
++ pw_response_header pw_resp;
+
+ if (mapped != NO_MAPPING)
+ {
+- const struct datahead *found = __nscd_cache_search (type, key, keylen,
+- mapped);
++ struct datahead *found = __nscd_cache_search (type, key, keylen, mapped);
+ if (found != NULL)
+ {
+- pw_resp = &found->data[0].pwdata;
+- pw_name = (const char *) (pw_resp + 1);
++ pw_name = (const char *) (&found->data[0].pwdata + 1);
++ pw_resp = found->data[0].pwdata;
+ recend = (const char *) found->data + found->recsize;
++ /* Now check if we can trust pw_resp fields. If GC is
++ in progress, it can contain anything. */
++ if (mapped->head->gc_cycle != gc_cycle)
++ {
++ retval = -2;
++ goto out;
++ }
+ }
+ }
+
+- pw_response_header pw_resp_mem;
+ int sock = -1;
+- if (pw_resp == NULL)
++ if (pw_name == NULL)
+ {
+- sock = __nscd_open_socket (key, keylen, type, &pw_resp_mem,
+- sizeof (pw_resp_mem));
++ sock = __nscd_open_socket (key, keylen, type, &pw_resp,
++ sizeof (pw_resp));
+ if (sock == -1)
+ {
+ __nss_not_use_nscd_passwd = 1;
+ goto out;
+ }
+-
+- pw_resp = &pw_resp_mem;
+ }
+
+ /* No value found so far. */
+ *result = NULL;
+
+- if (__builtin_expect (pw_resp->found == -1, 0))
++ if (__builtin_expect (pw_resp.found == -1, 0))
+ {
+ /* The daemon does not cache this database. */
+ __nss_not_use_nscd_passwd = 1;
+ goto out_close;
+ }
+
+- if (pw_resp->found == 1)
++ if (pw_resp.found == 1)
+ {
+ /* Set the information we already have. */
+- resultbuf->pw_uid = pw_resp->pw_uid;
+- resultbuf->pw_gid = pw_resp->pw_gid;
++ resultbuf->pw_uid = pw_resp.pw_uid;
++ resultbuf->pw_gid = pw_resp.pw_gid;
+
+ char *p = buffer;
+ /* get pw_name */
+ resultbuf->pw_name = p;
+- p += pw_resp->pw_name_len;
++ p += pw_resp.pw_name_len;
+ /* get pw_passwd */
+ resultbuf->pw_passwd = p;
+- p += pw_resp->pw_passwd_len;
++ p += pw_resp.pw_passwd_len;
+ /* get pw_gecos */
+ resultbuf->pw_gecos = p;
+- p += pw_resp->pw_gecos_len;
++ p += pw_resp.pw_gecos_len;
+ /* get pw_dir */
+ resultbuf->pw_dir = p;
+- p += pw_resp->pw_dir_len;
++ p += pw_resp.pw_dir_len;
+ /* get pw_pshell */
+ resultbuf->pw_shell = p;
+- p += pw_resp->pw_shell_len;
++ p += pw_resp.pw_shell_len;
+
+ ssize_t total = p - buffer;
+ if (__builtin_expect (pw_name + total > recend, 0))
+@@ -189,14 +195,14 @@ nscd_getpw_r (const char *key, size_t ke
+ memcpy (resultbuf->pw_name, pw_name, total);
+
+ /* Try to detect corrupt databases. */
+- if (resultbuf->pw_name[pw_resp->pw_name_len - 1] != '\0'
+- || resultbuf->pw_passwd[pw_resp->pw_passwd_len - 1] != '\0'
+- || resultbuf->pw_gecos[pw_resp->pw_gecos_len - 1] != '\0'
+- || resultbuf->pw_dir[pw_resp->pw_dir_len - 1] != '\0'
+- || resultbuf->pw_shell[pw_resp->pw_shell_len - 1] != '\0')
++ if (resultbuf->pw_name[pw_resp.pw_name_len - 1] != '\0'
++ || resultbuf->pw_passwd[pw_resp.pw_passwd_len - 1] != '\0'
++ || resultbuf->pw_gecos[pw_resp.pw_gecos_len - 1] != '\0'
++ || resultbuf->pw_dir[pw_resp.pw_dir_len - 1] != '\0'
++ || resultbuf->pw_shell[pw_resp.pw_shell_len - 1] != '\0')
+ {
+ /* We cannot use the database. */
+- retval = -1;
++ retval = mapped->head->gc_cycle != gc_cycle ? -2 : -1;
+ goto out_close;
+ }
+
+@@ -215,19 +221,21 @@ nscd_getpw_r (const char *key, size_t ke
+ if (sock != -1)
+ close_not_cancel_no_status (sock);
+ out:
+- if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0 && retval != -1)
++ if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
+ {
+ /* When we come here this means there has been a GC cycle while we
+ were looking for the data. This means the data might have been
+ inconsistent. Retry if possible. */
+- if ((gc_cycle & 1) != 0)
++ if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
+ {
+ /* nscd is just running gc now. Disable using the mapping. */
+- __nscd_unmap (mapped);
++ if (atomic_decrement_val (&mapped->counter) == 0)
++ __nscd_unmap (mapped);
+ mapped = NO_MAPPING;
+ }
+
+- goto retry;
++ if (retval != -1)
++ goto retry;
+ }
+
+ return retval;
+--- libc/nscd/nscd_helper.c 2 Oct 2006 16:33:51 -0000 1.17
++++ libc/nscd/nscd_helper.c 31 Jan 2007 09:14:21 -0000 1.18
+@@ -21,6 +21,7 @@
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <stdbool.h>
++#include <string.h>
+ #include <unistd.h>
+ #include <sys/mman.h>
+ #include <sys/poll.h>
+@@ -361,7 +362,10 @@ __nscd_get_map_ref (request_type type, c
+ }
+
+
+-const struct datahead *
++/* Don't return const struct datahead *, as eventhough the record
++ is normally constant, it can change arbitrarily during nscd
++ garbage collection. */
++struct datahead *
+ __nscd_cache_search (request_type type, const char *key, size_t keylen,
+ const struct mapped_database *mapped)
+ {
+@@ -373,16 +377,32 @@ __nscd_cache_search (request_type type,
+ {
+ struct hashentry *here = (struct hashentry *) (mapped->data + work);
+
++#ifndef _STRING_ARCH_unaligned
++ /* Although during garbage collection when moving struct hashentry
++ records around we first copy from old to new location and then
++ adjust pointer from previous hashentry to it, there is no barrier
++ between those memory writes. It is very unlikely to hit it,
++ so check alignment only if a misaligned load can crash the
++ application. */
++ if ((uintptr_t) here & (__alignof__ (*here) - 1))
++ return NULL;
++#endif
++
+ if (type == here->type
+ && keylen == here->len
+- && here->key + here->len <= datasize
++ && here->key + keylen <= datasize
+ && memcmp (key, mapped->data + here->key, keylen) == 0
+ && here->packet + sizeof (struct datahead) <= datasize)
+ {
+ /* We found the entry. Increment the appropriate counter. */
+- const struct datahead *dh
++ struct datahead *dh
+ = (struct datahead *) (mapped->data + here->packet);
+
++#ifndef _STRING_ARCH_unaligned
++ if ((uintptr_t) dh & (__alignof__ (*dh) - 1))
++ return NULL;
++#endif
++
+ /* See whether we must ignore the entry or whether something
+ is wrong because garbage collection is in progress. */
+ if (dh->usable && here->packet + dh->allocsize <= datasize)
+--- libc/nscd/nscd_initgroups.c 29 Sep 2006 17:05:21 -0000 1.11
++++ libc/nscd/nscd_initgroups.c 31 Jan 2007 09:14:21 -0000 1.12
+@@ -39,6 +39,7 @@ __nscd_getgrouplist (const char *user, g
+ {
+ size_t userlen = strlen (user) + 1;
+ int gc_cycle;
++ int nretries = 0;
+
+ /* If the mapping is available, try to search there instead of
+ communicating with the nscd. */
+@@ -46,44 +47,49 @@ __nscd_getgrouplist (const char *user, g
+ mapped = __nscd_get_map_ref (GETFDGR, "group", &__gr_map_handle, &gc_cycle);
+
+ retry:;
+- const initgr_response_header *initgr_resp = NULL;
+ char *respdata = NULL;
+ int retval = -1;
+ int sock = -1;
++ initgr_response_header initgr_resp;
+
+ if (mapped != NO_MAPPING)
+ {
+- const struct datahead *found = __nscd_cache_search (INITGROUPS, user,
+- userlen, mapped);
++ struct datahead *found = __nscd_cache_search (INITGROUPS, user,
++ userlen, mapped);
+ if (found != NULL)
+ {
+- initgr_resp = &found->data[0].initgrdata;
+- respdata = (char *) (initgr_resp + 1);
++ respdata = (char *) (&found->data[0].initgrdata + 1);
++ initgr_resp = found->data[0].initgrdata;
+ char *recend = (char *) found->data + found->recsize;
+
+- if (respdata + initgr_resp->ngrps * sizeof (int32_t) > recend)
++ /* Now check if we can trust initgr_resp fields. If GC is
++ in progress, it can contain anything. */
++ if (mapped->head->gc_cycle != gc_cycle)
++ {
++ retval = -2;
++ goto out;
++ }
++
++ if (respdata + initgr_resp.ngrps * sizeof (int32_t) > recend)
+ goto out;
+ }
+ }
+
+ /* If we do not have the cache mapped, try to get the data over the
+ socket. */
+- initgr_response_header initgr_resp_mem;
+- if (initgr_resp == NULL)
++ if (respdata == NULL)
+ {
+- sock = __nscd_open_socket (user, userlen, INITGROUPS, &initgr_resp_mem,
+- sizeof (initgr_resp_mem));
++ sock = __nscd_open_socket (user, userlen, INITGROUPS, &initgr_resp,
++ sizeof (initgr_resp));
+ if (sock == -1)
+ {
+ /* nscd not running or wrong version. */
+ __nss_not_use_nscd_group = 1;
+ goto out;
+ }
+-
+- initgr_resp = &initgr_resp_mem;
+ }
+
+- if (initgr_resp->found == 1)
++ if (initgr_resp.found == 1)
+ {
+ /* The following code assumes that gid_t and int32_t are the
+ same size. This is the case for al existing implementation.
+@@ -91,40 +97,40 @@ __nscd_getgrouplist (const char *user, g
+ doesn't use memcpy but instead copies each array element one
+ by one. */
+ assert (sizeof (int32_t) == sizeof (gid_t));
+- assert (initgr_resp->ngrps > 0);
++ assert (initgr_resp.ngrps > 0);
+
+ /* Make sure we have enough room. We always count GROUP in even
+ though we might not end up adding it. */
+- if (*size < initgr_resp->ngrps + 1)
++ if (*size < initgr_resp.ngrps + 1)
+ {
+ gid_t *newp = realloc (*groupsp,
+- (initgr_resp->ngrps + 1) * sizeof (gid_t));
++ (initgr_resp.ngrps + 1) * sizeof (gid_t));
+ if (newp == NULL)
+ /* We cannot increase the buffer size. */
+ goto out_close;
+
+ *groupsp = newp;
+- *size = initgr_resp->ngrps + 1;
++ *size = initgr_resp.ngrps + 1;
+ }
+
+ if (respdata == NULL)
+ {
+ /* Read the data from the socket. */
+- if ((size_t) __readall (sock, *groupsp, initgr_resp->ngrps
++ if ((size_t) __readall (sock, *groupsp, initgr_resp.ngrps
+ * sizeof (gid_t))
+- == initgr_resp->ngrps * sizeof (gid_t))
+- retval = initgr_resp->ngrps;
++ == initgr_resp.ngrps * sizeof (gid_t))
++ retval = initgr_resp.ngrps;
+ }
+ else
+ {
+ /* Just copy the data. */
+- retval = initgr_resp->ngrps;
++ retval = initgr_resp.ngrps;
+ memcpy (*groupsp, respdata, retval * sizeof (gid_t));
+ }
+ }
+ else
+ {
+- if (__builtin_expect (initgr_resp->found == -1, 0))
++ if (__builtin_expect (initgr_resp.found == -1, 0))
+ {
+ /* The daemon does not cache this database. */
+ __nss_not_use_nscd_group = 1;
+@@ -153,19 +159,21 @@ __nscd_getgrouplist (const char *user, g
+ if (sock != -1)
+ close_not_cancel_no_status (sock);
+ out:
+- if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0 && retval != -1)
++ if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
+ {
+ /* When we come here this means there has been a GC cycle while we
+ were looking for the data. This means the data might have been
+ inconsistent. Retry if possible. */
+- if ((gc_cycle & 1) != 0)
++ if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
+ {
+ /* nscd is just running gc now. Disable using the mapping. */
+- __nscd_unmap (mapped);
++ if (atomic_decrement_val (&mapped->counter) == 0)
++ __nscd_unmap (mapped);
+ mapped = NO_MAPPING;
+ }
+
+- goto retry;
++ if (retval != -1)
++ goto retry;
+ }
+
+ return retval;
--- /dev/null
+2006-08-24 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/generic/ldsodefs.h (DL_ADDR_SYM_MATCH): For undefined
+ symbol require exact match (these are PLTs).
+ * sysdeps/unix/sysv/linux/powerpc/powerpc64/ldsodefs.h
+ (_dl_ppc64_addr_sym_match): Likewise.
+
+ [BZ #2683]
+ * elf/dl-addr.c (_dl_addr): Don't ignore all undefined symbols.
+ If symbol has a value use it.
+ * elf/tst-dladdr1.c: New file.
+ * elf/Makefile: Add rules to build and run tst-addr1.
+
+2006-05-24 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #2683]
+ * elf/dl-addr.c (_dl_addr): Don't match undefined references.
+
+2005-08-30 Jakub Jelinek <jakub@redhat.com>
+ Alan Modra <amodra@bigpond.net.au>
+
+ * elf/dl-addr.c (_dl_addr): Use DL_ADDR_SYM_MATCH macro.
+ * sysdeps/generic/ldsodefs.h (DL_ADDR_SYM_MATCH): Define.
+ * sysdeps/unix/sysv/linux/powerpc/powerpc64/ldsodefs.h: New file.
+
+--- libc/elf/dl-addr.c.jj 2004-10-19 12:44:19.000000000 -0400
++++ libc/elf/dl-addr.c 2007-02-13 02:56:54.000000000 -0500
+@@ -87,21 +87,16 @@ _dl_addr (const void *address, Dl_info *
+ the string table which generally follows the symbol table. */
+ symtabend = (const ElfW(Sym) *) strtab;
+
+- /* We assume that the string table follows the symbol table,
+- because there is no way in ELF to know the size of the
+- dynamic symbol table!! */
+ for (matchsym = NULL; (void *) symtab < (void *) symtabend; ++symtab)
+- if (addr >= match->l_addr + symtab->st_value
++ if ((ELFW(ST_BIND) (symtab->st_info) == STB_GLOBAL
++ || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK)
+ #if defined USE_TLS
+ && ELFW(ST_TYPE) (symtab->st_info) != STT_TLS
+ #endif
+- && ((symtab->st_size == 0
+- && addr == match->l_addr + symtab->st_value)
+- || addr < match->l_addr + symtab->st_value + symtab->st_size)
+- && symtab->st_name < strtabsize
+- && (matchsym == NULL || matchsym->st_value < symtab->st_value)
+- && (ELFW(ST_BIND) (symtab->st_info) == STB_GLOBAL
+- || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK))
++ && (symtab->st_shndx != SHN_UNDEF
++ || symtab->st_value != 0)
++ && DL_ADDR_SYM_MATCH (match, symtab, matchsym, addr)
++ && symtab->st_name < strtabsize)
+ matchsym = (ElfW(Sym) *) symtab;
+
+ if (mapp)
+--- libc/sysdeps/generic/ldsodefs.h.jj 2005-04-05 22:50:21.000000000 -0400
++++ libc/sysdeps/generic/ldsodefs.h 2007-02-13 02:54:33.000000000 -0500
+@@ -81,6 +81,14 @@ typedef ElfW(Addr) lookup_t;
+ # define DL_DT_FINI_ADDRESS(map, start) (start)
+ #endif
+
++/* On some architectures dladdr can't use st_size of all symbols this way. */
++#define DL_ADDR_SYM_MATCH(L, SYM, MATCHSYM, ADDR) \
++ ((ADDR) >= (L)->l_addr + (SYM)->st_value \
++ && ((((SYM)->st_shndx == SHN_UNDEF || (SYM)->st_size == 0) \
++ && (ADDR) == (L)->l_addr + (SYM)->st_value) \
++ || (ADDR) < (L)->l_addr + (SYM)->st_value + (SYM)->st_size) \
++ && ((MATCHSYM) == NULL || (MATCHSYM)->st_value < (SYM)->st_value))
++
+ /* Unmap a loaded object, called by _dl_close (). */
+ #ifndef DL_UNMAP_IS_SPECIAL
+ # define DL_UNMAP(map) \
+--- libc/sysdeps/unix/sysv/linux/powerpc/powerpc64/ldsodefs.h.jj 2007-02-13 02:49:09.000000000 -0500
++++ libc/sysdeps/unix/sysv/linux/powerpc/powerpc64/ldsodefs.h 2007-02-13 02:54:33.000000000 -0500
+@@ -0,0 +1,77 @@
++/* Run-time dynamic linker data structures for loaded ELF shared objects.
++ Copyright (C) 2005 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#ifndef _LDSODEFS_H
++
++/* Get the real definitions. */
++#include_next <ldsodefs.h>
++
++/* Now define our stuff. */
++
++static inline __attribute__ ((always_inline)) bool
++_dl_ppc64_is_opd_sym (const struct link_map *l, const ElfW(Sym) *sym)
++{
++ return (ELFW(ST_TYPE) (sym->st_info) == STT_FUNC
++ && l->l_addr + sym->st_value >= (ElfW(Addr)) l->l_ld
++ && l->l_addr + sym->st_value < l->l_map_end
++ && sym->st_size != 0);
++}
++
++static inline __attribute__ ((always_inline)) bool
++_dl_ppc64_addr_sym_match (const struct link_map *l, const ElfW(Sym) *sym,
++ const ElfW(Sym) *matchsym, ElfW(Addr) addr)
++{
++ ElfW(Addr) value = l->l_addr + sym->st_value;
++ if (_dl_ppc64_is_opd_sym (l, sym))
++ {
++ if (addr < value || addr >= value + 24)
++ {
++ value = *(ElfW(Addr) *) value;
++ if (addr < value || addr >= value + sym->st_size)
++ return false;
++ }
++ }
++ else if (sym->st_shndx == SHN_UNDEF || sym->st_size == 0)
++ {
++ if (addr != value)
++ return false;
++ }
++ else if (addr < value || addr >= value + sym->st_size)
++ return false;
++
++ if (matchsym == NULL)
++ return true;
++
++ ElfW(Addr) matchvalue = l->l_addr + matchsym->st_value;
++ if (_dl_ppc64_is_opd_sym (l, matchsym)
++ && (addr < matchvalue || addr > matchvalue + 24))
++ matchvalue = *(ElfW(Addr) *) matchvalue;
++
++ return matchvalue < value;
++}
++
++/* If this is a function symbol defined past the end of our dynamic
++ section, then it must be a function descriptor. Allow these symbols
++ to match their associated function code range as well as the
++ descriptor addresses. */
++#undef DL_ADDR_SYM_MATCH
++#define DL_ADDR_SYM_MATCH(L, SYM, MATCHSYM, ADDR) \
++ _dl_ppc64_addr_sym_match (L, SYM, MATCHSYM, ADDR)
++
++#endif /* ldsodefs.h */
+--- libc/elf/tst-addr1.c.jj 2007-02-13 02:59:02.000000000 -0500
++++ libc/elf/tst-addr1.c 2007-02-13 02:54:34.000000000 -0500
+@@ -0,0 +1,19 @@
++#include <dlfcn.h>
++#include <stdio.h>
++#include <string.h>
++
++static int
++do_test (void)
++{
++ Dl_info i;
++ if (dladdr (&printf, &i) == 0)
++ {
++ puts ("not found");
++ return 1;
++ }
++ printf ("found symbol %s in %s\n", i.dli_sname, i.dli_fname);
++ return i.dli_sname == NULL || strcmp (i.dli_sname, "printf") != 0;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- libc/elf/Makefile.jj 2007-02-13 03:00:22.000000000 -0500
++++ libc/elf/Makefile 2007-02-13 02:55:35.000000000 -0500
+@@ -161,7 +161,8 @@ tests += loadtest restest1 preloadtest l
+ tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-align \
+ tst-align2 $(tests-execstack-$(have-z-execstack)) tst-dlmodcount \
+ tst-dlopenrpath tst-deep1 tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
+- unload3 unload4 unload5 unload6 unload7 tst-global1 order2
++ unload3 unload4 unload5 unload6 unload7 tst-global1 order2 \
++ tst-addr1
+ # reldep9
+ test-srcs = tst-pathopt
+ tests-vis-yes = vismain
+@@ -844,3 +845,5 @@ $(objpfx)tst-leaks1-mem: $(objpfx)tst-le
+ $(common-objpfx)malloc/mtrace $(objpfx)tst-leaks1.mtrace > $@
+
+ tst-leaks1-ENV = MALLOC_TRACE=$(objpfx)tst-leaks1.mtrace
++
++$(objpfx)tst-addr1: $(libdl)
--- /dev/null
+2007-02-09 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S
+ (__lll_mutex_timedlock_wait): Use correct pointer when we don't
+ call into the kernel to delay.
+
+--- libc/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S 17 Jan 2007 09:33:20 -0000 1.16
++++ libc/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S 10 Feb 2007 00:04:24 -0000 1.17
+@@ -164,7 +164,7 @@ __lll_mutex_timedlock_wait:
+ 8: /* NB: %edx == 2 */
+ xorl %eax, %eax
+ LOCK
+- cmpxchgl %edx, (%rdi)
++ cmpxchgl %edx, (%r12)
+ jnz 7f
+
+ 6: addq $16, %rsp
--- /dev/null
+2007-11-10 Ulrich Drepper <drepper@redhat.com>
+
+ * crypt/sha256-crypt.c: Fix a comment.
+ * crypt/sha512-crypt.c: Likewise.
+
+2007-10-28 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #5204]
+ * crypt/sha256c-test.c: Define TIMEOUT to 6 for ancient hardware.
+ * crypt/sha512c-test.c: Likewise.
+
+2007-09-19 Ulrich Drepper <drepper@redhat.com>
+
+ * crypt/Makefile (libcrypt-routines): Add sha256-crypt, sha256,
+ sha512-crypt, and sha512.
+ (tests): Add sha256test, sha256c-test, sha512test, and sha512c-test.
+ (distribute): Add sha256.h and sha512.h.
+ * crypt/crypt-entry.c (crypt): Recognize the new $5$ and $6$ prefixes
+ and call the appropriate code.
+ * crypt/sha256-crypt.c: New file.
+ * crypt/sha256.c: New file.
+ * crypt/sha256.h: New file.
+ * crypt/sha256c-test.c: New file.
+ * crypt/sha256test.c: New file.
+ * crypt/sha512-crypt.c: New file.
+ * crypt/sha512.c: New file.
+ * crypt/sha512.h: New file.
+ * crypt/sha512c-test.c: New file.
+ * crypt/sha512test.c: New file.
+
+--- libc/crypt/Makefile 5 Oct 2005 19:33:35 -0000 1.10
++++ libc/crypt/Makefile 19 Sep 2007 20:37:33 -0000 1.11
+@@ -28,12 +28,13 @@ distribute := md5.h
+ extra-libs := libcrypt
+ extra-libs-others := $(extra-libs)
+
+-libcrypt-routines := crypt-entry md5-crypt md5 crypt crypt_util
++libcrypt-routines := crypt-entry md5-crypt md5 sha256-crypt sha256 \
++ sha512-crypt sha512 crypt crypt_util
+
+-tests = cert md5test md5c-test
++tests = cert md5test md5c-test sha256test sha256c-test sha512test sha512c-test
+
+ distribute = ufc-crypt.h crypt-private.h ufc.c speeds.c README.ufc-crypt \
+- Banner md5.h
++ Banner md5.h sha256.h sha512.h
+
+ include ../Makeconfig
+
+@@ -42,6 +43,8 @@ routines += $(libcrypt-routines)
+ endif
+
+ $(objpfx)md5test: $(objpfx)md5.o
++$(objpfx)sha256test: $(objpfx)sha256.o
++$(objpfx)sha512test: $(objpfx)sha512.o
+
+ include ../Rules
+
+--- libc/crypt/crypt-entry.c 6 Jul 2001 05:18:49 -0000 1.2
++++ libc/crypt/crypt-entry.c 19 Sep 2007 20:37:15 -0000 1.3
+@@ -55,6 +55,12 @@ void _ufc_clearmem (char *start, int cnt
+ extern char *__md5_crypt_r (const char *key, const char *salt, char *buffer,
+ int buflen);
+ extern char *__md5_crypt (const char *key, const char *salt);
++extern char *__sha256_crypt_r (const char *key, const char *salt,
++ char *buffer, int buflen);
++extern char *__sha256_crypt (const char *key, const char *salt);
++extern char *__sha512_crypt_r (const char *key, const char *salt,
++ char *buffer, int buflen);
++extern char *__sha512_crypt (const char *key, const char *salt);
+ #endif
+
+ /* Define our magic string to mark salt for MD5 encryption
+@@ -62,6 +68,12 @@ extern char *__md5_crypt (const char *ke
+ encryption implementations. */
+ static const char md5_salt_prefix[] = "$1$";
+
++/* Magic string for SHA256 encryption. */
++static const char sha256_salt_prefix[] = "$5$";
++
++/* Magic string for SHA512 encryption. */
++static const char sha512_salt_prefix[] = "$6$";
++
+ /* For use by the old, non-reentrant routines (crypt/encrypt/setkey) */
+ extern struct crypt_data _ufc_foobar;
+
+@@ -84,6 +96,16 @@ __crypt_r (key, salt, data)
+ if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0)
+ return __md5_crypt_r (key, salt, (char *) data,
+ sizeof (struct crypt_data));
++
++ /* Try to find out whether we have to use SHA256 encryption replacement. */
++ if (strncmp (sha256_salt_prefix, salt, sizeof (sha256_salt_prefix) - 1) == 0)
++ return __sha256_crypt_r (key, salt, (char *) data,
++ sizeof (struct crypt_data));
++
++ /* Try to find out whether we have to use SHA512 encryption replacement. */
++ if (strncmp (sha512_salt_prefix, salt, sizeof (sha512_salt_prefix) - 1) == 0)
++ return __sha512_crypt_r (key, salt, (char *) data,
++ sizeof (struct crypt_data));
+ #endif
+
+ /*
+@@ -126,6 +148,14 @@ crypt (key, salt)
+ /* Try to find out whether we have to use MD5 encryption replacement. */
+ if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0)
+ return __md5_crypt (key, salt);
++
++ /* Try to find out whether we have to use SHA256 encryption replacement. */
++ if (strncmp (sha256_salt_prefix, salt, sizeof (sha256_salt_prefix) - 1) == 0)
++ return __sha256_crypt (key, salt);
++
++ /* Try to find out whether we have to use SHA512 encryption replacement. */
++ if (strncmp (sha512_salt_prefix, salt, sizeof (sha512_salt_prefix) - 1) == 0)
++ return __sha512_crypt (key, salt);
+ #endif
+
+ return __crypt_r (key, salt, &_ufc_foobar);
+--- libc/crypt/sha256-crypt.c 1 Jan 1970 00:00:00 -0000
++++ libc/crypt/sha256-crypt.c 10 Nov 2007 19:36:00 -0000 1.2
+@@ -0,0 +1,344 @@
++/* One way encryption based on SHA256 sum.
++ Copyright (C) 2007 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2007.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <assert.h>
++#include <errno.h>
++#include <stdbool.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/param.h>
++
++#include "sha256.h"
++
++
++/* Define our magic string to mark salt for SHA256 "encryption"
++ replacement. */
++static const char sha256_salt_prefix[] = "$5$";
++
++/* Prefix for optional rounds specification. */
++static const char sha256_rounds_prefix[] = "rounds=";
++
++/* Maximum salt string length. */
++#define SALT_LEN_MAX 16
++/* Default number of rounds if not explicitly specified. */
++#define ROUNDS_DEFAULT 5000
++/* Minimum number of rounds. */
++#define ROUNDS_MIN 1000
++/* Maximum number of rounds. */
++#define ROUNDS_MAX 999999999
++
++/* Table with characters for base64 transformation. */
++static const char b64t[64] =
++"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
++
++
++/* Prototypes for local functions. */
++extern char *__sha256_crypt_r (const char *key, const char *salt,
++ char *buffer, int buflen);
++extern char *__sha256_crypt (const char *key, const char *salt);
++
++
++char *
++__sha256_crypt_r (key, salt, buffer, buflen)
++ const char *key;
++ const char *salt;
++ char *buffer;
++ int buflen;
++{
++ unsigned char alt_result[32]
++ __attribute__ ((__aligned__ (__alignof__ (uint32_t))));
++ unsigned char temp_result[32]
++ __attribute__ ((__aligned__ (__alignof__ (uint32_t))));
++ struct sha256_ctx ctx;
++ struct sha256_ctx alt_ctx;
++ size_t salt_len;
++ size_t key_len;
++ size_t cnt;
++ char *cp;
++ char *copied_key = NULL;
++ char *copied_salt = NULL;
++ char *p_bytes;
++ char *s_bytes;
++ /* Default number of rounds. */
++ size_t rounds = ROUNDS_DEFAULT;
++ bool rounds_custom = false;
++
++ /* Find beginning of salt string. The prefix should normally always
++ be present. Just in case it is not. */
++ if (strncmp (sha256_salt_prefix, salt, sizeof (sha256_salt_prefix) - 1) == 0)
++ /* Skip salt prefix. */
++ salt += sizeof (sha256_salt_prefix) - 1;
++
++ if (strncmp (salt, sha256_rounds_prefix, sizeof (sha256_rounds_prefix) - 1)
++ == 0)
++ {
++ const char *num = salt + sizeof (sha256_rounds_prefix) - 1;
++ char *endp;
++ unsigned long int srounds = strtoul (num, &endp, 10);
++ if (*endp == '$')
++ {
++ salt = endp + 1;
++ rounds = MAX (ROUNDS_MIN, MIN (srounds, ROUNDS_MAX));
++ rounds_custom = true;
++ }
++ }
++
++ salt_len = MIN (strcspn (salt, "$"), SALT_LEN_MAX);
++ key_len = strlen (key);
++
++ if ((key - (char *) 0) % __alignof__ (uint32_t) != 0)
++ {
++ char *tmp = (char *) alloca (key_len + __alignof__ (uint32_t));
++ key = copied_key =
++ memcpy (tmp + __alignof__ (uint32_t)
++ - (tmp - (char *) 0) % __alignof__ (uint32_t),
++ key, key_len);
++ assert ((key - (char *) 0) % __alignof__ (uint32_t) == 0);
++ }
++
++ if ((salt - (char *) 0) % __alignof__ (uint32_t) != 0)
++ {
++ char *tmp = (char *) alloca (salt_len + __alignof__ (uint32_t));
++ salt = copied_salt =
++ memcpy (tmp + __alignof__ (uint32_t)
++ - (tmp - (char *) 0) % __alignof__ (uint32_t),
++ salt, salt_len);
++ assert ((salt - (char *) 0) % __alignof__ (uint32_t) == 0);
++ }
++
++ /* Prepare for the real work. */
++ __sha256_init_ctx (&ctx);
++
++ /* Add the key string. */
++ __sha256_process_bytes (key, key_len, &ctx);
++
++ /* The last part is the salt string. This must be at most 16
++ characters and it ends at the first `$' character. */
++ __sha256_process_bytes (salt, salt_len, &ctx);
++
++
++ /* Compute alternate SHA256 sum with input KEY, SALT, and KEY. The
++ final result will be added to the first context. */
++ __sha256_init_ctx (&alt_ctx);
++
++ /* Add key. */
++ __sha256_process_bytes (key, key_len, &alt_ctx);
++
++ /* Add salt. */
++ __sha256_process_bytes (salt, salt_len, &alt_ctx);
++
++ /* Add key again. */
++ __sha256_process_bytes (key, key_len, &alt_ctx);
++
++ /* Now get result of this (32 bytes) and add it to the other
++ context. */
++ __sha256_finish_ctx (&alt_ctx, alt_result);
++
++ /* Add for any character in the key one byte of the alternate sum. */
++ for (cnt = key_len; cnt > 32; cnt -= 32)
++ __sha256_process_bytes (alt_result, 32, &ctx);
++ __sha256_process_bytes (alt_result, cnt, &ctx);
++
++ /* Take the binary representation of the length of the key and for every
++ 1 add the alternate sum, for every 0 the key. */
++ for (cnt = key_len; cnt > 0; cnt >>= 1)
++ if ((cnt & 1) != 0)
++ __sha256_process_bytes (alt_result, 32, &ctx);
++ else
++ __sha256_process_bytes (key, key_len, &ctx);
++
++ /* Create intermediate result. */
++ __sha256_finish_ctx (&ctx, alt_result);
++
++ /* Start computation of P byte sequence. */
++ __sha256_init_ctx (&alt_ctx);
++
++ /* For every character in the password add the entire password. */
++ for (cnt = 0; cnt < key_len; ++cnt)
++ __sha256_process_bytes (key, key_len, &alt_ctx);
++
++ /* Finish the digest. */
++ __sha256_finish_ctx (&alt_ctx, temp_result);
++
++ /* Create byte sequence P. */
++ cp = p_bytes = alloca (key_len);
++ for (cnt = key_len; cnt >= 32; cnt -= 32)
++ cp = mempcpy (cp, temp_result, 32);
++ memcpy (cp, temp_result, cnt);
++
++ /* Start computation of S byte sequence. */
++ __sha256_init_ctx (&alt_ctx);
++
++ /* For every character in the password add the entire password. */
++ for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
++ __sha256_process_bytes (salt, salt_len, &alt_ctx);
++
++ /* Finish the digest. */
++ __sha256_finish_ctx (&alt_ctx, temp_result);
++
++ /* Create byte sequence S. */
++ cp = s_bytes = alloca (salt_len);
++ for (cnt = salt_len; cnt >= 32; cnt -= 32)
++ cp = mempcpy (cp, temp_result, 32);
++ memcpy (cp, temp_result, cnt);
++
++ /* Repeatedly run the collected hash value through SHA256 to burn
++ CPU cycles. */
++ for (cnt = 0; cnt < rounds; ++cnt)
++ {
++ /* New context. */
++ __sha256_init_ctx (&ctx);
++
++ /* Add key or last result. */
++ if ((cnt & 1) != 0)
++ __sha256_process_bytes (p_bytes, key_len, &ctx);
++ else
++ __sha256_process_bytes (alt_result, 32, &ctx);
++
++ /* Add salt for numbers not divisible by 3. */
++ if (cnt % 3 != 0)
++ __sha256_process_bytes (s_bytes, salt_len, &ctx);
++
++ /* Add key for numbers not divisible by 7. */
++ if (cnt % 7 != 0)
++ __sha256_process_bytes (p_bytes, key_len, &ctx);
++
++ /* Add key or last result. */
++ if ((cnt & 1) != 0)
++ __sha256_process_bytes (alt_result, 32, &ctx);
++ else
++ __sha256_process_bytes (p_bytes, key_len, &ctx);
++
++ /* Create intermediate result. */
++ __sha256_finish_ctx (&ctx, alt_result);
++ }
++
++ /* Now we can construct the result string. It consists of three
++ parts. */
++ cp = __stpncpy (buffer, sha256_salt_prefix, MAX (0, buflen));
++ buflen -= sizeof (sha256_salt_prefix) - 1;
++
++ if (rounds_custom)
++ {
++ int n = snprintf (cp, MAX (0, buflen), "%s%zu$",
++ sha256_rounds_prefix, rounds);
++ cp += n;
++ buflen -= n;
++ }
++
++ cp = __stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len));
++ buflen -= MIN ((size_t) MAX (0, buflen), salt_len);
++
++ if (buflen > 0)
++ {
++ *cp++ = '$';
++ --buflen;
++ }
++
++#define b64_from_24bit(B2, B1, B0, N) \
++ do { \
++ unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \
++ int n = (N); \
++ while (n-- > 0 && buflen > 0) \
++ { \
++ *cp++ = b64t[w & 0x3f]; \
++ --buflen; \
++ w >>= 6; \
++ } \
++ } while (0)
++
++ b64_from_24bit (alt_result[0], alt_result[10], alt_result[20], 4);
++ b64_from_24bit (alt_result[21], alt_result[1], alt_result[11], 4);
++ b64_from_24bit (alt_result[12], alt_result[22], alt_result[2], 4);
++ b64_from_24bit (alt_result[3], alt_result[13], alt_result[23], 4);
++ b64_from_24bit (alt_result[24], alt_result[4], alt_result[14], 4);
++ b64_from_24bit (alt_result[15], alt_result[25], alt_result[5], 4);
++ b64_from_24bit (alt_result[6], alt_result[16], alt_result[26], 4);
++ b64_from_24bit (alt_result[27], alt_result[7], alt_result[17], 4);
++ b64_from_24bit (alt_result[18], alt_result[28], alt_result[8], 4);
++ b64_from_24bit (alt_result[9], alt_result[19], alt_result[29], 4);
++ b64_from_24bit (0, alt_result[31], alt_result[30], 3);
++ if (buflen <= 0)
++ {
++ __set_errno (ERANGE);
++ buffer = NULL;
++ }
++ else
++ *cp = '\0'; /* Terminate the string. */
++
++ /* Clear the buffer for the intermediate result so that people
++ attaching to processes or reading core dumps cannot get any
++ information. We do it in this way to clear correct_words[]
++ inside the SHA256 implementation as well. */
++ __sha256_init_ctx (&ctx);
++ __sha256_finish_ctx (&ctx, alt_result);
++ memset (temp_result, '\0', sizeof (temp_result));
++ memset (p_bytes, '\0', key_len);
++ memset (s_bytes, '\0', salt_len);
++ memset (&ctx, '\0', sizeof (ctx));
++ memset (&alt_ctx, '\0', sizeof (alt_ctx));
++ if (copied_key != NULL)
++ memset (copied_key, '\0', key_len);
++ if (copied_salt != NULL)
++ memset (copied_salt, '\0', salt_len);
++
++ return buffer;
++}
++
++#ifndef _LIBC
++# define libc_freeres_ptr(decl) decl
++#endif
++libc_freeres_ptr (static char *buffer);
++
++/* This entry point is equivalent to the `crypt' function in Unix
++ libcs. */
++char *
++__sha256_crypt (const char *key, const char *salt)
++{
++ /* We don't want to have an arbitrary limit in the size of the
++ password. We can compute an upper bound for the size of the
++ result in advance and so we can prepare the buffer we pass to
++ `sha256_crypt_r'. */
++ static int buflen;
++ int needed = (sizeof (sha256_salt_prefix) - 1
++ + sizeof (sha256_rounds_prefix) + 9 + 1
++ + strlen (salt) + 1 + 43 + 1);
++
++ if (buflen < needed)
++ {
++ char *new_buffer = (char *) realloc (buffer, needed);
++ if (new_buffer == NULL)
++ return NULL;
++
++ buffer = new_buffer;
++ buflen = needed;
++ }
++
++ return __sha256_crypt_r (key, salt, buffer, buflen);
++}
++
++#ifndef _LIBC
++static void
++__attribute__ ((__destructor__))
++free_mem (void)
++{
++ free (buffer);
++}
++#endif
+--- libc/crypt/sha256.c 1 Jan 1970 00:00:00 -0000
++++ libc/crypt/sha256.c 19 Sep 2007 20:35:44 -0000 1.1
+@@ -0,0 +1,304 @@
++/* Functions to compute SHA256 message digest of files or memory blocks.
++ according to the definition of SHA256 in FIPS 180-2.
++ Copyright (C) 2007 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++/* Written by Ulrich Drepper <drepper@redhat.com>, 2007. */
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include <endian.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/types.h>
++
++#include "sha256.h"
++
++#if __BYTE_ORDER == __LITTLE_ENDIAN
++# ifdef _LIBC
++# include <byteswap.h>
++# define SWAP(n) bswap_32 (n)
++# else
++# define SWAP(n) \
++ (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
++# endif
++#else
++# define SWAP(n) (n)
++#endif
++
++
++/* This array contains the bytes used to pad the buffer to the next
++ 64-byte boundary. (FIPS 180-2:5.1.1) */
++static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
++
++
++/* Constants for SHA256 from FIPS 180-2:4.2.2. */
++static const uint32_t K[64] =
++ {
++ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
++ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
++ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
++ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
++ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
++ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
++ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
++ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
++ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
++ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
++ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
++ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
++ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
++ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
++ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
++ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
++ };
++
++
++/* Process LEN bytes of BUFFER, accumulating context into CTX.
++ It is assumed that LEN % 64 == 0. */
++static void
++sha256_process_block (const void *buffer, size_t len, struct sha256_ctx *ctx)
++{
++ const uint32_t *words = buffer;
++ size_t nwords = len / sizeof (uint32_t);
++ uint32_t a = ctx->H[0];
++ uint32_t b = ctx->H[1];
++ uint32_t c = ctx->H[2];
++ uint32_t d = ctx->H[3];
++ uint32_t e = ctx->H[4];
++ uint32_t f = ctx->H[5];
++ uint32_t g = ctx->H[6];
++ uint32_t h = ctx->H[7];
++
++ /* First increment the byte count. FIPS 180-2 specifies the possible
++ length of the file up to 2^64 bits. Here we only compute the
++ number of bytes. Do a double word increment. */
++ ctx->total[0] += len;
++ if (ctx->total[0] < len)
++ ++ctx->total[1];
++
++ /* Process all bytes in the buffer with 64 bytes in each round of
++ the loop. */
++ while (nwords > 0)
++ {
++ uint32_t W[64];
++ uint32_t a_save = a;
++ uint32_t b_save = b;
++ uint32_t c_save = c;
++ uint32_t d_save = d;
++ uint32_t e_save = e;
++ uint32_t f_save = f;
++ uint32_t g_save = g;
++ uint32_t h_save = h;
++
++ /* Operators defined in FIPS 180-2:4.1.2. */
++#define Ch(x, y, z) ((x & y) ^ (~x & z))
++#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
++#define S0(x) (CYCLIC (x, 2) ^ CYCLIC (x, 13) ^ CYCLIC (x, 22))
++#define S1(x) (CYCLIC (x, 6) ^ CYCLIC (x, 11) ^ CYCLIC (x, 25))
++#define R0(x) (CYCLIC (x, 7) ^ CYCLIC (x, 18) ^ (x >> 3))
++#define R1(x) (CYCLIC (x, 17) ^ CYCLIC (x, 19) ^ (x >> 10))
++
++ /* It is unfortunate that C does not provide an operator for
++ cyclic rotation. Hope the C compiler is smart enough. */
++#define CYCLIC(w, s) ((w >> s) | (w << (32 - s)))
++
++ /* Compute the message schedule according to FIPS 180-2:6.2.2 step 2. */
++ for (unsigned int t = 0; t < 16; ++t)
++ {
++ W[t] = SWAP (*words);
++ ++words;
++ }
++ for (unsigned int t = 16; t < 64; ++t)
++ W[t] = R1 (W[t - 2]) + W[t - 7] + R0 (W[t - 15]) + W[t - 16];
++
++ /* The actual computation according to FIPS 180-2:6.2.2 step 3. */
++ for (unsigned int t = 0; t < 64; ++t)
++ {
++ uint32_t T1 = h + S1 (e) + Ch (e, f, g) + K[t] + W[t];
++ uint32_t T2 = S0 (a) + Maj (a, b, c);
++ h = g;
++ g = f;
++ f = e;
++ e = d + T1;
++ d = c;
++ c = b;
++ b = a;
++ a = T1 + T2;
++ }
++
++ /* Add the starting values of the context according to FIPS 180-2:6.2.2
++ step 4. */
++ a += a_save;
++ b += b_save;
++ c += c_save;
++ d += d_save;
++ e += e_save;
++ f += f_save;
++ g += g_save;
++ h += h_save;
++
++ /* Prepare for the next round. */
++ nwords -= 16;
++ }
++
++ /* Put checksum in context given as argument. */
++ ctx->H[0] = a;
++ ctx->H[1] = b;
++ ctx->H[2] = c;
++ ctx->H[3] = d;
++ ctx->H[4] = e;
++ ctx->H[5] = f;
++ ctx->H[6] = g;
++ ctx->H[7] = h;
++}
++
++
++/* Initialize structure containing state of computation.
++ (FIPS 180-2:5.3.2) */
++void
++__sha256_init_ctx (ctx)
++ struct sha256_ctx *ctx;
++{
++ ctx->H[0] = 0x6a09e667;
++ ctx->H[1] = 0xbb67ae85;
++ ctx->H[2] = 0x3c6ef372;
++ ctx->H[3] = 0xa54ff53a;
++ ctx->H[4] = 0x510e527f;
++ ctx->H[5] = 0x9b05688c;
++ ctx->H[6] = 0x1f83d9ab;
++ ctx->H[7] = 0x5be0cd19;
++
++ ctx->total[0] = ctx->total[1] = 0;
++ ctx->buflen = 0;
++}
++
++
++/* Process the remaining bytes in the internal buffer and the usual
++ prolog according to the standard and write the result to RESBUF.
++
++ IMPORTANT: On some systems it is required that RESBUF is correctly
++ aligned for a 32 bits value. */
++void *
++__sha256_finish_ctx (ctx, resbuf)
++ struct sha256_ctx *ctx;
++ void *resbuf;
++{
++ /* Take yet unprocessed bytes into account. */
++ uint32_t bytes = ctx->buflen;
++ size_t pad;
++
++ /* Now count remaining bytes. */
++ ctx->total[0] += bytes;
++ if (ctx->total[0] < bytes)
++ ++ctx->total[1];
++
++ pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
++ memcpy (&ctx->buffer[bytes], fillbuf, pad);
++
++ /* Put the 64-bit file length in *bits* at the end of the buffer. */
++ *(uint32_t *) &ctx->buffer[bytes + pad + 4] = SWAP (ctx->total[0] << 3);
++ *(uint32_t *) &ctx->buffer[bytes + pad] = SWAP ((ctx->total[1] << 3) |
++ (ctx->total[0] >> 29));
++
++ /* Process last bytes. */
++ sha256_process_block (ctx->buffer, bytes + pad + 8, ctx);
++
++ /* Put result from CTX in first 32 bytes following RESBUF. */
++ for (unsigned int i = 0; i < 8; ++i)
++ ((uint32_t *) resbuf)[i] = SWAP (ctx->H[i]);
++
++ return resbuf;
++}
++
++
++void
++__sha256_process_bytes (buffer, len, ctx)
++ const void *buffer;
++ size_t len;
++ struct sha256_ctx *ctx;
++{
++ /* When we already have some bits in our internal buffer concatenate
++ both inputs first. */
++ if (ctx->buflen != 0)
++ {
++ size_t left_over = ctx->buflen;
++ size_t add = 128 - left_over > len ? len : 128 - left_over;
++
++ memcpy (&ctx->buffer[left_over], buffer, add);
++ ctx->buflen += add;
++
++ if (ctx->buflen > 64)
++ {
++ sha256_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
++
++ ctx->buflen &= 63;
++ /* The regions in the following copy operation cannot overlap. */
++ memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
++ ctx->buflen);
++ }
++
++ buffer = (const char *) buffer + add;
++ len -= add;
++ }
++
++ /* Process available complete blocks. */
++ if (len >= 64)
++ {
++#if !_STRING_ARCH_unaligned
++/* To check alignment gcc has an appropriate operator. Other
++ compilers don't. */
++# if __GNUC__ >= 2
++# define UNALIGNED_P(p) (((uintptr_t) p) % __alignof__ (uint32_t) != 0)
++# else
++# define UNALIGNED_P(p) (((uintptr_t) p) % sizeof (uint32_t) != 0)
++# endif
++ if (UNALIGNED_P (buffer))
++ while (len > 64)
++ {
++ sha256_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
++ buffer = (const char *) buffer + 64;
++ len -= 64;
++ }
++ else
++#endif
++ {
++ sha256_process_block (buffer, len & ~63, ctx);
++ buffer = (const char *) buffer + (len & ~63);
++ len &= 63;
++ }
++ }
++
++ /* Move remaining bytes into internal buffer. */
++ if (len > 0)
++ {
++ size_t left_over = ctx->buflen;
++
++ memcpy (&ctx->buffer[left_over], buffer, len);
++ left_over += len;
++ if (left_over >= 64)
++ {
++ sha256_process_block (ctx->buffer, 64, ctx);
++ left_over -= 64;
++ memcpy (ctx->buffer, &ctx->buffer[64], left_over);
++ }
++ ctx->buflen = left_over;
++ }
++}
+--- libc/crypt/sha256.h 1 Jan 1970 00:00:00 -0000
++++ libc/crypt/sha256.h 19 Sep 2007 20:35:50 -0000 1.1
+@@ -0,0 +1,58 @@
++/* Declaration of functions and data types used for SHA256 sum computing
++ library functions.
++ Copyright (C) 2007 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#ifndef _SHA256_H
++#define _SHA256_H 1
++
++#include <limits.h>
++#include <stdint.h>
++#include <stdio.h>
++
++
++/* Structure to save state of computation between the single steps. */
++struct sha256_ctx
++{
++ uint32_t H[8];
++
++ uint32_t total[2];
++ uint32_t buflen;
++ char buffer[128] __attribute__ ((__aligned__ (__alignof__ (uint32_t))));
++};
++
++/* Initialize structure containing state of computation.
++ (FIPS 180-2: 5.3.2) */
++extern void __sha256_init_ctx (struct sha256_ctx *ctx) __THROW;
++
++/* Starting with the result of former calls of this function (or the
++ initialization function update the context for the next LEN bytes
++ starting at BUFFER.
++ It is NOT required that LEN is a multiple of 64. */
++extern void __sha256_process_bytes (const void *buffer, size_t len,
++ struct sha256_ctx *ctx) __THROW;
++
++/* Process the remaining bytes in the buffer and put result from CTX
++ in first 32 bytes following RESBUF.
++
++ IMPORTANT: On some systems it is required that RESBUF is correctly
++ aligned for a 32 bits value. */
++extern void *__sha256_finish_ctx (struct sha256_ctx *ctx, void *resbuf)
++ __THROW;
++
++#endif /* sha256.h */
+--- libc/crypt/sha256c-test.c 1 Jan 1970 00:00:00 -0000
++++ libc/crypt/sha256c-test.c 28 Oct 2007 19:46:43 -0000 1.2
+@@ -0,0 +1,62 @@
++#include <crypt.h>
++#include <stdio.h>
++#include <string.h>
++
++static const struct
++{
++ const char *salt;
++ const char *input;
++ const char *expected;
++} tests[] =
++{
++ { "$5$saltstring", "Hello world!",
++ "$5$saltstring$5B8vYYiY.CVt1RlTTf8KbXBH3hsxY/GNooZaBBGWEc5" },
++ { "$5$rounds=10000$saltstringsaltstring", "Hello world!",
++ "$5$rounds=10000$saltstringsaltst$3xv.VbSHBb41AL9AvLeujZkZRBAwqFMz2."
++ "opqey6IcA" },
++ { "$5$rounds=5000$toolongsaltstring", "This is just a test",
++ "$5$rounds=5000$toolongsaltstrin$Un/5jzAHMgOGZ5.mWJpuVolil07guHPvOW8"
++ "mGRcvxa5" },
++ { "$5$rounds=1400$anotherlongsaltstring",
++ "a very much longer text to encrypt. This one even stretches over more"
++ "than one line.",
++ "$5$rounds=1400$anotherlongsalts$Rx.j8H.h8HjEDGomFU8bDkXm3XIUnzyxf12"
++ "oP84Bnq1" },
++ { "$5$rounds=77777$short",
++ "we have a short salt string but not a short password",
++ "$5$rounds=77777$short$JiO1O3ZpDAxGJeaDIuqCoEFysAe1mZNJRs3pw0KQRd/" },
++ { "$5$rounds=123456$asaltof16chars..", "a short string",
++ "$5$rounds=123456$asaltof16chars..$gP3VQ/6X7UUEW3HkBn2w1/Ptq2jxPyzV/"
++ "cZKmF/wJvD" },
++ { "$5$rounds=10$roundstoolow", "the minimum number is still observed",
++ "$5$rounds=1000$roundstoolow$yfvwcWrQ8l/K0DAWyuPMDNHpIVlTQebY9l/gL97"
++ "2bIC" },
++};
++#define ntests (sizeof (tests) / sizeof (tests[0]))
++
++
++
++static int
++do_test (void)
++{
++ int result = 0;
++ int i;
++
++ for (i = 0; i < ntests; ++i)
++ {
++ char *cp = crypt (tests[i].input, tests[i].salt);
++
++ if (strcmp (cp, tests[i].expected) != 0)
++ {
++ printf ("test %d: expected \"%s\", got \"%s\"\n",
++ i, tests[i].expected, cp);
++ result = 1;
++ }
++ }
++
++ return result;
++}
++
++#define TIMEOUT 6
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- libc/crypt/sha256test.c 1 Jan 1970 00:00:00 -0000
++++ libc/crypt/sha256test.c 19 Sep 2007 20:36:15 -0000 1.1
+@@ -0,0 +1,92 @@
++#include <string.h>
++#include "sha256.h"
++
++static const struct
++{
++ const char *input;
++ const char result[32];
++} tests[] =
++ {
++ /* Test vectors from FIPS 180-2: appendix B.1. */
++ { "abc",
++ "\xba\x78\x16\xbf\x8f\x01\xcf\xea\x41\x41\x40\xde\x5d\xae\x22\x23"
++ "\xb0\x03\x61\xa3\x96\x17\x7a\x9c\xb4\x10\xff\x61\xf2\x00\x15\xad" },
++ /* Test vectors from FIPS 180-2: appendix B.2. */
++ { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
++ "\x24\x8d\x6a\x61\xd2\x06\x38\xb8\xe5\xc0\x26\x93\x0c\x3e\x60\x39"
++ "\xa3\x3c\xe4\x59\x64\xff\x21\x67\xf6\xec\xed\xd4\x19\xdb\x06\xc1" },
++ /* Test vectors from the NESSIE project. */
++ { "",
++ "\xe3\xb0\xc4\x42\x98\xfc\x1c\x14\x9a\xfb\xf4\xc8\x99\x6f\xb9\x24"
++ "\x27\xae\x41\xe4\x64\x9b\x93\x4c\xa4\x95\x99\x1b\x78\x52\xb8\x55" },
++ { "a",
++ "\xca\x97\x81\x12\xca\x1b\xbd\xca\xfa\xc2\x31\xb3\x9a\x23\xdc\x4d"
++ "\xa7\x86\xef\xf8\x14\x7c\x4e\x72\xb9\x80\x77\x85\xaf\xee\x48\xbb" },
++ { "message digest",
++ "\xf7\x84\x6f\x55\xcf\x23\xe1\x4e\xeb\xea\xb5\xb4\xe1\x55\x0c\xad"
++ "\x5b\x50\x9e\x33\x48\xfb\xc4\xef\xa3\xa1\x41\x3d\x39\x3c\xb6\x50" },
++ { "abcdefghijklmnopqrstuvwxyz",
++ "\x71\xc4\x80\xdf\x93\xd6\xae\x2f\x1e\xfa\xd1\x44\x7c\x66\xc9\x52"
++ "\x5e\x31\x62\x18\xcf\x51\xfc\x8d\x9e\xd8\x32\xf2\xda\xf1\x8b\x73" },
++ { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
++ "\x24\x8d\x6a\x61\xd2\x06\x38\xb8\xe5\xc0\x26\x93\x0c\x3e\x60\x39"
++ "\xa3\x3c\xe4\x59\x64\xff\x21\x67\xf6\xec\xed\xd4\x19\xdb\x06\xc1" },
++ { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
++ "\xdb\x4b\xfc\xbd\x4d\xa0\xcd\x85\xa6\x0c\x3c\x37\xd3\xfb\xd8\x80"
++ "\x5c\x77\xf1\x5f\xc6\xb1\xfd\xfe\x61\x4e\xe0\xa7\xc8\xfd\xb4\xc0" },
++ { "123456789012345678901234567890123456789012345678901234567890"
++ "12345678901234567890",
++ "\xf3\x71\xbc\x4a\x31\x1f\x2b\x00\x9e\xef\x95\x2d\xd8\x3c\xa8\x0e"
++ "\x2b\x60\x02\x6c\x8e\x93\x55\x92\xd0\xf9\xc3\x08\x45\x3c\x81\x3e" }
++ };
++
++
++int
++main (void)
++{
++ struct sha256_ctx ctx;
++ char sum[32];
++ int result = 0;
++ int cnt;
++
++ for (cnt = 0; cnt < (int) (sizeof (tests) / sizeof (tests[0])); ++cnt)
++ {
++ __sha256_init_ctx (&ctx);
++ __sha256_process_bytes (tests[cnt].input, strlen (tests[cnt].input),
++ &ctx);
++ __sha256_finish_ctx (&ctx, sum);
++ if (memcmp (tests[cnt].result, sum, 32) != 0)
++ {
++ printf ("test %d run %d failed\n", cnt, 1);
++ result = 1;
++ }
++
++ __sha256_init_ctx (&ctx);
++ for (int i = 0; tests[cnt].input[i] != '\0'; ++i)
++ __sha256_process_bytes (&tests[cnt].input[i], 1, &ctx);
++ __sha256_finish_ctx (&ctx, sum);
++ if (memcmp (tests[cnt].result, sum, 32) != 0)
++ {
++ printf ("test %d run %d failed\n", cnt, 2);
++ result = 1;
++ }
++ }
++
++ /* Test vector from FIPS 180-2: appendix B.3. */
++ char buf[1000];
++ memset (buf, 'a', sizeof (buf));
++ __sha256_init_ctx (&ctx);
++ for (int i = 0; i < 1000; ++i)
++ __sha256_process_bytes (buf, sizeof (buf), &ctx);
++ __sha256_finish_ctx (&ctx, sum);
++ static const char expected[32] =
++ "\xcd\xc7\x6e\x5c\x99\x14\xfb\x92\x81\xa1\xc7\xe2\x84\xd7\x3e\x67"
++ "\xf1\x80\x9a\x48\xa4\x97\x20\x0e\x04\x6d\x39\xcc\xc7\x11\x2c\xd0";
++ if (memcmp (expected, sum, 32) != 0)
++ {
++ printf ("test %d failed\n", cnt);
++ result = 1;
++ }
++
++ return result;
++}
+--- libc/crypt/sha512-crypt.c 1 Jan 1970 00:00:00 -0000
++++ libc/crypt/sha512-crypt.c 10 Nov 2007 19:36:00 -0000 1.2
+@@ -0,0 +1,356 @@
++/* One way encryption based on SHA512 sum.
++ Copyright (C) 2007 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2007.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <assert.h>
++#include <errno.h>
++#include <stdbool.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/param.h>
++
++#include "sha512.h"
++
++
++/* Define our magic string to mark salt for SHA512 "encryption"
++ replacement. */
++static const char sha512_salt_prefix[] = "$6$";
++
++/* Prefix for optional rounds specification. */
++static const char sha512_rounds_prefix[] = "rounds=";
++
++/* Maximum salt string length. */
++#define SALT_LEN_MAX 16
++/* Default number of rounds if not explicitly specified. */
++#define ROUNDS_DEFAULT 5000
++/* Minimum number of rounds. */
++#define ROUNDS_MIN 1000
++/* Maximum number of rounds. */
++#define ROUNDS_MAX 999999999
++
++/* Table with characters for base64 transformation. */
++static const char b64t[64] =
++"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
++
++
++/* Prototypes for local functions. */
++extern char *__sha512_crypt_r (const char *key, const char *salt,
++ char *buffer, int buflen);
++extern char *__sha512_crypt (const char *key, const char *salt);
++
++
++char *
++__sha512_crypt_r (key, salt, buffer, buflen)
++ const char *key;
++ const char *salt;
++ char *buffer;
++ int buflen;
++{
++ unsigned char alt_result[64]
++ __attribute__ ((__aligned__ (__alignof__ (uint64_t))));
++ unsigned char temp_result[64]
++ __attribute__ ((__aligned__ (__alignof__ (uint64_t))));
++ struct sha512_ctx ctx;
++ struct sha512_ctx alt_ctx;
++ size_t salt_len;
++ size_t key_len;
++ size_t cnt;
++ char *cp;
++ char *copied_key = NULL;
++ char *copied_salt = NULL;
++ char *p_bytes;
++ char *s_bytes;
++ /* Default number of rounds. */
++ size_t rounds = ROUNDS_DEFAULT;
++ bool rounds_custom = false;
++
++ /* Find beginning of salt string. The prefix should normally always
++ be present. Just in case it is not. */
++ if (strncmp (sha512_salt_prefix, salt, sizeof (sha512_salt_prefix) - 1) == 0)
++ /* Skip salt prefix. */
++ salt += sizeof (sha512_salt_prefix) - 1;
++
++ if (strncmp (salt, sha512_rounds_prefix, sizeof (sha512_rounds_prefix) - 1)
++ == 0)
++ {
++ const char *num = salt + sizeof (sha512_rounds_prefix) - 1;
++ char *endp;
++ unsigned long int srounds = strtoul (num, &endp, 10);
++ if (*endp == '$')
++ {
++ salt = endp + 1;
++ rounds = MAX (ROUNDS_MIN, MIN (srounds, ROUNDS_MAX));
++ rounds_custom = true;
++ }
++ }
++
++ salt_len = MIN (strcspn (salt, "$"), SALT_LEN_MAX);
++ key_len = strlen (key);
++
++ if ((key - (char *) 0) % __alignof__ (uint64_t) != 0)
++ {
++ char *tmp = (char *) alloca (key_len + __alignof__ (uint64_t));
++ key = copied_key =
++ memcpy (tmp + __alignof__ (uint64_t)
++ - (tmp - (char *) 0) % __alignof__ (uint64_t),
++ key, key_len);
++ assert ((key - (char *) 0) % __alignof__ (uint64_t) == 0);
++ }
++
++ if ((salt - (char *) 0) % __alignof__ (uint64_t) != 0)
++ {
++ char *tmp = (char *) alloca (salt_len + __alignof__ (uint64_t));
++ salt = copied_salt =
++ memcpy (tmp + __alignof__ (uint64_t)
++ - (tmp - (char *) 0) % __alignof__ (uint64_t),
++ salt, salt_len);
++ assert ((salt - (char *) 0) % __alignof__ (uint64_t) == 0);
++ }
++
++ /* Prepare for the real work. */
++ __sha512_init_ctx (&ctx);
++
++ /* Add the key string. */
++ __sha512_process_bytes (key, key_len, &ctx);
++
++ /* The last part is the salt string. This must be at most 16
++ characters and it ends at the first `$' character. */
++ __sha512_process_bytes (salt, salt_len, &ctx);
++
++
++ /* Compute alternate SHA512 sum with input KEY, SALT, and KEY. The
++ final result will be added to the first context. */
++ __sha512_init_ctx (&alt_ctx);
++
++ /* Add key. */
++ __sha512_process_bytes (key, key_len, &alt_ctx);
++
++ /* Add salt. */
++ __sha512_process_bytes (salt, salt_len, &alt_ctx);
++
++ /* Add key again. */
++ __sha512_process_bytes (key, key_len, &alt_ctx);
++
++ /* Now get result of this (64 bytes) and add it to the other
++ context. */
++ __sha512_finish_ctx (&alt_ctx, alt_result);
++
++ /* Add for any character in the key one byte of the alternate sum. */
++ for (cnt = key_len; cnt > 64; cnt -= 64)
++ __sha512_process_bytes (alt_result, 64, &ctx);
++ __sha512_process_bytes (alt_result, cnt, &ctx);
++
++ /* Take the binary representation of the length of the key and for every
++ 1 add the alternate sum, for every 0 the key. */
++ for (cnt = key_len; cnt > 0; cnt >>= 1)
++ if ((cnt & 1) != 0)
++ __sha512_process_bytes (alt_result, 64, &ctx);
++ else
++ __sha512_process_bytes (key, key_len, &ctx);
++
++ /* Create intermediate result. */
++ __sha512_finish_ctx (&ctx, alt_result);
++
++ /* Start computation of P byte sequence. */
++ __sha512_init_ctx (&alt_ctx);
++
++ /* For every character in the password add the entire password. */
++ for (cnt = 0; cnt < key_len; ++cnt)
++ __sha512_process_bytes (key, key_len, &alt_ctx);
++
++ /* Finish the digest. */
++ __sha512_finish_ctx (&alt_ctx, temp_result);
++
++ /* Create byte sequence P. */
++ cp = p_bytes = alloca (key_len);
++ for (cnt = key_len; cnt >= 64; cnt -= 64)
++ cp = mempcpy (cp, temp_result, 64);
++ memcpy (cp, temp_result, cnt);
++
++ /* Start computation of S byte sequence. */
++ __sha512_init_ctx (&alt_ctx);
++
++ /* For every character in the password add the entire password. */
++ for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
++ __sha512_process_bytes (salt, salt_len, &alt_ctx);
++
++ /* Finish the digest. */
++ __sha512_finish_ctx (&alt_ctx, temp_result);
++
++ /* Create byte sequence S. */
++ cp = s_bytes = alloca (salt_len);
++ for (cnt = salt_len; cnt >= 64; cnt -= 64)
++ cp = mempcpy (cp, temp_result, 64);
++ memcpy (cp, temp_result, cnt);
++
++ /* Repeatedly run the collected hash value through SHA512 to burn
++ CPU cycles. */
++ for (cnt = 0; cnt < rounds; ++cnt)
++ {
++ /* New context. */
++ __sha512_init_ctx (&ctx);
++
++ /* Add key or last result. */
++ if ((cnt & 1) != 0)
++ __sha512_process_bytes (p_bytes, key_len, &ctx);
++ else
++ __sha512_process_bytes (alt_result, 64, &ctx);
++
++ /* Add salt for numbers not divisible by 3. */
++ if (cnt % 3 != 0)
++ __sha512_process_bytes (s_bytes, salt_len, &ctx);
++
++ /* Add key for numbers not divisible by 7. */
++ if (cnt % 7 != 0)
++ __sha512_process_bytes (p_bytes, key_len, &ctx);
++
++ /* Add key or last result. */
++ if ((cnt & 1) != 0)
++ __sha512_process_bytes (alt_result, 64, &ctx);
++ else
++ __sha512_process_bytes (p_bytes, key_len, &ctx);
++
++ /* Create intermediate result. */
++ __sha512_finish_ctx (&ctx, alt_result);
++ }
++
++ /* Now we can construct the result string. It consists of three
++ parts. */
++ cp = __stpncpy (buffer, sha512_salt_prefix, MAX (0, buflen));
++ buflen -= sizeof (sha512_salt_prefix) - 1;
++
++ if (rounds_custom)
++ {
++ int n = snprintf (cp, MAX (0, buflen), "%s%zu$",
++ sha512_rounds_prefix, rounds);
++ cp += n;
++ buflen -= n;
++ }
++
++ cp = __stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len));
++ buflen -= MIN ((size_t) MAX (0, buflen), salt_len);
++
++ if (buflen > 0)
++ {
++ *cp++ = '$';
++ --buflen;
++ }
++
++#define b64_from_24bit(B2, B1, B0, N) \
++ do { \
++ unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \
++ int n = (N); \
++ while (n-- > 0 && buflen > 0) \
++ { \
++ *cp++ = b64t[w & 0x3f]; \
++ --buflen; \
++ w >>= 6; \
++ } \
++ } while (0)
++
++ b64_from_24bit (alt_result[0], alt_result[21], alt_result[42], 4);
++ b64_from_24bit (alt_result[22], alt_result[43], alt_result[1], 4);
++ b64_from_24bit (alt_result[44], alt_result[2], alt_result[23], 4);
++ b64_from_24bit (alt_result[3], alt_result[24], alt_result[45], 4);
++ b64_from_24bit (alt_result[25], alt_result[46], alt_result[4], 4);
++ b64_from_24bit (alt_result[47], alt_result[5], alt_result[26], 4);
++ b64_from_24bit (alt_result[6], alt_result[27], alt_result[48], 4);
++ b64_from_24bit (alt_result[28], alt_result[49], alt_result[7], 4);
++ b64_from_24bit (alt_result[50], alt_result[8], alt_result[29], 4);
++ b64_from_24bit (alt_result[9], alt_result[30], alt_result[51], 4);
++ b64_from_24bit (alt_result[31], alt_result[52], alt_result[10], 4);
++ b64_from_24bit (alt_result[53], alt_result[11], alt_result[32], 4);
++ b64_from_24bit (alt_result[12], alt_result[33], alt_result[54], 4);
++ b64_from_24bit (alt_result[34], alt_result[55], alt_result[13], 4);
++ b64_from_24bit (alt_result[56], alt_result[14], alt_result[35], 4);
++ b64_from_24bit (alt_result[15], alt_result[36], alt_result[57], 4);
++ b64_from_24bit (alt_result[37], alt_result[58], alt_result[16], 4);
++ b64_from_24bit (alt_result[59], alt_result[17], alt_result[38], 4);
++ b64_from_24bit (alt_result[18], alt_result[39], alt_result[60], 4);
++ b64_from_24bit (alt_result[40], alt_result[61], alt_result[19], 4);
++ b64_from_24bit (alt_result[62], alt_result[20], alt_result[41], 4);
++ b64_from_24bit (0, 0, alt_result[63], 2);
++
++ if (buflen <= 0)
++ {
++ __set_errno (ERANGE);
++ buffer = NULL;
++ }
++ else
++ *cp = '\0'; /* Terminate the string. */
++
++ /* Clear the buffer for the intermediate result so that people
++ attaching to processes or reading core dumps cannot get any
++ information. We do it in this way to clear correct_words[]
++ inside the SHA512 implementation as well. */
++ __sha512_init_ctx (&ctx);
++ __sha512_finish_ctx (&ctx, alt_result);
++ memset (temp_result, '\0', sizeof (temp_result));
++ memset (p_bytes, '\0', key_len);
++ memset (s_bytes, '\0', salt_len);
++ memset (&ctx, '\0', sizeof (ctx));
++ memset (&alt_ctx, '\0', sizeof (alt_ctx));
++ if (copied_key != NULL)
++ memset (copied_key, '\0', key_len);
++ if (copied_salt != NULL)
++ memset (copied_salt, '\0', salt_len);
++
++ return buffer;
++}
++
++#ifndef _LIBC
++# define libc_freeres_ptr(decl) decl
++#endif
++libc_freeres_ptr (static char *buffer);
++
++/* This entry point is equivalent to the `crypt' function in Unix
++ libcs. */
++char *
++__sha512_crypt (const char *key, const char *salt)
++{
++ /* We don't want to have an arbitrary limit in the size of the
++ password. We can compute an upper bound for the size of the
++ result in advance and so we can prepare the buffer we pass to
++ `sha512_crypt_r'. */
++ static int buflen;
++ int needed = (sizeof (sha512_salt_prefix) - 1
++ + sizeof (sha512_rounds_prefix) + 9 + 1
++ + strlen (salt) + 1 + 86 + 1);
++
++ if (buflen < needed)
++ {
++ char *new_buffer = (char *) realloc (buffer, needed);
++ if (new_buffer == NULL)
++ return NULL;
++
++ buffer = new_buffer;
++ buflen = needed;
++ }
++
++ return __sha512_crypt_r (key, salt, buffer, buflen);
++}
++
++#ifndef _LIBC
++static void
++__attribute__ ((__destructor__))
++free_mem (void)
++{
++ free (buffer);
++}
++#endif
+--- libc/crypt/sha512.c 1 Jan 1970 00:00:00 -0000
++++ libc/crypt/sha512.c 19 Sep 2007 20:36:37 -0000 1.1
+@@ -0,0 +1,336 @@
++/* Functions to compute SHA512 message digest of files or memory blocks.
++ according to the definition of SHA512 in FIPS 180-2.
++ Copyright (C) 2007 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++/* Written by Ulrich Drepper <drepper@redhat.com>, 2007. */
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include <endian.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/types.h>
++
++#include "sha512.h"
++
++#if __BYTE_ORDER == __LITTLE_ENDIAN
++# ifdef _LIBC
++# include <byteswap.h>
++# define SWAP(n) bswap_64 (n)
++# else
++# define SWAP(n) \
++ (((n) << 56) \
++ | (((n) & 0xff00) << 40) \
++ | (((n) & 0xff0000) << 24) \
++ | (((n) & 0xff000000) << 8) \
++ | (((n) >> 8) & 0xff000000) \
++ | (((n) >> 24) & 0xff0000) \
++ | (((n) >> 40) & 0xff00) \
++ | ((n) >> 56))
++# endif
++#else
++# define SWAP(n) (n)
++#endif
++
++
++/* This array contains the bytes used to pad the buffer to the next
++ 64-byte boundary. (FIPS 180-2:5.1.2) */
++static const unsigned char fillbuf[128] = { 0x80, 0 /* , 0, 0, ... */ };
++
++
++/* Constants for SHA512 from FIPS 180-2:4.2.3. */
++static const uint64_t K[80] =
++ {
++ UINT64_C (0x428a2f98d728ae22), UINT64_C (0x7137449123ef65cd),
++ UINT64_C (0xb5c0fbcfec4d3b2f), UINT64_C (0xe9b5dba58189dbbc),
++ UINT64_C (0x3956c25bf348b538), UINT64_C (0x59f111f1b605d019),
++ UINT64_C (0x923f82a4af194f9b), UINT64_C (0xab1c5ed5da6d8118),
++ UINT64_C (0xd807aa98a3030242), UINT64_C (0x12835b0145706fbe),
++ UINT64_C (0x243185be4ee4b28c), UINT64_C (0x550c7dc3d5ffb4e2),
++ UINT64_C (0x72be5d74f27b896f), UINT64_C (0x80deb1fe3b1696b1),
++ UINT64_C (0x9bdc06a725c71235), UINT64_C (0xc19bf174cf692694),
++ UINT64_C (0xe49b69c19ef14ad2), UINT64_C (0xefbe4786384f25e3),
++ UINT64_C (0x0fc19dc68b8cd5b5), UINT64_C (0x240ca1cc77ac9c65),
++ UINT64_C (0x2de92c6f592b0275), UINT64_C (0x4a7484aa6ea6e483),
++ UINT64_C (0x5cb0a9dcbd41fbd4), UINT64_C (0x76f988da831153b5),
++ UINT64_C (0x983e5152ee66dfab), UINT64_C (0xa831c66d2db43210),
++ UINT64_C (0xb00327c898fb213f), UINT64_C (0xbf597fc7beef0ee4),
++ UINT64_C (0xc6e00bf33da88fc2), UINT64_C (0xd5a79147930aa725),
++ UINT64_C (0x06ca6351e003826f), UINT64_C (0x142929670a0e6e70),
++ UINT64_C (0x27b70a8546d22ffc), UINT64_C (0x2e1b21385c26c926),
++ UINT64_C (0x4d2c6dfc5ac42aed), UINT64_C (0x53380d139d95b3df),
++ UINT64_C (0x650a73548baf63de), UINT64_C (0x766a0abb3c77b2a8),
++ UINT64_C (0x81c2c92e47edaee6), UINT64_C (0x92722c851482353b),
++ UINT64_C (0xa2bfe8a14cf10364), UINT64_C (0xa81a664bbc423001),
++ UINT64_C (0xc24b8b70d0f89791), UINT64_C (0xc76c51a30654be30),
++ UINT64_C (0xd192e819d6ef5218), UINT64_C (0xd69906245565a910),
++ UINT64_C (0xf40e35855771202a), UINT64_C (0x106aa07032bbd1b8),
++ UINT64_C (0x19a4c116b8d2d0c8), UINT64_C (0x1e376c085141ab53),
++ UINT64_C (0x2748774cdf8eeb99), UINT64_C (0x34b0bcb5e19b48a8),
++ UINT64_C (0x391c0cb3c5c95a63), UINT64_C (0x4ed8aa4ae3418acb),
++ UINT64_C (0x5b9cca4f7763e373), UINT64_C (0x682e6ff3d6b2b8a3),
++ UINT64_C (0x748f82ee5defb2fc), UINT64_C (0x78a5636f43172f60),
++ UINT64_C (0x84c87814a1f0ab72), UINT64_C (0x8cc702081a6439ec),
++ UINT64_C (0x90befffa23631e28), UINT64_C (0xa4506cebde82bde9),
++ UINT64_C (0xbef9a3f7b2c67915), UINT64_C (0xc67178f2e372532b),
++ UINT64_C (0xca273eceea26619c), UINT64_C (0xd186b8c721c0c207),
++ UINT64_C (0xeada7dd6cde0eb1e), UINT64_C (0xf57d4f7fee6ed178),
++ UINT64_C (0x06f067aa72176fba), UINT64_C (0x0a637dc5a2c898a6),
++ UINT64_C (0x113f9804bef90dae), UINT64_C (0x1b710b35131c471b),
++ UINT64_C (0x28db77f523047d84), UINT64_C (0x32caab7b40c72493),
++ UINT64_C (0x3c9ebe0a15c9bebc), UINT64_C (0x431d67c49c100d4c),
++ UINT64_C (0x4cc5d4becb3e42b6), UINT64_C (0x597f299cfc657e2a),
++ UINT64_C (0x5fcb6fab3ad6faec), UINT64_C (0x6c44198c4a475817)
++ };
++
++
++/* Process LEN bytes of BUFFER, accumulating context into CTX.
++ It is assumed that LEN % 128 == 0. */
++static void
++sha512_process_block (const void *buffer, size_t len, struct sha512_ctx *ctx)
++{
++ const uint64_t *words = buffer;
++ size_t nwords = len / sizeof (uint64_t);
++ uint64_t a = ctx->H[0];
++ uint64_t b = ctx->H[1];
++ uint64_t c = ctx->H[2];
++ uint64_t d = ctx->H[3];
++ uint64_t e = ctx->H[4];
++ uint64_t f = ctx->H[5];
++ uint64_t g = ctx->H[6];
++ uint64_t h = ctx->H[7];
++
++ /* First increment the byte count. FIPS 180-2 specifies the possible
++ length of the file up to 2^128 bits. Here we only compute the
++ number of bytes. Do a double word increment. */
++ ctx->total[0] += len;
++ if (ctx->total[0] < len)
++ ++ctx->total[1];
++
++ /* Process all bytes in the buffer with 128 bytes in each round of
++ the loop. */
++ while (nwords > 0)
++ {
++ uint64_t W[80];
++ uint64_t a_save = a;
++ uint64_t b_save = b;
++ uint64_t c_save = c;
++ uint64_t d_save = d;
++ uint64_t e_save = e;
++ uint64_t f_save = f;
++ uint64_t g_save = g;
++ uint64_t h_save = h;
++
++ /* Operators defined in FIPS 180-2:4.1.2. */
++#define Ch(x, y, z) ((x & y) ^ (~x & z))
++#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
++#define S0(x) (CYCLIC (x, 28) ^ CYCLIC (x, 34) ^ CYCLIC (x, 39))
++#define S1(x) (CYCLIC (x, 14) ^ CYCLIC (x, 18) ^ CYCLIC (x, 41))
++#define R0(x) (CYCLIC (x, 1) ^ CYCLIC (x, 8) ^ (x >> 7))
++#define R1(x) (CYCLIC (x, 19) ^ CYCLIC (x, 61) ^ (x >> 6))
++
++ /* It is unfortunate that C does not provide an operator for
++ cyclic rotation. Hope the C compiler is smart enough. */
++#define CYCLIC(w, s) ((w >> s) | (w << (64 - s)))
++
++ /* Compute the message schedule according to FIPS 180-2:6.3.2 step 2. */
++ for (unsigned int t = 0; t < 16; ++t)
++ {
++ W[t] = SWAP (*words);
++ ++words;
++ }
++ for (unsigned int t = 16; t < 80; ++t)
++ W[t] = R1 (W[t - 2]) + W[t - 7] + R0 (W[t - 15]) + W[t - 16];
++
++ /* The actual computation according to FIPS 180-2:6.3.2 step 3. */
++ for (unsigned int t = 0; t < 80; ++t)
++ {
++ uint64_t T1 = h + S1 (e) + Ch (e, f, g) + K[t] + W[t];
++ uint64_t T2 = S0 (a) + Maj (a, b, c);
++ h = g;
++ g = f;
++ f = e;
++ e = d + T1;
++ d = c;
++ c = b;
++ b = a;
++ a = T1 + T2;
++ }
++
++ /* Add the starting values of the context according to FIPS 180-2:6.3.2
++ step 4. */
++ a += a_save;
++ b += b_save;
++ c += c_save;
++ d += d_save;
++ e += e_save;
++ f += f_save;
++ g += g_save;
++ h += h_save;
++
++ /* Prepare for the next round. */
++ nwords -= 16;
++ }
++
++ /* Put checksum in context given as argument. */
++ ctx->H[0] = a;
++ ctx->H[1] = b;
++ ctx->H[2] = c;
++ ctx->H[3] = d;
++ ctx->H[4] = e;
++ ctx->H[5] = f;
++ ctx->H[6] = g;
++ ctx->H[7] = h;
++}
++
++
++/* Initialize structure containing state of computation.
++ (FIPS 180-2:5.3.3) */
++void
++__sha512_init_ctx (ctx)
++ struct sha512_ctx *ctx;
++{
++ ctx->H[0] = UINT64_C (0x6a09e667f3bcc908);
++ ctx->H[1] = UINT64_C (0xbb67ae8584caa73b);
++ ctx->H[2] = UINT64_C (0x3c6ef372fe94f82b);
++ ctx->H[3] = UINT64_C (0xa54ff53a5f1d36f1);
++ ctx->H[4] = UINT64_C (0x510e527fade682d1);
++ ctx->H[5] = UINT64_C (0x9b05688c2b3e6c1f);
++ ctx->H[6] = UINT64_C (0x1f83d9abfb41bd6b);
++ ctx->H[7] = UINT64_C (0x5be0cd19137e2179);
++
++ ctx->total[0] = ctx->total[1] = 0;
++ ctx->buflen = 0;
++}
++
++
++/* Process the remaining bytes in the internal buffer and the usual
++ prolog according to the standard and write the result to RESBUF.
++
++ IMPORTANT: On some systems it is required that RESBUF is correctly
++ aligned for a 32 bits value. */
++void *
++__sha512_finish_ctx (ctx, resbuf)
++ struct sha512_ctx *ctx;
++ void *resbuf;
++{
++ /* Take yet unprocessed bytes into account. */
++ uint64_t bytes = ctx->buflen;
++ size_t pad;
++
++ /* Now count remaining bytes. */
++ ctx->total[0] += bytes;
++ if (ctx->total[0] < bytes)
++ ++ctx->total[1];
++
++ pad = bytes >= 112 ? 128 + 112 - bytes : 112 - bytes;
++ memcpy (&ctx->buffer[bytes], fillbuf, pad);
++
++ /* Put the 128-bit file length in *bits* at the end of the buffer. */
++ *(uint64_t *) &ctx->buffer[bytes + pad + 8] = SWAP (ctx->total[0] << 3);
++ *(uint64_t *) &ctx->buffer[bytes + pad] = SWAP ((ctx->total[1] << 3) |
++ (ctx->total[0] >> 61));
++
++ /* Process last bytes. */
++ sha512_process_block (ctx->buffer, bytes + pad + 16, ctx);
++
++ /* Put result from CTX in first 64 bytes following RESBUF. */
++ for (unsigned int i = 0; i < 8; ++i)
++ ((uint64_t *) resbuf)[i] = SWAP (ctx->H[i]);
++
++ return resbuf;
++}
++
++
++void
++__sha512_process_bytes (buffer, len, ctx)
++ const void *buffer;
++ size_t len;
++ struct sha512_ctx *ctx;
++{
++ /* When we already have some bits in our internal buffer concatenate
++ both inputs first. */
++ if (ctx->buflen != 0)
++ {
++ size_t left_over = ctx->buflen;
++ size_t add = 256 - left_over > len ? len : 256 - left_over;
++
++ memcpy (&ctx->buffer[left_over], buffer, add);
++ ctx->buflen += add;
++
++ if (ctx->buflen > 128)
++ {
++ sha512_process_block (ctx->buffer, ctx->buflen & ~127, ctx);
++
++ ctx->buflen &= 127;
++ /* The regions in the following copy operation cannot overlap. */
++ memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~127],
++ ctx->buflen);
++ }
++
++ buffer = (const char *) buffer + add;
++ len -= add;
++ }
++
++ /* Process available complete blocks. */
++ if (len >= 128)
++ {
++#if !_STRING_ARCH_unaligned
++/* To check alignment gcc has an appropriate operator. Other
++ compilers don't. */
++# if __GNUC__ >= 2
++# define UNALIGNED_P(p) (((uintptr_t) p) % __alignof__ (uint64_t) != 0)
++# else
++# define UNALIGNED_P(p) (((uintptr_t) p) % sizeof (uint64_t) != 0)
++# endif
++ if (UNALIGNED_P (buffer))
++ while (len > 128)
++ {
++ sha512_process_block (memcpy (ctx->buffer, buffer, 128), 128,
++ ctx);
++ buffer = (const char *) buffer + 128;
++ len -= 128;
++ }
++ else
++#endif
++ {
++ sha512_process_block (buffer, len & ~127, ctx);
++ buffer = (const char *) buffer + (len & ~127);
++ len &= 127;
++ }
++ }
++
++ /* Move remaining bytes into internal buffer. */
++ if (len > 0)
++ {
++ size_t left_over = ctx->buflen;
++
++ memcpy (&ctx->buffer[left_over], buffer, len);
++ left_over += len;
++ if (left_over >= 128)
++ {
++ sha512_process_block (ctx->buffer, 128, ctx);
++ left_over -= 128;
++ memcpy (ctx->buffer, &ctx->buffer[128], left_over);
++ }
++ ctx->buflen = left_over;
++ }
++}
+--- libc/crypt/sha512.h 1 Jan 1970 00:00:00 -0000
++++ libc/crypt/sha512.h 19 Sep 2007 20:36:43 -0000 1.1
+@@ -0,0 +1,58 @@
++/* Declaration of functions and data types used for SHA512 sum computing
++ library functions.
++ Copyright (C) 2007 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#ifndef _SHA512_H
++#define _SHA512_H 1
++
++#include <limits.h>
++#include <stdint.h>
++#include <stdio.h>
++
++
++/* Structure to save state of computation between the single steps. */
++struct sha512_ctx
++{
++ uint64_t H[8];
++
++ uint64_t total[2];
++ uint64_t buflen;
++ char buffer[256] __attribute__ ((__aligned__ (__alignof__ (uint64_t))));
++};
++
++/* Initialize structure containing state of computation.
++ (FIPS 180-2: 5.3.3) */
++extern void __sha512_init_ctx (struct sha512_ctx *ctx) __THROW;
++
++/* Starting with the result of former calls of this function (or the
++ initialization function update the context for the next LEN bytes
++ starting at BUFFER.
++ It is NOT required that LEN is a multiple of 128. */
++extern void __sha512_process_bytes (const void *buffer, size_t len,
++ struct sha512_ctx *ctx) __THROW;
++
++/* Process the remaining bytes in the buffer and put result from CTX
++ in first 64 bytes following RESBUF.
++
++ IMPORTANT: On some systems it is required that RESBUF is correctly
++ aligned for a 64 bits value. */
++extern void *__sha512_finish_ctx (struct sha512_ctx *ctx, void *resbuf)
++ __THROW;
++
++#endif /* sha512.h */
+--- libc/crypt/sha512c-test.c 1 Jan 1970 00:00:00 -0000
++++ libc/crypt/sha512c-test.c 28 Oct 2007 19:46:43 -0000 1.2
+@@ -0,0 +1,63 @@
++#include <crypt.h>
++#include <stdio.h>
++#include <string.h>
++
++static const struct
++{
++ const char *salt;
++ const char *input;
++ const char *expected;
++} tests[] =
++{
++ { "$6$saltstring", "Hello world!",
++ "$6$saltstring$svn8UoSVapNtMuq1ukKS4tPQd8iKwSMHWjl/O817G3uBnIFNjnQJu"
++ "esI68u4OTLiBFdcbYEdFCoEOfaS35inz1" },
++ { "$6$rounds=10000$saltstringsaltstring", "Hello world!",
++ "$6$rounds=10000$saltstringsaltst$OW1/O6BYHV6BcXZu8QVeXbDWra3Oeqh0sb"
++ "HbbMCVNSnCM/UrjmM0Dp8vOuZeHBy/YTBmSK6H9qs/y3RnOaw5v." },
++ { "$6$rounds=5000$toolongsaltstring", "This is just a test",
++ "$6$rounds=5000$toolongsaltstrin$lQ8jolhgVRVhY4b5pZKaysCLi0QBxGoNeKQ"
++ "zQ3glMhwllF7oGDZxUhx1yxdYcz/e1JSbq3y6JMxxl8audkUEm0" },
++ { "$6$rounds=1400$anotherlongsaltstring",
++ "a very much longer text to encrypt. This one even stretches over more"
++ "than one line.",
++ "$6$rounds=1400$anotherlongsalts$POfYwTEok97VWcjxIiSOjiykti.o/pQs.wP"
++ "vMxQ6Fm7I6IoYN3CmLs66x9t0oSwbtEW7o7UmJEiDwGqd8p4ur1" },
++ { "$6$rounds=77777$short",
++ "we have a short salt string but not a short password",
++ "$6$rounds=77777$short$WuQyW2YR.hBNpjjRhpYD/ifIw05xdfeEyQoMxIXbkvr0g"
++ "ge1a1x3yRULJ5CCaUeOxFmtlcGZelFl5CxtgfiAc0" },
++ { "$6$rounds=123456$asaltof16chars..", "a short string",
++ "$6$rounds=123456$asaltof16chars..$BtCwjqMJGx5hrJhZywWvt0RLE8uZ4oPwc"
++ "elCjmw2kSYu.Ec6ycULevoBK25fs2xXgMNrCzIMVcgEJAstJeonj1" },
++ { "$6$rounds=10$roundstoolow", "the minimum number is still observed",
++ "$6$rounds=1000$roundstoolow$kUMsbe306n21p9R.FRkW3IGn.S9NPN0x50YhH1x"
++ "hLsPuWGsUSklZt58jaTfF4ZEQpyUNGc0dqbpBYYBaHHrsX." },
++};
++#define ntests (sizeof (tests) / sizeof (tests[0]))
++
++
++static int
++do_test (void)
++{
++ int result = 0;
++ int i;
++
++ for (i = 0; i < ntests; ++i)
++ {
++ char *cp = crypt (tests[i].input, tests[i].salt);
++
++ if (strcmp (cp, tests[i].expected) != 0)
++ {
++ printf ("test %d: expected \"%s\", got \"%s\"\n",
++ i, tests[i].expected, cp);
++ result = 1;
++ }
++ }
++
++ return result;
++}
++
++#define TIMEOUT 6
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- libc/crypt/sha512test.c 1 Jan 1970 00:00:00 -0000
++++ libc/crypt/sha512test.c 19 Sep 2007 20:37:02 -0000 1.1
+@@ -0,0 +1,113 @@
++#include <string.h>
++#include "sha512.h"
++
++static const struct
++{
++ const char *input;
++ const char result[64];
++} tests[] =
++ {
++ /* Test vectors from FIPS 180-2: appendix C.1. */
++ { "abc",
++ "\xdd\xaf\x35\xa1\x93\x61\x7a\xba\xcc\x41\x73\x49\xae\x20\x41\x31"
++ "\x12\xe6\xfa\x4e\x89\xa9\x7e\xa2\x0a\x9e\xee\xe6\x4b\x55\xd3\x9a"
++ "\x21\x92\x99\x2a\x27\x4f\xc1\xa8\x36\xba\x3c\x23\xa3\xfe\xeb\xbd"
++ "\x45\x4d\x44\x23\x64\x3c\xe8\x0e\x2a\x9a\xc9\x4f\xa5\x4c\xa4\x9f" },
++ /* Test vectors from FIPS 180-2: appendix C.2. */
++ { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
++ "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
++ "\x8e\x95\x9b\x75\xda\xe3\x13\xda\x8c\xf4\xf7\x28\x14\xfc\x14\x3f"
++ "\x8f\x77\x79\xc6\xeb\x9f\x7f\xa1\x72\x99\xae\xad\xb6\x88\x90\x18"
++ "\x50\x1d\x28\x9e\x49\x00\xf7\xe4\x33\x1b\x99\xde\xc4\xb5\x43\x3a"
++ "\xc7\xd3\x29\xee\xb6\xdd\x26\x54\x5e\x96\xe5\x5b\x87\x4b\xe9\x09" },
++ /* Test vectors from the NESSIE project. */
++ { "",
++ "\xcf\x83\xe1\x35\x7e\xef\xb8\xbd\xf1\x54\x28\x50\xd6\x6d\x80\x07"
++ "\xd6\x20\xe4\x05\x0b\x57\x15\xdc\x83\xf4\xa9\x21\xd3\x6c\xe9\xce"
++ "\x47\xd0\xd1\x3c\x5d\x85\xf2\xb0\xff\x83\x18\xd2\x87\x7e\xec\x2f"
++ "\x63\xb9\x31\xbd\x47\x41\x7a\x81\xa5\x38\x32\x7a\xf9\x27\xda\x3e" },
++ { "a",
++ "\x1f\x40\xfc\x92\xda\x24\x16\x94\x75\x09\x79\xee\x6c\xf5\x82\xf2"
++ "\xd5\xd7\xd2\x8e\x18\x33\x5d\xe0\x5a\xbc\x54\xd0\x56\x0e\x0f\x53"
++ "\x02\x86\x0c\x65\x2b\xf0\x8d\x56\x02\x52\xaa\x5e\x74\x21\x05\x46"
++ "\xf3\x69\xfb\xbb\xce\x8c\x12\xcf\xc7\x95\x7b\x26\x52\xfe\x9a\x75" },
++ { "message digest",
++ "\x10\x7d\xbf\x38\x9d\x9e\x9f\x71\xa3\xa9\x5f\x6c\x05\x5b\x92\x51"
++ "\xbc\x52\x68\xc2\xbe\x16\xd6\xc1\x34\x92\xea\x45\xb0\x19\x9f\x33"
++ "\x09\xe1\x64\x55\xab\x1e\x96\x11\x8e\x8a\x90\x5d\x55\x97\xb7\x20"
++ "\x38\xdd\xb3\x72\xa8\x98\x26\x04\x6d\xe6\x66\x87\xbb\x42\x0e\x7c" },
++ { "abcdefghijklmnopqrstuvwxyz",
++ "\x4d\xbf\xf8\x6c\xc2\xca\x1b\xae\x1e\x16\x46\x8a\x05\xcb\x98\x81"
++ "\xc9\x7f\x17\x53\xbc\xe3\x61\x90\x34\x89\x8f\xaa\x1a\xab\xe4\x29"
++ "\x95\x5a\x1b\xf8\xec\x48\x3d\x74\x21\xfe\x3c\x16\x46\x61\x3a\x59"
++ "\xed\x54\x41\xfb\x0f\x32\x13\x89\xf7\x7f\x48\xa8\x79\xc7\xb1\xf1" },
++ { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
++ "\x20\x4a\x8f\xc6\xdd\xa8\x2f\x0a\x0c\xed\x7b\xeb\x8e\x08\xa4\x16"
++ "\x57\xc1\x6e\xf4\x68\xb2\x28\xa8\x27\x9b\xe3\x31\xa7\x03\xc3\x35"
++ "\x96\xfd\x15\xc1\x3b\x1b\x07\xf9\xaa\x1d\x3b\xea\x57\x78\x9c\xa0"
++ "\x31\xad\x85\xc7\xa7\x1d\xd7\x03\x54\xec\x63\x12\x38\xca\x34\x45" },
++ { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
++ "\x1e\x07\xbe\x23\xc2\x6a\x86\xea\x37\xea\x81\x0c\x8e\xc7\x80\x93"
++ "\x52\x51\x5a\x97\x0e\x92\x53\xc2\x6f\x53\x6c\xfc\x7a\x99\x96\xc4"
++ "\x5c\x83\x70\x58\x3e\x0a\x78\xfa\x4a\x90\x04\x1d\x71\xa4\xce\xab"
++ "\x74\x23\xf1\x9c\x71\xb9\xd5\xa3\xe0\x12\x49\xf0\xbe\xbd\x58\x94" },
++ { "123456789012345678901234567890123456789012345678901234567890"
++ "12345678901234567890",
++ "\x72\xec\x1e\xf1\x12\x4a\x45\xb0\x47\xe8\xb7\xc7\x5a\x93\x21\x95"
++ "\x13\x5b\xb6\x1d\xe2\x4e\xc0\xd1\x91\x40\x42\x24\x6e\x0a\xec\x3a"
++ "\x23\x54\xe0\x93\xd7\x6f\x30\x48\xb4\x56\x76\x43\x46\x90\x0c\xb1"
++ "\x30\xd2\xa4\xfd\x5d\xd1\x6a\xbb\x5e\x30\xbc\xb8\x50\xde\xe8\x43" }
++ };
++
++
++int
++main (void)
++{
++ struct sha512_ctx ctx;
++ char sum[64];
++ int result = 0;
++ int cnt;
++
++ for (cnt = 0; cnt < (int) (sizeof (tests) / sizeof (tests[0])); ++cnt)
++ {
++ __sha512_init_ctx (&ctx);
++ __sha512_process_bytes (tests[cnt].input, strlen (tests[cnt].input),
++ &ctx);
++ __sha512_finish_ctx (&ctx, sum);
++ if (memcmp (tests[cnt].result, sum, 64) != 0)
++ {
++ printf ("test %d run %d failed\n", cnt, 1);
++ result = 1;
++ }
++
++ __sha512_init_ctx (&ctx);
++ for (int i = 0; tests[cnt].input[i] != '\0'; ++i)
++ __sha512_process_bytes (&tests[cnt].input[i], 1, &ctx);
++ __sha512_finish_ctx (&ctx, sum);
++ if (memcmp (tests[cnt].result, sum, 64) != 0)
++ {
++ printf ("test %d run %d failed\n", cnt, 2);
++ result = 1;
++ }
++ }
++
++ /* Test vector from FIPS 180-2: appendix C.3. */
++ char buf[1000];
++ memset (buf, 'a', sizeof (buf));
++ __sha512_init_ctx (&ctx);
++ for (int i = 0; i < 1000; ++i)
++ __sha512_process_bytes (buf, sizeof (buf), &ctx);
++ __sha512_finish_ctx (&ctx, sum);
++ static const char expected[64] =
++ "\xe7\x18\x48\x3d\x0c\xe7\x69\x64\x4e\x2e\x42\xc7\xbc\x15\xb4\x63"
++ "\x8e\x1f\x98\xb1\x3b\x20\x44\x28\x56\x32\xa8\x03\xaf\xa9\x73\xeb"
++ "\xde\x0f\xf2\x44\x87\x7e\xa6\x0a\x4c\xb0\x43\x2c\xe5\x77\xc3\x1b"
++ "\xeb\x00\x9c\x5c\x2c\x49\xaa\x2e\x4e\xad\xb2\x17\xad\x8c\xc0\x9b";
++ if (memcmp (expected, sum, 64) != 0)
++ {
++ printf ("test %d failed\n", cnt);
++ result = 1;
++ }
++
++ return result;
++}
--- /dev/null
+2007-04-25 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/unix/sysv/linux/check_pf.c (make_request): Return -1 instead
+ of 0 after the out_fail label.
+
+2007-03-18 Jakub Jelinek <jakub@redhat.com>
+
+ * nscd/gai.c: Include alloca.h.
+ (__libc_use_alloca): Define.
+
+2007-03-15 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/unix/sysv/linux/ifaddrs.c (__netlink_request): Never
+ reallocate the buffer, instead fail for MSG_TRUNC or for EBUSY
+ NLMSG_ERR. Instead use a page sized buffer.
+ * sysdeps/unix/sysv/linux/check_pf.c (make_request): Use page sized
+ buffer.
+
+2007-03-02 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/unix/sysv/linux/ifaddrs.c (__netlink_request): Retry with
+ a new netlink socket if NLMSG_ERR -EBUSY is seen after some MSG_TRUNC
+ message.
+
+2007-02-27 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/unix/sysv/linux/ifaddrs.c (__netlink_request): Fix
+ memory reallocation.
+
+--- libc/sysdeps/unix/sysv/linux/ifaddrs.c 19 May 2006 07:46:03 -0000 1.16
++++ libc/sysdeps/unix/sysv/linux/ifaddrs.c 15 Mar 2007 20:02:11 -0000 1.19
+@@ -122,36 +122,36 @@ int
+ __netlink_request (struct netlink_handle *h, int type)
+ {
+ struct netlink_res *nlm_next;
+- struct netlink_res **new_nlm_list;
+- static volatile size_t buf_size = 4096;
+- char *buf;
+ struct sockaddr_nl nladdr;
+ struct nlmsghdr *nlmh;
+ ssize_t read_len;
+ bool done = false;
+- bool use_malloc = false;
+
+- if (__netlink_sendreq (h, type) < 0)
+- return -1;
++#ifdef PAGE_SIZE
++ /* Help the compiler optimize out the malloc call if PAGE_SIZE
++ is constant and smaller or equal to PTHREAD_STACK_MIN/4. */
++ const size_t buf_size = PAGE_SIZE;
++#else
++ const size_t buf_size = __getpagesize ();
++#endif
++ bool use_malloc = false;
++ char *buf;
+
+- size_t this_buf_size = buf_size;
+- if (__libc_use_alloca (this_buf_size))
+- buf = alloca (this_buf_size);
++ if (__libc_use_alloca (buf_size))
++ buf = alloca (buf_size);
+ else
+ {
+- buf = malloc (this_buf_size);
++ buf = malloc (buf_size);
+ if (buf != NULL)
+ use_malloc = true;
+ else
+ goto out_fail;
+ }
+
+- struct iovec iov = { buf, this_buf_size };
++ struct iovec iov = { buf, buf_size };
+
+- if (h->nlm_list != NULL)
+- new_nlm_list = &h->end_ptr->next;
+- else
+- new_nlm_list = &h->nlm_list;
++ if (__netlink_sendreq (h, type) < 0)
++ goto out_fail;
+
+ while (! done)
+ {
+@@ -171,48 +171,7 @@ __netlink_request (struct netlink_handle
+ continue;
+
+ if (__builtin_expect (msg.msg_flags & MSG_TRUNC, 0))
+- {
+- if (this_buf_size >= SIZE_MAX / 2)
+- goto out_fail;
+-
+- nlm_next = *new_nlm_list;
+- while (nlm_next != NULL)
+- {
+- struct netlink_res *tmpptr;
+-
+- tmpptr = nlm_next->next;
+- free (nlm_next);
+- nlm_next = tmpptr;
+- }
+- *new_nlm_list = NULL;
+-
+- if (__libc_use_alloca (2 * this_buf_size))
+- buf = extend_alloca (buf, this_buf_size, 2 * this_buf_size);
+- else
+- {
+- this_buf_size *= 2;
+-
+- char *new_buf = realloc (use_malloc ? buf : NULL, this_buf_size);
+- if (new_buf == NULL)
+- goto out_fail;
+- new_buf = buf;
+-
+- use_malloc = true;
+- }
+- buf_size = this_buf_size;
+-
+- iov.iov_base = buf;
+- iov.iov_len = this_buf_size;
+-
+- /* Increase sequence number, so that we can distinguish
+- between old and new request messages. */
+- h->seq++;
+-
+- if (__netlink_sendreq (h, type) < 0)
+- goto out_fail;
+-
+- continue;
+- }
++ goto out_fail;
+
+ size_t count = 0;
+ size_t remaining_len = read_len;
+--- libc/sysdeps/unix/sysv/linux/check_pf.c 24 Sep 2006 16:50:22 -0000 1.8
++++ libc/sysdeps/unix/sysv/linux/check_pf.c 25 Apr 2007 16:05:18 -0000 1.10
+@@ -17,6 +17,7 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
++#include <alloca.h>
+ #include <errno.h>
+ #include <ifaddrs.h>
+ #include <netdb.h>
+@@ -52,17 +53,38 @@ make_request (int fd, pid_t pid, bool *s
+ memset (&nladdr, '\0', sizeof (nladdr));
+ nladdr.nl_family = AF_NETLINK;
+
++#ifdef PAGE_SIZE
++ /* Help the compiler optimize out the malloc call if PAGE_SIZE
++ is constant and smaller or equal to PTHREAD_STACK_MIN/4. */
++ const size_t buf_size = PAGE_SIZE;
++#else
++ const size_t buf_size = __getpagesize ();
++#endif
++ bool use_malloc = false;
++ char *buf;
++
++ if (__libc_use_alloca (buf_size))
++ buf = alloca (buf_size);
++ else
++ {
++ buf = malloc (buf_size);
++ if (buf != NULL)
++ use_malloc = true;
++ else
++ goto out_fail;
++ }
++
++ struct iovec iov = { buf, buf_size };
++
+ if (TEMP_FAILURE_RETRY (__sendto (fd, (void *) &req, sizeof (req), 0,
+ (struct sockaddr *) &nladdr,
+ sizeof (nladdr))) < 0)
+- return -1;
++ goto out_fail;
+
+ *seen_ipv4 = false;
+ *seen_ipv6 = false;
+
+ bool done = false;
+- char buf[4096];
+- struct iovec iov = { buf, sizeof (buf) };
+
+ do
+ {
+@@ -76,10 +98,10 @@ make_request (int fd, pid_t pid, bool *s
+
+ ssize_t read_len = TEMP_FAILURE_RETRY (__recvmsg (fd, &msg, 0));
+ if (read_len < 0)
+- return -1;
++ goto out_fail;
+
+ if (msg.msg_flags & MSG_TRUNC)
+- return -1;
++ goto out_fail;
+
+ struct nlmsghdr *nlmh;
+ for (nlmh = (struct nlmsghdr *) buf;
+@@ -117,7 +139,14 @@ make_request (int fd, pid_t pid, bool *s
+
+ __close (fd);
+
++ if (use_malloc)
++ free (buf);
+ return 0;
++
++out_fail:
++ if (use_malloc)
++ free (buf);
++ return -1;
+ }
+
+
+--- libc/nscd/gai.c 14 Jan 2007 05:23:23 -0000 1.5
++++ libc/nscd/gai.c 18 Mar 2007 17:55:48 -0000 1.6
+@@ -1,3 +1,4 @@
++#include <alloca.h>
+ /* This file uses the getaddrinfo code but it compiles it without NSCD
+ support. We just need a few symbol renames. */
+ #define __getservbyname_r getservbyname_r
+@@ -8,6 +9,8 @@
+ #define __bind bind
+ #define __sendto sendto
+ #define __strchrnul strchrnul
++/* nscd uses 1MB or 2MB thread stacks. */
++#define __libc_use_alloca(size) (size <= __MAX_ALLOCA_CUTOFF)
+
+ #include <getaddrinfo.c>
+
--- /dev/null
+2007-02-25 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/unix/sysv/linux/fork.c (__libc_fork): Reset refcntr in
+ new thread, don't just decrement it.
+ Patch by Suzuki K P <suzuki@in.ibm.com>.
+
+--- libc/nptl/sysdeps/unix/sysv/linux/fork.c 20 Dec 2003 23:37:13 -0000 1.11
++++ libc/nptl/sysdeps/unix/sysv/linux/fork.c 25 Feb 2007 21:43:28 -0000 1.12
+@@ -167,8 +167,11 @@ __libc_fork (void)
+ allp->handler->child_handler ();
+
+ /* Note that we do not have to wake any possible waiter.
+- This is the only thread in the new process. */
+- --allp->handler->refcntr;
++ This is the only thread in the new process. The count
++ may have been bumped up by other threads doing a fork.
++ We reset it to 1, to avoid waiting for non-existing
++ thread(s) to release the count. */
++ allp->handler->refcntr = 1;
+
+ /* XXX We could at this point look through the object pool
+ and mark all objects not on the __fork_handlers list as
--- /dev/null
+2007-04-05 Jakub Jelinek <jakub@redhat.com>
+
+ * nis/nis_call.c (__nisfind_server): Replace (*dir)->do_servers
+ with obj->do_servers after first_shoot.
+
+2007-03-01 Jakub Jelinek <jakub@redhat.com>
+
+ * nis/nis_call.c: Include bits/libc-lock.h, sys/stat.h, unistd.h.
+ (nis_server_cache, nis_server_cache_lock, nis_cold_start_mtime): New
+ variables.
+ (nis_server_cache_search, nis_server_cache_add): New functions.
+ (__nisfind_server): Use them. Add dbp and flags argument, if
+ call __nisbind_create.
+ (__nisbind_create): Add server_used and current_ep arguments,
+ only call __nis_findfastest if server_used is ~0.
+ (__do_niscall2, __prepare_niscall): Adjust callers.
+ (ckey_cache, ckey_cache_size, ckey_cache_allocated, ckey_cache_pid,
+ ckey_cache_euid, ckey_cache_lock): New variables.
+ (get_ckey): New function.
+ (__nisbind_connect): If not dbp->use_udp, pass IPPROTO_TCP to
+ __pmap_getnisport. Save __pmap_getnisport result in
+ dbp->addr.sin_port if non-zero. Use get_ckey to create conversation
+ key.
+ * nis/nis_lookup.c (nis_lookup): Likewise.
+ * nis/nis_table.c (nis_list): Likewise.
+ * nis/rpcsvc/nislib.h (__nisbind_create, __nisfind_server): Adjust
+ prototypes.
+
+ * nis/nss_nisplus/nisplus-pwd.c (_nss_nisplus_getpwnam_r,
+ _nss_nisplus_getpwuid_r): Pass USE_DGRAM flag to nis_list.
+ * nis/nss_nisplus/nisplus-service.c (_nss_nisplus_getservbyname_r,
+ _nss_nisplus_getservbyport_r): Likewise.
+ * nis/nss_nisplus/nisplus-network.c (_nss_nisplus_getnetbyname_r,
+ _nss_nisplus_getnetbyaddr_r): Likewise.
+ * nis/nss_nisplus/nisplus-spwd.c (_nss_nisplus_getspnam_r): Likewise.
+ * nis/nss_nisplus/nisplus-ethers.c (_nss_nisplus_gethostton_r,
+ _nss_nisplus_getntohost_r): Likewise.
+ * nis/nss_nisplus/nisplus-rpc.c (_nss_nisplus_getrpcbyname_r,
+ _nss_nisplus_getrpcbynumber_r): Likewise.
+
+--- libc/nis/nss_nisplus/nisplus-pwd.c.jj 2006-05-20 21:20:19.000000000 +0200
++++ libc/nis/nss_nisplus/nisplus-pwd.c 2007-03-01 13:45:32.000000000 +0100
+@@ -311,7 +311,7 @@ _nss_nisplus_getpwnam_r (const char *nam
+
+ snprintf (buf, sizeof (buf), "[name=%s],%s", name, pwd_tablename_val);
+
+- result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++ result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, NULL, NULL);
+
+ if (result == NULL)
+ {
+@@ -370,7 +370,7 @@ _nss_nisplus_getpwuid_r (const uid_t uid
+ snprintf (buf, sizeof (buf), "[uid=%lu],%s",
+ (unsigned long int) uid, pwd_tablename_val);
+
+- result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++ result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, NULL, NULL);
+
+ if (result == NULL)
+ {
+--- libc/nis/nss_nisplus/nisplus-service.c.jj 2006-04-30 07:44:23.000000000 +0200
++++ libc/nis/nss_nisplus/nisplus-service.c 2007-03-01 13:45:32.000000000 +0100
+@@ -322,7 +322,8 @@ _nss_nisplus_getservbyname_r (const char
+ for the next search */
+ snprintf (buf, sizeof (buf), "[name=%s,proto=%s],%s", name, protocol,
+ tablename_val);
+- nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++ nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM,
++ NULL, NULL);
+
+ if (result != NULL)
+ {
+@@ -351,7 +352,8 @@ _nss_nisplus_getservbyname_r (const char
+ }
+
+ nis_freeresult (result);
+- result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++ result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM,
++ NULL, NULL);
+ }
+
+ if (result == NULL)
+@@ -420,7 +422,8 @@ _nss_nisplus_getservbyport_r (const int
+ snprintf (buf, sizeof (buf), "[port=%d,proto=%s],%s",
+ number, protocol, tablename_val);
+
+- nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++ nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM,
++ NULL, NULL);
+
+ if (result == NULL)
+ {
+--- libc/nis/nss_nisplus/nisplus-network.c.jj 2006-04-30 07:44:23.000000000 +0200
++++ libc/nis/nss_nisplus/nisplus-network.c 2007-03-01 13:45:32.000000000 +0100
+@@ -338,7 +339,7 @@ _nss_nisplus_getnetbyname_r (const char
+ /* Search at first in the alias list, and use the correct name
+ for the next search */
+ snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
+- result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
++ result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH | USE_DGRAM, NULL, NULL);
+
+ if (result != NULL)
+ {
+@@ -366,7 +367,8 @@ _nss_nisplus_getnetbyname_r (const char
+ }
+
+ nis_freeresult (result);
+- result = nis_list (bufptr, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
++ result = nis_list (bufptr, FOLLOW_LINKS | FOLLOW_PATH | USE_DGRAM,
++ NULL, NULL);
+ }
+
+ if (result == NULL)
+@@ -438,7 +440,8 @@ _nss_nisplus_getnetbyaddr_r (uint32_t ad
+ while (1)
+ {
+ snprintf (buf, sizeof (buf), "[addr=%s],%s", buf2, tablename_val);
+- nis_result *result = nis_list (buf, EXPAND_NAME, NULL, NULL);
++ nis_result *result = nis_list (buf, EXPAND_NAME | USE_DGRAM,
++ NULL, NULL);
+
+ if (result == NULL)
+ {
+--- libc/nis/nss_nisplus/nisplus-spwd.c.jj 2006-04-30 07:44:23.000000000 +0200
++++ libc/nis/nss_nisplus/nisplus-spwd.c 2007-03-01 13:45:32.000000000 +0100
+@@ -182,7 +183,7 @@ _nss_nisplus_getspnam_r (const char *nam
+
+ snprintf (buf, sizeof (buf), "[name=%s],%s", name, pwd_tablename_val);
+
+- result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++ result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM, NULL, NULL);
+
+ if (result == NULL)
+ {
+--- libc/nis/nss_nisplus/nisplus-ethers.c.jj 2006-04-30 07:44:23.000000000 +0200
++++ libc/nis/nss_nisplus/nisplus-ethers.c 2007-03-01 13:45:32.000000000 +0100
+@@ -256,7 +257,8 @@ _nss_nisplus_gethostton_r (const char *n
+
+ snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
+
+- nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++ nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM,
++ NULL, NULL);
+
+ if (result == NULL)
+ {
+@@ -322,7 +324,8 @@ _nss_nisplus_getntohost_r (const struct
+ addr->ether_addr_octet[4], addr->ether_addr_octet[5],
+ tablename_val);
+
+- nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++ nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM,
++ NULL, NULL);
+
+ if (result == NULL)
+ {
+--- libc/nis/nss_nisplus/nisplus-rpc.c.jj 2006-04-30 07:44:23.000000000 +0200
++++ libc/nis/nss_nisplus/nisplus-rpc.c 2007-03-01 13:45:32.000000000 +0100
+@@ -315,7 +315,8 @@ _nss_nisplus_getrpcbyname_r (const char
+ /* Search at first in the alias list, and use the correct name
+ for the next search */
+ snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
+- nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
++ nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM,
++ NULL, NULL);
+
+ if (result != NULL)
+ {
+@@ -342,7 +343,8 @@ _nss_nisplus_getrpcbyname_r (const char
+ }
+
+ nis_freeresult (result);
+- result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS , NULL, NULL);
++ result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS | USE_DGRAM,
++ NULL, NULL);
+ }
+
+ if (result == NULL)
+@@ -402,7 +404,8 @@ _nss_nisplus_getrpcbynumber_r (const int
+
+ snprintf (buf, sizeof (buf), "[number=%d],%s", number, tablename_val);
+
+- nis_result *result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
++ nis_result *result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH | USE_DGRAM,
++ NULL, NULL);
+
+ if (result == NULL)
+ {
+--- libc/nis/nis_lookup.c.jj 2006-08-07 18:02:48.000000000 +0200
++++ libc/nis/nis_lookup.c 2007-03-01 13:45:32.000000000 +0100
+@@ -127,18 +128,10 @@ nis_lookup (const_nis_name name, const u
+ /* Otherwise __nisfind_server will not do anything. */
+ dir = NULL;
+
+- if (__nisfind_server (req.ns_name, 1, &dir)
++ if (__nisfind_server (req.ns_name, 1, &dir, &bptr,
++ flags & ~MASTER_ONLY)
+ != NIS_SUCCESS)
+ goto out;
+-
+- if (__nisbind_create (&bptr,
+- dir->do_servers.do_servers_val,
+- dir->do_servers.do_servers_len,
+- flags) != NIS_SUCCESS)
+- {
+- nis_free_directory (dir);
+- goto out;
+- }
+ }
+ else
+ if (__nisbind_next (&bptr) != NIS_SUCCESS)
+--- libc/nis/nis_call.c.jj 2006-08-07 19:39:39.000000000 +0200
++++ libc/nis/nis_call.c 2007-03-01 15:23:07.000000000 +0100
+@@ -25,8 +26,11 @@
+ #include <rpc/auth.h>
+ #include <rpcsvc/nis.h>
+ #include <sys/socket.h>
++#include <sys/stat.h>
++#include <unistd.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
++#include <bits/libc-lock.h>
+
+ #include "nis_xdr.h"
+ #include "nis_intern.h"
+@@ -107,10 +111,79 @@ __nisbind_next (dir_binding *bind)
+ }
+ libnsl_hidden_def (__nisbind_next)
+
++static struct ckey_cache_entry
++{
++ struct in_addr inaddr;
++ in_port_t port;
++ unsigned int protocol;
++ des_block ckey;
++} *ckey_cache;
++static size_t ckey_cache_size;
++static size_t ckey_cache_allocated;
++static pid_t ckey_cache_pid;
++static uid_t ckey_cache_euid;
++__libc_lock_define_initialized (static, ckey_cache_lock)
++
++static bool_t
++get_ckey (des_block *ckey, struct sockaddr_in *addr, unsigned int protocol)
++{
++ size_t i;
++ pid_t pid = getpid ();
++ uid_t euid = geteuid ();
++ bool_t ret = FALSE;
++
++ __libc_lock_lock (ckey_cache_lock);
++
++ if (ckey_cache_pid != pid || ckey_cache_euid != euid)
++ {
++ ckey_cache_size = 0;
++ ckey_cache_pid = pid;
++ ckey_cache_euid = euid;
++ }
++
++ for (i = 0; i < ckey_cache_size; ++i)
++ if (ckey_cache[i].port == addr->sin_port
++ && ckey_cache[i].protocol == protocol
++ && memcmp (&ckey_cache[i].inaddr, &addr->sin_addr,
++ sizeof (addr->sin_addr)) == 0)
++ {
++ *ckey = ckey_cache[i].ckey;
++ ret = TRUE;
++ break;
++ }
++
++ if (!ret && key_gendes (ckey) >= 0)
++ {
++ ret = TRUE;
++ /* Don't grow the cache indefinitely. */
++ if (ckey_cache_size == 256)
++ ckey_cache_size = 0;
++ if (ckey_cache_size == ckey_cache_allocated)
++ {
++ size_t size = ckey_cache_allocated ? ckey_cache_allocated * 2 : 16;
++ struct ckey_cache_entry *new_cache
++ = realloc (ckey_cache, size * sizeof (*ckey_cache));
++ if (new_cache != NULL)
++ {
++ ckey_cache = new_cache;
++ ckey_cache_allocated = size;
++ }
++ }
++ ckey_cache[ckey_cache_size].inaddr = addr->sin_addr;
++ ckey_cache[ckey_cache_size].port = addr->sin_port;
++ ckey_cache[ckey_cache_size].protocol = protocol;
++ ckey_cache[ckey_cache_size++].ckey = *ckey;
++ }
++
++ __libc_lock_unlock (ckey_cache_lock);
++ return ret;
++}
++
+ nis_error
+ __nisbind_connect (dir_binding *dbp)
+ {
+ nis_server *serv;
++ u_short port;
+
+ if (dbp == NULL)
+ return NIS_FAIL;
+@@ -128,9 +202,12 @@ __nisbind_connect (dir_binding *dbp)
+
+ /* Check, if the host is online and rpc.nisd is running. Much faster
+ then the clnt*_create functions: */
+- if (__pmap_getnisport (&dbp->addr, NIS_PROG, NIS_VERSION, IPPROTO_UDP) == 0)
++ port = __pmap_getnisport (&dbp->addr, NIS_PROG, NIS_VERSION,
++ dbp->use_udp ? IPPROTO_UDP : IPPROTO_TCP);
++ if (port == 0)
+ return NIS_RPCERROR;
+
++ dbp->addr.sin_port = htons (port);
+ dbp->socket = RPC_ANYSOCK;
+ if (dbp->use_udp)
+ dbp->clnt = clntudp_create (&dbp->addr, NIS_PROG, NIS_VERSION,
+@@ -153,17 +230,16 @@ __nisbind_connect (dir_binding *dbp)
+ {
+ char netname[MAXNETNAMELEN + 1];
+ char *p;
++ des_block ckey;
+
+- p = stpcpy (netname, "unix.");
++ p = stpcpy (netname, "unix@");
+ strncpy (p, serv->name, MAXNETNAMELEN - 5);
+ netname[MAXNETNAMELEN] = '\0';
+- // XXX What is this supposed to do? If we really want to replace
+- // XXX the first dot, then we might as well use unix@ as the
+- // XXX prefix string. --drepper
+- p = strchr (netname, '.');
+- *p = '@';
+- dbp->clnt->cl_auth =
+- authdes_pk_create (netname, &serv->pkey, 300, NULL, NULL);
++ dbp->clnt->cl_auth = NULL;
++ if (get_ckey (&ckey, &dbp->addr,
++ dbp->use_udp ? IPPROTO_UDP : IPPROTO_TCP))
++ dbp->clnt->cl_auth =
++ authdes_pk_create (netname, &serv->pkey, 300, NULL, &ckey);
+ if (!dbp->clnt->cl_auth)
+ dbp->clnt->cl_auth = authunix_create_default ();
+ }
+@@ -177,7 +253,8 @@ libnsl_hidden_def (__nisbind_connect)
+
+ nis_error
+ __nisbind_create (dir_binding *dbp, const nis_server *serv_val,
+- unsigned int serv_len, unsigned int flags)
++ unsigned int serv_len, unsigned int server_used,
++ unsigned int current_ep, unsigned int flags)
+ {
+ dbp->clnt = NULL;
+
+@@ -203,8 +280,16 @@ __nisbind_create (dir_binding *dbp, cons
+ dbp->trys = 1;
+
+ dbp->class = -1;
+- if (__nis_findfastest (dbp) < 1)
+- return NIS_NAMEUNREACHABLE;
++ if (server_used == ~0)
++ {
++ if (__nis_findfastest (dbp) < 1)
++ return NIS_NAMEUNREACHABLE;
++ }
++ else
++ {
++ dbp->server_used = server_used;
++ dbp->current_ep = current_ep;
++ }
+
+ return NIS_SUCCESS;
+ }
+@@ -306,7 +391,7 @@ __do_niscall2 (const nis_server *server,
+ if (flags & MASTER_ONLY)
+ server_len = 1;
+
+- status = __nisbind_create (&dbp, server, server_len, flags);
++ status = __nisbind_create (&dbp, server, server_len, ~0, ~0, flags);
+ if (status != NIS_SUCCESS)
+ return status;
+
+@@ -499,42 +584,221 @@ first_shoot (const_nis_name name, int se
+ return obj;
+ }
+
++static struct nis_server_cache
++{
++ int search_parent_first;
++ int uses;
++ unsigned int size;
++ unsigned int server_used;
++ unsigned int current_ep;
++ time_t expires;
++ char name[];
++} *nis_server_cache[16];
++static time_t nis_cold_start_mtime;
++__libc_lock_define_initialized (static, nis_server_cache_lock)
++
++static directory_obj *
++nis_server_cache_search (const_nis_name name, int search_parent_first,
++ unsigned int *server_used, unsigned int *current_ep,
++ struct timeval *now)
++{
++ directory_obj *ret = NULL;
++ int i;
++ char *addr;
++ XDR xdrs;
++ struct stat64 st;
++
++ if (stat64 ("/var/nis/NIS_COLD_START", &st) < 0)
++ st.st_mtime = nis_cold_start_mtime + 1;
++
++ __libc_lock_lock (nis_server_cache_lock);
++
++ for (i = 0; i < 16; ++i)
++ if (nis_server_cache[i] == NULL)
++ continue;
++ else if (st.st_mtime != nis_cold_start_mtime
++ || now->tv_sec > nis_server_cache[i]->expires)
++ {
++ free (nis_server_cache[i]);
++ nis_server_cache[i] = NULL;
++ }
++ else if (nis_server_cache[i]->search_parent_first == search_parent_first
++ && strcmp (nis_server_cache[i]->name, name) == 0)
++ {
++ ret = calloc (1, sizeof (directory_obj));
++ if (ret == NULL)
++ break;
++
++ addr = rawmemchr (nis_server_cache[i]->name, '\0') + 8;
++ addr = (char *) ((uintptr_t) addr & ~(uintptr_t) 7);
++ xdrmem_create (&xdrs, addr, nis_server_cache[i]->size, XDR_DECODE);
++ if (!_xdr_directory_obj (&xdrs, ret))
++ {
++ xdr_destroy (&xdrs);
++ free (ret);
++ ret = NULL;
++ free (nis_server_cache[i]);
++ nis_server_cache[i] = NULL;
++ break;
++ }
++ xdr_destroy (&xdrs);
++ *server_used = nis_server_cache[i]->server_used;
++ *current_ep = nis_server_cache[i]->current_ep;
++ break;
++ }
++
++ nis_cold_start_mtime = st.st_mtime;
++
++ __libc_lock_unlock (nis_server_cache_lock);
++ return ret;
++}
++
++static void
++nis_server_cache_add (const_nis_name name, int search_parent_first,
++ directory_obj *dir, unsigned int server_used,
++ unsigned int current_ep, struct timeval *now)
++{
++ struct nis_server_cache **loc;
++ struct nis_server_cache *new;
++ struct nis_server_cache *old;
++ int i;
++ char *addr;
++ unsigned int size;
++ XDR xdrs;
++
++ if (dir == NULL)
++ return;
++
++ size = xdr_sizeof ((xdrproc_t) _xdr_directory_obj, (char *) dir);
++ new = calloc (1, sizeof (*new) + strlen (name) + 8 + size);
++ if (new == NULL)
++ return;
++ new->search_parent_first = search_parent_first;
++ new->uses = 1;
++ new->expires = now->tv_sec + dir->do_ttl;
++ new->size = size;
++ new->server_used = server_used;
++ new->current_ep = current_ep;
++ addr = stpcpy (new->name, name) + 8;
++ addr = (char *) ((uintptr_t) addr & ~(uintptr_t) 7);
++
++ xdrmem_create(&xdrs, addr, size, XDR_ENCODE);
++ if (!_xdr_directory_obj (&xdrs, dir))
++ {
++ xdr_destroy (&xdrs);
++ free (new);
++ return;
++ }
++ xdr_destroy (&xdrs);
++
++ __libc_lock_lock (nis_server_cache_lock);
++
++ /* Choose which entry should be evicted from the cache. */
++ loc = &nis_server_cache[0];
++ if (*loc != NULL)
++ for (i = 1; i < 16; ++i)
++ if (nis_server_cache[i] == NULL)
++ {
++ loc = &nis_server_cache[i];
++ break;
++ }
++ else if ((*loc)->uses > nis_server_cache[i]->uses
++ || ((*loc)->uses == nis_server_cache[i]->uses
++ && (*loc)->expires > nis_server_cache[i]->expires))
++ loc = &nis_server_cache[i];
++ old = *loc;
++ *loc = new;
++
++ __libc_lock_unlock (nis_server_cache_lock);
++ free (old);
++}
++
+ nis_error
+ __nisfind_server (const_nis_name name, int search_parent_first,
+- directory_obj **dir)
++ directory_obj **dir, dir_binding *dbp, unsigned int flags)
+ {
++ nis_error result = NIS_SUCCESS;
++ nis_error status;
++ directory_obj *obj;
++ struct timeval now;
++ unsigned int server_used = ~0;
++ unsigned int current_ep = ~0;
++
+ if (name == NULL)
+ return NIS_BADNAME;
+
+-#if 0
+- /* Search in local cache. In the moment, we ignore the fastest server */
+- if (!(flags & NO_CACHE))
+- dir = __nis_cache_search (name, flags, &cinfo);
+-#endif
++ if (*dir != NULL)
++ return NIS_SUCCESS;
+
+- nis_error result = NIS_SUCCESS;
+- if (*dir == NULL)
++ (void) gettimeofday (&now, NULL);
++
++ if ((flags & NO_CACHE) == 0)
++ *dir = nis_server_cache_search (name, search_parent_first, &server_used,
++ ¤t_ep, &now);
++ if (*dir != NULL)
+ {
+- nis_error status;
+- directory_obj *obj;
++ unsigned int server_len = (*dir)->do_servers.do_servers_len;
++ if (flags & MASTER_ONLY)
++ {
++ server_len = 1;
++ if (server_used != 0)
++ {
++ server_used = ~0;
++ current_ep = ~0;
++ }
++ }
++ result = __nisbind_create (dbp, (*dir)->do_servers.do_servers_val,
++ server_len, server_used, current_ep, flags);
++ if (result != NIS_SUCCESS)
++ {
++ nis_free_directory (*dir);
++ *dir = NULL;
++ }
++ return result;
++ }
+
+- *dir = readColdStartFile ();
+- if (*dir == NULL)
+- /* No /var/nis/NIS_COLD_START->no NIS+ installed. */
+- return NIS_UNAVAIL;
++ *dir = readColdStartFile ();
++ if (*dir == NULL)
++ /* No /var/nis/NIS_COLD_START->no NIS+ installed. */
++ return NIS_UNAVAIL;
+
+- /* Try at first, if servers in "dir" know our object */
+- obj = first_shoot (name, search_parent_first, *dir);
++ /* Try at first, if servers in "dir" know our object */
++ obj = first_shoot (name, search_parent_first, *dir);
++ if (obj == NULL)
++ {
++ obj = rec_dirsearch (name, *dir, &status);
+ if (obj == NULL)
++ result = status;
++ }
++
++ if (result == NIS_SUCCESS)
++ {
++ unsigned int server_len = obj->do_servers.do_servers_len;
++ if (flags & MASTER_ONLY)
++ server_len = 1;
++ result = __nisbind_create (dbp, obj->do_servers.do_servers_val,
++ server_len, ~0, ~0, flags);
++ if (result == NIS_SUCCESS)
+ {
+- obj = rec_dirsearch (name, *dir, &status);
+- if (obj == NULL)
+- result = status;
++ if ((flags & MASTER_ONLY) == 0
++ || obj->do_servers.do_servers_len == 1)
++ {
++ server_used = dbp->server_used;
++ current_ep = dbp->current_ep;
++ }
++ if ((flags & NO_CACHE) == 0)
++ nis_server_cache_add (name, search_parent_first, obj,
++ server_used, current_ep, &now);
++ }
++ else
++ {
++ nis_free_directory (obj);
++ obj = NULL;
+ }
+-
+- *dir = obj;
+ }
+
++ *dir = obj;
++
+ return result;
+ }
+
+@@ -543,38 +807,19 @@ nis_error
+ __prepare_niscall (const_nis_name name, directory_obj **dirp,
+ dir_binding *bptrp, unsigned int flags)
+ {
+- nis_error retcode = __nisfind_server (name, 1, dirp);
++ nis_error retcode = __nisfind_server (name, 1, dirp, bptrp, flags);
+ if (__builtin_expect (retcode != NIS_SUCCESS, 0))
+ return retcode;
+
+- nis_server *server;
+- u_int server_len;
+-
+- if (flags & MASTER_ONLY)
+- {
+- server = (*dirp)->do_servers.do_servers_val;
+- server_len = 1;
+- }
+- else
+- {
+- server = (*dirp)->do_servers.do_servers_val;
+- server_len = (*dirp)->do_servers.do_servers_len;
+- }
+-
+- retcode = __nisbind_create (bptrp, server, server_len, flags);
+- if (retcode == NIS_SUCCESS)
+- {
+- do
+- if (__nisbind_connect (bptrp) == NIS_SUCCESS)
+- return NIS_SUCCESS;
+- while (__nisbind_next (bptrp) == NIS_SUCCESS);
+-
+- __nisbind_destroy (bptrp);
+- memset (bptrp, '\0', sizeof (*bptrp));
++ do
++ if (__nisbind_connect (bptrp) == NIS_SUCCESS)
++ return NIS_SUCCESS;
++ while (__nisbind_next (bptrp) == NIS_SUCCESS);
+
+- retcode = NIS_NAMEUNREACHABLE;
+- }
++ __nisbind_destroy (bptrp);
++ memset (bptrp, '\0', sizeof (*bptrp));
+
++ retcode = NIS_NAMEUNREACHABLE;
+ nis_free_directory (*dirp);
+ *dirp = NULL;
+
+--- libc/nis/nis_table.c.jj 2006-10-09 09:46:37.000000000 +0200
++++ libc/nis/nis_table.c 2007-03-01 13:45:32.000000000 +0100
+@@ -274,21 +275,14 @@ nis_list (const_nis_name name, unsigned
+ memset (res, '\0', sizeof (nis_result));
+
+ status = __nisfind_server (ibreq->ibr_name,
+- ibreq->ibr_srch.ibr_srch_val != NULL, &dir);
++ ibreq->ibr_srch.ibr_srch_val != NULL,
++ &dir, &bptr, flags & ~MASTER_ONLY);
+ if (status != NIS_SUCCESS)
+ {
+ NIS_RES_STATUS (res) = status;
+ goto fail3;
+ }
+
+- status = __nisbind_create (&bptr, dir->do_servers.do_servers_val,
+- dir->do_servers.do_servers_len, flags);
+- if (__builtin_expect (status != NIS_SUCCESS, 0))
+- {
+- NIS_RES_STATUS (res) = status;
+- goto fail2;
+- }
+-
+ while (__nisbind_connect (&bptr) != NIS_SUCCESS)
+ if (__builtin_expect (__nisbind_next (&bptr) != NIS_SUCCESS, 0))
+ {
+@@ -338,7 +332,6 @@ nis_list (const_nis_name name, unsigned
+ NIS_RES_STATUS (res) = NIS_NOMEMORY;
+ fail:
+ __nisbind_destroy (&bptr);
+- fail2:
+ nis_free_directory (dir);
+ fail3:
+ free (tablepath);
+--- libc/nis/rpcsvc/nislib.h.jj 2006-08-07 18:01:48.000000000 +0200
++++ libc/nis/rpcsvc/nislib.h 2007-03-01 13:45:32.000000000 +0100
+@@ -272,12 +272,13 @@ struct dir_binding
+ typedef struct dir_binding dir_binding;
+
+ extern nis_error __nisbind_create (dir_binding *, const nis_server *,
+- unsigned int, unsigned int) __THROW;
++ unsigned int, unsigned int, unsigned int,
++ unsigned int) __THROW;
+ extern nis_error __nisbind_connect (dir_binding *) __THROW;
+ extern nis_error __nisbind_next (dir_binding *) __THROW;
+ extern void __nisbind_destroy (dir_binding *) __THROW;
+-extern nis_error __nisfind_server (const_nis_name, int, directory_obj **)
+- __THROW;
++extern nis_error __nisfind_server (const_nis_name, int, directory_obj **,
++ dir_binding *, unsigned int) __THROW;
+
+ #endif
+
--- /dev/null
+2007-04-06 Jakub Jelinek <jakub@redhat.com>
+
+ * nis/nis_domain_of.c (__nis_domain_of): New function.
+ * include/rpcsvc/nislib.h (__nis_domain_of): New prototype.
+ * nis/nis_lookup.c (nis_lookup): Use __nis_domain_of.
+ * nis/nis_call.c (rec_dirsearch): Likewise.
+ (first_shoot): Likewise. Remove search_parent_first argument.
+ (struct nis_server_cache): Rename search_parent_first field
+ to search_parent.
+ (nis_server_cache_search, nis_server_cache_add): Rename
+ search_parent_first argument to search_parent.
+ (__nisfind_server): Likewise. If search_parent, call
+ __nis_domain_of.
+
+--- libc/nis/nis_domain_of.c.jj 2001-07-06 00:55:36.000000000 -0400
++++ libc/nis/nis_domain_of.c 2007-04-06 11:03:41.000000000 -0400
+@@ -1,4 +1,4 @@
+-/* Copyright (c) 1997 Free Software Foundation, Inc.
++/* Copyright (c) 1997, 2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
+
+@@ -26,3 +26,17 @@ nis_domain_of (const_nis_name name)
+
+ return nis_domain_of_r (name, result, NIS_MAXNAMELEN);
+ }
++
++const_nis_name
++__nis_domain_of (const_nis_name name)
++{
++ const_nis_name cptr = strchr (name, '.');
++
++ if (cptr++ == NULL)
++ return "";
++
++ if (*cptr == '\0')
++ return ".";
++
++ return cptr;
++}
+--- libc/nis/nis_lookup.c.jj 2007-04-05 07:40:08.000000000 -0400
++++ libc/nis/nis_lookup.c 2007-04-06 11:13:17.000000000 -0400
+@@ -74,7 +74,6 @@ nis_lookup (const_nis_name name, const u
+ {
+ static const struct timeval RPCTIMEOUT = {10, 0};
+ enum clnt_stat result;
+- char ndomain[strlen (req.ns_name) + 1];
+
+ again:
+ result = clnt_call (bptr.clnt, NIS_LOOKUP,
+@@ -136,10 +135,9 @@ nis_lookup (const_nis_name name, const u
+ if (__nisbind_next (&bptr) != NIS_SUCCESS)
+ {
+ /* No more servers to search. Try parent. */
+- nis_domain_of_r (req.ns_name, ndomain,
+- sizeof (ndomain));
++ const char *ndomain = __nis_domain_of (req.ns_name);
+ req.ns_name = strdupa (ndomain);
+- if (strcmp (ndomain, ".") == 0)
++ if (strcmp (req.ns_name, ".") == 0)
+ {
+ NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
+ goto out;
+--- libc/nis/nis_call.c.jj 2007-04-05 08:10:07.000000000 -0400
++++ libc/nis/nis_call.c 2007-04-06 11:31:30.000000000 -0400
+@@ -423,9 +423,7 @@ rec_dirsearch (const_nis_name name, dire
+ case HIGHER_NAME:
+ { /* We need data from a parent domain */
+ directory_obj *obj;
+- char ndomain[strlen (dir->do_name) + 3];
+-
+- nis_domain_of_r (dir->do_name, ndomain, sizeof (ndomain));
++ const char *ndomain = __nis_domain_of (dir->do_name);
+
+ /* The root server of our domain is a replica of the parent
+ domain ! (Now I understand why a root server must be a
+@@ -469,7 +467,7 @@ rec_dirsearch (const_nis_name name, dire
+ size_t namelen = strlen (name);
+ char leaf[namelen + 3];
+ char domain[namelen + 3];
+- char ndomain[namelen + 3];
++ const char *ndomain;
+ char *cp;
+
+ strcpy (domain, name);
+@@ -482,8 +480,8 @@ rec_dirsearch (const_nis_name name, dire
+ return NULL;
+ }
+ nis_leaf_of_r (domain, leaf, sizeof (leaf));
+- nis_domain_of_r (domain, ndomain, sizeof (ndomain));
+- strcpy (domain, ndomain);
++ ndomain = __nis_domain_of (domain);
++ memmove (domain, ndomain, strlen (ndomain) + 1);
+ }
+ while (nis_dir_cmp (domain, dir->do_name) != SAME_NAME);
+
+@@ -536,29 +534,16 @@ rec_dirsearch (const_nis_name name, dire
+ /* We try to query the current server for the searched object,
+ maybe he know about it ? */
+ static directory_obj *
+-first_shoot (const_nis_name name, int search_parent_first, directory_obj *dir)
++first_shoot (const_nis_name name, directory_obj *dir)
+ {
+ directory_obj *obj = NULL;
+ fd_result *fd_res;
+ XDR xdrs;
+- char domain[strlen (name) + 3];
+
+-#if 0
+ if (nis_dir_cmp (name, dir->do_name) == SAME_NAME)
+ return dir;
+-#endif
+-
+- const char *search_name = name;
+- if (search_parent_first)
+- {
+- nis_domain_of_r (name, domain, sizeof (domain));
+- search_name = domain;
+- }
+-
+- if (nis_dir_cmp (search_name, dir->do_name) == SAME_NAME)
+- return dir;
+
+- fd_res = __nis_finddirectory (dir, search_name);
++ fd_res = __nis_finddirectory (dir, name);
+ if (fd_res == NULL)
+ return NULL;
+ if (fd_res->status == NIS_SUCCESS
+@@ -586,7 +571,7 @@ first_shoot (const_nis_name name, int se
+
+ static struct nis_server_cache
+ {
+- int search_parent_first;
++ int search_parent;
+ int uses;
+ unsigned int size;
+ unsigned int server_used;
+@@ -598,7 +583,7 @@ static time_t nis_cold_start_mtime;
+ __libc_lock_define_initialized (static, nis_server_cache_lock)
+
+ static directory_obj *
+-nis_server_cache_search (const_nis_name name, int search_parent_first,
++nis_server_cache_search (const_nis_name name, int search_parent,
+ unsigned int *server_used, unsigned int *current_ep,
+ struct timeval *now)
+ {
+@@ -622,7 +607,7 @@ nis_server_cache_search (const_nis_name
+ free (nis_server_cache[i]);
+ nis_server_cache[i] = NULL;
+ }
+- else if (nis_server_cache[i]->search_parent_first == search_parent_first
++ else if (nis_server_cache[i]->search_parent == search_parent
+ && strcmp (nis_server_cache[i]->name, name) == 0)
+ {
+ ret = calloc (1, sizeof (directory_obj));
+@@ -654,7 +639,7 @@ nis_server_cache_search (const_nis_name
+ }
+
+ static void
+-nis_server_cache_add (const_nis_name name, int search_parent_first,
++nis_server_cache_add (const_nis_name name, int search_parent,
+ directory_obj *dir, unsigned int server_used,
+ unsigned int current_ep, struct timeval *now)
+ {
+@@ -673,7 +658,7 @@ nis_server_cache_add (const_nis_name nam
+ new = calloc (1, sizeof (*new) + strlen (name) + 8 + size);
+ if (new == NULL)
+ return;
+- new->search_parent_first = search_parent_first;
++ new->search_parent = search_parent;
+ new->uses = 1;
+ new->expires = now->tv_sec + dir->do_ttl;
+ new->size = size;
+@@ -714,7 +699,7 @@ nis_server_cache_add (const_nis_name nam
+ }
+
+ nis_error
+-__nisfind_server (const_nis_name name, int search_parent_first,
++__nisfind_server (const_nis_name name, int search_parent,
+ directory_obj **dir, dir_binding *dbp, unsigned int flags)
+ {
+ nis_error result = NIS_SUCCESS;
+@@ -733,7 +718,7 @@ __nisfind_server (const_nis_name name, i
+ (void) gettimeofday (&now, NULL);
+
+ if ((flags & NO_CACHE) == 0)
+- *dir = nis_server_cache_search (name, search_parent_first, &server_used,
++ *dir = nis_server_cache_search (name, search_parent, &server_used,
+ ¤t_ep, &now);
+ if (*dir != NULL)
+ {
+@@ -763,10 +748,13 @@ __nisfind_server (const_nis_name name, i
+ return NIS_UNAVAIL;
+
+ /* Try at first, if servers in "dir" know our object */
+- obj = first_shoot (name, search_parent_first, *dir);
++ const char *search_name = name;
++ if (search_parent)
++ search_name = __nis_domain_of (name);
++ obj = first_shoot (search_name, *dir);
+ if (obj == NULL)
+ {
+- obj = rec_dirsearch (name, *dir, &status);
++ obj = rec_dirsearch (search_name, *dir, &status);
+ if (obj == NULL)
+ result = status;
+ }
+@@ -787,7 +775,7 @@ __nisfind_server (const_nis_name name, i
+ current_ep = dbp->current_ep;
+ }
+ if ((flags & NO_CACHE) == 0)
+- nis_server_cache_add (name, search_parent_first, obj,
++ nis_server_cache_add (name, search_parent, obj,
+ server_used, current_ep, &now);
+ }
+ else
+--- libc/include/rpcsvc/nislib.h.jj 2004-10-24 16:25:25.000000000 -0400
++++ libc/include/rpcsvc/nislib.h 2007-04-06 11:04:51.000000000 -0400
+@@ -42,4 +42,6 @@ libnsl_hidden_proto (__nis_default_group
+ libnsl_hidden_proto (__nis_default_access)
+ libnsl_hidden_proto (nis_clone_object)
+
++extern const_nis_name __nis_domain_of (const_nis_name) __THROW;
++
+ #endif
--- /dev/null
+2007-05-07 Ulrich Drepper <drepper@redhat.com>
+ Jakub Jelinek <jakub@redhat.com>
+
+ * malloc/arena.c (heap_info): Add mprotect_size field, adjust pad.
+ (new_heap): Initialize mprotect_size.
+ (grow_heap): When growing, only mprotect from mprotect_size till
+ new_size if mprotect_size is smaller. When shrinking, use PROT_NONE
+ MMAP for __libc_enable_secure only, otherwise use MADV_DONTNEED.
+
+--- libc/malloc/arena.c 27 Oct 2006 23:11:43 -0000 1.25
++++ libc/malloc/arena.c 7 May 2007 15:30:57 -0000 1.26
+@@ -57,7 +57,8 @@ typedef struct _heap_info {
+ mstate ar_ptr; /* Arena for this heap. */
+ struct _heap_info *prev; /* Previous heap. */
+ size_t size; /* Current size in bytes. */
+- size_t pad; /* Make sure the following data is properly aligned. */
++ size_t mprotect_size; /* Size in bytes that has been mprotected
++ PROT_READ|PROT_WRITE. */
+ } heap_info;
+
+ /* Thread specific data */
+@@ -654,6 +655,7 @@ new_heap(size, top_pad) size_t size, top
+ }
+ h = (heap_info *)p2;
+ h->size = size;
++ h->mprotect_size = size;
+ THREAD_STAT(stat_n_heaps++);
+ return h;
+ }
+@@ -676,17 +678,34 @@ grow_heap(h, diff) heap_info *h; long di
+ new_size = (long)h->size + diff;
+ if((unsigned long) new_size > (unsigned long) HEAP_MAX_SIZE)
+ return -1;
+- if(mprotect((char *)h + h->size, diff, PROT_READ|PROT_WRITE) != 0)
+- return -2;
++ if((unsigned long) new_size > h->mprotect_size) {
++ if (mprotect((char *)h + h->mprotect_size,
++ (unsigned long) new_size - h->mprotect_size,
++ PROT_READ|PROT_WRITE) != 0)
++ return -2;
++ h->mprotect_size = new_size;
++ }
+ } else {
+ new_size = (long)h->size + diff;
+ if(new_size < (long)sizeof(*h))
+ return -1;
+ /* Try to re-map the extra heap space freshly to save memory, and
+ make it inaccessible. */
+- if((char *)MMAP((char *)h + new_size, -diff, PROT_NONE,
+- MAP_PRIVATE|MAP_FIXED) == (char *) MAP_FAILED)
+- return -2;
++#ifdef _LIBC
++ if (__builtin_expect (__libc_enable_secure, 0))
++#else
++ if (1)
++#endif
++ {
++ if((char *)MMAP((char *)h + new_size, -diff, PROT_NONE,
++ MAP_PRIVATE|MAP_FIXED) == (char *) MAP_FAILED)
++ return -2;
++ h->mprotect_size = new_size;
++ }
++#ifdef _LIBC
++ else
++ madvise ((char *)h + new_size, -diff, MADV_DONTNEED);
++#endif
+ /*fprintf(stderr, "shrink %p %08lx\n", h, new_size);*/
+ }
+ h->size = new_size;
--- /dev/null
+2007-04-30 Jakub Jelinek <jakub@redhat.com>
+
+ * stdio-common/printf_fp.c (___printf_fp): Don't print negative sign
+ for exponent 0.
+ * stdio-common/tfformat.c (sprint_doubles): Add a new test.
+
+--- libc/stdio-common/printf_fp.c 16 Apr 2007 23:28:26 -0000 1.62
++++ libc/stdio-common/printf_fp.c 30 Apr 2007 22:31:21 -0000 1.63
+@@ -793,7 +793,7 @@ ___printf_fp (FILE *fp,
+ else
+ {
+ /* This is a special case. We don't need a factor because the
+- numbers are in the range of 0.0 <= fp < 8.0. We simply
++ numbers are in the range of 1.0 <= |fp| < 8.0. We simply
+ shift it to the right place and divide it by 1.0 to get the
+ leading digit. (Of course this division is not really made.) */
+ assert (0 <= exponent && exponent < 3 &&
+@@ -1013,6 +1013,12 @@ ___printf_fp (FILE *fp,
+ {
+ *wstartp = '1';
+ exponent += expsign == 0 ? 1 : -1;
++
++ /* The above exponent adjustment could lead to 1.0e-00,
++ e.g. for 0.999999999. Make sure exponent 0 always
++ uses + sign. */
++ if (exponent == 0)
++ expsign = 0;
+ }
+ else if (intdig_no == dig_max)
+ {
+--- libc/stdio-common/tfformat.c 16 Apr 2007 23:28:37 -0000 1.9
++++ libc/stdio-common/tfformat.c 30 Apr 2007 22:31:36 -0000 1.10
+@@ -4021,6 +4021,8 @@ sprint_double_type sprint_doubles[] =
+ {__LINE__, 0.000098, "0.0001", "%#.0g"},
+ {__LINE__, 0.0000996, "0.00010", "%#.2g"},
+ {__LINE__, 9.999999999999999e-05, "0.0001", "%g"},
++ {__LINE__, 1.0, "1.000000e+00", "%e"},
++ {__LINE__, .9999999999999999, "1.000000e+00", "%e"},
+
+ {0 }
+
--- /dev/null
+2007-08-02 Jakub Jelinek <jakub@redhat.com>
+
+ * intl/dcigettext.c (_nl_find_msg): Return (char *) -1 if
+ domain->conv is (__gconv_t) -2.
+ * intl/loadmsgcat.c (_nl_init_domain_conv): If __gconv_open
+ returns non-__GCONV_OK and non-__GCONV_NULCONV, set
+ domain->conv to (__gconv_t) -2.
+ (_nl_free_domain_conv): Don't call __gconv_close on
+ (__gconv_t) -2.
+
+2007-07-19 Jakub Jelinek <jakub@redhat.com>
+
+ * iconv/gconv_int.h (__GCONV_NULCONV): New internal only error code.
+ * iconv/gconv_cache.c (__gconv_lookup_cache): Return __GCONV_NULCONV
+ if from and to charsets are the same.
+ * iconv/gconv_db.c (__gconv_find_transform): Likewise.
+
+2007-07-11 Jakub Jelinek <jakub@redhat.com>
+
+ * intl/finddomain.c (_nl_find_domain): If _nl_explode_name
+ returned -1, return NULL.
+ * intl/explodename.c (_nl_explode_name): Return -1 if
+ _nl_normalize_codeset failed.
+
+--- libc/intl/dcigettext.c.jj 2007-08-02 10:33:21.000000000 -0400
++++ libc/intl/dcigettext.c 2007-08-02 15:03:56.000000000 -0400
+@@ -818,6 +818,13 @@ _nl_find_msg (domain_file, domainbinding
+ # endif
+ )
+ {
++# ifdef _LIBC
++ if (__builtin_expect (domain->conv == (__gconv_t) -2, 0))
++ /* Nothing we can do, no more memory. We cannot use the
++ translation because it might be encoded incorrectly. */
++ return (char *) -1;
++# endif
++
+ /* We are supposed to do a conversion. First allocate an
+ appropriate table with the same structure as the table
+ of translations in the file, where we can put the pointers
+--- libc/iconv/gconv_cache.c.jj 2007-08-02 10:33:20.000000000 -0400
++++ libc/iconv/gconv_cache.c 2007-08-02 10:48:35.000000000 -0400
+@@ -274,7 +274,7 @@ __gconv_lookup_cache (const char *toset,
+
+ /* Avoid copy-only transformations if the user requests. */
+ if (__builtin_expect (flags & GCONV_AVOID_NOCONV, 0) && fromidx == toidx)
+- return __GCONV_NOCONV;
++ return __GCONV_NULCONV;
+
+ /* If there are special conversions available examine them first. */
+ if (fromidx != 0 && toidx != 0
+--- libc/iconv/gconv_db.c.jj 2004-08-06 13:50:31.000000000 -0400
++++ libc/iconv/gconv_db.c 2007-08-02 10:48:35.000000000 -0400
+@@ -717,7 +717,7 @@ __gconv_find_transform (const char *tose
+ {
+ /* Both character sets are the same. */
+ __libc_lock_unlock (__gconv_lock);
+- return __GCONV_NOCONV;
++ return __GCONV_NULCONV;
+ }
+
+ result = find_derivation (toset, toset_expand, fromset, fromset_expand,
+--- libc/iconv/gconv_int.h.jj 2004-03-24 22:51:56.000000000 -0500
++++ libc/iconv/gconv_int.h 2007-08-02 10:48:35.000000000 -0400
+@@ -112,6 +112,12 @@ enum
+ GCONV_AVOID_NOCONV = 1 << 0
+ };
+
++/* When GCONV_AVOID_NOCONV is set and no conversion is needed,
++ __GCONV_NULCONV should be returned. */
++enum
++{
++ __GCONV_NULCONV = -1
++};
+
+ /* Global variables. */
+
+--- libc/intl/explodename.c.jj 2003-01-08 01:34:43.000000000 -0500
++++ libc/intl/explodename.c 2007-08-02 10:48:35.000000000 -0400
+@@ -108,7 +108,9 @@ _nl_explode_name (name, language, modifi
+ {
+ *normalized_codeset = _nl_normalize_codeset (*codeset,
+ cp - *codeset);
+- if (strcmp (*codeset, *normalized_codeset) == 0)
++ if (*normalized_codeset == NULL)
++ return -1;
++ else if (strcmp (*codeset, *normalized_codeset) == 0)
+ free ((char *) *normalized_codeset);
+ else
+ mask |= XPG_NORM_CODESET;
+--- libc/intl/finddomain.c.jj 2007-08-02 10:33:20.000000000 -0400
++++ libc/intl/finddomain.c 2007-08-02 10:48:35.000000000 -0400
+@@ -126,6 +126,9 @@ _nl_find_domain (dirname, locale, domain
+ we use XPG4 style, and `_', `+', and `,' if we use CEN syntax. */
+ mask = _nl_explode_name (locale, &language, &modifier, &territory,
+ &codeset, &normalized_codeset);
++ if (mask == -1)
++ /* This means we are out of core. */
++ return NULL;
+
+ /* We need to protect modifying the _NL_LOADED_DOMAINS data. */
+ __libc_rwlock_wrlock (lock);
+--- libc/intl/loadmsgcat.c.jj 2004-09-26 01:06:56.000000000 -0400
++++ libc/intl/loadmsgcat.c 2007-08-02 15:03:21.000000000 -0400
+@@ -834,10 +834,15 @@ _nl_init_domain_conv (domain_file, domai
+ /* We always want to use transliteration. */
+ outcharset = norm_add_slashes (outcharset, "TRANSLIT");
+ charset = norm_add_slashes (charset, "");
+- if (__gconv_open (outcharset, charset, &domain->conv,
+- GCONV_AVOID_NOCONV)
+- != __GCONV_OK)
+- domain->conv = (__gconv_t) -1;
++ int res = __gconv_open (outcharset, charset, &domain->conv,
++ GCONV_AVOID_NOCONV);
++ if (res != __GCONV_OK)
++ {
++ if (res == __GCONV_NULCONV)
++ domain->conv = (__gconv_t) -1;
++ else
++ domain->conv = (__gconv_t) -2;
++ }
+ # else
+ # if HAVE_ICONV
+ /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5,
+@@ -882,7 +887,7 @@ _nl_free_domain_conv (domain)
+ free (domain->conv_tab);
+
+ #ifdef _LIBC
+- if (domain->conv != (__gconv_t) -1)
++ if (domain->conv != (__gconv_t) -1 && domain->conv != (__gconv_t) -2)
+ __gconv_close (domain->conv);
+ #else
+ # if HAVE_ICONV
--- /dev/null
+2007-07-16 Jakub Jelinek <jakub@redhat.com>
+
+ * libio/iopopen.c (_IO_new_proc_open): Don't close child_std_end
+ if one of proc_file_chain streams has that fileno.
+ * stdio-common/Makefile (tests): Add tst-popen2.
+ * stdio-common/tst-popen2.c: New test.
+
+--- libc/libio/iopopen.c 14 Sep 2004 04:24:45 -0000 1.33
++++ libc/libio/iopopen.c 19 Jul 2007 17:02:07 -0000 1.34
+@@ -169,7 +170,15 @@ _IO_new_proc_open (fp, command, mode)
+ popen() calls that remain open in the parent process are closed
+ in the new child process." */
+ for (p = proc_file_chain; p; p = p->next)
+- _IO_close (_IO_fileno ((_IO_FILE *) p));
++ {
++ int fd = _IO_fileno ((_IO_FILE *) p);
++
++ /* If any stream from previous popen() calls has fileno
++ child_std_end, it has been already closed by the dup2 syscall
++ above. */
++ if (fd != child_std_end)
++ _IO_close (fd);
++ }
+
+ _IO_execl ("/bin/sh", "sh", "-c", command, (char *) 0);
+ _IO__exit (127);
+--- libc/stdio-common/Makefile 8 Jul 2007 04:41:08 -0000 1.104
++++ libc/stdio-common/Makefile 19 Jul 2007 17:02:55 -0000 1.105
+@@ -54,7 +54,7 @@ tests := tstscanf test_rdwr test-popen t
+ tst-swprintf tst-fseek tst-fmemopen test-vfprintf tst-gets \
+ tst-perror tst-sprintf tst-rndseek tst-fdopen tst-fphex bug14 bug15 \
+ tst-popen tst-unlockedio tst-fmemopen2 tst-put-error tst-fgets \
+- tst-fwrite bug16 bug17 bug18 bug18a bug19 bug19a
++ tst-fwrite bug16 bug17 bug18 bug18a bug19 bug19a tst-popen2
+
+ test-srcs = tst-unbputc tst-printf
+
+--- libc/stdio-common/tst-popen2.c 1 Jan 1970 00:00:00 -0000
++++ libc/stdio-common/tst-popen2.c 19 Jul 2007 17:02:43 -0000 1.1
+@@ -0,0 +1,92 @@
++#include <stdio.h>
++#include <string.h>
++#include <unistd.h>
++
++static int
++do_test (void)
++{
++ int fd = dup (fileno (stdout));
++ if (fd <= 1)
++ {
++ puts ("dup failed");
++ return 1;
++ }
++
++ FILE *f1 = fdopen (fd, "w");
++ if (f1 == NULL)
++ {
++ printf ("fdopen failed: %m\n");
++ return 1;
++ }
++
++ fclose (stdout);
++
++ FILE *f2 = popen ("echo test1", "r");
++ if (f2 == NULL)
++ {
++ fprintf (f1, "1st popen failed: %m\n");
++ return 1;
++ }
++ FILE *f3 = popen ("echo test2", "r");
++ if (f2 == NULL || f3 == NULL)
++ {
++ fprintf (f1, "2nd popen failed: %m\n");
++ return 1;
++ }
++
++ char *line = NULL;
++ size_t len = 0;
++ int result = 0;
++ if (getline (&line, &len, f2) != 6)
++ {
++ fputs ("could not read line from 1st popen\n", f1);
++ result = 1;
++ }
++ else if (strcmp (line, "test1\n") != 0)
++ {
++ fprintf (f1, "read \"%s\"\n", line);
++ result = 1;
++ }
++
++ if (getline (&line, &len, f2) != -1)
++ {
++ fputs ("second getline did not return -1\n", f1);
++ result = 1;
++ }
++
++ if (getline (&line, &len, f3) != 6)
++ {
++ fputs ("could not read line from 2nd popen\n", f1);
++ result = 1;
++ }
++ else if (strcmp (line, "test2\n") != 0)
++ {
++ fprintf (f1, "read \"%s\"\n", line);
++ result = 1;
++ }
++
++ if (getline (&line, &len, f3) != -1)
++ {
++ fputs ("second getline did not return -1\n", f1);
++ result = 1;
++ }
++
++ int ret = pclose (f2);
++ if (ret != 0)
++ {
++ fprintf (f1, "1st pclose returned %d\n", ret);
++ result = 1;
++ }
++
++ ret = pclose (f3);
++ if (ret != 0)
++ {
++ fprintf (f1, "2nd pclose returned %d\n", ret);
++ result = 1;
++ }
++
++ return result;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
--- /dev/null
+2007-08-17 Jakub Jelinek <jakub@redhat.com>
+
+ * nis/nis_table.c (nis_list): Don't fail if __follow_path returned
+ NIS_NOTFOUND.
+
+--- libc/nis/nis_table.c 21 Mar 2007 20:24:59 -0000 1.41
++++ libc/nis/nis_table.c 22 Aug 2007 16:04:09 -0000 1.42
+@@ -372,7 +372,8 @@ nis_list (const_nis_name name, unsigned
+ &bptr);
+ if (clnt_status != NIS_SUCCESS)
+ {
+- NIS_RES_STATUS (res) = clnt_status;
++ if (clnt_status == NIS_NOMEMORY)
++ NIS_RES_STATUS (res) = clnt_status;
+ ++done;
+ }
+ else
+@@ -452,10 +453,14 @@ nis_list (const_nis_name name, unsigned
+ ++done;
+ else
+ {
+- NIS_RES_STATUS (res)
++ clnt_status
+ = __follow_path (&tablepath, &tableptr, ibreq, &bptr);
+- if (NIS_RES_STATUS (res) != NIS_SUCCESS)
+- ++done;
++ if (clnt_status != NIS_SUCCESS)
++ {
++ if (clnt_status == NIS_NOMEMORY)
++ NIS_RES_STATUS (res) = clnt_status;
++ ++done;
++ }
+ }
+ }
+ break;
--- /dev/null
+2007-10-18 Ulrich Drepper <drepper@redhat.com>
+
+ * sunrpc/clnt_udp.c (clntudp_call): Don't block in recvfrom call
+ even if the poll result indicates there is data to read.
+ Patch by Jeff Moyer <jmoyer@redhat.com>.
+
+--- libc/sunrpc/clnt_udp.c 20 Dec 2005 22:38:40 -0000 1.33
++++ libc/sunrpc/clnt_udp.c 18 Oct 2007 22:23:57 -0000 1.34
+@@ -413,7 +413,7 @@ send_again:
+ {
+ fromlen = sizeof (struct sockaddr);
+ inlen = __recvfrom (cu->cu_sock, cu->cu_inbuf,
+- (int) cu->cu_recvsz, 0,
++ (int) cu->cu_recvsz, MSG_DONTWAIT,
+ (struct sockaddr *) &from, &fromlen);
+ }
+ while (inlen < 0 && errno == EINTR);
--- /dev/null
+2008-01-05 Jakub Jelinek <jakub@redhat.com>
+
+ [BZ #5112]
+ * nscd/connections.c (restart): Fix condition.
+
+2007-10-05 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #5112]
+ * nscd/connections.c (restart): Don't resync if database is
+ disabled. Patch mostly by Brian De Wolf <bldewolf@csupomona.edu>.
+
+--- libc/nscd/connections.c 29 Aug 2007 06:09:59 -0000 1.102
++++ libc/nscd/connections.c 4 Mar 2008 01:53:50 -0000 1.109
+@@ -1284,14 +1302,15 @@ cannot change to old working directory:
+
+ /* Synchronize memory. */
+ for (int cnt = 0; cnt < lastdb; ++cnt)
+- {
+- /* Make sure nobody keeps using the database. */
+- dbs[cnt].head->timestamp = 0;
++ if (dbs[cnt].enabled)
++ {
++ /* Make sure nobody keeps using the database. */
++ dbs[cnt].head->timestamp = 0;
+
+- if (dbs[cnt].persistent)
+- // XXX async OK?
+- msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
+- }
++ if (dbs[cnt].persistent)
++ // XXX async OK?
++ msync (dbs[cnt].head, dbs[cnt].memsize, MS_ASYNC);
++ }
+
+ /* The preparations are done. */
+ execv ("/proc/self/exe", argv);
--- /dev/null
+--- libc/include/ifaddrs.h.jj 2003-06-10 04:53:57.000000000 -0400
++++ libc/include/ifaddrs.h 2007-12-14 22:52:11.000000000 -0500
+@@ -1,10 +1,28 @@
+ #ifndef _IFADDRS_H
+ #include <inet/ifaddrs.h>
+ #include <stdbool.h>
++#include <stdint.h>
+
+ libc_hidden_proto (getifaddrs)
+ libc_hidden_proto (freeifaddrs)
+
+-extern void __check_pf (bool *seen_ipv4, bool *seen_ipv6) attribute_hidden;
++struct in6addrinfo
++{
++ enum {
++ in6ai_deprecated = 1,
++ in6ai_homeaddress = 2
++ } flags:8;
++ uint8_t prefixlen;
++ uint16_t :16;
++ uint32_t index;
++ uint32_t addr[4];
++};
++
++extern void __check_pf (bool *seen_ipv4, bool *seen_ipv6,
++ struct in6addrinfo **in6ai, size_t *in6ailen)
++ attribute_hidden;
++extern void __check_native (uint32_t a1_index, int *a1_native,
++ uint32_t a2_index, int *a2_native)
++ attribute_hidden;
+
+ #endif /* ifaddrs.h */
+--- libc/nscd/gai.c.jj 2007-12-14 22:52:09.000000000 -0500
++++ libc/nscd/gai.c 2007-12-14 22:52:11.000000000 -0500
+@@ -9,6 +9,7 @@
+ #define __bind bind
+ #define __sendto sendto
+ #define __strchrnul strchrnul
++#define __getline getline
+ /* nscd uses 1MB or 2MB thread stacks. */
+ #define __libc_use_alloca(size) (size <= __MAX_ALLOCA_CUTOFF)
+
+@@ -16,6 +17,7 @@
+
+ /* Support code. */
+ #include <check_pf.c>
++#include <check_native.c>
+ #ifdef HAVE_LIBIDN
+ # include <libidn/idn-stub.c>
+ #endif
+--- libc/sysdeps/unix/sysv/linux/check_pf.c.jj 2007-12-14 22:52:09.000000000 -0500
++++ libc/sysdeps/unix/sysv/linux/check_pf.c 2007-12-14 22:53:48.000000000 -0500
+@@ -1,5 +1,5 @@
+ /* Determine protocol families for which interfaces exist. Linux version.
+- Copyright (C) 2003 Free Software Foundation, Inc.
++ Copyright (C) 2003, 2006, 2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+@@ -17,10 +17,12 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+-#include <alloca.h>
++#include <assert.h>
+ #include <errno.h>
+ #include <ifaddrs.h>
+ #include <netdb.h>
++#include <stddef.h>
++#include <stdlib.h>
+ #include <string.h>
+ #include <time.h>
+ #include <unistd.h>
+@@ -30,16 +32,30 @@
+ #include <linux/netlink.h>
+ #include <linux/rtnetlink.h>
+
+-#include "kernel-features.h"
++#include <not-cancel.h>
++#include <kernel-features.h>
++
++
++#ifndef IFA_F_HOMEADDRESS
++# define IFA_F_HOMEADDRESS 0
++#endif
++#ifndef IFA_F_OPTIMISTIC
++# define IFA_F_OPTIMISTIC 0
++#endif
+
+
+ static int
+-make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6)
++make_request (int fd, pid_t pid, bool *seen_ipv4, bool *seen_ipv6,
++ struct in6addrinfo **in6ai, size_t *in6ailen)
+ {
+- struct
++ struct req
+ {
+ struct nlmsghdr nlh;
+ struct rtgenmsg g;
++ /* struct rtgenmsg consists of a single byte. This means there
++ are three bytes of padding included in the REQ definition.
++ We make them explicit here. */
++ char pad[3];
+ } req;
+ struct sockaddr_nl nladdr;
+
+@@ -50,6 +66,9 @@ make_request (int fd, pid_t pid, bool *s
+ req.nlh.nlmsg_seq = time (NULL);
+ req.g.rtgen_family = AF_UNSPEC;
+
++ assert (sizeof (req) - offsetof (struct req, pad) == 3);
++ memset (req.pad, '\0', sizeof (req.pad));
++
+ memset (&nladdr, '\0', sizeof (nladdr));
+ nladdr.nl_family = AF_NETLINK;
+
+@@ -85,6 +104,12 @@ make_request (int fd, pid_t pid, bool *s
+ *seen_ipv6 = false;
+
+ bool done = false;
++ struct in6ailist
++ {
++ struct in6addrinfo info;
++ struct in6ailist *next;
++ } *in6ailist = NULL;
++ size_t in6ailistlen = 0;
+
+ do
+ {
+@@ -115,6 +140,8 @@ make_request (int fd, pid_t pid, bool *s
+ if (nlmh->nlmsg_type == RTM_NEWADDR)
+ {
+ struct ifaddrmsg *ifam = (struct ifaddrmsg *) NLMSG_DATA (nlmh);
++ struct rtattr *rta = IFA_RTA (ifam);
++ size_t len = nlmh->nlmsg_len - NLMSG_LENGTH (sizeof (*ifam));
+
+ switch (ifam->ifa_family)
+ {
+@@ -126,8 +153,56 @@ make_request (int fd, pid_t pid, bool *s
+ break;
+ default:
+ /* Ignore. */
+- break;
++ continue;
++ }
++
++ if (in6ai == NULL)
++ continue;
++
++ const void *local = NULL;
++ const void *address = NULL;
++ while (RTA_OK (rta, len))
++ {
++ switch (rta->rta_type)
++ {
++ case IFA_LOCAL:
++ local = RTA_DATA (rta);
++ break;
++
++ case IFA_ADDRESS:
++ address = RTA_DATA (rta);
++ goto out;
++ }
++
++ rta = RTA_NEXT (rta, len);
++ }
++
++ if (local != NULL)
++ address = local;
++ out:;
++
++ struct in6ailist *newp = alloca (sizeof (*newp));
++ newp->info.flags = (((ifam->ifa_flags
++ & (IFA_F_DEPRECATED
++ | IFA_F_OPTIMISTIC))
++ ? in6ai_deprecated : 0)
++ | ((ifam->ifa_flags
++ & IFA_F_HOMEADDRESS)
++ ? in6ai_homeaddress : 0));
++ newp->info.prefixlen = ifam->ifa_prefixlen;
++ newp->info.index = ifam->ifa_index;
++ if (ifam->ifa_family == AF_INET)
++ {
++ newp->info.addr[0] = 0;
++ newp->info.addr[1] = 0;
++ newp->info.addr[2] = htonl (0xffff);
++ newp->info.addr[3] = *(const in_addr_t *) address;
+ }
++ else
++ memcpy (newp->info.addr, address, sizeof (newp->info.addr));
++ newp->next = in6ailist;
++ in6ailist = newp;
++ ++in6ailistlen;
+ }
+ else if (nlmh->nlmsg_type == NLMSG_DONE)
+ /* We found the end, leave the loop. */
+@@ -137,7 +212,23 @@ make_request (int fd, pid_t pid, bool *s
+ }
+ while (! done);
+
+- __close (fd);
++ close_not_cancel_no_status (fd);
++
++ if (*seen_ipv6 && in6ailist != NULL)
++ {
++ *in6ai = malloc (in6ailistlen * sizeof (**in6ai));
++ if (*in6ai == NULL)
++ goto out_fail;
++
++ *in6ailen = in6ailistlen;
++
++ do
++ {
++ (*in6ai)[--in6ailistlen] = in6ailist->info;
++ in6ailist = in6ailist->next;
++ }
++ while (in6ailist != NULL);
++ }
+
+ if (use_malloc)
+ free (buf);
+@@ -162,8 +253,15 @@ extern int __no_netlink_support attribut
+
+ void
+ attribute_hidden
+-__check_pf (bool *seen_ipv4, bool *seen_ipv6)
++__check_pf (bool *seen_ipv4, bool *seen_ipv6,
++ struct in6addrinfo **in6ai, size_t *in6ailen)
+ {
++ if (in6ai)
++ {
++ *in6ai = NULL;
++ *in6ailen = 0;
++ }
++
+ if (! __no_netlink_support)
+ {
+ int fd = __socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+@@ -177,7 +275,8 @@ __check_pf (bool *seen_ipv4, bool *seen_
+ if (fd >= 0
+ && __bind (fd, (struct sockaddr *) &nladdr, sizeof (nladdr)) == 0
+ && __getsockname (fd, (struct sockaddr *) &nladdr, &addr_len) == 0
+- && make_request (fd, nladdr.nl_pid, seen_ipv4, seen_ipv6) == 0)
++ && make_request (fd, nladdr.nl_pid, seen_ipv4, seen_ipv6,
++ in6ai, in6ailen) == 0)
+ /* It worked. */
+ return;
+
+--- libc/sysdeps/unix/sysv/linux/check_native.c.jj 2007-11-13 10:14:11.610303087 -0500
++++ libc/sysdeps/unix/sysv/linux/check_native.c 2007-12-14 22:52:11.000000000 -0500
+@@ -0,0 +1,172 @@
++/* Determine whether interfaces use native transport. Linux version.
++ Copyright (C) 2007 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <assert.h>
++#include <errno.h>
++#include <ifaddrs.h>
++#include <stddef.h>
++#include <stdint.h>
++#include <stdlib.h>
++#include <time.h>
++#include <unistd.h>
++#include <net/if.h>
++#include <net/if_arp.h>
++#include <sys/ioctl.h>
++
++#include <asm/types.h>
++#include <linux/netlink.h>
++#include <linux/rtnetlink.h>
++
++#include <not-cancel.h>
++
++
++void
++__check_native (uint32_t a1_index, int *a1_native,
++ uint32_t a2_index, int *a2_native)
++{
++ int fd = __socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
++
++ struct sockaddr_nl nladdr;
++ memset (&nladdr, '\0', sizeof (nladdr));
++ nladdr.nl_family = AF_NETLINK;
++
++ socklen_t addr_len = sizeof (nladdr);
++
++ if (fd < 0
++ || __bind (fd, (struct sockaddr *) &nladdr, sizeof (nladdr)) != 0
++ || __getsockname (fd, (struct sockaddr *) &nladdr, &addr_len) != 0)
++ return;
++
++ pid_t pid = nladdr.nl_pid;
++ struct req
++ {
++ struct nlmsghdr nlh;
++ struct rtgenmsg g;
++ /* struct rtgenmsg consists of a single byte. This means there
++ are three bytes of padding included in the REQ definition.
++ We make them explicit here. */
++ char pad[3];
++ } req;
++
++ req.nlh.nlmsg_len = sizeof (req);
++ req.nlh.nlmsg_type = RTM_GETLINK;
++ req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
++ req.nlh.nlmsg_pid = 0;
++ req.nlh.nlmsg_seq = time (NULL);
++ req.g.rtgen_family = AF_UNSPEC;
++
++ assert (sizeof (req) - offsetof (struct req, pad) == 3);
++ memset (req.pad, '\0', sizeof (req.pad));
++
++ memset (&nladdr, '\0', sizeof (nladdr));
++ nladdr.nl_family = AF_NETLINK;
++
++#ifdef PAGE_SIZE
++ /* Help the compiler optimize out the malloc call if PAGE_SIZE
++ is constant and smaller or equal to PTHREAD_STACK_MIN/4. */
++ const size_t buf_size = PAGE_SIZE;
++#else
++ const size_t buf_size = __getpagesize ();
++#endif
++ bool use_malloc = false;
++ char *buf;
++
++ if (__libc_use_alloca (buf_size))
++ buf = alloca (buf_size);
++ else
++ {
++ buf = malloc (buf_size);
++ if (buf != NULL)
++ use_malloc = true;
++ else
++ goto out_fail;
++ }
++
++ struct iovec iov = { buf, buf_size };
++
++ if (TEMP_FAILURE_RETRY (__sendto (fd, (void *) &req, sizeof (req), 0,
++ (struct sockaddr *) &nladdr,
++ sizeof (nladdr))) < 0)
++ goto out_fail;
++
++ bool done = false;
++ do
++ {
++ struct msghdr msg =
++ {
++ (void *) &nladdr, sizeof (nladdr),
++ &iov, 1,
++ NULL, 0,
++ 0
++ };
++
++ ssize_t read_len = TEMP_FAILURE_RETRY (__recvmsg (fd, &msg, 0));
++ if (read_len < 0)
++ goto out_fail;
++
++ if (msg.msg_flags & MSG_TRUNC)
++ goto out_fail;
++
++ struct nlmsghdr *nlmh;
++ for (nlmh = (struct nlmsghdr *) buf;
++ NLMSG_OK (nlmh, (size_t) read_len);
++ nlmh = (struct nlmsghdr *) NLMSG_NEXT (nlmh, read_len))
++ {
++ if (nladdr.nl_pid != 0 || (pid_t) nlmh->nlmsg_pid != pid
++ || nlmh->nlmsg_seq != req.nlh.nlmsg_seq)
++ continue;
++
++ if (nlmh->nlmsg_type == RTM_NEWLINK)
++ {
++ struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlmh);
++ int native = (ifim->ifi_type != ARPHRD_TUNNEL6
++ && ifim->ifi_type != ARPHRD_TUNNEL
++ && ifim->ifi_type != ARPHRD_SIT);
++
++ if (a1_index == ifim->ifi_index)
++ {
++ *a1_native = native;
++ a1_index = 0xffffffffu;
++ }
++ if (a2_index == ifim->ifi_index)
++ {
++ *a2_native = native;
++ a2_index = 0xffffffffu;
++ }
++
++ if (a1_index == 0xffffffffu
++ && a2_index == 0xffffffffu)
++ goto out;
++ }
++ else if (nlmh->nlmsg_type == NLMSG_DONE)
++ /* We found the end, leave the loop. */
++ done = true;
++ }
++ }
++ while (! done);
++
++ out:
++ close_not_cancel_no_status (fd);
++
++ return;
++
++out_fail:
++ if (use_malloc)
++ free (buf);
++}
+--- libc/sysdeps/posix/getaddrinfo.c.jj 2007-12-14 22:52:09.000000000 -0500
++++ libc/sysdeps/posix/getaddrinfo.c 2007-12-14 22:52:11.000000000 -0500
+@@ -56,6 +56,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBI
+ #include <not-cancel.h>
+ #include <nscd/nscd-client.h>
+ #include <nscd/nscd_proto.h>
++#include <sys/stat.h>
++#include <bits/libc-lock.h>
++#include <stdio_ext.h>
++#include <ctype.h>
+
+ #ifdef HAVE_LIBIDN
+ extern int __idna_to_ascii_lz (const char *input, char **output, int flags);
+@@ -1138,6 +1142,62 @@ struct sort_result
+ };
+
+
++struct sort_result_new
++{
++ struct addrinfo *dest_addr;
++ struct sockaddr_storage source_addr;
++ uint8_t source_addr_len;
++ bool got_source_addr;
++ uint8_t source_addr_flags;
++ uint8_t prefixlen;
++ uint32_t index;
++ int32_t native;
++};
++
++struct sort_result_combo
++{
++ struct sort_result_new *results;
++ int nresults;
++};
++
++struct sort_order
++{
++ size_t index;
++ struct sort_result_combo *src;
++};
++
++#if __BYTE_ORDER == __BIG_ENDIAN
++# define htonl_c(n) n
++#else
++# define htonl_c(n) __bswap_constant_32 (n)
++#endif
++
++static const struct scopeentry
++{
++ union
++ {
++ char addr[4];
++ uint32_t addr32;
++ };
++ uint32_t netmask;
++ int32_t scope;
++} default_scopes[] =
++ {
++ /* Link-local addresses: scope 2. */
++ { { { 169, 254, 0, 0 } }, htonl_c (0xffff0000), 2 },
++ { { { 127, 0, 0, 0 } }, htonl_c (0xff000000), 2 },
++ /* Site-local addresses: scope 5. */
++ { { { 10, 0, 0, 0 } }, htonl_c (0xff000000), 5 },
++ { { { 172, 16, 0, 0 } }, htonl_c (0xfff00000), 5 },
++ { { { 192, 168, 0, 0 } }, htonl_c (0xffff0000), 5 },
++ /* Default: scope 14. */
++ { { { 0, 0, 0, 0 } }, htonl_c (0x00000000), 14 }
++ };
++
++/* The label table. */
++static const struct scopeentry *scopes;
++
++
+ static int
+ get_scope (const struct sockaddr_storage *ss)
+ {
+@@ -1162,17 +1222,17 @@ get_scope (const struct sockaddr_storage
+ else if (ss->ss_family == PF_INET)
+ {
+ const struct sockaddr_in *in = (const struct sockaddr_in *) ss;
+- const uint8_t *addr = (const uint8_t *) &in->sin_addr;
+
+- /* RFC 3484 specifies how to map IPv6 addresses to scopes.
+- 169.254/16 and 127/8 are link-local. */
+- if ((addr[0] == 169 && addr[1] == 254) || addr[0] == 127)
+- scope = 2;
+- else if (addr[0] == 10 || (addr[0] == 172 && addr[1] == 16)
+- || (addr[0] == 192 && addr[1] == 168))
+- scope = 5;
+- else
+- scope = 14;
++ size_t cnt = 0;
++ while (1)
++ {
++ if ((in->sin_addr.s_addr & scopes[cnt].netmask)
++ == scopes[cnt].addr32)
++ return scopes[cnt].scope;
++
++ ++cnt;
++ }
++ /* NOTREACHED */
+ }
+ else
+ /* XXX What is a good default? */
+@@ -1269,8 +1329,8 @@ match_prefix (const struct sockaddr_stor
+ for (idx = 0; ; ++idx)
+ {
+ unsigned int bits = list[idx].bits;
+- uint8_t *mask = list[idx].prefix.s6_addr;
+- uint8_t *val = in6->sin6_addr.s6_addr;
++ const uint8_t *mask = list[idx].prefix.s6_addr;
++ const uint8_t *val = in6->sin6_addr.s6_addr;
+
+ while (bits >= 8)
+ {
+@@ -1474,6 +1534,836 @@ rfc3484_sort (const void *p1, const void
+ return 0;
+ }
+
++/* The label table. */
++static const struct prefixlist *labels;
++
++/* Default labels. */
++static const struct prefixlist default_labels_new[] =
++ {
++ /* See RFC 3484 for the details. */
++ { { .in6_u
++ = { .u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } },
++ 128, 0 },
++ { { .in6_u
++ = { .u6_addr8 = { 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
++ 16, 2 },
++ { { .in6_u
++ = { .u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
++ 96, 3 },
++ { { .in6_u
++ = { .u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } } },
++ 96, 4 },
++ /* The next two entries differ from RFC 3484. We need to treat
++ IPv6 site-local addresses special because they are never NATed,
++ unlike site-locale IPv4 addresses. If this would not happen, on
++ machines which have only IPv4 and IPv6 site-local addresses, the
++ sorting would prefer the IPv6 site-local addresses, causing
++ unnecessary delays when trying to connect to a global IPv6 address
++ through a site-local IPv6 address. */
++ { { .in6_u
++ = { .u6_addr8 = { 0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
++ 10, 5 },
++ { { .in6_u
++ = { .u6_addr8 = { 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
++ 7, 6 },
++ /* Additional rule for Teredo tunnels. */
++ { { .in6_u
++ = { .u6_addr8 = { 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
++ 32, 7 },
++ { { .in6_u
++ = { .u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
++ 0, 1 }
++ };
++
++
++/* The precedence table. */
++static const struct prefixlist *precedence;
++
++/* The default precedences. */
++static const struct prefixlist default_precedence_new[] =
++ {
++ /* See RFC 3484 for the details. */
++ { { .in6_u
++ = { .u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } },
++ 128, 50 },
++ { { .in6_u
++ = { .u6_addr8 = { 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
++ 16, 30 },
++ { { .in6_u
++ = { .u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
++ 96, 20 },
++ { { .in6_u
++ = { .u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } } },
++ 96, 10 },
++ { { .in6_u
++ = { .u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } },
++ 0, 40 }
++ };
++
++
++static int
++get_label_new (const struct sockaddr_storage *ss)
++{
++ /* XXX What is a good default value? */
++ return match_prefix (ss, labels, INT_MAX);
++}
++
++
++static int
++get_precedence_new (const struct sockaddr_storage *ss)
++{
++ /* XXX What is a good default value? */
++ return match_prefix (ss, precedence, 0);
++}
++
++
++static int
++rfc3484_new_sort (const void *p1, const void *p2)
++{
++ const size_t idx1 = ((const struct sort_order *) p1)->index;
++ const size_t idx2 = ((const struct sort_order *) p2)->index;
++ struct sort_result_combo *src = ((const struct sort_order *) p1)->src;
++ struct sort_result_new *a1 = &src->results[idx1];
++ struct sort_result_new *a2 = &src->results[idx2];
++
++ /* Rule 1: Avoid unusable destinations.
++ We have the got_source_addr flag set if the destination is reachable. */
++ if (a1->got_source_addr && ! a2->got_source_addr)
++ return -1;
++ if (! a1->got_source_addr && a2->got_source_addr)
++ return 1;
++
++
++ /* Rule 2: Prefer matching scope. Only interesting if both
++ destination addresses are IPv6. */
++ int a1_dst_scope
++ = get_scope ((struct sockaddr_storage *) a1->dest_addr->ai_addr);
++
++ int a2_dst_scope
++ = get_scope ((struct sockaddr_storage *) a2->dest_addr->ai_addr);
++
++ if (a1->got_source_addr)
++ {
++ int a1_src_scope = get_scope (&a1->source_addr);
++ int a2_src_scope = get_scope (&a2->source_addr);
++
++ if (a1_dst_scope == a1_src_scope && a2_dst_scope != a2_src_scope)
++ return -1;
++ if (a1_dst_scope != a1_src_scope && a2_dst_scope == a2_src_scope)
++ return 1;
++ }
++
++
++ /* Rule 3: Avoid deprecated addresses. */
++ if (a1->got_source_addr)
++ {
++ if (!(a1->source_addr_flags & in6ai_deprecated)
++ && (a2->source_addr_flags & in6ai_deprecated))
++ return -1;
++ if ((a1->source_addr_flags & in6ai_deprecated)
++ && !(a2->source_addr_flags & in6ai_deprecated))
++ return 1;
++ }
++
++ /* Rule 4: Prefer home addresses. */
++ if (a1->got_source_addr)
++ {
++ if (!(a1->source_addr_flags & in6ai_homeaddress)
++ && (a2->source_addr_flags & in6ai_homeaddress))
++ return 1;
++ if ((a1->source_addr_flags & in6ai_homeaddress)
++ && !(a2->source_addr_flags & in6ai_homeaddress))
++ return -1;
++ }
++
++ /* Rule 5: Prefer matching label. */
++ if (a1->got_source_addr)
++ {
++ int a1_dst_label
++ = get_label_new ((struct sockaddr_storage *) a1->dest_addr->ai_addr);
++ int a1_src_label = get_label_new (&a1->source_addr);
++
++ int a2_dst_label
++ = get_label_new ((struct sockaddr_storage *) a2->dest_addr->ai_addr);
++ int a2_src_label = get_label_new (&a2->source_addr);
++
++ if (a1_dst_label == a1_src_label && a2_dst_label != a2_src_label)
++ return -1;
++ if (a1_dst_label != a1_src_label && a2_dst_label == a2_src_label)
++ return 1;
++ }
++
++
++ /* Rule 6: Prefer higher precedence. */
++ int a1_prec
++ = get_precedence_new ((struct sockaddr_storage *) a1->dest_addr->ai_addr);
++ int a2_prec
++ = get_precedence_new ((struct sockaddr_storage *) a2->dest_addr->ai_addr);
++
++ if (a1_prec > a2_prec)
++ return -1;
++ if (a1_prec < a2_prec)
++ return 1;
++
++
++ /* Rule 7: Prefer native transport. */
++ if (a1->got_source_addr)
++ {
++ /* The same interface index means the same interface which means
++ there is no difference in transport. This should catch many
++ (most?) cases. */
++ if (a1->index != a2->index)
++ {
++ int a1_native = a1->native;
++ int a2_native = a2->native;
++
++ if (a1_native == -1 || a2_native == -1)
++ {
++ uint32_t a1_index;
++ if (a1_native == -1)
++ {
++ /* If we do not have the information use 'native' as
++ the default. */
++ a1_native = 0;
++ a1_index = a1->index;
++ }
++ else
++ a1_index = 0xffffffffu;
++
++ uint32_t a2_index;
++ if (a2_native == -1)
++ {
++ /* If we do not have the information use 'native' as
++ the default. */
++ a2_native = 0;
++ a2_index = a2->index;
++ }
++ else
++ a2_index = 0xffffffffu;
++
++ __check_native (a1_index, &a1_native, a2_index, &a2_native);
++
++ /* Fill in the results in all the records. */
++ for (int i = 0; i < src->nresults; ++i)
++ if (src->results[i].index == a1_index)
++ {
++ assert (src->results[i].native == -1
++ || src->results[i].native == a1_native);
++ src->results[i].native = a1_native;
++ }
++ else if (src->results[i].index == a2_index)
++ {
++ assert (src->results[i].native == -1
++ || src->results[i].native == a2_native);
++ src->results[i].native = a2_native;
++ }
++ }
++
++ if (a1_native && !a2_native)
++ return -1;
++ if (!a1_native && a2_native)
++ return 1;
++ }
++ }
++
++
++ /* Rule 8: Prefer smaller scope. */
++ if (a1_dst_scope < a2_dst_scope)
++ return -1;
++ if (a1_dst_scope > a2_dst_scope)
++ return 1;
++
++
++ /* Rule 9: Use longest matching prefix. */
++ if (a1->got_source_addr
++ && a1->dest_addr->ai_family == a2->dest_addr->ai_family)
++ {
++ int bit1 = 0;
++ int bit2 = 0;
++
++ if (a1->dest_addr->ai_family == PF_INET)
++ {
++ assert (a1->source_addr.ss_family == PF_INET);
++ assert (a2->source_addr.ss_family == PF_INET);
++
++ /* Outside of subnets, as defined by the network masks,
++ common address prefixes for IPv4 addresses make no sense.
++ So, define a non-zero value only if source and
++ destination address are on the same subnet. */
++ struct sockaddr_in *in1_dst
++ = (struct sockaddr_in *) a1->dest_addr->ai_addr;
++ in_addr_t in1_dst_addr = ntohl (in1_dst->sin_addr.s_addr);
++ struct sockaddr_in *in1_src
++ = (struct sockaddr_in *) &a1->source_addr;
++ in_addr_t in1_src_addr = ntohl (in1_src->sin_addr.s_addr);
++ in_addr_t netmask1 = 0xffffffffu << (32 - a1->prefixlen);
++
++ if ((in1_src_addr & netmask1) == (in1_dst_addr & netmask1))
++ bit1 = fls (in1_dst_addr ^ in1_src_addr);
++
++ struct sockaddr_in *in2_dst
++ = (struct sockaddr_in *) a2->dest_addr->ai_addr;
++ in_addr_t in2_dst_addr = ntohl (in2_dst->sin_addr.s_addr);
++ struct sockaddr_in *in2_src
++ = (struct sockaddr_in *) &a2->source_addr;
++ in_addr_t in2_src_addr = ntohl (in2_src->sin_addr.s_addr);
++ in_addr_t netmask2 = 0xffffffffu << (32 - a2->prefixlen);
++
++ if ((in2_src_addr & netmask2) == (in2_dst_addr & netmask2))
++ bit2 = fls (in2_dst_addr ^ in2_src_addr);
++ }
++ else if (a1->dest_addr->ai_family == PF_INET6)
++ {
++ assert (a1->source_addr.ss_family == PF_INET6);
++ assert (a2->source_addr.ss_family == PF_INET6);
++
++ struct sockaddr_in6 *in1_dst;
++ struct sockaddr_in6 *in1_src;
++ struct sockaddr_in6 *in2_dst;
++ struct sockaddr_in6 *in2_src;
++
++ in1_dst = (struct sockaddr_in6 *) a1->dest_addr->ai_addr;
++ in1_src = (struct sockaddr_in6 *) &a1->source_addr;
++ in2_dst = (struct sockaddr_in6 *) a2->dest_addr->ai_addr;
++ in2_src = (struct sockaddr_in6 *) &a2->source_addr;
++
++ int i;
++ for (i = 0; i < 4; ++i)
++ if (in1_dst->sin6_addr.s6_addr32[i]
++ != in1_src->sin6_addr.s6_addr32[i]
++ || (in2_dst->sin6_addr.s6_addr32[i]
++ != in2_src->sin6_addr.s6_addr32[i]))
++ break;
++
++ if (i < 4)
++ {
++ bit1 = fls (ntohl (in1_dst->sin6_addr.s6_addr32[i]
++ ^ in1_src->sin6_addr.s6_addr32[i]));
++ bit2 = fls (ntohl (in2_dst->sin6_addr.s6_addr32[i]
++ ^ in2_src->sin6_addr.s6_addr32[i]));
++ }
++ }
++
++ if (bit1 > bit2)
++ return -1;
++ if (bit1 < bit2)
++ return 1;
++ }
++
++
++ /* Rule 10: Otherwise, leave the order unchanged. To ensure this
++ compare with the value indicating the order in which the entries
++ have been received from the services. NB: no two entries can have
++ the same order so the test will never return zero. */
++ return idx1 < idx2 ? -1 : 1;
++}
++
++
++static int
++in6aicmp (const void *p1, const void *p2)
++{
++ struct in6addrinfo *a1 = (struct in6addrinfo *) p1;
++ struct in6addrinfo *a2 = (struct in6addrinfo *) p2;
++
++ return memcmp (a1->addr, a2->addr, sizeof (a1->addr));
++}
++
++
++/* Name of the config file for RFC 3484 sorting (for now). */
++#define GAICONF_FNAME "/etc/gai.conf"
++
++
++/* Non-zero if we are supposed to reload the config file automatically
++ whenever it changed. */
++static int gaiconf_reload_flag;
++
++/* Non-zero if gaiconf_reload_flag was ever set to true. */
++static int gaiconf_reload_flag_ever_set;
++
++/* Last modification time. */
++static struct timespec gaiconf_mtime;
++
++
++libc_freeres_fn(fini)
++{
++ if (labels != default_labels_new)
++ {
++ const struct prefixlist *old = labels;
++ labels = default_labels_new;
++ free ((void *) old);
++ }
++
++ if (precedence != default_precedence_new)
++ {
++ const struct prefixlist *old = precedence;
++ precedence = default_precedence_new;
++ free ((void *) old);
++ }
++
++ if (scopes != default_scopes)
++ {
++ const struct scopeentry *old = scopes;
++ scopes = default_scopes;
++ free ((void *) old);
++ }
++}
++
++
++struct prefixlist_new
++{
++ struct prefixlist entry;
++ struct prefixlist_new *next;
++};
++
++
++struct scopelist
++{
++ struct scopeentry entry;
++ struct scopelist *next;
++};
++
++
++static void
++free_prefixlist (struct prefixlist_new *list)
++{
++ while (list != NULL)
++ {
++ struct prefixlist_new *oldp = list;
++ list = list->next;
++ free (oldp);
++ }
++}
++
++
++static void
++free_scopelist (struct scopelist *list)
++{
++ while (list != NULL)
++ {
++ struct scopelist *oldp = list;
++ list = list->next;
++ free (oldp);
++ }
++}
++
++
++static int
++prefixcmp (const void *p1, const void *p2)
++{
++ const struct prefixlist *e1 = (const struct prefixlist *) p1;
++ const struct prefixlist *e2 = (const struct prefixlist *) p2;
++
++ if (e1->bits < e2->bits)
++ return 1;
++ if (e1->bits == e2->bits)
++ return 0;
++ return -1;
++}
++
++
++static int
++scopecmp (const void *p1, const void *p2)
++{
++ const struct scopeentry *e1 = (const struct scopeentry *) p1;
++ const struct scopeentry *e2 = (const struct scopeentry *) p2;
++
++ if (e1->netmask > e2->netmask)
++ return -1;
++ if (e1->netmask == e2->netmask)
++ return 0;
++ return 1;
++}
++
++static bool gaiconf_present;
++
++static void
++gaiconf_init (void)
++{
++ struct prefixlist_new *labellist = NULL;
++ size_t nlabellist = 0;
++ bool labellist_nullbits = false;
++ struct prefixlist_new *precedencelist = NULL;
++ size_t nprecedencelist = 0;
++ bool precedencelist_nullbits = false;
++ struct scopelist *scopelist = NULL;
++ size_t nscopelist = 0;
++ bool scopelist_nullbits = false;
++
++ FILE *fp = fopen (GAICONF_FNAME, "rc");
++ if (fp != NULL)
++ {
++ struct stat64 st;
++ if (__fxstat64 (_STAT_VER, fileno (fp), &st) != 0)
++ {
++ fclose (fp);
++ goto no_file;
++ }
++
++ gaiconf_present = true;
++
++ char *line = NULL;
++ size_t linelen = 0;
++
++ __fsetlocking (fp, FSETLOCKING_BYCALLER);
++
++ while (!feof_unlocked (fp))
++ {
++ ssize_t n = __getline (&line, &linelen, fp);
++ if (n <= 0)
++ break;
++
++ /* Handle comments. No escaping possible so this is easy. */
++ char *cp = strchr (line, '#');
++ if (cp != NULL)
++ *cp = '\0';
++
++ cp = line;
++ while (isspace (*cp))
++ ++cp;
++
++ char *cmd = cp;
++ while (*cp != '\0' && !isspace (*cp))
++ ++cp;
++ size_t cmdlen = cp - cmd;
++
++ if (*cp != '\0')
++ *cp++ = '\0';
++ while (isspace (*cp))
++ ++cp;
++
++ char *val1 = cp;
++ while (*cp != '\0' && !isspace (*cp))
++ ++cp;
++ size_t val1len = cp - cmd;
++
++ /* We always need at least two values. */
++ if (val1len == 0)
++ continue;
++
++ if (*cp != '\0')
++ *cp++ = '\0';
++ while (isspace (*cp))
++ ++cp;
++
++ char *val2 = cp;
++ while (*cp != '\0' && !isspace (*cp))
++ ++cp;
++
++ /* Ignore the rest of the line. */
++ *cp = '\0';
++
++ struct prefixlist_new **listp;
++ size_t *lenp;
++ bool *nullbitsp;
++ switch (cmdlen)
++ {
++ case 5:
++ if (strcmp (cmd, "label") == 0)
++ {
++ struct in6_addr prefix;
++ unsigned long int bits;
++ unsigned long int val;
++ char *endp;
++
++ listp = &labellist;
++ lenp = &nlabellist;
++ nullbitsp = &labellist_nullbits;
++
++ new_elem:
++ bits = 128;
++ __set_errno (0);
++ cp = strchr (val1, '/');
++ if (cp != NULL)
++ *cp++ = '\0';
++ if (inet_pton (AF_INET6, val1, &prefix)
++ && (cp == NULL
++ || (bits = strtoul (cp, &endp, 10)) != ULONG_MAX
++ || errno != ERANGE)
++ && *endp == '\0'
++ && bits <= 128
++ && ((val = strtoul (val2, &endp, 10)) != ULONG_MAX
++ || errno != ERANGE)
++ && *endp == '\0'
++ && val <= INT_MAX)
++ {
++ struct prefixlist_new *newp = malloc (sizeof (*newp));
++ if (newp == NULL)
++ {
++ free (line);
++ fclose (fp);
++ goto no_file;
++ }
++
++ memcpy (&newp->entry.prefix, &prefix, sizeof (prefix));
++ newp->entry.bits = bits;
++ newp->entry.val = val;
++ newp->next = *listp;
++ *listp = newp;
++ ++*lenp;
++ *nullbitsp |= bits == 0;
++ }
++ }
++ break;
++
++ case 6:
++ if (strcmp (cmd, "reload") == 0)
++ {
++ gaiconf_reload_flag = strcmp (val1, "yes") == 0;
++ if (gaiconf_reload_flag)
++ gaiconf_reload_flag_ever_set = 1;
++ }
++ break;
++
++ case 7:
++ if (strcmp (cmd, "scopev4") == 0)
++ {
++ struct in6_addr prefix;
++ unsigned long int bits;
++ unsigned long int val;
++ char *endp;
++
++ bits = 32;
++ __set_errno (0);
++ cp = strchr (val1, '/');
++ if (cp != NULL)
++ *cp++ = '\0';
++ if (inet_pton (AF_INET6, val1, &prefix))
++ {
++ if (IN6_IS_ADDR_V4MAPPED (&prefix)
++ && (cp == NULL
++ || (bits = strtoul (cp, &endp, 10)) != ULONG_MAX
++ || errno != ERANGE)
++ && *endp == '\0'
++ && bits >= 96
++ && bits <= 128
++ && ((val = strtoul (val2, &endp, 10)) != ULONG_MAX
++ || errno != ERANGE)
++ && *endp == '\0'
++ && val <= INT_MAX)
++ {
++ struct scopelist *newp;
++ new_scope:
++ newp = malloc (sizeof (*newp));
++ if (newp == NULL)
++ {
++ free (line);
++ fclose (fp);
++ goto no_file;
++ }
++
++ newp->entry.netmask = htonl (bits != 96
++ ? (0xffffffff
++ << (128 - bits))
++ : 0);
++ newp->entry.addr32 = (prefix.s6_addr32[3]
++ & newp->entry.netmask);
++ newp->entry.scope = val;
++ newp->next = scopelist;
++ scopelist = newp;
++ ++nscopelist;
++ scopelist_nullbits |= bits == 96;
++ }
++ }
++ else if (inet_pton (AF_INET, val1, &prefix.s6_addr32[3])
++ && (cp == NULL
++ || (bits = strtoul (cp, &endp, 10)) != ULONG_MAX
++ || errno != ERANGE)
++ && *endp == '\0'
++ && bits <= 32
++ && ((val = strtoul (val2, &endp, 10)) != ULONG_MAX
++ || errno != ERANGE)
++ && *endp == '\0'
++ && val <= INT_MAX)
++ {
++ bits += 96;
++ goto new_scope;
++ }
++ }
++ break;
++
++ case 10:
++ if (strcmp (cmd, "precedence") == 0)
++ {
++ listp = &precedencelist;
++ lenp = &nprecedencelist;
++ nullbitsp = &precedencelist_nullbits;
++ goto new_elem;
++ }
++ break;
++ }
++ }
++
++ free (line);
++
++ fclose (fp);
++
++ /* Create the array for the labels. */
++ struct prefixlist *new_labels;
++ if (nlabellist > 0)
++ {
++ if (!labellist_nullbits)
++ ++nlabellist;
++ new_labels = malloc (nlabellist * sizeof (*new_labels));
++ if (new_labels == NULL)
++ goto no_file;
++
++ int i = nlabellist;
++ if (!labellist_nullbits)
++ {
++ --i;
++ memset (&new_labels[i].prefix, '\0', sizeof (struct in6_addr));
++ new_labels[i].bits = 0;
++ new_labels[i].val = 1;
++ }
++
++ struct prefixlist_new *l = labellist;
++ while (i-- > 0)
++ {
++ new_labels[i] = l->entry;
++ l = l->next;
++ }
++ free_prefixlist (labellist);
++
++ /* Sort the entries so that the most specific ones are at
++ the beginning. */
++ qsort (new_labels, nlabellist, sizeof (*new_labels), prefixcmp);
++ }
++ else
++ new_labels = (struct prefixlist *) default_labels_new;
++
++ struct prefixlist *new_precedence;
++ if (nprecedencelist > 0)
++ {
++ if (!precedencelist_nullbits)
++ ++nprecedencelist;
++ new_precedence = malloc (nprecedencelist * sizeof (*new_precedence));
++ if (new_precedence == NULL)
++ {
++ if (new_labels != default_labels_new)
++ free (new_labels);
++ goto no_file;
++ }
++
++ int i = nprecedencelist;
++ if (!precedencelist_nullbits)
++ {
++ --i;
++ memset (&new_precedence[i].prefix, '\0',
++ sizeof (struct in6_addr));
++ new_precedence[i].bits = 0;
++ new_precedence[i].val = 40;
++ }
++
++ struct prefixlist_new *l = precedencelist;
++ while (i-- > 0)
++ {
++ new_precedence[i] = l->entry;
++ l = l->next;
++ }
++ free_prefixlist (precedencelist);
++
++ /* Sort the entries so that the most specific ones are at
++ the beginning. */
++ qsort (new_precedence, nprecedencelist, sizeof (*new_precedence),
++ prefixcmp);
++ }
++ else
++ new_precedence = (struct prefixlist *) default_precedence_new;
++
++ struct scopeentry *new_scopes;
++ if (nscopelist > 0)
++ {
++ if (!scopelist_nullbits)
++ ++nscopelist;
++ new_scopes = malloc (nscopelist * sizeof (*new_scopes));
++ if (new_scopes == NULL)
++ {
++ if (new_labels != default_labels_new)
++ free (new_labels);
++ if (new_precedence != default_precedence_new)
++ free (new_precedence);
++ goto no_file;
++ }
++
++ int i = nscopelist;
++ if (!scopelist_nullbits)
++ {
++ --i;
++ new_scopes[i].addr32 = 0;
++ new_scopes[i].netmask = 0;
++ new_scopes[i].scope = 14;
++ }
++
++ struct scopelist *l = scopelist;
++ while (i-- > 0)
++ {
++ new_scopes[i] = l->entry;
++ l = l->next;
++ }
++ free_scopelist (scopelist);
++
++ /* Sort the entries so that the most specific ones are at
++ the beginning. */
++ qsort (new_scopes, nscopelist, sizeof (*new_scopes),
++ scopecmp);
++ }
++ else
++ new_scopes = (struct scopeentry *) default_scopes;
++
++ /* Now we are ready to replace the values. */
++ const struct prefixlist *old = labels;
++ labels = new_labels;
++ if (old != default_labels_new)
++ free ((void *) old);
++
++ old = precedence;
++ precedence = new_precedence;
++ if (old != default_precedence_new)
++ free ((void *) old);
++
++ const struct scopeentry *oldscope = scopes;
++ scopes = new_scopes;
++ if (oldscope != default_scopes)
++ free ((void *) oldscope);
++
++ gaiconf_mtime = st.st_mtim;
++ }
++ else
++ {
++ no_file:
++ free_prefixlist (labellist);
++ free_prefixlist (precedencelist);
++ free_scopelist (scopelist);
++
++ /* If we previously read the file but it is gone now, free the
++ old data and use the builtin one. Leave the reload flag
++ alone. */
++ fini ();
++ }
++}
++
++static void
++gaiconf_reload (void)
++{
++ struct stat64 st;
++ if (__xstat64 (_STAT_VER, GAICONF_FNAME, &st) != 0
++ || memcmp (&st.st_mtim, &gaiconf_mtime, sizeof (gaiconf_mtime)) != 0)
++ gaiconf_init ();
++}
++
+
+ int
+ getaddrinfo (const char *name, const char *service,
+@@ -1517,7 +2407,7 @@ getaddrinfo (const char *name, const cha
+ added at any time. */
+ bool seen_ipv4;
+ bool seen_ipv6;
+- __check_pf (&seen_ipv4, &seen_ipv6);
++ __check_pf (&seen_ipv4, &seen_ipv6, NULL, NULL);
+
+ /* Now make a decision on what we return, if anything. */
+ if (hints->ai_family == PF_UNSPEC && (seen_ipv4 || seen_ipv6))
+@@ -1600,9 +2490,16 @@ getaddrinfo (const char *name, const cha
+ if (j == 0)
+ return EAI_FAMILY;
+
+- if (nresults > 1)
++ if (nresults <= 1)
++ goto do_ret;
++
++ /* Read the config file. */
++ __libc_once_define (static, once);
++ __libc_once (once, gaiconf_init);
++
++ if (!gaiconf_present)
+ {
+- /* Sort results according to RFC 3484. */
++ /* Sort results according to RFC 3484, RHEL4 algorithm. */
+ struct sort_result results[nresults];
+ struct addrinfo *q;
+ struct addrinfo *last = NULL;
+@@ -1671,7 +2568,196 @@ getaddrinfo (const char *name, const cha
+ /* Fill in the canonical name into the new first entry. */
+ p->ai_canonname = canonname;
+ }
++ else
++ {
++ /* Sort results according to RFC 3484, Fedora 9 algorithm. */
++ struct sort_result_new results[nresults];
++ struct sort_order order[nresults];
++ struct addrinfo *q;
++ struct addrinfo *last = NULL;
++ char *canonname = NULL;
++ struct in6addrinfo *in6ai = NULL;
++ size_t in6ailen = 0;
++ bool seen_ipv4 = false;
++ bool seen_ipv6 = false;
++ /* We might need information about what interfaces are available.
++ Also determine whether we have IPv4 or IPv6 interfaces or both. We
++ cannot cache the results since new interfaces could be added at
++ any time. */
++ __check_pf (&seen_ipv4, &seen_ipv6, &in6ai, &in6ailen);
++
++ /* We got all the source addresses we can get, now sort using
++ the information. */
++ struct sort_result_combo src
++ = { .results = results, .nresults = nresults };
++
++ /* If we have information about deprecated and temporary addresses
++ sort the array now. */
++ if (in6ai != NULL)
++ qsort (in6ai, in6ailen, sizeof (*in6ai), in6aicmp);
++
++ int fd = -1;
++ int af = AF_UNSPEC;
++
++ for (i = 0, q = p; q != NULL; ++i, last = q, q = q->ai_next)
++ {
++ results[i].dest_addr = q;
++ results[i].native = -1;
++ order[i].index = i;
++ order[i].src = &src;
++
++ /* If we just looked up the address for a different
++ protocol, reuse the result. */
++ if (last != NULL && last->ai_addrlen == q->ai_addrlen
++ && memcmp (last->ai_addr, q->ai_addr, q->ai_addrlen) == 0)
++ {
++ memcpy (&results[i].source_addr, &results[i - 1].source_addr,
++ results[i - 1].source_addr_len);
++ results[i].source_addr_len = results[i - 1].source_addr_len;
++ results[i].got_source_addr = results[i - 1].got_source_addr;
++ results[i].source_addr_flags = results[i - 1].source_addr_flags;
++ results[i].prefixlen = results[i - 1].prefixlen;
++ results[i].index = results[i - 1].index;
++ }
++ else
++ {
++ results[i].got_source_addr = false;
++ results[i].source_addr_flags = 0;
++ results[i].prefixlen = 0;
++ results[i].index = 0xffffffffu;
++
++ /* We overwrite the type with SOCK_DGRAM since we do not
++ want connect() to connect to the other side. If we
++ cannot determine the source address remember this
++ fact. */
++ if (fd == -1 || (af == AF_INET && q->ai_family == AF_INET6))
++ {
++ if (fd != -1)
++ close_retry:
++ close_not_cancel_no_status (fd);
++ af = q->ai_family;
++ fd = __socket (af, SOCK_DGRAM, IPPROTO_IP);
++ }
++ else
++ {
++ /* Reset the connection. */
++ struct sockaddr sa = { .sa_family = AF_UNSPEC };
++ __connect (fd, &sa, sizeof (sa));
++ }
++
++ socklen_t sl = sizeof (results[i].source_addr);
++ if (fd != -1
++ && __connect (fd, q->ai_addr, q->ai_addrlen) == 0
++ && __getsockname (fd,
++ (struct sockaddr *) &results[i].source_addr,
++ &sl) == 0)
++ {
++ results[i].source_addr_len = sl;
++ results[i].got_source_addr = true;
++
++ if (in6ai != NULL)
++ {
++ /* See whether the source address is on the list of
++ deprecated or temporary addresses. */
++ struct in6addrinfo tmp;
++
++ if (q->ai_family == AF_INET && af == AF_INET)
++ {
++ struct sockaddr_in *sinp
++ = (struct sockaddr_in *) &results[i].source_addr;
++ tmp.addr[0] = 0;
++ tmp.addr[1] = 0;
++ tmp.addr[2] = htonl (0xffff);
++ tmp.addr[3] = sinp->sin_addr.s_addr;
++ }
++ else
++ {
++ struct sockaddr_in6 *sin6p
++ = (struct sockaddr_in6 *) &results[i].source_addr;
++ memcpy (tmp.addr, &sin6p->sin6_addr, IN6ADDRSZ);
++ }
++
++ struct in6addrinfo *found
++ = bsearch (&tmp, in6ai, in6ailen, sizeof (*in6ai),
++ in6aicmp);
++ if (found != NULL)
++ {
++ results[i].source_addr_flags = found->flags;
++ results[i].prefixlen = found->prefixlen;
++ results[i].index = found->index;
++ }
++ }
++
++ if (q->ai_family == AF_INET && af == AF_INET6)
++ {
++ /* We have to convert the address. The socket is
++ IPv6 and the request is for IPv4. */
++ struct sockaddr_in6 *sin6
++ = (struct sockaddr_in6 *) &results[i].source_addr;
++ struct sockaddr_in *sin
++ = (struct sockaddr_in *) &results[i].source_addr;
++ assert (IN6_IS_ADDR_V4MAPPED (sin6->sin6_addr.s6_addr32));
++ sin->sin_family = AF_INET;
++ /* We do not have to initialize sin_port since this
++ fields has the same position and size in the IPv6
++ structure. */
++ assert (offsetof (struct sockaddr_in, sin_port)
++ == offsetof (struct sockaddr_in6, sin6_port));
++ assert (sizeof (sin->sin_port)
++ == sizeof (sin6->sin6_port));
++ memcpy (&sin->sin_addr,
++ &sin6->sin6_addr.s6_addr32[3], INADDRSZ);
++ results[i].source_addr_len = sizeof (struct sockaddr_in);
++ }
++ }
++ else if (errno == EAFNOSUPPORT && af == AF_INET6
++ && q->ai_family == AF_INET)
++ /* This could mean IPv6 sockets are IPv6-only. */
++ goto close_retry;
++ else
++ /* Just make sure that if we have to process the same
++ address again we do not copy any memory. */
++ results[i].source_addr_len = 0;
++ }
++
++ /* Remember the canonical name. */
++ if (q->ai_canonname != NULL)
++ {
++ assert (canonname == NULL);
++ canonname = q->ai_canonname;
++ q->ai_canonname = NULL;
++ }
++ }
++
++ if (fd != -1)
++ close_not_cancel_no_status (fd);
++
++ if (__builtin_expect (gaiconf_reload_flag_ever_set, 0))
++ {
++ __libc_lock_define_initialized (static, lock);
++
++ __libc_lock_lock (lock);
++ if (gaiconf_reload_flag)
++ gaiconf_reload ();
++ qsort (order, nresults, sizeof (order[0]), rfc3484_new_sort);
++ __libc_lock_unlock (lock);
++ }
++ else
++ qsort (order, nresults, sizeof (order[0]), rfc3484_new_sort);
++
++ /* Queue the results up as they come out of sorting. */
++ q = p = results[order[0].index].dest_addr;
++ for (i = 1; i < nresults; ++i)
++ q = q->ai_next = results[order[i].index].dest_addr;
++ q->ai_next = NULL;
++
++ /* Fill in the canonical name into the new first entry. */
++ p->ai_canonname = canonname;
++
++ free (in6ai);
++ }
+
++do_ret:;
+ if (p)
+ {
+ *pai = p;
+--- libc/inet/Makefile.jj 2004-07-26 00:28:37.000000000 -0400
++++ libc/inet/Makefile 2007-12-14 22:52:11.000000000 -0500
+@@ -49,7 +49,7 @@ routines := htonl htons \
+ getipv4sourcefilter setipv4sourcefilter \
+ getsourcefilter setsourcefilter
+
+-aux := check_pf ifreq
++aux := check_pf check_native ifreq
+
+ tests := htontest test_ifindex tst-ntoa tst-ether_aton tst-network \
+ tst-gethnm test-ifaddrs bug-if1
+--- libc/posix/tst-rfc3484-2.c.jj 2007-11-13 10:14:11.610303087 -0500
++++ libc/posix/tst-rfc3484-2.c 2007-12-14 22:52:11.000000000 -0500
+@@ -0,0 +1,169 @@
++#include <stdbool.h>
++#include <stdio.h>
++#include <ifaddrs.h>
++
++/* Internal definitions used in the libc code. */
++#define __getservbyname_r getservbyname_r
++#define __socket socket
++#define __getsockname getsockname
++#define __inet_aton inet_aton
++#define __gethostbyaddr_r gethostbyaddr_r
++#define __gethostbyname2_r gethostbyname2_r
++
++void
++attribute_hidden
++__check_pf (bool *p1, bool *p2, struct in6addrinfo **in6ai, size_t *in6ailen)
++{
++ *p1 = *p2 = true;
++ *in6ai = NULL;
++ *in6ailen = 0;
++}
++void
++attribute_hidden
++__check_native (uint32_t a1_index, int *a1_native,
++ uint32_t a2_index, int *a2_native)
++{
++}
++int
++__idna_to_ascii_lz (const char *input, char **output, int flags)
++{
++ return 0;
++}
++int
++__idna_to_unicode_lzlz (const char *input, char **output, int flags)
++{
++ *output = NULL;
++ return 0;
++}
++
++#include "../sysdeps/posix/getaddrinfo.c"
++
++service_user *__nss_hosts_database attribute_hidden;
++
++
++/* This is the beginning of the real test code. The above defines
++ (among other things) the function rfc3484_sort. */
++
++
++#if __BYTE_ORDER == __BIG_ENDIAN
++# define h(n) n
++#else
++# define h(n) __bswap_constant_32 (n)
++#endif
++
++
++ssize_t
++__getline (char **lineptr, size_t *n, FILE *s)
++{
++ *lineptr = NULL;
++ *n = 0;
++ return 0;
++}
++
++
++static int
++do_test (void)
++{
++ labels = default_labels_new;
++ precedence = default_precedence_new;
++ scopes = default_scopes;
++
++ struct sockaddr_in so1;
++ so1.sin_family = AF_INET;
++ so1.sin_addr.s_addr = h (0xc0a85f19);
++
++ struct sockaddr_in sa1;
++ sa1.sin_family = AF_INET;
++ sa1.sin_addr.s_addr = h (0xe0a85f19);
++
++ struct addrinfo ai1;
++ ai1.ai_family = AF_INET;
++ ai1.ai_addr = (struct sockaddr *) &sa1;
++
++ struct sockaddr_in6 so2;
++ so2.sin6_family = AF_INET6;
++ so2.sin6_addr.s6_addr32[0] = h (0xfec01234);
++ so2.sin6_addr.s6_addr32[1] = 1;
++ so2.sin6_addr.s6_addr32[2] = 1;
++ so2.sin6_addr.s6_addr32[3] = 1;
++
++ struct sockaddr_in6 sa2;
++ sa2.sin6_family = AF_INET6;
++ sa2.sin6_addr.s6_addr32[0] = h (0x07d10001);
++ sa2.sin6_addr.s6_addr32[1] = 1;
++ sa2.sin6_addr.s6_addr32[2] = 1;
++ sa2.sin6_addr.s6_addr32[3] = 1;
++
++ struct addrinfo ai2;
++ ai2.ai_family = AF_INET6;
++ ai2.ai_addr = (struct sockaddr *) &sa2;
++
++
++ struct sort_result_new results[2];
++ struct sort_result_combo combo = { .results = results, .nresults = 2 };
++ struct sort_order order[2];
++
++ results[0].dest_addr = &ai1;
++ results[0].got_source_addr = true;
++ results[0].source_addr_len = sizeof (so1);
++ results[0].source_addr_flags = 0;
++ results[0].prefixlen = 16;
++ results[0].index = 0;
++ memcpy (&results[0].source_addr, &so1, sizeof (so1));
++ order[0].index = 0;
++ order[0].src = &combo;
++
++ results[1].dest_addr = &ai2;
++ results[1].got_source_addr = true;
++ results[1].source_addr_len = sizeof (so2);
++ results[1].source_addr_flags = 0;
++ results[1].prefixlen = 16;
++ results[1].index = 0;
++ memcpy (&results[1].source_addr, &so2, sizeof (so2));
++ order[1].index = 1;
++ order[1].src = &combo;
++
++ qsort (order, 2, sizeof (order[0]), rfc3484_new_sort);
++
++ int result = 0;
++ if (results[order[0].index].dest_addr->ai_family == AF_INET6)
++ {
++ puts ("wrong order in first test");
++ result |= 1;
++ }
++
++
++ /* And again, this time with the reverse starting order. */
++ results[1].dest_addr = &ai1;
++ results[1].got_source_addr = true;
++ results[1].source_addr_len = sizeof (so1);
++ results[1].source_addr_flags = 0;
++ results[1].prefixlen = 16;
++ results[1].index = 0;
++ memcpy (&results[1].source_addr, &so1, sizeof (so1));
++ order[1].index = 1;
++ order[1].src = &combo;
++
++ results[0].dest_addr = &ai2;
++ results[0].got_source_addr = true;
++ results[0].source_addr_len = sizeof (so2);
++ results[0].source_addr_flags = 0;
++ results[0].prefixlen = 16;
++ results[0].index = 0;
++ memcpy (&results[0].source_addr, &so2, sizeof (so2));
++ order[0].index = 0;
++ order[0].src = &combo;
++
++ qsort (order, 2, sizeof (order[0]), rfc3484_new_sort);
++
++ if (results[order[0].index].dest_addr->ai_family == AF_INET6)
++ {
++ puts ("wrong order in second test");
++ result |= 1;
++ }
++
++ return result;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- libc/posix/tst-rfc3484-3.c.jj 2007-11-13 10:14:11.610303087 -0500
++++ libc/posix/tst-rfc3484-3.c 2007-12-14 22:52:11.000000000 -0500
+@@ -0,0 +1,139 @@
++#include <stdbool.h>
++#include <stdio.h>
++#include <ifaddrs.h>
++
++/* Internal definitions used in the libc code. */
++#define __getservbyname_r getservbyname_r
++#define __socket socket
++#define __getsockname getsockname
++#define __inet_aton inet_aton
++#define __gethostbyaddr_r gethostbyaddr_r
++#define __gethostbyname2_r gethostbyname2_r
++
++void
++attribute_hidden
++__check_pf (bool *p1, bool *p2, struct in6addrinfo **in6ai, size_t *in6ailen)
++{
++ *p1 = *p2 = true;
++ *in6ai = NULL;
++ *in6ailen = 0;
++}
++void
++attribute_hidden
++__check_native (uint32_t a1_index, int *a1_native,
++ uint32_t a2_index, int *a2_native)
++{
++}
++int
++__idna_to_ascii_lz (const char *input, char **output, int flags)
++{
++ return 0;
++}
++int
++__idna_to_unicode_lzlz (const char *input, char **output, int flags)
++{
++ *output = NULL;
++ return 0;
++}
++
++#include "../sysdeps/posix/getaddrinfo.c"
++
++service_user *__nss_hosts_database attribute_hidden;
++
++
++/* This is the beginning of the real test code. The above defines
++ (among other things) the function rfc3484_sort. */
++
++
++#if __BYTE_ORDER == __BIG_ENDIAN
++# define h(n) n
++#else
++# define h(n) __bswap_constant_32 (n)
++#endif
++
++struct sockaddr_in addrs[] =
++{
++ { .sin_family = AF_INET, .sin_addr = { h (0xa0a86d1d) } },
++ { .sin_family = AF_INET, .sin_addr = { h (0xa0a85d03) } },
++ { .sin_family = AF_INET, .sin_addr = { h (0xa0a82c3d) } },
++ { .sin_family = AF_INET, .sin_addr = { h (0xa0a86002) } },
++ { .sin_family = AF_INET, .sin_addr = { h (0xa0a802f3) } },
++ { .sin_family = AF_INET, .sin_addr = { h (0xa0a80810) } },
++ { .sin_family = AF_INET, .sin_addr = { h (0xa0a85e02) } },
++ { .sin_family = AF_INET, .sin_addr = { h (0xac162311) } },
++ { .sin_family = AF_INET, .sin_addr = { h (0x0a324572) } }
++};
++#define naddrs (sizeof (addrs) / sizeof (addrs[0]))
++static struct addrinfo ais[naddrs];
++static struct sort_result_new results[naddrs];
++static struct sort_order order[naddrs];
++
++static const int expected[naddrs] =
++ {
++ 8, 0, 1, 2, 3, 4, 5, 6, 7
++ };
++
++static const struct scopeentry new_scopes[] =
++ {
++ { { { 169, 254, 0, 0 } }, h (0xffff0000), 2 },
++ { { { 127, 0, 0, 0 } }, h (0xff000000), 2 },
++ { { { 10, 0, 0, 0 } }, h (0xff000000), 5 },
++ { { { 192, 168, 0, 0 } }, h(0xffff0000), 5 },
++ { { { 0, 0, 0, 0 } }, h (0x00000000), 14 }
++ };
++
++
++ssize_t
++__getline (char **lineptr, size_t *n, FILE *s)
++{
++ *lineptr = NULL;
++ *n = 0;
++ return 0;
++}
++
++
++static int
++do_test (void)
++{
++ labels = default_labels_new;
++ precedence = default_precedence_new;
++ scopes = new_scopes;
++
++ struct sockaddr_in so;
++ so.sin_family = AF_INET;
++ so.sin_addr.s_addr = h (0x0aa85f19);
++ struct sort_result_combo combo = { .results = results, .nresults = naddrs };
++
++ for (int i = 0; i < naddrs; ++i)
++ {
++ ais[i].ai_family = AF_INET;
++ ais[i].ai_addr = (struct sockaddr *) &addrs[i];
++ results[i].dest_addr = &ais[i];
++ results[i].got_source_addr = true;
++ memcpy(&results[i].source_addr, &so, sizeof (so));
++ results[i].source_addr_len = sizeof (so);
++ results[i].source_addr_flags = 0;
++ results[i].prefixlen = 8;
++ results[i].index = 0;
++ order[i].index = i;
++ order[i].src = &combo;
++ }
++
++ qsort (order, naddrs, sizeof (order[0]), rfc3484_new_sort);
++
++ int result = 0;
++ for (int i = 0; i < naddrs; ++i)
++ {
++ struct in_addr addr = ((struct sockaddr_in *) (results[order[i].index].dest_addr->ai_addr))->sin_addr;
++
++ int here = memcmp (&addr, &addrs[expected[i]].sin_addr,
++ sizeof (struct in_addr));
++ printf ("[%d] = %s: %s\n", i, inet_ntoa (addr), here ? "FAIL" : "OK");
++ result |= here;
++ }
++
++ return result;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- libc/posix/Makefile.jj 2007-12-14 22:52:09.000000000 -0500
++++ libc/posix/Makefile 2007-12-14 22:52:11.000000000 -0500
+@@ -88,7 +88,8 @@ tests := tstgetopt testfnm runtests run
+ tst-execvp1 tst-execvp2 tst-execlp1 tst-execlp2 \
+ tst-execv1 tst-execv2 tst-execl1 tst-execl2 \
+ tst-execve1 tst-execve2 tst-execle1 tst-execle2 \
+- tst-execvp3 tst-execvp4 tst-rfc3484
++ tst-execvp3 tst-execvp4 tst-rfc3484 tst-rfc3484-2 \
++ tst-rfc3484-3
+ xtests := bug-ga2
+ ifeq (yes,$(build-shared))
+ test-srcs := globtest
+--- libc/posix/tst-rfc3484.c.jj 2007-12-14 22:52:08.000000000 -0500
++++ libc/posix/tst-rfc3484.c 2007-12-14 22:52:11.000000000 -0500
+@@ -1,5 +1,6 @@
+ #include <stdbool.h>
+ #include <stdio.h>
++#include <ifaddrs.h>
+
+ /* Internal definitions used in the libc code. */
+ #define __getservbyname_r getservbyname_r
+@@ -8,12 +9,21 @@
+ #define __inet_aton inet_aton
+ #define __gethostbyaddr_r gethostbyaddr_r
+ #define __gethostbyname2_r gethostbyname2_r
++#define __getline getline
+
+ void
+ attribute_hidden
+-__check_pf (bool *p1, bool *p2)
++__check_pf (bool *p1, bool *p2, struct in6addrinfo **in6ai, size_t *in6ailen)
+ {
+ *p1 = *p2 = true;
++ *in6ai = NULL;
++ *in6ailen = 0;
++}
++void
++attribute_hidden
++__check_native (uint32_t a1_index, int *a1_native,
++ uint32_t a2_index, int *a2_native)
++{
+ }
+ int
+ __idna_to_ascii_lz (const char *input, char **output, int flags)
+@@ -68,6 +78,8 @@ do_test (void)
+ so.sin_family = AF_INET;
+ so.sin_addr.s_addr = h (0xc0a85f19);
+
++ scopes = default_scopes;
++
+ for (int i = 0; i < naddrs; ++i)
+ {
+ ais[i].ai_family = AF_INET;
--- /dev/null
+2007-12-16 Ulrich Drepper <drepper@redhat.com>
+
+ * malloc/malloc.c (public_mTRIm): Iterate over all arenas and call
+ mTRIm for all of them.
+ (mTRIm): Additionally iterate over all free blocks and use madvise
+ to free memory for all those blocks which contain at least one
+ memory page.
+ * malloc/tst-trim1.c: New file.
+ * malloc/Makefile (tests): Add tst-trim1.
+
+--- libc/malloc/Makefile 21 May 2007 16:12:25 -0000 1.55
++++ libc/malloc/Makefile 16 Dec 2007 22:57:50 -0000 1.56
+@@ -26,7 +26,7 @@ all:
+ dist-headers := malloc.h
+ headers := $(dist-headers) obstack.h mcheck.h
+ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
+- tst-mallocstate
++ tst-mallocstate tst-trim1
+ test-srcs = tst-mtrace
+
+ distribute = thread-m.h mtrace.pl mcheck-init.c stackinfo.h memusage.h \
+--- libc/malloc/malloc.c 11 Dec 2007 23:46:31 -0000 1.182
++++ libc/malloc/malloc.c 16 Dec 2007 22:52:58 -0000 1.183
+@@ -1509,7 +1509,7 @@ static Void_t* _int_pvalloc(mstate, siz
+ /*static Void_t* cALLOc(size_t, size_t);*/
+ static Void_t** _int_icalloc(mstate, size_t, size_t, Void_t**);
+ static Void_t** _int_icomalloc(mstate, size_t, size_t*, Void_t**);
+-static int mTRIm(size_t);
++static int mTRIm(mstate, size_t);
+ static size_t mUSABLe(Void_t*);
+ static void mSTATs(void);
+ static int mALLOPt(int, int);
+@@ -3794,13 +3794,22 @@ public_cFREe(Void_t* m)
+ int
+ public_mTRIm(size_t s)
+ {
+- int result;
++ int result = 0;
+
+ if(__malloc_initialized < 0)
+ ptmalloc_init ();
+- (void)mutex_lock(&main_arena.mutex);
+- result = mTRIm(s);
+- (void)mutex_unlock(&main_arena.mutex);
++
++ mstate ar_ptr = &main_arena;
++ do
++ {
++ (void) mutex_lock (&ar_ptr->mutex);
++ result |= mTRIm (ar_ptr, s);
++ (void) mutex_unlock (&ar_ptr->mutex);
++
++ ar_ptr = ar_ptr->next;
++ }
++ while (ar_ptr != &main_arena);
++
+ return result;
+ }
+
+@@ -5186,20 +5195,60 @@ _int_pvalloc(av, bytes) mstate av, size_
+ */
+
+ #if __STD_C
+-int mTRIm(size_t pad)
++static int mTRIm(mstate av, size_t pad)
+ #else
+-int mTRIm(pad) size_t pad;
++static int mTRIm(av, pad) mstate av; size_t pad;
+ #endif
+ {
+- mstate av = &main_arena; /* already locked */
+-
+ /* Ensure initialization/consolidation */
+- malloc_consolidate(av);
++ malloc_consolidate (av);
++
++ const size_t ps = mp_.pagesize;
++ int psindex = bin_index (ps);
++ const size_t psm1 = ps - 1;
++
++ int result = 0;
++ for (int i = 1; i < NBINS; ++i)
++ if (i == 1 || i >= psindex)
++ {
++ mbinptr bin = bin_at (av, i);
++
++ for (mchunkptr p = last (bin); p != bin; p = p->bk)
++ {
++ INTERNAL_SIZE_T size = chunksize (p);
++
++ if (size > psm1 + sizeof (struct malloc_chunk))
++ {
++ /* See whether the chunk contains at least one unused page. */
++ char *paligned_mem = (char *) (((uintptr_t) p
++ + sizeof (struct malloc_chunk)
++ + psm1) & ~psm1);
++
++ assert ((char *) chunk2mem (p) + 4 * SIZE_SZ <= paligned_mem);
++ assert ((char *) p + size > paligned_mem);
++
++ /* This is the size we could potentially free. */
++ size -= paligned_mem - (char *) p;
++
++ if (size > psm1)
++ {
++#ifdef MALLOC_DEBUG
++ /* When debugging we simulate destroying the memory
++ content. */
++ memset (paligned_mem, 0x89, size & ~psm1);
++#endif
++ madvise (paligned_mem, size & ~psm1, MADV_DONTNEED);
++
++ result = 1;
++ }
++ }
++ }
++ }
+
+ #ifndef MORECORE_CANNOT_TRIM
+- return sYSTRIm(pad, av);
++ return result | (av == &main_arena ? sYSTRIm (pad, av) : 0);
+ #else
+- return 0;
++ return result;
+ #endif
+ }
+
+--- libc/malloc/tst-trim1.c 1 Jan 1970 00:00:00 -0000
++++ libc/malloc/tst-trim1.c 16 Dec 2007 22:57:25 -0000 1.1
+@@ -0,0 +1,56 @@
++#include <malloc.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++#define N 10000
++
++static void *arr[N];
++
++static int
++do_test (void)
++{
++ for (int i = 0; i < N; ++i)
++ {
++ size_t size = random () % 16384;
++
++ if ((arr[i] = malloc (size)) == NULL)
++ {
++ nomem:
++ puts ("not enough memory");
++ return 0;
++ }
++
++ memset (arr[i], size, size);
++ }
++
++ void *p = malloc (256);
++ if (p == NULL)
++ goto nomem;
++ memset (p, 1, 256);
++
++ puts ("==================================================================");
++
++ for (int i = 0; i < N; ++i)
++ if (i % 13 != 0)
++ free (arr[i]);
++
++ puts ("==================================================================");
++
++ malloc_trim (0);
++
++ puts ("==================================================================");
++
++ p = malloc (30000);
++ if (p == NULL)
++ goto nomem;
++
++ memset (p, 2, 30000);
++
++ malloc_trim (0);
++
++ return 0;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
--- /dev/null
+2007-12-17 Ulrich Drepper <drepper@redhat.com>
+
+ * malloc/malloc.c (public_cALLOc): For arena other than
+ main_arena, count all bytes inside the mprotect_size range of the
+ heap as uninitialized.
+
+--- libc/malloc/malloc.c 16 Dec 2007 22:52:58 -0000 1.183
++++ libc/malloc/malloc.c 17 Dec 2007 18:43:50 -0000 1.184
+@@ -3886,6 +3886,12 @@ public_cALLOc(size_t n, size_t elem_size
+ oldtopsize < mp_.sbrk_base + av->max_system_mem - (char *)oldtop)
+ oldtopsize = (mp_.sbrk_base + av->max_system_mem - (char *)oldtop);
+ #endif
++ if (av != &main_arena)
++ {
++ heap_info *heap = heap_for_ptr (oldtop);
++ if (oldtopsize < (char *) heap + heap->mprotect_size - (char *) oldtop)
++ oldtopsize = (char *) heap + heap->mprotect_size - (char *) oldtop;
++ }
+ #endif
+ mem = _int_malloc(av, sz);
+
--- /dev/null
+--- libc/fedora/glibc_post_upgrade.c 25 Aug 2007 19:15:32 -0000 1.1.2.10
++++ libc/fedora/glibc_post_upgrade.c 28 Mar 2008 14:05:57 -0000 1.1.2.11
+@@ -182,6 +182,7 @@ main (void)
+ /* Check if we can safely condrestart sshd. */
+ if (access ("/sbin/service", X_OK) == 0
+ && access ("/usr/sbin/sshd", X_OK) == 0
++ && access ("/etc/rc.d/init.d/sshd", X_OK) == 0
+ && access ("/bin/bash", X_OK) == 0)
+ {
+ if (check_elf ("/usr/sbin/sshd"))
--- /dev/null
+2008-03-11 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/unix/sysv/linux/x86_64/lowlevellock.S
+ (__lll_mutex_timedlock_wait): Use correct pointer when we don't
+ call into the kernel to delay and cmpxchgl fails. Patch by
+ Bryan Mason <bmason@redhat.com>.
+
+--- libc/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S.jj 2007-06-22 11:46:42.000000000 -0400
++++ libc/nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S 2008-03-11 06:07:39.000000000 -0400
+@@ -201,7 +201,7 @@ __lll_mutex_timedlock_wait:
+
+ /* Make sure the current holder knows we are going to sleep. */
+ movl %edx, %eax
+- xchgl %eax, (%rdi)
++ xchgl %eax, (%r12)
+ testl %eax, %eax
+ jz 6b
+ jmp 1b
--- /dev/null
+2007-01-03 Jakub Jelinek <jakub@redhat.com>
+
+ * posix/execvp.c: Include alloca.h.
+ (allocate_scripts_argv): Renamed to...
+ (scripts_argv): ... this. Don't allocate buffer here nor count
+ arguments.
+ (execvp): Use alloca if possible.
+ * posix/Makefile: Add rules to build and run tst-vfork3 test.
+ * posix/tst-vfork3.c: New test.
+
+--- libc/posix/Makefile 7 Sep 2006 13:50:05 -0000 1.193
++++ libc/posix/Makefile 3 Jan 2007 23:02:10 -0000 1.194
+@@ -83,7 +83,7 @@
+ bug-regex25 bug-regex26 bug-regex27 bug-regex28 \
+ tst-nice tst-nanosleep tst-regex2 \
+ transbug tst-rxspencer tst-pcre tst-boost \
+- bug-ga1 tst-vfork1 tst-vfork2 tst-waitid \
++ bug-ga1 tst-vfork1 tst-vfork2 tst-vfork3 tst-waitid \
+ tst-getaddrinfo2 bug-glob1 bug-glob2 tst-sysconf \
+ tst-execvp1 tst-execvp2 tst-execlp1 tst-execlp2 \
+ tst-execv1 tst-execv2 tst-execl1 tst-execl2 \
+@@ -108,7 +108,7 @@
+ tst-rxspencer-mem tst-rxspencer.mtrace tst-getconf.out \
+ tst-pcre-mem tst-pcre.mtrace tst-boost-mem tst-boost.mtrace \
+ bug-ga2.mtrace bug-ga2-mem bug-glob2.mtrace bug-glob2-mem \
+- getconf.speclist
++ tst-vfork3-mem tst-vfork3.mtrace getconf.speclist
+
+ include ../Rules
+
+@@ -174,6 +174,7 @@
+ tst-spawn-ARGS = -- $(built-program-cmd)
+ tst-dir-ARGS = `pwd` `cd $(common-objdir)/$(subdir); pwd` `cd $(common-objdir); pwd` $(objpfx)tst-dir
+ tst-chmod-ARGS = `pwd`
++tst-vfork3-ARGS = --test-dir=$(objpfx)
+
+ tst-fnmatch-ENV = LOCPATH=$(common-objpfx)localedata
+ tst-regexloc-ENV = LOCPATH=$(common-objpfx)localedata
+@@ -218,7 +219,7 @@
+ tests: $(objpfx)bug-regex2-mem $(objpfx)bug-regex14-mem \
+ $(objpfx)bug-regex21-mem $(objpfx)tst-rxspencer-mem \
+ $(objpfx)tst-pcre-mem $(objpfx)tst-boost-mem $(objpfx)tst-getconf.out \
+- $(objpfx)bug-glob2-mem
++ $(objpfx)bug-glob2-mem $(objpfx)tst-vfork3-mem
+ xtests: $(objpfx)bug-ga2-mem
+ endif
+
+@@ -245,6 +246,11 @@
+ $(objpfx)bug-regex21-mem: $(objpfx)bug-regex21.out
+ $(common-objpfx)malloc/mtrace $(objpfx)bug-regex21.mtrace > $@
+
++tst-vfork3-ENV = MALLOC_TRACE=$(objpfx)tst-vfork3.mtrace
++
++$(objpfx)tst-vfork3-mem: $(objpfx)tst-vfork3.out
++ $(common-objpfx)malloc/mtrace $(objpfx)tst-vfork3.mtrace > $@
++
+ # tst-rxspencer.mtrace is generated only when run without --utf8
+ # option, since otherwise the file has almost 100M and takes very long
+ # time to process.
+--- libc/posix/execvp.c 24 Jul 2005 21:38:43 -0000 1.26
++++ libc/posix/execvp.c 3 Jan 2007 23:01:15 -0000 1.27
+@@ -16,6 +17,7 @@
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
++#include <alloca.h>
+ #include <unistd.h>
+ #include <stdarg.h>
+ #include <stdbool.h>
+@@ -27,29 +29,18 @@
+
+ /* The file is accessible but it is not an executable file. Invoke
+ the shell to interpret it as a script. */
+-static char **
++static void
+ internal_function
+-allocate_scripts_argv (const char *file, char *const argv[])
++scripts_argv (const char *file, char *const argv[], int argc, char **new_argv)
+ {
+- /* Count the arguments. */
+- int argc = 0;
+- while (argv[argc++])
+- ;
+-
+ /* Construct an argument list for the shell. */
+- char **new_argv = (char **) malloc ((argc + 1) * sizeof (char *));
+- if (new_argv != NULL)
++ new_argv[0] = (char *) _PATH_BSHELL;
++ new_argv[1] = (char *) file;
++ while (argc > 1)
+ {
+- new_argv[0] = (char *) _PATH_BSHELL;
+- new_argv[1] = (char *) file;
+- while (argc > 1)
+- {
+- new_argv[argc] = argv[argc - 1];
+- --argc;
+- }
++ new_argv[argc] = argv[argc - 1];
++ --argc;
+ }
+-
+- return new_argv;
+ }
+
+
+@@ -67,8 +58,6 @@ execvp (file, argv)
+ return -1;
+ }
+
+- char **script_argv = NULL;
+-
+ if (strchr (file, '/') != NULL)
+ {
+ /* Don't search when it contains a slash. */
+@@ -76,46 +65,71 @@ execvp (file, argv)
+
+ if (errno == ENOEXEC)
+ {
+- script_argv = allocate_scripts_argv (file, argv);
++ /* Count the arguments. */
++ int argc = 0;
++ while (argv[argc++])
++ ;
++ size_t len = (argc + 1) * sizeof (char *);
++ char **script_argv;
++ void *ptr = NULL;
++ if (__libc_use_alloca (len))
++ script_argv = alloca (len);
++ else
++ script_argv = ptr = malloc (len);
++
+ if (script_argv != NULL)
+ {
++ scripts_argv (file, argv, argc, script_argv);
+ __execve (script_argv[0], script_argv, __environ);
+
+- free (script_argv);
++ free (ptr);
+ }
+ }
+ }
+ else
+ {
++ size_t pathlen;
++ size_t alloclen = 0;
+ char *path = getenv ("PATH");
++ if (path == NULL)
++ {
++ pathlen = confstr (_CS_PATH, (char *) NULL, 0);
++ alloclen = pathlen + 1;
++ }
++ else
++ pathlen = strlen (path);
++
++ size_t len = strlen (file) + 1;
++ alloclen += pathlen + len + 1;
++
++ char *name;
+ char *path_malloc = NULL;
++ if (__libc_use_alloca (alloclen))
++ name = alloca (alloclen);
++ else
++ {
++ path_malloc = name = malloc (alloclen);
++ if (name == NULL)
++ return -1;
++ }
++
+ if (path == NULL)
+ {
+ /* There is no `PATH' in the environment.
+ The default search path is the current directory
+ followed by the path `confstr' returns for `_CS_PATH'. */
+- size_t len = confstr (_CS_PATH, (char *) NULL, 0);
+- path = (char *) malloc (1 + len);
+- if (path == NULL)
+- return -1;
++ path = name + pathlen + len + 1;
+ path[0] = ':';
+- (void) confstr (_CS_PATH, path + 1, len);
+- path_malloc = path;
++ (void) confstr (_CS_PATH, path + 1, pathlen);
+ }
+
+- size_t len = strlen (file) + 1;
+- size_t pathlen = strlen (path);
+- char *name = malloc (pathlen + len + 1);
+- if (name == NULL)
+- {
+- free (path_malloc);
+- return -1;
+- }
+ /* Copy the file name at the top. */
+ name = (char *) memcpy (name + pathlen + 1, file, len);
+ /* And add the slash. */
+ *--name = '/';
+
++ char **script_argv = NULL;
++ void *script_argv_malloc = NULL;
+ bool got_eacces = false;
+ char *p = path;
+ do
+@@ -139,7 +153,15 @@ execvp (file, argv)
+ {
+ if (script_argv == NULL)
+ {
+- script_argv = allocate_scripts_argv (startp, argv);
++ /* Count the arguments. */
++ int argc = 0;
++ while (argv[argc++])
++ ;
++ size_t arglen = (argc + 1) * sizeof (char *);
++ if (__libc_use_alloca (alloclen + arglen))
++ script_argv = alloca (arglen);
++ else
++ script_argv = script_argv_malloc = malloc (arglen);
+ if (script_argv == NULL)
+ {
+ /* A possible EACCES error is not as important as
+@@ -147,6 +169,7 @@ execvp (file, argv)
+ got_eacces = false;
+ break;
+ }
++ scripts_argv (startp, argv, argc, script_argv);
+ }
+
+ __execve (script_argv[0], script_argv, __environ);
+@@ -184,11 +207,10 @@ execvp (file, argv)
+ /* We tried every element and none of them worked. */
+ if (got_eacces)
+ /* At least one failure was due to permissions, so report that
+- error. */
++ error. */
+ __set_errno (EACCES);
+
+- free (script_argv);
+- free (name - pathlen);
++ free (script_argv_malloc);
+ free (path_malloc);
+ }
+
+--- libc/posix/tst-vfork3.c 1 Jan 1970 00:00:00 -0000
++++ libc/posix/tst-vfork3.c 3 Jan 2007 23:01:58 -0000 1.1
+@@ -0,0 +1,224 @@
++/* Test for vfork functions.
++ Copyright (C) 2007 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Jakub Jelinek <jakub@redhat.com>, 2007.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <errno.h>
++#include <fcntl.h>
++#include <mcheck.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include <sys/wait.h>
++
++static int do_test (void);
++static void do_prepare (void);
++char *tmpdirname;
++
++#define TEST_FUNCTION do_test ()
++#define PREPARE(argc, argv) do_prepare ()
++#include "../test-skeleton.c"
++
++static int
++do_test (void)
++{
++ mtrace ();
++
++ const char *path = getenv ("PATH");
++ if (path == NULL)
++ path = "/bin";
++ char pathbuf[strlen (tmpdirname) + 1 + strlen (path) + 1];
++ strcpy (stpcpy (stpcpy (pathbuf, tmpdirname), ":"), path);
++ if (setenv ("PATH", pathbuf, 1) < 0)
++ {
++ puts ("setenv failed");
++ return 1;
++ }
++
++ size_t i;
++ char *argv[3] = { (char *) "script1.sh", (char *) "1", NULL };
++ for (i = 0; i < 5; i++)
++ {
++ pid_t pid = vfork ();
++ if (pid < 0)
++ {
++ printf ("vfork failed: %m\n");
++ return 1;
++ }
++ else if (pid == 0)
++ {
++ execvp ("script1.sh", argv);
++ _exit (errno);
++ }
++ int status;
++ if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
++ {
++ puts ("waitpid failed");
++ return 1;
++ }
++ else if (status != 0)
++ {
++ if (WIFEXITED (status))
++ printf ("script1.sh failed with status %d\n",
++ WEXITSTATUS (status));
++ else
++ printf ("script1.sh kill by signal %d\n",
++ WTERMSIG (status));
++ return 1;
++ }
++ }
++
++ argv[0] = (char *) "script2.sh";
++ argv[1] = (char *) "2";
++ for (i = 0; i < 5; i++)
++ {
++ pid_t pid = vfork ();
++ if (pid < 0)
++ {
++ printf ("vfork failed: %m\n");
++ return 1;
++ }
++ else if (pid == 0)
++ {
++ execvp ("script2.sh", argv);
++ _exit (errno);
++ }
++ int status;
++ if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
++ {
++ puts ("waitpid failed");
++ return 1;
++ }
++ else if (status != 0)
++ {
++ printf ("script2.sh failed with status %d\n", status);
++ return 1;
++ }
++ }
++
++ for (i = 0; i < 5; i++)
++ {
++ pid_t pid = vfork ();
++ if (pid < 0)
++ {
++ printf ("vfork failed: %m\n");
++ return 1;
++ }
++ else if (pid == 0)
++ {
++ execlp ("script2.sh", "script2.sh", "3", NULL);
++ _exit (errno);
++ }
++ int status;
++ if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
++ {
++ puts ("waitpid failed");
++ return 1;
++ }
++ else if (status != 0)
++ {
++ printf ("script2.sh failed with status %d\n", status);
++ return 1;
++ }
++ }
++
++ unsetenv ("PATH");
++ argv[0] = (char *) "echo";
++ argv[1] = (char *) "script 4";
++ for (i = 0; i < 5; i++)
++ {
++ pid_t pid = vfork ();
++ if (pid < 0)
++ {
++ printf ("vfork failed: %m\n");
++ return 1;
++ }
++ else if (pid == 0)
++ {
++ execvp ("echo", argv);
++ _exit (errno);
++ }
++ int status;
++ if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
++ {
++ puts ("waitpid failed");
++ return 1;
++ }
++ else if (status != 0)
++ {
++ printf ("echo failed with status %d\n", status);
++ return 1;
++ }
++ }
++
++ return 0;
++}
++
++static void
++do_prepare (void)
++{
++ size_t len = strlen (test_dir) + sizeof ("/tst-vfork3.XXXXXX");
++ tmpdirname = malloc (len);
++ char *script1 = malloc (len + sizeof "/script1.sh");
++ char *script2 = malloc (len + sizeof "/script2.sh");
++ if (tmpdirname == NULL || script1 == NULL || script2 == NULL)
++ {
++ puts ("out of memory");
++ exit (1);
++ }
++ strcpy (stpcpy (tmpdirname, test_dir), "/tst-vfork3.XXXXXX");
++
++ tmpdirname = mkdtemp (tmpdirname);
++ if (tmpdirname == NULL)
++ {
++ puts ("could not create temporary directory");
++ exit (1);
++ }
++
++ strcpy (stpcpy (script1, tmpdirname), "/script1.sh");
++ strcpy (stpcpy (script2, tmpdirname), "/script2.sh");
++
++ /* Need to make sure tmpdirname is at the end of the linked list. */
++ add_temp_file (script1);
++ add_temp_file (tmpdirname);
++ add_temp_file (script2);
++
++ const char content1[] = "#!/bin/sh\necho script $1\n";
++ int fd = open (script1, O_WRONLY | O_CREAT, 0700);
++ if (fd < 0
++ || TEMP_FAILURE_RETRY (write (fd, content1, sizeof content1))
++ != sizeof content1
++ || fchmod (fd, S_IRUSR | S_IXUSR) < 0)
++ {
++ printf ("Could not write %s\n", script1);
++ exit (1);
++ }
++ close (fd);
++
++ const char content2[] = "echo script $1\n";
++ fd = open (script2, O_WRONLY | O_CREAT, 0700);
++ if (fd < 0
++ || TEMP_FAILURE_RETRY (write (fd, content2, sizeof content2))
++ != sizeof content2
++ || fchmod (fd, S_IRUSR | S_IXUSR) < 0)
++ {
++ printf ("Could not write %s\n", script2);
++ exit (1);
++ }
++ close (fd);
++}
--- /dev/null
+2008-07-15 Ulrich Drepper <drepper@redhat.com>
+
+ * stdio-common/vfprintf.c (_IO_helper_overflow): In case _IO_sputn
+ doesn't manage to write anything, fail.
+
+--- libc/stdio-common/vfprintf.c 8 Apr 2008 07:59:50 -0000 1.128.2.13
++++ libc/stdio-common/vfprintf.c 16 Jul 2008 09:47:15 -0000
+@@ -2080,6 +2080,11 @@ _IO_helper_overflow (_IO_FILE *s, int c)
+ {
+ _IO_size_t written = _IO_sputn (target, s->_wide_data->_IO_write_base,
+ used);
++ if (written == 0 || written == WEOF)
++ return WEOF;
++ __wmemmove (s->_wide_data->_IO_write_base,
++ s->_wide_data->_IO_write_base + written,
++ used - written);
+ s->_wide_data->_IO_write_ptr -= written;
+ }
+ #else
+@@ -2087,6 +2092,10 @@ _IO_helper_overflow (_IO_FILE *s, int c)
+ if (used)
+ {
+ _IO_size_t written = _IO_sputn (target, s->_IO_write_base, used);
++ if (written == 0 || written == EOF)
++ return EOF;
++ memmove (s->_IO_write_base, s->_IO_write_base + written,
++ used - written);
+ s->_IO_write_ptr -= written;
+ }
+ #endif
--- /dev/null
+2008-09-12 Flavio Leitner <fleitner@redhat.com>
+ Ulrich Drepper <drepper@redhat.com>
+
+ * malloc/malloc.c (public_vALLOc): Try other arenas in case
+ _int_valloc fails.
+ (public_pVALLOc): Likewise.
+
+--- libc/malloc/malloc.c 4 Mar 2008 18:36:04 -0000 1.188
++++ libc/malloc/malloc.c 12 Sep 2008 18:18:25 -0000 1.189
+@@ -3800,17 +3800,39 @@ public_vALLOc(size_t bytes)
+ if(__malloc_initialized < 0)
+ ptmalloc_init ();
+
++ size_t pagesz = mp_.pagesize;
++
+ __malloc_ptr_t (*hook) __MALLOC_PMT ((size_t, size_t,
+ __const __malloc_ptr_t)) =
+ __memalign_hook;
+ if (hook != NULL)
+- return (*hook)(mp_.pagesize, bytes, RETURN_ADDRESS (0));
++ return (*hook)(pagesz, bytes, RETURN_ADDRESS (0));
+
+- arena_get(ar_ptr, bytes + mp_.pagesize + MINSIZE);
++ arena_get(ar_ptr, bytes + pagesz + MINSIZE);
+ if(!ar_ptr)
+ return 0;
+ p = _int_valloc(ar_ptr, bytes);
+ (void)mutex_unlock(&ar_ptr->mutex);
++ if(!p) {
++ /* Maybe the failure is due to running out of mmapped areas. */
++ if(ar_ptr != &main_arena) {
++ (void)mutex_lock(&main_arena.mutex);
++ p = _int_memalign(&main_arena, pagesz, bytes);
++ (void)mutex_unlock(&main_arena.mutex);
++ } else {
++#if USE_ARENAS
++ /* ... or sbrk() has failed and there is still a chance to mmap() */
++ ar_ptr = arena_get2(ar_ptr->next ? ar_ptr : 0, bytes);
++ if(ar_ptr) {
++ p = _int_memalign(ar_ptr, pagesz, bytes);
++ (void)mutex_unlock(&ar_ptr->mutex);
++ }
++#endif
++ }
++ }
++ assert(!p || chunk_is_mmapped(mem2chunk(p)) ||
++ ar_ptr == arena_for_chunk(mem2chunk(p)));
++
+ return p;
+ }
+
+@@ -3823,17 +3845,40 @@ public_pVALLOc(size_t bytes)
+ if(__malloc_initialized < 0)
+ ptmalloc_init ();
+
++ size_t pagesz = mp_.pagesize;
++ size_t page_mask = mp_.pagesize - 1;
++ size_t rounded_bytes = (bytes + page_mask) & ~(page_mask);
++
+ __malloc_ptr_t (*hook) __MALLOC_PMT ((size_t, size_t,
+ __const __malloc_ptr_t)) =
+ __memalign_hook;
+ if (hook != NULL)
+- return (*hook)(mp_.pagesize,
+- (bytes + mp_.pagesize - 1) & ~(mp_.pagesize - 1),
+- RETURN_ADDRESS (0));
++ return (*hook)(pagesz, rounded_bytes, RETURN_ADDRESS (0));
+
+- arena_get(ar_ptr, bytes + 2*mp_.pagesize + MINSIZE);
++ arena_get(ar_ptr, bytes + 2*pagesz + MINSIZE);
+ p = _int_pvalloc(ar_ptr, bytes);
+ (void)mutex_unlock(&ar_ptr->mutex);
++ if(!p) {
++ /* Maybe the failure is due to running out of mmapped areas. */
++ if(ar_ptr != &main_arena) {
++ (void)mutex_lock(&main_arena.mutex);
++ p = _int_memalign(&main_arena, pagesz, rounded_bytes);
++ (void)mutex_unlock(&main_arena.mutex);
++ } else {
++#if USE_ARENAS
++ /* ... or sbrk() has failed and there is still a chance to mmap() */
++ ar_ptr = arena_get2(ar_ptr->next ? ar_ptr : 0,
++ bytes + 2*pagesz + MINSIZE);
++ if(ar_ptr) {
++ p = _int_memalign(ar_ptr, pagesz, rounded_bytes);
++ (void)mutex_unlock(&ar_ptr->mutex);
++ }
++#endif
++ }
++ }
++ assert(!p || chunk_is_mmapped(mem2chunk(p)) ||
++ ar_ptr == arena_for_chunk(mem2chunk(p)));
++
+ return p;
+ }
+
--- /dev/null
+2008-09-22 Deborah S. Townsend <dstownse@us.ibm.com>
+
+ * sysdeps/s390/s390-64/s390x-mcount.S: Replace ahi with aghi.
+ * sysdeps/unix/sysv/linux/s390/s390-64/socket.S: Likewise.
+
+--- libc/sysdeps/s390/s390-64/s390x-mcount.S 26 May 2005 14:30:45 -0000 1.3
++++ libc/sysdeps/s390/s390-64/s390x-mcount.S 23 Sep 2008 17:17:30 -0000 1.4
+@@ -64,7 +64,7 @@ C_LABEL(_mcount)
+ /* Pop the saved registers. Please note that `mcount' has no
+ return value. */
+ lmg %r14,%r5,160(%r15)
+- ahi %r15,224
++ aghi %r15,224
+ br %r14
+ ASM_SIZE_DIRECTIVE(C_SYMBOL_NAME(_mcount))
+
+--- libc/sysdeps/unix/sysv/linux/s390/s390-64/socket.S 20 Dec 2005 06:55:02 -0000 1.7
++++ libc/sysdeps/unix/sysv/linux/s390/s390-64/socket.S 23 Sep 2008 17:17:30 -0000 1.8
+@@ -61,7 +61,7 @@ ENTRY(__socket)
+ cfi_offset (%r6,-112)
+ lgr %r1,%r15
+ lg %r0,8(%r15) /* Load eos. */
+- ahi %r15,-208 /* Buy stack space. */
++ aghi %r15,-208 /* Buy stack space. */
+ cfi_adjust_cfa_offset (208)
+ stg %r1,0(%r15) /* Store back chain. */
+ stg %r0,8(%r15) /* Store eos. */
--- /dev/null
+2008-10-17 Jakub Jelinek <jakub@redhat.com>
+
+ * elf/Makefile: Add rules to build and run tst-tls17.
+ * elf/tst-tls17.c: New test.
+ * elf/tst-tlsmod17a.c: New file.
+ * elf/tst-tlsmod17b.c: Likewise.
+
+2008-10-16 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/generic/dl-tls.c (_dl_update_slotinfo): Copy all of the
+ initial DTV.
+
+--- libc/elf/Makefile 19 Aug 2008 00:18:58 -0000 1.328
++++ libc/elf/Makefile 17 Oct 2008 15:23:58 -0000 1.329
+@@ -158,7 +158,7 @@ tests += loadtest restest1 preloadtest l
+ neededtest3 neededtest4 unload2 lateglobal initfirst global \
+ restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \
+ circleload1 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 tst-tls8 \
+- tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-align \
++ tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-tls17 tst-align \
+ tst-align2 $(tests-execstack-$(have-z-execstack)) tst-dlmodcount \
+ tst-dlopenrpath tst-deep1 tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
+ unload3 unload4 unload5 unload6 unload7 tst-global1 order2 \
+@@ -174,6 +174,7 @@ ifeq (yesyes,$(have-fpie)$(build-shared)
+ tests: $(objpfx)tst-pie1.out
+ endif
+ tests: $(objpfx)tst-leaks1-mem
++tlsmod17a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+ testobj1_1 failobj constload2 constload3 unloadmod \
+ dep1 dep2 dep3 dep4 $(modules-vis-$(have-protected)) \
+@@ -191,6 +192,8 @@ modules-names = testobj1 testobj2 testob
+ tst-tlsmod5 tst-tlsmod6 tst-tlsmod7 tst-tlsmod8 \
+ tst-tlsmod9 tst-tlsmod10 tst-tlsmod11 tst-tlsmod12 \
+ tst-tlsmod13 tst-tlsmod13a tst-tlsmod14a tst-tlsmod14b \
++ $(patsubst %,tst-tlsmod17a%,$(tlsmod17a-suffixes)) \
++ tst-tlsmod17b \
+ circlemod1 circlemod1a circlemod2 circlemod2a \
+ circlemod3 circlemod3a \
+ reldep8mod1 reldep8mod2 reldep8mod3 \
+@@ -694,6 +697,13 @@ $(objpfx)tst-tls13.out: $(objpfx)tst-tls
+ $(objpfx)tst-tls14: $(objpfx)tst-tlsmod14a.so $(libdl)
+ $(objpfx)tst-tls14.out:$(objpfx)tst-tlsmod14b.so
+
++$(objpfx)tst-tls17: $(libdl)
++$(objpfx)tst-tls17.out: $(objpfx)tst-tlsmod17b.so
++$(patsubst %,$(objpfx)tst-tlsmod17a%.os,$(tlsmod17a-suffixes)): $(objpfx)tst-tlsmod17a%.os : tst-tlsmod17a.c
++ $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ -DN=$* -DNOT_IN_libc=1 $<
++$(patsubst %,$(objpfx)tst-tlsmod17a%.so,$(tlsmod17a-suffixes)): $(objpfx)tst-tlsmod17a%.so: $(objpfx)ld.so
++$(objpfx)tst-tlsmod17b.so: $(patsubst %,$(objpfx)tst-tlsmod17a%.so,$(tlsmod17a-suffixes))
++
+ CFLAGS-tst-align.c = $(stack-align-test-flags)
+ CFLAGS-tst-align2.c = $(stack-align-test-flags)
+ CFLAGS-tst-alignmod.c = $(stack-align-test-flags)
+--- libc/sysdeps/generic/dl-tls.c 12 May 2008 05:35:52 -0000 1.7
++++ libc/sysdeps/generic/dl-tls.c 16 Oct 2008 21:57:52 -0000 1.9
+@@ -637,7 +637,7 @@ __tls_get_addr (GET_ADDR_ARGS)
+ newp = malloc ((2 + newsize) * sizeof (dtv_t));
+ if (newp == NULL)
+ oom ();
+- memcpy (newp, &dtv[-1], oldsize * sizeof (dtv_t));
++ memcpy (newp, &dtv[-1], (2 + oldsize) * sizeof (dtv_t));
+ }
+ else
+ {
+--- libc/elf/tst-tls17.c 1 Jan 1970 00:00:00 -0000
++++ libc/elf/tst-tls17.c 17 Oct 2008 15:23:11 -0000 1.1
+@@ -0,0 +1,28 @@
++#include <dlfcn.h>
++#include <stdio.h>
++
++static int
++do_test (void)
++{
++ void *h = dlopen ("tst-tlsmod17b.so", RTLD_LAZY);
++ if (h == NULL)
++ {
++ puts ("unexpectedly failed to open tst-tlsmod17b.so");
++ exit (1);
++ }
++
++ int (*fp) (void) = (int (*) (void)) dlsym (h, "tlsmod17b");
++ if (fp == NULL)
++ {
++ puts ("cannot find tlsmod17b");
++ exit (1);
++ }
++
++ if (fp ())
++ exit (1);
++
++ return 0;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- libc/elf/tst-tlsmod17a.c 1 Jan 1970 00:00:00 -0000
++++ libc/elf/tst-tlsmod17a.c 17 Oct 2008 15:23:44 -0000 1.1
+@@ -0,0 +1,23 @@
++#include <stdio.h>
++
++#ifndef N
++#define N 0
++#endif
++#define CONCAT1(s, n) s##n
++#define CONCAT(s, n) CONCAT1(s, n)
++
++__thread int CONCAT (v, N) = 4;
++
++int
++CONCAT (tlsmod17a, N) (void)
++{
++ int *p = &CONCAT (v, N);
++ /* GCC assumes &var is never NULL, add optimization barrier. */
++ asm volatile ("" : "+r" (p));
++ if (p == NULL || *p != 4)
++ {
++ printf ("fail %d %p\n", N, p);
++ return 1;
++ }
++ return 0;
++}
+--- libc/elf/tst-tlsmod17b.c 1 Jan 1970 00:00:00 -0000
++++ libc/elf/tst-tlsmod17b.c 17 Oct 2008 15:23:44 -0000 1.1
+@@ -0,0 +1,15 @@
++#define P(N) extern int tlsmod17a##N (void);
++#define PS P(0) P(1) P(2) P(3) P(4) P(5) P(6) P(7) P(8) P(9) \
++ P(10) P(12) P(13) P(14) P(15) P(16) P(17) P(18) P(19)
++PS
++#undef P
++
++int
++tlsmod17b (void)
++{
++ int res = 0;
++#define P(N) res |= tlsmod17a##N ();
++ PS
++#undef P
++ return res;
++}
--- /dev/null
+2008-10-30 Ulrich Drepper <drepper@redhat.com>
+
+ * grp/initgroups.c (internal_getgrouplist): Don't prematurely
+ abort if there is no initgroups_dyn function.
+
+--- libc/grp/initgroups.c 3 Aug 2006 15:39:47 -0000 1.37
++++ libc/grp/initgroups.c 30 Oct 2008 16:55:10 -0000 1.38
+@@ -94,13 +94,8 @@ internal_getgrouplist (const char *user,
+ fct = __nss_lookup_function (nip, "initgroups_dyn");
+
+ if (fct == NULL)
+- {
+- status = compat_call (nip, user, group, &start, size, groupsp,
+- limit, &errno);
+-
+- if (nss_next_action (nip, NSS_STATUS_UNAVAIL) != NSS_ACTION_CONTINUE)
+- break;
+- }
++ status = compat_call (nip, user, group, &start, size, groupsp,
++ limit, &errno);
+ else
+ status = DL_CALL_FCT (fct, (user, group, &start, size, groupsp,
+ limit, &errno));
--- /dev/null
+2006-05-11 Jakub Jelinek <jakub@redhat.com>
+
+ * Makefile (tests): Add tst-mqueue{8,9}, tst-timer5 and
+ tst-aiod{,64,2,3,4,5}.
+ (LDFLAGS-rtkaio.so): Add -Wl,--enable-new-dtags,-z,nodelete.
+ * sysdeps/unix/sysv/linux/kaio_misc.h: Include signal.h and
+ sysdep.h.
+ (aio_start_notify_thread, aio_create_helper_thread): Define
+ for !BROKEN_THREAD_SIGNALS.
+ (__aio_start_notify_thread, __aio_create_helper_thread): New
+ functions for !BROKEN_THREAD_SIGNALS.
+ * sysdeps/unix/sysv/linux/kaio_misc.c: Include sys/sysmacros.h.
+ (aio_create_helper_thread): Define if not yet defined.
+ (__aio_create_helper_thread): New function.
+ (__aio_wait_for_events): Pass 1 rather than 0 as min_nr to
+ io_getevents.
+ (handle_kernel_aio): Likewise.
+ (__aio_create_kernel_thread): Use aio_create_helper_thread.
+ (__aio_enqueue_user_request): Likewise.
+ (handle_fildes_io): Likewise. Remove noreturn attribute,
+ return NULL instead of calling pthread_exit (NULL).
+ (__aio_enqueue_request_ctx): Call fcntl and fxstat64 to avoid using
+ kaio on non-O_DIRECT non-/dev/raw* filedescriptors. For LIO_SYNC
+ and LIO_DSYNC also set kctx to KCTX_NONE.
+ * sysdeps/unix/sysv/linux/kaio_suspend.c (aio_suspend): Don't start
+ handle_kernel_aio thread if ktotal is zero.
+ * sysdeps/pthread/Makefile (tests): Add tst-mqueue8x.
+ (CFLAGS-tst-mqueue8x.c): Add -fexceptions.
+ * Versions.def (librtkaio): Add GLIBC_2.3.4 version.
+ * kaio_mq_close.c: New file.
+ * kaio_mq_getattr.c: New file.
+ * kaio_mq_notify.c: New file.
+ * kaio_mq_open.c: New file.
+ * kaio_mq_receive.c: New file.
+ * kaio_mq_send.c: New file.
+ * kaio_mq_setattr.c: New file.
+ * kaio_mq_timedreceive.c: New file.
+ * kaio_mq_timedsend.c: New file.
+ * kaio_mq_unlink.c: New file.
+ * sysdeps/pthread/tst-mqueue8x.c: New file.
+ * sysdeps/unix/sysv/linux/syscalls.list: New file.
+ * tst-mqueue8.c: New file.
+ * tst-mqueue9.c: New file.
+ * tst-timer5.c: New file.
+ * tst-aiod.h: New file.
+ * tst-aiod.c: New test.
+ * tst-aiod64.c: New test.
+ * tst-aiod2.c: New test.
+ * tst-aiod3.c: New test.
+ * tst-aiod4.c: New test.
+ * tst-aiod5.c: New test.
+ * sysdeps/mips/Makefile: New file.
+ * sysdeps/unix/alpha/Makefile: New file.
+ * sysdeps/unix/alpha/rtkaio-sysdep.S: New file.
+ * sysdeps/unix/mips/rtkaio-sysdep.S: New file.
+ * sysdeps/unix/sysv/linux/Makefile: New file.
+ * sysdeps/unix/sysv/linux/s390/Makefile: New file.
+ * sysdeps/unix/sysv/linux/s390/rtkaio-sysdep.S: New file.
+ * sysdeps/unix/sysv/linux/powerpc/Makefile: New file.
+ * sysdeps/unix/sysv/linux/powerpc/rtkaio-sysdep.c: New file.
+ * sysdeps/unix/sysv/linux/ia64/Makefile: New file.
+ * sysdeps/unix/sysv/linux/ia64/rtkaio-sysdep.S: New file.
+
+--- libc/rtkaio/Makefile.jj 2004-09-22 23:21:03.000000000 +0200
++++ libc/rtkaio/Makefile 2006-05-11 13:52:49.000000000 +0200
+@@ -1,4 +1,4 @@
+-# Copyright (C) 2003, 2004 Free Software Foundation, Inc.
++# Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc.
+ # This file is part of the GNU C Library.
+
+ # The GNU C Library is free software; you can redistribute it and/or
+@@ -42,7 +42,9 @@ librtkaio-routines = $(patsubst %,k%,$(a
+ tests := tst-shm tst-clock tst-clock_nanosleep tst-timer tst-timer2 \
+ tst-aio tst-aio64 tst-aio2 tst-aio3 tst-aio4 tst-aio5 tst-aio6 \
+ tst-aio7 tst-mqueue1 tst-mqueue2 tst-mqueue3 tst-mqueue4 \
+- tst-mqueue5 tst-mqueue6 tst-mqueue7 tst-timer3 tst-timer4
++ tst-mqueue5 tst-mqueue6 tst-mqueue7 tst-mqueue8 tst-mqueue9 \
++ tst-timer3 tst-timer4 tst-timer5 \
++ tst-aiod tst-aiod64 tst-aiod2 tst-aiod3 tst-aiod4 tst-aiod5
+
+ extra-libs := librtkaio
+ extra-libs-others := $(extra-libs)
+@@ -61,7 +63,8 @@ CFLAGS-kaio_suspend.c = -fexceptions
+ CFLAGS-kaio_clock_nanosleep.c = -fexceptions -fasynchronous-unwind-tables
+ CFLAGS-kaio_librt-cancellation.c = -fasynchronous-unwind-tables
+
+-LDFLAGS-rtkaio.so = -Wl,-soname=lib$(libprefix)rt.so$(librt.so-version)
++LDFLAGS-rtkaio.so = -Wl,-soname=lib$(libprefix)rt.so$(librt.so-version) \
++ -Wl,--enable-new-dtags,-z,nodelete
+ CPPFLAGS-librtkaio += -DIS_IN_librt=1
+
+ rpath-dirs := $(patsubst rt,rtkaio,$(rpath-dirs))
+--- libc/rtkaio/tst-aiod.h.jj 2006-05-11 13:00:06.000000000 +0200
++++ libc/rtkaio/tst-aiod.h 2006-05-11 13:01:45.000000000 +0200
+@@ -0,0 +1,52 @@
++/* Tests for AIO in librt.
++ Copyright (C) 1998, 2000, 2002, 2006 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <fcntl.h>
++#include <sys/mman.h>
++#include <unistd.h>
++
++static int
++set_o_direct (int fd)
++{
++ int ret = -1;
++#ifdef O_DIRECT
++ if (fcntl (fd, F_SETFL, fcntl (fd, F_GETFL) | O_DIRECT) >= 0)
++ {
++ int pgsz = sysconf (_SC_PAGESIZE);
++ char *buf = mmap (NULL, 16 * pgsz, PROT_READ | PROT_WRITE,
++ MAP_PRIVATE | MAP_ANON, -1, 0);
++ if (buf != MAP_FAILED)
++ {
++ memset (buf, 0, 16 * pgsz);
++ for (int sz = 256; sz <= 16 * pgsz; sz *= 2)
++ if (write (fd, buf, sz) > 0)
++ {
++ ret = sz;
++ break;
++ }
++ ftruncate64 (fd, 0);
++ munmap (buf, 16 * pgsz);
++ }
++ if (ret < 0)
++ fcntl (fd, F_SETFL, fcntl (fd, F_GETFL) & ~O_DIRECT);
++ }
++#endif
++ return ret;
++}
+--- libc/rtkaio/kaio_mq_send.c.jj 2006-05-10 15:23:59.000000000 +0200
++++ libc/rtkaio/kaio_mq_send.c 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1 @@
++#include <mq_send.c>
+--- libc/rtkaio/sysdeps/unix/alpha/Makefile.jj 2006-05-11 11:40:39.000000000 +0200
++++ libc/rtkaio/sysdeps/unix/alpha/Makefile 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1,3 @@
++ifeq ($(subdir),rtkaio)
++librtkaio-sysdep_routines += rtkaio-sysdep
++endif
+--- libc/rtkaio/sysdeps/unix/alpha/rtkaio-sysdep.S.jj 2006-05-11 11:40:39.000000000 +0200
++++ libc/rtkaio/sysdeps/unix/alpha/rtkaio-sysdep.S 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1 @@
++#include <rt-sysdep.S>
+--- libc/rtkaio/sysdeps/unix/mips/rtkaio-sysdep.S.jj 2006-05-11 11:40:39.000000000 +0200
++++ libc/rtkaio/sysdeps/unix/mips/rtkaio-sysdep.S 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1 @@
++#include <rt-sysdep.S>
+--- libc/rtkaio/sysdeps/unix/sysv/linux/Makefile.jj 2006-05-11 14:51:18.000000000 +0200
++++ libc/rtkaio/sysdeps/unix/sysv/linux/Makefile 2006-05-11 11:52:30.000000000 +0200
+@@ -0,0 +1,4 @@
++ifeq ($(subdir),rtkaio)
++CFLAGS-kaio_mq_send.c += -fexceptions
++CFLAGS-kaio_mq_receive.c += -fexceptions
++endif
+--- libc/rtkaio/sysdeps/unix/sysv/linux/kaio_misc.h.jj 2004-09-22 23:21:05.000000000 +0200
++++ libc/rtkaio/sysdeps/unix/sysv/linux/kaio_misc.h 2006-05-11 11:40:39.000000000 +0200
+@@ -1,4 +1,5 @@
+-/* Copyright (C) 1997,1999,2000,2001,2002,2003 Free Software Foundation, Inc.
++/* Copyright (C) 1997,1999,2000,2001,2002,2003,2006
++ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+@@ -34,6 +35,9 @@
+ #include <aio.h>
+ #include <pthread.h>
+ #include <stdint.h>
++#include <signal.h>
++#include <sysdep.h>
++#include <limits.h>
+
+ typedef unsigned long kctx_t;
+ #define KCTX_NONE ~0UL
+@@ -212,5 +216,49 @@ extern int __aio_create_kernel_thread (v
+ extern int __have_no_kernel_aio attribute_hidden;
+ extern int __kernel_thread_started attribute_hidden;
+
++#ifndef BROKEN_THREAD_SIGNALS
++# define aio_start_notify_thread __aio_start_notify_thread
++# define aio_create_helper_thread __aio_create_helper_thread
++
++extern inline void
++__aio_start_notify_thread (void)
++{
++ sigset_t ss;
++ sigemptyset (&ss);
++ INTERNAL_SYSCALL_DECL (err);
++ INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, NULL, _NSIG / 8);
++}
++
++extern inline int
++__aio_create_helper_thread (pthread_t *threadp, void *(*tf) (void *), void *arg)
++{
++ pthread_attr_t attr;
++
++ /* Make sure the thread is created detached. */
++ pthread_attr_init (&attr);
++ pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
++
++ /* The helper thread needs only very little resources. */
++ (void) pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN);
++
++ /* Block all signals in the helper thread. To do this thoroughly we
++ temporarily have to block all signals here. */
++ sigset_t ss;
++ sigset_t oss;
++ sigfillset (&ss);
++ INTERNAL_SYSCALL_DECL (err);
++ INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &ss, &oss, _NSIG / 8);
++
++ int ret = pthread_create (threadp, &attr, tf, arg);
++
++ /* Restore the signal mask. */
++ INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, &oss, NULL,
++ _NSIG / 8);
++
++ (void) pthread_attr_destroy (&attr);
++ return ret;
++}
++#endif
++
+ #endif
+ #endif /* aio_misc.h */
+--- libc/rtkaio/sysdeps/unix/sysv/linux/s390/Makefile.jj 2006-05-11 11:40:39.000000000 +0200
++++ libc/rtkaio/sysdeps/unix/sysv/linux/s390/Makefile 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1,3 @@
++ifeq ($(subdir),rtkaio)
++librtkaio-routines += rtkaio-sysdep
++endif
+--- libc/rtkaio/sysdeps/unix/sysv/linux/s390/rtkaio-sysdep.S.jj 2006-05-11 11:40:39.000000000 +0200
++++ libc/rtkaio/sysdeps/unix/sysv/linux/s390/rtkaio-sysdep.S 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1 @@
++#include <rt-sysdep.S>
+--- libc/rtkaio/sysdeps/unix/sysv/linux/powerpc/Makefile.jj 2006-05-11 11:40:39.000000000 +0200
++++ libc/rtkaio/sysdeps/unix/sysv/linux/powerpc/Makefile 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1,3 @@
++ifeq ($(subdir),rtkaio)
++librtkaio-routines += rtkaio-sysdep
++endif
+--- libc/rtkaio/sysdeps/unix/sysv/linux/powerpc/rtkaio-sysdep.c.jj 2006-05-11 11:40:39.000000000 +0200
++++ libc/rtkaio/sysdeps/unix/sysv/linux/powerpc/rtkaio-sysdep.c 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1 @@
++#include <rt-sysdep.c>
+--- libc/rtkaio/sysdeps/unix/sysv/linux/kaio_suspend.c.jj 2004-09-22 23:21:05.000000000 +0200
++++ libc/rtkaio/sysdeps/unix/sysv/linux/kaio_suspend.c 2006-05-11 14:49:47.000000000 +0200
+@@ -1,5 +1,6 @@
+ /* Suspend until termination of a requests.
+- Copyright (C) 1997,1998,1999,2000,2002,2003 Free Software Foundation, Inc.
++ Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2006
++ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+@@ -150,7 +151,7 @@ aio_suspend (list, nent, timeout)
+
+ pthread_cleanup_push (cleanup, &clparam);
+
+- if (!__kernel_thread_started)
++ if (!__kernel_thread_started && ktotal)
+ {
+ /* If the kernel aio thread was not started yet all requests
+ are served by the kernel and there are no other threads running,
+--- libc/rtkaio/sysdeps/unix/sysv/linux/ia64/Makefile.jj 2006-05-11 11:40:39.000000000 +0200
++++ libc/rtkaio/sysdeps/unix/sysv/linux/ia64/Makefile 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1,3 @@
++ifeq ($(subdir),rtkaio)
++librtkaio-routines += rtkaio-sysdep
++endif
+--- libc/rtkaio/sysdeps/unix/sysv/linux/ia64/rtkaio-sysdep.S.jj 2006-05-11 11:40:39.000000000 +0200
++++ libc/rtkaio/sysdeps/unix/sysv/linux/ia64/rtkaio-sysdep.S 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1 @@
++#include <rt-sysdep.S>
+--- libc/rtkaio/sysdeps/unix/sysv/linux/syscalls.list.jj 2006-05-10 16:22:10.000000000 +0200
++++ libc/rtkaio/sysdeps/unix/sysv/linux/syscalls.list 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1,5 @@
++# File name Caller Syscall name Args Strong name Weak names
++
++kaio_mq_timedsend - mq_timedsend Ci:ipiip __GI_mq_timedsend mq_timedsend
++kaio_mq_timedreceive - mq_timedreceive Ci:ipipp __GI_mq_timedreceive mq_timedreceive
++kaio_mq_setattr - mq_getsetattr i:ipp __GI_mq_setattr mq_setattr
+--- libc/rtkaio/sysdeps/unix/sysv/linux/kaio_misc.c.jj 2004-09-22 23:21:05.000000000 +0200
++++ libc/rtkaio/sysdeps/unix/sysv/linux/kaio_misc.c 2006-05-11 14:38:41.000000000 +0200
+@@ -1,5 +1,5 @@
+ /* Handle general operations.
+- Copyright (C) 1997,1998,1999,2000,2001,2002,2003
++ Copyright (C) 1997,1998,1999,2000,2001,2002,2003,2006
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+@@ -34,6 +34,28 @@
+ #include <unistd.h>
+ #include <sys/stat.h>
+ #include <sys/time.h>
++#include <sys/sysmacros.h>
++
++#ifndef aio_create_helper_thread
++# define aio_create_helper_thread __aio_create_helper_thread
++
++extern inline int
++__aio_create_helper_thread (pthread_t *threadp, void *(*tf) (void *), void *arg)
++{
++ pthread_attr_t attr;
++
++ /* Make sure the thread is created detached. */
++ pthread_attr_init (&attr);
++ pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
++
++ int ret = pthread_create (threadp, &attr, tf, arg);
++
++ (void) pthread_attr_destroy (&attr);
++ return ret;
++}
++
++#endif
++
+
+ static void add_request_to_runlist (struct requestlist *newrequest)
+ internal_function;
+@@ -421,7 +443,7 @@ __aio_wait_for_events (kctx_t kctx, cons
+ ts.tv_nsec = 0;
+ do
+ {
+- ret = INTERNAL_SYSCALL (io_getevents, err, 5, kctx, 0, 10, ev,
++ ret = INTERNAL_SYSCALL (io_getevents, err, 5, kctx, 1, 10, ev,
+ timespec);
+ if (INTERNAL_SYSCALL_ERROR_P (ret, err) || ret == 0)
+ break;
+@@ -453,16 +475,11 @@ internal_function
+ __aio_create_kernel_thread (void)
+ {
+ pthread_t thid;
+- pthread_attr_t attr;
+
+ if (__kernel_thread_started)
+ return 0;
+
+- /* Make sure the thread is created detached. */
+- pthread_attr_init (&attr);
+- pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+-
+- if (pthread_create (&thid, &attr, handle_kernel_aio, NULL) != 0)
++ if (aio_create_helper_thread (&thid, handle_kernel_aio, NULL) != 0)
+ return -1;
+ __kernel_thread_started = 1;
+ return 0;
+@@ -477,7 +494,7 @@ handle_kernel_aio (void *arg __attribute
+
+ for (;;)
+ {
+- ret = INTERNAL_SYSCALL (io_getevents, err, 5, __aio_kioctx, 0, 10, ev,
++ ret = INTERNAL_SYSCALL (io_getevents, err, 5, __aio_kioctx, 1, 10, ev,
+ NULL);
+ if (INTERNAL_SYSCALL_ERROR_P (ret, err) || ret == 0)
+ continue;
+@@ -593,16 +610,11 @@ __aio_enqueue_user_request (struct reque
+ if (nthreads < optim.aio_threads && idle_thread_count == 0)
+ {
+ pthread_t thid;
+- pthread_attr_t attr;
+-
+- /* Make sure the thread is created detached. */
+- pthread_attr_init (&attr);
+- pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+
+ running = newp->running = allocated;
+
+ /* Now try to start a thread. */
+- if (pthread_create (&thid, &attr, handle_fildes_io, newp) == 0)
++ if (aio_create_helper_thread (&thid, handle_fildes_io, newp) == 0)
+ /* We managed to enqueue the request. All errors which can
+ happen now can be recognized by calls to `aio_return' and
+ `aio_error'. */
+@@ -653,6 +665,7 @@ __aio_enqueue_request_ctx (aiocb_union *
+ aiocbp->aiocb.aio_reqprio = 0;
+ /* FIXME: Kernel doesn't support sync yet. */
+ operation &= ~LIO_KTHREAD;
++ kctx = KCTX_NONE;
+ }
+ else if (aiocbp->aiocb.aio_reqprio < 0
+ || aiocbp->aiocb.aio_reqprio > AIO_PRIO_DELTA_MAX)
+@@ -664,6 +677,23 @@ __aio_enqueue_request_ctx (aiocb_union *
+ return NULL;
+ }
+
++ if ((operation & LIO_KTHREAD) || kctx != KCTX_NONE)
++ {
++ /* io_* is only really asynchronous for O_DIRECT or /dev/raw*. */
++ int fl = __fcntl (aiocbp->aiocb.aio_fildes, F_GETFL);
++ if (fl < 0 || (fl & O_DIRECT) == 0)
++ {
++ struct stat64 st;
++ if (__fxstat64 (_STAT_VER, aiocbp->aiocb.aio_fildes, &st) < 0
++ || ! S_ISCHR (st.st_mode)
++ || major (st.st_rdev) != 162)
++ {
++ operation &= ~LIO_KTHREAD;
++ kctx = KCTX_NONE;
++ }
++ }
++ }
++
+ /* Compute priority for this request. */
+ pthread_getschedparam (pthread_self (), &policy, ¶m);
+ prio = param.sched_priority - aiocbp->aiocb.aio_reqprio;
+@@ -832,7 +862,6 @@ wait_for_kernel_requests (int fildes)
+
+
+ static void *
+-__attribute__ ((noreturn))
+ handle_fildes_io (void *arg)
+ {
+ pthread_t self = pthread_self ();
+@@ -1026,16 +1055,11 @@ handle_fildes_io (void *arg)
+ else if (nthreads < optim.aio_threads)
+ {
+ pthread_t thid;
+- pthread_attr_t attr;
+-
+- /* Make sure the thread is created detached. */
+- pthread_attr_init (&attr);
+- pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
+
+ /* Now try to start a thread. If we fail, no big deal,
+ because we know that there is at least one thread (us)
+ that is working on AIO operations. */
+- if (pthread_create (&thid, &attr, handle_fildes_io, NULL)
++ if (aio_create_helper_thread (&thid, handle_fildes_io, NULL)
+ == 0)
+ ++nthreads;
+ }
+@@ -1047,7 +1071,7 @@ handle_fildes_io (void *arg)
+ }
+ while (runp != NULL);
+
+- pthread_exit (NULL);
++ return NULL;
+ }
+
+
+--- libc/rtkaio/sysdeps/pthread/Makefile.jj 2004-09-22 23:21:05.000000000 +0200
++++ libc/rtkaio/sysdeps/pthread/Makefile 2006-05-11 11:40:39.000000000 +0200
+@@ -14,6 +14,11 @@ $(objpfx)tst-timer: $(objpfx)librtkaio.s
+ else
+ $(objpfx)tst-timer: $(objpfx)librtkaio.a $(static-thread-library)
+ endif
++
++ifeq ($(have-forced-unwind),yes)
++tests += tst-mqueue8x
++CFLAGS-tst-mqueue8x.c += -fexceptions
++endif
+ endif
+
+ endif
+--- libc/rtkaio/sysdeps/pthread/tst-mqueue8x.c.jj 2006-05-10 14:34:34.000000000 +0200
++++ libc/rtkaio/sysdeps/pthread/tst-mqueue8x.c 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1 @@
++#include_next <tst-mqueue8x.c>
+--- libc/rtkaio/sysdeps/mips/Makefile.jj 2006-05-11 11:40:39.000000000 +0200
++++ libc/rtkaio/sysdeps/mips/Makefile 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1,3 @@
++ifeq ($(subdir),rtkaio)
++librtkaio-sysdep_routines += rtkaio-sysdep
++endif
+--- libc/rtkaio/kaio_mq_close.c.jj 2006-05-10 15:23:59.000000000 +0200
++++ libc/rtkaio/kaio_mq_close.c 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1 @@
++#include <mq_close.c>
+--- libc/rtkaio/tst-mqueue9.c.jj 2006-05-10 14:27:13.000000000 +0200
++++ libc/rtkaio/tst-mqueue9.c 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1 @@
++#include <rt/tst-mqueue9.c>
+--- libc/rtkaio/kaio_mq_timedsend.c.jj 2006-05-10 15:23:59.000000000 +0200
++++ libc/rtkaio/kaio_mq_timedsend.c 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1 @@
++#include <mq_timedsend.c>
+--- libc/rtkaio/kaio_mq_getattr.c.jj 2006-05-10 15:23:59.000000000 +0200
++++ libc/rtkaio/kaio_mq_getattr.c 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1 @@
++#include <mq_getattr.c>
+--- libc/rtkaio/kaio_mq_setattr.c.jj 2006-05-10 15:23:59.000000000 +0200
++++ libc/rtkaio/kaio_mq_setattr.c 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1 @@
++#include <mq_setattr.c>
+--- libc/rtkaio/tst-timer5.c.jj 2006-05-10 14:27:56.000000000 +0200
++++ libc/rtkaio/tst-timer5.c 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1 @@
++#include <rt/tst-timer5.c>
+--- libc/rtkaio/Versions.def.jj 2004-09-22 23:21:03.000000000 +0200
++++ libc/rtkaio/Versions.def 2006-05-11 11:40:39.000000000 +0200
+@@ -3,4 +3,5 @@ librtkaio {
+ GLIBC_2.2
+ GLIBC_2.3
+ GLIBC_2.3.3
++ GLIBC_2.3.4
+ }
+--- libc/rtkaio/kaio_mq_open.c.jj 2006-05-10 15:23:59.000000000 +0200
++++ libc/rtkaio/kaio_mq_open.c 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1 @@
++#include <mq_open.c>
+--- libc/rtkaio/kaio_mq_receive.c.jj 2006-05-10 15:23:59.000000000 +0200
++++ libc/rtkaio/kaio_mq_receive.c 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1 @@
++#include <mq_receive.c>
+--- libc/rtkaio/kaio_mq_unlink.c.jj 2006-05-10 15:23:59.000000000 +0200
++++ libc/rtkaio/kaio_mq_unlink.c 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1 @@
++#include <mq_unlink.c>
+--- libc/rtkaio/tst-aiod3.c.jj 2006-05-11 13:31:34.000000000 +0200
++++ libc/rtkaio/tst-aiod3.c 2006-05-11 13:55:44.000000000 +0200
+@@ -0,0 +1,118 @@
++/* Test for notification mechanism in lio_listio.
++ Copyright (C) 2000, 2002, 2006 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <aio.h>
++#include <signal.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <errno.h>
++#include "tst-aiod.h"
++
++int flag;
++
++
++static void
++thrfct (sigval_t arg)
++{
++ flag = 1;
++}
++
++
++static int
++do_test (int argc, char *argv[])
++{
++ char name[] = "/tmp/aio3.XXXXXX";
++ int fd;
++ struct aiocb *arr[1];
++ struct aiocb cb;
++ static const char buf[] = "Hello World\n";
++
++ fd = mkstemp (name);
++ if (fd == -1)
++ {
++ printf ("cannot open temp name: %m\n");
++ return 1;
++ }
++
++ unlink (name);
++
++ arr[0] = &cb;
++
++ void *p;
++ int sz = set_o_direct (fd);
++ if (sz != -1)
++ {
++ int err = posix_memalign (&p, sz, sz);
++ if (err)
++ {
++ errno = err;
++ printf ("cannot allocate memory: %m\n");
++ return 1;
++ }
++ memcpy (p, buf, sizeof (buf) - 1);
++ memset (p + sizeof (buf) - 1, ' ', sz - sizeof (buf) + 1);
++ printf ("Using O_DIRECT with block size %d\n", sz);
++ }
++ else
++ {
++ p = (void *) buf;
++ sz = sizeof (buf) - 1;
++ }
++
++ cb.aio_fildes = fd;
++ cb.aio_lio_opcode = LIO_WRITE;
++ cb.aio_reqprio = 0;
++ cb.aio_buf = p;
++ cb.aio_nbytes = sz;
++ cb.aio_offset = 0;
++ cb.aio_sigevent.sigev_notify = SIGEV_THREAD;
++ cb.aio_sigevent.sigev_notify_function = thrfct;
++ cb.aio_sigevent.sigev_notify_attributes = NULL;
++ cb.aio_sigevent.sigev_value.sival_ptr = NULL;
++
++ if (lio_listio (LIO_NOWAIT, arr, 1, NULL) < 0)
++ {
++ if (errno == ENOSYS)
++ {
++ puts ("no aio support in this configuration");
++ return 0;
++ }
++ printf ("lio_listio failed: %m\n");
++ return 1;
++ }
++
++ if (aio_suspend ((const struct aiocb *const *) arr, 1, NULL) < 0)
++ {
++ printf ("aio_suspend failed: %m\n");
++ return 1;
++ }
++
++ if (flag != 0)
++ {
++ puts ("thread created, should not have happened");
++ return 1;
++ }
++
++ puts ("all OK");
++
++ return 0;
++}
++
++#include "../test-skeleton.c"
+--- libc/rtkaio/tst-aiod.c.jj 2006-05-11 11:56:20.000000000 +0200
++++ libc/rtkaio/tst-aiod.c 2006-05-11 13:55:20.000000000 +0200
+@@ -0,0 +1,307 @@
++/* Tests for AIO in librt.
++ Copyright (C) 1998, 2000, 2002, 2006 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <aio.h>
++#include <errno.h>
++#include <error.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include <sys/stat.h>
++#include "tst-aiod.h"
++
++
++/* Prototype for our test function. */
++extern void do_prepare (int argc, char *argv[]);
++extern int do_test (int argc, char *argv[]);
++
++/* We have a preparation function. */
++#define PREPARE do_prepare
++
++/* We might need a bit longer timeout. */
++#define TIMEOUT 20 /* sec */
++
++/* This defines the `main' function and some more. */
++#include <test-skeleton.c>
++
++
++/* These are for the temporary file we generate. */
++char *name;
++int fd;
++char *tmpbuf;
++int blksz = 100;
++
++void
++do_prepare (int argc, char *argv[])
++{
++ char name_len;
++
++ name_len = strlen (test_dir);
++ name = malloc (name_len + sizeof ("/aioXXXXXX"));
++ mempcpy (mempcpy (name, test_dir, name_len),
++ "/aioXXXXXX", sizeof ("/aioXXXXXX"));
++ add_temp_file (name);
++
++ /* Open our test file. */
++ fd = mkstemp (name);
++ if (fd == -1)
++ error (EXIT_FAILURE, errno, "cannot open test file `%s'", name);
++
++ int sz = set_o_direct (fd);
++ if (sz != -1)
++ {
++ blksz = sz;
++ printf ("Using O_DIRECT with block size %d\n", blksz);
++ }
++}
++
++
++static int
++test_file (const void *buf, size_t size, int fd, const char *msg)
++{
++ struct stat st;
++ char *tmp = tmpbuf;
++
++ errno = 0;
++ if (fstat (fd, &st) < 0)
++ {
++ error (0, errno, "%s: failed stat", msg);
++ return 1;
++ }
++
++ if (st.st_size != (off_t) size)
++ {
++ error (0, errno, "%s: wrong size: %lu, should be %lu",
++ msg, (unsigned long int) st.st_size, (unsigned long int) size);
++ return 1;
++ }
++
++ if (pread (fd, tmp, size, 0) != (ssize_t) size)
++ {
++ error (0, errno, "%s: failed pread", msg);
++ return 1;
++ }
++
++ if (memcmp (buf, tmp, size) != 0)
++ {
++ error (0, errno, "%s: failed comparison", msg);
++ return 1;
++ }
++
++ printf ("%s test ok\n", msg);
++
++ return 0;
++}
++
++
++static int
++do_wait (struct aiocb **cbp, size_t nent, int allowed_err)
++{
++ int go_on;
++ size_t cnt;
++ int result = 0;
++
++ do
++ {
++ aio_suspend ((const struct aiocb *const *) cbp, nent, NULL);
++ go_on = 0;
++ for (cnt = 0; cnt < nent; ++cnt)
++ if (cbp[cnt] != NULL)
++ {
++ if (aio_error (cbp[cnt]) == EINPROGRESS)
++ go_on = 1;
++ else
++ {
++ if (aio_return (cbp[cnt]) == -1
++ && (allowed_err == 0
++ || aio_error (cbp[cnt]) != allowed_err))
++ {
++ error (0, aio_error (cbp[cnt]), "Operation failed\n");
++ result = 1;
++ }
++ cbp[cnt] = NULL;
++ }
++ }
++ }
++ while (go_on);
++
++ return result;
++}
++
++
++int
++do_test (int argc, char *argv[])
++{
++ struct aiocb cbs[10];
++ struct aiocb cbs_fsync;
++ struct aiocb *cbp[10];
++ struct aiocb *cbp_fsync[1];
++ char *buf;
++ size_t cnt;
++ int result = 0;
++
++ buf = mmap (NULL, 20 * blksz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
++ tmpbuf = buf + 10 * blksz;
++ if (buf == MAP_FAILED)
++ {
++ error (0, errno, "mmap failed");
++ return 1;
++ }
++
++ /* Preparation. */
++ for (cnt = 0; cnt < 10; ++cnt)
++ {
++ cbs[cnt].aio_fildes = fd;
++ cbs[cnt].aio_reqprio = 0;
++ cbs[cnt].aio_buf = memset (&buf[cnt * blksz], '0' + cnt, blksz);
++ cbs[cnt].aio_nbytes = blksz;
++ cbs[cnt].aio_offset = cnt * blksz;
++ cbs[cnt].aio_sigevent.sigev_notify = SIGEV_NONE;
++
++ cbp[cnt] = &cbs[cnt];
++ }
++
++ /* First a simple test. */
++ for (cnt = 10; cnt > 0; )
++ if (aio_write (cbp[--cnt]) < 0 && errno == ENOSYS)
++ {
++ error (0, 0, "no aio support in this configuration");
++ return 0;
++ }
++ /* Wait 'til the results are there. */
++ result |= do_wait (cbp, 10, 0);
++ /* Test this. */
++ result |= test_file (buf, 10 * blksz, fd, "aio_write");
++
++ /* Read now as we've written it. */
++ memset (buf, '\0', 10 * blksz);
++ /* Issue the commands. */
++ for (cnt = 10; cnt > 0; )
++ {
++ --cnt;
++ cbp[cnt] = &cbs[cnt];
++ aio_read (cbp[cnt]);
++ }
++ /* Wait 'til the results are there. */
++ result |= do_wait (cbp, 10, 0);
++ /* Test this. */
++ for (cnt = 0; cnt < 10 * blksz; ++cnt)
++ if (buf[cnt] != '0' + (cnt / blksz))
++ {
++ result = 1;
++ error (0, 0, "comparison failed for aio_read test");
++ break;
++ }
++
++ if (cnt == 10 * blksz)
++ puts ("aio_read test ok");
++
++ /* Remove the test file contents. */
++ if (ftruncate (fd, 0) < 0)
++ {
++ error (0, errno, "ftruncate failed\n");
++ result = 1;
++ }
++
++ /* Test lio_listio. */
++ for (cnt = 0; cnt < 10; ++cnt)
++ {
++ cbs[cnt].aio_lio_opcode = LIO_WRITE;
++ cbp[cnt] = &cbs[cnt];
++ }
++ /* Issue the command. */
++ lio_listio (LIO_WAIT, cbp, 10, NULL);
++ /* ...and immediately test it since we started it in wait mode. */
++ result |= test_file (buf, 10 * blksz, fd, "lio_listio (write)");
++
++ /* Test aio_fsync. */
++ cbs_fsync.aio_fildes = fd;
++ cbs_fsync.aio_sigevent.sigev_notify = SIGEV_NONE;
++ cbp_fsync[0] = &cbs_fsync;
++
++ /* Remove the test file contents first. */
++ if (ftruncate (fd, 0) < 0)
++ {
++ error (0, errno, "ftruncate failed\n");
++ result = 1;
++ }
++
++ /* Write again. */
++ for (cnt = 10; cnt > 0; )
++ aio_write (cbp[--cnt]);
++
++ if (aio_fsync (O_SYNC, &cbs_fsync) < 0)
++ {
++ error (0, errno, "aio_fsync failed\n");
++ result = 1;
++ }
++ result |= do_wait (cbp_fsync, 1, 0);
++
++ /* ...and test since all data should be on disk now. */
++ result |= test_file (buf, 10 * blksz, fd, "aio_fsync (aio_write)");
++
++ /* Test aio_cancel. */
++ /* Remove the test file contents first. */
++ if (ftruncate (fd, 0) < 0)
++ {
++ error (0, errno, "ftruncate failed\n");
++ result = 1;
++ }
++
++ /* Write again. */
++ for (cnt = 10; cnt > 0; )
++ aio_write (cbp[--cnt]);
++
++ /* Cancel all requests. */
++ if (aio_cancel (fd, NULL) == -1)
++ printf ("aio_cancel (fd, NULL) cannot cancel anything\n");
++
++ result |= do_wait (cbp, 10, ECANCELED);
++
++ /* Another test for aio_cancel. */
++ /* Remove the test file contents first. */
++ if (ftruncate (fd, 0) < 0)
++ {
++ error (0, errno, "ftruncate failed\n");
++ result = 1;
++ }
++
++ /* Write again. */
++ for (cnt = 10; cnt > 0; )
++ {
++ --cnt;
++ cbp[cnt] = &cbs[cnt];
++ aio_write (cbp[cnt]);
++ }
++ puts ("finished3");
++
++ /* Cancel all requests. */
++ for (cnt = 10; cnt > 0; )
++ if (aio_cancel (fd, cbp[--cnt]) == -1)
++ /* This is not an error. The request can simply be finished. */
++ printf ("aio_cancel (fd, cbp[%Zd]) cannot be canceled\n", cnt);
++ puts ("finished2");
++
++ result |= do_wait (cbp, 10, ECANCELED);
++
++ puts ("finished");
++
++ return result;
++}
+--- libc/rtkaio/kaio_mq_timedreceive.c.jj 2006-05-10 15:23:59.000000000 +0200
++++ libc/rtkaio/kaio_mq_timedreceive.c 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1 @@
++#include <mq_timedreceive.c>
+--- libc/rtkaio/tst-aiod4.c.jj 2006-05-11 13:31:34.000000000 +0200
++++ libc/rtkaio/tst-aiod4.c 2006-05-11 13:55:52.000000000 +0200
+@@ -0,0 +1,182 @@
++/* Test for completion signal handling.
++ Copyright (C) 2000, 2001, 2002, 2006 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <aio.h>
++#include <signal.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <errno.h>
++#include "tst-aiod.h"
++
++/* We might need a bit longer timeout. */
++#define TIMEOUT 10 /* sec */
++
++int my_signo;
++
++volatile sig_atomic_t flag;
++
++
++static void
++sighandler (const int signo)
++{
++ flag = signo;
++}
++
++static int
++wait_flag (void)
++{
++ while (flag == 0)
++ {
++ puts ("Sleeping...");
++ sleep (1);
++ }
++
++ if (flag != my_signo)
++ {
++ printf ("signal handler received wrong signal, flag is %d\n", flag);
++ return 1;
++ }
++
++ return 0;
++}
++
++#ifndef SIGRTMIN
++# define SIGRTMIN -1
++# define SIGRTMAX -1
++#endif
++
++static int
++do_test (int argc, char *argv[])
++{
++ char name[] = "/tmp/aio4.XXXXXX";
++ int fd;
++ struct aiocb *arr[1];
++ struct aiocb cb;
++ static const char buf[] = "Hello World\n";
++ struct aioinit init = {10, 20, 0};
++ struct sigaction sa;
++ struct sigevent ev;
++
++ if (SIGRTMIN == -1)
++ {
++ printf ("RT signals not supported.\n");
++ return 0;
++ }
++
++ /* Select a signal from the middle of the available choices... */
++ my_signo = (SIGRTMAX + SIGRTMIN) / 2;
++
++ fd = mkstemp (name);
++ if (fd == -1)
++ {
++ printf ("cannot open temp name: %m\n");
++ return 1;
++ }
++
++ unlink (name);
++
++ /* Test also aio_init. */
++ aio_init (&init);
++
++ arr[0] = &cb;
++
++ void *p;
++ int sz = set_o_direct (fd);
++ if (sz != -1)
++ {
++ int err = posix_memalign (&p, sz, sz);
++ if (err)
++ {
++ errno = err;
++ printf ("cannot allocate memory: %m\n");
++ return 1;
++ }
++ memcpy (p, buf, sizeof (buf) - 1);
++ memset (p + sizeof (buf) - 1, ' ', sz - sizeof (buf) + 1);
++ printf ("Using O_DIRECT with block size %d\n", sz);
++ }
++ else
++ {
++ p = (void *) buf;
++ sz = sizeof (buf) - 1;
++ }
++
++ cb.aio_fildes = fd;
++ cb.aio_lio_opcode = LIO_WRITE;
++ cb.aio_reqprio = 0;
++ cb.aio_buf = p;
++ cb.aio_nbytes = sz;
++ cb.aio_offset = 0;
++ cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
++ cb.aio_sigevent.sigev_notify_function = NULL;
++ cb.aio_sigevent.sigev_notify_attributes = NULL;
++ cb.aio_sigevent.sigev_signo = my_signo;
++ cb.aio_sigevent.sigev_value.sival_ptr = NULL;
++
++ ev.sigev_notify = SIGEV_SIGNAL;
++ ev.sigev_notify_function = NULL;
++ ev.sigev_notify_attributes = NULL;
++ ev.sigev_signo = my_signo;
++
++ sa.sa_handler = sighandler;
++ sigemptyset (&sa.sa_mask);
++ sa.sa_flags = SA_RESTART;
++
++ if (sigaction (my_signo, &sa, NULL) < 0)
++ {
++ printf ("sigaction failed: %m\n");
++ return 1;
++ }
++
++ flag = 0;
++ /* First use aio_write. */
++ if (aio_write (arr[0]) < 0)
++ {
++ if (errno == ENOSYS)
++ {
++ puts ("no aio support in this configuration");
++ return 0;
++ }
++ printf ("aio_write failed: %m\n");
++ return 1;
++ }
++
++ if (wait_flag ())
++ return 1;
++
++ puts ("aio_write OK");
++
++ flag = 0;
++ /* Again with lio_listio. */
++ if (lio_listio (LIO_NOWAIT, arr, 1, &ev) < 0)
++ {
++ printf ("lio_listio failed: %m\n");
++ return 1;
++ }
++
++ if (wait_flag ())
++ return 1;
++
++ puts ("all OK");
++
++ return 0;
++}
++
++#include "../test-skeleton.c"
+--- libc/rtkaio/kaio_mq_notify.c.jj 2006-05-10 15:23:59.000000000 +0200
++++ libc/rtkaio/kaio_mq_notify.c 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1 @@
++#include <mq_notify.c>
+--- libc/rtkaio/tst-aiod5.c.jj 2006-05-11 13:31:34.000000000 +0200
++++ libc/rtkaio/tst-aiod5.c 2006-05-11 13:57:23.000000000 +0200
+@@ -0,0 +1,152 @@
++/* Test for completion thread handling.
++ Copyright (C) 2000, 2002, 2006 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <aio.h>
++#include <signal.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <errno.h>
++#include "tst-aiod.h"
++
++/* We might need a bit longer timeout. */
++#define TIMEOUT 10 /* sec */
++
++#define MY_SIVAL 27
++
++volatile sig_atomic_t flag;
++
++
++static void
++callback (sigval_t s)
++{
++ flag = s.sival_int;
++}
++
++static int
++wait_flag (void)
++{
++ while (flag == 0)
++ {
++ puts ("Sleeping...");
++ sleep (1);
++ }
++
++ if (flag != MY_SIVAL)
++ {
++ printf ("signal handler received wrong signal, flag is %d\n", flag);
++ return 1;
++ }
++
++ return 0;
++}
++
++
++static int
++do_test (int argc, char *argv[])
++{
++ char name[] = "/tmp/aio5.XXXXXX";
++ int fd;
++ struct aiocb *arr[1];
++ struct aiocb cb;
++ static const char buf[] = "Hello World\n";
++ struct sigevent ev;
++
++ fd = mkstemp (name);
++ if (fd == -1)
++ {
++ printf ("cannot open temp name: %m\n");
++ return 1;
++ }
++
++ unlink (name);
++
++ arr[0] = &cb;
++
++ void *p;
++ int sz = set_o_direct (fd);
++ if (sz != -1)
++ {
++ int err = posix_memalign (&p, sz, sz);
++ if (err)
++ {
++ errno = err;
++ printf ("cannot allocate memory: %m\n");
++ return 1;
++ }
++ memcpy (p, buf, sizeof (buf) - 1);
++ memset (p + sizeof (buf) - 1, ' ', sz - sizeof (buf) + 1);
++ printf ("Using O_DIRECT with block size %d\n", sz);
++ }
++ else
++ {
++ p = (void *) buf;
++ sz = sizeof (buf) - 1;
++ }
++
++ cb.aio_fildes = fd;
++ cb.aio_lio_opcode = LIO_WRITE;
++ cb.aio_reqprio = 0;
++ cb.aio_buf = p;
++ cb.aio_nbytes = sz;
++ cb.aio_offset = 0;
++ cb.aio_sigevent.sigev_notify = SIGEV_THREAD;
++ cb.aio_sigevent.sigev_notify_function = callback;
++ cb.aio_sigevent.sigev_notify_attributes = NULL;
++ cb.aio_sigevent.sigev_value.sival_int = MY_SIVAL;
++
++ ev.sigev_notify = SIGEV_THREAD;
++ ev.sigev_notify_function = callback;
++ ev.sigev_notify_attributes = NULL;
++ ev.sigev_value.sival_int = MY_SIVAL;
++
++ /* First use aio_write. */
++ if (aio_write (arr[0]) < 0)
++ {
++ if (errno == ENOSYS)
++ {
++ puts ("no aio support in this configuration");
++ return 0;
++ }
++ printf ("aio_write failed: %m\n");
++ return 1;
++ }
++
++ if (wait_flag ())
++ return 1;
++
++ puts ("aio_write OK");
++
++ flag = 0;
++ /* Again with lio_listio. */
++ if (lio_listio (LIO_NOWAIT, arr, 1, &ev) < 0)
++ {
++ printf ("lio_listio failed: %m\n");
++ return 1;
++ }
++
++ if (wait_flag ())
++ return 1;
++
++ puts ("all OK");
++
++ return 0;
++}
++
++#include "../test-skeleton.c"
+--- libc/rtkaio/tst-aiod2.c.jj 2006-05-11 13:31:34.000000000 +0200
++++ libc/rtkaio/tst-aiod2.c 2006-05-11 13:55:34.000000000 +0200
+@@ -0,0 +1,113 @@
++/* Test for notification mechanism in lio_listio.
++ Copyright (C) 2000, 2002, 2006 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@cygnus.com>, 2000.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <aio.h>
++#include <signal.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <errno.h>
++#include "tst-aiod.h"
++
++int flag;
++
++
++static void
++thrfct (sigval_t arg)
++{
++ flag = 1;
++}
++
++
++static int
++do_test (int argc, char *argv[])
++{
++ char name[] = "/tmp/aio2.XXXXXX";
++ int fd;
++ struct aiocb *arr[1];
++ struct aiocb cb;
++ static const char buf[] = "Hello World\n";
++
++ fd = mkstemp (name);
++ if (fd == -1)
++ {
++ printf ("cannot open temp name: %m\n");
++ return 1;
++ }
++
++ unlink (name);
++
++ arr[0] = &cb;
++
++ void *p;
++ int sz = set_o_direct (fd);
++ if (sz != -1)
++ {
++ int err = posix_memalign (&p, sz, sz);
++ if (err)
++ {
++ errno = err;
++ printf ("cannot allocate memory: %m\n");
++ return 1;
++ }
++ memcpy (p, buf, sizeof (buf) - 1);
++ memset (p + sizeof (buf) - 1, ' ', sz - sizeof (buf) + 1);
++ printf ("Using O_DIRECT with block size %d\n", sz);
++ }
++ else
++ {
++ p = (void *) buf;
++ sz = sizeof (buf) - 1;
++ }
++
++ cb.aio_fildes = fd;
++ cb.aio_lio_opcode = LIO_WRITE;
++ cb.aio_reqprio = 0;
++ cb.aio_buf = p;
++ cb.aio_nbytes = sz;
++ cb.aio_offset = 0;
++ cb.aio_sigevent.sigev_notify = SIGEV_THREAD;
++ cb.aio_sigevent.sigev_notify_function = thrfct;
++ cb.aio_sigevent.sigev_notify_attributes = NULL;
++ cb.aio_sigevent.sigev_value.sival_ptr = NULL;
++
++ if (lio_listio (LIO_WAIT, arr, 1, NULL) < 0)
++ {
++ if (errno == ENOSYS)
++ {
++ puts ("no aio support in this configuration");
++ return 0;
++ }
++ printf ("lio_listio failed: %m\n");
++ return 1;
++ }
++
++ if (flag != 0)
++ {
++ puts ("thread created, should not have happened");
++ return 1;
++ }
++
++ puts ("all OK");
++
++ return 0;
++}
++
++#include "../test-skeleton.c"
+--- libc/rtkaio/tst-mqueue8.c.jj 2006-05-10 14:27:13.000000000 +0200
++++ libc/rtkaio/tst-mqueue8.c 2006-05-11 11:40:39.000000000 +0200
+@@ -0,0 +1 @@
++#include <rt/tst-mqueue8.c>
+--- libc/rtkaio/tst-aiod64.c.jj 2006-05-11 13:31:34.000000000 +0200
++++ libc/rtkaio/tst-aiod64.c 2006-05-11 13:55:27.000000000 +0200
+@@ -0,0 +1,308 @@
++/* Tests for 64bit AIO in librt.
++ Copyright (C) 1998, 1999, 2000, 2002, 2006 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#define _LARGEFILE_SOURCE 1
++#include <aio.h>
++#include <errno.h>
++#include <error.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include <sys/stat.h>
++#include "tst-aiod.h"
++
++
++/* Prototype for our test function. */
++extern void do_prepare (int argc, char *argv[]);
++extern int do_test (int argc, char *argv[]);
++
++/* We have a preparation function. */
++#define PREPARE do_prepare
++
++/* We might need a bit longer timeout. */
++#define TIMEOUT 20 /* sec */
++
++/* This defines the `main' function and some more. */
++#include <test-skeleton.c>
++
++
++/* These are for the temporary file we generate. */
++char *name;
++int fd;
++char *tmpbuf;
++int blksz = 100;
++
++void
++do_prepare (int argc, char *argv[])
++{
++ char name_len;
++
++ name_len = strlen (test_dir);
++ name = malloc (name_len + sizeof ("/aioXXXXXX"));
++ mempcpy (mempcpy (name, test_dir, name_len),
++ "/aioXXXXXX", sizeof ("/aioXXXXXX"));
++ add_temp_file (name);
++
++ /* Open our test file. */
++ fd = mkstemp (name);
++ if (fd == -1)
++ error (EXIT_FAILURE, errno, "cannot open test file `%s'", name);
++
++ int sz = set_o_direct (fd);
++ if (sz != -1)
++ {
++ blksz = sz;
++ printf ("Using O_DIRECT with block size %d\n", blksz);
++ }
++}
++
++
++static int
++test_file (const void *buf, size_t size, int fd, const char *msg)
++{
++ struct stat st;
++ char *tmp = tmpbuf;
++
++ errno = 0;
++ if (fstat (fd, &st) < 0)
++ {
++ error (0, errno, "%s: failed stat", msg);
++ return 1;
++ }
++
++ if (st.st_size != (off_t) size)
++ {
++ error (0, errno, "%s: wrong size: %lu, should be %lu",
++ msg, (unsigned long int) st.st_size, (unsigned long int) size);
++ return 1;
++ }
++
++ if (pread (fd, tmp, size, 0) != (ssize_t) size)
++ {
++ error (0, errno, "%s: failed pread", msg);
++ return 1;
++ }
++
++ if (memcmp (buf, tmp, size) != 0)
++ {
++ error (0, errno, "%s: failed comparison", msg);
++ return 1;
++ }
++
++ printf ("%s test ok\n", msg);
++
++ return 0;
++}
++
++
++static int
++do_wait (struct aiocb64 **cbp, size_t nent, int allowed_err)
++{
++ int go_on;
++ size_t cnt;
++ int result = 0;
++
++ do
++ {
++ aio_suspend64 ((const struct aiocb64 *const *) cbp, nent, NULL);
++ go_on = 0;
++ for (cnt = 0; cnt < nent; ++cnt)
++ if (cbp[cnt] != NULL)
++ {
++ if (aio_error64 (cbp[cnt]) == EINPROGRESS)
++ go_on = 1;
++ else
++ {
++ if (aio_return64 (cbp[cnt]) == -1
++ && (allowed_err == 0
++ || aio_error64 (cbp[cnt]) != allowed_err))
++ {
++ error (0, aio_error64 (cbp[cnt]), "Operation failed\n");
++ result = 1;
++ }
++ cbp[cnt] = NULL;
++ }
++ }
++ }
++ while (go_on);
++
++ return result;
++}
++
++
++int
++do_test (int argc, char *argv[])
++{
++ struct aiocb64 cbs[10];
++ struct aiocb64 cbs_fsync;
++ struct aiocb64 *cbp[10];
++ struct aiocb64 *cbp_fsync[1];
++ char *buf;
++ size_t cnt;
++ int result = 0;
++
++ buf = mmap (NULL, 20 * blksz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
++ tmpbuf = buf + 10 * blksz;
++ if (buf == MAP_FAILED)
++ {
++ error (0, errno, "mmap failed");
++ return 1;
++ }
++
++ /* Preparation. */
++ for (cnt = 0; cnt < 10; ++cnt)
++ {
++ cbs[cnt].aio_fildes = fd;
++ cbs[cnt].aio_reqprio = 0;
++ cbs[cnt].aio_buf = memset (&buf[cnt * blksz], '0' + cnt, blksz);
++ cbs[cnt].aio_nbytes = blksz;
++ cbs[cnt].aio_offset = cnt * blksz;
++ cbs[cnt].aio_sigevent.sigev_notify = SIGEV_NONE;
++
++ cbp[cnt] = &cbs[cnt];
++ }
++
++ /* First a simple test. */
++ for (cnt = 10; cnt > 0; )
++ if (aio_write64 (cbp[--cnt]) < 0 && errno == ENOSYS)
++ {
++ error (0, 0, "no aio support in this configuration");
++ return 0;
++ }
++ /* Wait 'til the results are there. */
++ result |= do_wait (cbp, 10, 0);
++ /* Test this. */
++ result |= test_file (buf, 10 * blksz, fd, "aio_write");
++
++ /* Read now as we've written it. */
++ memset (buf, '\0', 10 * blksz);
++ /* Issue the commands. */
++ for (cnt = 10; cnt > 0; )
++ {
++ --cnt;
++ cbp[cnt] = &cbs[cnt];
++ aio_read64 (cbp[cnt]);
++ }
++ /* Wait 'til the results are there. */
++ result |= do_wait (cbp, 10, 0);
++ /* Test this. */
++ for (cnt = 0; cnt < 10 * blksz; ++cnt)
++ if (buf[cnt] != '0' + (cnt / blksz))
++ {
++ result = 1;
++ error (0, 0, "comparison failed for aio_read test");
++ break;
++ }
++
++ if (cnt == 10 * blksz)
++ puts ("aio_read test ok");
++
++ /* Remove the test file contents. */
++ if (ftruncate64 (fd, 0) < 0)
++ {
++ error (0, errno, "ftruncate failed\n");
++ result = 1;
++ }
++
++ /* Test lio_listio. */
++ for (cnt = 0; cnt < 10; ++cnt)
++ {
++ cbs[cnt].aio_lio_opcode = LIO_WRITE;
++ cbp[cnt] = &cbs[cnt];
++ }
++ /* Issue the command. */
++ lio_listio64 (LIO_WAIT, cbp, 10, NULL);
++ /* ...and immediately test it since we started it in wait mode. */
++ result |= test_file (buf, 10 * blksz, fd, "lio_listio (write)");
++
++ /* Test aio_fsync. */
++ cbs_fsync.aio_fildes = fd;
++ cbs_fsync.aio_sigevent.sigev_notify = SIGEV_NONE;
++ cbp_fsync[0] = &cbs_fsync;
++
++ /* Remove the test file contents first. */
++ if (ftruncate64 (fd, 0) < 0)
++ {
++ error (0, errno, "ftruncate failed\n");
++ result = 1;
++ }
++
++ /* Write again. */
++ for (cnt = 10; cnt > 0; )
++ aio_write64 (cbp[--cnt]);
++
++ if (aio_fsync64 (O_SYNC, &cbs_fsync) < 0)
++ {
++ error (0, errno, "aio_fsync failed\n");
++ result = 1;
++ }
++ result |= do_wait (cbp_fsync, 1, 0);
++
++ /* ...and test since all data should be on disk now. */
++ result |= test_file (buf, 10 * blksz, fd, "aio_fsync (aio_write)");
++
++ /* Test aio_cancel. */
++ /* Remove the test file contents first. */
++ if (ftruncate64 (fd, 0) < 0)
++ {
++ error (0, errno, "ftruncate failed\n");
++ result = 1;
++ }
++
++ /* Write again. */
++ for (cnt = 10; cnt > 0; )
++ aio_write64 (cbp[--cnt]);
++
++ /* Cancel all requests. */
++ if (aio_cancel64 (fd, NULL) == -1)
++ printf ("aio_cancel64 (fd, NULL) cannot cancel anything\n");
++
++ result |= do_wait (cbp, 10, ECANCELED);
++
++ /* Another test for aio_cancel. */
++ /* Remove the test file contents first. */
++ if (ftruncate64 (fd, 0) < 0)
++ {
++ error (0, errno, "ftruncate failed\n");
++ result = 1;
++ }
++
++ /* Write again. */
++ for (cnt = 10; cnt > 0; )
++ {
++ --cnt;
++ cbp[cnt] = &cbs[cnt];
++ aio_write64 (cbp[cnt]);
++ }
++ puts ("finished3");
++
++ /* Cancel all requests. */
++ for (cnt = 10; cnt > 0; )
++ if (aio_cancel64 (fd, cbp[--cnt]) == -1)
++ /* This is not an error. The request can simply be finished. */
++ printf ("aio_cancel64 (fd, cbp[%Zd]) cannot be canceled\n", cnt);
++ puts ("finished2");
++
++ result |= do_wait (cbp, 10, ECANCELED);
++
++ puts ("finished");
++
++ return result;
++}
--- /dev/null
+2006-01-02 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/s390/bits/setjmp.h (__jmp_buf): Add __s390_jmp_buf
+ struct tag to make C++ happy.
+
+--- libc/sysdeps/s390/bits/setjmp.h 28 Dec 2005 05:41:35 -0000 1.7
++++ libc/sysdeps/s390/bits/setjmp.h 2 Jan 2006 20:46:18 -0000 1.8
+@@ -40,7 +40,7 @@
+
+ #ifndef _ASM
+
+-typedef struct {
++typedef struct __s390_jmp_buf {
+ /* We save registers 6-15. */
+ long int __gregs[10];
+
--- /dev/null
+2006-02-01 Jakub Jelinek <jakub@redhat.com>
+
+ * math/bits/mathcalls.h: Guard __END_NAMESPACE_C99 with the
+ same #if condition as corresponding __BEGIN_NAMESPACE_C99.
+ (scalb): Don't define only if __USE_ISOC99.
+
+--- libc/math/bits/mathcalls.h 14 Jan 2006 12:09:23 -0000 1.21
++++ libc/math/bits/mathcalls.h 1 Feb 2006 19:45:21 -0000 1.22
+@@ -353,10 +353,13 @@ __MATHDECL_1 (int, __signbit,, (_Mdouble
+
+ /* Multiply-add function computed as a ternary operation. */
+ __MATHCALL (fma,, (_Mdouble_ __x, _Mdouble_ __y, _Mdouble_ __z));
++#endif /* Use ISO C99. */
++
++#if defined __USE_MISC || defined __USE_XOPEN_EXTENDED || defined __USE_ISOC99
+ __END_NAMESPACE_C99
++#endif
+
+-# if defined __USE_MISC || defined __USE_XOPEN_EXTENDED
++#if defined __USE_MISC || defined __USE_XOPEN_EXTENDED
+ /* Return X times (2 to the Nth power). */
+ __MATHCALL (scalb,, (_Mdouble_ __x, _Mdouble_ __n));
+-# endif
+-#endif /* Use ISO C99. */
++#endif
--- /dev/null
+2006-05-12 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/unix/sysv/linux/sched_getaffinity.c: Include sys/param.h.
+ (__sched_getaffinity_new): Don't crash if cpusetsize is smaller than
+ sizeof (cpu_set_t).
+
+--- libc/sysdeps/unix/sysv/linux/sched_getaffinity.c.jj 2005-12-19 08:43:50.000000000 +0100
++++ libc/sysdeps/unix/sysv/linux/sched_getaffinity.c 2006-05-12 17:34:33.000000000 +0200
+@@ -20,6 +20,7 @@
+ #include <sched.h>
+ #include <string.h>
+ #include <sysdep.h>
++#include <sys/param.h>
+ #include <sys/types.h>
+ #include <shlib-compat.h>
+
+@@ -28,8 +29,8 @@
+ int
+ __sched_getaffinity_new (pid_t pid, size_t cpusetsize, cpu_set_t *cpuset)
+ {
+- int res = INLINE_SYSCALL (sched_getaffinity, 3, pid, sizeof (cpu_set_t),
+- cpuset);
++ int res = INLINE_SYSCALL (sched_getaffinity, 3, pid,
++ MIN (INT_MAX, cpusetsize), cpuset);
+ if (res != -1)
+ {
+ /* Clean the rest of the memory the kernel didn't do. */
--- /dev/null
+2007-05-25 Ulrich Drepper <drepper@redhat.com>
+
+ * Makefile (tests): Add tst-sem10.
+ * tst-sem10.c: New file.
+
+2007-05-25 Ulrich Drepper <drepper@redhat.com>
+ Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S (sem_timedwait):
+ Move __pthread_enable_asynccancel right before futex syscall.
+ * sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S (sem_timedwait):
+ Likewise.
+
+--- libc/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S 9 Apr 2006 02:42:29 -0000 1.8
++++ libc/nptl/sysdeps/unix/sysv/linux/i386/i486/sem_timedwait.S 25 May 2007 19:27:03 -0000 1.9
+@@ -79,10 +79,7 @@ sem_timedwait:
+ jae 6f
+
+ cfi_offset(3, -16) /* %ebx */
+-7: call __pthread_enable_asynccancel
+- movl %eax, 8(%esp)
+-
+- xorl %ecx, %ecx
++7: xorl %ecx, %ecx
+ movl %esp, %ebx
+ movl %ecx, %edx
+ movl $SYS_gettimeofday, %eax
+@@ -105,6 +102,10 @@ sem_timedwait:
+
+ movl %ecx, (%esp) /* Store relative timeout. */
+ movl %edx, 4(%esp)
++
++ call __pthread_enable_asynccancel
++ movl %eax, 8(%esp)
++
+ movl 28(%esp), %ebx
+ xorl %ecx, %ecx
+ movl %esp, %esi
+--- libc/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S 15 May 2007 06:24:23 -0000 1.11
++++ libc/nptl/sysdeps/unix/sysv/linux/x86_64/sem_timedwait.S 25 May 2007 19:27:03 -0000 1.12
+@@ -79,10 +79,7 @@ sem_timedwait:
+ cfi_offset(14, -24) /* %r14 */
+ jae 6f
+
+-7: call __pthread_enable_asynccancel
+- movl %eax, 16(%rsp)
+-
+- xorq %rsi, %rsi
++7: xorq %rsi, %rsi
+ movq %rsp, %rdi
+ movq $VSYSCALL_ADDR_vgettimeofday, %rax
+ callq *%rax
+@@ -105,6 +102,9 @@ sem_timedwait:
+ movq %rdi, (%rsp) /* Store relative timeout. */
+ movq %rsi, 8(%rsp)
+
++ call __pthread_enable_asynccancel
++ movl %eax, 16(%rsp)
++
+ movq %rsp, %r10
+ movq %r12, %rdi
+ xorq %rsi, %rsi
+--- libc/nptl/Makefile 18 May 2007 00:52:02 -0000 1.189
++++ libc/nptl/Makefile 26 May 2007 01:30:09 -0000 1.190
+@@ -218,7 +218,7 @@ tests = tst-typesizes \
+ tst-once1 tst-once2 tst-once3 tst-once4 \
+ tst-key1 tst-key2 tst-key3 tst-key4 \
+ tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem5 tst-sem6 tst-sem7 \
+- tst-sem8 tst-sem9 \
++ tst-sem8 tst-sem9 tst-sem10 \
+ tst-barrier1 tst-barrier2 tst-barrier3 tst-barrier4 \
+ tst-align tst-align2 tst-align3 \
+ tst-basic1 tst-basic2 tst-basic3 tst-basic4 tst-basic5 tst-basic6 \
+--- libc/nptl/tst-sem10.c 1 Jan 1970 00:00:00 -0000
++++ libc/nptl/tst-sem10.c 26 May 2007 01:23:04 -0000 1.1
+@@ -0,0 +1,88 @@
++/* Copyright (C) 2007 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Jakub Jelinek <jakub@redhat.com>, 2007.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <errno.h>
++#include <pthread.h>
++#include <semaphore.h>
++#include <stdio.h>
++#include <time.h>
++#include <unistd.h>
++#include <sys/time.h>
++
++
++static int
++do_test (void)
++{
++ sem_t s;
++ if (sem_init (&s, 0, 0) == -1)
++ {
++ puts ("sem_init failed");
++ return 1;
++ }
++
++ struct timeval tv;
++ if (gettimeofday (&tv, NULL) != 0)
++ {
++ puts ("gettimeofday failed");
++ return 1;
++ }
++
++ struct timespec ts;
++ TIMEVAL_TO_TIMESPEC (&tv, &ts);
++
++ /* Set ts to yesterday. */
++ ts.tv_sec -= 86400;
++
++ int type_before;
++ if (pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &type_before) != 0)
++ {
++ puts ("first pthread_setcanceltype failed");
++ return 1;
++ }
++
++ errno = 0;
++ if (TEMP_FAILURE_RETRY (sem_timedwait (&s, &ts)) != -1)
++ {
++ puts ("sem_timedwait succeeded");
++ return 1;
++ }
++ if (errno != ETIMEDOUT)
++ {
++ printf ("sem_timedwait return errno = %d instead of ETIMEDOUT\n",
++ errno);
++ return 1;
++ }
++
++ int type_after;
++ if (pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &type_after) != 0)
++ {
++ puts ("second pthread_setcanceltype failed");
++ return 1;
++ }
++ if (type_after != PTHREAD_CANCEL_DEFERRED)
++ {
++ puts ("sem_timedwait changed cancellation type");
++ return 1;
++ }
++
++ return 0;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
--- /dev/null
+2005-08-01 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/unix/sysv/linux/sigwait.c (do_sigwait): Restart system
+ call if it returned EINTR.
+
+--- libc/sysdeps/unix/sysv/linux/sigwait.c 28 Sep 2004 22:43:12 -0000 1.11
++++ libc/sysdeps/unix/sysv/linux/sigwait.c 1 Aug 2005 19:25:41 -0000 1.12
+@@ -58,8 +58,11 @@ do_sigwait (const sigset_t *set, int *si
+ real size of the user-level sigset_t. */
+ #ifdef INTERNAL_SYSCALL
+ INTERNAL_SYSCALL_DECL (err);
+- ret = INTERNAL_SYSCALL (rt_sigtimedwait, err, 4, CHECK_SIGSET (set),
+- NULL, NULL, _NSIG / 8);
++ do
++ ret = INTERNAL_SYSCALL (rt_sigtimedwait, err, 4, CHECK_SIGSET (set),
++ NULL, NULL, _NSIG / 8);
++ while (INTERNAL_SYSCALL_ERROR_P (ret, err)
++ && INTERNAL_SYSCALL_ERRNO (ret, err) == EINTR);
+ if (! INTERNAL_SYSCALL_ERROR_P (ret, err))
+ {
+ *sig = ret;
+@@ -68,8 +71,10 @@ do_sigwait (const sigset_t *set, int *si
+ else
+ ret = INTERNAL_SYSCALL_ERRNO (ret, err);
+ #else
+- ret = INLINE_SYSCALL (rt_sigtimedwait, 4, CHECK_SIGSET (set),
+- NULL, NULL, _NSIG / 8);
++ do
++ ret = INLINE_SYSCALL (rt_sigtimedwait, 4, CHECK_SIGSET (set),
++ NULL, NULL, _NSIG / 8);
++ while (ret == -1 && errno == EINTR);
+ if (ret != -1)
+ {
+ *sig = ret;
--- /dev/null
+2005-09-17 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #1010]
+ * sysdeps/unix/sockatmark.c (sockatmark): Use SIOCATMARK correctly.
+
+--- libc/sysdeps/unix/sockatmark.c 17 Aug 2001 06:44:34 -0000 1.3
++++ libc/sysdeps/unix/sockatmark.c 17 Sep 2005 23:36:09 -0000 1.4
+@@ -24,5 +24,7 @@ int
+ sockatmark (fd)
+ int fd;
+ {
+- return __ioctl (fd, SIOCATMARK);
++ int answ;
++
++ return __ioctl (fd, SIOCATMARK, &answ) == -1 ? -1 : answ;
+ }
--- /dev/null
+2005-10-17 Ulrich Drepper <drepper@redhat.com>
+
+ * libio/oldfileops.c (_IO_old_file_xsputn): Fix last patch.
+ Return EOF not 0.
+
+2005-09-04 Ulrich Drepper <drepper@redhat.com>
+
+ * stdio-common/Makefile (tests): Add tst-put-error.
+ * stdio-common/tst-put-error.c: New file.
+ * libio/fileops.c (_IO_new_file_xsputn): If overflow fails and no more
+ data would have to be written signal error.
+ * libio/oldfileops.c (_IO_old_file_xsputn): Likewise.
+
+--- libc/libio/fileops.c 6 Dec 2004 22:36:56 -0000 1.107
++++ libc/libio/fileops.c 4 Sep 2005 20:07:40 -0000 1.108
+@@ -1338,7 +1338,9 @@ _IO_new_file_xsputn (f, data, n)
+ _IO_size_t block_size, do_write;
+ /* Next flush the (full) buffer. */
+ if (_IO_OVERFLOW (f, EOF) == EOF)
+- return n - to_do;
++ /* If nothing else has to be written we must not signal the
++ caller that everything has been written. */
++ return to_do == 0 ? EOF : n - to_do;
+
+ /* Try to maintain alignment: write a whole number of blocks.
+ dont_write is what gets left over. */
+--- libc/libio/oldfileops.c 14 Sep 2004 04:24:45 -0000 1.28
++++ libc/libio/oldfileops.c 4 Sep 2005 20:09:33 -0000 1.29
+@@ -752,7 +752,7 @@ _IO_old_file_xsputn (f, data, n)
+ _IO_size_t block_size, do_write;
+ /* Next flush the (full) buffer. */
+ if (__overflow (f, EOF) == EOF)
+- return n - to_do;
++ return to_do == 0 ? EOF : n - to_do;
+
+ /* Try to maintain alignment: write a whole number of blocks.
+ dont_write is what gets left over. */
+--- libc/stdio-common/Makefile 19 Jul 2005 23:39:22 -0000 1.92
++++ libc/stdio-common/Makefile 4 Sep 2005 20:04:54 -0000 1.93
+@@ -53,7 +53,8 @@ tests := tstscanf test_rdwr test-popen t
+ scanf11 scanf12 tst-tmpnam tst-cookie tst-obprintf tst-sscanf \
+ tst-swprintf tst-fseek tst-fmemopen test-vfprintf tst-gets \
+ tst-perror tst-sprintf tst-rndseek tst-fdopen tst-fphex bug14 bug15 \
+- tst-popen tst-unlockedio tst-fmemopen2 tst-fgets tst-fwrite
++ tst-popen tst-unlockedio tst-fmemopen2 tst-put-error tst-fgets \
++ tst-fwrite
+
+ test-srcs = tst-unbputc tst-printf
+
+--- libc/stdio-common/tst-put-error.c 1 Jan 1970 00:00:00 -0000
++++ libc/stdio-common/tst-put-error.c 5 Sep 2005 20:04:34 -0000 1.2
+@@ -0,0 +1,33 @@
++#include <errno.h>
++#include <error.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++
++
++static int
++do_test (void)
++{
++ char tmpl[] = "/tmp/tst-put-error.XXXXXX";
++ int fd = mkstemp (tmpl);
++ if (fd == -1)
++ error (EXIT_FAILURE, errno, "cannot create temporary file");
++ FILE *fp = fdopen (fd, "w");
++ if (fp == NULL)
++ error (EXIT_FAILURE, errno, "fdopen");
++ setlinebuf (fp);
++ close (fd);
++ unlink (tmpl);
++ int n = fprintf (fp, "hello world\n");
++ printf ("fprintf = %d\n", n);
++ if (n >= 0)
++ error (EXIT_FAILURE, 0, "first fprintf succeeded");
++ n = fprintf (fp, "hello world\n");
++ printf ("fprintf = %d\n", n);
++ if (n >= 0)
++ error (EXIT_FAILURE, 0, "second fprintf succeeded");
++ return 0;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
--- /dev/null
+2007-08-03 Jakub Jelinek <jakub@redhat.com>
+
+ * stdlib/strtod_l.c (____STRTOF_INTERNAL): Properly handle -0.
+ * stdlib/Makefile (tests): Add tst-strtod5.
+ (tst-strtod5-ENV): New.
+ * stdlib/tst-strtod5.c: New file.
+
+--- libc/stdlib/Makefile 11 Jan 2007 17:37:12 -0000 1.117
++++ libc/stdlib/Makefile 3 Aug 2007 16:45:35 -0000 1.118
+@@ -64,7 +64,8 @@ tests := tst-strtol tst-strtod testmb t
+ tst-xpg-basename tst-random tst-random2 tst-bsearch \
+ tst-limits tst-rand48 bug-strtod tst-setcontext \
+ test-a64l tst-qsort tst-system testmb2 bug-strtod2 \
+- tst-atof1 tst-atof2 tst-strtod2 tst-strtod3 tst-strtod4
++ tst-atof1 tst-atof2 tst-strtod2 tst-strtod3 tst-strtod4 \
++ tst-strtod5
+
+ include ../Makeconfig
+
+@@ -116,6 +117,7 @@ test-canon-ARGS = --test-dir=${common-ob
+ tst-strtod-ENV = LOCPATH=$(common-objpfx)localedata
+ tst-strtod3-ENV = LOCPATH=$(common-objpfx)localedata
+ tst-strtod4-ENV = LOCPATH=$(common-objpfx)localedata
++tst-strtod5-ENV = LOCPATH=$(common-objpfx)localedata
+ testmb2-ENV = LOCPATH=$(common-objpfx)localedata
+
+ # Run a test on the header files we use.
+--- libc/stdlib/strtod_l.c 22 Feb 2007 04:14:02 -0000 1.24
++++ libc/stdlib/strtod_l.c 3 Aug 2007 16:45:24 -0000 1.25
+@@ -700,7 +700,8 @@ ____STRTOF_INTERNAL (nptr, endptr, group
+ #endif
+ /* If TP is at the start of the digits, there was no correctly
+ grouped prefix of the string; so no number found. */
+- RETURN (0.0, tp == start_of_digits ? (base == 16 ? cp - 1 : nptr) : tp);
++ RETURN (negative ? -0.0 : 0.0,
++ tp == start_of_digits ? (base == 16 ? cp - 1 : nptr) : tp);
+ }
+
+ /* Remember first significant digit and read following characters until the
+@@ -759,7 +760,7 @@ ____STRTOF_INTERNAL (nptr, endptr, group
+ if (tp < startp)
+ /* The number is validly grouped, but consists
+ only of zeroes. The whole value is zero. */
+- RETURN (0.0, tp);
++ RETURN (negative ? -0.0 : 0.0, tp);
+
+ /* Recompute DIG_NO so we won't read more digits than
+ are properly grouped. */
+@@ -862,7 +863,7 @@ ____STRTOF_INTERNAL (nptr, endptr, group
+ {
+ /* Overflow or underflow. */
+ __set_errno (ERANGE);
+- result = (exp_negative ? 0.0 :
++ result = (exp_negative ? (negative ? -0.0 : 0.0) :
+ negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL);
+ }
+
+--- libc/stdlib/tst-strtod5.c 1 Jan 1970 00:00:00 -0000
++++ libc/stdlib/tst-strtod5.c 3 Aug 2007 16:45:08 -0000 1.1
+@@ -0,0 +1,88 @@
++#include <locale.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <math.h>
++
++#define NBSP "\xc2\xa0"
++
++static const struct
++{
++ const char *in;
++ int group;
++ double expected;
++} tests[] =
++ {
++ { "0", 0, 0.0 },
++ { "000", 0, 0.0 },
++ { "-0", 0, -0.0 },
++ { "-000", 0, -0.0 },
++ { "0,", 0, 0.0 },
++ { "-0,", 0, -0.0 },
++ { "0,0", 0, 0.0 },
++ { "-0,0", 0, -0.0 },
++ { "0e-10", 0, 0.0 },
++ { "-0e-10", 0, -0.0 },
++ { "0,e-10", 0, 0.0 },
++ { "-0,e-10", 0, -0.0 },
++ { "0,0e-10", 0, 0.0 },
++ { "-0,0e-10", 0, -0.0 },
++ { "0e-1000000", 0, 0.0 },
++ { "-0e-1000000", 0, -0.0 },
++ { "0,0e-1000000", 0, 0.0 },
++ { "-0,0e-1000000", 0, -0.0 },
++ { "0", 1, 0.0 },
++ { "000", 1, 0.0 },
++ { "-0", 1, -0.0 },
++ { "-000", 1, -0.0 },
++ { "0e-10", 1, 0.0 },
++ { "-0e-10", 1, -0.0 },
++ { "0e-1000000", 1, 0.0 },
++ { "-0e-1000000", 1, -0.0 },
++ { "000"NBSP"000"NBSP"000", 1, 0.0 },
++ { "-000"NBSP"000"NBSP"000", 1, -0.0 }
++ };
++#define NTESTS (sizeof (tests) / sizeof (tests[0]))
++
++
++static int
++do_test (void)
++{
++ if (setlocale (LC_ALL, "cs_CZ.UTF-8") == NULL)
++ {
++ puts ("could not set locale");
++ return 1;
++ }
++
++ int status = 0;
++
++ for (int i = 0; i < NTESTS; ++i)
++ {
++ char *ep;
++ double r;
++
++ if (tests[i].group)
++ r = __strtod_internal (tests[i].in, &ep, 1);
++ else
++ r = strtod (tests[i].in, &ep);
++
++ if (*ep != '\0')
++ {
++ printf ("%d: got rest string \"%s\", expected \"\"\n", i, ep);
++ status = 1;
++ }
++
++ if (r != tests[i].expected
++ || copysign (10.0, r) != copysign (10.0, tests[i].expected))
++ {
++ printf ("%d: got wrong results %g, expected %g\n",
++ i, r, tests[i].expected);
++ status = 1;
++ }
++ }
++
++ return status;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
--- /dev/null
+2006-12-11 Ulrich Drepper <drepper@redhat.com>
+
+ * stdlib/strtod_l.c (____STRTOF_INTERNAL): Parse thousand
+ separators also if no non-zero digits found.
+ * stdlib/Makefile (tests): Add tst-strtod3.
+
+2006-12-09 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #3664]
+ * stdlib/strtod_l.c (____STRTOF_INTERNAL): Fix test to recognize
+ empty parsed strings.
+ * stdlib/Makefile (tests): Add tst-strtod2.
+ * stdlib/tst-strtod2.c: New file.
+
+ [BZ #3673]
+ * stdlib/strtod_l.c (____STRTOF_INTERNAL): Fix exp_limit
+ computation.
+ * stdlib/Makefile (tests): Add tst-atof2.
+ * stdlib/tst-atof2.c: New file.
+
+ [BZ #3674]
+ * stdlib/strtod_l.c (____STRTOF_INTERNAL): Adjust exponent value
+ correctly if removing trailing zero of hex-float.
+ * stdlib/Makefile (tests): Add tst-atof1.
+ * stdlib/tst-atof1.c: New file.
+
+--- libc/stdlib/strtod_l.c 14 Jan 2006 12:09:09 -0000 1.14
++++ libc/stdlib/strtod_l.c 11 Dec 2006 21:43:48 -0000 1.19
+@@ -662,20 +662,20 @@ ____STRTOF_INTERNAL (nptr, endptr, group
+
+ /* If no other digit but a '0' is found the result is 0.0.
+ Return current read pointer. */
+- if ((c < L_('0') || c > L_('9'))
+- && (base == 16 && (c < (CHAR_TYPE) TOLOWER (L_('a'))
+- || c > (CHAR_TYPE) TOLOWER (L_('f'))))
++ if (!((c >= L_('0') && c <= L_('9'))
++ || (base == 16 && ((CHAR_TYPE) TOLOWER (c) >= L_('a')
++ && (CHAR_TYPE) TOLOWER (c) <= L_('f')))
+ #ifdef USE_WIDE_CHAR
+- && c != (wint_t) decimal
++ || c == (wint_t) decimal
+ #else
+- && ({ for (cnt = 0; decimal[cnt] != '\0'; ++cnt)
++ || ({ for (cnt = 0; decimal[cnt] != '\0'; ++cnt)
+ if (decimal[cnt] != cp[cnt])
+ break;
+- decimal[cnt] != '\0'; })
++ decimal[cnt] == '\0'; })
+ #endif
+- && (base == 16 && (cp == start_of_digits
+- || (CHAR_TYPE) TOLOWER (c) != L_('p')))
+- && (base != 16 && (CHAR_TYPE) TOLOWER (c) != L_('e')))
++ || (base == 16 && (cp != start_of_digits
++ && (CHAR_TYPE) TOLOWER (c) == L_('p')))
++ || (base != 16 && (CHAR_TYPE) TOLOWER (c) == L_('e'))))
+ {
+ #ifdef USE_WIDE_CHAR
+ tp = __correctly_grouped_prefixwc (start_of_digits, cp, thousands,
+@@ -721,7 +721,7 @@ ____STRTOF_INTERNAL (nptr, endptr, group
+ c = *++cp;
+ }
+
+- if (grouping && dig_no > 0)
++ if (grouping && cp > start_of_digits)
+ {
+ /* Check the grouping of the digits. */
+ #ifdef USE_WIDE_CHAR
+@@ -759,13 +759,15 @@ ____STRTOF_INTERNAL (nptr, endptr, group
+ }
+ }
+
+- /* We have the number digits in the integer part. Whether these are all or
+- any is really a fractional digit will be decided later. */
++ /* We have the number of digits in the integer part. Whether these
++ are all or any is really a fractional digit will be decided
++ later. */
+ int_no = dig_no;
+ lead_zero = int_no == 0 ? -1 : 0;
+
+- /* Read the fractional digits. A special case are the 'american style'
+- numbers like `16.' i.e. with decimal but without trailing digits. */
++ /* Read the fractional digits. A special case are the 'american
++ style' numbers like `16.' i.e. with decimal point but without
++ trailing digits. */
+ if (
+ #ifdef USE_WIDE_CHAR
+ c == (wint_t) decimal
+@@ -815,15 +817,16 @@ ____STRTOF_INTERNAL (nptr, endptr, group
+ if (base == 16)
+ exp_limit = (exp_negative ?
+ -MIN_EXP + MANT_DIG + 4 * int_no :
+- MAX_EXP - 4 * int_no + lead_zero);
++ MAX_EXP - 4 * int_no + 4 * lead_zero + 3);
+ else
+ exp_limit = (exp_negative ?
+ -MIN_10_EXP + MANT_DIG + int_no :
+- MAX_10_EXP - int_no + lead_zero);
++ MAX_10_EXP - int_no + lead_zero + 1);
+
+ do
+ {
+ exponent *= 10;
++ exponent += c - L_('0');
+
+ if (exponent > exp_limit)
+ /* The exponent is too large/small to represent a valid
+@@ -853,7 +856,6 @@ ____STRTOF_INTERNAL (nptr, endptr, group
+ /* NOTREACHED */
+ }
+
+- exponent += c - L_('0');
+ c = *++cp;
+ }
+ while (c >= L_('0') && c <= L_('9'));
+@@ -888,7 +890,7 @@ ____STRTOF_INTERNAL (nptr, endptr, group
+ --expp;
+ --dig_no;
+ --int_no;
+- ++exponent;
++ exponent += base == 16 ? 4 : 1;
+ }
+ while (dig_no > 0 && exponent < 0);
+
+--- libc/stdlib/Makefile 28 Oct 2006 06:44:04 -0000 1.110
++++ libc/stdlib/Makefile 11 Dec 2006 21:43:10 -0000 1.113
+@@ -66,7 +66,8 @@ tests := tst-strtol tst-strtod testmb t
+ test-canon test-canon2 tst-strtoll tst-environ \
+ tst-xpg-basename tst-random tst-random2 tst-bsearch \
+ tst-limits tst-rand48 bug-strtod tst-setcontext \
+- test-a64l tst-qsort tst-system testmb2 bug-strtod2
++ test-a64l tst-qsort tst-system testmb2 bug-strtod2 \
++ tst-atof1 tst-atof2 tst-strtod2 tst-strtod3
+
+ include ../Makeconfig
+
+--- libc/stdlib/tst-atof1.c 1 Jan 1970 00:00:00 -0000
++++ libc/stdlib/tst-atof1.c 10 Dec 2006 09:54:35 -0000 1.1
+@@ -0,0 +1,19 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++static int
++do_test (void)
++{
++ char buf[100];
++ snprintf (buf, sizeof (buf), "%g", atof ("0x10p-1"));
++ if (strcmp (buf, "8") != 0)
++ {
++ printf ("got \"%s\", expected \"8\"\n", buf);
++ return 1;
++ }
++ return 0;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- libc/stdlib/tst-atof2.c 1 Jan 1970 00:00:00 -0000
++++ libc/stdlib/tst-atof2.c 10 Dec 2006 01:10:17 -0000 1.1
+@@ -0,0 +1,55 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++
++static const struct
++{
++ const char *str;
++ const char *expected;
++} tests[] =
++ {
++ { "1e308", "1e+308" },
++ { "100000000e300", "1e+308" },
++ { "0x1p1023", "8.98847e+307" },
++ { "0x1000p1011", "8.98847e+307" },
++ { "0x1p1020", "1.12356e+307" },
++ { "0x0.00001p1040", "1.12356e+307" },
++ { "1e-307", "1e-307" },
++ { "0.000001e-301", "1e-307" },
++ { "0.0000001e-300", "1e-307" },
++ { "0.00000001e-299", "1e-307" },
++ { "1000000e-313", "1e-307" },
++ { "10000000e-314", "1e-307" },
++ { "100000000e-315", "1e-307" },
++ { "0x1p-1021", "4.45015e-308" },
++ { "0x1000p-1033", "4.45015e-308" },
++ { "0x10000p-1037", "4.45015e-308" },
++ { "0x0.001p-1009", "4.45015e-308" },
++ { "0x0.0001p-1005", "4.45015e-308" },
++ };
++#define NTESTS (sizeof (tests) / sizeof (tests[0]))
++
++
++static int
++do_test (void)
++{
++ int status = 0;
++
++ for (int i = 0; i < NTESTS; ++i)
++ {
++ char buf[100];
++ snprintf (buf, sizeof (buf), "%g", atof (tests[i].str));
++ if (strcmp (buf, tests[i].expected) != 0)
++ {
++ printf ("%d: got \"%s\", expected \"%s\"\n",
++ i, buf, tests[i].expected);
++ status = 1;
++ }
++ }
++
++ return status;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- libc/stdlib/tst-strtod2.c 1 Jan 1970 00:00:00 -0000
++++ libc/stdlib/tst-strtod2.c 11 Dec 2006 21:36:30 -0000 1.2
+@@ -0,0 +1,25 @@
++#include <stdio.h>
++#include <stdlib.h>
++
++static int
++do_test (void)
++{
++ int status = 0;
++ const char s[] = "0x";
++ char *ep;
++ double r = strtod (s, &ep);
++ if (r != 0)
++ {
++ printf ("r = %g, expect 0\n", r);
++ status = 1;
++ }
++ if (ep != s + 1)
++ {
++ printf ("strtod parsed %ju characters, expected 1\n", ep - s);
++ status = 1;
++ }
++ return status;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
+--- libc/stdlib/tst-strtod3.c 1 Jan 1970 00:00:00 -0000
++++ libc/stdlib/tst-strtod3.c 11 Dec 2006 21:43:01 -0000 1.1
+@@ -0,0 +1,55 @@
++#include <locale.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++static const struct
++{
++ const char *in;
++ const char *out;
++ double expected;
++} tests[] =
++ {
++ { "000,,,e1", ",,,e1", 0.0 },
++ { "000e1", "", 0.0 },
++ { "000,1e1", ",1e1", 0.0 }
++ };
++#define NTESTS (sizeof (tests) / sizeof (tests[0]))
++
++
++static int
++do_test (void)
++{
++ if (setlocale (LC_ALL, "en_US.ISO-8859-1") == NULL)
++ {
++ puts ("could not set locale");
++ return 1;
++ }
++
++ int status = 0;
++
++ for (int i = 0; i < NTESTS; ++i)
++ {
++ char *ep;
++ double r = __strtod_internal (tests[i].in, &ep, 1);
++
++ if (strcmp (ep, tests[i].out) != 0)
++ {
++ printf ("%d: got rest string \"%s\", expected \"%s\"\n",
++ i, ep, tests[i].out);
++ status = 1;
++ }
++
++ if (r != tests[i].expected)
++ {
++ printf ("%d: got wrong results %g, expected %g\n",
++ i, r, tests[i].expected);
++ status = 1;
++ }
++ }
++
++ return status;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
--- /dev/null
+2006-11-10 Jakub Jelinek <jakub@redhat.com>
+
+ * string/strxfrm_l.c (STRXFRM): Fix trailing \1 optimization
+ if N is one bigger than return value.
+ * string/tst-strxfrm2.c (do_test): Also test strxfrm with l1 + 1
+ and l1 last arguments, if buf is defined, verify the return value
+ equals to strlen (buf) and verify no byte beyond passed length
+ is modified.
+
+2006-11-09 Ulrich Drepper <drepper@redhat.com>
+
+ * string/Makefile (tests): Add tst-strxfrm2.
+ * string/tst-strxfrm2.c: New file.
+
+2006-11-08 Jakub Jelinek <jakub@redhat.com>
+
+ * string/strxfrm_l.c (STRXFRM): Do the trailing \1 removal
+ optimization even if needed > n.
+
+--- libc/string/Makefile 4 Jun 2006 16:35:25 -0000 1.69
++++ libc/string/Makefile 9 Nov 2006 20:19:24 -0000 1.70
+@@ -54,7 +54,7 @@ tests := tester inl-tester noinl-tester
+ bug-strncat1 bug-strspn1 bug-strpbrk1 tst-bswap \
+ tst-strtok tst-strxfrm bug-strcoll1 tst-strfry \
+ bug-strtok1 $(addprefix test-,$(strop-tests)) \
+- bug-envz1
++ bug-envz1 tst-strxfrm2
+ distribute := memcopy.h pagecopy.h tst-svc.expect test-string.h
+
+
+--- libc/string/strxfrm_l.c 15 Oct 2005 20:49:18 -0000 1.5
++++ libc/string/strxfrm_l.c 10 Nov 2006 15:18:46 -0000 1.7
+@@ -96,6 +97,7 @@ STRXFRM (STRING_TYPE *dest, const STRING
+ const int32_t *indirect;
+ uint_fast32_t pass;
+ size_t needed;
++ size_t last_needed;
+ const USTRING_TYPE *usrc;
+ size_t srclen = STRLEN (src);
+ int32_t *idxarr;
+@@ -197,6 +199,7 @@ STRXFRM (STRING_TYPE *dest, const STRING
+ this is true for all of them. */
+ int position = rule & sort_position;
+
++ last_needed = needed;
+ if (position == 0)
+ {
+ for (idxcnt = 0; idxcnt < idxmax; ++idxcnt)
+@@ -426,11 +429,11 @@ STRXFRM (STRING_TYPE *dest, const STRING
+ a `position' rule at the end and if no non-ignored character
+ is found the last \1 byte is immediately followed by a \0 byte
+ signalling this. We can avoid the \1 byte(s). */
+- if (needed <= n && needed > 2 && dest[needed - 2] == L('\1'))
++ if (needed > 2 && needed == last_needed + 1)
+ {
+ /* Remove the \1 byte. */
+- --needed;
+- dest[needed - 1] = L('\0');
++ if (--needed <= n)
++ dest[needed - 1] = L('\0');
+ }
+
+ /* Free the memory if needed. */
+--- libc/string/tst-strxfrm2.c 1 Jan 1970 00:00:00 -0000
++++ libc/string/tst-strxfrm2.c 10 Nov 2006 15:20:23 -0000 1.2
+@@ -0,0 +1,83 @@
++#include <locale.h>
++#include <stdio.h>
++#include <string.h>
++
++static int
++do_test (void)
++{
++ int res = 0;
++
++ char buf[20];
++ size_t l1 = strxfrm (NULL, "ab", 0);
++ size_t l2 = strxfrm (buf, "ab", 1);
++ size_t l3 = strxfrm (buf, "ab", sizeof (buf));
++ if (l3 < sizeof (buf) && strlen (buf) != l3)
++ {
++ puts ("C locale l3 test failed");
++ res = 1;
++ }
++
++ size_t l4 = strxfrm (buf, "ab", l1 + 1);
++ if (l4 < l1 + 1 && strlen (buf) != l4)
++ {
++ puts ("C locale l4 test failed");
++ res = 1;
++ }
++
++ buf[l1] = 'Z';
++ size_t l5 = strxfrm (buf, "ab", l1);
++ if (buf[l1] != 'Z')
++ {
++ puts ("C locale l5 test failed");
++ res = 1;
++ }
++
++ if (l1 != l2 || l1 != l3 || l1 != l4 || l1 != l5)
++ {
++ puts ("C locale retval test failed");
++ res = 1;
++ }
++
++ if (setlocale (LC_ALL, "de_DE.UTF-8") == NULL)
++ {
++ puts ("setlocale failed");
++ res = 1;
++ }
++ else
++ {
++ l1 = strxfrm (NULL, "ab", 0);
++ l2 = strxfrm (buf, "ab", 1);
++ l3 = strxfrm (buf, "ab", sizeof (buf));
++ if (l3 < sizeof (buf) && strlen (buf) != l3)
++ {
++ puts ("UTF-8 locale l3 test failed");
++ res = 1;
++ }
++
++ l4 = strxfrm (buf, "ab", l1 + 1);
++ if (l4 < l1 + 1 && strlen (buf) != l4)
++ {
++ puts ("UTF-8 locale l4 test failed");
++ res = 1;
++ }
++
++ buf[l1] = 'Z';
++ l5 = strxfrm (buf, "ab", l1);
++ if (buf[l1] != 'Z')
++ {
++ puts ("UTF-8 locale l5 test failed");
++ res = 1;
++ }
++
++ if (l1 != l2 || l1 != l3 || l1 != l4 || l1 != l5)
++ {
++ puts ("UTF-8 locale retval test failed");
++ res = 1;
++ }
++ }
++
++ return res;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
--- /dev/null
+2006-02-01 Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/unix/sysv/linux/i386/sysconf.c (intel_02_known): Add
+ some more entries.
+ * sysdeps/unix/sysv/linux/x86_64/sysconf.c (intel_02_known): Likewise.
+
+--- libc/sysdeps/unix/sysv/linux/i386/sysconf.c 5 Oct 2004 09:20:50 -0000 1.5
++++ libc/sysdeps/unix/sysv/linux/i386/sysconf.c 1 Feb 2006 18:26:19 -0000 1.6
+@@ -84,11 +84,24 @@ static const struct intel_02_cache_info
+ { 0x29, _SC_LEVEL3_CACHE_SIZE, 4194304, 8, 64 },
+ { 0x2c, _SC_LEVEL1_DCACHE_SIZE, 32768, 8, 64 },
+ { 0x30, _SC_LEVEL1_ICACHE_SIZE, 32768, 8, 64 },
++ { 0x39, _SC_LEVEL2_CACHE_SIZE, 131072, 4, 64 },
++ { 0x3a, _SC_LEVEL2_CACHE_SIZE, 196608, 6, 64 },
++ { 0x3b, _SC_LEVEL2_CACHE_SIZE, 131072, 2, 64 },
++ { 0x3c, _SC_LEVEL2_CACHE_SIZE, 262144, 4, 64 },
++ { 0x3d, _SC_LEVEL2_CACHE_SIZE, 393216, 6, 64 },
++ { 0x3e, _SC_LEVEL2_CACHE_SIZE, 524288, 4, 64 },
+ { 0x41, _SC_LEVEL2_CACHE_SIZE, 131072, 4, 32 },
+ { 0x42, _SC_LEVEL2_CACHE_SIZE, 262144, 4, 32 },
+ { 0x43, _SC_LEVEL2_CACHE_SIZE, 524288, 4, 32 },
+ { 0x44, _SC_LEVEL2_CACHE_SIZE, 1048576, 4, 32 },
+ { 0x45, _SC_LEVEL2_CACHE_SIZE, 2097152, 4, 32 },
++ { 0x46, _SC_LEVEL3_CACHE_SIZE, 4194304, 4, 64 },
++ { 0x47, _SC_LEVEL3_CACHE_SIZE, 8388608, 8, 64 },
++ { 0x49, _SC_LEVEL3_CACHE_SIZE, 4194304, 16, 64 },
++ { 0x4a, _SC_LEVEL3_CACHE_SIZE, 6291456, 12, 64 },
++ { 0x4b, _SC_LEVEL3_CACHE_SIZE, 8388608, 16, 64 },
++ { 0x4c, _SC_LEVEL3_CACHE_SIZE, 12582912, 12, 64 },
++ { 0x4d, _SC_LEVEL3_CACHE_SIZE, 16777216, 16, 64 },
+ { 0x60, _SC_LEVEL1_DCACHE_SIZE, 16384, 8, 64 },
+ { 0x66, _SC_LEVEL1_DCACHE_SIZE, 8192, 4, 64 },
+ { 0x67, _SC_LEVEL1_DCACHE_SIZE, 16384, 4, 64 },
+@@ -99,6 +112,7 @@ static const struct intel_02_cache_info
+ { 0x7b, _SC_LEVEL2_CACHE_SIZE, 524288, 8, 64 },
+ { 0x7c, _SC_LEVEL2_CACHE_SIZE, 1048576, 8, 64 },
+ { 0x7d, _SC_LEVEL2_CACHE_SIZE, 2097152, 8, 64 },
++ { 0x7f, _SC_LEVEL2_CACHE_SIZE, 524288, 2, 64 },
+ { 0x82, _SC_LEVEL2_CACHE_SIZE, 262144, 8, 32 },
+ { 0x83, _SC_LEVEL2_CACHE_SIZE, 524288, 8, 32 },
+ { 0x84, _SC_LEVEL2_CACHE_SIZE, 1048576, 8, 32 },
+--- libc/sysdeps/unix/sysv/linux/x86_64/sysconf.c 5 Oct 2004 09:23:06 -0000 1.3
++++ libc/sysdeps/unix/sysv/linux/x86_64/sysconf.c 2 Feb 2006 05:33:33 -0000 1.4
+@@ -45,11 +45,24 @@ static const struct intel_02_cache_info
+ { 0x29, _SC_LEVEL3_CACHE_SIZE, 4194304, 8, 64 },
+ { 0x2c, _SC_LEVEL1_DCACHE_SIZE, 32768, 8, 64 },
+ { 0x30, _SC_LEVEL1_ICACHE_SIZE, 32768, 8, 64 },
++ { 0x39, _SC_LEVEL2_CACHE_SIZE, 131072, 4, 64 },
++ { 0x3a, _SC_LEVEL2_CACHE_SIZE, 196608, 6, 64 },
++ { 0x3b, _SC_LEVEL2_CACHE_SIZE, 131072, 2, 64 },
++ { 0x3c, _SC_LEVEL2_CACHE_SIZE, 262144, 4, 64 },
++ { 0x3d, _SC_LEVEL2_CACHE_SIZE, 393216, 6, 64 },
++ { 0x3e, _SC_LEVEL2_CACHE_SIZE, 524288, 4, 64 },
+ { 0x41, _SC_LEVEL2_CACHE_SIZE, 131072, 4, 32 },
+ { 0x42, _SC_LEVEL2_CACHE_SIZE, 262144, 4, 32 },
+ { 0x43, _SC_LEVEL2_CACHE_SIZE, 524288, 4, 32 },
+ { 0x44, _SC_LEVEL2_CACHE_SIZE, 1048576, 4, 32 },
+ { 0x45, _SC_LEVEL2_CACHE_SIZE, 2097152, 4, 32 },
++ { 0x46, _SC_LEVEL3_CACHE_SIZE, 4194304, 4, 64 },
++ { 0x47, _SC_LEVEL3_CACHE_SIZE, 8388608, 8, 64 },
++ { 0x49, _SC_LEVEL3_CACHE_SIZE, 4194304, 16, 64 },
++ { 0x4a, _SC_LEVEL3_CACHE_SIZE, 6291456, 12, 64 },
++ { 0x4b, _SC_LEVEL3_CACHE_SIZE, 8388608, 16, 64 },
++ { 0x4c, _SC_LEVEL3_CACHE_SIZE, 12582912, 12, 64 },
++ { 0x4d, _SC_LEVEL3_CACHE_SIZE, 16777216, 16, 64 },
+ { 0x60, _SC_LEVEL1_DCACHE_SIZE, 16384, 8, 64 },
+ { 0x66, _SC_LEVEL1_DCACHE_SIZE, 8192, 4, 64 },
+ { 0x67, _SC_LEVEL1_DCACHE_SIZE, 16384, 4, 64 },
+@@ -60,6 +73,7 @@ static const struct intel_02_cache_info
+ { 0x7b, _SC_LEVEL2_CACHE_SIZE, 524288, 8, 64 },
+ { 0x7c, _SC_LEVEL2_CACHE_SIZE, 1048576, 8, 64 },
+ { 0x7d, _SC_LEVEL2_CACHE_SIZE, 2097152, 8, 64 },
++ { 0x7f, _SC_LEVEL2_CACHE_SIZE, 524288, 2, 64 },
+ { 0x82, _SC_LEVEL2_CACHE_SIZE, 262144, 8, 32 },
+ { 0x83, _SC_LEVEL2_CACHE_SIZE, 524288, 8, 32 },
+ { 0x84, _SC_LEVEL2_CACHE_SIZE, 1048576, 8, 32 },
--- /dev/null
+2005-10-14 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #865]
+ * math/tgmath.h: Correctly determine result type for
+ __TGMATH_BINARY_REAL_ONLY,
+ __TGMATH_TERNARY_FIRST_SECOND_REAL_ONLY,
+ __TGMATH_TERNARY_REAL_ONLY, and __TGMATH_BINARY_REAL_IMAG.
+
+2005-09-17 Andreas Jaeger <aj@suse.de>
+
+ [BZ #865]
+ * math/test-tgmath-int.c: New file.
+ * math/Makefile (tests): Add test-tgmath-int.
+
+--- libc/math/tgmath.h 7 May 2004 02:13:19 -0000 1.24
++++ libc/math/tgmath.h 15 Oct 2005 00:13:49 -0000 1.25
+@@ -98,7 +98,8 @@
+ __tgmres; }))
+
+ # define __TGMATH_BINARY_REAL_ONLY(Val1, Val2, Fct) \
+- (__extension__ ({ __tgmath_real_type ((Val1) + (Val2)) __tgmres; \
++ (__extension__ ({ __typeof((__tgmath_real_type (Val1)) 0 \
++ + (__tgmath_real_type (Val2)) 0) __tgmres; \
+ if ((sizeof (Val1) > sizeof (double) \
+ || sizeof (Val2) > sizeof (double)) \
+ && __builtin_classify_type ((Val1) + (Val2)) == 8) \
+@@ -113,7 +114,8 @@
+ __tgmres; }))
+
+ # define __TGMATH_TERNARY_FIRST_SECOND_REAL_ONLY(Val1, Val2, Val3, Fct) \
+- (__extension__ ({ __tgmath_real_type ((Val1) + (Val2)) __tgmres; \
++ (__extension__ ({ __typeof((__tgmath_real_type (Val1)) 0 \
++ + (__tgmath_real_type (Val2)) 0) __tgmres; \
+ if ((sizeof (Val1) > sizeof (double) \
+ || sizeof (Val2) > sizeof (double)) \
+ && __builtin_classify_type ((Val1) + (Val2)) == 8) \
+@@ -128,7 +130,9 @@
+ __tgmres; }))
+
+ # define __TGMATH_TERNARY_REAL_ONLY(Val1, Val2, Val3, Fct) \
+- (__extension__ ({ __tgmath_real_type ((Val1) + (Val2) + (Val3)) __tgmres;\
++ (__extension__ ({ __typeof((__tgmath_real_type (Val1)) 0 \
++ + (__tgmath_real_type (Val2)) 0 \
++ + (__tgmath_real_type (Val3)) 0) __tgmres; \
+ if ((sizeof (Val1) > sizeof (double) \
+ || sizeof (Val2) > sizeof (double) \
+ || sizeof (Val3) > sizeof (double)) \
+@@ -209,7 +213,8 @@
+ /* XXX This definition has to be changed as soon as the compiler understands
+ the imaginary keyword. */
+ # define __TGMATH_BINARY_REAL_IMAG(Val1, Val2, Fct, Cfct) \
+- (__extension__ ({ __tgmath_real_type ((Val1) + (Val2)) __tgmres; \
++ (__extension__ ({ __typeof((__tgmath_real_type (Val1)) 0 \
++ + (__tgmath_real_type (Val2)) 0) __tgmres; \
+ if ((sizeof (__real__ (Val1)) > sizeof (double) \
+ || sizeof (__real__ (Val2)) > sizeof (double)) \
+ && __builtin_classify_type (__real__ (Val1) \
+--- libc/math/Makefile 6 May 2004 18:58:08 -0000 1.126
++++ libc/math/Makefile 15 Oct 2005 00:15:45 -0000 1.127
+@@ -89,7 +89,7 @@ distribute += $(filter-out $(generated),
+ # Rules for the test suite.
+ tests = test-matherr test-fenv atest-exp atest-sincos atest-exp2 basic-test \
+ test-misc test-fpucw tst-definitions test-tgmath test-tgmath-ret \
+- bug-nextafter bug-nexttoward bug-tgmath1
++ bug-nextafter bug-nexttoward bug-tgmath1 test-tgmath-int
+ # We do the `long double' tests only if this data type is available and
+ # distinct from `double'.
+ test-longdouble-yes = test-ldouble test-ildoubl
+--- libc/math/test-tgmath-int.c 1 Jan 1970 00:00:00 -0000
++++ libc/math/test-tgmath-int.c 15 Oct 2005 00:15:17 -0000 1.1
+@@ -0,0 +1,71 @@
++/* Test compilation of tgmath macros.
++ Copyright (C) 2005 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Andreas Jaeger <aj@suse.de>, 2005.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <math.h>
++#include <complex.h>
++#include <tgmath.h>
++#include <stdio.h>
++
++static int errors = 0;
++
++static void
++our_error (const char *c)
++{
++ puts (c);
++ ++errors;
++}
++
++#define CHECK_RET_CONST_TYPE(func, rettype, name) \
++ if (sizeof (func) != sizeof (rettype)) \
++ our_error ("Return size of " #name " is " #func" wrong");
++
++#define CHECK_RET_CONST_FLOAT(func, name) \
++ CHECK_RET_CONST_TYPE (func, float, name)
++
++#define CHECK_RET_CONST_DOUBLE(func, name) \
++ CHECK_RET_CONST_TYPE (func, double, name)
++
++static int
++do_test (void)
++{
++ int i;
++ float f;
++ double d;
++
++ CHECK_RET_CONST_DOUBLE (sin (i), "sin (i)");
++ CHECK_RET_CONST_DOUBLE (pow (i, i), "pow (i, i)");
++ CHECK_RET_CONST_DOUBLE (pow (i, i), "pow (i, i)");
++ CHECK_RET_CONST_DOUBLE (pow (i, f), "pow (i, f)");
++ CHECK_RET_CONST_DOUBLE (pow (i, d), "pow (i, d)");
++ CHECK_RET_CONST_DOUBLE (pow (f, i), "pow (f, i)");
++ CHECK_RET_CONST_DOUBLE (pow (d, i), "pow (d, i)");
++ CHECK_RET_CONST_DOUBLE (fma (i, i, i), "fma (i, i, i)");
++ CHECK_RET_CONST_DOUBLE (fma (f, i, i), "fma (f, i, i)");
++ CHECK_RET_CONST_DOUBLE (fma (i, f, i), "fma (i, f, i)");
++ CHECK_RET_CONST_DOUBLE (fma (i, i, f), "fma (i, i, f)");
++ CHECK_RET_CONST_DOUBLE (fma (d, i, i), "fma (d, i, i)");
++ CHECK_RET_CONST_DOUBLE (fma (i, d, i), "fma (i, d, i)");
++ CHECK_RET_CONST_DOUBLE (fma (i, i, d), "fma (i, i, d)");
++
++ return errors != 0;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
--- /dev/null
+2005-09-22 Roland McGrath <roland@redhat.com>
+
+ * elf/dl-tsd.c (__libc_dl_error_tsd): Use attribute_tls_model_ie for
+ static __thread variable.
+ From Alexandre Oliva <aoliva@redhat.com>
+
+--- libc/elf/dl-tsd.c 4 Dec 2002 12:27:51 -0000 1.3
++++ libc/elf/dl-tsd.c 22 Sep 2005 07:29:47 -0000 1.4
+@@ -49,7 +49,7 @@ void **(*_dl_error_catch_tsd) (void) __a
+ void ** __attribute__ ((const))
+ __libc_dl_error_tsd (void)
+ {
+- static __thread void *data;
++ static __thread void *data attribute_tls_model_ie;
+ return &data;
+ }
+
--- /dev/null
+2006-01-09 Roland McGrath <roland@redhat.com>
+
+ * tst-initializers1-c89.c: New file.
+ * tst-initializers1-c99.c: New file.
+ * tst-initializers1-gnu89.c: New file.
+ * tst-initializers1-gnu99.c: New file.
+ * Makefile (tests): Add them.
+ (CFLAGS-tst-initializers1-c89.c): New variable.
+ (CFLAGS-tst-initializers1-c99.c): New variable.
+ (CFLAGS-tst-initializers1-gnu89.c): New variable.
+ (CFLAGS-tst-initializers1-gnu99.c): New variable.
+
+--- libc/nptl/Makefile 5 Jan 2006 08:16:20 -0000 1.175
++++ libc/nptl/Makefile 9 Jan 2006 23:04:44 -0000 1.176
+@@ -246,7 +246,8 @@ tests = tst-typesizes \
+ tst-backtrace1 \
+ tst-oddstacklimit \
+ tst-vfork1 tst-vfork2 tst-vfork1x tst-vfork2x \
+- tst-getpid1 tst-getpid2 tst-initializers1
++ tst-getpid1 tst-getpid2 \
++ tst-initializers1 $(patsubst %,tst-initializers1-%,c89 gnu89 c99 gnu99)
+ xtests = tst-setuid1 tst-setuid1-static
+
+ # Files which must not be linked with libpthread.
+@@ -415,7 +416,13 @@ CFLAGS-tst-oncex3.c += -fexceptions
+ CFLAGS-tst-oncex4.c += -fexceptions
+ CFLAGS-tst-align.c += $(stack-align-test-flags)
+ CFLAGS-tst-align3.c += $(stack-align-test-flags)
+-CFLAGS-tst-initializers1.c += -W -Wall -Werror
++CFLAGS-tst-initializers1.c = -W -Wall -Werror
++CFLAGS-tst-initializers1-< = $(CFLAGS-tst-initializers1.c) \
++ $(patsubst tst-initializers1-%.c,-std=%,$<)
++CFLAGS-tst-initializers1-c89.c = $(CFLAGS-tst-initializers1-<)
++CFLAGS-tst-initializers1-c99.c = $(CFLAGS-tst-initializers1-<)
++CFLAGS-tst-initializers1-gnu89.c = $(CFLAGS-tst-initializers1-<)
++CFLAGS-tst-initializers1-gnu99.c = $(CFLAGS-tst-initializers1-<)
+
+ tst-cancel7-ARGS = --command "$(built-program-cmd)"
+ tst-cancelx7-ARGS = $(tst-cancel7-ARGS)
+--- libc/nptl/tst-initializers1-c89.c 1 Jan 1970 00:00:00 -0000
++++ libc/nptl/tst-initializers1-c89.c 9 Jan 2006 23:04:44 -0000 1.1
+@@ -0,0 +1 @@
++#include "tst-initializers1.c"
+--- libc/nptl/tst-initializers1-c99.c 1 Jan 1970 00:00:00 -0000
++++ libc/nptl/tst-initializers1-c99.c 9 Jan 2006 23:04:44 -0000 1.1
+@@ -0,0 +1 @@
++#include "tst-initializers1.c"
+--- libc/nptl/tst-initializers1-gnu89.c 1 Jan 1970 00:00:00 -0000
++++ libc/nptl/tst-initializers1-gnu89.c 9 Jan 2006 23:04:44 -0000 1.1
+@@ -0,0 +1 @@
++#include "tst-initializers1.c"
+--- libc/nptl/tst-initializers1-gnu99.c 1 Jan 1970 00:00:00 -0000
++++ libc/nptl/tst-initializers1-gnu99.c 9 Jan 2006 23:04:44 -0000 1.1
+@@ -0,0 +1 @@
++#include "tst-initializers1.c"
--- /dev/null
+2005-12-28 Ulrich Drepper <drepper@redhat.com>
+
+ * Makefile (tests): Add tst-signal7.
+ * tst-signal7.c: New file.
+
+--- libc/nptl/Makefile 27 Dec 2005 00:53:17 -0000 1.173
++++ libc/nptl/Makefile 28 Dec 2005 20:48:24 -0000 1.174
+@@ -229,7 +229,7 @@ tests = tst-typesizes \
+ tst-cleanup0 tst-cleanup1 tst-cleanup2 tst-cleanup3 tst-cleanup4 \
+ tst-flock1 tst-flock2 \
+ tst-signal1 tst-signal2 tst-signal3 tst-signal4 tst-signal5 \
+- tst-signal6 \
++ tst-signal6 tst-signal7 \
+ tst-exec1 tst-exec2 tst-exec3 tst-exec4 \
+ tst-exit1 tst-exit2 tst-exit3 \
+ tst-stdio1 tst-stdio2 \
+--- libc/nptl/tst-signal7.c 1 Jan 1970 00:00:00 -0000
++++ libc/nptl/tst-signal7.c 28 Dec 2005 20:48:38 -0000 1.1
+@@ -0,0 +1,59 @@
++/* Copyright (C) 2005 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Ulrich Drepper <drepper@redhat.com>, 2005.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <errno.h>
++#include <pthreadP.h>
++#include <signal.h>
++#include <stdio.h>
++
++
++static int
++do_test (void)
++{
++ int result = 0;
++
++ errno = 0;
++ if (sigaction (SIGCANCEL, NULL, NULL) == 0)
++ {
++ puts ("sigaction(SIGCANCEL) did not fail");
++ result = 1;
++ }
++ else if (errno != EINVAL)
++ {
++ puts ("sigaction(SIGCANCEL) did not set errno to EINVAL");
++ result = 1;
++ }
++
++ errno = 0;
++ if (sigaction (SIGSETXID, NULL, NULL) == 0)
++ {
++ puts ("sigaction(SIGSETXID) did not fail");
++ result = 1;
++ }
++ else if (errno != EINVAL)
++ {
++ puts ("sigaction(SIGSETXID) did not set errno to EINVAL");
++ result = 1;
++ }
++
++ return result;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
--- /dev/null
+2005-09-12 Jakub Jelinek <jakub@redhat.com>
+
+ * fedora/tzdata-update.c: New file.
+
+--- libc/fedora/tzdata-update.c 2004-06-24 14:04:38.000000000 -0400
++++ libc/fedora/tzdata-update.c 2005-09-12 12:10:55.000000000 -0400
+@@ -0,0 +1,589 @@
++#ifdef __sparc__
++register void *__thread_self __asm ("g7");
++#endif
++#define _GNU_SOURCE 1
++#include <errno.h>
++#include <fcntl.h>
++#include <stdlib.h>
++#include <string.h>
++#include <syscall.h>
++#include <unistd.h>
++
++#if defined __i386__
++# define INTERNAL_SYSCALL_DECL(err) do { } while (0)
++# define INTERNAL_SYSCALL(name, err, nr, args...) \
++ ({ \
++ register unsigned int resultvar; \
++ asm volatile ( \
++ "movl %1, %%eax\n\t" \
++ "int $0x80\n\t" \
++ : "=a" (resultvar) \
++ : "i" (__NR_##name) ASMFMT_##nr(args) : "memory", "cc"); \
++ (int) resultvar; })
++# define INTERNAL_SYSCALL_ERROR_P(val, err) \
++ ((unsigned int) (val) >= 0xfffff001u)
++# define ASMFMT_0()
++# define ASMFMT_1(arg1) \
++ , "b" (arg1)
++# define ASMFMT_2(arg1, arg2) \
++ , "b" (arg1), "c" (arg2)
++# define ASMFMT_3(arg1, arg2, arg3) \
++ , "b" (arg1), "c" (arg2), "d" (arg3)
++#elif defined __x86_64__
++# define INTERNAL_SYSCALL_DECL(err) do { } while (0)
++# define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
++ ({ \
++ unsigned long resultvar; \
++ LOAD_ARGS_##nr (args) \
++ LOAD_REGS_##nr \
++ asm volatile ( \
++ "syscall\n\t" \
++ : "=a" (resultvar) \
++ : "0" (name) ASM_ARGS_##nr : "memory", "cc", "r11", "cx"); \
++ (long) resultvar; })
++# define INTERNAL_SYSCALL(name, err, nr, args...) \
++ INTERNAL_SYSCALL_NCS (__NR_##name, err, nr, ##args)
++# define INTERNAL_SYSCALL_ERROR_P(val, err) \
++ ((unsigned long) (val) >= -4095L)
++# define LOAD_ARGS_0()
++# define LOAD_REGS_0
++# define ASM_ARGS_0
++# define LOAD_ARGS_1(a1) \
++ long int __arg1 = (long) (a1); \
++ LOAD_ARGS_0 ()
++# define LOAD_REGS_1 \
++ register long int _a1 asm ("rdi") = __arg1; \
++ LOAD_REGS_0
++# define ASM_ARGS_1 ASM_ARGS_0, "r" (_a1)
++# define LOAD_ARGS_2(a1, a2) \
++ long int __arg2 = (long) (a2); \
++ LOAD_ARGS_1 (a1)
++# define LOAD_REGS_2 \
++ register long int _a2 asm ("rsi") = __arg2; \
++ LOAD_REGS_1
++# define ASM_ARGS_2 ASM_ARGS_1, "r" (_a2)
++# define LOAD_ARGS_3(a1, a2, a3) \
++ long int __arg3 = (long) (a3); \
++ LOAD_ARGS_2 (a1, a2)
++# define LOAD_REGS_3 \
++ register long int _a3 asm ("rdx") = __arg3; \
++ LOAD_REGS_2
++# define ASM_ARGS_3 ASM_ARGS_2, "r" (_a3)
++#elif defined __powerpc__
++# define INTERNAL_SYSCALL_DECL(err) long int err
++# define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
++ ({ \
++ register long int r0 __asm__ ("r0"); \
++ register long int r3 __asm__ ("r3"); \
++ register long int r4 __asm__ ("r4"); \
++ register long int r5 __asm__ ("r5"); \
++ register long int r6 __asm__ ("r6"); \
++ register long int r7 __asm__ ("r7"); \
++ register long int r8 __asm__ ("r8"); \
++ LOADARGS_##nr(name, args); \
++ __asm__ __volatile__ \
++ ("sc\n\t" \
++ "mfcr %0\n\t" \
++ : "=&r" (r0), \
++ "=&r" (r3), "=&r" (r4), "=&r" (r5), \
++ "=&r" (r6), "=&r" (r7), "=&r" (r8) \
++ : ASM_INPUT_##nr \
++ : "r9", "r10", "r11", "r12", \
++ "cr0", "ctr", "memory"); \
++ err = r0; \
++ (int) r3; \
++ })
++# define INTERNAL_SYSCALL(name, err, nr, args...) \
++ INTERNAL_SYSCALL_NCS (__NR_##name, err, nr, ##args)
++# define INTERNAL_SYSCALL_ERROR_P(val, err) \
++ ((void) (val), __builtin_expect ((err) & (1 << 28), 0))
++# define LOADARGS_0(name, dummy) \
++ r0 = name
++# define LOADARGS_1(name, __arg1) \
++ long int arg1 = (long int) (__arg1); \
++ LOADARGS_0(name, 0); \
++ r3 = arg1
++# define LOADARGS_2(name, __arg1, __arg2) \
++ long int arg2 = (long int) (__arg2); \
++ LOADARGS_1(name, __arg1); \
++ r4 = arg2
++# define LOADARGS_3(name, __arg1, __arg2, __arg3) \
++ long int arg3 = (long int) (__arg3); \
++ LOADARGS_2(name, __arg1, __arg2); \
++ r5 = arg3
++# define ASM_INPUT_0 "0" (r0)
++# define ASM_INPUT_1 ASM_INPUT_0, "1" (r3)
++# define ASM_INPUT_2 ASM_INPUT_1, "2" (r4)
++# define ASM_INPUT_3 ASM_INPUT_2, "3" (r5)
++#elif defined __ia64__
++# define DO_INLINE_SYSCALL_NCS(name, nr, args...) \
++ LOAD_ARGS_##nr (args) \
++ register long _r8 asm ("r8"); \
++ register long _r10 asm ("r10"); \
++ register long _r15 asm ("r15") = name; \
++ long _retval; \
++ LOAD_REGS_##nr \
++ __asm __volatile ("break 0x100000;;" \
++ : "=r" (_r8), "=r" (_r10), "=r" (_r15) \
++ ASM_OUTARGS_##nr \
++ : "2" (_r15) ASM_ARGS_##nr \
++ : "memory" ASM_CLOBBERS_##nr); \
++ _retval = _r8;
++# define INTERNAL_SYSCALL_DECL(err) long int err
++# define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
++ ({ \
++ DO_INLINE_SYSCALL_NCS (name, nr, args) \
++ err = _r10; \
++ _retval; })
++# define INTERNAL_SYSCALL(name, err, nr, args...) \
++ INTERNAL_SYSCALL_NCS (__NR_##name, err, nr, ##args)
++# define INTERNAL_SYSCALL_ERROR_P(val, err) (err == -1)
++# define LOAD_ARGS_0()
++# define LOAD_REGS_0
++# define LOAD_ARGS_1(a1) \
++ long _arg1 = (long) (a1); \
++ LOAD_ARGS_0 ()
++# define LOAD_REGS_1 \
++ register long _out0 asm ("out0") = _arg1; \
++ LOAD_REGS_0
++# define LOAD_ARGS_2(a1, a2) \
++ long _arg2 = (long) (a2); \
++ LOAD_ARGS_1 (a1)
++# define LOAD_REGS_2 \
++ register long _out1 asm ("out1") = _arg2; \
++ LOAD_REGS_1
++# define LOAD_ARGS_3(a1, a2, a3) \
++ long _arg3 = (long) (a3); \
++ LOAD_ARGS_2 (a1, a2)
++# define LOAD_REGS_3 \
++ register long _out2 asm ("out2") = _arg3; \
++ LOAD_REGS_2
++# define ASM_OUTARGS_0
++# define ASM_OUTARGS_1 ASM_OUTARGS_0, "=r" (_out0)
++# define ASM_OUTARGS_2 ASM_OUTARGS_1, "=r" (_out1)
++# define ASM_OUTARGS_3 ASM_OUTARGS_2, "=r" (_out2)
++# define ASM_ARGS_0
++# define ASM_ARGS_1 ASM_ARGS_0, "3" (_out0)
++# define ASM_ARGS_2 ASM_ARGS_1, "4" (_out1)
++# define ASM_ARGS_3 ASM_ARGS_2, "5" (_out2)
++# define ASM_CLOBBERS_0 ASM_CLOBBERS_1, "out0"
++# define ASM_CLOBBERS_1 ASM_CLOBBERS_2, "out1"
++# define ASM_CLOBBERS_2 ASM_CLOBBERS_3, "out2"
++# define ASM_CLOBBERS_3 ASM_CLOBBERS_4, "out3"
++# define ASM_CLOBBERS_4 ASM_CLOBBERS_5, "out4"
++# define ASM_CLOBBERS_5 ASM_CLOBBERS_6, "out5"
++# define ASM_CLOBBERS_6_COMMON , "out6", "out7", \
++ /* Non-stacked integer registers, minus r8, r10, r15. */ \
++ "r2", "r3", "r9", "r11", "r12", "r13", "r14", "r16", "r17", "r18", \
++ "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", \
++ "r28", "r29", "r30", "r31", \
++ /* Predicate registers. */ \
++ "p6", "p7", "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15", \
++ /* Non-rotating fp registers. */ \
++ "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \
++ /* Branch registers. */ \
++ "b6"
++# define ASM_CLOBBERS_6 ASM_CLOBBERS_6_COMMON , "b7"
++#elif defined __s390__
++# define INTERNAL_SYSCALL_DECL(err) do { } while (0)
++# define INTERNAL_SYSCALL_DIRECT(name, err, nr, args...) \
++ ({ \
++ DECLARGS_##nr(args) \
++ register long _ret asm("2"); \
++ asm volatile ( \
++ "svc %b1\n\t" \
++ : "=d" (_ret) \
++ : "i" (__NR_##name) ASMFMT_##nr \
++ : "memory" ); \
++ _ret; })
++# define INTERNAL_SYSCALL_SVC0(name, err, nr, args...) \
++ ({ \
++ DECLARGS_##nr(args) \
++ register unsigned long _nr asm("1") = (unsigned long)(__NR_##name); \
++ register long _ret asm("2"); \
++ asm volatile ( \
++ "svc 0\n\t" \
++ : "=d" (_ret) \
++ : "d" (_nr) ASMFMT_##nr \
++ : "memory" ); \
++ _ret; })
++# define INTERNAL_SYSCALL(name, err, nr, args...) \
++ (((__NR_##name) < 256) ? \
++ INTERNAL_SYSCALL_DIRECT(name, err, nr, args) : \
++ INTERNAL_SYSCALL_SVC0(name, err,nr, args))
++# define INTERNAL_SYSCALL_ERROR_P(val, err) \
++ ((unsigned long) (val) >= -4095UL)
++# define DECLARGS_0()
++# define DECLARGS_1(arg1) \
++ register unsigned long gpr2 asm ("2") = (unsigned long)(arg1);
++# define DECLARGS_2(arg1, arg2) \
++ DECLARGS_1(arg1) \
++ register unsigned long gpr3 asm ("3") = (unsigned long)(arg2);
++# define DECLARGS_3(arg1, arg2, arg3) \
++ DECLARGS_2(arg1, arg2) \
++ register unsigned long gpr4 asm ("4") = (unsigned long)(arg3);
++# define ASMFMT_0
++# define ASMFMT_1 , "0" (gpr2)
++# define ASMFMT_2 , "0" (gpr2), "d" (gpr3)
++# define ASMFMT_3 , "0" (gpr2), "d" (gpr3), "d" (gpr4)
++#elif defined __sparc__
++# ifndef __arch64__
++# define __INTERNAL_SYSCALL_STRING \
++ "ta 0x10;" \
++ "bcs,a 1f;" \
++ " sub %%g0, %%o0, %%o0;" \
++ "1:"
++# define __SYSCALL_CLOBBERS "g2", "g3", "g4", "g5", "g6", \
++ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
++ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \
++ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", \
++ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", \
++ "cc", "memory"
++# else
++# define __INTERNAL_SYSCALL_STRING \
++ "ta 0x6d;" \
++ "bcs,a,pt %%xcc, 1f;" \
++ " sub %%g0, %%o0, %%o0;" \
++ "1:"
++# define __SYSCALL_CLOBBERS "g2", "g3", "g4", "g5", "g6", \
++ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
++ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \
++ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", \
++ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", \
++ "f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46", \
++ "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62", \
++ "cc", "memory"
++# endif
++#define INTERNAL_SYSCALL_DECL(err) do { } while (0)
++#define INTERNAL_SYSCALL(name, err, nr, args...) \
++ inline_syscall##nr(__INTERNAL_SYSCALL_STRING, __NR_##name, args)
++#define INTERNAL_SYSCALL_ERROR_P(val, err) \
++ ((unsigned long) (val) >= -515L)
++# define inline_syscall0(string,name,dummy...) \
++({ \
++ register long __o0 __asm__ ("o0"); \
++ register long __g1 __asm__ ("g1") = name; \
++ __asm __volatile (string : "=r" (__g1), "=r" (__o0) : \
++ "0" (__g1) : \
++ __SYSCALL_CLOBBERS); \
++ __o0; \
++})
++# define inline_syscall1(string,name,arg1) \
++({ \
++ register long __o0 __asm__ ("o0") = (long)(arg1); \
++ register long __g1 __asm__ ("g1") = name; \
++ __asm __volatile (string : "=r" (__g1), "=r" (__o0) : \
++ "0" (__g1), "1" (__o0) : \
++ __SYSCALL_CLOBBERS); \
++ __o0; \
++})
++# define inline_syscall2(string,name,arg1,arg2) \
++({ \
++ register long __o0 __asm__ ("o0") = (long)(arg1); \
++ register long __o1 __asm__ ("o1") = (long)(arg2); \
++ register long __g1 __asm__ ("g1") = name; \
++ __asm __volatile (string : "=r" (__g1), "=r" (__o0) : \
++ "0" (__g1), "1" (__o0), "r" (__o1) : \
++ __SYSCALL_CLOBBERS); \
++ __o0; \
++})
++# define inline_syscall3(string,name,arg1,arg2,arg3) \
++({ \
++ register long __o0 __asm__ ("o0") = (long)(arg1); \
++ register long __o1 __asm__ ("o1") = (long)(arg2); \
++ register long __o2 __asm__ ("o2") = (long)(arg3); \
++ register long __g1 __asm__ ("g1") = name; \
++ __asm __volatile (string : "=r" (__g1), "=r" (__o0) : \
++ "0" (__g1), "1" (__o0), "r" (__o1), \
++ "r" (__o2) : \
++ __SYSCALL_CLOBBERS); \
++ __o0; \
++})
++#elif defined __alpha__
++# define INTERNAL_SYSCALL(name, err_out, nr, args...) \
++ INTERNAL_SYSCALL1(name, err_out, nr, args)
++# define INTERNAL_SYSCALL1(name, err_out, nr, args...) \
++ INTERNAL_SYSCALL_NCS(__NR_##name, err_out, nr, args)
++# define INTERNAL_SYSCALL_NCS(name, err_out, nr, args...) \
++({ \
++ long _sc_ret, _sc_err; \
++ inline_syscall##nr(name, args); \
++ err_out = _sc_err; \
++ _sc_ret; \
++})
++# define INTERNAL_SYSCALL_DECL(err) long int err
++# define INTERNAL_SYSCALL_ERROR_P(val, err) err
++# define inline_syscall_clobbers \
++ "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", \
++ "$22", "$23", "$24", "$25", "$27", "$28", "memory"
++# define inline_syscall_r0_asm
++# define inline_syscall_r0_out_constraint "=v"
++# define inline_syscall0(name, args...) \
++{ \
++ register long _sc_0 inline_syscall_r0_asm; \
++ register long _sc_19 __asm__("$19"); \
++ \
++ _sc_0 = name; \
++ __asm__ __volatile__ \
++ ("callsys # %0 %1 <= %2" \
++ : inline_syscall_r0_out_constraint (_sc_0), \
++ "=r"(_sc_19) \
++ : "0"(_sc_0) \
++ : inline_syscall_clobbers, \
++ "$16", "$17", "$18", "$20", "$21"); \
++ _sc_ret = _sc_0, _sc_err = _sc_19; \
++}
++# define inline_syscall1(name,arg1) \
++{ \
++ register long _sc_0 inline_syscall_r0_asm; \
++ register long _sc_16 __asm__("$16"); \
++ register long _sc_19 __asm__("$19"); \
++ \
++ _sc_0 = name; \
++ _sc_16 = (long) (arg1); \
++ __asm__ __volatile__ \
++ ("callsys # %0 %1 <= %2 %3" \
++ : inline_syscall_r0_out_constraint (_sc_0), \
++ "=r"(_sc_19), "=r"(_sc_16) \
++ : "0"(_sc_0), "2"(_sc_16) \
++ : inline_syscall_clobbers, \
++ "$17", "$18", "$20", "$21"); \
++ _sc_ret = _sc_0, _sc_err = _sc_19; \
++}
++# define inline_syscall2(name,arg1,arg2) \
++{ \
++ register long _sc_0 inline_syscall_r0_asm; \
++ register long _sc_16 __asm__("$16"); \
++ register long _sc_17 __asm__("$17"); \
++ register long _sc_19 __asm__("$19"); \
++ \
++ _sc_0 = name; \
++ _sc_16 = (long) (arg1); \
++ _sc_17 = (long) (arg2); \
++ __asm__ __volatile__ \
++ ("callsys # %0 %1 <= %2 %3 %4" \
++ : inline_syscall_r0_out_constraint (_sc_0), \
++ "=r"(_sc_19), "=r"(_sc_16), "=r"(_sc_17) \
++ : "0"(_sc_0), "2"(_sc_16), "3"(_sc_17) \
++ : inline_syscall_clobbers, \
++ "$18", "$20", "$21"); \
++ _sc_ret = _sc_0, _sc_err = _sc_19; \
++}
++# define inline_syscall3(name,arg1,arg2,arg3) \
++{ \
++ register long _sc_0 inline_syscall_r0_asm; \
++ register long _sc_16 __asm__("$16"); \
++ register long _sc_17 __asm__("$17"); \
++ register long _sc_18 __asm__("$18"); \
++ register long _sc_19 __asm__("$19"); \
++ \
++ _sc_0 = name; \
++ _sc_16 = (long) (arg1); \
++ _sc_17 = (long) (arg2); \
++ _sc_18 = (long) (arg3); \
++ __asm__ __volatile__ \
++ ("callsys # %0 %1 <= %2 %3 %4 %5" \
++ : inline_syscall_r0_out_constraint (_sc_0), \
++ "=r"(_sc_19), "=r"(_sc_16), "=r"(_sc_17), \
++ "=r"(_sc_18) \
++ : "0"(_sc_0), "2"(_sc_16), "3"(_sc_17), \
++ "4"(_sc_18) \
++ : inline_syscall_clobbers, "$20", "$21"); \
++ _sc_ret = _sc_0, _sc_err = _sc_19; \
++}
++#endif
++
++char buffer[32768], data[32768];
++size_t datasize;
++char zonename[1024];
++
++ssize_t
++readall (int fd, void *buf, size_t len)
++{
++ INTERNAL_SYSCALL_DECL (err);
++ size_t n = len;
++ ssize_t ret;
++ do
++ {
++ ret = INTERNAL_SYSCALL (read, err, 3, fd, buf, n);
++ if (INTERNAL_SYSCALL_ERROR_P (ret, err))
++ {
++ ret = -1;
++ break;
++ }
++ else if (ret == 0)
++ break;
++ buf = (char *) buf + ret;
++ n -= ret;
++ }
++ while (n > 0);
++ return ret < 0 ? ret : (ssize_t) (len - n);
++}
++
++ssize_t
++writeall (int fd, const void *buf, size_t len)
++{
++ INTERNAL_SYSCALL_DECL (err);
++ size_t n = len;
++ ssize_t ret;
++ do
++ {
++ ret = INTERNAL_SYSCALL (write, err, 3, fd, buf, n);
++ if (INTERNAL_SYSCALL_ERROR_P (ret, err))
++ {
++ ret = -1;
++ break;
++ }
++ else if (ret == 0)
++ break;
++ buf = (const char *) buf + ret;
++ n -= ret;
++ }
++ while (n > 0);
++ return ret < 0 ? ret : (ssize_t) (len - n);
++}
++
++void
++update (const char *filename)
++{
++ INTERNAL_SYSCALL_DECL (err);
++ long int fd = INTERNAL_SYSCALL (open, err, 2, filename, O_RDONLY);
++ if (INTERNAL_SYSCALL_ERROR_P (fd, err))
++ return;
++ ssize_t ret = readall (fd, buffer, sizeof (buffer));
++ INTERNAL_SYSCALL (close, err, 1, fd);
++ if (ret <= 0 || (size_t) ret == sizeof (buffer))
++ return;
++ /* Don't update the file unnecessarily. */
++ if ((size_t) ret == datasize && memcmp (buffer, data, datasize) == 0)
++ return;
++ size_t len = strlen (filename);
++ char tempfilename[len + sizeof (".tzupdate")];
++ memcpy (tempfilename, filename, len);
++ memcpy (tempfilename + len, ".tzupdate", sizeof (".tzupdate"));
++
++ fd = INTERNAL_SYSCALL (open, err, 3, tempfilename, O_WRONLY | O_CREAT | O_EXCL, 0600);
++ if (INTERNAL_SYSCALL_ERROR_P (fd, err))
++ return;
++ if (writeall (fd, data, datasize) != datasize)
++ {
++clean_up:
++ INTERNAL_SYSCALL (unlink, err, 1, tempfilename);
++ INTERNAL_SYSCALL (close, err, 1, fd);
++ return;
++ }
++ long int sret;
++ sret = INTERNAL_SYSCALL (fchmod, err, 2, fd, 0644);
++ if (INTERNAL_SYSCALL_ERROR_P (sret, err))
++ goto clean_up;
++ INTERNAL_SYSCALL (close, err, 1, fd);
++
++ sret = INTERNAL_SYSCALL (rename, err, 2, tempfilename, filename);
++ if (INTERNAL_SYSCALL_ERROR_P (sret, err))
++ INTERNAL_SYSCALL (unlink, err, 1, tempfilename);
++}
++
++int
++main (int argc, char **argv)
++{
++ INTERNAL_SYSCALL_DECL (err);
++ long int fd = INTERNAL_SYSCALL (open, err, 2, "/etc/sysconfig/clock", O_RDONLY);
++ if (INTERNAL_SYSCALL_ERROR_P (fd, err))
++ return 0;
++ ssize_t ret = readall (fd, buffer, sizeof (buffer) - 1);
++ INTERNAL_SYSCALL (close, err, 1, fd);
++ if (ret <= 0 || (size_t) ret == sizeof (buffer) - 1)
++ return 0;
++ char *p = buffer;
++ while (p != NULL)
++ {
++ while (*p == ' ' || *p == '\t') p++;
++ if (memcmp (p, "ZONE", 4) == 0)
++ {
++ p += 4;
++ while (*p == ' ' || *p == '\t') p++;
++ if (*p == '=')
++ {
++ p++;
++ while (*p == ' ' || *p == '\t') p++;
++ if (*p == '"') p++;
++ char *q = p;
++ while (strchr (" \t\n\"", *p) == NULL) p++;
++ const char path[] = "/usr/share/zoneinfo/";
++ if (p - q >= sizeof (zonename) - sizeof (path))
++ return 0;
++ memcpy (zonename, path, sizeof (path) - 1);
++ memcpy (zonename + sizeof (path) - 1, q, p - q);
++ break;
++ }
++ }
++ p = strchr (p, '\n');
++ if (p) p++;
++ }
++ if (*zonename == '\0')
++ return 0;
++ fd = INTERNAL_SYSCALL (open, err, 2, zonename, O_RDONLY);
++ if (INTERNAL_SYSCALL_ERROR_P (fd, err))
++ return 0;
++ ret = readall (fd, data, sizeof (data));
++ INTERNAL_SYSCALL (close, err, 1, fd);
++ if (ret <= 0 || (size_t) ret == sizeof (data))
++ return 0;
++ datasize = (size_t) ret;
++ update ("/etc/localtime");
++ update ("/var/spool/postfix/etc/localtime");
++ return 0;
++}
++
++int __libc_multiple_threads __attribute__((nocommon));
++int __libc_enable_asynccancel (void) { return 0; }
++void __libc_disable_asynccancel (int x) { }
++void __libc_csu_init (void) { }
++void __libc_csu_fini (void) { }
++pid_t __fork (void) { return -1; }
++char thr_buf[65536];
++
++#ifndef __powerpc__
++int __libc_start_main (int (*main) (int argc, char **argv),
++ int argc, char **argv,
++ void (*init) (void), void (*fini) (void),
++ void (*rtld_fini) (void), void * stack_end)
++#else
++struct startup_info
++{
++ void *sda_base;
++ int (*main) (int, char **, char **, void *);
++ int (*init) (int, char **, char **, void *);
++ void (*fini) (void);
++};
++
++int __libc_start_main (int argc, char **argv, char **ev,
++ void *auxvec, void (*rtld_fini) (void),
++ struct startup_info *stinfo,
++ char **stack_on_entry)
++#endif
++{
++#if defined __ia64__ || defined __powerpc64__
++ register void *r13 __asm ("r13") = thr_buf + 32768;
++ __asm ("" : : "r" (r13));
++#elif defined __sparc__
++ register void *g6 __asm ("g6") = thr_buf + 32768;
++ __thread_self = thr_buf + 32768;
++ __asm ("" : : "r" (g6), "r" (__thread_self));
++#elif defined __s390__ && !defined __s390x__
++ __asm ("sar %%a0,%0" : : "d" (thr_buf + 32768));
++#elif defined __s390x__
++ __asm ("sar %%a1,%0; srlg 0,%0,32; sar %%a0,0" : : "d" (thr_buf + 32768) : "0");
++#elif defined __powerpc__ && !defined __powerpc64__
++ register void *r2 __asm ("r2") = thr_buf + 32768;
++ __asm ("" : : "r" (r2));
++#endif
++#ifdef __powerpc__
++ argc = (long)*stack_on_entry;
++ argv = stack_on_entry + 1;
++#endif
++ long ret = main (argc, argv);
++ INTERNAL_SYSCALL_DECL (err);
++ INTERNAL_SYSCALL (exit, err, 1, ret);
++ return 110;
++}
--- /dev/null
+2006-03-16 Roland McGrath <roland@redhat.com>
+
+ * wcsmbs/wchar.h (__wcstol_internal, __wcstoul_internal): Declare these
+ only when we will use them, under [__OPTIMIZE__ && __GNUC__ >= 2].
+ (__wcstoll_internal, __wcstoull_internal_defined): Likewise.
+
+--- libc/wcsmbs/wchar.h 14 Jan 2006 20:14:36 -0000 1.62
++++ libc/wcsmbs/wchar.h 16 Mar 2006 22:10:58 -0000 1.63
+@@ -507,26 +507,30 @@ extern long double __wcstold_internal (_
+ wchar_t **__restrict __endptr,
+ int __group) __THROW;
+
+-#ifndef __wcstol_internal_defined
++#if !defined __wcstol_internal_defined \
++ && defined __OPTIMIZE__ && __GNUC__ >= 2
+ extern long int __wcstol_internal (__const wchar_t *__restrict __nptr,
+ wchar_t **__restrict __endptr,
+ int __base, int __group) __THROW;
+ # define __wcstol_internal_defined 1
+ #endif
+-#ifndef __wcstoul_internal_defined
++#if !defined __wcstoul_internal_defined \
++ && defined __OPTIMIZE__ && __GNUC__ >= 2
+ extern unsigned long int __wcstoul_internal (__const wchar_t *__restrict __npt,
+ wchar_t **__restrict __endptr,
+ int __base, int __group) __THROW;
+ # define __wcstoul_internal_defined 1
+ #endif
+-#ifndef __wcstoll_internal_defined
++#if !defined __wcstoll_internal_defined \
++ && defined __OPTIMIZE__ && __GNUC__ >= 2
+ __extension__
+ extern long long int __wcstoll_internal (__const wchar_t *__restrict __nptr,
+ wchar_t **__restrict __endptr,
+ int __base, int __group) __THROW;
+ # define __wcstoll_internal_defined 1
+ #endif
+-#ifndef __wcstoull_internal_defined
++#if !defined __wcstoull_internal_defined \
++ && defined __OPTIMIZE__ && __GNUC__ >= 2
+ __extension__
+ extern unsigned long long int __wcstoull_internal (__const wchar_t *
+ __restrict __nptr,
--- /dev/null
+2005-07-06 Jakub Jelinek <jakub@redhat.com>
+
+ * sysdeps/x86_64/__longjmp.S (__longjmp): Use 3 instead of %rbx
+ and 5 instead of %rdi in cfi directives to workaround buggy assembler.
+
+--- libc/sysdeps/unix/sysv/linux/x86_64/setcontext.S.jj 2004-01-22 09:17:42.000000000 +0100
++++ libc/sysdeps/unix/sysv/linux/x86_64/setcontext.S 2005-07-06 12:00:02.000000000 +0200
+@@ -59,8 +59,8 @@ ENTRY(__setcontext)
+
+ /* Load the new stack pointer, the preserved registers and
+ registers used for passing args. */
+- cfi_def_cfa(%rdi, 0)
+- cfi_offset(%rbx,oRBX)
++ cfi_def_cfa(5, 0) /* %rdi; workaround for buggy assembler. */
++ cfi_offset(3,oRBX) /* %rbx; workaround for buggy assembler. */
+ cfi_offset(%rbp,oRBP)
+ cfi_offset(%r12,oR12)
+ cfi_offset(%r13,oR13)
+--- libc/sysdeps/x86_64/__longjmp.S.jj 2004-01-11 13:23:01.000000000 +0100
++++ libc/sysdeps/x86_64/__longjmp.S 2005-07-06 12:01:13.000000000 +0200
+@@ -28,8 +28,8 @@
+ ENTRY(__longjmp)
+ /* Restore registers. */
+ /* We add unwind information for the target here. */
+- cfi_def_cfa(%rdi, 0)
+- cfi_offset(%rbx,JB_RBX*8)
++ cfi_def_cfa(5, 0) /* %rdi; workaround for buggy assembler. */
++ cfi_offset(3,JB_RBX*8) /* %rbx; workaround for buggy assembler. */
+ cfi_offset(%rbp,JB_RBP*8)
+ cfi_offset(%r12,JB_R12*8)
+ cfi_offset(%r13,JB_R13*8)
--- /dev/null
+2005-10-14 Jakub Jelinek <jakub@redhat.com>
+ Ulrich Drepper <drepper@redhat.com>
+
+ * sysdeps/unix/sysv/linux/x86_64/pthread_once.S: Fix stack
+ alignment in callback function.
+ * Makefile: Add rules to build and run tst-align3.
+ * tst-align3.c: New file.
+
+--- libc/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S 2003-07-01 19:01:44.000000000 +0200
++++ libc/nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S 2005-10-14 21:22:58.000000000 +0200
+@@ -82,9 +82,11 @@ __pthread_once:
+ /* Preserve the pointer to the control variable. */
+ 3: pushq %rdi
+ .Lpush_rdi:
++ pushq %rdi
++.Lpush_rdi2:
+
+ .LcleanupSTART:
+- callq *8(%rsp)
++ callq *16(%rsp)
+ .LcleanupEND:
+
+ /* Get the control variable address back. */
+@@ -95,6 +97,9 @@ __pthread_once:
+ LOCK
+ incl (%rdi)
+
++ addq $8, %rsp
++.Ladd1:
++
+ /* Wake up all other threads. */
+ movl $0x7fffffff, %edx
+ movl $FUTEX_WAKE, %esi
+@@ -102,7 +107,7 @@ __pthread_once:
+ syscall
+
+ 4: addq $8, %rsp
+-.Ladd:
++.Ladd2:
+ xorq %rax, %rax
+ retq
+
+@@ -220,20 +225,28 @@ clear_once_control:
+ .byte 14 # DW_CFA_def_cfa_offset
+ .uleb128 24
+ .byte 4 # DW_CFA_advance_loc4
+- .long .Lpop_rdi-.Lpush_rdi
++ .long .Lpush_rdi2-.Lpush_rdi
++ .byte 14 # DW_CFA_def_cfa_offset
++ .uleb128 32
++ .byte 4 # DW_CFA_advance_loc4
++ .long .Lpop_rdi-.Lpush_rdi2
++ .byte 14 # DW_CFA_def_cfa_offset
++ .uleb128 24
++ .byte 4 # DW_CFA_advance_loc4
++ .long .Ladd1-.Lpop_rdi
+ .byte 14 # DW_CFA_def_cfa_offset
+ .uleb128 16
+ .byte 4 # DW_CFA_advance_loc4
+- .long .Ladd-.Lpop_rdi
++ .long .Ladd2-.Ladd1
+ .byte 14 # DW_CFA_def_cfa_offset
+ .uleb128 8
+ .byte 4 # DW_CFA_advance_loc4
+- .long clear_once_control-.Ladd
++ .long clear_once_control-.Ladd2
+ .byte 14 # DW_CFA_def_cfa_offset
+- .uleb128 24
++ .uleb128 32
+ #if 0
+ .byte 4 # DW_CFA_advance_loc4
+- .long .Lpop_rdi2-clear_once_control
++ .long .Lpop_rdi3-clear_once_control
+ .byte 14 # DW_CFA_def_cfa_offset
+ .uleb128 16
+ #endif
+--- libc/nptl/Makefile 11 Jul 2005 16:40:21 -0000 1.169
++++ libc/nptl/Makefile 14 Oct 2005 18:50:50 -0000 1.170
+@@ -205,7 +205,7 @@ tests = tst-attr1 tst-attr2 tst-attr3 \
+ tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem5 tst-sem6 tst-sem7 \
+ tst-sem8 tst-sem9 \
+ tst-barrier1 tst-barrier2 tst-barrier3 tst-barrier4 \
+- tst-align tst-align2 \
++ tst-align tst-align2 tst-align3 \
+ tst-basic1 tst-basic2 tst-basic3 tst-basic4 tst-basic5 tst-basic6 \
+ tst-kill1 tst-kill2 tst-kill3 tst-kill4 tst-kill5 tst-kill6 \
+ tst-raise1 \
+@@ -412,6 +412,7 @@ CFLAGS-tst-cleanupx4.c += -fexceptions
+ CFLAGS-tst-oncex3.c += -fexceptions
+ CFLAGS-tst-oncex4.c += -fexceptions
+ CFLAGS-tst-align.c += $(stack-align-test-flags)
++CFLAGS-tst-align3.c += $(stack-align-test-flags)
+ CFLAGS-tst-initializers1.c += -W -Wall -Werror
+
+ tst-cancel7-ARGS = --command "$(built-program-cmd)"
+--- libc/nptl/tst-align3.c 1 Jan 1970 00:00:00 -0000
++++ libc/nptl/tst-align3.c 14 Oct 2005 18:49:29 -0000 1.1
+@@ -0,0 +1,57 @@
++/* Copyright (C) 2005 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++ Contributed by Jakub Jelinek <jakub@redhat.com>, 2005.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <pthread.h>
++#include <stdbool.h>
++#include <stdint.h>
++#include <stdio.h>
++#include <tst-stack-align.h>
++
++static bool ok = true;
++static pthread_once_t once = PTHREAD_ONCE_INIT;
++
++static void
++once_test (void)
++{
++ puts ("in once_test");
++
++ if (TEST_STACK_ALIGN ())
++ ok = false;
++}
++
++static int
++do_test (void)
++{
++ puts ("in main");
++
++ if (TEST_STACK_ALIGN ())
++ ok = false;
++
++ if (pthread_once (&once, once_test))
++ {
++ puts ("pthread once failed");
++ return 1;
++ }
++
++ return ok ? 0 : 1;
++}
++
++
++#define TEST_FUNCTION do_test ()
++#include "../test-skeleton.c"
--- /dev/null
+2005-09-17 Ulrich Drepper <drepper@redhat.com>
+
+ [BZ #1053]
+ * debug/xtrace.sh: Add missing escape character in -? match.
+ Patch by Peter Breitenlohner <peb@mppmu.mpg.de>.
+
+--- libc/debug/xtrace.sh 12 Jan 2005 23:39:52 -0000 1.14
++++ libc/debug/xtrace.sh 17 Sep 2005 17:30:44 -0000 1.15
+@@ -107,7 +107,7 @@ while test $# -gt 0; do
+ --d=* | --da=* | --dat=* | --data=*)
+ data=${1##*=}
+ ;;
+- -? | --h | --he | --hel | --help)
++ -\? | --h | --he | --hel | --help)
+ do_help
+ ;;
+ -V | --v | --ve | --ver | --vers | --versi | --versio | --version)