Goto sanos source index
//
// touch.c
//
// Change file access and modification times
//
// Copyright (C) 2013 Michael Ringgaard. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. Neither the name of the project nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <shlib.h>
#include <fcntl.h>
#include <time.h>
#include <utime.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
static char *parse_num(char *str, int len, int *result) {
*result = 0;
while (len > 0) {
if (*str < '0' || *str > '9') return NULL;
*result = *result * 10 + (*str++ - '0');
len--;
}
return str;
}
static int parse_time(char *str, time_t *result) {
time_t now;
struct tm *tm;
char *dot;
int len;
time(&now);
tm = localtime(&now);
tm->tm_sec = 0;
dot = strchr(str, '.');
len = dot ? dot - str : strlen(str);
// Parse year
if (len == 12) {
str = parse_num(str, 4, &tm->tm_year);
if (!str) return 1;
tm->tm_year -= 1900;
} else if (len == 10) {
str = parse_num(str, 2, &tm->tm_year);
if (!str) return 1;
if (tm->tm_year < 69) tm->tm_year += 100;
}
// Parse month
str = parse_num(str, 2, &tm->tm_mon);
tm->tm_mon -= 1;
if (!str) return 1;
// Parse day
str = parse_num(str, 2, &tm->tm_mday);
if (!str) return 1;
// Parse hour
str = parse_num(str, 2, &tm->tm_hour);
if (!str) return 1;
// Parse minute
str = parse_num(str, 2, &tm->tm_min);
if (!str) return 1;
if (*str != 0 && *str != '.') return 1;
// Parse second
if (dot) {
str = parse_num(dot + 1, 2, &tm->tm_sec);
if (!str || *str != 0) return 1;
}
*result = mktime(tm);
return 0;
}
static void usage() {
fprintf(stderr, "usage: touch [OPTIONS] FILE...\n\n");
fprintf(stderr, " -a Change access time\n");
fprintf(stderr, " -m Change modifcation time\n");
fprintf(stderr, " -c Do not create file if it does not exist\n");
fprintf(stderr, " -r FILE Use the time of FILE instead of the current time\n");
fprintf(stderr, " -t TIME Use TIME instead of the current time ([[CC]YY]MMDDhhmm[.SS])\n");
exit(1);
}
shellcmd(touch) {
int c;
int i;
int atime = 0;
int mtime = 1;
int create = 1;
char *reffile = NULL;
char *reftime = NULL;
time_t newtime;
// Parse command line options
while ((c = getopt(argc, argv, "amcr:t:?")) != EOF) {
switch (c) {
case 'a':
atime = 1;
mtime = 0;
break;
case 'm':
atime = 0;
mtime = 1;
break;
case 'c':
create = 0;
break;
case 'r':
reffile = optarg;
break;
case 't':
reftime = optarg;
break;
case '?':
default:
usage();
}
}
if (reffile) {
struct stat st;
if (stat(reffile, &st) < 0) {
perror(reffile);
return 1;
}
newtime = st.st_mtime;
} else if (reftime) {
if (parse_time(reftime, &newtime) != 0) {
fprintf(stderr, "%s: invalid time\n", reftime);
return 1;
}
} else {
newtime = time(NULL);
}
for (i = optind; i < argc; i++) {
char *fn = argv[i];
struct utimbuf times;
// Create file if it does not exist
if (access(fn, F_OK) != 0) {
int f;
if (errno != ENOENT || !create) {
perror(fn);
return 1;
}
f = creat(fn, 0666);
if (f < 0) {
perror(fn);
return 1;
}
close(f);
}
// Change modification and/or access time
times.actime = atime ? newtime : -1;
times.modtime = mtime ? newtime : -1;
if (utime(fn, ×) < 0) {
perror(fn);
return 1;
}
}
return 0;
}