1 /* $OpenBSD: touch.c,v 1.17 2007/08/06 19:16:06 sobrado Exp $ */
2 /* $NetBSD: touch.c,v 1.11 1995/08/31 22:10:06 jtc Exp $ */
6 * The Regents of the University of California. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include <sys/types.h>
50 void stime_arg1(char *, struct timeval
*);
51 void stime_arg2(char *, int, struct timeval
*);
52 void stime_file(char *, struct timeval
*);
53 __dead
void usage(void);
58 main(int argc
, char *argv
[])
62 struct utimbuf timbuf
;
63 int aflag
, cflag
, mflag
, ch
, fd
, len
, rval
, timeset
;
66 (void)setlocale(LC_ALL
, "");
69 aflag
= cflag
= mflag
= timeset
= 0;
70 if (gettimeofday(&tv
[0], NULL
))
71 err(1, "gettimeofday");
73 while ((ch
= getopt(argc
, argv
, "acfmr:t:")) != -1)
88 stime_file(optarg
, tv
);
92 stime_arg1(optarg
, tv
);
100 /* Default is both -a and -m. */
101 if (aflag
== 0 && mflag
== 0)
105 * If no -r or -t flag, at least two operands, the first of which
106 * is an 8 or 10 digit number, use the obsolete time specification.
108 if (!timeset
&& argc
> 1) {
109 (void)strtol(argv
[0], &p
, 10);
111 if (*p
== '\0' && (len
== 8 || len
== 10)) {
113 stime_arg2(*argv
++, len
== 10, tv
);
117 /* Otherwise use the current time of day. */
124 for (rval
= 0; *argv
; ++argv
) {
125 /* See if the file exists. */
126 if (stat(*argv
, &sb
)) {
128 /* Create the file. */
130 O_WRONLY
| O_CREAT
, DEFFILEMODE
);
131 if (fd
== -1 || fstat(fd
, &sb
) || close(fd
)) {
137 /* If using the current time, we're done. */
146 TIMESPEC_TO_TIMEVAL(&tv
[0], &sb
.st_atimespec
);
148 TIMESPEC_TO_TIMEVAL(&tv
[1], &sb
.st_mtimespec
);
151 tv
[0].tv_sec
= sb
.st_atime
;
153 tv
[1].tv_sec
= sb
.st_mtime
;
158 if (!utimes(*argv
, tv
))
161 timbuf
.actime
= tv
[0].tv_sec
;
162 timbuf
.modtime
= tv
[1].tv_sec
;
163 if (!utime(*argv
, &timbuf
))
167 /* If the user specified a time, nothing else we can do. */
174 * System V and POSIX 1003.1 require that a NULL argument
175 * set the access/modification times to the current time.
176 * The permission checks are different, too, in that the
177 * ability to write the file is sufficient. Take a shot.
180 if (!utimes(*argv
, NULL
))
183 if (!utime(*argv
, NULL
))
193 #define ATOI2(s) ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0'))
196 stime_arg1(char *arg
, struct timeval
*tvp
)
202 /* Start with the current time. */
203 tmptime
= tvp
[0].tv_sec
;
204 if ((lt
= localtime(&tmptime
)) == NULL
)
206 /* [[CC]YY]MMDDhhmm[.SS] */
207 for (p
= arg
, dot
= NULL
; *p
!= '\0'; p
++) {
208 if (*p
== '.' && dot
== NULL
)
210 else if (!isdigit((unsigned char)*p
))
214 lt
->tm_sec
= 0; /* Seconds defaults to 0. */
217 if (strlen(dot
) != 2)
219 lt
->tm_sec
= ATOI2(dot
);
220 if (lt
->tm_sec
> 61) /* Could be leap second. */
225 switch (strlen(arg
)) {
226 case 12: /* CCYYMMDDhhmm */
227 lt
->tm_year
= ATOI2(arg
) * 100 - TM_YEAR_BASE
;
230 case 10: /* YYMMDDhhmm */
232 yearset
= ATOI2(arg
);
233 lt
->tm_year
+= yearset
;
235 yearset
= ATOI2(arg
);
236 /* Preserve current century. */
237 lt
->tm_year
= ((lt
->tm_year
/ 100) * 100) + yearset
;
240 case 8: /* MMDDhhmm */
241 lt
->tm_mon
= ATOI2(arg
);
242 if (lt
->tm_mon
> 12 || lt
->tm_mon
== 0)
244 --lt
->tm_mon
; /* Convert from 01-12 to 00-11 */
245 lt
->tm_mday
= ATOI2(arg
);
246 if (lt
->tm_mday
> 31 || lt
->tm_mday
== 0)
248 lt
->tm_hour
= ATOI2(arg
);
249 if (lt
->tm_hour
> 23)
251 lt
->tm_min
= ATOI2(arg
);
259 lt
->tm_isdst
= -1; /* Figure out DST. */
260 tvp
[0].tv_sec
= tvp
[1].tv_sec
= mktime(lt
);
261 if (tvp
[0].tv_sec
== -1)
263 "out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]");
265 tvp
[0].tv_usec
= tvp
[1].tv_usec
= 0;
269 stime_arg2(char *arg
, int year
, struct timeval
*tvp
)
273 /* Start with the current time. */
274 tmptime
= tvp
[0].tv_sec
;
275 if ((lt
= localtime(&tmptime
)) == NULL
)
278 lt
->tm_mon
= ATOI2(arg
); /* MMDDhhmm[YY] */
279 if (lt
->tm_mon
> 12 || lt
->tm_mon
== 0)
281 --lt
->tm_mon
; /* Convert from 01-12 to 00-11 */
282 lt
->tm_mday
= ATOI2(arg
);
283 if (lt
->tm_mday
> 31 || lt
->tm_mday
== 0)
285 lt
->tm_hour
= ATOI2(arg
);
286 if (lt
->tm_hour
> 23)
288 lt
->tm_min
= ATOI2(arg
);
292 year
= ATOI2(arg
); /* Preserve current century. */
293 lt
->tm_year
= ((lt
->tm_year
/ 100) * 100) + year
;
297 lt
->tm_isdst
= -1; /* Figure out DST. */
298 tvp
[0].tv_sec
= tvp
[1].tv_sec
= mktime(lt
);
299 if (tvp
[0].tv_sec
== -1)
301 "out of range or illegal time specification: MMDDhhmm[YY]");
303 tvp
[0].tv_usec
= tvp
[1].tv_usec
= 0;
307 stime_file(char *fname
, struct timeval
*tvp
)
311 if (stat(fname
, &sb
))
314 TIMESPEC_TO_TIMEVAL(tvp
, &sb
.st_atimespec
);
315 TIMESPEC_TO_TIMEVAL(tvp
+ 1, &sb
.st_mtimespec
);
317 (tvp
+ 0)->tv_sec
= sb
.st_atime
;
318 (tvp
+ 1)->tv_sec
= sb
.st_mtime
;
325 extern char *__progname
;
327 (void)fprintf(stderr
,
328 "usage: %s [-acm] [-r file] [-t [[CC]YY]MMDDhhmm[.SS]] file ...\n",