touch.c - sbase - suckless unix tools | |
git clone git://git.suckless.org/sbase | |
Log | |
Files | |
Refs | |
README | |
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 … | |
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 } |