| 1 | /* Touch - change file access and modification times. | 
|---|
| 2 | * | 
|---|
| 3 | * Usage: see end of file | 
|---|
| 4 | * | 
|---|
| 5 | * Conforms to P1003.2 draft 10, sec. 4.62, except that time values | 
|---|
| 6 | * are not checked for validity, but passed on to mktime, so that | 
|---|
| 7 | * 9301990000 will refer to Apr. 9th 1993. As a side effect, leap | 
|---|
| 8 | * seconds are not handled correctly. | 
|---|
| 9 | * | 
|---|
| 10 | * Authors: Original author unknown. Rewritten for POSIX by | 
|---|
| 11 | *      Peter Holzer (hp@vmars.tuwien.ac.at). | 
|---|
| 12 | * | 
|---|
| 13 | * $Id: touch.c,v 1.1.1.1 2005/04/21 14:55:35 beng Exp $ | 
|---|
| 14 | * $Log: touch.c,v $ | 
|---|
| 15 | * Revision 1.1.1.1  2005/04/21 14:55:35  beng | 
|---|
| 16 | * Initial import of pre-3.0.1 | 
|---|
| 17 | * | 
|---|
| 18 | * Revision 1.1.1.1  2005/04/20 13:33:47  beng | 
|---|
| 19 | * Initial import of minix 2.0.4 | 
|---|
| 20 | * | 
|---|
| 21 | * Revision 1.8  1994/03/17  21:39:19  hjp | 
|---|
| 22 | * fixed bug with 4-digit years | 
|---|
| 23 | * | 
|---|
| 24 | * Revision 1.7  1994/03/15  00:43:27  hjp | 
|---|
| 25 | * Changes from kjb (vmd 1.6.25.1): | 
|---|
| 26 | * fixed exit code | 
|---|
| 27 | * nonstandard flag 0 to make file very old | 
|---|
| 28 | * | 
|---|
| 29 | * Revision 1.6  1994/02/12  17:26:33  hjp | 
|---|
| 30 | * fixed -a and -m flags | 
|---|
| 31 | * | 
|---|
| 32 | * Revision 1.5  1994/02/12  16:04:13  hjp | 
|---|
| 33 | * fixed bug when -t argument was not given | 
|---|
| 34 | * removed debugging code | 
|---|
| 35 | * run through pretty to get Minix layout | 
|---|
| 36 | * | 
|---|
| 37 | * Revision 1.4  1994/02/07  21:23:11  hjp | 
|---|
| 38 | * POSIXified. | 
|---|
| 39 | * | 
|---|
| 40 | */ | 
|---|
| 41 |  | 
|---|
| 42 | #define _POSIX_C_SOURCE 2       /* getopt */ | 
|---|
| 43 | #include <assert.h> | 
|---|
| 44 | #include <ctype.h> | 
|---|
| 45 | #include <sys/types.h> | 
|---|
| 46 | #include <sys/stat.h> | 
|---|
| 47 | #include <errno.h> | 
|---|
| 48 | #include <stdlib.h> | 
|---|
| 49 | #include <stdio.h> | 
|---|
| 50 | #include <string.h> | 
|---|
| 51 | #include <time.h> | 
|---|
| 52 | #include <fcntl.h> | 
|---|
| 53 | #include <unistd.h> | 
|---|
| 54 | #include <utime.h> | 
|---|
| 55 |  | 
|---|
| 56 | #define val2(string) ((string)[0] * 10 + (string)[1] - '0' * 11) | 
|---|
| 57 | #define val4(string) (val2(string) * 100 + val2(string + 2)) | 
|---|
| 58 |  | 
|---|
| 59 | typedef enum { | 
|---|
| 60 | OLD, NEW | 
|---|
| 61 | } formatT; | 
|---|
| 62 |  | 
|---|
| 63 | char *cmnd; | 
|---|
| 64 | int no_creat = 0; | 
|---|
| 65 | unsigned int to_change = 0; | 
|---|
| 66 | #       define ATIME    1 | 
|---|
| 67 | #       define MTIME    2 | 
|---|
| 68 |  | 
|---|
| 69 | _PROTOTYPE(int main, (int argc, char **argv)); | 
|---|
| 70 | _PROTOTYPE(int doit, (char *name, struct utimbuf tvp)); | 
|---|
| 71 | _PROTOTYPE(void usage, (void)); | 
|---|
| 72 | _PROTOTYPE(time_t parsetime, (const char *string, formatT format)); | 
|---|
| 73 |  | 
|---|
| 74 | time_t parsetime(string, format) | 
|---|
| 75 | const char *string; | 
|---|
| 76 | formatT format; | 
|---|
| 77 | { | 
|---|
| 78 | struct tm tm; | 
|---|
| 79 | time_t touchtime; | 
|---|
| 80 | size_t l; | 
|---|
| 81 |  | 
|---|
| 82 | l = strspn(string, "0123456789"); | 
|---|
| 83 | if (l % 2 == 1) return -1; | 
|---|
| 84 | if (string[l] != '\0' && (string[l] != '.' || format == OLD)) { | 
|---|
| 85 | return -1; | 
|---|
| 86 | } | 
|---|
| 87 | if (format == OLD) { | 
|---|
| 88 | if (l == 10) { | 
|---|
| 89 | /* Last two digits are year */ | 
|---|
| 90 | tm.tm_year = val2(string + 8); | 
|---|
| 91 | if (tm.tm_year <= 68) tm.tm_year += 100; | 
|---|
| 92 | } else if (l == 8) { | 
|---|
| 93 | time(&touchtime); | 
|---|
| 94 | tm = *localtime(&touchtime); | 
|---|
| 95 | } else { | 
|---|
| 96 | return -1; | 
|---|
| 97 | } | 
|---|
| 98 | } else { | 
|---|
| 99 | if (l == 12) { | 
|---|
| 100 | /* First four digits are year */ | 
|---|
| 101 | tm.tm_year = val4(string) - 1900; | 
|---|
| 102 | string += 4; | 
|---|
| 103 | } else if (l == 10) { | 
|---|
| 104 | /* First two digits are year */ | 
|---|
| 105 | tm.tm_year = val2(string); | 
|---|
| 106 | if (tm.tm_year <= 68) tm.tm_year += 100; | 
|---|
| 107 | string += 2; | 
|---|
| 108 | } else if (l == 8) { | 
|---|
| 109 | time(&touchtime); | 
|---|
| 110 | tm = *localtime(&touchtime); | 
|---|
| 111 | } else { | 
|---|
| 112 | return -1; | 
|---|
| 113 | } | 
|---|
| 114 | } | 
|---|
| 115 | tm.tm_mon = val2(string) - 1; | 
|---|
| 116 | string += 2; | 
|---|
| 117 | tm.tm_mday = val2(string); | 
|---|
| 118 | string += 2; | 
|---|
| 119 | tm.tm_hour = val2(string); | 
|---|
| 120 | string += 2; | 
|---|
| 121 | tm.tm_min = val2(string); | 
|---|
| 122 | string += 2; | 
|---|
| 123 | if (format == NEW && string[0] == '.') { | 
|---|
| 124 | if (isdigit(string[1]) && isdigit(string[2]) && | 
|---|
| 125 | string[3] == '\0') { | 
|---|
| 126 | tm.tm_sec = val2(string + 1); | 
|---|
| 127 | } else { | 
|---|
| 128 | return -1; | 
|---|
| 129 | } | 
|---|
| 130 | } else { | 
|---|
| 131 | tm.tm_sec = 0; | 
|---|
| 132 | } | 
|---|
| 133 | tm.tm_isdst = -1; | 
|---|
| 134 | touchtime = mktime(&tm); | 
|---|
| 135 | return touchtime; | 
|---|
| 136 | } | 
|---|
| 137 |  | 
|---|
| 138 |  | 
|---|
| 139 | int main(argc, argv) | 
|---|
| 140 | int argc; | 
|---|
| 141 | char **argv; | 
|---|
| 142 | { | 
|---|
| 143 | time_t auxtime; | 
|---|
| 144 | struct stat sb; | 
|---|
| 145 | int c; | 
|---|
| 146 | struct utimbuf touchtimes; | 
|---|
| 147 | int fail = 0; | 
|---|
| 148 |  | 
|---|
| 149 | cmnd = argv[0]; | 
|---|
| 150 | auxtime = time((time_t *) NULL); | 
|---|
| 151 | touchtimes.modtime = auxtime; | 
|---|
| 152 | touchtimes.actime = auxtime; | 
|---|
| 153 |  | 
|---|
| 154 | while ((c = getopt(argc, argv, "r:t:acm0")) != EOF) { | 
|---|
| 155 | switch (c) { | 
|---|
| 156 | case 'r': | 
|---|
| 157 | if (stat(optarg, &sb) == -1) { | 
|---|
| 158 | fprintf(stderr, "%s: cannot stat %s: %s\n", | 
|---|
| 159 | cmnd, optarg, strerror(errno)); | 
|---|
| 160 | exit(1); | 
|---|
| 161 | } | 
|---|
| 162 | touchtimes.modtime = sb.st_mtime; | 
|---|
| 163 | touchtimes.actime = sb.st_atime; | 
|---|
| 164 | break; | 
|---|
| 165 | case 't': | 
|---|
| 166 | auxtime = parsetime(optarg, NEW); | 
|---|
| 167 | if (auxtime == (time_t) - 1) usage(); | 
|---|
| 168 | touchtimes.modtime = auxtime; | 
|---|
| 169 | touchtimes.actime = auxtime; | 
|---|
| 170 | break; | 
|---|
| 171 | case 'a':   to_change |= ATIME;     break; | 
|---|
| 172 | case 'm':   to_change |= MTIME;     break; | 
|---|
| 173 | case 'c':   no_creat = 1;   break; | 
|---|
| 174 | case '0': | 
|---|
| 175 | touchtimes.modtime = touchtimes.actime = 0; | 
|---|
| 176 | break; | 
|---|
| 177 | case '?':   usage();        break; | 
|---|
| 178 | default:    assert(0); | 
|---|
| 179 | } | 
|---|
| 180 | } | 
|---|
| 181 | if (to_change == 0) { | 
|---|
| 182 | to_change = ATIME | MTIME; | 
|---|
| 183 | } | 
|---|
| 184 | if (optind == argc) usage(); | 
|---|
| 185 |  | 
|---|
| 186 | /* Now check for old style time argument */ | 
|---|
| 187 | if (strcmp(argv[optind - 1], "--") != 0 && | 
|---|
| 188 | (auxtime = parsetime(argv[optind], OLD)) != (time_t) - 1) { | 
|---|
| 189 | touchtimes.modtime = auxtime; | 
|---|
| 190 | touchtimes.actime = auxtime; | 
|---|
| 191 | optind++; | 
|---|
| 192 | if (optind == argc) usage(); | 
|---|
| 193 | } | 
|---|
| 194 | while (optind < argc) { | 
|---|
| 195 | if (doit(argv[optind], touchtimes) > 0) { | 
|---|
| 196 | fprintf(stderr, "%s: cannot touch %s: %s\n", | 
|---|
| 197 | cmnd, argv[optind], strerror(errno)); | 
|---|
| 198 | fail = 1; | 
|---|
| 199 | } | 
|---|
| 200 | optind++; | 
|---|
| 201 | } | 
|---|
| 202 | return fail ? 1 : 0; | 
|---|
| 203 | } | 
|---|
| 204 |  | 
|---|
| 205 |  | 
|---|
| 206 | int doit(name, tvp) | 
|---|
| 207 | char *name; | 
|---|
| 208 | struct utimbuf tvp; | 
|---|
| 209 | { | 
|---|
| 210 | int fd; | 
|---|
| 211 | struct stat sb; | 
|---|
| 212 |  | 
|---|
| 213 | if (to_change != (ATIME | MTIME)) { | 
|---|
| 214 |  | 
|---|
| 215 | if (stat(name, &sb) != -1) { | 
|---|
| 216 | if (!(to_change & ATIME)) { | 
|---|
| 217 | tvp.actime = sb.st_atime; | 
|---|
| 218 | } else { | 
|---|
| 219 | tvp.modtime = sb.st_mtime; | 
|---|
| 220 | } | 
|---|
| 221 | } | 
|---|
| 222 | } | 
|---|
| 223 | if (utime(name, &tvp) == 0) return 0; | 
|---|
| 224 | if (errno != ENOENT) return 1; | 
|---|
| 225 | if (no_creat == 1) return 0; | 
|---|
| 226 | if ((fd = creat(name, 0666)) >= 0) { | 
|---|
| 227 | if (fstat(fd, &sb) != -1) { | 
|---|
| 228 | if (!(to_change & ATIME)) { | 
|---|
| 229 | tvp.actime = sb.st_atime; | 
|---|
| 230 | } else { | 
|---|
| 231 | tvp.modtime = sb.st_mtime; | 
|---|
| 232 | } | 
|---|
| 233 | } else { | 
|---|
| 234 | assert(0); | 
|---|
| 235 | } | 
|---|
| 236 | close(fd); | 
|---|
| 237 | if (utime(name, &tvp) == 0) return 0; | 
|---|
| 238 | } | 
|---|
| 239 | return 1; | 
|---|
| 240 | } | 
|---|
| 241 |  | 
|---|
| 242 |  | 
|---|
| 243 | void usage() | 
|---|
| 244 | { | 
|---|
| 245 | fprintf(stderr, "Usage: %s [-c] [-a] [-m] [-r file] [-t [CC[YY]]MMDDhhmm[.ss]] " | 
|---|
| 246 | "[MMDDhhmm[YY]] file...\n", cmnd); | 
|---|
| 247 | exit(1); | 
|---|
| 248 | } | 
|---|