1/* vi: set sw=4 ts=4: */ 2/* 3 * Mini touch implementation for busybox 4 * 5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> 6 * 7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 8 */ 9/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) 10 * 11 * Previous version called open() and then utime(). While this will be 12 * be necessary to implement -r and -t, it currently only makes things bigger. 13 * Also, exiting on a failure was a bug. All args should be processed. 14 */ 15//config:config TOUCH 16//config: bool "touch (5.9 kb)" 17//config: default y 18//config: help 19//config: touch is used to create or change the access and/or 20//config: modification timestamp of specified files. 21//config: 22//config:config FEATURE_TOUCH_SUSV3 23//config: bool "Add support for SUSV3 features (-a -d -m -t -r)" 24//config: default y 25//config: depends on TOUCH 26//config: help 27//config: Enable touch to use a reference file or a given date/time argument. 28 29//applet:IF_TOUCH(APPLET_NOFORK(touch, touch, BB_DIR_BIN, BB_SUID_DROP, touch)) 30 31//kbuild:lib-$(CONFIG_TOUCH) += touch.o 32 33//usage:#define touch_trivial_usage 34//usage: "[-ch" IF_FEATURE_TOUCH_SUSV3("am") "]" 35//usage: IF_FEATURE_TOUCH_SUSV3(" [-d DATE] [-t DATE] [-r FILE]") 36//usage: " FILE..." 37//usage:#define touch_full_usage "\n\n" 38//usage: "Update mtime of FILEs\n" 39//usage: "\n -c Don't create files" 40//usage: "\n -h Don't follow links" 41//usage: IF_FEATURE_TOUCH_SUSV3( 42//usage: "\n -a Change only atime" 43//usage: "\n -m Change only mtime" 44//usage: "\n -d DT Date/time to use" 45//usage: "\n -t DT Date/time to use" 46//usage: "\n -r FILE Use FILE's date/time" 47//usage: ) 48//usage: 49//usage:#define touch_example_usage 50//usage: "$ ls -l /tmp/foo\n" 51//usage: "/bin/ls: /tmp/foo: No such file or directory\n" 52//usage: "$ touch /tmp/foo\n" 53//usage: "$ ls -l /tmp/foo\n" 54//usage: "-rw-rw-r-- 1 andersen andersen 0 Apr 15 01:11 /tmp/foo\n" 55 56/* coreutils implements: 57 * -a change only the access time 58 * -c, --no-create 59 * do not create any files 60 * -d, --date=STRING 61 * parse STRING and use it instead of current time 62 * -f (ignored, BSD compat) 63 * -m change only the modification time 64 * -h, --no-dereference 65 * -r, --reference=FILE 66 * use this file's times instead of current time 67 * -t STAMP 68 * use [[CC]YY]MMDDhhmm[.ss] instead of current time 69 * --time=WORD 70 * change the specified time: WORD is access, atime, or use 71 */ 72 73#include "libbb.h" 74 75int touch_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 76int touch_main(int argc UNUSED_PARAM, char **argv) 77{ 78 int fd; 79 int opts; 80 smalluint status = EXIT_SUCCESS; 81#if ENABLE_FEATURE_TOUCH_SUSV3 82 char *reference_file; 83 char *date_str; 84 /* timebuf[0] is atime, timebuf[1] is mtime */ 85 struct timespec timebuf[2]; 86#else 87# define reference_file NULL 88# define date_str NULL 89# define timebuf ((struct timespec*)NULL) 90#endif 91 92 enum { 93 OPT_c = (1 << 0), 94 OPT_h = (1 << 1), 95 OPT_r = (1 << 2) * ENABLE_FEATURE_TOUCH_SUSV3, 96 OPT_d = (1 << 3) * ENABLE_FEATURE_TOUCH_SUSV3, 97 OPT_t = (1 << 4) * ENABLE_FEATURE_TOUCH_SUSV3, 98 OPT_a = (1 << 5) * ENABLE_FEATURE_TOUCH_SUSV3, 99 OPT_m = (1 << 6) * ENABLE_FEATURE_TOUCH_SUSV3, 100 }; 101#if ENABLE_LONG_OPTS 102 static const char touch_longopts[] ALIGN1 = 103 /* name, has_arg, val */ 104 "no-create\0" No_argument "c" 105 "no-dereference\0" No_argument "h" 106 IF_FEATURE_TOUCH_SUSV3("reference\0" Required_argument "r") 107 IF_FEATURE_TOUCH_SUSV3("date\0" Required_argument "d") 108 ; 109#endif 110 /* -d and -t both set time. In coreutils, 111 * accepted data format differs a bit between -d and -t. 112 * We accept the same formats for both 113 */ 114 opts = getopt32long(argv, "^" 115 "ch" 116 IF_FEATURE_TOUCH_SUSV3("r:d:t:am") 117 /*ignored:*/ "f" IF_NOT_FEATURE_TOUCH_SUSV3("am") 118 "\0" /* opt_complementary: */ 119 /* at least one arg: */ "-1" 120 /* coreutils forbids -r and -t at once: */ IF_FEATURE_TOUCH_SUSV3(":r--t:t--r") 121 /* but allows these combinations: "r--d:d--r:t--d:d--t" */ 122 , touch_longopts 123#if ENABLE_FEATURE_TOUCH_SUSV3 124 , &reference_file 125 , &date_str 126 , &date_str 127#endif 128 ); 129 130#if ENABLE_FEATURE_TOUCH_SUSV3 131 timebuf[0].tv_nsec = timebuf[1].tv_nsec = UTIME_NOW; 132 if (opts & OPT_r) { 133 struct stat stbuf; 134 xstat(reference_file, &stbuf); 135 timebuf[0].tv_sec = stbuf.st_atime; 136 timebuf[1].tv_sec = stbuf.st_mtime; 137 timebuf[0].tv_nsec = stbuf.st_atim.tv_nsec; 138 timebuf[1].tv_nsec = stbuf.st_mtim.tv_nsec; 139 } 140 if (opts & (OPT_d|OPT_t)) { 141 struct tm tm_time; 142 time_t t; 143 int check_dst; 144 145 //memset(&tm_time, 0, sizeof(tm_time)); 146 /* Better than memset: makes "HH:MM" dates meaningful */ 147 time(&t); 148 localtime_r(&t, &tm_time); 149 check_dst = parse_datestr(date_str, &tm_time); 150 151 /* Correct any day of week and day of year etc. fields */ 152 if (check_dst) 153 tm_time.tm_isdst = -1; /* recheck dst unless date is UTC */ 154 t = validate_tm_time(date_str, &tm_time); 155 156 timebuf[1].tv_sec = timebuf[0].tv_sec = t; 157 timebuf[1].tv_nsec = timebuf[0].tv_nsec = 0; 158 } 159 /* If both -a and -m specified, both times should be set. 160 * IOW: set OMIT only if one, not both, of them is given! 161 */ 162 if ((opts & (OPT_a|OPT_m)) == OPT_a) 163 timebuf[1].tv_nsec = UTIME_OMIT; 164 if ((opts & (OPT_a|OPT_m)) == OPT_m) 165 timebuf[0].tv_nsec = UTIME_OMIT; 166#endif 167 168 argv += optind; 169 do { 170 int result = utimensat(AT_FDCWD, *argv, timebuf, 171 (opts & OPT_h) ? AT_SYMLINK_NOFOLLOW : 0); 172 if (result != 0) { 173 if (errno == ENOENT) { /* no such file? */ 174 if (opts & OPT_c) { 175 /* Creation is disabled, so ignore */ 176 continue; 177 } 178 /* Try to create the file */ 179 fd = open(*argv, O_RDWR | O_CREAT, 0666); 180 if (fd >= 0) { 181 if (opts & (OPT_r|OPT_d|OPT_t)) 182 futimens(fd, timebuf); 183 xclose(fd); 184 continue; 185 } 186 } 187 status = EXIT_FAILURE; 188 bb_simple_perror_msg(*argv); 189 } 190 } while (*++argv); 191 192 return status; 193} 194