diff options
Diffstat (limited to 'util/sbase/touch.c')
-rw-r--r-- | util/sbase/touch.c | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/util/sbase/touch.c b/util/sbase/touch.c new file mode 100644 index 00000000..6e63bf80 --- /dev/null +++ b/util/sbase/touch.c @@ -0,0 +1,159 @@ +/* See LICENSE file for copyright and license details. */ +#include <sys/stat.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#include "util.h" + +static int aflag; +static int cflag; +static int mflag; +static struct timespec times[2] = {{.tv_nsec = UTIME_NOW}}; + +static void +touch(const char *file) +{ + int fd, ret; + + if (utimensat(AT_FDCWD, file, times, 0) == 0) + return; + if (errno != ENOENT) + eprintf("utimensat %s:", file); + if (cflag) + return; + if ((fd = open(file, O_WRONLY | O_CREAT | O_EXCL, 0666)) < 0) + eprintf("open %s:", file); + ret = futimens(fd, times); + close(fd); + if (ret < 0) + eprintf("futimens %s:", file); +} + +static time_t +parsetime(char *str) +{ + time_t now; + struct tm *cur, t = { 0 }; + int zulu = 0; + char *format; + size_t len = strlen(str); + + if ((now = time(NULL)) == -1) + eprintf("time:"); + if (!(cur = localtime(&now))) + eprintf("localtime:"); + t.tm_isdst = -1; + + switch (len) { + /* -t flag argument */ + case 8: + t.tm_year = cur->tm_year; + format = "%m%d%H%M"; + break; + case 10: + format = "%y%m%d%H%M"; + break; + case 11: + t.tm_year = cur->tm_year; + format = "%m%d%H%M.%S"; + break; + case 12: + format = "%Y%m%d%H%M"; + break; + case 13: + format = "%y%m%d%H%M.%S"; + break; + case 15: + format = "%Y%m%d%H%M.%S"; + break; + /* -d flag argument */ + case 19: + format = "%Y-%m-%dT%H:%M:%S"; + break; + case 20: + /* only Zulu-timezone supported */ + if (str[19] != 'Z') + eprintf("Invalid time zone\n"); + str[19] = 0; + zulu = 1; + format = "%Y-%m-%dT%H:%M:%S"; + break; + default: + eprintf("Invalid date format length\n", str); + } + + if (!strptime(str, format, &t)) + eprintf("strptime %s: Invalid date format\n", str); + if (zulu) { + t.tm_hour += t.tm_gmtoff / 60; + t.tm_gmtoff = 0; + t.tm_zone = "Z"; + } + + return mktime(&t); +} + +static void +usage(void) +{ + eprintf("usage: %s [-acm] [-d time | -r ref_file | -t time | -T time] " + "file ...\n", argv0); +} + +int +main(int argc, char *argv[]) +{ + struct stat st; + char *ref = NULL; + + ARGBEGIN { + case 'a': + aflag = 1; + break; + case 'c': + cflag = 1; + break; + case 'd': + case 't': + times[0].tv_sec = parsetime(EARGF(usage())); + times[0].tv_nsec = 0; + break; + case 'm': + mflag = 1; + break; + case 'r': + ref = EARGF(usage()); + if (stat(ref, &st) < 0) + eprintf("stat '%s':", ref); + times[0] = st.st_atim; + times[1] = st.st_mtim; + break; + case 'T': + times[0].tv_sec = estrtonum(EARGF(usage()), 0, LLONG_MAX); + times[0].tv_nsec = 0; + break; + default: + usage(); + } ARGEND + + if (!argc) + usage(); + if (!aflag && !mflag) + aflag = mflag = 1; + if (!ref) + times[1] = times[0]; + if (!aflag) + times[0].tv_nsec = UTIME_OMIT; + if (!mflag) + times[1].tv_nsec = UTIME_OMIT; + + for (; *argv; argc--, argv++) + touch(*argv); + + return 0; +} |