#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#define isleap(y) (((y) % 4) == 0 && ((y) % 100) != 0 || ((y) % 400) == 0)
struct stat stbuf;
int status;
#ifdef S5EMUL
int dmsize[12]={31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
#endif
static char usage[] =
#ifdef S5EMUL
"[-amc] [mmddhhmm[yy]]";
#else
"[-amcf]";
int force = 0;
int nowrite;
#endif
int mflg=1, aflg=1, cflg=0, nflg=0;
char *prog;
#ifdef S5EMUL
char *cbp;
#endif
time_t time();
off_t lseek();
time_t timelocal(), timegm();
struct timeval timbuf;
static void timestruc_to_timeval(timestruc_t *, struct timeval *);
#ifdef S5EMUL
struct tm *
gtime()
{
static struct tm newtime;
long nt;
newtime.tm_mon = gpair() - 1;
newtime.tm_mday = gpair();
newtime.tm_hour = gpair();
if (newtime.tm_hour == 24) {
newtime.tm_hour = 0;
newtime.tm_mday++;
}
newtime.tm_min = gpair();
newtime.tm_sec = 0;
newtime.tm_year = gpair();
if (newtime.tm_year < 0) {
(void) time(&nt);
newtime.tm_year = localtime(&nt)->tm_year;
}
return (&newtime);
}
gpair()
{
int c, d;
char *cp;
cp = cbp;
if (*cp == 0)
return (-1);
c = (*cp++ - '0') * 10;
if (c<0 || c>100)
return (-1);
if (*cp == 0)
return (-1);
if ((d = *cp++ - '0') < 0 || d > 9)
return (-1);
cbp = cp;
return (c+d);
}
#endif
int
main(int argc, char *argv[])
{
int c;
#ifdef S5EMUL
int days_in_month;
struct tm *tp;
#endif
int errflg=0, optc;
extern char *optarg;
extern int optind;
extern int opterr;
prog = argv[0];
opterr = 0;
while ((optc=getopt(argc, argv, "amcf")) != EOF)
switch (optc) {
case 'm':
mflg++;
aflg--;
break;
case 'a':
aflg++;
mflg--;
break;
case 'c':
cflg++;
break;
#ifndef S5EMUL
case 'f':
force++;
break;
#endif
case '?':
errflg++;
}
if (((argc-optind) < 1) || errflg) {
(void) fprintf(stderr, "usage: %s %s file ...\n", prog, usage);
exit(2);
}
status = 0;
#ifdef S5EMUL
if (!isnumber(argv[optind])) {
#endif
if ((aflg <= 0) || (mflg <= 0))
(void) gettimeofday(&timbuf, NULL);
else
nflg++;
#ifdef S5EMUL
} else {
cbp = (char *)argv[optind++];
if ((tp = gtime()) == NULL) {
(void) fprintf(stderr, "%s: bad date conversion\n",
prog);
exit(2);
}
days_in_month = dmsize[tp->tm_mon];
if (tp->tm_mon == 1 && isleap(tp->tm_year + 1900))
days_in_month = 29;
if (tp->tm_mon < 0 || tp->tm_mon > 11 ||
tp->tm_mday < 1 || tp->tm_mday > days_in_month ||
tp->tm_hour < 0 || tp->tm_hour > 23 ||
tp->tm_min < 0 || tp->tm_min > 59 ||
tp->tm_sec < 0 || tp->tm_sec > 59) {
(void) fprintf(stderr, "%s: bad date conversion\n",
prog);
exit(2);
}
timbuf = timelocal(tp);
}
#endif
for (c = optind; c < argc; c++) {
if (touch(argv[c]) < 0)
status++;
}
return (status);
}
int
touch(filename)
char *filename;
{
struct timeval times[2];
int fd;
if (stat(filename, &stbuf)) {
if (errno != ENOENT) {
(void) fprintf(stderr,"%s: cannot stat ", prog);
perror(filename);
return (-1);
} else if (cflg) {
return (-1);
}
else if ((fd = creat(filename, 0666)) < 0) {
(void) fprintf(stderr, "%s: cannot create ", prog);
perror(filename);
return (-1);
}
else {
(void) close(fd);
if (stat(filename, &stbuf)) {
(void) fprintf(stderr,"%s: cannot stat ", prog);
perror(filename);
return (-1);
}
}
if (nflg)
return (0);
}
times[0] = times[1] = timbuf;
if (mflg <= 0)
timestruc_to_timeval(&stbuf.st_mtim, times + 1);
if (aflg <= 0)
timestruc_to_timeval(&stbuf.st_atim, times);
#ifndef S5EMUL
nowrite = access(filename, R_OK|W_OK);
if (nowrite && !force) {
(void) fprintf(stderr,
"%s: cannot touch %s: no write permission\n",
prog, filename);
return (-1);
}
#endif
if (utimes(filename, nflg ? NULL : times)) {
if (nflg && (errno != EROFS) && (errno != EACCES)) {
return (oldtouch(filename, &stbuf));
}
(void) fprintf(stderr,"%s: cannot change times on ", prog);
perror(filename);
return (-1);
}
return (0);
}
int
oldtouch(filename, statp)
char *filename;
struct stat *statp;
{
int rwstatus;
if ((statp->st_mode & S_IFMT) != S_IFREG) {
(void) fprintf(stderr,
"%s: %s: only owner may touch special files on this filesystem\n",
prog, filename);
return (-1);
}
#ifndef S5EMUL
if (nowrite && force) {
if (chmod(filename, 0666)) {
fprintf(stderr, "%s: could not chmod ", prog);
perror(filename);
return (-1);
}
rwstatus = readwrite(filename, statp->st_size);
if (chmod(filename, (int)statp->st_mode)) {
fprintf(stderr, "%s: could not chmod back ", prog);
perror(filename);
return (-1);
}
return (rwstatus);
} else
#endif
return (readwrite(filename, statp->st_size));
}
int
readwrite(filename, size)
char *filename;
off_t size;
{
int fd;
char first;
if (size) {
if ((fd = open(filename, 2)) < 0)
goto error;
if (read(fd, &first, 1) != 1)
goto closeerror;
if (lseek(fd, 0L, 0) == -1)
goto closeerror;
if (write(fd, &first, 1) != 1)
goto closeerror;
} else {
if ((fd = creat(filename, 0666)) < 0)
goto error;
}
if (close(fd) < 0)
goto error;
return (0);
closeerror:
(void) close(fd);
error:
(void) fprintf(stderr, "%s: could not touch ", prog);
perror(filename);
return (-1);
}
#ifdef S5EMUL
isnumber(s)
char *s;
{
char c;
while (c = *s++)
if (!isdigit(c))
return (0);
return (1);
}
#endif
static void
timestruc_to_timeval(timestruc_t *ts, struct timeval *tv)
{
tv->tv_sec = ts->tv_sec;
tv->tv_usec = ts->tv_nsec / 1000;
}