1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1989-2011 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <glenn.s.fowler@gmail.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22 * Glenn Fowler
23 * AT&T Research
24 *
25 * touch -- touch file times
26 */
27
28 static const char usage[] =
29 "[-?\n@(#)$Id: touch (AT&T Research) 2004-12-12 $\n]"
30 USAGE_LICENSE
31 "[+NAME?touch - change file access, modification and status change "
32 "times]"
33 "[+DESCRIPTION?\btouch\b changes the modification time, access time or "
34 "both of each \afile\a. The modification time is the \ast_mtime\a member "
35 "of the \bstat\b(2) information and the access time is the \ast_atime\a "
36 "member. On most systems the file status change time is always set to "
37 "the current time when either the access or modification times are "
38 "changed.]"
39 "[+?If neither the \b--reference\b nor the \b--time\b options are "
40 "specified then the time used will be the \adate\a operand or the "
41 "current time if \adate\a is omitted.]"
42 "[+?If the \adate\a operand consists of 4, 6, 8, 10 or 12 digits "
43 "followed by an optional \b.\b and two digits then it is interpreted as: "
44 "\aHHMM.SS\a, \addHHMM.SS\a, \ammddHHMM.SS\a, \ammddHHMMyy.SS\a or "
45 "\ayymmddHHMM.SS\a, or \ammddHHMMccyy.SS\a or \accyymmddHHMM.SS\a. "
46 "Conflicting standards and practice allow a leading or trailing 2 or 4 "
47 "digit year for the 10 and 12 digit forms; the X/Open leading form is "
48 "used to disambiguate (\bdate\b(1) uses the trailing form.) Avoid the 10 "
49 "digit form to avoid confusion. The digit fields are:]"
50 "{"
51 "[+cc?Century - 1, 19-20.]"
52 "[+yy?Year in century, 00-99.]"
53 "[+mm?Month, 01-12.]"
54 "[+dd?Day of month, 01-31.]"
55 "[+HH?Hour, 00-23.]"
56 "[+MM?Minute, 00-59.]"
57 "[+SS?Seconds, 00-60.]"
58 "}"
59 "[a:access|atime|use?Change the access time. Do not change the "
60 "modification time unless \b--modify\b is also specified.]"
61 "[c!:create?Create the \afile\a if it does not exist, but write no "
62 "diagnostic.]"
63 "[f:force?Ignored by this implementation.]"
64 "[m:modify|mtime|modification?Change the modify time. Do not change the "
65 "access time unless \b--access\b is also specified.]"
66 "[r:reference?Use the corresponding time of \afile\a instead of the "
67 "current time.]:[file]"
68 "[s|n:change|ctime|neither?Change only the file status change time "
69 "\ast_ctime\a. Most systems summarily set \ast_ctime\a to the current "
70 "time.]"
71 "[t|d:time|date?Use the specified \adate-time\a instead of the current "
72 "date-time. Most common formats are accepted. See \btmdate\b(3) for "
73 "details. If \adate-time\a consists of 4, 6, 8, 10 or 12 digits followed "
74 "by an optional \b.\b and 2 digits and another optional \b.\b and 1 or "
75 "more digits then it is interpreted as the \adate\a operand above, "
76 "except that the leading 2 or 4 digit year form is used to disambiguate. "
77 "Avoid the 10 digit form to avoid confusion. If \b--reference\b is "
78 "specified or if \afile\a already exists then \atime\a may also be one "
79 "of:]:[date-time]"
80 "{"
81 "[+access|atime|use?The access time of the reference file.]"
82 "[+change|ctime?The change time of the reference file.]"
83 "[+modify|mtime|modification?The modify time of the reference "
84 "file.]"
85 "}"
86 "[v:verbose?Write a diagnostic for each nonexistent \afile\a.]"
87 "\n\n"
88 "[ date ]"
89 "file ...\n\n"
90 "[+CAVEATS?Some systems or file system types may limit the range of "
91 "times that can be set. These limitations may not show up until a "
92 "subsequent \bstat\b(2) call (yes, the time can be set but not checked!) "
93 "Upper limits of <0xffffffff and <0x7fffffff have been observed.]"
94 "[+SEE ALSO?\bdate\b(1), \bnmake\b(1), \butime\b(2), \btm\b(3)]"
95 ;
96
97 #include <ast.h>
98 #include <ls.h>
99 #include <tmx.h>
100 #include <error.h>
101
102 #define ATIME 01
103 #define CTIME 02
104 #define MTIME 04
105
106 int
main(int argc,register char ** argv)107 main(int argc, register char** argv)
108 {
109 register char* reference = 0;
110 int create = 1;
111 int set = 0;
112 int use = 0;
113 int verbose = 0;
114
115 register char* file;
116 char* e;
117 int n;
118 struct stat st;
119 Time_t t;
120 Tv_t* ap;
121 Tv_t* cp;
122 Tv_t* mp;
123 Tv_t* up;
124 Tv_t av;
125 Tv_t cv;
126 Tv_t mv;
127 Tv_t uv;
128
129 NoP(argc);
130 error_info.id = "touch";
131 up = 0;
132 for (;;)
133 {
134 switch (optget(argv, usage))
135 {
136 case 'a':
137 set |= ATIME;
138 continue;
139 case 'c':
140 create = 0;
141 continue;
142 case 'd':
143 case 't':
144 if (streq(opt_info.arg, "access") || streq(opt_info.arg, "atime") || streq(opt_info.arg, "use"))
145 use = ATIME;
146 else if (streq(opt_info.arg, "change") || streq(opt_info.arg, "ctime"))
147 use = CTIME;
148 else if (streq(opt_info.arg, "modify") || streq(opt_info.arg, "mtime") || streq(opt_info.arg, "modification"))
149 use = MTIME;
150 else
151 {
152 reference = 0;
153 t = tmxdate(opt_info.arg, &e, TMX_NOW);
154 if (*e)
155 error(3, "%s: invalid date specification", e);
156 up = &uv;
157 tmx2tv(t, up);
158 }
159 continue;
160 case 'f':
161 continue;
162 case 'm':
163 set |= MTIME;
164 continue;
165 case 'r':
166 reference = opt_info.arg;
167 continue;
168 case 's':
169 set |= CTIME;
170 continue;
171 case 'v':
172 verbose = 1;
173 continue;
174 case ':':
175 error(2, "%s", opt_info.arg);
176 break;
177 case '?':
178 error(ERROR_USAGE|4, "%s", opt_info.arg);
179 break;
180 }
181 break;
182 }
183 argv += opt_info.index;
184 if (error_info.errors || !*argv)
185 error(ERROR_USAGE|4, "%s", optusage(NiL));
186 if (reference)
187 {
188 if (stat(reference, &st))
189 error(ERROR_SYSTEM|3, "%s: not found", reference);
190 if (use)
191 {
192 up = &uv;
193 switch (use)
194 {
195 case ATIME:
196 tvgetatime(up, &st);
197 break;
198 case CTIME:
199 tvgetctime(up, &st);
200 break;
201 case MTIME:
202 tvgetmtime(up, &st);
203 break;
204 }
205 }
206 }
207 else if (!use && !up)
208 {
209 for (file = *argv; *file >= '0' && *file <= '9'; file++);
210 if (((n = (file - *argv)) == 4 || n == 6 || n == 8 || n == 10 || n == 12) && (!*file || *file == '.' && *(file + 1) >= '0' && *(file + 1) <= '9' && *(file + 2) >= '0' && *(file + 2) <= '9' && !*(file + 3)))
211 {
212 t = tmxdate(file = *argv++, &e, TMX_NOW);
213 if (*e)
214 error(3, "%s: invalid date specification", file);
215 up = &uv;
216 tmx2tv(t, up);
217 }
218 }
219 if (!set)
220 set = MTIME;
221 if (set & ATIME)
222 {
223 if (use || !reference)
224 ap = up;
225 else
226 {
227 ap = &av;
228 tvgetatime(ap, &st);
229 }
230 }
231 else
232 ap = TV_TOUCH_RETAIN;
233 if (set & CTIME)
234 {
235 if (use || !reference)
236 cp = up;
237 else
238 {
239 cp = &cv;
240 tvgetctime(cp, &st);
241 }
242 }
243 else
244 cp = TV_TOUCH_RETAIN;
245 if (set & MTIME)
246 {
247 if (use || !reference)
248 mp = up;
249 else
250 {
251 mp = &mv;
252 tvgetmtime(mp, &st);
253 }
254 }
255 else
256 mp = TV_TOUCH_RETAIN;
257 if (reference)
258 use = 0;
259 else if (use)
260 up = &uv;
261 while (file = *argv++)
262 {
263 if (use)
264 {
265 if (stat(file, &st))
266 {
267 error(2, "%s: not found", file);
268 continue;
269 }
270 switch (use)
271 {
272 case ATIME:
273 tvgetatime(up, &st);
274 break;
275 case CTIME:
276 tvgetctime(up, &st);
277 break;
278 case MTIME:
279 tvgetmtime(up, &st);
280 break;
281 }
282 if (set & ATIME)
283 ap = up;
284 if (set & CTIME)
285 cp = up;
286 if (set & MTIME)
287 mp = up;
288 }
289 if (tvtouch(file, ap, mp, cp, create))
290 if (errno != ENOENT)
291 error(ERROR_SYSTEM|2, "%s: cannot touch", file);
292 else if (verbose)
293 error(1, "%s: not found", file);
294 }
295 return error_info.errors != 0;
296 }
297