📄 hwclock.c
字号:
adjtime_p->last_calib_time = nowtime; adjtime_p->last_adj_time = nowtime; adjtime_p->not_adjusted = 0; adjtime_p->dirty = TRUE;}static voidcalculate_adjustment(const double factor, const time_t last_time, const double not_adjusted, const time_t systime, int *adjustment_p, double *retro_p, const int debug ) {/*---------------------------------------------------------------------------- Do the drift adjustment calculation. The way we have to set the clock, we need the adjustment in two parts: 1) an integer number of seconds (return as *adjustment_p) 2) a positive fraction of a second (less than 1) (return as *retro_p) The sum of these two values is the adjustment needed. Positive means to advance the clock or insert seconds. Negative means to retard the clock or remove seconds.----------------------------------------------------------------------------*/ double exact_adjustment; exact_adjustment = ((double) (systime - last_time)) * factor / (24 * 60 * 60) + not_adjusted; *adjustment_p = FLOOR(exact_adjustment); *retro_p = exact_adjustment - (double) *adjustment_p; if (debug) { printf (_("Time since last adjustment is %d seconds\n"), (int) (systime - last_time)); printf (_("Need to insert %d seconds and refer time back " "%.6f seconds ago\n"), *adjustment_p, *retro_p); }}static voidsave_adjtime(const struct adjtime adjtime, const bool testing) {/*----------------------------------------------------------------------------- Write the contents of the <adjtime> structure to its disk file. But if the contents are clean (unchanged since read from disk), don't bother.-----------------------------------------------------------------------------*/ char newfile[412]; /* Stuff to write to disk file */ if (adjtime.dirty) { /* snprintf is not always available, but this is safe as long as libc does not use more than 100 positions for %ld or %f */ sprintf(newfile, "%f %ld %f\n%ld\n%s\n", adjtime.drift_factor, (long) adjtime.last_adj_time, adjtime.not_adjusted, (long) adjtime.last_calib_time, (adjtime.local_utc == UTC) ? "UTC" : "LOCAL"); if (testing) { printf(_("Not updating adjtime file because of testing mode.\n")); printf(_("Would have written the following to %s:\n%s"), ADJPATH, newfile); } else { FILE *adjfile; int err = 0; adjfile = fopen(ADJPATH, "w"); if (adjfile == NULL) { outsyserr("Could not open file with the clock adjustment parameters " "in it (" ADJPATH ") for writing"); err = 1; } else { if (fputs(newfile, adjfile) < 0) { outsyserr("Could not update file with the clock adjustment " "parameters (" ADJPATH ") in it"); err = 1; } if (fclose(adjfile) < 0) { outsyserr("Could not update file with the clock adjustment " "parameters (" ADJPATH ") in it"); err = 1; } } if (err) fprintf(stderr, _("Drift adjustment parameters not updated.\n")); } }}static voiddo_adjustment(struct adjtime *adjtime_p, const bool hclock_valid, const time_t hclocktime, const struct timeval read_time, const bool universal, const bool testing) {/*--------------------------------------------------------------------------- Do the adjustment requested, by 1) setting the Hardware Clock (if necessary), and 2) updating the last-adjusted time in the adjtime structure. Do not update anything if the Hardware Clock does not currently present a valid time. arguments <factor> and <last_time> are current values from the adjtime file. <hclock_valid> means the Hardware Clock contains a valid time, and that time is <hclocktime>. <read_time> is the current system time (to be precise, it is the system time at the time <hclocktime> was read, which due to computational delay could be a short time ago). <universal>: the Hardware Clock is kept in UTC. <testing>: We are running in test mode (no updating of clock). We do not bother to update the clock if the adjustment would be less than one second. This is to avoid cumulative error and needless CPU hogging (remember we use an infinite loop for some timing) if the user runs us frequently.----------------------------------------------------------------------------*/ if (!hclock_valid) { fprintf(stderr, _("The Hardware Clock does not contain a valid time, " "so we cannot adjust it.\n")); adjtime_p->last_calib_time = 0; /* calibration startover is required */ adjtime_p->last_adj_time = 0; adjtime_p->not_adjusted = 0; adjtime_p->dirty = TRUE; } else if (adjtime_p->last_adj_time == 0) { if (debug) printf("Not setting clock because last adjustment time is zero, " "so history is bad."); } else { int adjustment; /* Number of seconds we must insert in the Hardware Clock */ double retro; /* Fraction of second we have to remove from clock after inserting <adjustment> whole seconds. */ calculate_adjustment(adjtime_p->drift_factor, adjtime_p->last_adj_time, adjtime_p->not_adjusted, hclocktime, &adjustment, &retro, debug ); if (adjustment > 0 || adjustment < -1) { set_hardware_clock_exact(hclocktime + adjustment, time_inc(read_time, -retro), universal, testing); adjtime_p->last_adj_time = hclocktime + adjustment; adjtime_p->not_adjusted = 0; adjtime_p->dirty = TRUE; } else if (debug) printf(_("Needed adjustment is less than one second, " "so not setting clock.\n")); }}static voiddetermine_clock_access_method(const bool user_requests_ISA) { ur = NULL; if (user_requests_ISA) ur = probe_for_cmos_clock(); if (!ur) ur = probe_for_rtc_clock(); if (!ur) ur = probe_for_kd_clock(); if (!ur && !user_requests_ISA) ur = probe_for_cmos_clock(); if (debug) { if (ur) printf(_("Using %s.\n"), ur->interface_name); else printf(_("No usable clock interface found.\n")); }}static intmanipulate_clock(const bool show, const bool adjust, const bool noadjfile, const bool set, const time_t set_time, const bool hctosys, const bool systohc, const struct timeval startup_time, const bool utc, const bool local_opt, const bool testing) {/*--------------------------------------------------------------------------- Do all the normal work of hwclock - read, set clock, etc. Issue output to stdout and error message to stderr where appropriate. Return rc == 0 if everything went OK, rc != 0 if not.----------------------------------------------------------------------------*/ struct adjtime adjtime; /* Contents of the adjtime file, or what they should be. */ int rc; /* local return code */ bool no_auth; /* User lacks necessary authorization to access the clock */ no_auth = ur->get_permissions(); if (no_auth) return EX_NOPERM; if (!noadjfile && (adjust || set || systohc || (!utc && !local_opt))) { rc = read_adjtime(&adjtime); if (rc) return rc; } else { /* A little trick to avoid reading the file if we don't have to */ adjtime.dirty = FALSE; rc = 0; } { const bool universal = hw_clock_is_utc(utc, local_opt, adjtime); if ((set || systohc || adjust) && (adjtime.local_utc == UTC) != universal) { adjtime.local_utc = universal ? UTC : LOCAL; adjtime.dirty = TRUE; } rc = synchronize_to_clock_tick(); /* this takes up to 1 second */ if (rc) return rc; { struct timeval read_time; /* The time at which we read the Hardware Clock */ bool hclock_valid; /* The Hardware Clock gives us a valid time, or at least something close enough to fool mktime(). */ time_t hclocktime; /* The time the hardware clock had just after we synchronized to its next clock tick when we started up. Defined only if hclock_valid is true. */ gettimeofday(&read_time, NULL); read_hardware_clock(universal, &hclock_valid, &hclocktime); if (show) { display_time(hclock_valid, hclocktime, time_diff(read_time, startup_time)); } else if (set) { set_hardware_clock_exact(set_time, startup_time, universal, testing); adjust_drift_factor(&adjtime, set_time, hclock_valid, hclocktime, time_diff(read_time, startup_time)); } else if (adjust) { do_adjustment(&adjtime, hclock_valid, hclocktime, read_time, universal, testing); } else if (systohc) { struct timeval nowtime, reftime; /* We can only set_hardware_clock_exact to a whole seconds time, so we set it with reference to the most recent whole seconds time. */ gettimeofday(&nowtime, NULL); reftime.tv_sec = nowtime.tv_sec; reftime.tv_usec = 0; set_hardware_clock_exact((time_t) reftime.tv_sec, reftime, universal, testing); adjust_drift_factor(&adjtime, (time_t) reftime.tv_sec, hclock_valid, hclocktime, (double) read_time.tv_usec / 1E6); } else if (hctosys) { rc = set_system_clock(hclock_valid, hclocktime, testing); if (rc) { printf(_("Unable to set system clock.\n")); return rc; } } if (!noadjfile) save_adjtime(adjtime, testing); } } return 0;}static voidmanipulate_epoch(const bool getepoch, const bool setepoch, const int epoch_opt, const bool testing) {/*---------------------------------------------------------------------------- Get or set the Hardware Clock epoch value in the kernel, as appropriate. <getepoch>, <setepoch>, and <epoch> are hwclock invocation options. <epoch> == -1 if the user did not specify an "epoch" option.-----------------------------------------------------------------------------*/ /* Maintenance note: This should work on non-Alpha machines, but the evidence today (98.03.04) indicates that the kernel only keeps the epoch value on Alphas. If that is ever fixed, this function should be changed. */#ifndef __alpha__ fprintf(stderr, _("The kernel keeps an epoch value for the Hardware Clock " "only on an Alpha machine.\nThis copy of hwclock was built for " "a machine other than Alpha\n(and thus is presumably not running " "on an Alpha now). No action taken.\n"));#else if (getepoch) { unsigned long epoch; if (get_epoch_rtc(&epoch, 0)) fprintf(stderr, _("Unable to get the epoch value from the kernel.\n")); else printf(_("Kernel is assuming an epoch value of %lu\n"), epoch); } else if (setepoch) { if (epoch_opt == -1) fprintf(stderr, _("To set the epoch value, you must use the 'epoch' " "option to tell to what value to set it.\n")); else if (testing) printf(_("Not setting the epoch to %d - testing only.\n"), epoch_opt); else if (set_epoch_rtc(epoch_opt)) printf(_("Unable to set the epoch value in the kernel.\n")); }#endif}#if __ia64__#define RTC_DEV "/dev/efirtc"#else#define RTC_DEV "/dev/rtc"#endifstatic voidout_version(void) { printf(_("%s from %s\n"), MYNAME, util_linux_version);}/* usage - Output (error and) usage information This function is called both directly from main to show usage information and as fatal function from shhopt if some argument is not understood. In case of normal usage info FMT should be NULL. In that case the info is printed to stdout. If FMT is given usage will act like fprintf( stderr, fmt, ... ), show a usage information and terminate the program afterwards.*/static void usage( const char *fmt, ... ) { FILE *usageto; va_list ap; usageto = fmt ? stderr : stdout; fprintf( usageto, _( "hwclock - query and set the hardware clock (RTC)\n\n" "Usage: hwclock [function] [options...]\n\n" "Functions:\n" " --help show this help\n" " --show read hardware clock and print result\n" " --set set the rtc to the time given with --date\n" " --hctosys set the system time from the hardware clock\n" " --systohc set the hardware clock to the current system time\n" " --adjust adjust the rtc to account for systematic drift since \n" " the clock was last set or adjusted\n" " --getepoch print out the kernel's hardware clock epoch value\n" " --setepoch set the kernel's hardware clock epoch value to the \n" " value given with --epoch\n" " --version print out the version of hwclock to stdout\n" "\nOptions: \n" " --utc the hardware clock is kept in coordinated universal time\n" " --localtime the hardware clock is kept in local time\n" " --directisa access the ISA bus directly instead of %s\n" " --badyear ignore rtc's year because the bios is broken\n" " --date specifies the time to which to set the hardware clock\n" " --epoch=year specifies the year which is the beginning of the \n" " hardware clock's epoch value\n" " --noadjfile do not access /etc/adjtime. Requires the use of\n" " either --utc or --localtime\n" ),RTC_DEV);#ifdef __alpha__ fprintf(usageto, _( " --jensen, --arc, --srm, --funky-toy\n" " tell hwclock the type of alpha you have (see hwclock(8))\n" ) );#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -