1 /* A helper tool for perl's 2038 support. 2 * See Porting/README.y2038 for details 3 */ 4 5 #include <sys/types.h> 6 #include <stdio.h> 7 #include <time.h> 8 #include <errno.h> 9 #include <string.h> 10 11 int opt_v = 0; 12 int i; 13 struct tm *tmp; 14 time_t pt, pt_max, pt_min; 15 16 static char hexbuf[80]; 17 char *hex (time_t t) 18 { 19 if ((long long)t < 0) 20 sprintf (hexbuf, " -0x%016lx", -t); 21 else 22 sprintf (hexbuf, " 0x%016lx", t); 23 return (hexbuf); 24 } /* hex */ 25 26 void gm_check (time_t t, int min_year, int max_year) 27 { 28 tmp = gmtime (&t); 29 if ( tmp == NULL || 30 /* Check tm_year overflow */ 31 tmp->tm_year < min_year || tmp->tm_year > max_year) { 32 if (opt_v) 33 fprintf (stderr, "gmtime (%ld) failed with errno %d\n", t, errno); 34 } 35 else { 36 if (opt_v) 37 fprintf (stderr, "%3d:%s: %12ld-%02d-%02d %02d:%02d:%02d\n", 38 i, hex (t), 39 (long)(tmp->tm_year) + 1900, tmp->tm_mon + 1, tmp->tm_mday, 40 tmp->tm_hour, tmp->tm_min, tmp->tm_sec); 41 pt = t; 42 } 43 } /* gm_check */ 44 45 int check_gm_max () 46 { 47 tmp = NULL; 48 pt = 0; 49 if (tmp == NULL || tmp->tm_year < 0) { 50 for (i = 63; i >= 0; i--) { 51 time_t x = pt | ((time_t)1 << i); 52 if (x < 0 || x < pt) continue; 53 gm_check (x, 69, 0x7fffffff); 54 } 55 } 56 pt_max = pt; 57 return (0); 58 } /* check_gm_max */ 59 60 int check_gm_min () 61 { 62 tmp = NULL; 63 pt = 0; 64 if (tmp == NULL) { 65 for (i = 36; i >= 0; i--) { 66 time_t x = pt - ((time_t)1 << i); 67 if (x > 0) continue; 68 gm_check (x, -1900, 70); 69 } 70 } 71 pt_min = pt; 72 return (0); 73 } /* check_gm_min */ 74 75 void lt_check (time_t t, int min_year, int max_year) 76 { 77 if (sizeof (time_t) > 4 && t > 0x7ffffffffffff000LL) 78 tmp = NULL; 79 else 80 tmp = localtime (&t); 81 if ( tmp == NULL || 82 /* Check tm_year overflow */ 83 tmp->tm_year < min_year || tmp->tm_year > max_year) { 84 if (opt_v) 85 fprintf (stderr, "localtime (%ld) failed with errno %d\n", t, errno); 86 } 87 else { 88 if (opt_v) 89 fprintf (stderr, "%3d:%s: %12ld-%02d-%02d %02d:%02d:%02d\n", 90 i, hex (t), 91 (long)(tmp->tm_year) + 1900, tmp->tm_mon + 1, tmp->tm_mday, 92 tmp->tm_hour, tmp->tm_min, tmp->tm_sec); 93 pt = t; 94 } 95 } /* lt_check */ 96 97 int check_lt_max () 98 { 99 tmp = NULL; 100 pt = 0; 101 if (tmp == NULL || tmp->tm_year < 0) { 102 for (i = 63; i >= 0; i--) { 103 time_t x = pt | ((time_t)1 << i); 104 if (x < 0 || x < pt) continue; 105 lt_check (x, 69, 0x7fffffff); 106 } 107 } 108 pt_max = pt; 109 return (0); 110 } /* check_lt_max */ 111 112 int check_lt_min () 113 { 114 tmp = NULL; 115 pt = 0; 116 if (tmp == NULL) { 117 for (i = 36; i >= 0; i--) { 118 time_t x = pt - ((time_t)1 << i); 119 if (x > 0) continue; 120 lt_check (x, -1900, 70); 121 } 122 } 123 pt_min = pt; 124 return (0); 125 } /* check_lt_min */ 126 127 int main (int argc, char *argv[]) 128 { 129 time_t gm_max, gm_min, lt_max, lt_min; 130 if (argc > 1 && strcmp (argv[1], "-v") == 0) opt_v++; 131 132 check_gm_max (); gm_max = pt_max; 133 check_gm_min (); gm_min = pt_min; 134 check_lt_max (); lt_max = pt_max; 135 check_lt_min (); lt_min = pt_min; 136 137 opt_v++; 138 printf ("======================\n"); 139 printf ("Sizeof time_t = %d\n", (i = sizeof (time_t))); 140 printf ("gmtime () boundaries:\n"); 141 gm_check (gm_max, 69, 0x7fffffff); 142 gm_check (gm_min, -1900, 70); 143 printf ("localtime () boundaries:\n"); 144 lt_check (lt_max, 69, 0x7fffffff); 145 lt_check (lt_min, -1900, 70); 146 printf ("Configure variables:\n"); 147 printf ("sGMTIME_max='%ld'\n", gm_max); 148 printf ("sGMTIME_min='%ld'\n", gm_min); 149 printf ("sLOCALTIME_max='%ld'\n", lt_max); 150 printf ("sLOCALTIME_min='%ld'\n", lt_min); 151 return (0); 152 } /* main */ 153