touch.c revision 3b862e9a9ce59d5dbf0177b9eb293109fde6bf36
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
* 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 2009 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 */
#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 <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_datetime(char *, timespec_t *);
static void parse_time(char *, timespec_t *);
static void parse_timespec(char *, timespec_t *);
int
{
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 = -1;
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
cflag++;
stflag++;
switch (optc) {
case 'f':
rflag++;
usecurrenttime = 0;
return (2);
}
break;
case '?':
break;
}
}
} else {
switch (optc) {
case 'a':
aflag++;
break;
case 'c':
cflag++;
break;
case 'f': /* silently ignore for UCB compat */
break;
case 'm':
mflag++;
break;
case 'r': /* same as settime's -f option */
rflag++;
usecurrenttime = 0;
return (2);
}
break;
case 'd':
tflag++;
usecurrenttime = 0;
break;
case 't':
tflag++;
usecurrenttime = 0;
break;
case '?':
break;
}
}
}
aflag = 1;
mflag = 1;
}
usecurrenttime = 0;
/*
* If -r, -t or -d has been specified,
* use the specified time.
*/
/*
* time is specified as an operand; use it.
*/
usecurrenttime = 0;
timespecified = 1;
argc--;
}
for (c = 0; c < argc; c++) {
/*
* If stat failed for reasons other than EOVERFLOW or
* ENOENT, the file should not be created, since this
* can clobber the contents of an existing file.
*/
/*
* Since we have EOVERFLOW,
* we know the file exists.
*/
/* EMPTY */;
gettext("%s: cannot stat %s: %s\n"),
status++;
continue;
} else if (cflag) {
continue;
gettext("%s: cannot create %s: %s\n"),
status++;
continue;
}
}
if (usecurrenttime) {
} else {
if (mflag == 0) {
/* Keep the mtime of the file */
} else if (timespecified) {
/* Set the specified time */
} else {
/* Otherwise, use the current time */
}
if (aflag == 0) {
/* Keep the atime of the file */
} else if (timespecified) {
/* Set the specified time */
} else {
/* Otherwise, use the current time */
}
}
gettext("%s: cannot change times on %s: %s\n"),
status++;
}
if (fd >= 0) {
fd = -1;
}
}
return (status);
}
static int
isnumber(char *s)
{
int c;
while ((c = *s++) != '\0')
if (!isdigit(c))
return (0);
return (1);
}
static void
{
char date[64];
char *year;
char *month;
char *day;
char *hour;
char *minute;
char *second;
char *fraction;
int utc = 0;
char *p;
int nanoseconds;
/*
* The date string has the format (defined by the touch(1) spec):
* YYYY-MM-DDThh:mm:SS[.frac][tz]
* YYYY-MM-DDThh:mm:SS[,frac][tz]
* T is either the literal 'T' or is a space character.
* tz is either empty (local time) or the literal 'Z' (UTC).
* All other fields are strings of digits.
*/
/*
* Make a copy of the date string so it can be tokenized.
*/
/* deal with the optional trailing 'Z' first */
if (*p == 'Z') {
utc = 1;
*p = '\0';
}
/* break out the component tokens */
p = date;
fraction = p;
/* verify the component tokens */
if (utc) {
tzset();
}
errno = 0;
nanoseconds = 0;
} else {
/* truncate beyond 9 digits (nanoseconds) */
case 1:
nanoseconds *= 100000000;
break;
case 2:
nanoseconds *= 10000000;
break;
case 3:
nanoseconds *= 1000000;
break;
case 4:
nanoseconds *= 100000;
break;
case 5:
nanoseconds *= 10000;
break;
case 6:
nanoseconds *= 1000;
break;
case 7:
nanoseconds *= 100;
break;
case 8:
nanoseconds *= 10;
break;
case 9:
break;
}
}
}
static void
{
int century = 0;
int seconds = 0;
char *p;
/*
* time in the following format (defined by the touch(1) spec):
* [[CC]YY]MMDDhhmm[.SS]
*/
*p = '\0';
}
switch (strlen(t)) {
case 12: /* CCYYMMDDhhmm */
t += 2;
/* FALLTHROUGH */
case 10: /* YYMMDDhhmm */
t += 2;
if (century == 0) {
} else
/* FALLTHROUGH */
case 8: /* MMDDhhmm */
t += 2;
t += 2;
t += 2;
break;
default:
}
}
static void
{
/*
* time in the following format (defined by the touch(1) spec):
* MMDDhhmm[yy]
*/
switch (strlen(t)) {
case 10: /* MMDDhhmmyy */
/* FALLTHROUGH */
case 8: /* MMDDhhmm */
t += 2;
t += 2;
t += 2;
break;
default:
}
}
static int
atoi_for2(char *p)
{
int value;
return (value);
}
static void
touchabort(const char *message)
{
exit(1);
}
static void
{
if (settime) {
"usage: %s [-f file] [mmddhhmm[yy]] file...\n"), myname);
exit(2);
}
"usage: %s [-acm] [-r ref_file] file...\n"
" %s [-acm] [-t [[CC]YY]MMDDhhmm[.SS]] file...\n"
" %s [-acm] [-d YYYY-MM-DDThh:mm:SS[.frac][Z]] file...\n"
" %s [-acm] [-d YYYY-MM-DDThh:mm:SS[,frac][Z]] file...\n"
" %s [-acm] [MMDDhhmm[yy]] file...\n"),
exit(2);
}