summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog128
-rw-r--r--catgets/catgets.c2
-rw-r--r--dirent/Makefile2
-rw-r--r--dirent/dirent.h7
-rw-r--r--dirent/readdir_r.c37
-rw-r--r--gmon/gmon.c4
-rw-r--r--inet/rcmd.c9
-rw-r--r--inet/rexec.c4
-rw-r--r--inet/ruserpass.c11
-rw-r--r--libio/stdio.h6
-rw-r--r--locale/programs/ld-time.c6
-rw-r--r--locale/setlocale.c15
-rw-r--r--login/Makefile2
-rw-r--r--login/pty.h43
-rw-r--r--login/pututline_r.c2
-rw-r--r--manual/filesys.texi77
-rw-r--r--misc/Makefile7
-rw-r--r--misc/hsearch_r.c2
-rw-r--r--misc/mntent_r.c8
-rw-r--r--nss/nss_dns/dns-host.c6
-rw-r--r--resolv/res_debug.c2
-rw-r--r--resolv/res_init.c4
-rw-r--r--resolv/res_query.c2
-rw-r--r--stdio-common/tempnam.c14
-rw-r--r--stdio-common/temptest.c3
-rw-r--r--stdio-common/tmpfile.c8
-rw-r--r--stdio-common/tmpnam.c43
-rw-r--r--stdio-common/tmpnam_r.c37
-rw-r--r--stdio/stdio.h9
-rw-r--r--stdlib/stdlib.h4
-rw-r--r--stdlib/test-canon.c20
-rw-r--r--string/string.h1
-rw-r--r--sysdeps/generic/getenv.c23
-rw-r--r--sysdeps/generic/prof-freq.c2
-rw-r--r--sysdeps/generic/pty.c3
-rw-r--r--sysdeps/generic/strsep.c3
-rw-r--r--sysdeps/generic/sys/sysinfo.h8
-rw-r--r--sysdeps/posix/getcwd.c4
-rw-r--r--sysdeps/posix/mk-stdiolim.c8
-rw-r--r--sysdeps/posix/tempname.c58
-rw-r--r--sysdeps/posix/ttyname.c2
-rw-r--r--sysdeps/posix/ttyname_r.c2
-rw-r--r--sysdeps/stub/getenv.c1
-rw-r--r--sysdeps/stub/nanosleep.c6
-rw-r--r--sysdeps/stub/tempname.c4
-rw-r--r--sysdeps/unix/nlist.c4
-rw-r--r--sysdeps/unix/sysv/linux/getsysstats.c9
-rw-r--r--sysdeps/unix/sysv/linux/sleep.c2
-rw-r--r--sysdeps/unix/sysv/linux/sys/sysinfo.h8
-rw-r--r--sysdeps/unix/sysv/linux/syscalls.list14
-rw-r--r--time/strftime.c56
-rw-r--r--time/time.h2
52 files changed, 547 insertions, 197 deletions
diff --git a/ChangeLog b/ChangeLog
index d28ec2d9d1..decbf31275 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,14 +1,126 @@
-Mon Sep 23 15:31:04 1996  Thomas Bushnell, n/BSG  <thomas@gnu.ai.mit.edu>
+Sat Sep 28 03:02:49 1996  Ulrich Drepper  <drepper@cygnus.com>
 
-	* hurd/Makefile ($(includedir)/rpc/netdb.h): There is no make
-	variable `top_srcdir' in libc; use $(..) instead.
+	* dirent/Makefile (routines): Add readdir_r.
+	* dirent/readdir_r.c: New file.  Wrapper around readdir.c.
+	* dirent/dirent.h: Add prototype for readdir_r.
 
-	* sysdeps/mach/hurd/Makefile (rtld-installed-name): Delete special
-	definition.  It was a *Mistake*.  (With a capital M.)
+	* misc/hsearch_r.c (ENTRY): Make field `used' of type `unsigned int'
+	to prevent warnings.
 
-	* sysdeps/mach/getsysstats.c (__get_nprocs): Renamed from
-	__get_nproc.
-	(__get_nprocs_conf): Renamed from __get_nproc_conf.
+	* sysdeps/unix/sysv/linux/getsysstats.c (get_proc_path):
+ 	Initialize `result'.
+
+Sat Sep 28 01:16:42 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+	* sysdeps/generic/strsep.c: Rename to __strsep and make strsep
+	weak alias.
+	* string/string.h: Add prototype for __strsep.
+	* misc/mntent_r.c: Use __strsep instead of strsep to keep
+	namespace clean.
+
+	* sysdeps/stub/nanosleep.c: Rename to __libc_nanosleep and make
+	__nanosleep and nanosleep weak aliases.
+	* sysdeps/unix/sysv/linux/syscalls.list: Add __nanosleep as weak
+	alias.
+	* sysdeps/unix/sysv/linux/sleep.c: Call __nanosleep instead of
+	nanosleep to keep namespace clean.
+
+	* sysdeps/posix/ttyname.c (ttyname): Add cast to prevent warning.
+	* sysdeps/posix/ttyname_r.c (ttyname_r): Likewise.
+	* sysdeps/posix/getcwd.c (__getcwd): Likewise.
+
+	* sysdeps/unix/nlist.c: Use ISO C definition since we don't always
+	have prototype.
+
+	* login/Makefile (headers): Add pty.h.
+	* login/pty.h: New file.
+	* sysdeps/generic/pty.h: Include <pty.h>.
+	* login/pututline_r.c: Add cast to prevent warning.
+
+	* gmon/gmon.c: Add prototype for __profile_frequency.
+	(monstartup): Add cast to prevent warning.
+	* sysdeps/generic/prof-freq.c: Change to use ISO C style definition.
+
+	* locale/programs/ld-time.c (time_output): Write `era' information
+	in correct order.
+
+Sat Sep 28 00:11:08 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+	* sysdeps/unix/sysv/linux/syscalls.list: Add weak alias
+	`adjtimex'.
+	Set caller for mlock, mlockall, mremap, munlock, and munlockall
+	to EXTRA.
+	Reported by Matthias Urlichs <smurf@smurf.noris.de>.
+
+1996-09-27  Paul Eggert  <eggert@twinsun.com>
+
+	* strftime.c (strftime): Output incomplete formats like %E
+	at end of string.
+
+1996-09-27  Paul Eggert  <eggert@twinsun.com>
+
+	* strftime.c (strftime): Add support for %EC and %Ey.
+	Fix support for %EY.  This uses the new _nl_get_era_entry function.
+
+Fri Sep 27 14:12:27 1996  Ulrich Drepper  <drepper@cygnus.com>
+
+	Security related patch by Elliot Lee <sopwith@redhat.com> and
+	David Holland <dholland@eecs.harvard.edu>.
+
+	* inet/rexec.c (rexec): Increase size of `num' array from 8 to 32.
+	* inet/ruserpass.c (ruserpass): Don't allow $HOME envvar to not exist.
+
+	* sysdeps/generic/getenv.c (__secure_getenv): New function.  Return
+	NULL when programs runs with SUID or SGID enabled.
+	* sysdeps/stub/getenv.c: Make __secure_getenv an alias of getenv.
+	* stdlib/stdlib.h: Add prototype for __secure_getenv.
+
+	* locale/setlocale.c: Use __secure_getenv.
+	* resolv/res_init.c: Likewise.
+	* resolv/res_query.c: Likewise.
+	* inet/ruserpass.c: Likewise.
+	* sysdeps/posix/tempname.c: Likewise.
+	* malloc/mtrace.c: Likewise.
+	* catgets/catgets.c: Likewise.
+
+	Make temporary file handling functions reentrant.
+
+	* stdio-common/tmpnam.c: Rewrite to have own buffer to write
+	result to.  The called __stdio_gen_tempname function must be
+	thread safe.
+	* stdio-common/tmpnam_r.c: New file.
+	* stdio/stdio.h: Add prototype for `tmpnam_r'.
+	Change prototype for __stdio_gen_tempname.
+	* stdio/libio.h: Likewise.
+	* sysdeps/posix/tempname.c: Add new parameters and use them instead
+	of static buffer.
+	Don't reset `indeces' when PID changed between calls.
+	Don't fail for long running programs when index counter once
+	reached the limit.
+	* sysdeps/stub/tempname.c: Likewise.
+	* stdio-common/tempnam.c: Provide local buffer as extra argument
+	to __stdio_gen_tempname.  This makes this function reentrant.
+	* stdio-common/tmpfile.c: Likewise.
+	* stdio-common/temptest.c: Provide extra argument to
+	__stdio_gen_tempname.
+	* manual/filesys.texi: Describe tmpnam_r and add comments about
+	reentrancy of the functions.
+
+	* inet/rcmd.c: Fixed address length handling.
+
+	* sysdeps/posix/mk-stdiolim.c: Count final \0 byte in L_tmpnam value.
+
+	* time/strftime.c: Remove unused variables alt_digits and
+ 	end_alt_digits.
+
+	* sysdeps/unix/sysv/linux/sys/sysinfo.h: Correct prototype names
+	for get_nprocs and get_nprocs_conf.
+	* sysdeps/generic/sys/sysinfo.h: Likewise.
+
+	* stdlib/test-canon.c: Finally do the right fix.
+
+	* misc/Makefile: Only compile force-wrapper when compiling
+	reentrant libc.
 
 Fri Sep 27 03:49:56 1996  Ulrich Drepper  <drepper@cygnus.com>
 
diff --git a/catgets/catgets.c b/catgets/catgets.c
index 0abc182414..7c45b4569a 100644
--- a/catgets/catgets.c
+++ b/catgets/catgets.c
@@ -79,7 +79,7 @@ catopen (const char *cat_name, int flag)
 	  return (nl_catd) -1;
 	}
 
-      if (getenv ("NLSPATH") != NULL)
+      if (__secure_getenv ("NLSPATH") != NULL)
 	result->nlspath = __strdup (getenv ("NLSPATH"));
       else
 	result->nlspath = __strdup (NLSPATH);
diff --git a/dirent/Makefile b/dirent/Makefile
index b6a42190eb..8d706dfe64 100644
--- a/dirent/Makefile
+++ b/dirent/Makefile
@@ -22,7 +22,7 @@
 subdir		:= dirent
 
 headers		:= dirent.h direntry.h
-routines	:= opendir closedir readdir rewinddir \
+routines	:= opendir closedir readdir readdir_r rewinddir \
 		   seekdir telldir scandir alphasort \
 		   getdents dirfd
 distribute := dirstream.h
diff --git a/dirent/dirent.h b/dirent/dirent.h
index 02a5e6a18a..06e92cb6b9 100644
--- a/dirent/dirent.h
+++ b/dirent/dirent.h
@@ -116,6 +116,13 @@ extern int closedir __P ((DIR * __dirp));
 extern struct dirent *__readdir __P ((DIR * __dirp));
 extern struct dirent *readdir __P ((DIR * __dirp));
 
+#ifdef __USE_REENTRANT
+/* Reentrant versio of `readdir'.  Return in RESULT a pointer to the
+   next entry.  */
+extern int readdir_r __P ((DIR *__dirp, struct dirent *entry,
+			   struct dirent **result));
+#endif
+
 /* Rewind DIRP to the beginning of the directory.  */
 extern void rewinddir __P ((DIR * __dirp));
 
diff --git a/dirent/readdir_r.c b/dirent/readdir_r.c
new file mode 100644
index 0000000000..b9979660fa
--- /dev/null
+++ b/dirent/readdir_r.c
@@ -0,0 +1,37 @@
+/* readdir_r - Reentrant version of readdir.
+Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#include <dirent.h>
+
+/* Some systems have reentrancy problems with their `readdir'
+   implementation so they have an additional `readdir_r' version.  The
+   GNU version does not have these problems but for compatibility
+   reasons we provide this function.  It is simply a wrapper around
+   the normal function.
+
+   The actual definition of this functions varies very strong from
+   system to system.  We chose to follow the POSIX version.  */
+int
+readdir_r (DIR *dirp, struct dirent *entry, struct dirent **result)
+{
+  *result = readdir (dirp);
+
+  return *result != NULL ? 0 : -1;
+}
diff --git a/gmon/gmon.c b/gmon/gmon.c
index a450d11365..ecf7518bfb 100644
--- a/gmon/gmon.c
+++ b/gmon/gmon.c
@@ -45,6 +45,8 @@
 #include <string.h>
 #include <unistd.h>
 
+extern int __profile_frequency (void);
+
 struct __bb *__bb_head;	/*  Head of basic-block list or NULL. */
 
 struct gmonparam _gmonparam = { GMON_PROF_OFF };
@@ -128,7 +130,7 @@ DEFUN(monstartup, (lowpc, highpc), u_long lowpc AND u_long highpc)
   p->tos[0].link = 0;
 
   o = p->highpc - p->lowpc;
-  if (p->kcountsize < o)
+  if (p->kcountsize < (u_long) o)
     {
 #ifndef hp300
       s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
diff --git a/inet/rcmd.c b/inet/rcmd.c
index 1c63e952dc..a9756d109a 100644
--- a/inet/rcmd.c
+++ b/inet/rcmd.c
@@ -52,6 +52,9 @@ static char sccsid[] = "@(#)rcmd.c	8.3 (Berkeley) 3/26/94";
 #include <ctype.h>
 #include <string.h>
 
+#define MIN(A, B) ((A) < (B) ? (A) : (B))
+
+
 int	__ivaliduser __P((FILE *, u_int32_t, const char *, const char *));
 static int __icheckhost __P((u_int32_t, char *));
 
@@ -92,7 +95,8 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
 		}
 		fcntl(s, F_SETOWN, pid);
 		sin.sin_family = hp->h_addrtype;
-		bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length);
+		bcopy(hp->h_addr_list[0], &sin.sin_addr,
+		      MIN (sizeof (sin.sin_addr), hp->h_length));
 		sin.sin_port = rport;
 		if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
 			break;
@@ -114,7 +118,8 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
 			__set_errno (oerrno);
 			perror(0);
 			hp->h_addr_list++;
-			bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length);
+			bcopy(hp->h_addr_list[0], &sin.sin_addr,
+			      MIN (sizeof (sin.sin_addr), hp->h_length));
 			(void)fprintf(stderr, _("Trying %s...\n"),
 			    inet_ntoa(sin.sin_addr));
 			continue;
diff --git a/inet/rexec.c b/inet/rexec.c
index 297e44402d..7533410eb3 100644
--- a/inet/rexec.c
+++ b/inet/rexec.c
@@ -91,9 +91,9 @@ retry:
 		(void) write(s, "", 1);
 		port = 0;
 	} else {
-		char num[8];
+		char num[32];
 		int s2, sin2len;
-		
+
 		s2 = socket(AF_INET, SOCK_STREAM, 0);
 		if (s2 < 0) {
 			(void) close(s);
diff --git a/inet/ruserpass.c b/inet/ruserpass.c
index cff9493b07..a0a4b97bdb 100644
--- a/inet/ruserpass.c
+++ b/inet/ruserpass.c
@@ -87,9 +87,14 @@ ruserpass(host, aname, apass)
 	int t, i, c, usedefault = 0;
 	struct stat stb;
 
-	hdir = getenv("HOME");
-	if (hdir == NULL)
-		hdir = ".";
+	hdir = __secure_getenv("HOME");
+	if (hdir == NULL) {
+		/* If we can't get HOME, fail instead of trying ".",
+		   which is no improvement. This really should call
+		   getpwuid(getuid()).  */
+		/*hdir = ".";*/
+	  	return -1;
+	}
 
 	buf = alloca (strlen (hdir) + 8);
 
diff --git a/libio/stdio.h b/libio/stdio.h
index 3b399e5502..c71cf4d1d2 100644
--- a/libio/stdio.h
+++ b/libio/stdio.h
@@ -135,10 +135,14 @@ extern int sprintf __P ((char*, __const char* format, ...));
 extern int sscanf __P ((__const char* string, __const char* format, ...));
 extern FILE* tmpfile __P ((void));
 extern char* tmpnam __P ((char*));
+#ifdef	__USE_REENTRANT
+extern char* tmpnam_r __P ((char*));
+#endif
 #ifdef	__USE_SVID
 extern char *tempnam __P ((__const char *__dir, __const char *__pfx));
 #endif
-extern char *__stdio_gen_tempname __P ((__const char *dir, __const char *pfx,
+extern char *__stdio_gen_tempname __P ((char *__buf, size_t bufsize,
+					__const char *dir, __const char *pfx,
 					int dir_search, size_t *lenptr,
 					FILE **streamptr));
 extern int ungetc __P ((int c, FILE* fp));
diff --git a/locale/programs/ld-time.c b/locale/programs/ld-time.c
index 1b118ae14c..6f961b658a 100644
--- a/locale/programs/ld-time.c
+++ b/locale/programs/ld-time.c
@@ -548,11 +548,11 @@ time_output (struct localedef_t *locale, const char *output_path)
   ++last_idx;
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-# define ERA_B1 time->era_entries
-# define ERA_B2 time->era_entries_ob
-#else
 # define ERA_B1 time->era_entries_ob
 # define ERA_B2 time->era_entries
+#else
+# define ERA_B1 time->era_entries
+# define ERA_B2 time->era_entries_ob
 #endif
   idx[1 + last_idx] = idx[last_idx];
   for (num = 0; num < time->cur_num_era; ++num)
diff --git a/locale/setlocale.c b/locale/setlocale.c
index 76320f8a32..ceec1a69a6 100644
--- a/locale/setlocale.c
+++ b/locale/setlocale.c
@@ -227,6 +227,7 @@ setlocale (int category, const char *locale)
 {
   char *locale_path;
   size_t locale_path_len;
+  const char *locpath_var;
   char *composite;
 
   /* Sanity check for CATEGORY argument.  */
@@ -248,15 +249,11 @@ setlocale (int category, const char *locale)
   locale_path = NULL;
   locale_path_len = 0;
 
-  if (!__libc_enable_secure)
-    {
-      char *locpath_var = getenv ("LOCPATH");
-
-      if (locpath_var != NULL && locpath_var[0] != '\0')
-	if (__argz_create_sep (locpath_var, ':',
-			       &locale_path, &locale_path_len) != 0)
-	  return NULL;
-    }
+  locpath_var = __secure_getenv ("LOCPATH");
+  if (locpath_var != NULL && locpath_var[0] != '\0')
+    if (__argz_create_sep (locpath_var, ':',
+			   &locale_path, &locale_path_len) != 0)
+      return NULL;
 
   if (__argz_append (&locale_path, &locale_path_len,
 		     LOCALE_PATH, sizeof (LOCALE_PATH)) != 0)
diff --git a/login/Makefile b/login/Makefile
index 99687433a0..56a6aebf44 100644
--- a/login/Makefile
+++ b/login/Makefile
@@ -22,7 +22,7 @@
 
 subdir	:= login
 
-headers	:= utmp.h utmpbits.h lastlog.h
+headers	:= utmp.h utmpbits.h lastlog.h pty.h
 
 routines := setutent endutent getutent getutid getutline pututline	\
 	    setutent_r endutent_r getutent_r getutid_r getutline_r	\
diff --git a/login/pty.h b/login/pty.h
new file mode 100644
index 0000000000..da78742cf7
--- /dev/null
+++ b/login/pty.h
@@ -0,0 +1,43 @@
+/* pty.h - Functions for pseudo TTY handlung.
+Copyright (C) 1996 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#ifndef _PTY_H
+
+#define _PTY_H	1
+#include <features.h>
+
+#include <termios.h>
+
+
+__BEGIN_DECLS
+
+/* Create pseudo tty master slave pair with NAME and set terminal
+   attributes according to TERMP and WINP and return handles for both
+   ends in AMASTER and ASLAVE.  */
+extern int openpty __P ((int *__amaster, int *__aslave, char *__name,
+			 struct termios *__termp, struct winsize *__winp));
+
+/* Create child process and establish the slave pseudo terminal as the
+   child's controlling terminal.  */
+extern int forkpty __P ((int *__amaster, char *__name,
+			 struct termios *__termp, struct winsize *__winp));
+
+__END_DECLS
+
+#endif	/* pty.h */
diff --git a/login/pututline_r.c b/login/pututline_r.c
index 42ea3cd778..33ba96f461 100644
--- a/login/pututline_r.c
+++ b/login/pututline_r.c
@@ -96,7 +96,7 @@ __pututline_r (const struct utmp *id, struct utmp_data *utmp_data)
   if (result >= 0)
     /* Position file correctly.  */
     if (utmp_data->loc_utmp < (off_t) sizeof (struct utmp)
-	|| utmp_data->loc_utmp - sizeof (struct utmp) > st.st_size)
+	|| (off_t) (utmp_data->loc_utmp - sizeof (struct utmp)) > st.st_size)
       /* Not located at any valid entry.  Add at the end.  */
       {
 	result = lseek (utmp_data->ut_fd, 0L, SEEK_END);
diff --git a/manual/filesys.texi b/manual/filesys.texi
index d2afe8623f..e269663e70 100644
--- a/manual/filesys.texi
+++ b/manual/filesys.texi
@@ -261,7 +261,7 @@ are declared in the header file @file{dirent.h}.
 @comment dirent.h
 @comment POSIX.1
 @deftp {Data Type} DIR
-The @code{DIR} data type represents a directory stream.  
+The @code{DIR} data type represents a directory stream.
 @end deftp
 
 You shouldn't ever allocate objects of the @code{struct dirent} or
@@ -333,7 +333,7 @@ The @var{dirstream} argument is not valid.
 @comment POSIX.1
 @deftypefun int closedir (DIR *@var{dirstream})
 This function closes the directory stream @var{dirstream}.  It returns
-@code{0} on success and @code{-1} on failure.  
+@code{0} on success and @code{-1} on failure.
 
 The following @code{errno} error conditions are defined for this
 function:
@@ -443,7 +443,7 @@ following @code{errno} error conditions are defined for this function:
 @item EACCES
 You are not allowed to write the directory in which the new link is to
 be written.
-@ignore 
+@ignore
 Some implementations also require that the existing file be accessible
 by the caller, and use this error to report failure for that reason.
 @end ignore
@@ -627,7 +627,7 @@ The function @code{unlink} is declared in the header file @file{unistd.h}.
 
 This function returns @code{0} on successful completion, and @code{-1}
 on error.  In addition to the usual file name errors
-(@pxref{File Name Errors}), the following @code{errno} error conditions are 
+(@pxref{File Name Errors}), the following @code{errno} error conditions are
 defined for this function:
 
 @table @code
@@ -672,7 +672,7 @@ are two additional @code{errno} error conditions defined for
 @table @code
 @item ENOTEMPTY
 @itemx EEXIST
-The directory to be deleted is not empty.  
+The directory to be deleted is not empty.
 @end table
 
 These two error codes are synonymous; some systems use one, and some use
@@ -851,20 +851,20 @@ This section contains information about how you can inquire about and
 modify these attributes of files.
 
 @menu
-* Attribute Meanings::          The names of the file attributes, 
+* Attribute Meanings::          The names of the file attributes,
                                  and what their values mean.
 * Reading Attributes::          How to read the attributes of a file.
 * Testing File Type::           Distinguishing ordinary files,
-                                 directories, links... 
+                                 directories, links...
 * File Owner::                  How ownership for new files is determined,
 			         and how to change it.
 * Permission Bits::             How information about a file's access
-                                 mode is stored. 
+                                 mode is stored.
 * Access Permission::           How the system decides who can access a file.
 * Setting Permissions::         How permissions for new files are assigned,
 			         and how to change them.
 * Testing File Access::         How to find out if your process can
-                                 access a file. 
+                                 access a file.
 * File Times::                  About the time attributes of a file.
 @end menu
 
@@ -1079,7 +1079,7 @@ a socket, and so on.  For information about the access permission,
 @ref{Permission Bits}.
 
 There are two predefined ways you can access the file type portion of
-the file mode.  First of all, for each type of file, there is a 
+the file mode.  First of all, for each type of file, there is a
 @dfn{predicate macro} which examines a file mode value and returns
 true or false---is the file of that type, or not.  Secondly, you can
 mask out the rest of the file mode to get just a file type code.
@@ -1260,7 +1260,7 @@ bits may not be appropriate for the new owner.)  The other file
 permission bits are not changed.
 
 The return value is @code{0} on success and @code{-1} on failure.
-In addition to the usual file name errors (@pxref{File Name Errors}), 
+In addition to the usual file name errors (@pxref{File Name Errors}),
 the following @code{errno} error conditions are defined for this function:
 
 @table @code
@@ -1421,7 +1421,7 @@ This is equivalent to @samp{(S_IROTH | S_IWOTH | S_IXOTH)}.
 @comment POSIX
 @item S_ISUID
 @vindex S_ISUID
-This is the set-user-ID on execute bit, usually 04000. 
+This is the set-user-ID on execute bit, usually 04000.
 @xref{How Change Persona}.
 
 @comment sys/stat.h
@@ -1462,7 +1462,7 @@ arose since the last run.
 
 On some modern systems where the sticky bit has no useful meaning for an
 executable file, you cannot set the bit at all for a non-directory.
-If you try, @code{chmod} fails with @code{EFTYPE}; 
+If you try, @code{chmod} fails with @code{EFTYPE};
 @pxref{Setting Permissions}.
 
 Some systems (particularly SunOS) have yet another use for the sticky
@@ -1527,7 +1527,7 @@ The bits that are set in the file creation mask identify permissions
 that are always to be disabled for newly created files.  For example, if
 you set all the ``other'' access bits in the mask, then newly created
 files are not accessible at all to processes in the ``other''
-category, even if the @var{mode} argument specified to the creation 
+category, even if the @var{mode} argument specified to the creation
 function would permit such access.  In other words, the file creation
 mask is the complement of the ordinary access permissions you want to
 grant.
@@ -1671,7 +1671,7 @@ files off-limits to ordinary users---for example, to modify
 @file{/etc/passwd}.  Programs designed to be run by ordinary users but
 access such files use the setuid bit feature so that they always run
 with @code{root} as the effective user ID.
- 
+
 Such a program may also access files specified by the user, files which
 conceptually are being accessed explicitly by the user.  Since the
 program runs as @code{root}, it has permission to access whatever file
@@ -1776,7 +1776,7 @@ Argument that means, test for existence of the file.
 Each file has three timestamps associated with it:  its access time,
 its modification time, and its attribute modification time.  These
 correspond to the @code{st_atime}, @code{st_mtime}, and @code{st_ctime}
-members of the @code{stat} structure; see @ref{File Attributes}.  
+members of the @code{stat} structure; see @ref{File Attributes}.
 
 All of these times are represented in calendar time format, as
 @code{time_t} objects.  This data type is defined in @file{time.h}.
@@ -1832,7 +1832,7 @@ named @var{filename}.
 If @var{times} is a null pointer, then the access and modification times
 of the file are set to the current time.  Otherwise, they are set to the
 values from the @code{actime} and @code{modtime} members (respectively)
-of the @code{utimbuf} structure pointed at by @var{times}.  
+of the @code{utimbuf} structure pointed at by @var{times}.
 
 The attribute modification time for the file is set to the current time
 in either case (since changing the timestamps is itself a modification
@@ -1938,12 +1938,14 @@ this file, you must remove the old file explicitly first.
 
 If you need to use a temporary file in your program, you can use the
 @code{tmpfile} function to open it.  Or you can use the @code{tmpnam}
-function make a name for a temporary file and then open it in the usual
-way with @code{fopen}.
+(better: @code{tmpnam_r}) function make a name for a temporary file and
+then open it in the usual way with @code{fopen}.
 
 The @code{tempnam} function is like @code{tmpnam} but lets you choose
 what directory temporary files will go in, and something about what
-their file names will look like.
+their file names will look like.  Important for multi threaded programs
+is that @code{tempnam} is reentrant while @code{tmpnam} is not since it
+returns a pointer to a static buffer.
 
 These facilities are declared in the header file @file{stdio.h}.
 @pindex stdio.h
@@ -1956,6 +1958,8 @@ calling @code{fopen} with mode @code{"wb+"}.  The file is deleted
 automatically when it is closed or when the program terminates.  (On
 some other ANSI C systems the file may fail to be deleted if the program
 terminates abnormally).
+
+This function is reentrant.
 @end deftypefun
 
 @comment stdio.h
@@ -1964,14 +1968,26 @@ terminates abnormally).
 This function constructs and returns a file name that is a valid file
 name and that does not name any existing file.  If the @var{result}
 argument is a null pointer, the return value is a pointer to an internal
-static string, which might be modified by subsequent calls.  Otherwise,
-the @var{result} argument should be a pointer to an array of at least
-@code{L_tmpnam} characters, and the result is written into that array.
-
-It is possible for @code{tmpnam} to fail if you call it too many times.
-This is because the fixed length of a temporary file name gives room for
-only a finite number of different names.  If @code{tmpnam} fails, it
-returns a null pointer.
+static string, which might be modified by subsequent calls and therefore
+makes this function non-reentrant.  Otherwise, the @var{result} argument
+should be a pointer to an array of at least @code{L_tmpnam} characters,
+and the result is written into that array.
+
+It is possible for @code{tmpnam} to fail if you call it too many times
+without removing previously created files.  This is because the fixed
+length of a temporary file name gives room for only a finite number of
+different names.  If @code{tmpnam} fails, it returns a null pointer.
+@end deftypefun
+
+@comment stdio.h
+@comment GNU
+@deftypefun {char *} tmpnam_r (char *@var{result})
+This function is nearly identical to the @code{tmpnam} function.  But it
+does not allow @var{result} to be a null pointer.  In the later case a
+null pointer is returned.
+
+This function is reentrant because the non-reentrant situation of
+@code{tmpnam} cannot happen here.
 @end deftypefun
 
 @comment stdio.h
@@ -2006,13 +2022,16 @@ prefix for the file name.  The return value is a string newly allocated
 with @code{malloc}; you should release its storage with @code{free} when
 it is no longer needed.
 
+Because the string is dynamically allocated this function is reentrant.
+
 The directory prefix for the temporary file name is determined by testing
 each of the following, in sequence.  The directory must exist and be
 writable.
 
 @itemize @bullet
 @item
-The environment variable @code{TMPDIR}, if it is defined.
+The environment variable @code{TMPDIR}, if it is defined.  For security
+reasons this only happens if the program is not SUID or SGID enabled.
 
 @item
 The @var{dir} argument, if it is not a null pointer.
diff --git a/misc/Makefile b/misc/Makefile
index 00f5f785be..e6ad0d06d8 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -55,7 +55,12 @@ routines := brk sbrk sstk ioctl \
 	    efgcvt efgcvt_r qefgcvt qefgcvt_r \
 	    hsearch hsearch_r tsearch lsearch \
 	    err error ustat \
-	    getsysstats force-wrapper
+	    getsysstats
+
+ifneq (,$(filter %REENTRANT, $(defines)))
+routines += force-wrapper
+endif
+
 aux := init-misc
 distribute := bsd-compat.c
 extra-objs := bsd-compat.o
diff --git a/misc/hsearch_r.c b/misc/hsearch_r.c
index 95813e4bfb..d0fb3e183f 100644
--- a/misc/hsearch_r.c
+++ b/misc/hsearch_r.c
@@ -32,7 +32,7 @@ Boston, MA 02111-1307, USA.  */
    which describes the current status.  */
 typedef struct _ENTRY
 {
-  int   used;
+  unsigned int used;
   ENTRY entry;
 }
 _ENTRY;
diff --git a/misc/mntent_r.c b/misc/mntent_r.c
index 93955254cd..70da258de6 100644
--- a/misc/mntent_r.c
+++ b/misc/mntent_r.c
@@ -74,16 +74,16 @@ __getmntent_r (FILE *stream, struct mntent *mp, char *buffer, int bufsiz)
       /* skip empty lines and comment lines:  */
     } while (head[0] == '\0' || head[0] == '#');
 
-  mp->mnt_fsname = strsep (&head, " \t") ?: (char *) "";
+  mp->mnt_fsname = __strsep (&head, " \t") ?: (char *) "";
   if (head)
     head += strspn (head, " \t");
-  mp->mnt_dir = strsep (&head, " \t") ?: (char *) "";
+  mp->mnt_dir = __strsep (&head, " \t") ?: (char *) "";
   if (head)
     head += strspn (head, " \t");
-  mp->mnt_type = strsep (&head, " \t") ?: (char *) "";
+  mp->mnt_type = __strsep (&head, " \t") ?: (char *) "";
   if (head)
     head += strspn (head, " \t");
-  mp->mnt_opts = strsep (&head, " \t") ?: (char *) "";
+  mp->mnt_opts = __strsep (&head, " \t") ?: (char *) "";
   switch (head ? sscanf (head, " %d %d ", &mp->mnt_freq, &mp->mnt_passno) : 0)
     {
     case 0:
diff --git a/nss/nss_dns/dns-host.c b/nss/nss_dns/dns-host.c
index 9a01c9f545..f8d5d37e72 100644
--- a/nss/nss_dns/dns-host.c
+++ b/nss/nss_dns/dns-host.c
@@ -501,7 +501,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
 	      ++had_error;
 	      continue;
 	    }
-	  strcpy (bp, tbuf);
+	  strcpy (bp, tbuf);		/* Cannot overflow.  */
 	  result->h_name = bp;
 	  bp += n;
 	  linebuflen -= n;
@@ -524,7 +524,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
 	      ++had_error;
 	      continue;
 	    }
-	  strcpy (bp, tbuf);
+	  strcpy (bp, tbuf);		/* Cannot overflow.  */
 	  tname = bp;
 	  bp += n;
 	  linebuflen -= n;
@@ -650,7 +650,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
 	  n = strlen (qname) + 1;	/* For the \0.  */
 	  if (n > linebuflen)
 	    goto try_again;
-	  strcpy (bp, qname);
+	  strcpy (bp, qname);		/* Cannot overflow.  */
 	  result->h_name = bp;
 	  bp += n;
 	  linebuflen -= n;
diff --git a/resolv/res_debug.c b/resolv/res_debug.c
index 61724bf23b..842e63c2fb 100644
--- a/resolv/res_debug.c
+++ b/resolv/res_debug.c
@@ -1046,7 +1046,7 @@ const char *
 p_time(value)
 	u_int32_t value;
 {
-	static char nbuf[40];
+	static char nbuf[60];
 	int secs, mins, hours, days;
 	register char *p;
 
diff --git a/resolv/res_init.c b/resolv/res_init.c
index caeb337e24..c8a74f6e05 100644
--- a/resolv/res_init.c
+++ b/resolv/res_init.c
@@ -216,7 +216,7 @@ res_init()
 	_res.pfcode = 0;
 
 	/* Allow user to override the local domain definition */
-	if ((cp = getenv("LOCALDOMAIN")) != NULL) {
+	if ((cp = __secure_getenv("LOCALDOMAIN")) != NULL) {
 		(void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
 		haveenv++;
 
@@ -421,7 +421,7 @@ res_init()
 #endif /* !RFC1535 */
 	}
 
-	if ((cp = getenv("RES_OPTIONS")) != NULL)
+	if ((cp = __secure_getenv("RES_OPTIONS")) != NULL)
 		res_setoptions(cp, "env");
 	_res.options |= RES_INIT;
 	return (0);
diff --git a/resolv/res_query.c b/resolv/res_query.c
index e9898023bf..ac50a9c7c5 100644
--- a/resolv/res_query.c
+++ b/resolv/res_query.c
@@ -363,7 +363,7 @@ hostalias(name)
 
 	if (_res.options & RES_NOALIASES)
 		return (NULL);
-	file = getenv("HOSTALIASES");
+	file = __secure_getenv("HOSTALIASES");
 	if (file == NULL || (fp = fopen(file, "r")) == NULL)
 		return (NULL);
 	setbuf(fp, NULL);
diff --git a/stdio-common/tempnam.c b/stdio-common/tempnam.c
index 14988a8656..a86ac08610 100644
--- a/stdio-common/tempnam.c
+++ b/stdio-common/tempnam.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1993 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1993, 1996 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
@@ -16,7 +16,6 @@ License along with the GNU C Library; see the file COPYING.LIB.  If
 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
 Cambridge, MA 02139, USA.  */
 
-#include <ansidecl.h>
 #include <errno.h>
 #include <stddef.h>
 #include <stdio.h>
@@ -32,19 +31,20 @@ Cambridge, MA 02139, USA.  */
    P_tmpdir is tried and finally "/tmp".  The storage for the filename
    is allocated by `malloc'.  */
 char *
-DEFUN(tempnam, (dir, pfx), CONST char *dir AND CONST char *pfx)
+tempnam (const char *dir, const char *pfx)
 {
+  char buf[FILENAME_MAX];
   size_t len;
   register char *s;
-  register char *t = __stdio_gen_tempname(dir, pfx, 1, &len, (FILE **) NULL);
+  register char *t = __stdio_gen_tempname (buf, sizeof (buf), dir, pfx, 1,
+					   &len, (FILE **) NULL);
 
   if (t == NULL)
     return NULL;
 
-  s = (char *) malloc(len);
+  s = (char *) malloc (len);
   if (s == NULL)
     return NULL;
 
-  (void) memcpy(s, t, len);
-  return s;
+  return (char *) memcpy (s, t, len);
 }
diff --git a/stdio-common/temptest.c b/stdio-common/temptest.c
index 374719896a..09786b25e7 100644
--- a/stdio-common/temptest.c
+++ b/stdio-common/temptest.c
@@ -7,12 +7,13 @@ char *files[500];
 int
 main ()
 {
+  char buf[FILENAME_MAX];
   char *fn;
   FILE *fp;
   int i;
 
   for (i = 0; i < 500; i++) {
-    fn = __stdio_gen_tempname((CONST char *) NULL,
+    fn = __stdio_gen_tempname(buf, sizeof (buf), (CONST char *) NULL,
 	"file", 0, (size_t *) NULL, (FILE **) NULL);
     if (fn == NULL) {
       printf ("__stdio_gen_tempname failed\n");
diff --git a/stdio-common/tmpfile.c b/stdio-common/tmpfile.c
index dfe11ada50..924df9b6bb 100644
--- a/stdio-common/tmpfile.c
+++ b/stdio-common/tmpfile.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1993 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1993, 1996 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
@@ -16,7 +16,6 @@ License along with the GNU C Library; see the file COPYING.LIB.  If
 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
 Cambridge, MA 02139, USA.  */
 
-#include <ansidecl.h>
 #include <stdio.h>
 
 
@@ -25,12 +24,13 @@ Cambridge, MA 02139, USA.  */
    If we couldn't generate a unique filename or the file couldn't
    be opened, NULL is returned.  */
 FILE *
-DEFUN_VOID(tmpfile)
+tmpfile ()
 {
+  char buf[FILENAME_MAX];
   char *filename;
   FILE *f;
 
-  filename = __stdio_gen_tempname ((char *) NULL, "tmpf", 0,
+  filename = __stdio_gen_tempname (buf, sizeof (buf), (char *) NULL, "tmpf", 0,
 				   (size_t *) NULL, &f);
   if (filename == NULL)
     return NULL;
diff --git a/stdio-common/tmpnam.c b/stdio-common/tmpnam.c
index 88dd0a4ca5..44397bc3f2 100644
--- a/stdio-common/tmpnam.c
+++ b/stdio-common/tmpnam.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1993 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1993, 1996 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
@@ -16,27 +16,34 @@ License along with the GNU C Library; see the file COPYING.LIB.  If
 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
 Cambridge, MA 02139, USA.  */
 
-#include <ansidecl.h>
-#include <stddef.h>
 #include <stdio.h>
 #include <string.h>
 
 
-/* Generate a unique filename in P_tmpdir.  */
+/* Generate a unique filename in P_tmpdir.
+
+   This function is *not* thread safe!  */
 char *
-DEFUN(tmpnam, (s), register char *s)
+tmpnam (char *s)
 {
-  register char *t = __stdio_gen_tempname((CONST char *) NULL,
-					  (CONST char *) NULL, 0,
-					  (size_t *) NULL, (FILE **) NULL);
-
-  if (t == NULL)
-    return NULL;
-
-  if (s != NULL)
-    (void) strcpy(s, t);
-  else
-    s = t;
-
-  return s;
+  /* By using two buffers we manage to be thread safe in the case
+     where S != NULL.  */
+  static char buf[L_tmpnam];
+  char *tmpbuf[L_tmpnam];
+  char *result;
+
+  /* In the following call we use the buffer pointed to by S if
+     non-NULL although we don't know the size.  But we limit the size
+     to FILENAME_MAX characters in any case.  */
+  result = __stdio_gen_tempname (s ?: tmpbuf, L_tmpnam, (const char *) NULL,
+				 (const char *) NULL, 0,
+				 (size_t *) NULL, (FILE **) NULL);
+
+  if (result != NULL && s == NULL)
+    {
+      memcpy (buf, result, L_tmpnam);
+      result = buf;
+    }
+
+  return result;
 }
diff --git a/stdio-common/tmpnam_r.c b/stdio-common/tmpnam_r.c
new file mode 100644
index 0000000000..2794e7728e
--- /dev/null
+++ b/stdio-common/tmpnam_r.c
@@ -0,0 +1,37 @@
+/* Copyright (C) 1991, 1993, 1996 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 Library General Public License as
+published by the Free Software Foundation; either version 2 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <stdio.h>
+#include <string.h>
+
+
+/* Generate a unique filename in P_tmpdir.  If S is NULL return NULL.
+   This makes this function thread safe.  */
+char *
+tmpnam_r (char *s)
+{
+  if (s == NULL)
+    return NULL;
+
+  /* In the following call we use the buffer pointed to by S if
+     non-NULL although we don't know the size.  But we limit the size
+     to L_tmpnam characters in any case.  */
+  return __stdio_gen_tempname (s, L_tmpnam, (const char *) NULL,
+			       (const char *) NULL, 0,
+			       (size_t *) NULL, (FILE **) NULL);
+}
diff --git a/stdio/stdio.h b/stdio/stdio.h
index 47348a6576..8072625312 100644
--- a/stdio/stdio.h
+++ b/stdio/stdio.h
@@ -156,7 +156,8 @@ extern int __stdio_open __P ((__const char *__file, __io_mode __m,
 /* Put out an error message for when stdio needs to die.  */
 extern void __stdio_errmsg __P ((__const char *__msg, size_t __len));
 /* Generate a unique file name (and possibly open it with mode "w+b").  */
-extern char *__stdio_gen_tempname __P ((__const char *__dir,
+extern char *__stdio_gen_tempname __P ((char *__buf, size_t __bufsize,
+					__const char *__dir,
 					__const char *__pfx,
 					int __dir_search,
 					size_t *__lenptr,
@@ -294,6 +295,12 @@ extern FILE *tmpfile __P ((void));
 /* Generate a temporary filename.  */
 extern char *tmpnam __P ((char *__s));
 
+#ifdef __USE_REENTRANT
+/* This is the reentrant variant of `tmpnam'.  The only difference is
+   that it does not allow S to be NULL.  */
+extern char *tmpnam_r __P ((char *__s));
+#endif
+
 
 #ifdef	__USE_SVID
 /* Generate a unique temporary filename using up to five characters of PFX
diff --git a/stdlib/stdlib.h b/stdlib/stdlib.h
index 7da32b91e1..cb48aa1f1c 100644
--- a/stdlib/stdlib.h
+++ b/stdlib/stdlib.h
@@ -361,6 +361,10 @@ extern void exit __P ((int __status)) __attribute__ ((__noreturn__));
 /* Return the value of envariable NAME, or NULL if it doesn't exist.  */
 extern char *getenv __P ((__const char *__name));
 
+/* This function is similar to the above but returns NULL if the
+   programs is running with SUID or SGID enabled.  */
+extern char *__secure_getenv __P ((__const char *__name));
+
 #ifdef	__USE_SVID
 /* The SVID says this is in <stdio.h>, but this seems a better place.	*/
 /* Put STRING, which is of the form "NAME=VALUE", in the environment.
diff --git a/stdlib/test-canon.c b/stdlib/test-canon.c
index f41106716a..95a5b78128 100644
--- a/stdlib/test-canon.c
+++ b/stdlib/test-canon.c
@@ -107,7 +107,7 @@ check_path (const char * result, const char * expected)
 }
 
 
-void
+int
 main (int argc, char ** argv)
 {
   char * result;
@@ -117,12 +117,12 @@ main (int argc, char ** argv)
   getcwd (cwd, sizeof(buf));
   cwd_len = strlen (cwd);
 
-  for (i = 0; i < sizeof (symlinks) / sizeof (symlinks[0]); ++i)
+  for (i = 0; i < (int) (sizeof (symlinks) / sizeof (symlinks[0])); ++i)
     symlink (symlinks[i].value, symlinks[i].name);
 
   fd = open("doesExist", O_CREAT | O_EXCL, 0777);
 
-  for (i = 0; i < sizeof (tests) / sizeof (tests[0]); ++i)
+  for (i = 0; i < (int) (sizeof (tests) / sizeof (tests[0])); ++i)
     {
       buf[0] = '\0';
       result = realpath (tests[i].in, buf);
@@ -148,7 +148,7 @@ main (int argc, char ** argv)
       if (!tests[i].out && errno != tests[i].error)
 	{
 	  printf ("%s: flunked test %d (expected errno %d, got %d)\n",
-		  argv[0], i, tests[i].errno, errno);
+		  argv[0], i, tests[i].error, errno);
 	  ++errors;
 	  continue;
 	}
@@ -165,17 +165,15 @@ main (int argc, char ** argv)
   if (fd >= 0)
     unlink("doesExist");
 
-  for (i = 0; i < sizeof (symlinks) / sizeof (symlinks[0]); ++i)
+  for (i = 0; i < (int) (sizeof (symlinks) / sizeof (symlinks[0])); ++i)
     unlink (symlinks[i].name);
 
-  if (errors == 0)
-    {
-      puts ("No errors.");
-      exit (EXIT_SUCCESS);
-    }
-  else
+  if (errors != 0)
     {
       printf ("%d errors.\n", errors);
       exit (EXIT_FAILURE);
     }
+
+  puts ("No errors.");
+  return EXIT_SUCCESS;
 }
diff --git a/string/string.h b/string/string.h
index 53b6096497..8b9fd5c359 100644
--- a/string/string.h
+++ b/string/string.h
@@ -209,6 +209,7 @@ extern int strncasecmp __P ((__const char *__s1, __const char *__s2,
 
 /* Return the next DELIM-delimited token from *STRINGP,
    terminating it with a '\0', and update *STRINGP to point past it.  */
+extern char *__strsep __P ((char **__stringp, __const char *__delim));
 extern char *strsep __P ((char **__stringp, __const char *__delim));
 #endif
 
diff --git a/sysdeps/generic/getenv.c b/sysdeps/generic/getenv.c
index d4099a9733..daf292743a 100644
--- a/sysdeps/generic/getenv.c
+++ b/sysdeps/generic/getenv.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1992, 1994 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1992, 1994, 1996 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
@@ -16,7 +16,6 @@ License along with the GNU C Library; see the file COPYING.LIB.  If
 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
 Cambridge, MA 02139, USA.  */
 
-#include <ansidecl.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
@@ -28,17 +27,29 @@ Cambridge, MA 02139, USA.  */
 
 /* Return the value of the environment variable NAME.  */
 char *
-DEFUN(getenv, (name), register CONST char *name)
+getenv (name)
+     const char *name;
 {
-  register CONST size_t len = strlen(name);
-  register char **ep;
+  const size_t len = strlen (name);
+  char **ep;
 
   if (__environ == NULL)
     return NULL;
 
   for (ep = __environ; *ep != NULL; ++ep)
-    if (!strncmp(*ep, name, len) && (*ep)[len] == '=')
+    if (!strncmp (*ep, name, len) && (*ep)[len] == '=')
       return &(*ep)[len + 1];
 
   return NULL;
 }
+
+
+/* Some programs and especially the libc itself have to be careful
+   what values to accept from the environment.  This special version
+   checks for SUID or SGID first before doing any work.  */
+char *
+__secure_getenv (name)
+     const char *name;
+{
+  return __libc_enable_secure ? NULL : getenv (name);
+}
diff --git a/sysdeps/generic/prof-freq.c b/sysdeps/generic/prof-freq.c
index 4ad42124e8..ff085145b5 100644
--- a/sysdeps/generic/prof-freq.c
+++ b/sysdeps/generic/prof-freq.c
@@ -37,7 +37,7 @@
 #include <sys/time.h>
 
 int
-__profile_frequency ()
+__profile_frequency (void)
 {
   /*
    * Discover the tick frequency of the machine if something goes wrong,
diff --git a/sysdeps/generic/pty.c b/sysdeps/generic/pty.c
index dda2125836..6995417d3a 100644
--- a/sysdeps/generic/pty.c
+++ b/sysdeps/generic/pty.c
@@ -46,6 +46,7 @@ static char sccsid[] = "@(#)pty.c	8.1 (Berkeley) 6/4/93";
 #include <stdio.h>
 #include <string.h>
 #include <grp.h>
+#include <pty.h>
 
 int
 openpty(amaster, aslave, name, termp, winp)
@@ -105,7 +106,7 @@ forkpty(amaster, name, termp, winp)
 	struct termios *termp;
 	struct winsize *winp;
 {
-	extern int login_tty();
+	extern int login_tty __P ((int fd));
 	int master, slave, pid;
 
 	if (openpty(&master, &slave, name, termp, winp) == -1)
diff --git a/sysdeps/generic/strsep.c b/sysdeps/generic/strsep.c
index 6fbcb084a6..15c5891044 100644
--- a/sysdeps/generic/strsep.c
+++ b/sysdeps/generic/strsep.c
@@ -19,7 +19,7 @@ Boston, MA 02111-1307, USA.  */
 #include <string.h>
 
 char *
-strsep (char **stringp, const char *delim)
+__strsep (char **stringp, const char *delim)
 {
   char *begin, *end;
 
@@ -41,3 +41,4 @@ strsep (char **stringp, const char *delim)
 
   return begin;
 }
+weak_alias (__strsep, strsep)
diff --git a/sysdeps/generic/sys/sysinfo.h b/sysdeps/generic/sys/sysinfo.h
index e9f667499e..f68fcc032c 100644
--- a/sysdeps/generic/sys/sysinfo.h
+++ b/sysdeps/generic/sys/sysinfo.h
@@ -22,12 +22,12 @@ Boston, MA 02111-1307, USA.  */
 #include <features.h>
 
 /* Return number of configured processors.  */
-extern int __get_nproc_conf __P ((void));
-extern int get_nproc_conf __P ((void));
+extern int __get_nprocs_conf __P ((void));
+extern int get_nprocs_conf __P ((void));
 
 /* Return number of available processors.  */
-extern int __get_nproc __P ((void));
-extern int get_nproc __P ((void));
+extern int __get_nprocs __P ((void));
+extern int get_nprocs __P ((void));
 
 
 /* Return number of physical pages of memory in the system.  */
diff --git a/sysdeps/posix/getcwd.c b/sysdeps/posix/getcwd.c
index a9536b95cf..825599f370 100644
--- a/sysdeps/posix/getcwd.c
+++ b/sysdeps/posix/getcwd.c
@@ -298,7 +298,7 @@ __getcwd (buf, size)
 	      (d->d_name[1] == '\0' ||
 	       (d->d_name[1] == '.' && d->d_name[2] == '\0')))
 	    continue;
-	  if (mount_point || d->d_ino == thisino)
+	  if (mount_point || (ino_t) d->d_ino == thisino)
 	    {
 	      char name[dotlist + dotsize - dotp + 1 + _D_ALLOC_NAMLEN (d)];
 	      memcpy (name, dotp, dotlist + dotsize - dotp);
@@ -326,7 +326,7 @@ __getcwd (buf, size)
 	{
 	  size_t namlen = _D_EXACT_NAMLEN (d);
 
-	  if (pathp - path < namlen)
+	  if ((size_t) (pathp - path) < namlen)
 	    {
 	      if (buf != NULL)
 		{
diff --git a/sysdeps/posix/mk-stdiolim.c b/sysdeps/posix/mk-stdiolim.c
index da78a98394..5df460e89a 100644
--- a/sysdeps/posix/mk-stdiolim.c
+++ b/sysdeps/posix/mk-stdiolim.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1992, 1993, 1996 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
@@ -23,7 +23,7 @@ main()
 {
   /* These values correspond to the code in sysdeps/posix/tempname.c.
      Change the values here if you change that code.  */
-  printf("#define L_tmpnam %u\n", sizeof("/usr/tmp/") + 8);
+  printf("#define L_tmpnam %u\n", sizeof("/usr/tmp/") + 9);
   printf("#define TMP_MAX %u\n", 62 * 62 * 62);
 
   puts  ("#ifdef __USE_POSIX");
@@ -36,7 +36,7 @@ main()
      is the case in the Hurd).  ANSI still requires that FOPEN_MAX and
      FILENAME_MAX be defined, however.  */
 
-  printf("#define FOPEN_MAX %u\n", 
+  printf("#define FOPEN_MAX %u\n",
 #ifdef	OPEN_MAX
 
 	 OPEN_MAX
@@ -51,7 +51,7 @@ main()
 
 	 );
 
-  printf("#define FILENAME_MAX %u\n", 
+  printf("#define FILENAME_MAX %u\n",
 #ifdef	PATH_MAX
 	 PATH_MAX
 #else
diff --git a/sysdeps/posix/tempname.c b/sysdeps/posix/tempname.c
index 6fd698e2b8..d58024fe7e 100644
--- a/sysdeps/posix/tempname.c
+++ b/sysdeps/posix/tempname.c
@@ -81,21 +81,24 @@ static const char letters[] =
    existing file will be returned.  When the cycle reaches its end
    (12345ZZZ), NULL is returned.  */
 char *
-__stdio_gen_tempname (const char *dir, const char *pfx, int dir_search,
-		      size_t *lenptr, FILE **streamptr)
+__stdio_gen_tempname (char *buf, size_t bufsize, const char *dir,
+		      const char *pfx, int dir_search, size_t *lenptr,
+		      FILE **streamptr)
 {
   int saverrno = errno;
   static const char tmpdir[] = P_tmpdir;
   static size_t indices[2];
   size_t *idx;
-  static char buf[FILENAME_MAX];
+#if 0
   static pid_t oldpid = (pid_t) 0;
+#endif
   pid_t pid = __getpid();
   register size_t len, plen, dlen;
+  int wrapped;
 
   if (dir_search)
     {
-      register const char *d = getenv ("TMPDIR");
+      register const char *d = __secure_getenv ("TMPDIR");
       if (d != NULL && !diraccess (d))
 	d = NULL;
       if (d == NULL && dir != NULL && diraccess (dir))
@@ -133,34 +136,51 @@ __stdio_gen_tempname (const char *dir, const char *pfx, int dir_search,
     dir = tmpdir;
   idx = &indices[(plen == 0 && dir == tmpdir) ? 1 : 0];
 
+#if 0
+  /* XXX Is this ever useful???  At least when using a thread package
+     which uses different PIDs for the threads it is not helpful.  */
   if (pid != oldpid)
     {
       oldpid = pid;
       indices[0] = indices[1] = 0;
     }
+#endif
 
+  wrapped = 0; /* We have not yet wrapped around the index counter.  */
   len = dlen + 1 + plen + 5 + 3;
-  while (*idx < ((sizeof (letters) - 1) * (sizeof (letters) - 1) *
-		 (sizeof (letters) - 1)))
+  while (1)
     {
-      const size_t i = (*idx)++;
+      const size_t i;
+
+      if (*idx >= ((sizeof (letters) - 1) * (sizeof (letters) - 1) *
+		   (sizeof (letters) - 1)))
+	{
+	  if (wrapped)
+	    /* We really wrapped around this call.  Can't believe it
+	       but nevertheless stop the endless loop.  */
+	    break;
+
+	  indices[0] = indices[1] = 0;
+	  wrapped = 1;
+	}
+
+      i = (*idx)++;
 
       /* Construct a file name and see if it already exists.
 
 	 We use a single counter in *IDX to cycle each of three
 	 character positions through each of 62 possible letters.  */
 
-      if (sizeof (buf) < len ||
-	  sprintf (buf, "%.*s/%.*s%.5d%c%c%c",
-		   (int) dlen, dir, (int) plen,
-		   pfx, pid % 100000,
-		   letters[i % (sizeof (letters) - 1)],
-		   letters[(i / (sizeof (letters) - 1))
-			   % (sizeof (letters) - 1)],
-		   letters[(i / ((sizeof (letters) - 1) *
-				 (sizeof (letters) - 1)))
-			   % (sizeof (letters) - 1)]
-		   ) != (int) len)
+      if (__snprintf (buf, bufsize, "%.*s/%.*s%.5d%c%c%c",
+		      (int) dlen, dir, (int) plen,
+		      pfx, pid % 100000,
+		      letters[i % (sizeof (letters) - 1)],
+		      letters[(i / (sizeof (letters) - 1))
+			     % (sizeof (letters) - 1)],
+		      letters[(i / ((sizeof (letters) - 1) *
+				    (sizeof (letters) - 1)))
+			     % (sizeof (letters) - 1)]
+		    ) != (int) len)
 	return NULL;
 
       if (streamptr != NULL)
@@ -176,7 +196,7 @@ __stdio_gen_tempname (const char *dir, const char *pfx, int dir_search,
 	      struct _IO_FILE_plus *fp;
 
 	      fp = (struct _IO_FILE_plus *)
-		malloc(sizeof (struct _IO_FILE_plus));
+		malloc (sizeof (struct _IO_FILE_plus));
 	      if (fp == NULL)
 		{
 		  /* We lost trying to create a stream (out of memory?).
diff --git a/sysdeps/posix/ttyname.c b/sysdeps/posix/ttyname.c
index be82827d00..9668117b47 100644
--- a/sysdeps/posix/ttyname.c
+++ b/sysdeps/posix/ttyname.c
@@ -57,7 +57,7 @@ ttyname (fd)
     return NULL;
 
   while ((d = readdir (dirstream)) != NULL)
-    if (d->d_fileno == myino)
+    if ((ino_t) d->d_fileno == myino)
       {
 	size_t dlen = _D_ALLOC_NAMLEN (d);
 	if (sizeof (dev) + dlen > namelen)
diff --git a/sysdeps/posix/ttyname_r.c b/sysdeps/posix/ttyname_r.c
index 1fb4b047d4..d7f6026d8a 100644
--- a/sysdeps/posix/ttyname_r.c
+++ b/sysdeps/posix/ttyname_r.c
@@ -72,7 +72,7 @@ __ttyname_r (fd, buf, buflen)
   buflen -= sizeof (dev);
 
   while ((d = readdir (dirstream)) != NULL)
-    if (d->d_fileno == myino)
+    if ((ino_t) d->d_fileno == myino)
       {
 	char *cp;
 
diff --git a/sysdeps/stub/getenv.c b/sysdeps/stub/getenv.c
index fab9f08c75..f12964ed70 100644
--- a/sysdeps/stub/getenv.c
+++ b/sysdeps/stub/getenv.c
@@ -27,6 +27,7 @@ getenv (name)
   __set_errno (ENOSYS);
   return NULL;
 }
+strong_alias (getenv, __secure_getenv)
 
 
 stub_warning (getenv)
diff --git a/sysdeps/stub/nanosleep.c b/sysdeps/stub/nanosleep.c
index 0995bb9654..bdc9d28f2d 100644
--- a/sysdeps/stub/nanosleep.c
+++ b/sysdeps/stub/nanosleep.c
@@ -22,9 +22,13 @@ Boston, MA 02111-1307, USA.  */
 
 /* Pause execution for a number of nanoseconds.  */
 int
-nanosleep (const struct timespec *requested_time, struct timespec *remaining)
+__libc_nanosleep (const struct timespec *requested_time,
+		  struct timespec *remaining)
 {
   __set_errno (ENOSYS);
   return -1;
 }
 stub_warning (nanosleep)
+
+weak_alias (__libc_nanosleep, __nanosleep)
+weak_alias (__libc_nanosleep, nanosleep)
diff --git a/sysdeps/stub/tempname.c b/sysdeps/stub/tempname.c
index 939c70fb0d..e38345721e 100644
--- a/sysdeps/stub/tempname.c
+++ b/sysdeps/stub/tempname.c
@@ -26,7 +26,9 @@ Cambridge, MA 02139, USA.  */
    Return the generated filename or NULL if one could not
    be generated, putting the length of the string in *LENPTR.  */
 char *
-__stdio_gen_tempname (dir, pfx, dir_search, lenptr)
+__stdio_gen_tempname (buf, bufsize, dir, pfx, dir_search, lenptr)
+     char *buf;
+     size_t bufsize;
      const char *dir;
      const char *pfx;
      int dir_search;
diff --git a/sysdeps/unix/nlist.c b/sysdeps/unix/nlist.c
index b40aedbc82..ffdd21d796 100644
--- a/sysdeps/unix/nlist.c
+++ b/sysdeps/unix/nlist.c
@@ -26,9 +26,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    which is terminated by an element with a NULL `n_un.n_name' member,
    and fill in the elements of NL.  */
 int
-nlist (file, nl)
-     const char *file;
-     struct nlist *nl;
+nlist (const char *file, struct nlist *nl)
 {
   FILE *f;
   struct exec header;
diff --git a/sysdeps/unix/sysv/linux/getsysstats.c b/sysdeps/unix/sysv/linux/getsysstats.c
index c4c6fd78f6..349da98e90 100644
--- a/sysdeps/unix/sysv/linux/getsysstats.c
+++ b/sysdeps/unix/sysv/linux/getsysstats.c
@@ -33,14 +33,11 @@ get_proc_path (char *buffer, size_t bufsize)
   FILE *fp;
   struct mntent mount_point;
   struct mntent *entry;
-  char *result;
+  char *result = NULL;
 
   /* First find the mount point of the proc filesystem.  */
   fp = __setmntent (_PATH_MNTTAB, "r");
-  if (fp == NULL)
-    /* Cannot find mount table file.  */
-    result = NULL;
-  else
+  if (fp != NULL)
     {
       while ((entry = __getmntent_r (fp, &mount_point, buffer, bufsize))
 	     != NULL)
@@ -108,7 +105,7 @@ weak_alias (__get_nprocs, get_nprocs)
 
 /* As far as I know Linux has no separate numbers for configured and
    available processors.  So make the `get_nprocs_conf' function an
-   prototype.  */
+   alias.  */
 strong_alias (__get_nprocs, __get_nprocs_conf)
 weak_alias (__get_nprocs, get_nprocs_conf)
 
diff --git a/sysdeps/unix/sysv/linux/sleep.c b/sysdeps/unix/sysv/linux/sleep.c
index 1094df5129..a4cf47bb0b 100644
--- a/sysdeps/unix/sysv/linux/sleep.c
+++ b/sysdeps/unix/sysv/linux/sleep.c
@@ -26,7 +26,7 @@ sleep (unsigned int seconds)
   struct timespec ts = { tv_sec: (long int) seconds, tv_nsec: 0 };
   unsigned int result;
 
-  if (nanosleep (&ts, &ts) == 0)
+  if (__nanosleep (&ts, &ts) == 0)
     result = 0;
   else
     /* Round remaining time.  */
diff --git a/sysdeps/unix/sysv/linux/sys/sysinfo.h b/sysdeps/unix/sysv/linux/sys/sysinfo.h
index 1fabb06392..fbdb1def2b 100644
--- a/sysdeps/unix/sysv/linux/sys/sysinfo.h
+++ b/sysdeps/unix/sysv/linux/sys/sysinfo.h
@@ -29,12 +29,12 @@ extern int sysinfo __P ((struct sysinfo *__info));
 
 
 /* Return number of configured processors.  */
-extern int __get_nproc_conf __P ((void));
-extern int get_nproc_conf __P ((void));
+extern int __get_nprocs_conf __P ((void));
+extern int get_nprocs_conf __P ((void));
 
 /* Return number of available processors.  */
-extern int __get_nproc __P ((void));
-extern int get_nproc __P ((void));
+extern int __get_nprocs __P ((void));
+extern int get_nprocs __P ((void));
 
 
 /* Return number of physical pages of memory in the system.  */
diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list
index 3601b5f357..f831b41072 100644
--- a/sysdeps/unix/sysv/linux/syscalls.list
+++ b/sysdeps/unix/sysv/linux/syscalls.list
@@ -1,6 +1,6 @@
 # File name	Caller	Syscall name	# args	Strong name	Weak names
 
-adjtimex	adjtime	adjtimex	1	__adjtimex
+adjtimex	adjtime	adjtimex	1	__adjtimex	adjtimex
 bdflush		EXTRA	bdflush		2	bdflush
 create_module	EXTRA	create_module	3	create_module
 delete_module	EXTRA	delete_module	3	delete_module
@@ -20,13 +20,13 @@ iopl		-	iopl		1	iopl
 ipc		msgget	ipc		5	__ipc
 klogctl		EXTRA	syslog		3	klogctl
 llseek		EXTRA	_llseek		5	llseek
-mlock		-	mlock		2	__mlock	mlock
-mlockall	-	mlockall	1	__mlockall	mlockall
+mlock		EXTRA	mlock		2	__mlock	mlock
+mlockall	EXTRA	mlockall	1	__mlockall	mlockall
 mount		EXTRA	mount		5	__mount	mount
-mremap		-	mremap		4	__mremap	mremap
-munlock		-	munlock		2	__munlock	munlock
-munlockall	-	munlockall	0	__munlockall	munlockall
-nanosleep	-	nanosleep	2	__libc_nanosleep	nanosleep
+mremap		EXTRA	mremap		4	__mremap	mremap
+munlock		EXTRA	munlock		2	__munlock	munlock
+munlockall	EXTRA	munlockall	0	__munlockall	munlockall
+nanosleep	-	nanosleep	2	__libc_nanosleep	__nanosleep nanosleep
 pause		-	pause		0	__libc_pause	pause
 personality	init-first personality	1	__personality	personality
 pipe		-	pipe		1	__pipe		pipe
diff --git a/time/strftime.c b/time/strftime.c
index 9d23cf7183..36088d04c9 100644
--- a/time/strftime.c
+++ b/time/strftime.c
@@ -24,6 +24,7 @@ Cambridge, MA 02139, USA.  */
 # define HAVE_LIMITS_H 1
 # define HAVE_MBLEN 1
 # define HAVE_MBRLEN 1
+# define HAVE_STRUCT_ERA_ENTRY 1
 # define HAVE_TM_GMTOFF 1
 # define HAVE_TM_ZONE 1
 # define MULTIBYTE_IS_FORMAT_SAFE 1
@@ -260,12 +261,9 @@ strftime (s, maxsize, format, tp)
   const char *const f_month = _NL_CURRENT (LC_TIME, MON_1 + tp->tm_mon);
   const char *const ampm = _NL_CURRENT (LC_TIME,
 					hour12 > 11 ? PM_STR : AM_STR);
-  size_t aw_len = strlen(a_wkday);
-  size_t am_len = strlen(a_month);
+  size_t aw_len = strlen (a_wkday);
+  size_t am_len = strlen (a_month);
   size_t ap_len = strlen (ampm);
-
-  const char *alt_digits = _NL_CURRENT (LC_TIME, ALT_DIGITS);
-  const char *end_alt_digits = _NL_CURRENT (LC_TIME, ALT_DIGITS + 1);
 #else
   const char *const f_wkday = weekday_name[tp->tm_wday];
   const char *const f_month = month_name[tp->tm_mon];
@@ -423,9 +421,6 @@ strftime (s, maxsize, format, tp)
 #define DO_NUMBER_SPACEPAD(d, v) \
 	  digits = d; number_value = v; goto do_number_spacepad
 
-	case '\0':		/* GNU extension: % at end of format.  */
-	    --f;
-	    /* Fall through.  */
 	case '%':
 	  if (modifier != 0)
 	    goto bad_format;
@@ -480,8 +475,17 @@ strftime (s, maxsize, format, tp)
 	case 'C':		/* POSIX.2 extension.  */
 	  if (modifier == 'O')
 	    goto bad_format;
-#ifdef _NL_CURRENT
-	  /* XXX %EC is not implemented yet.  */
+#if HAVE_STRUCT_ERA_ENTRY
+	  if (modifier == 'E')
+	    {
+	      struct era_entry *era = _nl_get_era_entry (tp);
+	      if (era)
+		{
+		  size_t len = strlen (era->name_fmt);
+		  cpy (len, era->name_fmt);
+		  break;
+		}
+	    }
 #endif
 	  {
 	    int year = tp->tm_year + TM_YEAR_BASE;
@@ -769,10 +773,16 @@ strftime (s, maxsize, format, tp)
 	  DO_NUMBER (1, tp->tm_wday);
 
 	case 'Y':
-#ifdef _NL_CURRENT
-	  if (modifier == 'E'
-	      && *(subfmt = _NL_CURRENT (LC_TIME, ERA_YEAR)) != '\0')
-	    goto subformat;
+#if HAVE_STRUCT_ERA_ENTRY
+	  if (modifier == 'E')
+	    {
+	      struct era_entry *era = _nl_get_era_entry (tp);
+	      if (era)
+		{
+		  subfmt = strchr (era->name_fmt, '\0') + 1;
+		  goto subformat;
+		}
+	    }
 #endif
 	  if (modifier == 'O')
 	    goto bad_format;
@@ -780,8 +790,17 @@ strftime (s, maxsize, format, tp)
 	    DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
 
 	case 'y':
-#ifdef _NL_CURRENT
-	  /* XXX %Ey is not implemented yet.  */
+#if HAVE_STRUCT_ERA_ENTRY
+	  if (modifier == 'E')
+	    {
+	      struct era_entry *era = _nl_get_era_entry (tp);
+	      if (era)
+		{
+		  int delta = tp->tm_year - era->start_date[0];
+		  DO_NUMBER (1, (era->offset
+				 + (era->direction == '-' ? -delta : delta)));
+		}
+	    }
 #endif
 	  DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
 
@@ -837,6 +856,9 @@ strftime (s, maxsize, format, tp)
 	    DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
 	  }
 
+	case '\0':		/* GNU extension: % at end of format.  */
+	    --f;
+	    /* Fall through.  */
 	default:
 	  /* Unknown format; output the format, including the '%',
 	     since this is most likely the right thing to do if a
@@ -844,7 +866,7 @@ strftime (s, maxsize, format, tp)
 	bad_format:
 	  {
 	    int flen;
-	    for (flen = 2; f[1 - flen] != '%'; flen++)
+	    for (flen = 1; f[1 - flen] != '%'; flen++)
 	      continue;
 	    cpy (flen, &f[1 - flen]);
 	  }
diff --git a/time/time.h b/time/time.h
index f4c27f926e..2dc25ab0b9 100644
--- a/time/time.h
+++ b/time/time.h
@@ -265,6 +265,8 @@ extern int dysize __P ((int __year));
 
 #ifdef __USE_POSIX
 /* Pause execution for a number of nanoseconds.  */
+extern int __nanosleep __P ((__const struct timespec *__requested_time,
+			     struct timespec *__remaining));
 extern int nanosleep __P ((__const struct timespec *__requested_time,
 			   struct timespec *__remaining));
 #endif