bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

another fix for an unlikely core dump in 'who' and 'pinky'


From: Paul Eggert
Subject: another fix for an unlikely core dump in 'who' and 'pinky'
Date: Mon, 21 Jun 2004 01:23:07 -0700
User-agent: Gnus/5.1006 (Gnus v5.10.6) Emacs/21.3 (gnu/linux)

It turns out that my previous fix wasn't enough in general, since the
C standard says that ctime has undefined behavior if the year is
before -999 or after 9999.  The most straightforward fix is to avoid
using ctime entirely, and to use strftime instead.  But since strftime
uses localized dates, we might as well fix the FIXME and support
i18nized time stamps for who and pinky.  Here is a proposed patch.

Note that the output format will differ now, outside the POSIX locale.


2004-06-21  Paul Eggert  <address@hidden>

        The 2004-06-19 fix for who and pinky was incomplete, as ctime
        has undefined behavior if the year precedes -999 or follows 9999.
        Since we have to stop using ctime anyway, we might as well use
        strftime and fix the FIXME, and support internationalized dates.
        
        * NEWS: Document the new behavior.
         * src/who.c: Include "hard-locale.h".
         (time_format, time_format_width): New vars.
         (time_string, print_line): Use them.
         (main): Set them.
         (time_string): Use localtime + strftime instead of
         ctime, to avoid problems with years before -999 or after 9999.
         * src/pinky.c: Likewise.

Index: NEWS
===================================================================
RCS file: /home/meyering/coreutils/cu/NEWS,v
retrieving revision 1.217
diff -p -u -r1.217 NEWS
--- NEWS        20 Jun 2004 06:51:34 -0000      1.217
+++ NEWS        21 Jun 2004 08:15:52 -0000
@@ -65,6 +65,10 @@ GNU coreutils NEWS                      
   are no longer safe, as `sort' might start writing F before `cat' is
   done reading it.  This problem cannot occur unless `-m' is used.
 
+  When outside the default POSIX locale, the 'who' and 'pinky'
+  commands now output time stamps like "2004-06-21 13:09" instead of
+  the traditional "Jun 21 13:09".
+
   pwd now works even when run from a working directory whose name
   is longer than PATH_MAX.
 
Index: src/who.c
===================================================================
RCS file: /home/meyering/coreutils/cu/src/who.c,v
retrieving revision 1.96
diff -p -u -r1.96 who.c
--- src/who.c   20 Jun 2004 06:53:05 -0000      1.96
+++ src/who.c   21 Jun 2004 08:03:18 -0000
@@ -33,6 +33,7 @@
 
 #include "readutmp.h"
 #include "error.h"
+#include "hard-locale.h"
 #include "inttostr.h"
 #include "vasprintf.h"
 
@@ -167,6 +168,11 @@ static int need_users;
 /* If nonzero, display info only for the controlling tty */
 static int my_line_only;
 
+/* The strftime format to use for login times, and its expected
+   output width.  */
+static char const *time_format;
+static int time_format_width;
+
 /* for long options with no corresponding short option, use enum */
 enum
 {
@@ -221,11 +227,12 @@ idle_string (time_t when)
   return _(" old ");
 }
 
-/* Return a standard time string, "mon dd hh:mm"
-   FIXME: handle localization */
+/* Return a time string.  */
 static const char *
 time_string (const STRUCT_UTMP *utmp_ent)
 {
+  static char buf[INT_STRLEN_BOUND (intmax_t) + sizeof "-%m-%d %H:%M"];
+
   /* Don't take the address of UT_TIME_MEMBER directly.
      Ulrich Drepper wrote:
      ``... GNU libc (and perhaps other libcs as well) have extended
@@ -233,19 +240,15 @@ time_string (const STRUCT_UTMP *utmp_ent
      In glibc, ut_time is a macro which selects for backward compatibility
      the tv_sec member of a struct timeval value.''  */
   time_t tm = UT_TIME_MEMBER (utmp_ent);
+  struct tm *tmp = localtime (&tm);
 
-  char *ptr = ctime (&tm);
-  if (ptr)
+  if (tmp)
     {
-      ptr += 4;
-      ptr[12] = '\0';
+      strftime (buf, sizeof buf, time_format, tmp);
+      return buf;
     }
   else
-    {
-      static char buf[INT_BUFSIZE_BOUND (intmax_t)];
-      ptr = (TYPE_SIGNED (time_t) ? imaxtostr (tm, buf) : umaxtostr (tm, buf));
-    }
-  return ptr;
+    return TYPE_SIGNED (time_t) ? imaxtostr (tm, buf) : umaxtostr (tm, buf);
 }
 
 /* Print formatted output line. Uses mostly arbitrary field sizes, probably
@@ -285,7 +288,7 @@ print_line (const char *user, const char
                  "%-8s"
                  "%s"
                  " %-12s"
-                 " %-12s"
+                 " %-*s"
                  "%s"
                  "%s"
                  " %-8s"
@@ -294,6 +297,7 @@ print_line (const char *user, const char
                  user ? user : "   .",
                  include_mesg ? mesg : "",
                  line,
+                 time_format_width,
                  time_str,
                  x_idle,
                  x_pid,
@@ -793,6 +797,17 @@ main (int argc, char **argv)
   if (include_exit)
     {
       short_output = 0;
+    }
+
+  if (hard_locale (LC_TIME))
+    {
+      time_format = "%Y-%m-%d %H:%M";
+      time_format_width = 4 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2;
+    }
+  else
+    {
+      time_format = "%b %e %H:%M";
+      time_format_width = 3 + 1 + 2 + 1 + 2 + 1 + 2;
     }
 
   switch (argc - optind)
Index: src/pinky.c
===================================================================
RCS file: /home/meyering/coreutils/cu/src/pinky.c,v
retrieving revision 1.39
diff -p -u -r1.39 pinky.c
--- src/pinky.c 20 Jun 2004 06:56:52 -0000      1.39
+++ src/pinky.c 21 Jun 2004 08:03:35 -0000
@@ -26,6 +26,7 @@
 #include "system.h"
 
 #include "error.h"
+#include "hard-locale.h"
 #include "inttostr.h"
 #include "readutmp.h"
 
@@ -77,6 +78,11 @@ static int do_short_format = 1;
 static int include_where = 1;
 #endif
 
+/* The strftime format to use for login times, and its expected
+   output width.  */
+static char const *time_format;
+static int time_format_width;
+
 static struct option const longopts[] =
 {
   {GETOPT_HELP_OPTION_DECL},
@@ -161,11 +167,12 @@ idle_string (time_t when)
   return (const char *) idle_hhmm;
 }
 
-/* Return a standard time string, "mon dd hh:mm"
-   FIXME: handle localization */
+/* Return a time string.  */
 static const char *
 time_string (const STRUCT_UTMP *utmp_ent)
 {
+  static char buf[INT_STRLEN_BOUND (intmax_t) + sizeof "-%m-%d %H:%M"];
+
   /* Don't take the address of UT_TIME_MEMBER directly.
      Ulrich Drepper wrote:
      ``... GNU libc (and perhaps other libcs as well) have extended
@@ -173,19 +180,15 @@ time_string (const STRUCT_UTMP *utmp_ent
      In glibc, ut_time is a macro which selects for backward compatibility
      the tv_sec member of a struct timeval value.''  */
   time_t tm = UT_TIME_MEMBER (utmp_ent);
+  struct tm *tmp = localtime (&tm);
 
-  char *ptr = ctime (&tm);
-  if (ptr)
+  if (tmp)
     {
-      ptr += 4;
-      ptr[12] = '\0';
+      strftime (buf, sizeof buf, time_format, tmp);
+      return buf;
     }
   else
-    {
-      static char buf[INT_BUFSIZE_BOUND (intmax_t)];
-      ptr = (TYPE_SIGNED (time_t) ? imaxtostr (tm, buf) : umaxtostr (tm, buf));
-    }
-  return ptr;
+    return TYPE_SIGNED (time_t) ? imaxtostr (tm, buf) : umaxtostr (tm, buf);
 }
 
 /* Display a line of information about UTMP_ENT. */
@@ -408,7 +411,7 @@ print_heading (void)
   printf (" %-9s", _(" TTY"));
   if (include_idle)
     printf (" %-6s", _("Idle"));
-  printf (" %-12s", _("When"));
+  printf (" %-*s", time_format_width, _("When"));
 #ifdef HAVE_UT_HOST
   if (include_where)
     printf (" %s", _("Where"));
@@ -422,6 +425,17 @@ static void
 scan_entries (int n, const STRUCT_UTMP *utmp_buf,
              const int argc_names, char *const argv_names[])
 {
+  if (hard_locale (LC_TIME))
+    {
+      time_format = "%Y-%m-%d %H:%M";
+      time_format_width = 4 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2;
+    }
+  else
+    {
+      time_format = "%b %e %H:%M";
+      time_format_width = 3 + 1 + 2 + 1 + 2 + 1 + 2;
+    }
+
   if (include_heading)
     print_heading ();
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]