/* * setdate * program to set the system date * * compile: cc -O -o setdate setdate.c * * requires: superuser privileges to reset date * * arguments: * -d yymmdd set the date to mm/dd/yy; be aware the month is * 0-11, not 1-12 (that is, January is 0 and December, * 11) * -q do NOT print the new date and time when done * hhmmss new hours and minutes to set the clock to; hh = hour * (on the 14-hour clock); mm = minutes, ss = seconds. * the seconds may be omitted. * * Versions: * * for ECS 235A class * 10/24/2021 * * Authors: * bishop: Matt Bishop * Department of Computer Science * University of California at Davis * Davis, CA 95616-8562 * phone: (530) 752-8060 * email: bishop@cs.ucdavis.edu */ #include #include #include #include #include #include /* * macros */ #define todigit(x) ((x)-'0') /* convert char digit to an integer */ #define MAXLEN 16 /* max length for internal buffer */ /* * useful external variables (for getopt(3)) */ extern int optind; /* index of next argument to be processed */ extern char *optarg; /* any option to an argument */ /* * globals defined for this program's use */ char *progname = "setdate"; /* name of the program */ struct tm tim; /* the current time, broken into parts */ /* * usage * purpose: print a correct usage message and exit * arguments: none * returns: never * exceptions: none * side effects: TERMINATES PROGRAM */ void usage(void) { fprintf(stderr, "Usage: %s [ -d yymmdd ] hhmm[ss]\n", progname); exit(EXIT_FAILURE); } /* * error * purpose: print an error message and exit * arguments: char *msg -- error message * if NULL, use system error message * returns: never * exceptions: none * side effects: TERMINATES PROGRAM */ void error(char *msg) { if (msg == NULL) perror(progname); else{ fprintf(stderr, progname); fprintf(stderr, msg); } exit(EXIT_FAILURE); } /* * dateset * purpose: parse char string to get desired date and reset date * arguments: char *p -- points to string with desired date * returns: 0 if string is not a valid date * 1 if string is a valid date * exceptions: none * side effects: resets month, date, year fields in global structure tim */ int dateset(char *p) { int i; /* counter in for loop */ int yr; /* desired year, as extracted from date string */ int mon; /* desired month, as extracted from date string */ int day; /* desired day, as extracted from date string */ /* * be sure it's 6 digits * error return if not! */ for(i = 0; i < 6;i++) if (!isdigit(p[i])) return(0); /* * first 2 are year, next 2 month, next 2 date * convert them to integers */ yr = todigit(p[0]) * 10 + todigit(p[1]); mon = todigit(p[2]) * 10 + todigit(p[3]); day = todigit(p[4]) * 10 + todigit(p[5]); /* * now stuff them into the global time structure */ tim.tm_mday = day; tim.tm_mon = mon; tim.tm_year = yr; /* yippee! we did it! */ return(1); } /* * timeset * purpose: parse char string to get desired time and reset time * arguments: char *p -- points to string with desired time * returns: 0 if string is not a valid time * 1 if string is a valid time * exceptions: none * side effects: resets hour, minute, seconds fields in global * structure tim */ int timeset(char *p) { int i; /* counter in for loop */ int hr; /* desired hour, as extracted from time string */ int min; /* desired minute, as extracted from time string */ int sec; /* desired second, as extracted from time string */ /* * be sure it's at least 4 digits * error return if not! */ for(i = 0; i < 4;i++) if (!isdigit(p[i])) return(0); /* * first 2 are hour, next 2 minute * convert them to integers */ hr = todigit(p[0]) * 10 + todigit(p[1]); min = todigit(p[2]) * 10 + todigit(p[3]); /* * now check for seconds * if, and only if, next 2 are digits, they are seconds * if so, convert them to integers * if not, prime the value so it won't change later */ if (isdigit(p[4]) && isdigit(p[5])) sec = todigit(p[4]) * 10 + todigit(p[5]); else sec = tim.tm_sec; /* * now stuff them into the global time structure */ tim.tm_hour = hr; tim.tm_min = min; tim.tm_sec = sec; /* once again, the flawless UNIX system comes through! */ return(1); } /* * main * purpose: to reset the date * arguments: int argc -- argument count * char *argv[] -- argument list * returns: EXIT_FAILURE on failure * EXIT_SUCCESS on success * exceptions: none * side effects: resets date, time on success * prints error message on failure */ int main(int argc, char *argv[]) { char buf[MAXLEN]; /* temp buffer for arguments */ int quiet = 0; /* default is to announce the new date */ int c; /* current option */ time_t t; /* seconds since the epoch */ struct timeval tp; /* time structure for getting, resetting time */ /* * set program name and check usage */ progname = argv[0]; if (argc == 1) usage(); /* * get the current time of day */ if (gettimeofday(&tp, NULL) < 0) error(NULL); /* * convert it to a more useful time structure */ tim = *localtime((time_t *) &(tp.tv_sec)); /* * now reset those fields you need to */ while((c = getopt(argc, argv, "d:q")) != EOF) switch(c){ case 'd': /* next arg is a date yymmdd */ /* buffer the argument */ (void) strcpy(buf, optarg); /* change the date according to this argument */ if (!dateset(buf)) error("invalid date format"); break; case 'q': /* don't announce the changed date */ quiet = 1; break; default: /* everything else is an error */ usage(); exit(EXIT_FAILURE); } /* * now reset the time */ if (argc == optind + 1){ /* buffer it */ (void) strcpy(buf, argv[argc-1]); /* change the time according to this argument */ if (!timeset(buf)) error("invalid time format"); } else usage(); /* * now to convert it to seconds * since the epoch */ tp.tv_sec = t = mktime(&tim); /* * set the time of day */ if (settimeofday(&tp, NULL) < 0) error(NULL); /* * announce it unless asked not to */ if (!quiet) printf("Date set to %s", ctime(&t)); /* * Say goodnight, Dick! */ exit(EXIT_SUCCESS); }