From 3481910d32826e5363e3f6a39a031d3750b58420 Mon Sep 17 00:00:00 2001 From: Greg Lehey Date: Mon, 9 Apr 2007 02:19:37 +0000 Subject: [PATCH] Add -A flag to adjust existing time stamps. Print name by which program was started in usage() message. MFC after: 2 weeks --- usr.bin/touch/touch.1 | 91 ++++++++++++++++++++++++++++++++++++------- usr.bin/touch/touch.c | 62 ++++++++++++++++++++++++----- 2 files changed, 130 insertions(+), 23 deletions(-) diff --git a/usr.bin/touch/touch.1 b/usr.bin/touch/touch.1 index 8c7ab8b3b9f5..623190576e7f 100644 --- a/usr.bin/touch/touch.1 +++ b/usr.bin/touch/touch.1 @@ -43,6 +43,7 @@ .Nd change file access and modification times .Sh SYNOPSIS .Nm +.Op Fl A Ar [-][[hh]mm]SS .Op Fl acfhm .Op Fl r Ar file .Op Fl t Ar [[CC]YY]MMDDhhmm[.SS] @@ -50,17 +51,79 @@ .Sh DESCRIPTION The .Nm -utility sets the modification and access times of files to the -current time of day. -If the file does not exist, it is created with default permissions. +utility sets the modification and access times of files. +If any file does not exist, it is created with default permissions. +.Pp +By default, +.Nm +changes both modification and access times. The +.Fl a +and +.Fl m +flags may be used to select the access time or the modification time +individually. +Selecting both is equivalent to the default. +The base times for the modification are both set to the current time. +The +.Fl t +flag explicitly specifies a single time for both values, and the +.Fl r +flag specifies to set the times from those of a different file. +The +.Fl A +flag adjusts the values by a specified amount. +This adjustment is done after first establishing the base times. .Pp The following options are available: .Bl -tag -width Ds +.It Fl A +Adjust the access and modification time stamps for the file by the +specified value. +This flag is intended for use in modifying files with a time stamp +relative to an incorrect time zone. +It always modifies both the access time and the modification time. +.Pp +The argument is of the form +.Dq [-][[hh]mm]SS +where each pair of letters represents the following: +.Pp +.Bl -tag -width Ds -compact -offset indent +.It Ar - +Make the adjustment negative: the new time stamp is set to be before +the old one. +.It Ar hh +The hour of the day, from 00 to 23. +.It Ar mm +The minute of the hour, from 00 to 59. +.It Ar SS +The second of the minute, from 00 to 59. +.El +.Pp +When used in conjunction with the +.Fl a +flag only, the modification time is adjusted by the time specified as +argument to the +.Fl A +flag, while the access time is modified from the base time described +above. +Similarly, when used in conjunction with the +.Fl m +flag only, the access time is adjusted by the time specified as +argument to the +.Fl A +flag, while the access time is modified from the base time described +above. +.Pp +If the file does not exist, and creation is allowed, +.Fl A +does not change its time stamps. .It Fl a Change the access time of the file. -The modification time of the file is not changed unless the +The modification time of the file is not changed unless one of the +.Fl A +or .Fl m -flag is also specified. +flags is also specified. .It Fl c Do not create the file if it does not exist. The @@ -80,15 +143,17 @@ implies and thus will not create any new files. .It Fl m Change the modification time of the file. -The access time of the file is not changed unless the +The access time of the file is not changed unless one of the +.Fl A +or .Fl a -flag is also specified. +flags is also specified. .It Fl r Use the access and modifications times from the specified file instead of the current time of day. .It Fl t Change the access and modification times to the specified time. -The argument should be in the form +The argument is of the form .Dq [[CC]YY]MMDDhhmm[.SS] where each pair of letters represents the following: .Pp @@ -110,15 +175,15 @@ Otherwise, a .Dq CC value of 20 is used. .It Ar MM -The month of the year, from 1 to 12. +The month of the year, from 01 to 12. .It Ar DD -the day of the month, from 1 to 31. +the day of the month, from 01 to 31. .It Ar hh -The hour of the day, from 0 to 23. +The hour of the day, from 00 to 23. .It Ar mm -The minute of the hour, from 0 to 59. +The minute of the hour, from 00 to 59. .It Ar SS -The second of the minute, from 0 to 61. +The second of the minute, from 00 to 61. .El .Pp If the diff --git a/usr.bin/touch/touch.c b/usr.bin/touch/touch.c index 8853eca17cea..ef2c6affdb81 100644 --- a/usr.bin/touch/touch.c +++ b/usr.bin/touch/touch.c @@ -62,7 +62,8 @@ int rw(char *, struct stat *, int); void stime_arg1(char *, struct timeval *); void stime_arg2(char *, int, struct timeval *); void stime_file(char *, struct timeval *); -void usage(void); +int timeoffset(char *); +void usage(char *); int main(int argc, char *argv[]) @@ -71,17 +72,22 @@ main(int argc, char *argv[]) struct timeval tv[2]; int (*stat_f)(const char *, struct stat *); int (*utimes_f)(const char *, const struct timeval *); - int aflag, cflag, fflag, mflag, ch, fd, len, rval, timeset; + int Aflag, aflag, cflag, fflag, mflag, ch, fd, len, rval, timeset; char *p; + char *myname; - aflag = cflag = fflag = mflag = timeset = 0; + myname = argv[0]; + Aflag = aflag = cflag = fflag = mflag = timeset = 0; stat_f = stat; utimes_f = utimes; if (gettimeofday(&tv[0], NULL)) err(1, "gettimeofday"); - while ((ch = getopt(argc, argv, "acfhmr:t:")) != -1) + while ((ch = getopt(argc, argv, "A:acfhmr:t:")) != -1) switch(ch) { + case 'A': + Aflag = timeoffset(optarg); + break; case 'a': aflag = 1; break; @@ -109,13 +115,13 @@ main(int argc, char *argv[]) break; case '?': default: - usage(); + usage(myname); } argc -= optind; argv += optind; - /* Default is both -a and -m. */ - if (aflag == 0 && mflag == 0) + /* -a and -m are default unless one of them or -A is set. */ + if (aflag == 0 && mflag == 0 && Aflag == 0) aflag = mflag = 1; /* @@ -136,7 +142,7 @@ main(int argc, char *argv[]) tv[1] = tv[0]; if (*argv == NULL) - usage(); + usage(myname); for (rval = 0; *argv; ++argv) { /* See if the file exists. */ @@ -158,10 +164,15 @@ main(int argc, char *argv[]) continue; } + /* If -a or -m are not set, base time on current file time. */ if (!aflag) TIMESPEC_TO_TIMEVAL(&tv[0], &sb.st_atimespec); if (!mflag) TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec); + if (Aflag) { + tv[0].tv_sec += Aflag; + tv[1].tv_sec += Aflag; + } /* Try utimes(2). */ if (!utimes_f(*argv, tv)) @@ -286,6 +297,36 @@ stime_arg2(char *arg, int year, struct timeval *tvp) tvp[0].tv_usec = tvp[1].tv_usec = 0; } +/* Calculate a time offset in seconds, given an arg of the format [-]HHMMSS. */ +int +timeoffset(char *arg) +{ + int offset; + int isneg; + + offset = 0; + isneg = *arg == '-'; + if (isneg) + arg++; + switch (strlen(arg)) { + default: /* invalid */ + errx(1, "Invalid offset spec, must be [-][[HH]MM]SS"); + + case 6: /* HHMMSS */ + offset = ATOI2(arg); + /* FALLTHROUGH */ + case 4: /* MMSS */ + offset = offset * 60 + ATOI2(arg); + /* FALLTHROUGH */ + case 2: /* SS */ + offset = offset * 60 + ATOI2(arg); + } + if (isneg) + return (-offset); + else + return (offset); +} + void stime_file(char *fname, struct timeval *tvp) { @@ -347,8 +388,9 @@ err: rval = 1; } void -usage(void) +usage(char *myname) { - (void)fprintf(stderr, "usage: touch [-acfhm] [-r file] [-t [[CC]YY]MMDDhhmm[.SS]] file ...\n"); + fprintf(stderr, "usage:\n" "%s [-A [-][[hh]mm]SS] [-acfhm] [-r file] " + "[-t [[CC]YY]MMDDhhmm[.SS]] file ...\n", myname); exit(1); }