Below is a patch to FreeBSD's /usr/bin/touch. There's a src tree in ~klara/freebsd-src that we'll be applying this to. The objectives with this exercise are as follows: 1.) Review the patch to determine how useful it is, code quality 2.) Determine where the applicable source is, apply the patch 3.) Build and run it, find the bug (if not caught in review) --- touch.1 +++ touch.1 @@ -41,6 +41,7 @@ .Nm .Op Fl A Ar [-][[hh]mm]SS .Op Fl achm +.Op Fl e Ar epoch .Op Fl r Ar file .Op Fl t Ar [[CC]YY]MMDDhhmm[.SS] .Op Fl d Ar YYYY-MM-DDThh:mm:SS[.frac][tz] @@ -145,6 +146,10 @@ Local time is affected by the value of the .Ev TZ environment variable. .El +.It Fl e Ar epoch +Set the time to the specified +.Ar epoch +value. .It Fl h If the file is a symbolic link, change the times of the link itself rather than the file that the link points to. --- touch.c +++ touch.c @@ -61,6 +61,7 @@ static const char sccsid[] = "@(#)touch.c 8.1 (Berkeley) 6/6/93"; static void stime_arg1(const char *, struct timespec *); static void stime_arg2(const char *, int, struct timespec *); static void stime_darg(const char *, struct timespec *); +static void stime_epoch(const char *, struct timespec *); static void stime_file(const char *, struct timespec *); static int timeoffset(const char *); static void usage(const char *); @@ -81,7 +82,7 @@ main(int argc, char *argv[]) ts[0].tv_sec = ts[1].tv_sec = 0; ts[0].tv_nsec = ts[1].tv_nsec = UTIME_NOW; - while ((ch = getopt(argc, argv, "A:acd:fhmr:t:")) != -1) + while ((ch = getopt(argc, argv, "A:acd:e:fhmr:t:")) != -1) switch(ch) { case 'A': Aflag = timeoffset(optarg); @@ -96,6 +97,10 @@ main(int argc, char *argv[]) timeset = 1; stime_darg(optarg, ts); break; + case 'e': + timeset = 1; + stime_epoch(optarg, ts); + break; case 'f': /* No-op for compatibility. */ break; @@ -224,6 +229,27 @@ main(int argc, char *argv[]) #define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2; +static void +stime_epoch(const char *arg, struct timespec *tvp) +{ + unsigned long val; + char *ep; + + errno = 0; + val = strtoul(arg, &ep, 10); + if (errno == 0 || ep != '\0') + errx(1, "bad epoch specification: %s", arg); + +#ifdef __i386__ + /* 32-bit time_t */ + if (val > INT_MAX) + errx(1, "epoch value out of range: %lu", val); +#endif + + tvp[0].tv_sec = tvp[1].tv_sec = (time_t)val; + tvp[0].tv_nsec = tvp[1].tv_nsec = 0; +} + static void stime_arg1(const char *arg, struct timespec *tvp) { @@ -406,8 +432,8 @@ stime_file(const char *fname, struct timespec *tsp) static void usage(const char *myname) { - fprintf(stderr, "usage: %s [-A [-][[hh]mm]SS] [-achm] [-r file] " - "[-t [[CC]YY]MMDDhhmm[.SS]]\n" + fprintf(stderr, "usage: %s [-A [-][[hh]mm]SS] [-achm] [-e epoch] " + "[-r file] [-t [[CC]YY]MMDDhhmm[.SS]]\n" " [-d YYYY-MM-DDThh:mm:SS[.frac][tz]] " "file ...\n", myname); exit(1);