1 /* 2 * systime -- routines to fiddle a UNIX clock. 3 */ 4 5 #ifdef HAVE_CONFIG_H 6 # include <config.h> 7 #endif 8 9 #include <stdio.h> 10 #include <sys/types.h> 11 #include <sys/time.h> 12 #ifdef HAVE_SYS_PARAM_H 13 # include <sys/param.h> 14 #endif 15 #ifdef HAVE_UTMP_H 16 # include <utmp.h> 17 #endif /* HAVE_UTMP_H */ 18 #ifdef HAVE_UTMPX_H 19 # include <utmpx.h> 20 #endif /* HAVE_UTMPX_H */ 21 22 #include "ntp_machine.h" 23 #include "ntp_fp.h" 24 #include "ntp_syslog.h" 25 #include "ntp_unixtime.h" 26 #include "ntp_stdlib.h" 27 28 int systime_10ms_ticks = 0; /* adj sysclock in 10ms increments */ 29 30 #define MAXFREQ 500e-6 31 32 /* 33 * These routines (init_systime, get_systime, step_systime, adj_systime) 34 * implement an interface between the (more or less) system independent 35 * bits of NTP and the peculiarities of dealing with the Unix system 36 * clock. 37 */ 38 double sys_residual = 0; /* residual from previous adjustment */ 39 double sys_maxfreq = MAXFREQ; /* max frequency correction */ 40 41 42 /* 43 * get_systime - return the system time in timestamp format biased by 44 * the current time offset. 45 */ 46 void 47 get_systime( 48 l_fp *now 49 ) 50 { 51 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) 52 struct timespec ts; 53 #else 54 struct timeval tv; 55 #endif 56 double dtemp; 57 58 /* 59 * We use nanosecond time if we can get it. Watch out for 60 * rounding wiggles, which may overflow the fraction. 61 */ 62 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) 63 # ifdef HAVE_CLOCK_GETTIME 64 (void) clock_gettime(CLOCK_REALTIME, &ts); 65 # else 66 (void) getclock(TIMEOFDAY, &ts); 67 # endif 68 now->l_i = ts.tv_sec + JAN_1970; 69 dtemp = ts.tv_nsec * FRAC / 1e9; 70 if (dtemp >= FRAC) 71 now->l_i++; 72 now->l_uf = (u_int32)dtemp; 73 #else /* HAVE_CLOCK_GETTIME */ 74 (void) GETTIMEOFDAY(&tv, (struct timezone *)0); 75 now->l_i = tv.tv_sec + JAN_1970; 76 77 #if defined RELIANTUNIX_CLOCK || defined SCO5_CLOCK 78 if (systime_10ms_ticks) { 79 /* fake better than 10ms resolution by interpolating 80 accumulated residual (in adj_systime(), see below) */ 81 dtemp = tv.tv_usec / 1e6; 82 if (sys_residual < 5000e-6 && sys_residual > -5000e-6) { 83 dtemp += sys_residual; 84 if (dtemp < 0) { 85 now->l_i--; 86 dtemp++; 87 } 88 } 89 dtemp *= FRAC; 90 } else 91 #endif 92 93 dtemp = tv.tv_usec * FRAC / 1e6; 94 95 if (dtemp >= FRAC) 96 now->l_i++; 97 now->l_uf = (u_int32)dtemp; 98 #endif /* HAVE_CLOCK_GETTIME */ 99 100 } 101 102 103 /* 104 * adj_systime - called once every second to make system time adjustments. 105 * Returns 1 if okay, 0 if trouble. 106 */ 107 #if !defined SYS_WINNT 108 int 109 adj_systime( 110 double now 111 ) 112 { 113 double dtemp; 114 struct timeval adjtv; 115 u_char isneg = 0; 116 struct timeval oadjtv; 117 118 /* 119 * Add the residual from the previous adjustment to the new 120 * adjustment, bound and round. 121 */ 122 dtemp = sys_residual + now; 123 sys_residual = 0; 124 if (dtemp < 0) { 125 isneg = 1; 126 dtemp = -dtemp; 127 } 128 129 #if defined RELIANTUNIX_CLOCK || defined SCO5_CLOCK 130 if (systime_10ms_ticks) { 131 /* accumulate changes until we have enough to adjust a tick */ 132 if (dtemp < 5000e-6) { 133 if (isneg) sys_residual = -dtemp; 134 else sys_residual = dtemp; 135 dtemp = 0; 136 } else { 137 if (isneg) sys_residual = 10000e-6 - dtemp; 138 else sys_residual = dtemp - 10000e-6; 139 dtemp = 10000e-6; 140 } 141 } else 142 #endif 143 if (dtemp > sys_maxfreq) 144 dtemp = sys_maxfreq; 145 146 dtemp = dtemp * 1e6 + .5; 147 148 if (isneg) 149 dtemp = -dtemp; 150 adjtv.tv_sec = 0; 151 adjtv.tv_usec = (int32)dtemp; 152 153 /* 154 * Here we do the actual adjustment. If for some reason the adjtime() 155 * call fails, like it is not implemented or something like that, 156 * we honk to the log. If the previous adjustment did not complete, 157 * we correct the residual offset. 158 */ 159 /* casey - we need a posix type thang here */ 160 if (adjtime(&adjtv, &oadjtv) < 0) 161 { 162 msyslog(LOG_ERR, "Can't adjust time: %m"); 163 return 0; 164 } 165 else { 166 sys_residual += oadjtv.tv_usec / 1e6; 167 } 168 #ifdef DEBUG 169 if (debug > 6) 170 printf("adj_systime: adj %.9f -> remaining residual %.9f\n", now, sys_residual); 171 #endif 172 return 1; 173 } 174 #endif 175 176 177 /* 178 * step_systime - step the system clock. 179 */ 180 int 181 step_systime( 182 double now 183 ) 184 { 185 struct timeval timetv, adjtv, oldtimetv; 186 int isneg = 0; 187 double dtemp; 188 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) 189 struct timespec ts; 190 #endif 191 192 dtemp = sys_residual + now; 193 if (dtemp < 0) { 194 isneg = 1; 195 dtemp = - dtemp; 196 adjtv.tv_sec = (int32)dtemp; 197 adjtv.tv_usec = (u_int32)((dtemp - (double)adjtv.tv_sec) * 198 1e6 + .5); 199 } else { 200 adjtv.tv_sec = (int32)dtemp; 201 adjtv.tv_usec = (u_int32)((dtemp - (double)adjtv.tv_sec) * 202 1e6 + .5); 203 } 204 #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK) 205 #ifdef HAVE_CLOCK_GETTIME 206 (void) clock_gettime(CLOCK_REALTIME, &ts); 207 #else 208 (void) getclock(TIMEOFDAY, &ts); 209 #endif 210 timetv.tv_sec = ts.tv_sec; 211 timetv.tv_usec = ts.tv_nsec / 1000; 212 #else /* not HAVE_GETCLOCK */ 213 (void) GETTIMEOFDAY(&timetv, (struct timezone *)0); 214 #endif /* not HAVE_GETCLOCK */ 215 216 oldtimetv = timetv; 217 218 #ifdef DEBUG 219 if (debug) 220 printf("step_systime: step %.6f residual %.6f\n", now, sys_residual); 221 #endif 222 if (isneg) { 223 timetv.tv_sec -= adjtv.tv_sec; 224 timetv.tv_usec -= adjtv.tv_usec; 225 if (timetv.tv_usec < 0) { 226 timetv.tv_sec--; 227 timetv.tv_usec += 1000000; 228 } 229 } else { 230 timetv.tv_sec += adjtv.tv_sec; 231 timetv.tv_usec += adjtv.tv_usec; 232 if (timetv.tv_usec >= 1000000) { 233 timetv.tv_sec++; 234 timetv.tv_usec -= 1000000; 235 } 236 } 237 if (ntp_set_tod(&timetv, (struct timezone *)0) != 0) { 238 msyslog(LOG_ERR, "Can't set time of day: %m"); 239 return (0); 240 } 241 sys_residual = 0; 242 243 #ifdef NEED_HPUX_ADJTIME 244 /* 245 * CHECKME: is this correct when called by ntpdate????? 246 */ 247 _clear_adjtime(); 248 #endif 249 250 /* 251 * FreeBSD, for example, has: 252 * struct utmp { 253 * char ut_line[UT_LINESIZE]; 254 * char ut_name[UT_NAMESIZE]; 255 * char ut_host[UT_HOSTSIZE]; 256 * long ut_time; 257 * }; 258 * and appends line="|", name="date", host="", time for the OLD 259 * and appends line="{", name="date", host="", time for the NEW 260 * to _PATH_WTMP . 261 * 262 * Some OSes have utmp, some have utmpx. 263 */ 264 265 /* 266 * Write old and new time entries in utmp and wtmp if step adjustment 267 * is greater than one second. 268 * 269 * This might become even Uglier... 270 */ 271 if (oldtimetv.tv_sec != timetv.tv_sec) 272 { 273 #ifdef HAVE_UTMP_H 274 struct utmp ut; 275 #endif 276 #ifdef HAVE_UTMPX_H 277 struct utmpx utx; 278 #endif 279 280 #ifdef HAVE_UTMP_H 281 memset((char *)&ut, 0, sizeof(ut)); 282 #endif 283 #ifdef HAVE_UTMPX_H 284 memset((char *)&utx, 0, sizeof(utx)); 285 #endif 286 287 /* UTMP */ 288 289 #ifdef UPDATE_UTMP 290 # ifdef HAVE_PUTUTLINE 291 ut.ut_type = OLD_TIME; 292 (void)strcpy(ut.ut_line, OTIME_MSG); 293 ut.ut_time = oldtimetv.tv_sec; 294 pututline(&ut); 295 setutent(); 296 ut.ut_type = NEW_TIME; 297 (void)strcpy(ut.ut_line, NTIME_MSG); 298 ut.ut_time = timetv.tv_sec; 299 pututline(&ut); 300 endutent(); 301 # else /* not HAVE_PUTUTLINE */ 302 # endif /* not HAVE_PUTUTLINE */ 303 #endif /* UPDATE_UTMP */ 304 305 /* UTMPX */ 306 307 #ifdef UPDATE_UTMPX 308 # ifdef HAVE_PUTUTXLINE 309 utx.ut_type = OLD_TIME; 310 (void)strcpy(utx.ut_line, OTIME_MSG); 311 utx.ut_tv = oldtimetv; 312 pututxline(&utx); 313 setutxent(); 314 utx.ut_type = NEW_TIME; 315 (void)strcpy(utx.ut_line, NTIME_MSG); 316 utx.ut_tv = timetv; 317 pututxline(&utx); 318 endutxent(); 319 # else /* not HAVE_PUTUTXLINE */ 320 # endif /* not HAVE_PUTUTXLINE */ 321 #endif /* UPDATE_UTMPX */ 322 323 /* WTMP */ 324 325 #ifdef UPDATE_WTMP 326 # ifdef HAVE_PUTUTLINE 327 utmpname(WTMP_FILE); 328 ut.ut_type = OLD_TIME; 329 (void)strcpy(ut.ut_line, OTIME_MSG); 330 ut.ut_time = oldtimetv.tv_sec; 331 pututline(&ut); 332 ut.ut_type = NEW_TIME; 333 (void)strcpy(ut.ut_line, NTIME_MSG); 334 ut.ut_time = timetv.tv_sec; 335 pututline(&ut); 336 endutent(); 337 # else /* not HAVE_PUTUTLINE */ 338 # endif /* not HAVE_PUTUTLINE */ 339 #endif /* UPDATE_WTMP */ 340 341 /* WTMPX */ 342 343 #ifdef UPDATE_WTMPX 344 # ifdef HAVE_PUTUTXLINE 345 utx.ut_type = OLD_TIME; 346 utx.ut_tv = oldtimetv; 347 (void)strcpy(utx.ut_line, OTIME_MSG); 348 # ifdef HAVE_UPDWTMPX 349 updwtmpx(WTMPX_FILE, &utx); 350 # else /* not HAVE_UPDWTMPX */ 351 # endif /* not HAVE_UPDWTMPX */ 352 # else /* not HAVE_PUTUTXLINE */ 353 # endif /* not HAVE_PUTUTXLINE */ 354 # ifdef HAVE_PUTUTXLINE 355 utx.ut_type = NEW_TIME; 356 utx.ut_tv = timetv; 357 (void)strcpy(utx.ut_line, NTIME_MSG); 358 # ifdef HAVE_UPDWTMPX 359 updwtmpx(WTMPX_FILE, &utx); 360 # else /* not HAVE_UPDWTMPX */ 361 # endif /* not HAVE_UPDWTMPX */ 362 # else /* not HAVE_PUTUTXLINE */ 363 # endif /* not HAVE_PUTUTXLINE */ 364 #endif /* UPDATE_WTMPX */ 365 366 } 367 return (1); 368 } 369