handle password file locking.
authorUlrich Drepper <drepper@redhat.com>
Mon, 26 Aug 1996 10:28:45 +0000 (10:28 +0000)
committerUlrich Drepper <drepper@redhat.com>
Mon, 26 Aug 1996 10:28:45 +0000 (10:28 +0000)
19 files changed:
NEWS
configure.in
elf/dl-error.c
elf/dl-open.c
elf/dlerror.c
elf/rtld.c
misc/syslog.c
resolv/res_debug.c
shadow/Makefile
shadow/lckpwdf.c [new file with mode: 0644]
shadow/shadow.h
sysdeps/generic/ftime.c
sysdeps/generic/setfpucw.c
sysdeps/i386/fpu_control.h
sysdeps/m68k/dl-machine.h
sysdeps/posix/gettimeofday.c
sysdeps/unix/sysv/linux/init-first.c
time/gmtime.c
time/strftime.c

diff --git a/NEWS b/NEWS
index edb07b8..76a4272 100644 (file)
--- 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;
index 631a035..a2668b9 100644 (file)
@@ -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
index 737bba7..2eaa7e0 100644 (file)
@@ -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);
     }
index 40b5224..76f6329 100644 (file)
@@ -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
index 4ec5037..663207d 100644 (file)
@@ -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;
index 9f13124..be71e88 100644 (file)
@@ -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;
index 3a39c43..de159da 100644 (file)
@@ -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)
index dfb3b47..bb314bc 100644 (file)
@@ -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);
 }
index 943881f..614f7af 100644 (file)
@@ -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 (file)
index 0000000..fb1c4b2
--- /dev/null
@@ -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.  */
+}
index 88199a9..b1a4c82 100644 (file)
@@ -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 */
index 76e9276..600e959 100644 (file)
@@ -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;
index 7b09a68..5654c94 100644 (file)
@@ -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);
 }
index 706dea3..7944b1a 100644 (file)
@@ -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;
index f36b9ce..8b9872c 100644 (file)
@@ -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.
index a4bb38a..c3b8108 100644 (file)
@@ -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;
     }
 
index feff028..ae163bc 100644 (file)
@@ -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 ();
index 93fba65..364b4c9 100644 (file)
@@ -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);
 
index 214f82f..129fd14 100644 (file)
@@ -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)
              {