summary refs log tree commit diff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1996-08-26 10:28:45 +0000
committerUlrich Drepper <drepper@redhat.com>1996-08-26 10:28:45 +0000
commitdcf0671d905200c449f92ead6cf43c184637a0d5 (patch)
tree91dc217311db41e89545d487b991865a6433205e
parent4884d0f03c5a3b3d2459655e76fa2d0684d389dc (diff)
downloadglibc-dcf0671d905200c449f92ead6cf43c184637a0d5.tar.gz
glibc-dcf0671d905200c449f92ead6cf43c184637a0d5.tar.xz
glibc-dcf0671d905200c449f92ead6cf43c184637a0d5.zip
handle password file locking. cvs/libc-960826
-rw-r--r--NEWS8
-rw-r--r--configure.in2
-rw-r--r--elf/dl-error.c9
-rw-r--r--elf/dl-open.c8
-rw-r--r--elf/dlerror.c8
-rw-r--r--elf/rtld.c15
-rw-r--r--misc/syslog.c6
-rw-r--r--resolv/res_debug.c12
-rw-r--r--shadow/Makefile3
-rw-r--r--shadow/lckpwdf.c181
-rw-r--r--shadow/shadow.h13
-rw-r--r--sysdeps/generic/ftime.c13
-rw-r--r--sysdeps/generic/setfpucw.c5
-rw-r--r--sysdeps/i386/fpu_control.h4
-rw-r--r--sysdeps/m68k/dl-machine.h2
-rw-r--r--sysdeps/posix/gettimeofday.c21
-rw-r--r--sysdeps/unix/sysv/linux/init-first.c31
-rw-r--r--time/gmtime.c12
-rw-r--r--time/strftime.c40
19 files changed, 321 insertions, 72 deletions
diff --git a/NEWS b/NEWS
index edb07b8330..76a4272569 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-GNU C Library NEWS -- history of user-visible changes.  24 June 1996
+GNU C Library NEWS -- history of user-visible changes.  25 August 1996
 
 Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
 See the end for copying conditions.
@@ -20,8 +20,8 @@ Version 2.0
   of many files which contained only symbol aliases, reducing the size of
   the source and the compiled library; many other files were renamed to
   less cryptic names previously occupied by the symbol alias files.
-  There is a new header file <elf.h> and new library `-lelf' for
-  programs which operate on files in the ELF format.
+  There is a new header file <elf.h> for programs which operate on
+  files in the ELF format.
 
 * Converted to Autoconf version 2, so `configure' has more options.
   Run `configure --help' to see the details.
@@ -104,7 +104,7 @@ Version 2.0
 * The new header file <fts.h> and suite of functions simplify programs that
   operate on directory trees.  This code comes from 4.4 BSD.
 
-* The resolver code has been updated from the BIND 4.9.4-T3B release.
+* The resolver code has been updated from the BIND 4.9.5-T1A release.
 
 * The new function `malloc_find_object_address' finds the starting address
   of a malloc'd block, given any address within the block;
diff --git a/configure.in b/configure.in
index 631a035e92..a2668b9ff9 100644
--- a/configure.in
+++ b/configure.in
@@ -483,6 +483,8 @@ fi
 AC_CACHE_CHECK(for ld --no-whole-archive, libc_cv_ld_no_whole_archive, [dnl
 cat > conftest.c <<\EOF
 _start () {}
+int __eh_pc;
+__throw () {}
 EOF
 dnl No \ in command here because it ends up inside ''.
 if AC_TRY_COMMAND([${CC-cc} $CFLAGS
diff --git a/elf/dl-error.c b/elf/dl-error.c
index 737bba7421..2eaa7e03d1 100644
--- a/elf/dl-error.c
+++ b/elf/dl-error.c
@@ -46,8 +46,13 @@ _dl_signal_error (int errcode,
 
   if (catch)
     {
-      /* We are inside _dl_catch_error.  Return to it.  */
-      catch->errstring = errstring;
+      /* We are inside _dl_catch_error.  Return to it.  We have to
+	 duplicate the error string since it might be allocated on the
+	 stack.  */
+      size_t len = strlen (errstring) + 1;
+      catch->errstring = malloc (len);
+      if (catch->errstring != NULL)
+	memcpy (catch->errstring, errstring, len);
       catch->objname = objname;
       longjmp (catch->env, errcode ?: -1);
     }
diff --git a/elf/dl-open.c b/elf/dl-open.c
index 40b5224725..76f6329762 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -27,6 +27,11 @@ extern void _dl_start (void); weak_extern (_dl_start)
 
 extern int __libc_multiple_libcs;	/* Defined in init-first.c.  */
 
+extern int __libc_argc;
+extern char **__libc_argv;
+extern char **__libc_envp;
+
+
 size_t _dl_global_scope_alloc;
 
 struct link_map *
@@ -136,7 +141,8 @@ _dl_open (const char *file, int mode)
 
   /* Run the initializer functions of new objects.  */
   while (init = _dl_init_next (new))
-    (*(void (*) (void)) init) ();
+    (*(void (*) (int, char **, char **)) init) (__libc_argc, __libc_argv,
+						__libc_envp);
 
   if (dl_start_ptr == NULL)
     /* We must be the static _dl_open in libc.a because ld.so.1 is not
diff --git a/elf/dlerror.c b/elf/dlerror.c
index 4ec5037de4..663207d708 100644
--- a/elf/dlerror.c
+++ b/elf/dlerror.c
@@ -1,5 +1,5 @@
 /* dlerror -- Return error detail for failing <dlfcn.h> functions.
-Copyright (C) 1995 Free Software Foundation, Inc.
+Copyright (C) 1995, 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
@@ -58,6 +58,7 @@ dlerror (void)
 	   ? NULL : buf);
 
   /* Reset the error indicator.  */
+  free (last_errstring);
   last_errstring = NULL;
   return ret;
 }
@@ -65,6 +66,11 @@ dlerror (void)
 int
 _dlerror_run (void (*operate) (void))
 {
+  if (last_errstring != NULL)
+    /* Free the error string from the last failed command.  This can
+       happen if `dlerror' was not run after an error was found.  */
+    free (last_errstring);
+
   last_errcode = _dl_catch_error (&last_errstring, &last_object_name,
 				  operate);
   return last_errstring != NULL;
diff --git a/elf/rtld.c b/elf/rtld.c
index 9f13124207..be71e88c3c 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -204,12 +204,15 @@ of this helper program; chances are you did not intend to run this program.\n",
 	    {
 	      l = _dl_map_object (NULL, _dl_argv[0], lt_library);
 	    }
-	  const char *err_str = NULL;
+	  char *err_str = NULL;
 	  const char *obj_name __attribute__ ((unused));
 
 	  (void) _dl_catch_error (&err_str, &obj_name, doit);
 	  if (err_str != NULL)
-	    _exit (EXIT_FAILURE);
+	    {
+	      free (err_str);
+	      _exit (EXIT_FAILURE);
+	    }
 	}
       else
 	l = _dl_map_object (NULL, _dl_argv[0], lt_library);
@@ -395,7 +398,8 @@ of this helper program; chances are you did not intend to run this program.\n",
 	    const ElfW(Sym) *ref = NULL;
 	    ElfW(Addr) loadbase = _dl_lookup_symbol (_dl_argv[i], &ref,
 						     &_dl_default_scope[2],
-						     "argument", 0);
+						     "argument",
+						     DL_LOOKUP_NOPLT);
 	    char buf[20], *bp;
 	    buf[sizeof buf - 1] = '\0';
 	    bp = _itoa (ref->st_value, &buf[sizeof buf - 1], 16, 0);
@@ -488,8 +492,9 @@ of this helper program; chances are you did not intend to run this program.\n",
 	 dynamic linker.  There is no additional initialization
 	 required for the ABI-compliant dynamic linker.  */
 
-      (*(void (*) (void)) (_dl_rtld_map.l_addr +
-			   _dl_rtld_map.l_info[DT_INIT]->d_un.d_ptr)) ();
+      (*(void (*) (int, char **, char**))
+       (_dl_rtld_map.l_addr + _dl_rtld_map.l_info[DT_INIT]->d_un.d_ptr))
+	(0, NULL, NULL);
 
       /* Clear the field so a future dlopen won't run it again.  */
       _dl_rtld_map.l_info[DT_INIT] = NULL;
diff --git a/misc/syslog.c b/misc/syslog.c
index 3a39c4317a..de159da9ee 100644
--- a/misc/syslog.c
+++ b/misc/syslog.c
@@ -96,6 +96,7 @@ vsyslog(pri, fmt, ap)
 	register const char *fmt;
 	va_list ap;
 {
+	struct tm now_tm;
 	time_t now;
 	int fd;
 	FILE *f;
@@ -126,10 +127,11 @@ vsyslog(pri, fmt, ap)
 #ifdef USE_IN_LIBIO
         f->_IO_write_ptr += strftime (f->_IO_write_ptr,
                                       f->_IO_write_end - f->_IO_write_ptr,
-                                      "%h %e %T ", localtime (&now));
+                                      "%h %e %T ",
+				      __localtime_r (&now, &now_tm));
 #else
 	f->__bufp += strftime (f->__bufp, f->__put_limit - f->__bufp,
-			       "%h %e %T ", localtime (&now));
+			       "%h %e %T ", __localtime_r (&now, &mow_tm));
 #endif
 	msgoff = ftell (f);
 	if (LogTag == NULL)
diff --git a/resolv/res_debug.c b/resolv/res_debug.c
index dfb3b4706f..bb314bcaa0 100644
--- a/resolv/res_debug.c
+++ b/resolv/res_debug.c
@@ -1491,13 +1491,13 @@ __p_secstodate (secs)
 {
 	static char output[15];         /* YYYYMMDDHHMMSS and null */
 	time_t clock = secs;
-	struct tm *time;
+	struct tm time;
 
-	time = gmtime(&clock);
-	time->tm_year += 1900;
-	time->tm_mon += 1;
+	__gmtime_r(&clock, &time);
+	time.tm_year += 1900;
+	time.tm_mon += 1;
 	sprintf(output, "%04d%02d%02d%02d%02d%02d",
-		time->tm_year, time->tm_mon, time->tm_mday,
-		time->tm_hour, time->tm_min, time->tm_sec);
+		time.tm_year, time.tm_mon, time.tm_mday,
+		time.tm_hour, time.tm_min, time.tm_sec);
 	return (output);
 }
diff --git a/shadow/Makefile b/shadow/Makefile
index 943881f1f1..614f7afdd4 100644
--- a/shadow/Makefile
+++ b/shadow/Makefile
@@ -23,7 +23,8 @@ subdir	:= shadow
 
 headers		= shadow.h
 routines	= getspent getspnam sgetspent fgetspent putspent \
-		  getspent_r getspnam_r sgetspent_r fgetspent_r
+		  getspent_r getspnam_r sgetspent_r fgetspent_r \
+		  lckpwdf
 
 
 include ../Rules
diff --git a/shadow/lckpwdf.c b/shadow/lckpwdf.c
new file mode 100644
index 0000000000..fb1c4b2e5e
--- /dev/null
+++ b/shadow/lckpwdf.c
@@ -0,0 +1,181 @@
+/* lckpwdf - handle locking of password file.
+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 <fcntl.h>
+#include <libc-lock.h>
+#include <shadow.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/file.h>
+
+
+/* Name of the lock file.  */
+#define PWD_LOCKFILE "/var/lock/lock.pwd"
+
+/* How long to wait for getting the lock before returning with an
+   error.  */
+#define TIMEOUT 15 /* sec */
+
+
+/* File descriptor for lock file.  */
+static int lock_fd = -1;
+
+/* Prevent problems in multithreaded program by using mutex.  */
+__libc_lock_define_initialized (static, lock)
+
+
+/* Prototypes for local functions.  */
+static void noop_handler __P ((int __sig));
+
+
+/* We cannot simply return in error cases.  We have to close the file
+   and perhaps restore the signal handler.  */
+#define RETURN_CLOSE_FD(code)						      \
+  do {									      \
+    if ((code) < 0 && lock_fd >= 0)					      \
+      {									      \
+	close (lock_fd);						      \
+	lock_fd = -1;							      \
+      }									      \
+    __libc_lock_unlock (lock);						      \
+    return (code);							      \
+  } while (0)
+
+#define RETURN_RESTORE_HANDLER(code)					      \
+  do {									      \
+    /* Restore old action handler for alarm.  We don't need to know	      \
+       about the current one.  */					      \
+    sigaction (SIGALRM, &saved_act, NULL);				      \
+    RETURN_CLOSE_FD (code);						      \
+  } while (0)
+
+#define RETURN_CLEAR_ALARM(code)					      \
+  do {									      \
+    /* Clear alarm.  */							      \
+    alarm (0);								      \
+    /* Restore old set of handled signals.  We don't need to know	      \
+       about the current one.*/						      \
+    sigprocmask (SIG_SETMASK, &saved_set, NULL);			      \
+    RETURN_RESTORE_HANDLER (code);					      \
+  } while (0)
+
+
+int
+__lckpwdf ()
+{
+  int flags;
+  sigset_t saved_set;			/* Saved set of caught signals.  */
+  struct sigaction saved_act;		/* Saved signal action.  */
+  sigset_t new_set;			/* New set of caught signals.  */
+  struct sigaction new_act;		/* New signal action.  */
+  int result;
+
+  if (lock_fd != -1)
+    /* Still locked by own process.  */
+    return -1;
+
+  /* Prevent problems caused by multiple threads.  */
+  __libc_lock_lock (lock);
+
+  lock_fd = open (PWD_LOCKFILE, O_WRONLY | O_CREAT, 0600);
+  if (lock_fd == -1)
+    /* Cannot create lock file.  */
+    RETURN_CLOSE_FD (-1);
+
+  /* Make sure file gets correctly closed when process finished.  */
+  flags = fcntl (lock_fd, F_GETFD, 0);
+  if (flags == -1)
+    /* Cannot get file flags.  */
+    RETURN_CLOSE_FD (-1);
+  flags |= FD_CLOEXEC;		/* Close on exit.  */
+  if (fcntl (lock_fd, F_SETFD, flags) < 0)
+    /* Cannot set new flags.  */
+    RETURN_CLOSE_FD (-1);
+
+  /* Now we have to get exclusive write access.  Since multiple
+     process could try this we won't stop when it first fails.
+     Instead we set a timeout for the system call.  Once the timer
+     expires it is likely that there are some problems which cannot be
+     resolved by waiting.
+
+     It is important that we don't change the signal state.  We must
+     restore the old signal behaviour.  */
+  memset (&new_act, '\0', sizeof (struct sigaction));
+  new_act.sa_handler = noop_handler;
+  sigfillset (&new_act.sa_mask);
+  new_act.sa_flags = 0ul;
+
+  /* Install new action handler for alarm and save old.  */
+  if (sigaction (SIGALRM, &new_act, &saved_act) < 0)
+    /* Cannot install signal handler.  */
+    RETURN_CLOSE_FD (-1);
+
+  /* Now make sure the alarm signal is not blocked.  */
+  sigemptyset (&new_set);
+  sigaddset (&new_set, SIGALRM);
+  if (sigprocmask (SIG_UNBLOCK, &new_set, &saved_set) < 0)
+    RETURN_RESTORE_HANDLER (-1);
+
+  /* Start timer.  If we cannot get the lock in the specified time we
+     get a signal.  */
+  alarm (TIMEOUT);
+
+  /* Try to get the lock.  */
+  result = flock (lock_fd, LOCK_EX);
+
+  RETURN_CLEAR_ALARM (result);
+}
+weak_alias (__lckpwdf, lckpwdf)
+
+
+int
+__ulckpwdf ()
+{
+  int result;
+
+  if (lock_fd == -1)
+    /* There is no lock set.  */
+    result = -1;
+  else
+    {
+      /* Prevent problems caused by multiple threads.  */
+      __libc_lock_lock (&lock);
+
+      result = close (lock_fd);
+
+      /* Mark descriptor as unused.  */
+      lock_fd = -1;
+
+      /* Clear mutex.  */
+      __libc_lock_unlock (lock);
+    }
+
+  return result;
+}
+weak_alias (__ulckpwdf, ulckpwdf)
+
+
+static void
+noop_handler (sig)
+     int sig;
+{
+  /* We simply return which makes the `flock' call return with an error.  */
+}
diff --git a/shadow/shadow.h b/shadow/shadow.h
index 88199a9856..b1a4c82b4e 100644
--- a/shadow/shadow.h
+++ b/shadow/shadow.h
@@ -46,8 +46,8 @@ struct spwd
 				   the password.  */
   __time_t sp_inact;		/* Number of days the account may be
 				   inactive.  */
-  __time_t sp_expire;		/* Number of days since 700101 until account
-				   expires.  */
+  __time_t sp_expire;		/* Number of days since 1970-01-01 until
+				   account expires.  */
   unsigned long int sp_flag;	/* Reserved.  */
 };
 
@@ -103,6 +103,15 @@ extern struct spwd *fgetspent_r __P ((FILE *__stream,
 				      char *__buffer, int __buflen));
 #endif	/* reentrant */
 
+
+/* Protect password file against multi writers.  */
+extern int __lckpwdf __P ((void));
+extern int lckpwdf __P ((void));
+
+/* Unlock password file.  */
+extern int __ulckpwdf __P ((void));
+extern int ulckpwdf __P ((void));
+
 __END_DECLS
 
 #endif /* shadow.h */
diff --git a/sysdeps/generic/ftime.c b/sysdeps/generic/ftime.c
index 76e9276483..600e959245 100644
--- a/sysdeps/generic/ftime.c
+++ b/sysdeps/generic/ftime.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1994 Free Software Foundation, Inc.
+/* Copyright (C) 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
@@ -25,19 +25,18 @@ ftime (timebuf)
      struct timeb *timebuf;
 {
   int save = errno;
-  struct tm *tp;
+  struct tm tp;
 
   errno = 0;
   if (time (&timebuf->time) == (time_t) -1 && errno != 0)
     return -1;
   timebuf->millitm = 0;
-  
-  tp = localtime (&timebuf->time);
-  if (tp == NULL)
+
+  if (__localtime_r (&timebuf->time, &tp) == NULL)
     return -1;
 
-  timebuf->timezone = tp->tm_gmtoff / 60;
-  timebuf->dstflag = tp->tm_isdst;
+  timebuf->timezone = tp.tm_gmtoff / 60;
+  timebuf->dstflag = tp.tm_isdst;
 
   errno = save;
   return 0;
diff --git a/sysdeps/generic/setfpucw.c b/sysdeps/generic/setfpucw.c
index 7b09a68b55..5654c942b0 100644
--- a/sysdeps/generic/setfpucw.c
+++ b/sysdeps/generic/setfpucw.c
@@ -29,5 +29,8 @@ __setfpucw (fpu_control_t set)
 
   /* Preserve the reserved bits, and set the rest as the user
      specified (or the default, if the user gave zero).  */
-  _FPU_SETCW ((cw & _FPU_RESERVED) | (set & ~_FPU_RESERVED));
+  cw &= _FPU_RESERVED;
+  cw |= set & ~_FPU_RESERVED;
+
+  _FPU_SETCW (cw);
 }
diff --git a/sysdeps/i386/fpu_control.h b/sysdeps/i386/fpu_control.h
index 706dea3d6d..7944b1a5ee 100644
--- a/sysdeps/i386/fpu_control.h
+++ b/sysdeps/i386/fpu_control.h
@@ -89,8 +89,8 @@ Boston, MA 02111-1307, USA.  */
 typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__HI__)));
 
 /* Macros for accessing the hardware control word.  */
-#define _FPU_GETCW(cw) __asm__ ("fnstcw %0" : "=m" (cw))
-#define _FPU_SETCW(cw) __asm__ ("fldcw %0" : : "m" (cw))
+#define _FPU_GETCW(cw) __asm__ ("fnstcw %0" : "=m" (*&cw))
+#define _FPU_SETCW(cw) __asm__ ("fldcw %0" : : "m" (*&cw))
 
 /* Default control word set at startup.  */
 extern fpu_control_t __fpu_control;
diff --git a/sysdeps/m68k/dl-machine.h b/sysdeps/m68k/dl-machine.h
index f36b9ce2f4..8b9872c15a 100644
--- a/sysdeps/m68k/dl-machine.h
+++ b/sysdeps/m68k/dl-machine.h
@@ -175,7 +175,7 @@ _dl_start_user:
 	| Loop to call _dl_init_next for the next initializer.
 	jra 0b
 1:	| Clear the startup flag.
-	move.l #0, _dl_starting_up@GOT(%a5)
+	clr.l _dl_starting_up@GOT(%a5)
 	| Pass our finalizer function to the user in %a1.
 	move.l _dl_fini@GOT(%a5), %a1
 	| Initialize %fp with the stack pointer.
diff --git a/sysdeps/posix/gettimeofday.c b/sysdeps/posix/gettimeofday.c
index a4bb38a41c..c3b8108258 100644
--- a/sysdeps/posix/gettimeofday.c
+++ b/sysdeps/posix/gettimeofday.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1992, 1994, 1995 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 92, 94, 95, 96 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 <time.h>
 #include <sys/time.h>
@@ -32,8 +31,9 @@ Cambridge, MA 02139, USA.  */
    putting it into *TV and *TZ.  If TZ is NULL, *TZ is not filled.
    Returns 0 on success, -1 on errors.  */
 int
-DEFUN(__gettimeofday, (tv, tz),
-      struct timeval *tv AND struct timezone *tz)
+__gettimeofday (tv, tz)
+     struct timeval *tv;
+     struct timezone *tz;
 {
   if (tv == NULL)
     {
@@ -46,16 +46,17 @@ DEFUN(__gettimeofday, (tv, tz),
 
   if (tz != NULL)
     {
-      CONST time_t timer = tv->tv_sec;
-      CONST struct tm *tm;
+      const time_t timer = tv->tv_sec;
+      struct tm tm;
+      const struct tm *tmp;
 
-      CONST long int save_timezone = __timezone;
-      CONST long int save_daylight = __daylight;
+      const long int save_timezone = __timezone;
+      const long int save_daylight = __daylight;
       char *save_tzname[2];
       save_tzname[0] = __tzname[0];
       save_tzname[1] = __tzname[1];
 
-      tm = localtime (&timer);
+      tmp = localtime (&timer, &tm);
 
       tz->tz_minuteswest = __timezone / 60;
       tz->tz_dsttime = __daylight;
@@ -65,7 +66,7 @@ DEFUN(__gettimeofday, (tv, tz),
       __tzname[0] = save_tzname[0];
       __tzname[1] = save_tzname[1];
 
-      if (tm == NULL)
+      if (tmp == NULL)
 	return -1;
     }
 
diff --git a/sysdeps/unix/sysv/linux/init-first.c b/sysdeps/unix/sysv/linux/init-first.c
index feff028a28..ae163bcd49 100644
--- a/sysdeps/unix/sysv/linux/init-first.c
+++ b/sysdeps/unix/sysv/linux/init-first.c
@@ -36,21 +36,30 @@ weak_extern (_dl_starting_up)
    used in the process.  Safe assumption if initializer never runs.  */
 int __libc_multiple_libcs = 1;
 
+/* Remember the command line argument and enviroment contents for
+   later calls of initializers for dynamic libraries.  */
+int __libc_argc;
+char **__libc_argv;
+char **__libc_envp;
+
+
 static void
 init (void *data)
 {
   extern int __personality (int);
 
-  int argc = *(long *)data;
-  char **argv = (char **)data + 1;
-  char **envp = &argv[argc + 1];
-
-
   __libc_multiple_libcs = &_dl_starting_up && ! _dl_starting_up;
 
+
   /* We must not call `personality' twice.  */
   if (!__libc_multiple_libcs)
     {
+      /* The argument we got points to the values describing the
+	 command line argument etc.  */
+      __libc_argc = *(int *)data;
+      __libc_argv = (char **)data + 1;
+      __libc_envp = &__libc_argv[__libc_argc + 1];
+
       /* The `personality' system call takes one argument that chooses
 	 the "personality", i.e. the set of system calls and such.  We
 	 must make this call first thing to disable emulation of some
@@ -61,9 +70,17 @@ init (void *data)
       /* Set the FPU control word to the proper default value.  */
       __setfpucw (__fpu_control);
     }
+  else
+    {
+      /* The argument we got points to the values describing the
+	 command line argument etc.  */
+      __libc_argc = *((int *)data)++;
+      __libc_argv = *((char ***)data)++;
+      __libc_envp = *(char ***)data;
+    }
 
-  __environ = envp;
-  __libc_init (argc, argv, envp);
+  __environ = __libc_envp;
+  __libc_init (__libc_argc, __libc_argv, __libc_envp);
 
 #ifdef PIC
   __libc_global_ctors ();
diff --git a/time/gmtime.c b/time/gmtime.c
index 93fba659be..364b4c9262 100644
--- a/time/gmtime.c
+++ b/time/gmtime.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1993, 1995 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 1993, 1995, 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 <stddef.h>
 #include <time.h>
 
@@ -25,16 +24,19 @@ extern struct tm _tmbuf;
 
 /* Return the `struct tm' representation of *T in UTC.	*/
 struct tm *
-DEFUN(gmtime, (t), CONST time_t *t)
+gmtime (t)
+     const time_t *t;
 {
   return __gmtime_r (t, &_tmbuf);
 }
 
+
 /* Return the `struct tm' representation of *T in UTC,
    using *TP to store the result.  */
 struct tm *
-DEFUN(__gmtime_r, (t, tp),
-      CONST time_t *t AND struct tm *tp)
+__gmtime_r (t, tp)
+     const time_t *t;
+     struct tm *tp;
 {
   __offtime (t, 0L, tp);
 
diff --git a/time/strftime.c b/time/strftime.c
index 214f82f488..129fd1412c 100644
--- a/time/strftime.c
+++ b/time/strftime.c
@@ -470,27 +470,37 @@ strftime (s, maxsize, format, tp)
 	case 'z':
 	  {
 	    struct tm tml = *tp;
-	    time_t t = mktime (&tml);
 	    struct tm tmg;
+	    time_t t;
+	    time_t offset = 0;
 	    int diff;
 
-	    tml = *localtime (&t);	/* Canonicalize the local time.  */
-	    tmg = *gmtime (&t);
+	    t = __mktime_internal (&tml, __localtime_r, &offset);
 
-	    /* Compute the difference.  */
-	    diff = tml.tm_min - tmg.tm_min;
-	    diff += 60 * (tml.tm_hour - tmg.tm_hour);
-
-	    if (tml.tm_mon != tmg.tm_mon)
+	    /* Canonicalize the local time.  */
+	    if (t == (time_t) -1 || __localtime_r (&t, &tml) == NULL)
+	      /* We didn't managed to get the local time.  Assume it
+		 GMT as a reasonable default value.  */
+	      diff = 0;
+	    else
 	      {
-		/* We assume no timezone differs from UTC by more than
-		   +- 23 hours.  This should be safe.  */
-		if (tmg.tm_mday == 1)
-		  tml.tm_mday = 0;
-		else /* tml.tm_mday == 1 */
-		  tmg.tm_mday = 0;
+		__gmtime_r (&t, &tmg);
+
+		/* Compute the difference.  */
+		diff = tml.tm_min - tmg.tm_min;
+		diff += 60 * (tml.tm_hour - tmg.tm_hour);
+
+		if (tml.tm_mon != tmg.tm_mon)
+		  {
+		    /* We assume no timezone differs from UTC by more
+		       than +- 23 hours.  This should be safe.  */
+		    if (tmg.tm_mday == 1)
+		      tml.tm_mday = 0;
+		    else /* tml.tm_mday == 1 */
+		      tmg.tm_mday = 0;
+		  }
+		diff += 1440 * (tml.tm_mday - tmg.tm_mday);
 	      }
-	    diff += 1440 * (tml.tm_mday - tmg.tm_mday);
 
 	    if (diff < 0)
 	      {