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