touch.c - sbase - suckless unix tools
(HTM) git clone git://git.suckless.org/sbase
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
touch.c (2796B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include <sys/stat.h>
3
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <time.h>
9 #include <unistd.h>
10
11 #include "util.h"
12
13 static int aflag;
14 static int cflag;
15 static int mflag;
16 static struct timespec times[2] = {{.tv_nsec = UTIME_NOW}};
17
18 static void
19 touch(const char *file)
20 {
21 int fd, ret;
22
23 if (utimensat(AT_FDCWD, file, times, 0) == 0)
24 return;
25 if (errno != ENOENT)
26 eprintf("utimensat %s:", file);
27 if (cflag)
28 return;
29 if ((fd = open(file, O_WRONLY | O_CREAT | O_EXCL, 0666)) < 0)
30 eprintf("open %s:", file);
31 ret = futimens(fd, times);
32 close(fd);
33 if (ret < 0)
34 eprintf("futimens %s:", file);
35 }
36
37 static time_t
38 parsetime(char *str)
39 {
40 time_t now;
41 struct tm *cur, t = { 0 };
42 int zulu = 0;
43 char *format;
44 size_t len = strlen(str);
45
46 if ((now = time(NULL)) == -1)
47 eprintf("time:");
48 if (!(cur = localtime(&now)))
49 eprintf("localtime:");
50 t.tm_isdst = -1;
51
52 switch (len) {
53 /* -t flag argument */
54 case 8:
55 t.tm_year = cur->tm_year;
56 format = "%m%d%H%M";
57 break;
58 case 10:
59 format = "%y%m%d%H%M";
60 break;
61 case 11:
62 t.tm_year = cur->tm_year;
63 format = "%m%d%H%M.%S";
64 break;
65 case 12:
66 format = "%Y%m%d%H%M";
67 break;
68 case 13:
69 format = "%y%m%d%H%M.%S";
70 break;
71 case 15:
72 format = "%Y%m%d%H%M.%S";
73 break;
74 /* -d flag argument */
75 case 19:
76 format = "%Y-%m-%dT%H:%M:%S";
77 break;
78 case 20:
79 /* only Zulu-timezone supported */
80 if (str[19] != 'Z')
81 eprintf("Invalid time zone\n");
82 str[19] = 0;
83 zulu = 1;
84 format = "%Y-%m-%dT%H:%M:%S";
85 break;
86 default:
87 eprintf("Invalid date format length\n", str);
88 }
89
90 if (!strptime(str, format, &t))
91 eprintf("strptime %s: Invalid date format\n", str);
92 if (zulu) {
93 t.tm_hour += t.tm_gmtoff / 60;
94 t.tm_gmtoff = 0;
95 t.tm_zone = "Z";
96 }
97
98 return mktime(&t);
99 }
100
101 static void
102 usage(void)
103 {
104 eprintf("usage: %s [-acm] [-d time | -r ref_file | -t time | -T time] "
105 "file ...\n", argv0);
106 }
107
108 int
109 main(int argc, char *argv[])
110 {
111 struct stat st;
112 char *ref = NULL;
113
114 ARGBEGIN {
115 case 'a':
116 aflag = 1;
117 break;
118 case 'c':
119 cflag = 1;
120 break;
121 case 'd':
122 case 't':
123 times[0].tv_sec = parsetime(EARGF(usage()));
124 times[0].tv_nsec = 0;
125 break;
126 case 'm':
127 mflag = 1;
128 break;
129 case 'r':
130 ref = EARGF(usage());
131 if (stat(ref, &st) < 0)
132 eprintf("stat '%s':", ref);
133 times[0] = st.st_atim;
134 times[1] = st.st_mtim;
135 break;
136 case 'T':
137 times[0].tv_sec = estrtonum(EARGF(usage()), 0, LLONG_MAX);
138 times[0].tv_nsec = 0;
139 break;
140 default:
141 usage();
142 } ARGEND
143
144 if (!argc)
145 usage();
146 if (!aflag && !mflag)
147 aflag = mflag = 1;
148 if (!ref)
149 times[1] = times[0];
150 if (!aflag)
151 times[0].tv_nsec = UTIME_OMIT;
152 if (!mflag)
153 times[1].tv_nsec = UTIME_OMIT;
154
155 for (; *argv; argc--, argv++)
156 touch(*argv);
157
158 return 0;
159 }