diff options
author | Karel Zak | 2006-12-07 00:25:58 +0100 |
---|---|---|
committer | Karel Zak | 2006-12-07 00:25:58 +0100 |
commit | 63cccae4684f83d2a462bc8abf24e51d1bd6efb6 (patch) | |
tree | 433db3f0b44e0f46e4130141f4a59db9c3564557 /hwclock/hwclock.c | |
parent | Imported from util-linux-2.11r tarball. (diff) | |
download | kernel-qcow2-util-linux-63cccae4684f83d2a462bc8abf24e51d1bd6efb6.tar.gz kernel-qcow2-util-linux-63cccae4684f83d2a462bc8abf24e51d1bd6efb6.tar.xz kernel-qcow2-util-linux-63cccae4684f83d2a462bc8abf24e51d1bd6efb6.zip |
Imported from util-linux-2.11t tarball.
Diffstat (limited to 'hwclock/hwclock.c')
-rw-r--r-- | hwclock/hwclock.c | 718 |
1 files changed, 428 insertions, 290 deletions
diff --git a/hwclock/hwclock.c b/hwclock/hwclock.c index 20c548eb0..9cf46dda1 100644 --- a/hwclock/hwclock.c +++ b/hwclock/hwclock.c @@ -20,6 +20,7 @@ * * Fix for Award 2094 bug, Dave Coffin (dcoffin@shore.net) 11/12/98 * Change of local time handling, Stefan Ring <e9725446@stud3.tuwien.ac.at> + * Change of adjtime handling, James P. Rutledge <ao112@rgfn.epcc.edu>. * * Distributed under GPL */ @@ -78,13 +79,13 @@ #include <sys/time.h> #include <sys/stat.h> #include <stdarg.h> +#include <getopt.h> +#include <sysexits.h> -#include "shhopt.h" #include "clock.h" #include "nls.h" #define MYNAME "hwclock" -#define VERSION "2.4c" char *progname = MYNAME; @@ -108,14 +109,17 @@ struct adjtime { updated since read from the disk file). */ bool dirty; + /* line 1 */ - float drift_factor; + double drift_factor; time_t last_adj_time; - float not_adjusted; + double not_adjusted; + /* line 2 */ time_t last_calib_time; /* The most recent time that we set the clock from an external authority (as opposed to just doing a drift adjustment) */ + /* line 3 */ enum a_local_utc {LOCAL, UTC, UNKNOWN} local_utc; /* To which time zone, local or UTC, we most recently set the @@ -170,18 +174,18 @@ read_date_from_file (struct tm *tm) { write_date_to_file (tm); } -static float +static double time_diff(struct timeval subtrahend, struct timeval subtractor) { /*--------------------------------------------------------------------------- The difference in seconds between two times in "timeval" format. ----------------------------------------------------------------------------*/ - return( (subtrahend.tv_sec - subtractor.tv_sec) - + (subtrahend.tv_usec - subtractor.tv_usec) / 1E6 ); + return (subtrahend.tv_sec - subtractor.tv_sec) + + (subtrahend.tv_usec - subtractor.tv_usec) / 1E6; } static struct timeval -time_inc(struct timeval addend, float increment) { +time_inc(struct timeval addend, double increment) { /*---------------------------------------------------------------------------- The time, in "timeval" format, which is <increment> seconds after the time <addend>. Of course, <increment> may be negative. @@ -199,7 +203,7 @@ time_inc(struct timeval addend, float increment) { newtime.tv_usec -= 1E6; newtime.tv_sec += 1; } - return(newtime); + return newtime; } @@ -223,39 +227,41 @@ hw_clock_is_utc(const bool utc, const bool local_opt, -static void -read_adjtime(struct adjtime *adjtime_p, int *rc_p) { +static int +read_adjtime(struct adjtime *adjtime_p) { /*---------------------------------------------------------------------------- Read the adjustment parameters out of the /etc/adjtime file. Return them as the adjtime structure <*adjtime_p>. - If there is no /etc/adjtime file, return defaults. If values are missing from the file, return defaults for them. - return *rc_p = 0 if all OK, !=0 otherwise. + return value 0 if all OK, !=0 otherwise. -----------------------------------------------------------------------------*/ FILE *adjfile; int rc; /* local return code */ struct stat statbuf; /* We don't even use the contents of this. */ - rc = stat(ADJPATH, &statbuf); - if (rc < 0 && errno == ENOENT) { - /* He doesn't have a adjtime file, so we'll use defaults. */ - adjtime_p->drift_factor = 0; - adjtime_p->last_adj_time = 0; - adjtime_p->not_adjusted = 0; - adjtime_p->last_calib_time = 0; - adjtime_p->local_utc = UNKNOWN; + rc = stat(ADJPATH, &statbuf); + if (rc < 0 && errno == ENOENT) { + /* He doesn't have a adjtime file, so we'll use defaults. */ + adjtime_p->drift_factor = 0; + adjtime_p->last_adj_time = 0; + adjtime_p->not_adjusted = 0; + adjtime_p->last_calib_time = 0; + adjtime_p->local_utc = UNKNOWN; + + return 0; + } - *rc_p = 0; - } else { adjfile = fopen(ADJPATH, "r"); /* open file for reading */ if (adjfile == NULL) { outsyserr("cannot open file " ADJPATH); - *rc_p = 2; - } else { + return EX_OSFILE; + } + + { char line1[81]; /* String: first line of adjtime file */ char line2[81]; /* String: second line of adjtime file */ char line3[81]; /* String: third line of adjtime file */ @@ -277,7 +283,7 @@ read_adjtime(struct adjtime *adjtime_p, int *rc_p) { adjtime_p->last_calib_time = 0; timeval = 0; - sscanf(line1, "%f %ld %f", + sscanf(line1, "%lf %ld %lf", &adjtime_p->drift_factor, &timeval, &adjtime_p->not_adjusted); @@ -299,8 +305,6 @@ read_adjtime(struct adjtime *adjtime_p, int *rc_p) { fprintf(stderr, _("(Expected: `UTC' or `LOCAL' or nothing.)\n")); } } - - *rc_p = 0; } adjtime_p->dirty = FALSE; @@ -313,12 +317,13 @@ read_adjtime(struct adjtime *adjtime_p, int *rc_p) { (adjtime_p->local_utc == LOCAL) ? _("local") : (adjtime_p->local_utc == UTC) ? _("UTC") : _("unknown")); } - } + + return 0; } -static void -synchronize_to_clock_tick(int *retcode_p) { +static int +synchronize_to_clock_tick(void) { /*----------------------------------------------------------------------------- Wait until the falling edge of the Hardware Clock's update flag so that any time that is read from the clock immediately after we @@ -330,14 +335,17 @@ synchronize_to_clock_tick(int *retcode_p) { We wait (up to one second) either blocked waiting for an rtc device or in a CPU spin loop. The former is probably not very accurate. - Return *retcode_p == 0 if it worked, nonzero if it didn't. - + Return 0 if it worked, nonzero if it didn't. -----------------------------------------------------------------------------*/ - if (debug) printf(_("Waiting for clock tick...\n")); + int rc; - *retcode_p = ur->synchronize_to_clock_tick(); + if (debug) printf(_("Waiting for clock tick...\n")); - if (debug) printf(_("...got clock tick\n")); + rc = ur->synchronize_to_clock_tick(); + + if (debug) printf(_("...got clock tick\n")); + + return rc; } @@ -520,7 +528,7 @@ set_hardware_clock_exact(const time_t settime, static void display_time(const bool hclock_valid, const time_t systime, - const float sync_duration) { + const double sync_duration) { /*---------------------------------------------------------------------------- Put the time "systime" on standard output in display format. Except if hclock_valid == false, just tell standard output that we don't @@ -638,7 +646,7 @@ interpret_date_string(const char *date_opt, time_t * const time_p) { } fclose(date_child_fp); - return(retcode); + return retcode; } @@ -663,7 +671,7 @@ set_system_clock(const bool hclock_valid, const time_t newtime, int retcode; if (!hclock_valid) { - fprintf(stderr,_("The Hardware Clock does not contain a valid time, so " + fprintf(stderr, _("The Hardware Clock does not contain a valid time, so " "we cannot set the System Time from it.\n")); retcode = 1; } else { @@ -685,10 +693,10 @@ set_system_clock(const bool hclock_valid, const time_t newtime, #endif if (debug) { - printf( _("Calling settimeofday:\n") ); - printf( _("\ttv.tv_sec = %ld, tv.tv_usec = %ld\n"), - (long) tv.tv_sec, (long) tv.tv_usec ); - printf( _("\ttz.tz_minuteswest = %d\n"), minuteswest); + printf(_("Calling settimeofday:\n")); + printf(_("\ttv.tv_sec = %ld, tv.tv_usec = %ld\n"), + (long) tv.tv_sec, (long) tv.tv_usec); + printf(_("\ttz.tz_minuteswest = %d\n"), minuteswest); } if (testing) { printf(_("Not setting system clock because running in test mode.\n")); @@ -697,85 +705,130 @@ set_system_clock(const bool hclock_valid, const time_t newtime, const struct timezone tz = { minuteswest, 0 }; rc = settimeofday(&tv, &tz); - if (rc != 0) { - if (errno == EPERM) - fprintf(stderr, _("Must be superuser to set system clock.\n")); - else - outsyserr(_("settimeofday() failed")); - retcode = 1; + if (rc) { + if (errno == EPERM) { + fprintf(stderr, + _("Must be superuser to set system clock.\n")); + retcode = EX_NOPERM; + } else { + outsyserr(_("settimeofday() failed")); + retcode = 1; + } } else retcode = 0; } } - return(retcode); + return retcode; } static void adjust_drift_factor(struct adjtime *adjtime_p, const time_t nowtime, - const bool hclock_valid, const time_t hclocktime ) { -/*--------------------------------------------------------------------------- + const bool hclock_valid, + const time_t hclocktime, + const double sync_delay) { +/*------------------------------------------------------------------------ Update the drift factor in <*adjtime_p> to reflect the fact that the Hardware Clock was calibrated to <nowtime> and before that was set to <hclocktime>. - We assume that the user has been doing regular drift adjustments - using the drift factor in the adjtime file, so if <nowtime> and - <clocktime> are different, that means the adjustment factor isn't - quite right. - We record in the adjtime file the time at which we last calibrated the clock so we can compute the drift rate each time we calibrate. EXCEPT: if <hclock_valid> is false, assume Hardware Clock was not set before to anything meaningful and regular adjustments have not been done, so don't adjust the drift factor. - -----------------------------------------------------------------------------*/ - if (!hclock_valid) { - if (debug) - printf(_("Not adjusting drift factor because the Hardware Clock " - "previously contained garbage.\n")); - } else if ((hclocktime - adjtime_p->last_calib_time) < 23 * 60 * 60) { - if (debug) - printf(_("Not adjusting drift factor because it has been less than a " - "day since the last calibration.\n")); - } else if (adjtime_p->last_calib_time != 0) { - const float factor_adjust = - ((float) (nowtime - hclocktime) - / (hclocktime - adjtime_p->last_calib_time)) - * 24 * 60 * 60; - - if (debug) - printf(_("Clock drifted %d seconds in the past %d seconds " - "in spite of a drift factor of %f seconds/day.\n" - "Adjusting drift factor by %f seconds/day\n"), - (int) (nowtime - hclocktime), - (int) (hclocktime - adjtime_p->last_calib_time), - adjtime_p->drift_factor, - factor_adjust ); + ------------------------------------------------------------------------*/ + if (!hclock_valid) { + if (debug) + printf(_("Not adjusting drift factor because the " + "Hardware Clock previously contained " + "garbage.\n")); + } else if (adjtime_p->last_calib_time == 0) { + if (debug) + printf(_("Not adjusting drift factor because last " + "calibration time is zero,\n" + "so history is bad and calibration startover " + "is necessary.\n")); + } else if ((hclocktime - adjtime_p->last_calib_time) < 23 * 60 * 60) { + if (debug) + printf(_("Not adjusting drift factor because it has " + "been less than a day since the last " + "calibration.\n")); + } else if (adjtime_p->last_calib_time != 0) { + /* + * At adjustment time we adjust the hardware clock according + * to the contents of /etc/adjtime. + * + * At calibration time we set the hardware clock and + * update /etc/adjtime, that is, for each calibration + * (except the first) we also do an adjustment. + * + * We are now at calibration time. + * + * Let us do computation in doubles. (Floats almost suffice, + * but 195 days + 1 second equals 195 days in floats.) + */ + const double sec_per_day = 24.0 * 60.0 * 60.0; + double atime_per_htime; + double adj_days, cal_days; + double exp_drift, unc_drift; + double factor_adjust; + + /* Adjusted time units per hardware time unit */ + atime_per_htime = 1.0 + adjtime_p->drift_factor / sec_per_day; + + /* Days since last adjustment (in hardware clock time) */ + adj_days = (double)(hclocktime - adjtime_p->last_adj_time) + / sec_per_day; + + /* Expected drift (sec) since last adjustment */ + exp_drift = adj_days * adjtime_p->drift_factor + + adjtime_p->not_adjusted; + + /* Uncorrected drift (sec) since last calibration */ + unc_drift = (double)(nowtime - hclocktime) + + sync_delay - exp_drift; + + /* Days since last calibration (in hardware clock time) */ + cal_days = ((double)(adjtime_p->last_adj_time + - adjtime_p->last_calib_time) + + adjtime_p->not_adjusted) + / (sec_per_day * atime_per_htime) + adj_days; + + /* Amount to add to previous drift factor */ + factor_adjust = unc_drift / cal_days; + + if (debug) + printf(_("Clock drifted %.1f seconds in the past " + "%d seconds in spite of a drift factor of " + "%f seconds/day.\n" + "Adjusting drift factor by %f seconds/day\n"), + unc_drift, + (int) (nowtime - adjtime_p->last_calib_time), + adjtime_p->drift_factor, + factor_adjust); - adjtime_p->drift_factor += factor_adjust; - } - adjtime_p->last_calib_time = nowtime; + adjtime_p->drift_factor += factor_adjust; + } + adjtime_p->last_calib_time = nowtime; - adjtime_p->last_adj_time = nowtime; + adjtime_p->last_adj_time = nowtime; - adjtime_p->not_adjusted = 0; + adjtime_p->not_adjusted = 0; - adjtime_p->dirty = TRUE; + adjtime_p->dirty = TRUE; } static void -calculate_adjustment( - const float factor, +calculate_adjustment(const double factor, const time_t last_time, - const float not_adjusted, + const double not_adjusted, const time_t systime, int *adjustment_p, - float *retro_p, + double *retro_p, const int debug ) { /*---------------------------------------------------------------------------- Do the drift adjustment calculation. @@ -790,13 +843,13 @@ calculate_adjustment( advance the clock or insert seconds. Negative means to retard the clock or remove seconds. ----------------------------------------------------------------------------*/ - float exact_adjustment; + double exact_adjustment; - exact_adjustment = ((float) (systime - last_time)) * factor / (24 * 60 * 60) + exact_adjustment = ((double) (systime - last_time)) * factor / (24 * 60 * 60) + not_adjusted; *adjustment_p = FLOOR(exact_adjustment); - *retro_p = exact_adjustment - (float) *adjustment_p; + *retro_p = exact_adjustment - (double) *adjustment_p; if (debug) { printf (_("Time since last adjustment is %d seconds\n"), (int) (systime - last_time)); @@ -897,10 +950,18 @@ do_adjustment(struct adjtime *adjtime_p, 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 */ - float retro; + double retro; /* Fraction of second we have to remove from clock after inserting <adjustment> whole seconds. */ @@ -951,13 +1012,13 @@ determine_clock_access_method(const bool user_requests_ISA) { } } -static void +static int manipulate_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, int *retcode_p) { + const bool testing) { /*--------------------------------------------------------------------------- Do all the normal work of hwclock - read, set clock, etc. @@ -965,24 +1026,26 @@ manipulate_clock(const bool show, const bool adjust, const bool noadjfile, 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) *retcode_p = 1; - else { - if (!noadjfile && (adjust || set || systohc || (!utc && !local_opt))) - read_adjtime(&adjtime, &rc); - else { + 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; } - if (rc != 0) *retcode_p = 2; - else { + + { const bool universal = hw_clock_is_utc(utc, local_opt, adjtime); if ((set || systohc || adjust) && @@ -991,9 +1054,11 @@ manipulate_clock(const bool show, const bool adjust, const bool noadjfile, adjtime.dirty = TRUE; } - synchronize_to_clock_tick(retcode_p); - /* this takes up to 1 second */ - if (*retcode_p == 0) { + 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 */ @@ -1014,16 +1079,14 @@ manipulate_clock(const bool show, const bool adjust, const bool noadjfile, if (show) { display_time(hclock_valid, hclocktime, time_diff(read_time, startup_time)); - *retcode_p = 0; } else if (set) { set_hardware_clock_exact(set_time, startup_time, universal, testing); - adjust_drift_factor(&adjtime, set_time, hclock_valid, hclocktime); - *retcode_p = 0; + 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); - *retcode_p = 0; } else if (systohc) { struct timeval nowtime, reftime; /* We can only set_hardware_clock_exact to a whole seconds @@ -1036,22 +1099,20 @@ manipulate_clock(const bool show, const bool adjust, const bool noadjfile, set_hardware_clock_exact((time_t) reftime.tv_sec, reftime, universal, testing); - *retcode_p = 0; adjust_drift_factor(&adjtime, (time_t) reftime.tv_sec, hclock_valid, - hclocktime); + hclocktime, (double) read_time.tv_usec / 1E6); } else if (hctosys) { rc = set_system_clock(hclock_valid, hclocktime, testing); - if (rc != 0) { + if (rc) { printf(_("Unable to set system clock.\n")); - *retcode_p = 1; - } else *retcode_p = 0; + return rc; + } } - if (!noadjfile) { + if (!noadjfile) save_adjtime(adjtime, testing); - } } } - } + return 0; } @@ -1104,6 +1165,11 @@ manipulate_epoch(const bool getepoch, const bool setepoch, #define RTC_DEV "/dev/rtc" #endif +static void +out_version(void) { + printf(_("%s from %s\n"), MYNAME, util_linux_version); +} + /* usage - Output (error and) usage information @@ -1148,7 +1214,7 @@ usage( const char *fmt, ... ) { " either --utc or --localtime\n" ),RTC_DEV); #ifdef __alpha__ - fprintf( usageto, _( + fprintf(usageto, _( " --jensen, --arc, --srm, --funky-toy\n" " tell hwclock the type of alpha you have (see hwclock(8))\n" ) ); @@ -1156,200 +1222,272 @@ usage( const char *fmt, ... ) { fflush(stdout); - if( fmt ) { + if (fmt) { usageto = stderr; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } - exit( fmt ? 99 : 0 ); + 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 */ + 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 retcode; /* Our eventual return code */ + bool permitted; /* User is permitted to do the function */ + int rc, c; - int rc; /* local return code */ + /* 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; - /* option_def is the control table for the option parser. These other - variables are the results of parsing the options and their meanings - are given by the option_def. The only exception is <show>, which - may be modified after parsing is complete to effect an implied option. - */ - bool help, show, set, systohc, hctosys, adjust, getepoch, setepoch, version; - bool ARCconsole, utc, testing, directisa, Jensen, SRM, funky_toy, noadjfile; - bool local_opt; - char *date_opt; - - const optStruct option_def[] = { - { 'h', (char *) "help", OPT_FLAG, &help, 0 }, - { 'r', (char *) "show", OPT_FLAG, &show, 0 }, - { 0, (char *) "set", OPT_FLAG, &set, 0 }, - { 'w', (char *) "systohc", OPT_FLAG, &systohc, 0 }, - { 's', (char *) "hctosys", OPT_FLAG, &hctosys, 0 }, - { 0, (char *) "getepoch", OPT_FLAG, &getepoch, 0 }, - { 0, (char *) "setepoch", OPT_FLAG, &setepoch, 0 }, - { 'a', (char *) "adjust", OPT_FLAG, &adjust, 0 }, - { 0, (char *) "noadjfile", OPT_FLAG, &noadjfile, 0 }, - { 'v', (char *) "version", OPT_FLAG, &version, 0 }, - { 'V', (char *) "version", OPT_FLAG, &version, 0 }, - { 0, (char *) "date", OPT_STRING, &date_opt, 0 }, - { 0, (char *) "epoch", OPT_UINT, &epoch_option,0 }, - { 'u', (char *) "utc", OPT_FLAG, &utc, 0 }, - { 0, (char *) "localtime", OPT_FLAG, &local_opt, 0 }, - { 0, (char *) "badyear", OPT_FLAG, &badyear, 0 }, - { 0, (char *) "directisa", OPT_FLAG, &directisa, 0 }, - { 0, (char *) "test", OPT_FLAG, &testing, 0 }, - { 'D', (char *) "debug", OPT_FLAG, &debug, 0 }, -#ifdef __alpha__ - { 'A', (char *) "ARC", OPT_FLAG, &ARCconsole,0 }, - { 'A', (char *) "arc", OPT_FLAG, &ARCconsole,0 }, - { 'J', (char *) "Jensen", OPT_FLAG, &Jensen, 0 }, - { 'J', (char *) "jensen", OPT_FLAG, &Jensen, 0 }, - { 'S', (char *) "SRM", OPT_FLAG, &SRM, 0 }, - { 'S', (char *) "srm", OPT_FLAG, &SRM, 0 }, - { 'F', (char *) "funky-toy", OPT_FLAG, &funky_toy, 0 }, -#endif - { 0, (char *) NULL, OPT_END, NULL, 0 } - }; - int argc_parse; /* argc, except we modify it as we parse */ - char **argv_parse; /* argv, except we modify it as we parse */ + /* Remember what time we were invoked */ + gettimeofday(&startup_time, NULL); - gettimeofday(&startup_time, NULL); /* Remember what time we were invoked */ - - setlocale(LC_ALL, ""); + 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"); + /* 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 */ - help = show = set = systohc = hctosys = adjust = noadjfile = - getepoch = setepoch = version = utc = local_opt = - ARCconsole = SRM = funky_toy = directisa = badyear = Jensen = - testing = debug = FALSE; - date_opt = NULL; - - argc_parse = argc; argv_parse = argv; - optParseOptions(&argc_parse, argv_parse, option_def, 0); - /* Uses and sets argc_parse, argv_parse. - Sets show, systohc, hctosys, adjust, utc, local_opt, version, - testing, debug, set, date_opt, getepoch, setepoch, epoch_option, - noadjtime */ - /* This is an ugly routine - for example, if I give an incorrect - option, it only says "unrecognized option" without telling - me what options are recognized. Rewrite with standard - getopt() and usage() and throw shhopt out. */ - - if (argc_parse - 1 > 0) { - usage( _("%s takes no non-option arguments. " - "You supplied %d.\n"), - MYNAME, argc_parse - 1); - } + 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); + } + } - if (help) - usage( NULL ); + argc -= optind; + argv += optind; - if (show + set + systohc + hctosys + adjust + - getepoch + setepoch + version > 1) { - fprintf(stderr, _("You have specified multiple function options.\n" - "You can only perform one function at a time.\n")); - exit(100); - } + if (argc > 0) { + usage(_("%s takes no non-option arguments. " + "You supplied %d.\n"), + MYNAME, argc); + } - if (utc && local_opt) { - fprintf(stderr, _("%s: The --utc and --localtime options are mutually " - "exclusive. You specified both.\n"), MYNAME); - exit(100); - } + 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 (adjust && noadjfile) { - fprintf(stderr, _("%s: The --adjust and --noadjfile options are mutually " - "exclusive. You specified both.\n"), MYNAME); - exit(100); - } + if (utc && local_opt) { + fprintf(stderr, _("%s: The --utc and --localtime 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(100); - } + 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); + 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(100); - } - } + 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 | - version)) - show = 1; /* default to show */ + 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) -- be secure! */ - 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 (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) retcode = 2; - else { - retcode = 0; - if (version) { - printf(MYNAME " " VERSION "/%s\n",util_linux_version); - } else if (getepoch || setepoch) { - manipulate_epoch(getepoch, setepoch, epoch_option, testing); - } else { - if (debug) - printf(MYNAME " " VERSION "/%s\n",util_linux_version); - determine_clock_access_method(directisa); - if (!ur) { - fprintf(stderr, - _("Cannot access the Hardware Clock via any known method.\n")); - if (!debug) + 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, - _("Use the --debug option to see the details of our " - "search for an access method.\n")); - } else - manipulate_clock(show, adjust, noadjfile, set, set_time, - hctosys, systohc, startup_time, utc, local_opt, - testing, &rc); - } - } - exit(retcode); + _("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 */ |