This is timeshift.c in view mode; [Download] [Up]
/* timeshift ** This program is linked to 3 different names. ** timeshift ** halt ** reboot ** When executed via the names halt or reboot, the clock is set to ** what it would be if the local time zone was GMT. After munging ** the clock, the real halt or reboot executable is then exec'ed. ** ** When executed via the name timeshift, the clock is shifted back ** to the normal time within the local time zone. ** ** In order to prevent shifting the clock an odd number of times ** and to prevent screwing up when shutdown and boot span a DST ** cusp, the amount of clock shift is stored in a lock file ** /usr/etc/shifted.time. ** ** This software is provided as shareware. ** If you find this software useful, please send me $10 ** ** email feedback to jq@quick.com ** For current snail address refer to address returned from internic ** via 'whois quick.com' ** ** $Header: /usr/users/jq/c/util/timeshift/RCS/timeshift.c,v 1.1 95/12/03 16:26:57 jq Exp $ */ #include <sys/param.h> #include <syslog.h> #include <libc.h> #include <sys/types.h> #include <sys/time.h> #include <sys/errno.h> #include <sys/file.h> #define TIME_LOCK "/usr/etc/shifted.time" extern int errno; enum shift_mode { UP = -1, NOCHANGE = 0, DOWN = 1 }; /* Return the basename of a pathname */ char * basename(char *path) { char *base = rindex(path, '/'); if (base) { base++; } else { base = path; } return base; } /* Shift the clock by the amount required to go from local time in time zone ** to local time in GMT when shutting down the computer. Reverse the ** process on the way back up. ** N.B. The reason for saving the time shift to a file and using it on the ** way back up, is to prevent dropping or gaining an hour if the system ** is brought down under daylight savings time and then brought up in ** standard time, or vice versa. */ void shift_time(enum shift_mode mode) { struct timeval tp; struct timezone tzone; long shift = 0; int err; FILE *stamp = 0; /* Let someone know why we did nothing. */ if (mode == NOCHANGE) { syslog(LOG_ALERT, "sync option prevented time change."); return; } /* Make sure that we do not set clock multiple timed in DOWN mode. */ if (mode == DOWN && access(TIME_LOCK, F_OK) == 0) { syslog(LOG_ALERT, "%s already exists. No change made.", TIME_LOCK); return; } /* Open the TIME_LOCK file in read mode on the way up and in ** write mode on the way down. */ stamp = fopen(TIME_LOCK, (mode == UP)?"r":"w"); if (stamp == 0) { syslog(LOG_ALERT, "Cannot fopen %s - %s", TIME_LOCK, strerror(errno)); return; } /* On the way down, set shift amount and save it in TIME_LOCK. ** On the way up, read the previous shift amount to undo it. */ if (mode == DOWN) { time_t clock = 0; struct tm *now; time(&clock); now = localtime(&clock); fprintf(stamp, "%ld\n", now->tm_gmtoff); shift = mode * (now->tm_gmtoff); } else if (mode == UP) { fscanf(stamp, "%ld", &shift); shift *= mode; } fclose(stamp); /* Now, get the current time, adjust for shift, and reset time. ** Note that we are not accounting for the amount of time it ** will take to set the clock or performe the addition. ** Though we could probably perform the operation and get a ** rough guess of how many microseconds to fudge, I don't think ** it's worth the effort. */ gettimeofday(&tp, &tzone); tp.tv_sec += shift; err = settimeofday(&tp, &tzone); if (err == -1) { /* If we failed to change the clock on the way down, ** then unlink the TIME_LOCK so that we don't make ** things worse on the way up. */ if (mode == DOWN) { unlink(TIME_LOCK); } } else { /* If we did set the clock, get rid of our old stamp file ** since we've undone the change it represents. */ if (mode == UP) { unlink(TIME_LOCK); } syslog(LOG_ALERT, "Clock adjusted by %d seconds\n", shift); } } /* Important safety checks! ** If 'reboot -n' or 'halt -n' are used it would be *extremely* uncool ** to do anything with the file system. Since a sync is not performed ** you can end up allocating a block which will remain linked to a ** directory entry, but actually be still on the free list. Ouch! ** ** I do not know if 'reboot -q' suffers the same problems but I'm ** erring on false positive here and bailing on any command which ** has either 'n' or 'q' as any part of a hyphenated argument. */ enum shift_mode safety_check(int argc, char **argv) { char *arg; int i; for (i = 0; i < argc; i++) { arg = argv[i]; if (*arg == '-' && (index(arg, 'n') || index(arg, 'q'))) { return NOCHANGE; /* whew */ } } return DOWN; } int main(int argc, char **argv) { char *base = basename(argv[0]); enum shift_mode mode = NOCHANGE; char realcmd[MAXPATHLEN + 1]; char *exec_cmd = 0; char ishmael[128]; /* What to call me. */ /* First determine whether we are coming down or booting up. */ if (strcmp(base,"timeshift") == 0) { mode = UP; strcpy(ishmael, base); } else if (strcmp(base, "halt") == 0 || strcmp(base, "reboot") == 0) { char *prefix = "/usr/etc/"; mode = safety_check(argc, argv); sprintf(ishmael, "%s (%s)", "timeshift", base); if (index(argv[0], '/') != 0) { prefix = ""; } sprintf(realcmd, "%s%s.real", prefix, argv[0]); exec_cmd = realcmd; } else { syslog(LOG_ALERT, "%s: is not named reboot halt or shiftup\n", argv[0]); exit(1); } openlog(ishmael, LOG_CONS, LOG_DAEMON); /* Next make sure we are root. ** It's kind of gilding the lily a bit, but better safe than sorry. */ if (geteuid() != 0) { syslog(LOG_ALERT, "%s: not run as root.\n", argv[0]); exit(1); } /* Cover our asses in case we should just not do anything. */ shift_time(mode); /* If we were called instead of the real halt or reboot ** we now need to exec the real mcCoy. */ if (exec_cmd) { execvp(exec_cmd, argv); syslog(LOG_ALERT, "Fatal error! Could't exec '%s'", realcmd); } return 0; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.