164aae2b41f10704acad3bfb8e37e1a5b8a4c2155Rob Landley/* touch.c : change timestamp of a file
2ea52189f6d88673c7d380d4808f8f78063ad5042Rob Landley *
3f6261b3a80a29da78d8b6976ceeb71dcb30f3745Rob Landley * Copyright 2012 Choubey Ji <warior.linux@gmail.com>
4ea52189f6d88673c7d380d4808f8f78063ad5042Rob Landley *
5f033f8607f156464747abe57487c1f6226f94001Rob Landley * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/touch.html
6f033f8607f156464747abe57487c1f6226f94001Rob Landley *
7f033f8607f156464747abe57487c1f6226f94001Rob Landley * TODO: have another go at merging the -t and -d stanzas
8ea52189f6d88673c7d380d4808f8f78063ad5042Rob Landley
99628107532c705b69a211e0f595815a33d390724Rob LandleyUSE_TOUCH(NEWTOY(touch, "acd:mr:t:h[!dtr]", TOYFLAG_BIN))
10ea52189f6d88673c7d380d4808f8f78063ad5042Rob Landley
11ea52189f6d88673c7d380d4808f8f78063ad5042Rob Landleyconfig TOUCH
12471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley  bool "touch"
13ea52189f6d88673c7d380d4808f8f78063ad5042Rob Landley  default y
14ea52189f6d88673c7d380d4808f8f78063ad5042Rob Landley  help
159628107532c705b69a211e0f595815a33d390724Rob Landley    usage: touch [-amch] [-d DATE] [-t TIME] [-r FILE] FILE...
16471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley
17ea52189f6d88673c7d380d4808f8f78063ad5042Rob Landley    Update the access and modification times of each FILE to the current time.
18471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley
19471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley    -a	change access time
20471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley    -m	change modification time
21471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley    -c	don't create file
229628107532c705b69a211e0f595815a33d390724Rob Landley    -h	change symlink
2364aae2b41f10704acad3bfb8e37e1a5b8a4c2155Rob Landley    -d	set time to DATE (in YYYY-MM-DDThh:mm:SS[.frac][tz] format)
249628107532c705b69a211e0f595815a33d390724Rob Landley    -t	set time to TIME (in [[CC]YY]MMDDhhmm[.ss][frac] format)
2564aae2b41f10704acad3bfb8e37e1a5b8a4c2155Rob Landley    -r	set time same as reference FILE
26ea52189f6d88673c7d380d4808f8f78063ad5042Rob Landley*/
27ea52189f6d88673c7d380d4808f8f78063ad5042Rob Landley
28bbda4efd9d7cda269d71ae99054e1ad2590d1b02Rob Landley#define FOR_touch
29ea52189f6d88673c7d380d4808f8f78063ad5042Rob Landley#include "toys.h"
30ea52189f6d88673c7d380d4808f8f78063ad5042Rob Landley
31bbda4efd9d7cda269d71ae99054e1ad2590d1b02Rob LandleyGLOBALS(
32471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley  char *time;
33bbda4efd9d7cda269d71ae99054e1ad2590d1b02Rob Landley  char *file;
34471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley  char *date;
35bbda4efd9d7cda269d71ae99054e1ad2590d1b02Rob Landley)
36f6261b3a80a29da78d8b6976ceeb71dcb30f3745Rob Landley
37471ce1b29933702bdd63bf27e4470898cb37b451Rob Landleyvoid touch_main(void)
38471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley{
399628107532c705b69a211e0f595815a33d390724Rob Landley  struct timespec ts[2];
401b7e562a286b528a440e56b48a4afe3823b2d86bRob Landley  char **ss;
419628107532c705b69a211e0f595815a33d390724Rob Landley  int fd, i;
42471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley
439628107532c705b69a211e0f595815a33d390724Rob Landley  // use current time if no -t or -d
449628107532c705b69a211e0f595815a33d390724Rob Landley  ts[0].tv_nsec = UTIME_NOW;
4564aae2b41f10704acad3bfb8e37e1a5b8a4c2155Rob Landley  if (toys.optflags & (FLAG_t|FLAG_d)) {
461b7e562a286b528a440e56b48a4afe3823b2d86bRob Landley    char *s, *date;
471b7e562a286b528a440e56b48a4afe3823b2d86bRob Landley    struct tm tm;
489628107532c705b69a211e0f595815a33d390724Rob Landley    int len = 0;
491b7e562a286b528a440e56b48a4afe3823b2d86bRob Landley
509628107532c705b69a211e0f595815a33d390724Rob Landley    localtime_r(&(ts->tv_sec), &tm);
511b7e562a286b528a440e56b48a4afe3823b2d86bRob Landley
521b7e562a286b528a440e56b48a4afe3823b2d86bRob Landley    // Set time from -d?
531b7e562a286b528a440e56b48a4afe3823b2d86bRob Landley
54471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley    if (toys.optflags & FLAG_d) {
55471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley      date = TT.date;
5664aae2b41f10704acad3bfb8e37e1a5b8a4c2155Rob Landley      i = strlen(date);
571b7e562a286b528a440e56b48a4afe3823b2d86bRob Landley      if (i) {
5876678fa5730dfced54c95696e77fdbc6c9c9e839Rob Landley        // Trailing Z means UTC timezone, don't expect libc to know this.
5976678fa5730dfced54c95696e77fdbc6c9c9e839Rob Landley        if (toupper(date[i-1])=='Z') {
6076678fa5730dfced54c95696e77fdbc6c9c9e839Rob Landley          date[i-1] = 0;
6176678fa5730dfced54c95696e77fdbc6c9c9e839Rob Landley          setenv("TZ", "UTC0", 1);
629628107532c705b69a211e0f595815a33d390724Rob Landley          localtime_r(&(ts->tv_sec), &tm);
6376678fa5730dfced54c95696e77fdbc6c9c9e839Rob Landley        }
6464aae2b41f10704acad3bfb8e37e1a5b8a4c2155Rob Landley        s = strptime(date, "%Y-%m-%dT%T", &tm);
65671146c3b41460ec3ad25f64f1269be0f3924b27Rob Landley        ts->tv_nsec = 0;
669628107532c705b69a211e0f595815a33d390724Rob Landley        if (s && *s=='.' && isdigit(s[1]))
679628107532c705b69a211e0f595815a33d390724Rob Landley          sscanf(s, ".%lu%n", &ts->tv_nsec, &len);
689628107532c705b69a211e0f595815a33d390724Rob Landley        else len = 0;
6964aae2b41f10704acad3bfb8e37e1a5b8a4c2155Rob Landley      } else s = 0;
7064aae2b41f10704acad3bfb8e37e1a5b8a4c2155Rob Landley
7164aae2b41f10704acad3bfb8e37e1a5b8a4c2155Rob Landley    // Set time from -t?
7264aae2b41f10704acad3bfb8e37e1a5b8a4c2155Rob Landley
73471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley    } else {
74471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley      strcpy(toybuf, "%Y%m%d%H%M");
75471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley      date = TT.time;
76a2fd3cedb28394bea7c84e4c785a61df8ccc92a9Rob Landley      i = ((s = strchr(date, '.'))) ? s-date : strlen(date);
77a2fd3cedb28394bea7c84e4c785a61df8ccc92a9Rob Landley      if (i < 8 || i%2) error_exit("bad '%s'", date);
78471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley      for (i=0;i<3;i++) {
79471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley        s = strptime(date, toybuf+(i&2), &tm);
80471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley        if (s) break;
81471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley        toybuf[1]='y';
82471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley      }
83671146c3b41460ec3ad25f64f1269be0f3924b27Rob Landley      ts->tv_nsec = 0;
849628107532c705b69a211e0f595815a33d390724Rob Landley      if (s && *s=='.' && sscanf(s, ".%2u%n", &(tm.tm_sec), &len) == 1) {
859628107532c705b69a211e0f595815a33d390724Rob Landley        sscanf(s += len, "%lu%n", &ts->tv_nsec, &len);
869628107532c705b69a211e0f595815a33d390724Rob Landley        len++;
879628107532c705b69a211e0f595815a33d390724Rob Landley      } else len = 0;
889628107532c705b69a211e0f595815a33d390724Rob Landley    }
899628107532c705b69a211e0f595815a33d390724Rob Landley    if (len) {
909628107532c705b69a211e0f595815a33d390724Rob Landley      s += len;
919628107532c705b69a211e0f595815a33d390724Rob Landley      if (ts->tv_nsec > 999999999) s = 0;
929628107532c705b69a211e0f595815a33d390724Rob Landley      else while (len++ < 10) ts->tv_nsec *= 10;
93f6261b3a80a29da78d8b6976ceeb71dcb30f3745Rob Landley    }
94471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley
95471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley    errno = 0;
969628107532c705b69a211e0f595815a33d390724Rob Landley    ts->tv_sec = mktime(&tm);
971b7e562a286b528a440e56b48a4afe3823b2d86bRob Landley    if (!s || *s || errno == EOVERFLOW) perror_exit("bad '%s'", date);
98f6261b3a80a29da78d8b6976ceeb71dcb30f3745Rob Landley  }
999628107532c705b69a211e0f595815a33d390724Rob Landley  ts[1]=ts[0];
100471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley
10164aae2b41f10704acad3bfb8e37e1a5b8a4c2155Rob Landley  // Set time from -r?
10264aae2b41f10704acad3bfb8e37e1a5b8a4c2155Rob Landley
1039628107532c705b69a211e0f595815a33d390724Rob Landley  if (TT.file) {
1049628107532c705b69a211e0f595815a33d390724Rob Landley    struct stat st;
105471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley
1069628107532c705b69a211e0f595815a33d390724Rob Landley    xstat(TT.file, &st);
1079628107532c705b69a211e0f595815a33d390724Rob Landley    ts[0] = st.st_atim;
1089628107532c705b69a211e0f595815a33d390724Rob Landley    ts[1] = st.st_mtim;
1099628107532c705b69a211e0f595815a33d390724Rob Landley  }
11064aae2b41f10704acad3bfb8e37e1a5b8a4c2155Rob Landley
1119628107532c705b69a211e0f595815a33d390724Rob Landley  // Which time(s) should we actually change?
1129628107532c705b69a211e0f595815a33d390724Rob Landley  i = toys.optflags & (FLAG_a|FLAG_m);
1139628107532c705b69a211e0f595815a33d390724Rob Landley  if (i && i!=(FLAG_a|FLAG_m)) ts[i==FLAG_m].tv_nsec = UTIME_OMIT;
114471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley
11564aae2b41f10704acad3bfb8e37e1a5b8a4c2155Rob Landley  // Loop through files on command line
1169628107532c705b69a211e0f595815a33d390724Rob Landley  for (ss = toys.optargs; *ss;) {
1179628107532c705b69a211e0f595815a33d390724Rob Landley
1189628107532c705b69a211e0f595815a33d390724Rob Landley    // cheat: FLAG_h is rightmost flag, so its value is 1
1199628107532c705b69a211e0f595815a33d390724Rob Landley    if (!utimensat(AT_FDCWD, *ss, ts,
1209628107532c705b69a211e0f595815a33d390724Rob Landley        (toys.optflags & FLAG_h)*AT_SYMLINK_NOFOLLOW)) ss++;
121471ce1b29933702bdd63bf27e4470898cb37b451Rob Landley    else if (toys.optflags & FLAG_c) ss++;
1229628107532c705b69a211e0f595815a33d390724Rob Landley    else if (access(*ss, F_OK) && (-1!=(fd = open(*ss, O_CREAT, 0666))))
1239628107532c705b69a211e0f595815a33d390724Rob Landley      close(fd);
124662a267c9b52f256b027d0f176a846b1d973ab99Rob Landley    else perror_msg("'%s'", *ss++);
125f6261b3a80a29da78d8b6976ceeb71dcb30f3745Rob Landley  }
126f6261b3a80a29da78d8b6976ceeb71dcb30f3745Rob Landley}
127