summaryrefslogtreecommitdiff
path: root/usr.bin/touch
diff options
context:
space:
mode:
authorKiyoshi Aman <kiyoshi.aman+adelie@gmail.com>2019-02-01 22:55:37 +0000
committerKiyoshi Aman <kiyoshi.aman+adelie@gmail.com>2019-02-03 18:22:05 -0600
commit5b57d28ffb6e1ef86b50f7d05d977826eae89bfe (patch)
tree154a22fe556b49e6927197336f8bf91b12eacd5e /usr.bin/touch
downloaduserland-5b57d28ffb6e1ef86b50f7d05d977826eae89bfe.tar.gz
userland-5b57d28ffb6e1ef86b50f7d05d977826eae89bfe.tar.bz2
userland-5b57d28ffb6e1ef86b50f7d05d977826eae89bfe.tar.xz
userland-5b57d28ffb6e1ef86b50f7d05d977826eae89bfe.zip
initial population
Diffstat (limited to 'usr.bin/touch')
-rw-r--r--usr.bin/touch/touch.1215
-rw-r--r--usr.bin/touch/touch.c337
2 files changed, 552 insertions, 0 deletions
diff --git a/usr.bin/touch/touch.1 b/usr.bin/touch/touch.1
new file mode 100644
index 0000000..d1d1fb4
--- /dev/null
+++ b/usr.bin/touch/touch.1
@@ -0,0 +1,215 @@
+.\" $NetBSD: touch.1,v 1.26 2016/12/24 15:49:18 abhinav Exp $
+.\"
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)touch.1 8.3 (Berkeley) 4/28/95
+.\"
+.Dd December 24, 2016
+.Dt TOUCH 1
+.Os
+.Sh NAME
+.Nm touch
+.Nd change file access and modification times
+.Sh SYNOPSIS
+.Nm
+.Op Fl acfhm
+.Op Fl d Ar human-datetime
+.Op Fl Fl date Ar human-datetime
+.Op Fl r Ar file
+.Op Fl Fl reference Ar file
+.Op Fl t Ar datetime
+.Ar file ...
+.Sh DESCRIPTION
+The
+.Nm
+utility changes the access and modification times of files to the
+current time of day.
+If the file doesn't exist, it is created with default permissions.
+.Pp
+The following options are available:
+.Bl -tag -width "-d human-datetime"
+.It Fl a
+Change the access time of the file.
+The modification time of the file is not changed unless the
+.Fl m
+flag is also specified.
+.It Fl c
+Do not create the file if it does not exist.
+The
+.Nm
+utility does not treat this as an error.
+No error messages are displayed and the exit value is not affected.
+.It Fl d Ar human-datetime
+.It Fl Fl date Ar human-datetime
+Parse
+.Ar human-datetime
+using the human datetime parser
+.Xr parsedate 3 .
+.It Fl f
+This flag has no effect; it is accepted for compatibility reasons.
+.It Fl h
+If
+.Ar file
+is a symbolic link, access and/or modification time of the link is changed.
+This option implies
+.Fl c .
+.It Fl m
+Change the modification time of the file.
+The access time of the file is not changed unless the
+.Fl a
+flag is also specified.
+.It Fl r Ar file
+.It Fl Fl reference Ar file
+Use the access and modifications times from
+.Ar file
+instead of the current time of day.
+.It Fl t Ar datetime
+Change the access and modification times to the specified time.
+The argument
+.Ar datetime
+should be in the form
+.Dq [[CC]YY]MMDDhhmm[.SS]
+where each pair of letters represents the following:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It Ar CC
+The first two digits of the year (the century).
+.It Ar YY
+The second two digits of the year.
+If
+.Dq YY
+is specified, but
+.Dq CC
+is not, a value for
+.Dq YY
+between 69 and 99 results in a
+.Dq CC
+value of 19.
+Otherwise, a
+.Dq CC
+value of 20 is used.
+.It Ar MM
+The month of the year, from 1 to 12.
+.It Ar DD
+The day of the month, from 1 to 31.
+.It Ar hh
+The hour of the day, from 0 to 23.
+.It Ar mm
+The minute of the hour, from 0 to 59.
+.It Ar SS
+The second of the minute, from 0 to 60 (permitting leap seconds).
+If
+.Ar SS
+is 60 and the resulting time,
+as affected by the
+.Ev TZ
+environment variable,
+does not refer to a leap second,
+the resulting time is one second after a time where
+.Ar SS
+is 59.
+If
+.Ar SS
+is not given a value, it is assumed to be zero.
+.El
+.Pp
+If the
+.Dq CC
+and
+.Dq YY
+letter pairs are not specified, the values default to the current
+year.
+If the
+.Dq SS
+letter pair is not specified, the value defaults to 0.
+.El
+.Pp
+The
+.Fl d ,
+.Fl r ,
+and
+.Fl t
+options are mutually exclusive.
+If more than one of these options is present, the last one is used.
+.Sh ENVIRONMENT
+.Bl -tag -width -iTZ
+.It Ev TZ
+The timezone to be used for interpreting the
+.Ar datetime
+argument of the
+.Fl t
+option.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh COMPATIBILITY
+The obsolescent form of
+.Nm ,
+where a time format is specified as the first argument, is supported.
+When no
+.Fl d ,
+.Fl r ,
+or
+.Fl t
+option is specified, there are at least two arguments, and the first
+argument is a string of digits either eight or ten characters in length,
+the first argument is interpreted as a time specification of the form
+.Dq MMDDhhmm[YY] .
+.Pp
+The
+.Dq MM ,
+.Dq DD ,
+.Dq hh
+and
+.Dq mm
+letter pairs are treated as their counterparts specified to the
+.Fl t
+option.
+If the
+.Dq YY
+letter pair is in the range 69 to 99, the year is set to 1969 to 1999,
+otherwise, the year is set in the 21st century.
+.Sh SEE ALSO
+.Xr utimes 2 ,
+.Xr parsedate 3
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be a superset of the
+.St -p1003.2
+specification.
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.At v7 .
+.Sh BUGS
+A symbolic link can't be a reference file of access and/or modification time.
diff --git a/usr.bin/touch/touch.c b/usr.bin/touch/touch.c
new file mode 100644
index 0000000..1963815
--- /dev/null
+++ b/usr.bin/touch/touch.c
@@ -0,0 +1,337 @@
+/* $NetBSD: touch.c,v 1.33 2015/03/02 03:17:24 enami Exp $ */
+
+/*
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1993\
+ The Regents of the University of California. All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)touch.c 8.2 (Berkeley) 4/28/95";
+#endif
+__RCSID("$NetBSD: touch.c,v 1.33 2015/03/02 03:17:24 enami Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <time.h>
+#include <tzfile.h>
+#include <unistd.h>
+#include <util.h>
+#include <getopt.h>
+
+static void stime_arg0(char *, struct timespec *);
+static void stime_arg1(char *, struct timespec *);
+static void stime_arg2(char *, int, struct timespec *);
+static void stime_file(char *, struct timespec *);
+__dead static void usage(void);
+
+struct option touch_longopts[] = {
+ { "date", required_argument, 0,
+ 'd' },
+ { "reference", required_argument, 0,
+ 'r' },
+ { NULL, 0, 0,
+ 0 },
+};
+
+int
+main(int argc, char *argv[])
+{
+ struct stat sb;
+ struct timespec ts[2];
+ int aflag, cflag, hflag, mflag, ch, fd, len, rval, timeset;
+ char *p;
+ int (*change_file_times)(const char *, const struct timespec *);
+ int (*get_file_status)(const char *, struct stat *);
+
+ setlocale(LC_ALL, "");
+
+ aflag = cflag = hflag = mflag = timeset = 0;
+ if (clock_gettime(CLOCK_REALTIME, &ts[0]))
+ err(1, "clock_gettime");
+
+ while ((ch = getopt_long(argc, argv, "acd:fhmr:t:", touch_longopts,
+ NULL)) != -1)
+ switch(ch) {
+ case 'a':
+ aflag = 1;
+ break;
+ case 'c':
+ cflag = 1;
+ break;
+ case 'd':
+ timeset = 1;
+ stime_arg0(optarg, ts);
+ break;
+ case 'f':
+ break;
+ case 'h':
+ hflag = 1;
+ break;
+ case 'm':
+ mflag = 1;
+ break;
+ case 'r':
+ timeset = 1;
+ stime_file(optarg, ts);
+ break;
+ case 't':
+ timeset = 1;
+ stime_arg1(optarg, ts);
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* Default is both -a and -m. */
+ if (aflag == 0 && mflag == 0)
+ aflag = mflag = 1;
+
+ if (hflag) {
+ cflag = 1; /* Don't create new file */
+ change_file_times = lutimens;
+ get_file_status = lstat;
+ } else {
+ change_file_times = utimens;
+ get_file_status = stat;
+ }
+
+ /*
+ * If no -r or -t flag, at least two operands, the first of which
+ * is an 8 or 10 digit number, use the obsolete time specification.
+ */
+ if (!timeset && argc > 1) {
+ (void)strtol(argv[0], &p, 10);
+ len = p - argv[0];
+ if (*p == '\0' && (len == 8 || len == 10)) {
+ timeset = 1;
+ stime_arg2(*argv++, len == 10, ts);
+ }
+ }
+
+ /* Otherwise use the current time of day. */
+ if (!timeset)
+ ts[1] = ts[0];
+
+ if (*argv == NULL)
+ usage();
+
+ for (rval = EXIT_SUCCESS; *argv; ++argv) {
+ /* See if the file exists. */
+ if ((*get_file_status)(*argv, &sb)) {
+ if (!cflag) {
+ /* Create the file. */
+ fd = open(*argv,
+ O_WRONLY | O_CREAT, DEFFILEMODE);
+ if (fd == -1 || fstat(fd, &sb) || close(fd)) {
+ rval = EXIT_FAILURE;
+ warn("%s", *argv);
+ continue;
+ }
+
+ /* If using the current time, we're done. */
+ if (!timeset)
+ continue;
+ } else
+ continue;
+ }
+ if (!aflag)
+ ts[0] = sb.st_atimespec;
+ if (!mflag)
+ ts[1] = sb.st_mtimespec;
+
+ /* Try utimes(2). */
+ if (!(*change_file_times)(*argv, ts))
+ continue;
+
+ /* If the user specified a time, nothing else we can do. */
+ if (timeset) {
+ rval = EXIT_FAILURE;
+ warn("%s", *argv);
+ }
+
+ /*
+ * System V and POSIX 1003.1 require that a NULL argument
+ * set the access/modification times to the current time.
+ * The permission checks are different, too, in that the
+ * ability to write the file is sufficient. Take a shot.
+ */
+ if (!(*change_file_times)(*argv, NULL))
+ continue;
+
+ rval = EXIT_FAILURE;
+ warn("%s", *argv);
+ }
+ exit(rval);
+}
+
+#define ATOI2(s) ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0'))
+
+static void
+stime_arg0(char *arg, struct timespec *tsp)
+{
+ tsp[1].tv_sec = tsp[0].tv_sec = parsedate(arg, NULL, NULL);
+ if (tsp[0].tv_sec == -1)
+ errx(EXIT_FAILURE, "Could not parse `%s'", arg);
+ tsp[0].tv_nsec = tsp[1].tv_nsec = 0;
+}
+
+static void
+stime_arg1(char *arg, struct timespec *tsp)
+{
+ struct tm *t;
+ time_t tmptime;
+ int yearset;
+ char *p;
+ /* Start with the current time. */
+ tmptime = tsp[0].tv_sec;
+ if ((t = localtime(&tmptime)) == NULL)
+ err(EXIT_FAILURE, "localtime");
+ /* [[CC]YY]MMDDhhmm[.SS] */
+ if ((p = strchr(arg, '.')) == NULL)
+ t->tm_sec = 0; /* Seconds defaults to 0. */
+ else {
+ if (strlen(p + 1) != 2)
+ goto terr;
+ *p++ = '\0';
+ t->tm_sec = ATOI2(p);
+ }
+
+ yearset = 0;
+ switch (strlen(arg)) {
+ case 12: /* CCYYMMDDhhmm */
+ t->tm_year = ATOI2(arg) * 100 - TM_YEAR_BASE;
+ yearset = 1;
+ /* FALLTHROUGH */
+ case 10: /* YYMMDDhhmm */
+ if (yearset) {
+ t->tm_year += ATOI2(arg);
+ } else {
+ yearset = ATOI2(arg);
+ if (yearset < 69)
+ t->tm_year = yearset + 2000 - TM_YEAR_BASE;
+ else
+ t->tm_year = yearset + 1900 - TM_YEAR_BASE;
+ }
+ /* FALLTHROUGH */
+ case 8: /* MMDDhhmm */
+ t->tm_mon = ATOI2(arg);
+ --t->tm_mon; /* Convert from 01-12 to 00-11 */
+ /* FALLTHROUGH */
+ case 6:
+ t->tm_mday = ATOI2(arg);
+ /* FALLTHROUGH */
+ case 4:
+ t->tm_hour = ATOI2(arg);
+ /* FALLTHROUGH */
+ case 2:
+ t->tm_min = ATOI2(arg);
+ break;
+ default:
+ goto terr;
+ }
+
+ t->tm_isdst = -1; /* Figure out DST. */
+ tsp[0].tv_sec = tsp[1].tv_sec = mktime(t);
+ if (tsp[0].tv_sec == -1)
+terr: errx(EXIT_FAILURE,
+ "out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]");
+
+ tsp[0].tv_nsec = tsp[1].tv_nsec = 0;
+}
+
+static void
+stime_arg2(char *arg, int year, struct timespec *tsp)
+{
+ struct tm *t;
+ time_t tmptime;
+ /* Start with the current time. */
+ tmptime = tsp[0].tv_sec;
+ if ((t = localtime(&tmptime)) == NULL)
+ err(EXIT_FAILURE, "localtime");
+
+ t->tm_mon = ATOI2(arg); /* MMDDhhmm[yy] */
+ --t->tm_mon; /* Convert from 01-12 to 00-11 */
+ t->tm_mday = ATOI2(arg);
+ t->tm_hour = ATOI2(arg);
+ t->tm_min = ATOI2(arg);
+ if (year) {
+ year = ATOI2(arg);
+ if (year < 69)
+ t->tm_year = year + 2000 - TM_YEAR_BASE;
+ else
+ t->tm_year = year + 1900 - TM_YEAR_BASE;
+ }
+ t->tm_sec = 0;
+
+ t->tm_isdst = -1; /* Figure out DST. */
+ tsp[0].tv_sec = tsp[1].tv_sec = mktime(t);
+ if (tsp[0].tv_sec == -1)
+ errx(EXIT_FAILURE,
+ "out of range or illegal time specification: MMDDhhmm[yy]");
+
+ tsp[0].tv_nsec = tsp[1].tv_nsec = 0;
+}
+
+static void
+stime_file(char *fname, struct timespec *tsp)
+{
+ struct stat sb;
+
+ if (stat(fname, &sb))
+ err(1, "%s", fname);
+ tsp[0] = sb.st_atimespec;
+ tsp[1] = sb.st_mtimespec;
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr,
+ "Usage: %s [-acfhm] [-d|--date datetime] [-r|--reference file] [-t time] file ...\n",
+ getprogname());
+ exit(EXIT_FAILURE);
+}