1 /* touch -- change modification and access times of files
2 Copyright (C) 87, 1989-1991, 1995-2003 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* Written by Paul Rubin, Arnold Robbins, Jim Kingdon, David MacKenzie,
24 #include <sys/types.h>
33 #include "safe-read.h"
36 /* The official name of this program (e.g., no `g' prefix). */
37 #define PROGRAM_NAME "touch"
40 _("Written by Paul Rubin, Arnold Robbins, Jim Kingdon, David MacKenzie, and Randy Smith.")
46 /* Bitmasks for `change_times'. */
50 /* The name by which this program was run. */
53 /* Which timestamps to change. */
54 static int change_times;
56 /* (-c) If nonzero, don't create if not already there. */
59 /* (-d) If nonzero, date supplied on command line in get_date formats. */
60 static int flexible_date;
62 /* (-r) If nonzero, use times from a reference file. */
65 /* (-t) If nonzero, date supplied on command line in POSIX format. */
66 static int posix_date;
68 /* If nonzero, the only thing we have to do is change both the
69 modification and access time to the current time, so we don't
70 have to own the file, just be able to read and write it.
71 On some systems, we can do this if we own the file, even though
72 we have neither read nor write access to it. */
73 static int amtime_now;
75 /* New time to use when setting time. */
76 static struct timespec newtime;
78 /* File to use for -r. */
79 static char *ref_file;
81 /* Info about the reference file. */
82 static struct stat ref_stats;
84 /* For long options that have no equivalent short option, use a
85 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
88 TIME_OPTION = CHAR_MAX + 1
91 static struct option const longopts[] =
93 {"time", required_argument, 0, TIME_OPTION},
94 {"no-create", no_argument, 0, 'c'},
95 {"date", required_argument, 0, 'd'},
96 {"file", required_argument, 0, 'r'}, /* FIXME: phase out --file */
97 {"reference", required_argument, 0, 'r'},
98 {GETOPT_HELP_OPTION_DECL},
99 {GETOPT_VERSION_OPTION_DECL},
103 /* Valid arguments to the `--time' option. */
104 static char const* const time_args[] =
106 "atime", "access", "use", "mtime", "modify", 0
109 /* The bits in `change_times' that those arguments set. */
110 static int const time_masks[] =
112 CH_ATIME, CH_ATIME, CH_ATIME, CH_MTIME, CH_MTIME
115 /* Update the time of file FILE according to the options given.
116 Return 0 if successful, 1 if an error occurs. */
119 touch (const char *file)
128 /* Try to open FILE, creating it if necessary. */
129 fd = open (file, O_WRONLY | O_CREAT | O_NONBLOCK | O_NOCTTY,
130 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
132 /* Don't save a copy of errno if it's EISDIR, since that would lead
133 touch to give a bogus diagnostic for e.g., `touch /' (assuming
134 we don't own / or have write access to it). On Solaris 5.6,
135 and probably other systems, it is EINVAL. On SunOS4, it's EPERM. */
136 if (fd == -1 && errno != EISDIR && errno != EINVAL && errno != EPERM)
142 /* We're setting only one of the time values. stat the target to get
143 the other one. If we have the file descriptor already, use fstat.
144 Otherwise, either we're in no-create mode (and hence didn't call open)
145 or FILE is inaccessible or a directory, so we have to use stat. */
146 if (fd != -1 ? fstat (fd, &sbuf) : stat (file, &sbuf))
149 error (0, open_errno, _("creating %s"), quote (file));
152 if (no_create && errno == ENOENT)
154 error (0, errno, _("failed to get attributes of %s"),
163 if (fd != -1 && close (fd) < 0)
165 error (0, errno, _("creating %s"), quote (file));
171 /* Pass NULL to utime so it will not fail if we just have
172 write access to the file, but don't own it. */
173 status = utime (file, NULL);
177 struct timespec timespec[2];
179 /* There's currently no interface to set file timestamps with
180 better than 1-second resolution, so discard any fractional
181 part of the source timestamp. */
185 timespec[0].tv_sec = ref_stats.st_atime;
186 timespec[0].tv_nsec = TIMESPEC_NS (ref_stats.st_atim);
187 timespec[1].tv_sec = ref_stats.st_mtime;
188 timespec[1].tv_nsec = TIMESPEC_NS (ref_stats.st_mtim);
191 timespec[0] = timespec[1] = newtime;
193 if (!(change_times & CH_ATIME))
195 timespec[0].tv_sec = sbuf.st_atime;
196 timespec[0].tv_nsec = TIMESPEC_NS (sbuf.st_atim);
199 if (!(change_times & CH_MTIME))
201 timespec[1].tv_sec = sbuf.st_mtime;
202 timespec[1].tv_nsec = TIMESPEC_NS (sbuf.st_mtim);
205 status = utimens (file, timespec);
212 /* The wording of this diagnostic should cover at least two cases:
213 - the file does not exist, but the parent directory is unwritable
214 - the file exists, but it isn't writable
215 I think it's not worth trying to distinguish them. */
216 error (0, open_errno, _("cannot touch %s"), quote (file));
220 if (no_create && errno == ENOENT)
222 error (0, errno, _("setting times of %s"), quote (file));
234 fprintf (stderr, _("Try `%s --help' for more information.\n"),
238 printf (_("Usage: %s [OPTION]... FILE...\n"), program_name);
240 Update the access and modification times of each FILE to the current time.\n\
244 Mandatory arguments to long options are mandatory for short options too.\n\
247 -a change only the access time\n\
248 -c, --no-create do not create any files\n\
249 -d, --date=STRING parse STRING and use it instead of current time\n\
251 -m change only the modification time\n\
254 -r, --reference=FILE use this file's times instead of current time\n\
255 -t STAMP use [[CC]YY]MMDDhhmm[.ss] instead of current time\n\
256 --time=WORD set time given by WORD: access atime use (same as -a)\n\
257 modify mtime (same as -m)\n\
259 fputs (HELP_OPTION_DESCRIPTION, stdout);
260 fputs (VERSION_OPTION_DESCRIPTION, stdout);
263 Note that the -d and -t options accept different time-date formats.\n\
265 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
271 main (int argc, char **argv)
277 initialize_main (&argc, &argv);
278 program_name = argv[0];
279 setlocale (LC_ALL, "");
280 bindtextdomain (PACKAGE, LOCALEDIR);
281 textdomain (PACKAGE);
283 atexit (close_stdout);
285 change_times = no_create = use_ref = posix_date = flexible_date = 0;
287 while ((c = getopt_long (argc, argv, "acd:fmr:t:", longopts, NULL)) != -1)
295 change_times |= CH_ATIME;
304 newtime.tv_sec = get_date (optarg, NULL);
305 newtime.tv_nsec = 0; /* FIXME: get_date should set this. */
306 if (newtime.tv_sec == (time_t) -1)
307 error (EXIT_FAILURE, 0, _("invalid date format %s"), quote (optarg));
315 change_times |= CH_MTIME;
325 if (! posixtime (&newtime.tv_sec, optarg,
326 PDS_LEADING_YEAR | PDS_CENTURY | PDS_SECONDS))
327 error (EXIT_FAILURE, 0, _("invalid date format %s"), quote (optarg));
332 case TIME_OPTION: /* --time */
333 change_times |= XARGMATCH ("--time", optarg,
334 time_args, time_masks);
337 case_GETOPT_HELP_CHAR;
339 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, WRITTEN_BY);
342 usage (EXIT_FAILURE);
346 if (change_times == 0)
347 change_times = CH_ATIME | CH_MTIME;
349 if ((use_ref && (posix_date || flexible_date))
350 || (posix_date && flexible_date))
352 error (0, 0, _("cannot specify times from more than one source"));
353 usage (EXIT_FAILURE);
358 if (stat (ref_file, &ref_stats))
359 error (EXIT_FAILURE, errno,
360 _("failed to get attributes of %s"), quote (ref_file));
364 /* The obsolete `MMDDhhmm[YY]' form is valid IFF there are
365 two or more non-option arguments. */
366 if (!date_set && 2 <= argc - optind && !STREQ (argv[optind - 1], "--")
367 && posix2_version () < 200112)
369 if (posixtime (&newtime.tv_sec, argv[optind], PDS_TRAILING_YEAR))
372 if (! getenv ("POSIXLY_CORRECT"))
374 struct tm const *tm = localtime (&newtime.tv_sec);
376 _("warning: `touch %s' is obsolete; use\
377 `touch -t %04d%02d%02d%02d%02d.%02d'"),
379 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
380 tm->tm_hour, tm->tm_min, tm->tm_sec);
389 if ((change_times & (CH_ATIME | CH_MTIME)) == (CH_ATIME | CH_MTIME))
393 /* Get time of day, but only to microsecond resolution,
394 since 'utimes' currently supports only microsecond
395 resolution at best. It would be cleaner here to invoke
396 gettime, but then we would have to link in more shared
397 libraries on platforms like Solaris, and we'd rather not
398 have 'touch' depend on libraries that it doesn't
400 struct timeval timeval;
401 if (gettimeofday (&timeval, NULL) != 0)
402 error (EXIT_FAILURE, errno, _("cannot get time of day"));
403 newtime.tv_sec = timeval.tv_sec;
404 newtime.tv_nsec = timeval.tv_usec * 1000;
410 error (0, 0, _("file arguments missing"));
411 usage (EXIT_FAILURE);
414 for (; optind < argc; ++optind)
415 err += touch (argv[optind]);