Print this page
8980 BIOS clock is sometimes one hour fast
Reviewed by: Toomas Soome <tsoome@me.com>
Reviewed by: C Fraire <cfraire@me.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/rtc/rtc.c
          +++ new/usr/src/cmd/rtc/rtc.c
↓ open down ↓ 12 lines elided ↑ open up ↑
  13   13   *
  14   14   * When distributing Covered Code, include this CDDL HEADER in each
  15   15   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16   16   * If applicable, add the following below this CDDL HEADER, with the
  17   17   * fields enclosed by brackets "[]" replaced with your own identifying
  18   18   * information: Portions Copyright [yyyy] [name of copyright owner]
  19   19   *
  20   20   * CDDL HEADER END
  21   21   */
  22   22  /*
       23 + * Copyright 2018 Gary Mills
  23   24   * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  24   25   * Use is subject to license terms.
  25   26   */
  26   27  
  27      -#pragma ident   "%Z%%M% %I%     %E% SMI"
  28      -
  29   28  #include <stdio.h>
  30   29  #include <stdlib.h>
  31   30  #include <unistd.h>
  32   31  #include <sys/types.h>
  33   32  #include <sys/sysi86.h>
  34   33  #include <errno.h>
  35   34  #include <time.h>
  36   35  #include <string.h>
  37   36  #include <sys/stat.h>
  38   37  
       38 +/* RTC modes */
       39 +#define M_UNSET 0 /* Mode never set */
       40 +#define M_VAR   1 /* Tracks local time including DST */
       41 +#define M_UTC   2 /* Clock runs in UTC */
       42 +#define M_STD   3 /* Clock runs in local standard time */
       43 +
  39   44  static char *progname;
  40   45  static char *zonefile = "/etc/rtc_config";
  41   46  static FILE *zonefptr;
  42   47  static char zone_info[256];
  43   48  static char zone_lag[256];
  44   49  static char tz[256] = "TZ=";
       50 +static char *utc_zone = "UTC";
  45   51  int debug = 0;
       52 +int rtc_mode = M_UNSET;
  46   53  int lag;
  47   54  int errors_ok = 0; /* allow "rtc no-args" to be quiet when not configured */
  48   55  static time_t clock_val;
  49   56  static char zone_comment[] =
  50   57          "#\n"
  51   58          "#      This file (%s) contains information used to manage the\n"
  52   59          "#      x86 real time clock hardware.  The hardware is kept in\n"
  53   60          "#      the machine's local time for compatibility with other x86\n"
  54   61          "#      operating systems.  This file is read by the kernel at\n"
  55   62          "#      boot time.  It is set and updated by the /usr/sbin/rtc\n"
↓ open down ↓ 8 lines elided ↑ open up ↑
  64   71   */
  65   72  int
  66   73  open_zonefile()
  67   74  {
  68   75          char b[256], *s;
  69   76          int lag_hrs;
  70   77  
  71   78          if ((zonefptr = fopen(zonefile, "r")) == NULL) {
  72   79                  if (errors_ok == 0)
  73   80                          (void) fprintf(stderr,
  74      -                                "%s: cannot open %s: errno = %d\n",
  75      -                                progname, zonefile, errno);
       81 +                            "%s: cannot open %s: errno = %d\n",
       82 +                            progname, zonefile, errno);
  76   83                  return (1);
  77   84          }
  78   85  
  79   86          for (;;) {
  80   87                  if ((s = fgets(b, sizeof (b), zonefptr)) == NULL)
  81   88                          break;
  82   89                  if ((s = strchr(s, 'z')) == NULL)
  83   90                          continue;
  84   91                  if (strncmp(s, "zone_info", 9) == 0) {
  85   92                          s += 9;
↓ open down ↓ 63 lines elided ↑ open up ↑
 149  156  
 150  157  void
 151  158  display_zone_string(void)
 152  159  {
 153  160          if (open_zonefile() == 0)
 154  161                  (void) printf("%s\n", zone_info);
 155  162          else
 156  163                  (void) printf("GMT\n");
 157  164  }
 158  165  
 159      -long
 160      -set_zone(char *zone_string)
      166 +int
      167 +get_local(char *z)
 161  168  {
 162  169          struct tm *tm;
 163      -        long current_lag;
 164  170  
 165      -        (void) umask(0022);
 166      -        if ((zonefptr = fopen(zonefile, "w")) == NULL) {
 167      -                (void) fprintf(stderr, "%s: cannot open %s: errno = %d\n",
 168      -                        progname, zonefile, errno);
 169      -                return (0);
 170      -        }
 171      -
 172  171          tz[3] = 0;
 173      -        (void) strncat(tz, zone_string, 253);
      172 +        (void) strncat(tz, z, 253);
 174  173          if (debug)
 175  174                  (void) fprintf(stderr, "Time Zone string is '%s'\n", tz);
 176  175  
 177  176          (void) putenv(tz);
 178  177          if (debug)
 179  178                  (void) system("env | grep TZ");
 180  179  
 181  180          (void) time(&clock_val);
 182  181  
 183  182          tm = localtime(&clock_val);
 184      -        current_lag = tm->tm_isdst ? altzone : timezone;
      183 +        return (tm->tm_isdst);
      184 +}
      185 +
      186 +long
      187 +set_zone(char *zone_string)
      188 +{
      189 +        int isdst;
      190 +        long current_lag;
      191 +
      192 +        (void) umask(0022);
      193 +        if ((zonefptr = fopen(zonefile, "w")) == NULL) {
      194 +                (void) fprintf(stderr, "%s: cannot open %s: errno = %d\n",
      195 +                    progname, zonefile, errno);
      196 +                return (0);
      197 +        }
      198 +
      199 +        switch (rtc_mode) {
      200 +        case M_VAR:
      201 +                isdst = get_local(zone_string);
      202 +                current_lag = isdst ? altzone : timezone;
      203 +                break;
      204 +        case M_STD:
      205 +                isdst = get_local(zone_string);
      206 +                current_lag = timezone;
      207 +                break;
      208 +        default:        /* Includes M_UTC */
      209 +                isdst = 0;
      210 +                current_lag = 0;
      211 +                zone_string = utc_zone;
      212 +                break;
      213 +        }
 185  214          if (debug)
 186      -                (void) printf("%s DST.    Lag is %ld.\n", tm->tm_isdst ? "Is" :
 187      -                    "Is NOT",  tm->tm_isdst ? altzone : timezone);
      215 +                (void) printf("%s DST.    Lag is %ld.\n", isdst ? "Is" :
      216 +                    "Is NOT",  current_lag);
 188  217  
 189  218          (void) fprintf(zonefptr, zone_comment, zonefile);
 190  219          (void) fprintf(zonefptr, "zone_info=%s\n", zone_string);
 191      -        (void) fprintf(zonefptr, "zone_lag=%ld\n",
 192      -            tm->tm_isdst ? altzone : timezone);
      220 +        (void) fprintf(zonefptr, "zone_lag=%ld\n", current_lag);
 193  221          (void) fclose(zonefptr);
 194  222          zonefptr = NULL;
 195  223          return (current_lag);
 196  224  }
 197  225  
 198  226  void
 199  227  correct_rtc_and_lag()
 200  228  {
 201      -        struct tm *tm;
      229 +        int isdst;
 202  230          long kernels_lag;
 203  231          long current_lag;
 204  232  
 205  233          if (open_zonefile())
 206  234                  return;
 207  235  
 208      -        tz[3] = 0;
 209      -        (void) strncat(tz, zone_info, 253);
 210      -        if (debug)
 211      -                (void) fprintf(stderr, "Time Zone string is '%s'\n", tz);
      236 +        switch (rtc_mode) {
      237 +        case M_VAR:
      238 +                isdst = get_local(zone_info);
      239 +                current_lag = isdst ? altzone : timezone;
      240 +                break;
      241 +        case M_STD:
      242 +                (void) get_local(zone_info);
      243 +                current_lag = timezone;
      244 +                break;
      245 +        default:        /* Includes M_UTC */
      246 +                current_lag = 0;
      247 +                break;
      248 +        }
 212  249  
 213      -        (void) putenv(tz);
 214      -        if (debug)
 215      -                (void) system("env | grep TZ");
 216      -
 217      -        (void) time(&clock_val);
 218      -        tm = localtime(&clock_val);
 219      -        current_lag = tm->tm_isdst ? altzone : timezone;
 220      -
 221  250          if (current_lag != lag) {       /* if file is wrong */
 222  251                  if (debug)
 223      -                        (void) fprintf(stderr, "correcting file");
      252 +                        (void) fprintf(stderr, "correcting file\n");
 224  253                  (void) set_zone(zone_info);     /* then rewrite file */
 225  254          }
 226  255  
 227  256          (void) sysi86(GGMTL, &kernels_lag);
 228  257          if (current_lag != kernels_lag) {
 229  258                  if (debug)
 230      -                        (void) fprintf(stderr, "correcting kernel's lag");
      259 +                        (void) fprintf(stderr, "correcting kernel's lag\n");
 231  260                  (void) sysi86(SGMTL, current_lag);      /* correct the lag */
 232  261                  (void) sysi86(WTODC);                   /* set the rtc to */
 233  262                                                          /* new local time */
 234  263          }
 235  264  }
 236  265  
 237  266  void
 238  267  initialize_zone(char *zone_string)
 239  268  {
 240  269          long current_lag;
↓ open down ↓ 9 lines elided ↑ open up ↑
 250  279           * assuming the rtc was the correct
 251  280           * local time.
 252  281           */
 253  282          (void) sysi86(RTCSYNC);
 254  283  }
 255  284  
 256  285  void
 257  286  usage()
 258  287  {
 259  288          static char Usage[] = "Usage:\n\
 260      -rtc [-c] [-z time_zone] [-?]\n";
      289 +rtc [-w] [-s|-u|-v] [-c] [-z time_zone] [-?]\n";
 261  290  
 262  291          (void) fprintf(stderr, Usage);
 263  292  }
 264  293  
 265  294  void
 266  295  verbose_usage()
 267  296  {
 268  297          static char Usage1[] = "\
 269  298          Options:\n\
      299 +            -w\t\tDoes nothing.\n\
      300 +            -s\t\tRTC runs in local standard time.\n\
      301 +            -u\t\tRTC runs in UTC time.\n\
      302 +            -v\t\tRTC tracks local time (with cron command).\n\
 270  303              -c\t\tCheck and correct for daylight savings time rollover.\n\
 271  304              -z [zone]\tRecord the zone info in the config file.\n";
 272  305  
 273  306          (void) fprintf(stderr, Usage1);
 274  307  }
 275  308  
      309 +void
      310 +set_default()
      311 +{
      312 +        switch (rtc_mode) {
      313 +        default:        /* Includes M_UNSET */
      314 +                rtc_mode = M_VAR;
      315 +                break;
      316 +        case M_VAR:
      317 +                /*FALLTHROUGH*/
      318 +        case M_UTC:
      319 +                /*FALLTHROUGH*/
      320 +        case M_STD:
      321 +                break;
      322 +        }
      323 +}
      324 +
      325 +void
      326 +check_mode(int letter, int mode)
      327 +{
      328 +        if (rtc_mode == M_UNSET || rtc_mode == mode) {
      329 +                rtc_mode = mode;
      330 +                return;
      331 +        }
      332 +        (void) fprintf(stderr, "%s: option -%c conflicts with other options\n",
      333 +            progname, letter);
      334 +        exit(1);
      335 +}
      336 +
      337 +
 276  338  int
 277  339  main(int argc, char *argv[])
 278  340  {
 279  341          int c;
      342 +        int cflg = 0;
      343 +        char *zone_name = NULL;
 280  344  
 281  345          progname = argv[0];
 282  346  
 283  347          if (argc == 1) {
 284  348                  errors_ok = 1;
 285  349                  display_zone_string();
      350 +                exit(0);
 286  351          }
 287  352  
 288      -        while ((c = getopt(argc, argv, "cz:d")) != EOF) {
      353 +        while ((c = getopt(argc, argv, "suvwcz:d")) != EOF) {
 289  354                  switch (c) {
 290  355                  case 'c':
 291      -                        correct_rtc_and_lag();
      356 +                        cflg++;
 292  357                          continue;
 293  358                  case 'z':
 294      -                        initialize_zone(optarg);
      359 +                        zone_name = optarg;
 295  360                          continue;
 296  361                  case 'd':
 297  362                          debug = 1;
 298  363                          continue;
      364 +                case 's':       /* standard: RTC runs local standard time */
      365 +                        check_mode(c, M_STD);
      366 +                        continue;
      367 +                case 'u':       /* utc: RTC runs UTC time */
      368 +                        check_mode(c, M_UTC);
      369 +                        continue;
      370 +                case 'v':       /* varies: RTC tracks local time */
      371 +                        check_mode(c, M_VAR);
      372 +                        continue;
      373 +                case 'w':       /* Does nothing */
      374 +                        continue;
 299  375                  case '?':
 300  376                          verbose_usage();
 301      -                        return (0);
      377 +                        exit(0);
 302  378                  default:
 303  379                          usage();
 304      -                        return (1);
      380 +                        exit(1);
 305  381                  }
 306  382          }
 307      -        return (0);
      383 +        set_default();
      384 +        if (zone_name != NULL)
      385 +                initialize_zone(zone_name);
      386 +        if (cflg > 0)
      387 +                correct_rtc_and_lag();
      388 +        exit(0);
      389 +        /*LINTED*/
 308  390  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX