So, with the tzset(3) restriction in place I'd like to fix grdc, because
what we currently have is wrong:

There are time zones that have minute offsets, display those
correctly. Pointed out by pjanzen@.
To display the offset, use ISO 8601, as suggested by David Goerger.

Take a guess if tzset(3) will accept the time zone specified in TZ as
a relative path and only display it if that is true and it's not too
long. All time zones currently in /usr/share/zoneinfo fit.

Lastly check if tm->tm_gmtoff changed which probably means that we
moved in or out of daylight savings time.

OK?

p.s. I don't know what to do about wintoosmall at this time, the diff is
big enough as it is. And quite frankly I don't care about that.

diff --git grdc.6 grdc.6
index 16e1758c6d2..5aa6e84a2d2 100644
--- grdc.6
+++ grdc.6
@@ -34,8 +34,11 @@ key exits the program.
 .Bl -tag -width Ds
 .It Ev TZ
 The time zone to use for displaying the time.
-It is specified as a pathname relative to
-.Pa /usr/share/zoneinfo .
+It is normally specified as a pathname relative to
+.Pa /usr/share/zoneinfo ,
+though see
+.Xr tzset 3
+for more information.
 If this variable is not set, the time zone is determined based on
 .Pa /etc/localtime .
 .El
diff --git grdc.c grdc.c
index 66e5eee79e6..4bb7fa1b1af 100644
--- grdc.c
+++ grdc.c
@@ -12,6 +12,7 @@
  */
 
 #include <sys/ioctl.h>
+#include <sys/stat.h>
 
 #include <curses.h>
 #include <err.h>
@@ -20,6 +21,7 @@
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <time.h>
 #include <unistd.h>
 
@@ -45,6 +47,7 @@ void getwinsize(int *, int *);
 void set(int, int);
 void standt(int);
 void __dead usage(void);
+int check_tz(const char *);
 
 void
 sigalrm(int signo)
@@ -64,6 +67,36 @@ sigresize(int signo)
        sigwinched = signo;
 }
 
+/* Take a guess if tzset(3) will accept TZ as a relative path */
+int
+check_tz(const char *tz)
+{
+       struct stat      sb;
+       char             fullname[PATH_MAX];
+       int              i;
+
+       if (tz == NULL)
+               return 0;
+
+       if (tz[0] == ':')
+               tz++;
+
+       if (tz[0] == '/' || strstr(tz, "../") != NULL)
+               return 0;
+
+       i = snprintf(fullname, sizeof(fullname), "/usr/share/zoneinfo/%s", tz);
+       if (i < 0 || i >= sizeof(fullname))
+               return 0;
+
+       if (stat(fullname, &sb) == -1)
+               return 0;
+
+       if (!S_ISREG(sb.st_mode))
+               return 0;
+
+       return 1;
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -78,9 +111,19 @@ main(int argc, char *argv[])
        int xbase;
        int ybase;
        int wintoosmall;
+       int tz_valid;
+       int tz_len = 0;
+       int prev_tm_gmtoff;
        char *tz;
 
        tz = getenv("TZ");
+       tz_valid = check_tz(tz);
+
+       if (tz_valid) {
+               if (tz[0] == ':')
+                       tz++;
+               tz_len = strlen(tz);
+       }
 
        scrol = wintoosmall = 0;
        while ((i = getopt(argc, argv, "sh")) != -1) {
@@ -135,6 +178,7 @@ main(int argc, char *argv[])
 
        curs_set(0);
        sigwinched = 1; /* force initial sizing */
+       prev_tm_gmtoff = 24 * 3600; /* force initial header printing */
 
        clock_gettime(CLOCK_REALTIME, &now);
        if (n) {
@@ -152,9 +196,11 @@ main(int argc, char *argv[])
                set(tm->tm_hour / 10, 24);
                set(10, 7);
                set(10, 17);
-               if (sigwinched) {
+               /* force repaint if window size changed or DST changed */
+               if (sigwinched || prev_tm_gmtoff != tm->tm_gmtoff) {
                        sigwinched = 0;
                        wintoosmall = 0;
+                       prev_tm_gmtoff = tm->tm_gmtoff;
                        getwinsize(&i, &j);
                        if (i >= XLENGTH + 2)
                                xbase = (i - XLENGTH) / 2;
@@ -185,9 +231,20 @@ main(int argc, char *argv[])
                                vline(ACS_VLINE, YDEPTH);
 
                                if (tz != NULL) {
+                                       int     h, m;
+                                       h = tm->tm_gmtoff / 3600;
+                                       m = abs((int)tm->tm_gmtoff % 3600 / 60);
+                                       if (tz_valid && tz_len > XLENGTH -
+                                           strlen("[  () +0000 ]") -
+                                           strlen(tm->tm_zone))
+                                               tz_valid = 0;
                                        move(ybase - 1, xbase);
-                                       printw("[ %s %+d ]", tz,
-                                           tm->tm_gmtoff / 60 / 60 );
+                                       if (tz_valid)
+                                               printw("[ %s (%s) %+2.2d%02d ]",
+                                                   tz, tm->tm_zone, h, m);
+                                       else
+                                               printw("[ %s %+2.2d%02d ]",
+                                                   tm->tm_zone, h, m);
                                }
 
                                attrset(COLOR_PAIR(2));

-- 
I'm not entirely sure you are real.

Reply via email to