summaryrefslogtreecommitdiff
path: root/usr/src/cmd/touch/touch.c
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/touch/touch.c
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/touch/touch.c')
-rw-r--r--usr/src/cmd/touch/touch.c410
1 files changed, 410 insertions, 0 deletions
diff --git a/usr/src/cmd/touch/touch.c b/usr/src/cmd/touch/touch.c
new file mode 100644
index 0000000000..1263cfe4b5
--- /dev/null
+++ b/usr/src/cmd/touch/touch.c
@@ -0,0 +1,410 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/* Copyright (c) 1987, 1988 Microsoft Corporation */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <libgen.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <time.h>
+#include <unistd.h>
+#include <locale.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#define BADTIME "bad time specification"
+
+static char *myname;
+
+static int isnumber(char *);
+static int atoi_for2(char *);
+static void usage(const int);
+static void touchabort(const char *);
+static void parse_time(char *, timestruc_t *);
+static void parse_datetime(char *, timestruc_t *);
+static void timestruc_to_timeval(timestruc_t *, struct timeval *);
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+
+ int aflag = 0;
+ int cflag = 0;
+ int rflag = 0;
+ int mflag = 0;
+ int tflag = 0;
+ int stflag = 0;
+ int status = 0;
+ int usecurrenttime = 1;
+ int timespecified;
+ int optc;
+ int fd;
+ struct stat stbuf;
+ struct stat prstbuf;
+ struct timeval times[2];
+
+ (void) setlocale(LC_ALL, "");
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+ (void) textdomain(TEXT_DOMAIN);
+
+ myname = basename(argv[0]);
+ if (strcmp(myname, "settime") == NULL) {
+ cflag++;
+ stflag++;
+ while ((optc = getopt(argc, argv, "f:")) != EOF)
+ switch (optc) {
+ case 'f':
+ rflag++;
+ usecurrenttime = 0;
+ if (stat(optarg, &prstbuf) == -1) {
+ (void) fprintf(stderr, "%s: ", myname);
+ perror(optarg);
+ return (2);
+ }
+ break;
+ case '?':
+ usage(stflag);
+ break;
+ };
+ } else
+ while ((optc = getopt(argc, argv, "acfmr:t:")) != EOF)
+ switch (optc) {
+ case 'a':
+ aflag++;
+ usecurrenttime = 0;
+ break;
+ case 'c':
+ cflag++;
+ break;
+ case 'f': /* silently ignore for UCB compat */
+ break;
+ case 'm':
+ mflag++;
+ usecurrenttime = 0;
+ break;
+ case 'r': /* same as settime's -f option */
+ rflag++;
+ usecurrenttime = 0;
+ if (stat(optarg, &prstbuf) == -1) {
+ (void) fprintf(stderr, "%s: ", myname);
+ perror(optarg);
+ return (2);
+ }
+ break;
+ case 't':
+ tflag++;
+ usecurrenttime = 0;
+ parse_time(optarg, &prstbuf.st_mtim);
+ prstbuf.st_atim = prstbuf.st_mtim;
+ break;
+ case '?':
+ usage(stflag);
+ break;
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if ((argc < 1) || (rflag + tflag > 1))
+ usage(stflag);
+
+ if ((aflag == 0) && (mflag == 0)) {
+ aflag = 1;
+ mflag = 1;
+ }
+
+ /*
+ * If either -r or -t has been specified,
+ * use the specified time.
+ */
+ timespecified = rflag || tflag;
+
+ if (timespecified == 0) {
+ if (argc >= 2 && isnumber(*argv) && (strlen(*argv) == 8 ||
+ strlen(*argv) == 10)) {
+ /*
+ * time is specified as an operand.
+ * use it.
+ */
+ parse_datetime(*argv++, &prstbuf.st_mtim);
+ prstbuf.st_atim = prstbuf.st_mtim;
+ usecurrenttime = 0;
+ timespecified = 1;
+ argc--;
+ } else {
+ /*
+ * no time information is specified.
+ * use the current time.
+ */
+ (void) gettimeofday(times, NULL);
+ times[1] = times[0];
+ }
+ }
+ for (c = 0; c < argc; c++) {
+ if (stat(argv[c], &stbuf)) {
+ /*
+ * if stat failed for reasons other than ENOENT,
+ * the file should not be created, since this
+ * can clobber the contents of an existing file
+ * (for example, a large file that results in overflow).
+ */
+ if (errno != ENOENT) {
+ (void) fprintf(stderr,
+ gettext("%s: %s cannot stat\n"),
+ myname, argv[c]);
+ status++;
+ continue;
+ } else if (cflag) {
+ continue;
+ } else if ((fd = creat(argv[c],
+ (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)))
+ < 0) {
+ (void) fprintf(stderr,
+ gettext("%s: %s cannot create\n"),
+ myname, argv[c]);
+ status++;
+ continue;
+ } else {
+ (void) close(fd);
+ if (stat(argv[c], &stbuf)) {
+ (void) fprintf(stderr,
+ gettext("%s: %s cannot stat\n"),
+ myname, argv[c]);
+ status++;
+ continue;
+ }
+ }
+ }
+
+ if (mflag == 0) {
+ /* Keep the mtime of the file */
+ timestruc_to_timeval(&stbuf.st_mtim, times + 1);
+ } else {
+ if (timespecified) {
+ /* Set the specified time */
+ timestruc_to_timeval(&prstbuf.st_mtim,
+ times + 1);
+ }
+ /* Otherwise, use the current time by gettimeofday */
+ }
+
+ if (aflag == 0) {
+ /* Keep the atime of the file */
+ timestruc_to_timeval(&stbuf.st_atim, times);
+ } else {
+ if (timespecified) {
+ /* Set the specified time */
+ timestruc_to_timeval(&prstbuf.st_atim, times);
+ }
+ /* Otherwise, use the current time by gettimeofday */
+ }
+
+ if (utimes(argv[c], (usecurrenttime) ? NULL : times)) {
+ (void) fprintf(stderr,
+ gettext("%s: cannot change times on %s\n"),
+ myname, argv[c]);
+ status++;
+ continue;
+ }
+ }
+ return (status);
+}
+
+static int
+isnumber(char *s)
+{
+ int c;
+
+ while ((c = *s++) != '\0')
+ if (!isdigit(c))
+ return (0);
+ return (1);
+}
+
+
+static void
+parse_time(char *t, timestruc_t *ts)
+{
+ int century = 0;
+ int seconds = 0;
+ char *p;
+ time_t when;
+ struct tm tm;
+
+ /*
+ * time in the following format (defined by the touch(1) spec):
+ * [[CC]YY]MMDDhhmm[.SS]
+ */
+ if ((p = strchr(t, '.')) != NULL) {
+ if (strchr(p+1, '.') != NULL)
+ touchabort(BADTIME);
+ seconds = atoi_for2(p+1);
+ *p = '\0';
+ }
+
+ (void) memset(&tm, 0, sizeof (struct tm));
+ when = time(0);
+ tm.tm_year = localtime(&when)->tm_year;
+
+ switch (strlen(t)) {
+ case 12: /* CCYYMMDDhhmm */
+ century = atoi_for2(t);
+ t += 2;
+ /* FALLTHROUGH */
+ case 10: /* YYMMDDhhmm */
+ tm.tm_year = atoi_for2(t);
+ t += 2;
+ if (century == 0) {
+ if (tm.tm_year < 69)
+ tm.tm_year += 100;
+ } else
+ tm.tm_year += (century - 19) * 100;
+ /* FALLTHROUGH */
+ case 8: /* MMDDhhmm */
+ tm.tm_mon = atoi_for2(t) - 1;
+ t += 2;
+ tm.tm_mday = atoi_for2(t);
+ t += 2;
+ tm.tm_hour = atoi_for2(t);
+ t += 2;
+ tm.tm_min = atoi_for2(t);
+ tm.tm_sec = seconds;
+ break;
+ default:
+ touchabort(BADTIME);
+ }
+
+ if ((when = mktime(&tm)) == -1)
+ touchabort(BADTIME);
+ if (tm.tm_isdst)
+ when -= (timezone-altzone);
+
+ ts->tv_sec = when;
+ ts->tv_nsec = 0;
+}
+
+static void
+parse_datetime(char *t, timestruc_t *ts)
+{
+ time_t when;
+ struct tm tm;
+
+ /*
+ * time in the following format (defined by the touch(1) spec):
+ * MMDDhhmm[yy]
+ */
+
+ (void) memset(&tm, 0, sizeof (struct tm));
+ when = time(0);
+ tm.tm_year = localtime(&when)->tm_year;
+
+ switch (strlen(t)) {
+ case 10: /* MMDDhhmmyy */
+ tm.tm_year = atoi_for2(t+8);
+ if (tm.tm_year < 69)
+ tm.tm_year += 100;
+ /* FALLTHROUGH */
+ case 8: /* MMDDhhmm */
+ tm.tm_mon = atoi_for2(t) - 1;
+ t += 2;
+ tm.tm_mday = atoi_for2(t);
+ t += 2;
+ tm.tm_hour = atoi_for2(t);
+ t += 2;
+ tm.tm_min = atoi_for2(t);
+ break;
+ default:
+ touchabort(BADTIME);
+ }
+
+ if ((when = mktime(&tm)) == -1)
+ touchabort(BADTIME);
+ if (tm.tm_isdst)
+ when -= (timezone - altzone);
+
+ ts->tv_sec = when;
+ ts->tv_nsec = 0;
+}
+
+static int
+atoi_for2(char *p)
+{
+ int value;
+
+ value = (*p - '0') * 10 + *(p+1) - '0';
+ if ((value < 0) || (value > 99))
+ touchabort(BADTIME);
+ return (value);
+}
+
+static void
+touchabort(const char *message)
+{
+ (void) fprintf(stderr, "%s: %s\n", myname, gettext(message));
+ exit(1);
+}
+
+static void
+usage(const int settime)
+{
+ if (settime)
+ (void) fprintf(stderr, gettext(
+ "usage: %s [-f file] [mmddhhmm[yy]] file...\n"),
+ myname);
+ else
+ (void) fprintf(stderr, gettext(
+ "usage: %s [-acm] [-r ref_file] file...\n"
+ " %s [-acm] [MMDDhhmm[yy]] file...\n"
+ " %s [-acm] [-t [[CC]YY]MMDDhhmm[.SS]] file...\n"),
+ myname, myname, myname);
+ exit(2);
+}
+
+/*
+ * nanoseconds are rounded off to microseconds by flooring.
+ */
+static void
+timestruc_to_timeval(timestruc_t *ts, struct timeval *tv)
+{
+ tv->tv_sec = ts->tv_sec;
+ tv->tv_usec = ts->tv_nsec / 1000;
+}