diff options
author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
---|---|---|
committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/touch/touch.c | |
download | illumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz |
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/touch/touch.c')
-rw-r--r-- | usr/src/cmd/touch/touch.c | 410 |
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; +} |