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.8 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_NODEREF 23//config: bool "Add support for -h" 24//config: default y 25//config: depends on TOUCH 26//config: help 27//config: Enable touch to have the -h option. 28//config: This requires libc support for lutimes() function. 29//config: 30//config:config FEATURE_TOUCH_SUSV3 31//config: bool "Add support for SUSV3 features (-d -t -r)" 32//config: default y 33//config: depends on TOUCH 34//config: help 35//config: Enable touch to use a reference file or a given date/time argument. 36 37//applet:IF_TOUCH(APPLET_NOFORK(touch, touch, BB_DIR_BIN, BB_SUID_DROP, touch)) 38 39//kbuild:lib-$(CONFIG_TOUCH) += touch.o 40 41/* BB_AUDIT SUSv3 _NOT_ compliant -- options -a, -m not supported. */ 42/* http://www.opengroup.org/onlinepubs/007904975/utilities/touch.html */ 43 44//usage:#define touch_trivial_usage 45//usage: "[-c]" IF_FEATURE_TOUCH_SUSV3(" [-d DATE] [-t DATE] [-r FILE]") " FILE..." 46//usage:#define touch_full_usage "\n\n" 47//usage: "Update the last-modified date on the given FILE[s]\n" 48//usage: "\n -c Don't create files" 49//usage: IF_FEATURE_TOUCH_NODEREF( 50//usage: "\n -h Don't follow links" 51//usage: ) 52//usage: IF_FEATURE_TOUCH_SUSV3( 53//usage: "\n -d DT Date/time to use" 54//usage: "\n -t DT Date/time to use" 55//usage: "\n -r FILE Use FILE's date/time" 56//usage: ) 57//usage: 58//usage:#define touch_example_usage 59//usage: "$ ls -l /tmp/foo\n" 60//usage: "/bin/ls: /tmp/foo: No such file or directory\n" 61//usage: "$ touch /tmp/foo\n" 62//usage: "$ ls -l /tmp/foo\n" 63//usage: "-rw-rw-r-- 1 andersen andersen 0 Apr 15 01:11 /tmp/foo\n" 64 65/* coreutils implements: 66 * -a change only the access time 67 * -c, --no-create 68 * do not create any files 69 * -d, --date=STRING 70 * parse STRING and use it instead of current time 71 * -f (ignored, BSD compat) 72 * -m change only the modification time 73 * -h, --no-dereference 74 * -r, --reference=FILE 75 * use this file's times instead of current time 76 * -t STAMP 77 * use [[CC]YY]MMDDhhmm[.ss] instead of current time 78 * --time=WORD 79 * change the specified time: WORD is access, atime, or use 80 */ 81 82#include "libbb.h" 83 84int touch_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 85int touch_main(int argc UNUSED_PARAM, char **argv) 86{ 87 int fd; 88 int status = EXIT_SUCCESS; 89 int opts; 90 enum { 91 OPT_c = (1 << 0), 92 OPT_r = (1 << 1) * ENABLE_FEATURE_TOUCH_SUSV3, 93 OPT_d = (1 << 2) * ENABLE_FEATURE_TOUCH_SUSV3, 94 OPT_t = (1 << 3) * ENABLE_FEATURE_TOUCH_SUSV3, 95 OPT_h = (1 << 4) * ENABLE_FEATURE_TOUCH_NODEREF, 96 }; 97#if ENABLE_FEATURE_TOUCH_SUSV3 98# if ENABLE_LONG_OPTS 99 static const char touch_longopts[] ALIGN1 = 100 /* name, has_arg, val */ 101 "no-create\0" No_argument "c" 102 "reference\0" Required_argument "r" 103 "date\0" Required_argument "d" 104 IF_FEATURE_TOUCH_NODEREF("no-dereference\0" No_argument "h") 105 ; 106# define GETOPT32 getopt32long 107# define LONGOPTS ,touch_longopts 108# else 109# define GETOPT32 getopt32 110# define LONGOPTS 111# endif 112 char *reference_file = NULL; 113 char *date_str = NULL; 114 struct timeval timebuf[2]; 115 timebuf[1].tv_usec = timebuf[0].tv_usec = 0; 116#else 117# define reference_file NULL 118# define date_str NULL 119# define timebuf ((struct timeval*)NULL) 120# define GETOPT32 getopt32 121# define LONGOPTS 122#endif 123 124 /* -d and -t both set time. In coreutils, 125 * accepted data format differs a bit between -d and -t. 126 * We accept the same formats for both */ 127 opts = GETOPT32(argv, "c" IF_FEATURE_TOUCH_SUSV3("r:d:t:") 128 IF_FEATURE_TOUCH_NODEREF("h") 129 /*ignored:*/ "fma" 130 LONGOPTS 131 IF_FEATURE_TOUCH_SUSV3(, &reference_file) 132 IF_FEATURE_TOUCH_SUSV3(, &date_str) 133 IF_FEATURE_TOUCH_SUSV3(, &date_str) 134 ); 135 136 argv += optind; 137 if (!*argv) { 138 bb_show_usage(); 139 } 140 141 if (reference_file) { 142 struct stat stbuf; 143 xstat(reference_file, &stbuf); 144 timebuf[1].tv_sec = timebuf[0].tv_sec = stbuf.st_mtime; 145 /* Can use .st_mtim.tv_nsec 146 * (or is it .st_mtimensec?? see date.c) 147 * to set microseconds too. 148 */ 149 } 150 151 if (date_str) { 152 struct tm tm_time; 153 time_t t; 154 155 //memset(&tm_time, 0, sizeof(tm_time)); 156 /* Better than memset: makes "HH:MM" dates meaningful */ 157 time(&t); 158 localtime_r(&t, &tm_time); 159 parse_datestr(date_str, &tm_time); 160 161 /* Correct any day of week and day of year etc. fields */ 162 tm_time.tm_isdst = -1; /* Be sure to recheck dst */ 163 t = validate_tm_time(date_str, &tm_time); 164 165 timebuf[1].tv_sec = timebuf[0].tv_sec = t; 166 } 167 168 do { 169 int result; 170 result = ( 171#if ENABLE_FEATURE_TOUCH_NODEREF 172 (opts & OPT_h) ? lutimes : 173#endif 174 utimes)(*argv, (reference_file || date_str) ? timebuf : NULL); 175 if (result != 0) { 176 if (errno == ENOENT) { /* no such file? */ 177 if (opts & OPT_c) { 178 /* Creation is disabled, so ignore */ 179 continue; 180 } 181 /* Try to create the file */ 182 fd = open(*argv, O_RDWR | O_CREAT, 0666); 183 if (fd >= 0) { 184 xclose(fd); 185 if (reference_file || date_str) 186 utimes(*argv, timebuf); 187 continue; 188 } 189 } 190 status = EXIT_FAILURE; 191 bb_simple_perror_msg(*argv); 192 } 193 } while (*++argv); 194 195 return status; 196} 197