17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5eaacacc0SMilan Jurik * Common Development and Distribution License (the "License"). 6eaacacc0SMilan Jurik * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 213b862e9aSRoger A. Faulkner 227c478bd9Sstevel@tonic-gate /* 233b862e9aSRoger A. Faulkner * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 287c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate /* Copyright (c) 1987, 1988 Microsoft Corporation */ 317c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate #include <sys/types.h> 347c478bd9Sstevel@tonic-gate #include <sys/stat.h> 357c478bd9Sstevel@tonic-gate #include <stdio.h> 367c478bd9Sstevel@tonic-gate #include <string.h> 377c478bd9Sstevel@tonic-gate #include <strings.h> 387c478bd9Sstevel@tonic-gate #include <stdlib.h> 397c478bd9Sstevel@tonic-gate #include <ctype.h> 407c478bd9Sstevel@tonic-gate #include <libgen.h> 417c478bd9Sstevel@tonic-gate #include <fcntl.h> 427c478bd9Sstevel@tonic-gate #include <pwd.h> 437c478bd9Sstevel@tonic-gate #include <time.h> 447c478bd9Sstevel@tonic-gate #include <unistd.h> 457c478bd9Sstevel@tonic-gate #include <locale.h> 467c478bd9Sstevel@tonic-gate #include <sys/time.h> 477c478bd9Sstevel@tonic-gate #include <errno.h> 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate #define BADTIME "bad time specification" 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate static char *myname; 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate static int isnumber(char *); 547c478bd9Sstevel@tonic-gate static int atoi_for2(char *); 557c478bd9Sstevel@tonic-gate static void usage(const int); 567c478bd9Sstevel@tonic-gate static void touchabort(const char *); 573b862e9aSRoger A. Faulkner static void parse_datetime(char *, timespec_t *); 583b862e9aSRoger A. Faulkner static void parse_time(char *, timespec_t *); 593b862e9aSRoger A. Faulkner static void parse_timespec(char *, timespec_t *); 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate int 627c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 637c478bd9Sstevel@tonic-gate { 647c478bd9Sstevel@tonic-gate int c; 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate int aflag = 0; 677c478bd9Sstevel@tonic-gate int cflag = 0; 687c478bd9Sstevel@tonic-gate int rflag = 0; 697c478bd9Sstevel@tonic-gate int mflag = 0; 707c478bd9Sstevel@tonic-gate int tflag = 0; 717c478bd9Sstevel@tonic-gate int stflag = 0; 727c478bd9Sstevel@tonic-gate int status = 0; 737c478bd9Sstevel@tonic-gate int usecurrenttime = 1; 747c478bd9Sstevel@tonic-gate int timespecified; 757c478bd9Sstevel@tonic-gate int optc; 763b862e9aSRoger A. Faulkner int fd = -1; 773b862e9aSRoger A. Faulkner mode_t cmode = 783b862e9aSRoger A. Faulkner (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); 797c478bd9Sstevel@tonic-gate struct stat stbuf; 807c478bd9Sstevel@tonic-gate struct stat prstbuf; 813b862e9aSRoger A. Faulkner timespec_t times[2]; 823b862e9aSRoger A. Faulkner timespec_t *tsp; 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 857c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 867c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 877c478bd9Sstevel@tonic-gate #endif 887c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate myname = basename(argv[0]); 913b862e9aSRoger A. Faulkner if (strcmp(myname, "settime") == 0) { 927c478bd9Sstevel@tonic-gate cflag++; 937c478bd9Sstevel@tonic-gate stflag++; 943b862e9aSRoger A. Faulkner while ((optc = getopt(argc, argv, "f:")) != EOF) { 957c478bd9Sstevel@tonic-gate switch (optc) { 967c478bd9Sstevel@tonic-gate case 'f': 977c478bd9Sstevel@tonic-gate rflag++; 987c478bd9Sstevel@tonic-gate usecurrenttime = 0; 997c478bd9Sstevel@tonic-gate if (stat(optarg, &prstbuf) == -1) { 1007c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", myname); 1017c478bd9Sstevel@tonic-gate perror(optarg); 1027c478bd9Sstevel@tonic-gate return (2); 1037c478bd9Sstevel@tonic-gate } 1047c478bd9Sstevel@tonic-gate break; 1057c478bd9Sstevel@tonic-gate case '?': 1067c478bd9Sstevel@tonic-gate usage(stflag); 1077c478bd9Sstevel@tonic-gate break; 1083b862e9aSRoger A. Faulkner } 1093b862e9aSRoger A. Faulkner } 1103b862e9aSRoger A. Faulkner } else { 1113b862e9aSRoger A. Faulkner while ((optc = getopt(argc, argv, "acfmr:d:t:")) != EOF) { 1127c478bd9Sstevel@tonic-gate switch (optc) { 1137c478bd9Sstevel@tonic-gate case 'a': 1147c478bd9Sstevel@tonic-gate aflag++; 1157c478bd9Sstevel@tonic-gate break; 1167c478bd9Sstevel@tonic-gate case 'c': 1177c478bd9Sstevel@tonic-gate cflag++; 1187c478bd9Sstevel@tonic-gate break; 1197c478bd9Sstevel@tonic-gate case 'f': /* silently ignore for UCB compat */ 1207c478bd9Sstevel@tonic-gate break; 1217c478bd9Sstevel@tonic-gate case 'm': 1227c478bd9Sstevel@tonic-gate mflag++; 1237c478bd9Sstevel@tonic-gate break; 1247c478bd9Sstevel@tonic-gate case 'r': /* same as settime's -f option */ 1257c478bd9Sstevel@tonic-gate rflag++; 1267c478bd9Sstevel@tonic-gate usecurrenttime = 0; 1277c478bd9Sstevel@tonic-gate if (stat(optarg, &prstbuf) == -1) { 1287c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", myname); 1297c478bd9Sstevel@tonic-gate perror(optarg); 1307c478bd9Sstevel@tonic-gate return (2); 1317c478bd9Sstevel@tonic-gate } 1327c478bd9Sstevel@tonic-gate break; 1333b862e9aSRoger A. Faulkner case 'd': 1343b862e9aSRoger A. Faulkner tflag++; 1353b862e9aSRoger A. Faulkner usecurrenttime = 0; 1363b862e9aSRoger A. Faulkner parse_datetime(optarg, &prstbuf.st_mtim); 1373b862e9aSRoger A. Faulkner prstbuf.st_atim = prstbuf.st_mtim; 1383b862e9aSRoger A. Faulkner break; 1397c478bd9Sstevel@tonic-gate case 't': 1407c478bd9Sstevel@tonic-gate tflag++; 1417c478bd9Sstevel@tonic-gate usecurrenttime = 0; 1427c478bd9Sstevel@tonic-gate parse_time(optarg, &prstbuf.st_mtim); 1437c478bd9Sstevel@tonic-gate prstbuf.st_atim = prstbuf.st_mtim; 1447c478bd9Sstevel@tonic-gate break; 1457c478bd9Sstevel@tonic-gate case '?': 1467c478bd9Sstevel@tonic-gate usage(stflag); 1477c478bd9Sstevel@tonic-gate break; 1487c478bd9Sstevel@tonic-gate } 1493b862e9aSRoger A. Faulkner } 1503b862e9aSRoger A. Faulkner } 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate argc -= optind; 1537c478bd9Sstevel@tonic-gate argv += optind; 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate if ((argc < 1) || (rflag + tflag > 1)) 1567c478bd9Sstevel@tonic-gate usage(stflag); 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate if ((aflag == 0) && (mflag == 0)) { 1597c478bd9Sstevel@tonic-gate aflag = 1; 1607c478bd9Sstevel@tonic-gate mflag = 1; 1617c478bd9Sstevel@tonic-gate } 1623b862e9aSRoger A. Faulkner if ((aflag && !mflag) || (mflag && !aflag)) 1633b862e9aSRoger A. Faulkner usecurrenttime = 0; 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate /* 1663b862e9aSRoger A. Faulkner * If -r, -t or -d has been specified, 1677c478bd9Sstevel@tonic-gate * use the specified time. 1687c478bd9Sstevel@tonic-gate */ 1693b862e9aSRoger A. Faulkner timespecified = (rflag | tflag); 1707c478bd9Sstevel@tonic-gate 1713b862e9aSRoger A. Faulkner if (timespecified == 0 && argc >= 2 && isnumber(*argv) && 1723b862e9aSRoger A. Faulkner (strlen(*argv) == 8 || strlen(*argv) == 10)) { 1737c478bd9Sstevel@tonic-gate /* 1743b862e9aSRoger A. Faulkner * time is specified as an operand; use it. 1757c478bd9Sstevel@tonic-gate */ 1763b862e9aSRoger A. Faulkner parse_timespec(*argv++, &prstbuf.st_mtim); 1777c478bd9Sstevel@tonic-gate prstbuf.st_atim = prstbuf.st_mtim; 1787c478bd9Sstevel@tonic-gate usecurrenttime = 0; 1797c478bd9Sstevel@tonic-gate timespecified = 1; 1807c478bd9Sstevel@tonic-gate argc--; 1817c478bd9Sstevel@tonic-gate } 1823b862e9aSRoger A. Faulkner 1837c478bd9Sstevel@tonic-gate for (c = 0; c < argc; c++) { 1847c478bd9Sstevel@tonic-gate if (stat(argv[c], &stbuf)) { 1857c478bd9Sstevel@tonic-gate /* 186eaacacc0SMilan Jurik * If stat failed for reasons other than EOVERFLOW or 187eaacacc0SMilan Jurik * ENOENT, the file should not be created, since this 188eaacacc0SMilan Jurik * can clobber the contents of an existing file. 1897c478bd9Sstevel@tonic-gate */ 190eaacacc0SMilan Jurik if (errno == EOVERFLOW) { 191eaacacc0SMilan Jurik /* 1923b862e9aSRoger A. Faulkner * Since we have EOVERFLOW, 1933b862e9aSRoger A. Faulkner * we know the file exists. 194eaacacc0SMilan Jurik */ 1953b862e9aSRoger A. Faulkner /* EMPTY */; 196eaacacc0SMilan Jurik } else if (errno != ENOENT) { 197eaacacc0SMilan Jurik (void) fprintf(stderr, 198eaacacc0SMilan Jurik gettext("%s: cannot stat %s: %s\n"), 199eaacacc0SMilan Jurik myname, argv[c], strerror(errno)); 2007c478bd9Sstevel@tonic-gate status++; 2017c478bd9Sstevel@tonic-gate continue; 2027c478bd9Sstevel@tonic-gate } else if (cflag) { 2037c478bd9Sstevel@tonic-gate continue; 2043b862e9aSRoger A. Faulkner } else if ((fd = creat(argv[c], cmode)) < 0) { 2057c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 206eaacacc0SMilan Jurik gettext("%s: cannot create %s: %s\n"), 207eaacacc0SMilan Jurik myname, argv[c], strerror(errno)); 2087c478bd9Sstevel@tonic-gate status++; 2097c478bd9Sstevel@tonic-gate continue; 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate } 2127c478bd9Sstevel@tonic-gate 2133b862e9aSRoger A. Faulkner if (usecurrenttime) { 2143b862e9aSRoger A. Faulkner tsp = NULL; 2153b862e9aSRoger A. Faulkner } else { 2167c478bd9Sstevel@tonic-gate if (mflag == 0) { 2177c478bd9Sstevel@tonic-gate /* Keep the mtime of the file */ 2183b862e9aSRoger A. Faulkner times[1].tv_nsec = UTIME_OMIT; 2193b862e9aSRoger A. Faulkner } else if (timespecified) { 2207c478bd9Sstevel@tonic-gate /* Set the specified time */ 2213b862e9aSRoger A. Faulkner times[1] = prstbuf.st_mtim; 2223b862e9aSRoger A. Faulkner } else { 2233b862e9aSRoger A. Faulkner /* Otherwise, use the current time */ 2243b862e9aSRoger A. Faulkner times[1].tv_nsec = UTIME_NOW; 2257c478bd9Sstevel@tonic-gate } 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate if (aflag == 0) { 2287c478bd9Sstevel@tonic-gate /* Keep the atime of the file */ 2293b862e9aSRoger A. Faulkner times[0].tv_nsec = UTIME_OMIT; 2303b862e9aSRoger A. Faulkner } else if (timespecified) { 2317c478bd9Sstevel@tonic-gate /* Set the specified time */ 2323b862e9aSRoger A. Faulkner times[0] = prstbuf.st_atim; 2333b862e9aSRoger A. Faulkner } else { 2343b862e9aSRoger A. Faulkner /* Otherwise, use the current time */ 2353b862e9aSRoger A. Faulkner times[0].tv_nsec = UTIME_NOW; 2367c478bd9Sstevel@tonic-gate } 2377c478bd9Sstevel@tonic-gate 2383b862e9aSRoger A. Faulkner tsp = times; 2393b862e9aSRoger A. Faulkner } 2403b862e9aSRoger A. Faulkner 2413b862e9aSRoger A. Faulkner if ((fd >= 0 && futimens(fd, tsp) != 0) || 242*b08ea9b8SMarcel Telka (fd < 0 && utimensat(AT_FDCWD, argv[c], tsp, 0) != 0)) { 2437c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 244eaacacc0SMilan Jurik gettext("%s: cannot change times on %s: %s\n"), 245eaacacc0SMilan Jurik myname, argv[c], strerror(errno)); 2467c478bd9Sstevel@tonic-gate status++; 2473b862e9aSRoger A. Faulkner } 2483b862e9aSRoger A. Faulkner if (fd >= 0) { 2493b862e9aSRoger A. Faulkner (void) close(fd); 2503b862e9aSRoger A. Faulkner fd = -1; 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate return (status); 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate static int 2577c478bd9Sstevel@tonic-gate isnumber(char *s) 2587c478bd9Sstevel@tonic-gate { 2597c478bd9Sstevel@tonic-gate int c; 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate while ((c = *s++) != '\0') 2627c478bd9Sstevel@tonic-gate if (!isdigit(c)) 2637c478bd9Sstevel@tonic-gate return (0); 2647c478bd9Sstevel@tonic-gate return (1); 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate 2673b862e9aSRoger A. Faulkner static void 2683b862e9aSRoger A. Faulkner parse_datetime(char *t, timespec_t *ts) 2693b862e9aSRoger A. Faulkner { 2703b862e9aSRoger A. Faulkner char date[64]; 2713b862e9aSRoger A. Faulkner char *year; 2723b862e9aSRoger A. Faulkner char *month; 2733b862e9aSRoger A. Faulkner char *day; 2743b862e9aSRoger A. Faulkner char *hour; 2753b862e9aSRoger A. Faulkner char *minute; 2763b862e9aSRoger A. Faulkner char *second; 2773b862e9aSRoger A. Faulkner char *fraction; 2783b862e9aSRoger A. Faulkner int utc = 0; 2793b862e9aSRoger A. Faulkner char *p; 2803b862e9aSRoger A. Faulkner time_t when; 2813b862e9aSRoger A. Faulkner int nanoseconds; 2823b862e9aSRoger A. Faulkner struct tm tm; 2833b862e9aSRoger A. Faulkner 2843b862e9aSRoger A. Faulkner /* 2853b862e9aSRoger A. Faulkner * The date string has the format (defined by the touch(1) spec): 2863b862e9aSRoger A. Faulkner * YYYY-MM-DDThh:mm:SS[.frac][tz] 2873b862e9aSRoger A. Faulkner * YYYY-MM-DDThh:mm:SS[,frac][tz] 2883b862e9aSRoger A. Faulkner * T is either the literal 'T' or is a space character. 2893b862e9aSRoger A. Faulkner * tz is either empty (local time) or the literal 'Z' (UTC). 2903b862e9aSRoger A. Faulkner * All other fields are strings of digits. 2913b862e9aSRoger A. Faulkner */ 2923b862e9aSRoger A. Faulkner 2933b862e9aSRoger A. Faulkner /* 2943b862e9aSRoger A. Faulkner * Make a copy of the date string so it can be tokenized. 2953b862e9aSRoger A. Faulkner */ 2963b862e9aSRoger A. Faulkner if (strlcpy(date, t, sizeof (date)) >= sizeof (date)) 2973b862e9aSRoger A. Faulkner touchabort(BADTIME); 2983b862e9aSRoger A. Faulkner 2993b862e9aSRoger A. Faulkner /* deal with the optional trailing 'Z' first */ 3003b862e9aSRoger A. Faulkner p = date + strlen(date) - 1; 3013b862e9aSRoger A. Faulkner if (*p == 'Z') { 3023b862e9aSRoger A. Faulkner utc = 1; 3033b862e9aSRoger A. Faulkner *p = '\0'; 3043b862e9aSRoger A. Faulkner } 3053b862e9aSRoger A. Faulkner 3063b862e9aSRoger A. Faulkner /* break out the component tokens */ 3073b862e9aSRoger A. Faulkner p = date; 3083b862e9aSRoger A. Faulkner year = strsep(&p, "-"); 3093b862e9aSRoger A. Faulkner month = strsep(&p, "-"); 3103b862e9aSRoger A. Faulkner day = strsep(&p, "T "); 3113b862e9aSRoger A. Faulkner hour = strsep(&p, ":"); 3123b862e9aSRoger A. Faulkner minute = strsep(&p, ":"); 3133b862e9aSRoger A. Faulkner second = strsep(&p, ".,"); 3143b862e9aSRoger A. Faulkner fraction = p; 3153b862e9aSRoger A. Faulkner 3163b862e9aSRoger A. Faulkner /* verify the component tokens */ 3173b862e9aSRoger A. Faulkner if (year == NULL || strlen(year) < 4 || !isnumber(year) || 3183b862e9aSRoger A. Faulkner month == NULL || strlen(month) != 2 || !isnumber(month) || 3193b862e9aSRoger A. Faulkner day == NULL || strlen(day) != 2 || !isnumber(day) || 3203b862e9aSRoger A. Faulkner hour == NULL || strlen(hour) != 2 || !isnumber(hour) || 3213b862e9aSRoger A. Faulkner minute == NULL || strlen(minute) != 2 || !isnumber(minute) || 3223b862e9aSRoger A. Faulkner second == NULL || strlen(second) != 2 || !isnumber(second) || 3233b862e9aSRoger A. Faulkner (fraction != NULL && (*fraction == '\0' || !isnumber(fraction)))) 3243b862e9aSRoger A. Faulkner touchabort(BADTIME); 3253b862e9aSRoger A. Faulkner 3263b862e9aSRoger A. Faulkner (void) memset(&tm, 0, sizeof (struct tm)); 3273b862e9aSRoger A. Faulkner 3283b862e9aSRoger A. Faulkner tm.tm_year = atoi(year) - 1900; 3293b862e9aSRoger A. Faulkner tm.tm_mon = atoi(month) - 1; 3303b862e9aSRoger A. Faulkner tm.tm_mday = atoi(day); 3313b862e9aSRoger A. Faulkner tm.tm_hour = atoi(hour); 3323b862e9aSRoger A. Faulkner tm.tm_min = atoi(minute); 3333b862e9aSRoger A. Faulkner tm.tm_sec = atoi(second); 3343b862e9aSRoger A. Faulkner if (utc) { 3353b862e9aSRoger A. Faulkner (void) setenv("TZ", "GMT0", 1); 3363b862e9aSRoger A. Faulkner tzset(); 3373b862e9aSRoger A. Faulkner } 3383b862e9aSRoger A. Faulkner 3393b862e9aSRoger A. Faulkner errno = 0; 3403b862e9aSRoger A. Faulkner if ((when = mktime(&tm)) == -1 && errno != 0) 3413b862e9aSRoger A. Faulkner touchabort(BADTIME); 3423b862e9aSRoger A. Faulkner if (tm.tm_isdst) 3433b862e9aSRoger A. Faulkner when -= (timezone - altzone); 3443b862e9aSRoger A. Faulkner 3453b862e9aSRoger A. Faulkner if (fraction == NULL) { 3463b862e9aSRoger A. Faulkner nanoseconds = 0; 3473b862e9aSRoger A. Faulkner } else { 3483b862e9aSRoger A. Faulkner /* truncate beyond 9 digits (nanoseconds) */ 3493b862e9aSRoger A. Faulkner if (strlen(fraction) > 9) 3503b862e9aSRoger A. Faulkner fraction[9] = '\0'; 3513b862e9aSRoger A. Faulkner nanoseconds = atoi(fraction); 3523b862e9aSRoger A. Faulkner 3533b862e9aSRoger A. Faulkner switch (strlen(fraction)) { 3543b862e9aSRoger A. Faulkner case 1: 3553b862e9aSRoger A. Faulkner nanoseconds *= 100000000; 3563b862e9aSRoger A. Faulkner break; 3573b862e9aSRoger A. Faulkner case 2: 3583b862e9aSRoger A. Faulkner nanoseconds *= 10000000; 3593b862e9aSRoger A. Faulkner break; 3603b862e9aSRoger A. Faulkner case 3: 3613b862e9aSRoger A. Faulkner nanoseconds *= 1000000; 3623b862e9aSRoger A. Faulkner break; 3633b862e9aSRoger A. Faulkner case 4: 3643b862e9aSRoger A. Faulkner nanoseconds *= 100000; 3653b862e9aSRoger A. Faulkner break; 3663b862e9aSRoger A. Faulkner case 5: 3673b862e9aSRoger A. Faulkner nanoseconds *= 10000; 3683b862e9aSRoger A. Faulkner break; 3693b862e9aSRoger A. Faulkner case 6: 3703b862e9aSRoger A. Faulkner nanoseconds *= 1000; 3713b862e9aSRoger A. Faulkner break; 3723b862e9aSRoger A. Faulkner case 7: 3733b862e9aSRoger A. Faulkner nanoseconds *= 100; 3743b862e9aSRoger A. Faulkner break; 3753b862e9aSRoger A. Faulkner case 8: 3763b862e9aSRoger A. Faulkner nanoseconds *= 10; 3773b862e9aSRoger A. Faulkner break; 3783b862e9aSRoger A. Faulkner case 9: 3793b862e9aSRoger A. Faulkner break; 3803b862e9aSRoger A. Faulkner } 3813b862e9aSRoger A. Faulkner } 3823b862e9aSRoger A. Faulkner 3833b862e9aSRoger A. Faulkner ts->tv_sec = when; 3843b862e9aSRoger A. Faulkner ts->tv_nsec = nanoseconds; 3853b862e9aSRoger A. Faulkner } 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate static void 3883b862e9aSRoger A. Faulkner parse_time(char *t, timespec_t *ts) 3897c478bd9Sstevel@tonic-gate { 3907c478bd9Sstevel@tonic-gate int century = 0; 3917c478bd9Sstevel@tonic-gate int seconds = 0; 3927c478bd9Sstevel@tonic-gate char *p; 3937c478bd9Sstevel@tonic-gate time_t when; 3947c478bd9Sstevel@tonic-gate struct tm tm; 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* 3977c478bd9Sstevel@tonic-gate * time in the following format (defined by the touch(1) spec): 3987c478bd9Sstevel@tonic-gate * [[CC]YY]MMDDhhmm[.SS] 3997c478bd9Sstevel@tonic-gate */ 4007c478bd9Sstevel@tonic-gate if ((p = strchr(t, '.')) != NULL) { 4017c478bd9Sstevel@tonic-gate if (strchr(p+1, '.') != NULL) 4027c478bd9Sstevel@tonic-gate touchabort(BADTIME); 4037c478bd9Sstevel@tonic-gate seconds = atoi_for2(p+1); 4047c478bd9Sstevel@tonic-gate *p = '\0'; 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate (void) memset(&tm, 0, sizeof (struct tm)); 4087c478bd9Sstevel@tonic-gate when = time(0); 4097c478bd9Sstevel@tonic-gate tm.tm_year = localtime(&when)->tm_year; 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate switch (strlen(t)) { 4127c478bd9Sstevel@tonic-gate case 12: /* CCYYMMDDhhmm */ 4137c478bd9Sstevel@tonic-gate century = atoi_for2(t); 4147c478bd9Sstevel@tonic-gate t += 2; 4157c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 4167c478bd9Sstevel@tonic-gate case 10: /* YYMMDDhhmm */ 4177c478bd9Sstevel@tonic-gate tm.tm_year = atoi_for2(t); 4187c478bd9Sstevel@tonic-gate t += 2; 4197c478bd9Sstevel@tonic-gate if (century == 0) { 4207c478bd9Sstevel@tonic-gate if (tm.tm_year < 69) 4217c478bd9Sstevel@tonic-gate tm.tm_year += 100; 4227c478bd9Sstevel@tonic-gate } else 4237c478bd9Sstevel@tonic-gate tm.tm_year += (century - 19) * 100; 4247c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 4257c478bd9Sstevel@tonic-gate case 8: /* MMDDhhmm */ 4267c478bd9Sstevel@tonic-gate tm.tm_mon = atoi_for2(t) - 1; 4277c478bd9Sstevel@tonic-gate t += 2; 4287c478bd9Sstevel@tonic-gate tm.tm_mday = atoi_for2(t); 4297c478bd9Sstevel@tonic-gate t += 2; 4307c478bd9Sstevel@tonic-gate tm.tm_hour = atoi_for2(t); 4317c478bd9Sstevel@tonic-gate t += 2; 4327c478bd9Sstevel@tonic-gate tm.tm_min = atoi_for2(t); 4337c478bd9Sstevel@tonic-gate tm.tm_sec = seconds; 4347c478bd9Sstevel@tonic-gate break; 4357c478bd9Sstevel@tonic-gate default: 4367c478bd9Sstevel@tonic-gate touchabort(BADTIME); 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate if ((when = mktime(&tm)) == -1) 4407c478bd9Sstevel@tonic-gate touchabort(BADTIME); 4417c478bd9Sstevel@tonic-gate if (tm.tm_isdst) 4427c478bd9Sstevel@tonic-gate when -= (timezone-altzone); 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate ts->tv_sec = when; 4457c478bd9Sstevel@tonic-gate ts->tv_nsec = 0; 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate static void 4493b862e9aSRoger A. Faulkner parse_timespec(char *t, timespec_t *ts) 4507c478bd9Sstevel@tonic-gate { 4517c478bd9Sstevel@tonic-gate time_t when; 4527c478bd9Sstevel@tonic-gate struct tm tm; 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate /* 4557c478bd9Sstevel@tonic-gate * time in the following format (defined by the touch(1) spec): 4567c478bd9Sstevel@tonic-gate * MMDDhhmm[yy] 4577c478bd9Sstevel@tonic-gate */ 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate (void) memset(&tm, 0, sizeof (struct tm)); 4607c478bd9Sstevel@tonic-gate when = time(0); 4617c478bd9Sstevel@tonic-gate tm.tm_year = localtime(&when)->tm_year; 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate switch (strlen(t)) { 4647c478bd9Sstevel@tonic-gate case 10: /* MMDDhhmmyy */ 4657c478bd9Sstevel@tonic-gate tm.tm_year = atoi_for2(t+8); 4667c478bd9Sstevel@tonic-gate if (tm.tm_year < 69) 4677c478bd9Sstevel@tonic-gate tm.tm_year += 100; 4687c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 4697c478bd9Sstevel@tonic-gate case 8: /* MMDDhhmm */ 4707c478bd9Sstevel@tonic-gate tm.tm_mon = atoi_for2(t) - 1; 4717c478bd9Sstevel@tonic-gate t += 2; 4727c478bd9Sstevel@tonic-gate tm.tm_mday = atoi_for2(t); 4737c478bd9Sstevel@tonic-gate t += 2; 4747c478bd9Sstevel@tonic-gate tm.tm_hour = atoi_for2(t); 4757c478bd9Sstevel@tonic-gate t += 2; 4767c478bd9Sstevel@tonic-gate tm.tm_min = atoi_for2(t); 4777c478bd9Sstevel@tonic-gate break; 4787c478bd9Sstevel@tonic-gate default: 4797c478bd9Sstevel@tonic-gate touchabort(BADTIME); 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate if ((when = mktime(&tm)) == -1) 4837c478bd9Sstevel@tonic-gate touchabort(BADTIME); 4847c478bd9Sstevel@tonic-gate if (tm.tm_isdst) 4857c478bd9Sstevel@tonic-gate when -= (timezone - altzone); 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate ts->tv_sec = when; 4887c478bd9Sstevel@tonic-gate ts->tv_nsec = 0; 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate static int 4927c478bd9Sstevel@tonic-gate atoi_for2(char *p) 4937c478bd9Sstevel@tonic-gate { 4947c478bd9Sstevel@tonic-gate int value; 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate value = (*p - '0') * 10 + *(p+1) - '0'; 4977c478bd9Sstevel@tonic-gate if ((value < 0) || (value > 99)) 4987c478bd9Sstevel@tonic-gate touchabort(BADTIME); 4997c478bd9Sstevel@tonic-gate return (value); 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate static void 5037c478bd9Sstevel@tonic-gate touchabort(const char *message) 5047c478bd9Sstevel@tonic-gate { 5057c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: %s\n", myname, gettext(message)); 5067c478bd9Sstevel@tonic-gate exit(1); 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate static void 5107c478bd9Sstevel@tonic-gate usage(const int settime) 5117c478bd9Sstevel@tonic-gate { 5123b862e9aSRoger A. Faulkner if (settime) { 5137c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 514eaacacc0SMilan Jurik "usage: %s [-f file] [mmddhhmm[yy]] file...\n"), myname); 5157c478bd9Sstevel@tonic-gate exit(2); 5167c478bd9Sstevel@tonic-gate } 5173b862e9aSRoger A. Faulkner (void) fprintf(stderr, gettext( 5183b862e9aSRoger A. Faulkner "usage: %s [-acm] [-r ref_file] file...\n" 5193b862e9aSRoger A. Faulkner " %s [-acm] [-t [[CC]YY]MMDDhhmm[.SS]] file...\n" 5203b862e9aSRoger A. Faulkner " %s [-acm] [-d YYYY-MM-DDThh:mm:SS[.frac][Z]] file...\n" 5213b862e9aSRoger A. Faulkner " %s [-acm] [-d YYYY-MM-DDThh:mm:SS[,frac][Z]] file...\n" 5223b862e9aSRoger A. Faulkner " %s [-acm] [MMDDhhmm[yy]] file...\n"), 5233b862e9aSRoger A. Faulkner myname, myname, myname, myname, myname); 5243b862e9aSRoger A. Faulkner exit(2); 5257c478bd9Sstevel@tonic-gate } 526