📄 hwclock.c
字号:
fflush(stdout); if (fmt) { usageto = stderr; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } exit(fmt ? EX_USAGE : 0);}static const struct option longopts[] = { { "adjust", 0, 0, 'a' }, { "help", 0, 0, 'h' }, { "show", 0, 0, 'r' }, { "hctosys", 0, 0, 's' }, { "utc", 0, 0, 'u' }, { "version", 0, 0, 'v' }, { "systohc", 0, 0, 'w' }, { "debug", 0, 0, 'D' },#ifdef __alpha__ { "ARC", 0, 0, 'A' }, { "arc", 0, 0, 'A' }, { "Jensen", 0, 0, 'J' }, { "jensen", 0, 0, 'J' }, { "SRM", 0, 0, 'S' }, { "srm", 0, 0, 'S' }, { "funky-toy", 0, 0, 'F'},#endif { "set", 0, 0, 128 }, { "getepoch", 0, 0, 129 }, { "setepoch", 0, 0, 130 }, { "noadjfile", 0, 0, 131 }, { "localtime", 0, 0, 132 }, { "badyear", 0, 0, 133 }, { "directisa", 0, 0, 134 }, { "test", 0, 0, 135 }, { "date", 1, 0, 136 }, { "epoch", 1, 0, 137 }, { NULL, 0, 0, 0 }};/* * Returns: * EX_USAGE: bad invocation * EX_NOPERM: no permission * EX_OSFILE: cannot open /dev/rtc or /etc/adjtime * EX_IOERR: ioctl error getting or setting the time * 0: OK (or not) * 1: failure */int main(int argc, char **argv) { struct timeval startup_time; /* The time we started up, in seconds into the epoch, including fractions. */ time_t set_time; /* Time to which user said to set Hardware Clock */ bool permitted; /* User is permitted to do the function */ int rc, c; /* Variables set by various options; show may also be set later */ /* The options debug, badyear and epoch_option are global */ bool show, set, systohc, hctosys, adjust, getepoch, setepoch; bool utc, testing, local_opt, noadjfile, directisa; bool ARCconsole, Jensen, SRM, funky_toy; char *date_opt; /* Remember what time we were invoked */ gettimeofday(&startup_time, NULL); setlocale(LC_ALL, "");#ifdef LC_NUMERIC /* We need LC_CTYPE and LC_TIME and LC_MESSAGES, but must avoid LC_NUMERIC since it gives problems when we write to /etc/adjtime. - gqueri@mail.dotcom.fr */ setlocale(LC_NUMERIC, "C");#endif bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); /* Set option defaults */ show = set = systohc = hctosys = adjust = noadjfile = FALSE; getepoch = setepoch = utc = local_opt = testing = debug = FALSE; ARCconsole = Jensen = SRM = funky_toy = directisa = badyear = FALSE; date_opt = NULL; while ((c = getopt_long (argc, argv, "?hvVDarsuwAJSF", longopts, NULL)) != -1) { switch (c) { case 'D': debug = TRUE; break; case 'a': adjust = TRUE; break; case 'r': show = TRUE; break; case 's': hctosys = TRUE; break; case 'u': utc = TRUE; break; case 'w': systohc = TRUE; break;#ifdef __alpha__ case 'A': ARCconsole = TRUE; break; case 'J': Jensen = TRUE; break; case 'S': SRM = TRUE; break; case 'F': funky_toy = TRUE; break;#endif case 128: set = TRUE; break; case 129: getepoch = TRUE; break; case 130: setepoch = TRUE; break; case 131: noadjfile = TRUE; break; case 132: local_opt = TRUE; /* --localtime */ break; case 133: badyear = TRUE; break; case 134: directisa = TRUE; break; case 135: testing = TRUE; /* --test */ break; case 136: date_opt = optarg; /* --date */ break; case 137: epoch_option = atoi(optarg); /* --epoch */ break; case 'v': /* --version */ case 'V': out_version(); return 0; case 'h': /* --help */ case '?': default: usage(NULL); } } argc -= optind; argv += optind; if (argc > 0) { usage(_("%s takes no non-option arguments. " "You supplied %d.\n"), MYNAME, argc); } if (show + set + systohc + hctosys + adjust + getepoch + setepoch > 1){ fprintf(stderr, _("You have specified multiple functions.\n" "You can only perform one function " "at a time.\n")); exit(EX_USAGE); } if (utc && local_opt) { fprintf(stderr, _("%s: The --utc and --localtime options " "are mutually exclusive. You specified " "both.\n"), MYNAME); exit(EX_USAGE); } if (adjust && noadjfile) { fprintf(stderr, _("%s: The --adjust and --noadjfile options " "are mutually exclusive. You specified " "both.\n"), MYNAME); exit(EX_USAGE); } if (noadjfile && !(utc || local_opt)) { fprintf(stderr, _("%s: With --noadjfile, you must specify " "either --utc or --localtime\n"), MYNAME); exit(EX_USAGE); }#ifdef __alpha__ set_cmos_epoch(ARCconsole, SRM); set_cmos_access(Jensen, funky_toy);#endif if (set) { rc = interpret_date_string(date_opt, &set_time); /* (time-consuming) */ if (rc != 0) { fprintf(stderr, _("No usable set-to time. " "Cannot set clock.\n")); exit(EX_USAGE); } } if (!(show | set | systohc | hctosys | adjust | getepoch | setepoch)) show = 1; /* default to show */ if (getuid() == 0) permitted = TRUE; else { /* program is designed to run setuid (in some situations) */ if (set || hctosys || systohc || adjust) { fprintf(stderr, _("Sorry, only the superuser can change " "the Hardware Clock.\n")); permitted = FALSE; } else if (hctosys) { fprintf(stderr, _("Sorry, only the superuser can change " "the System Clock.\n")); permitted = FALSE; } else if (setepoch) { fprintf(stderr, _("Sorry, only the superuser can change the " "Hardware Clock epoch in the kernel.\n")); permitted = FALSE; } else permitted = TRUE; } if (!permitted) exit(EX_NOPERM); if (getepoch || setepoch) { manipulate_epoch(getepoch, setepoch, epoch_option, testing); return 0; } if (debug) out_version(); determine_clock_access_method(directisa); if (!ur) { fprintf(stderr, _("Cannot access the Hardware Clock via " "any known method.\n")); if (!debug) fprintf(stderr, _("Use the --debug option to see the details " "of our search for an access method.\n")); exit(1); } return manipulate_clock(show, adjust, noadjfile, set, set_time, hctosys, systohc, startup_time, utc, local_opt, testing);}/* A single routine for greater uniformity */voidoutsyserr(char *msg, ...) { va_list args; int errsv = errno; fprintf(stderr, "%s: ", progname); va_start(args, msg); vfprintf(stderr, msg, args); va_end(args); fprintf(stderr, ", errno=%d: %s.\n", errsv, strerror(errsv));}/**************************************************************************** History of this program: 98.08.12 BJH Version 2.4 Don't use century byte from Hardware Clock. Add comments telling why. 98.06.20 BJH Version 2.3. Make --hctosys set the kernel timezone from TZ environment variable and/or /usr/lib/zoneinfo. From Klaus Ripke (klaus@ripke.com). 98.03.05 BJH. Version 2.2. Add --getepoch and --setepoch. Fix some word length things so it works on Alpha. Make it work when /dev/rtc doesn't have the interrupt functions. In this case, busywait for the top of a second instead of blocking and waiting for the update complete interrupt. Fix a bunch of bugs too numerous to mention. 97.06.01: BJH. Version 2.1. Read and write the century byte (Byte 50) of the ISA Hardware Clock when using direct ISA I/O. Problem discovered by job (jei@iclnl.icl.nl). Use the rtc clock access method in preference to the KDGHWCLK method. Problem discovered by Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>. November 1996: Version 2.0.1. Modifications by Nicolai Langfeldt (janl@math.uio.no) to make it compile on linux 1.2 machines as well as more recent versions of the kernel. Introduced the NO_CLOCK access method and wrote feature test code to detect absense of rtc headers.************************************************************************** Maintenance notes To compile this, you must use GNU compiler optimization (-O option) in order to make the "extern inline" functions from asm/io.h (inb(), etc.) compile. If you don't optimize, which means the compiler will generate no inline functions, the references to these functions in this program will be compiled as external references. Since you probably won't be linking with any functions by these names, you will have unresolved external references when you link. The program is designed to run setuid superuser, since we need to be able to do direct I/O. (More to the point: we need permission to execute the iopl() system call). (However, if you use one of the methods other than direct ISA I/O to access the clock, no setuid is required). Here's some info on how we must deal with the time that elapses while this program runs: There are two major delays as we run: 1) Waiting up to 1 second for a transition of the Hardware Clock so we are synchronized to the Hardware Clock. 2) Running the "date" program to interpret the value of our --date option. Reading the /etc/adjtime file is the next biggest source of delay and uncertainty. The user wants to know what time it was at the moment he invoked us, not some arbitrary time later. And in setting the clock, he is giving us the time at the moment we are invoked, so if we set the clock some time later, we have to add some time to that. So we check the system time as soon as we start up, then run "date" and do file I/O if necessary, then wait to synchronize with a Hardware Clock edge, then check the system time again to see how much time we spent. We immediately read the clock then and (if appropriate) report that time, and additionally, the delay we measured. If we're setting the clock to a time given by the user, we wait some more so that the total delay is an integral number of seconds, then set the Hardware Clock to the time the user requested plus that integral number of seconds. N.B. The Hardware Clock can only be set in integral seconds. If we're setting the clock to the system clock value, we wait for the system clock to reach the top of a second, and then set the Hardware Clock to the system clock's value. Here's an interesting point about setting the Hardware Clock: On my machine, when you set it, it sets to that precise time. But one can imagine another clock whose update oscillator marches on a steady one second period, so updating the clock between any two oscillator ticks is the same as updating it right at the earlier tick. To avoid any complications that might cause, we set the clock as soon as possible after an oscillator tick. About synchronizing to the Hardware Clock when reading the time: The precision of the Hardware Clock counters themselves is one second. You can't read the counters and find out that is 12:01:02.5. But if you consider the location in time of the counter's ticks as part of its value, then its precision is as infinite as time is continuous! What I'm saying is this: To find out the _exact_ time in the hardware clock, we wait until the next clock tick (the next time the second counter changes) and measure how long we had to wait. We then read the value of the clock counters and subtract the wait time and we know precisely what time it was when we set out to query the time. hwclock uses this method, and considers the Hardware Clock to have infinite precision. Enhancements needed: - When waiting for whole second boundary in set_hardware_clock_exact, fail if we miss the goal by more than .1 second, as could happen if we get pre-empted (by the kernel dispatcher).****************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -