touch.c - sbase - suckless unix tools
 (HTM) git clone git://git.suckless.org/sbase
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       touch.c (2796B)
       ---
            1 /* See LICENSE file for copyright and license details. */
            2 #include <sys/stat.h>
            3 
            4 #include <errno.h>
            5 #include <fcntl.h>
            6 #include <stdlib.h>
            7 #include <string.h>
            8 #include <time.h>
            9 #include <unistd.h>
           10 
           11 #include "util.h"
           12 
           13 static int aflag;
           14 static int cflag;
           15 static int mflag;
           16 static struct timespec times[2] = {{.tv_nsec = UTIME_NOW}};
           17 
           18 static void
           19 touch(const char *file)
           20 {
           21         int fd, ret;
           22 
           23         if (utimensat(AT_FDCWD, file, times, 0) == 0)
           24                 return;
           25         if (errno != ENOENT)
           26                 eprintf("utimensat %s:", file);
           27         if (cflag)
           28                 return;
           29         if ((fd = open(file, O_WRONLY | O_CREAT | O_EXCL, 0666)) < 0)
           30                 eprintf("open %s:", file);
           31         ret = futimens(fd, times);
           32         close(fd);
           33         if (ret < 0)
           34                 eprintf("futimens %s:", file);
           35 }
           36 
           37 static time_t
           38 parsetime(char *str)
           39 {
           40         time_t now;
           41         struct tm *cur, t = { 0 };
           42         int zulu = 0;
           43         char *format;
           44         size_t len = strlen(str);
           45 
           46         if ((now = time(NULL)) == -1)
           47                 eprintf("time:");
           48         if (!(cur = localtime(&now)))
           49                 eprintf("localtime:");
           50         t.tm_isdst = -1;
           51 
           52         switch (len) {
           53         /* -t flag argument */
           54         case 8:
           55                 t.tm_year = cur->tm_year;
           56                 format = "%m%d%H%M";
           57                 break;
           58         case 10:
           59                 format = "%y%m%d%H%M";
           60                 break;
           61         case 11:
           62                 t.tm_year = cur->tm_year;
           63                 format = "%m%d%H%M.%S";
           64                 break;
           65         case 12:
           66                 format = "%Y%m%d%H%M";
           67                 break;
           68         case 13:
           69                 format = "%y%m%d%H%M.%S";
           70                 break;
           71         case 15:
           72                 format = "%Y%m%d%H%M.%S";
           73                 break;
           74         /* -d flag argument */
           75         case 19:
           76                 format = "%Y-%m-%dT%H:%M:%S";
           77                 break;
           78         case 20:
           79                 /* only Zulu-timezone supported */
           80                 if (str[19] != 'Z')
           81                         eprintf("Invalid time zone\n");
           82                 str[19] = 0;
           83                 zulu = 1;
           84                 format = "%Y-%m-%dT%H:%M:%S";
           85                 break;
           86         default:
           87                 eprintf("Invalid date format length\n", str);
           88         }
           89 
           90         if (!strptime(str, format, &t))
           91                 eprintf("strptime %s: Invalid date format\n", str);
           92         if (zulu) {
           93                 t.tm_hour += t.tm_gmtoff / 60;
           94                 t.tm_gmtoff = 0;
           95                 t.tm_zone = "Z";
           96         }
           97 
           98         return mktime(&t);
           99 }
          100 
          101 static void
          102 usage(void)
          103 {
          104         eprintf("usage: %s [-acm] [-d time | -r ref_file | -t time | -T time] "
          105                 "file ...\n", argv0);
          106 }
          107 
          108 int
          109 main(int argc, char *argv[])
          110 {
          111         struct stat st;
          112         char *ref = NULL;
          113 
          114         ARGBEGIN {
          115         case 'a':
          116                 aflag = 1;
          117                 break;
          118         case 'c':
          119                 cflag = 1;
          120                 break;
          121         case 'd':
          122         case 't':
          123                 times[0].tv_sec = parsetime(EARGF(usage()));
          124                 times[0].tv_nsec = 0;
          125                 break;
          126         case 'm':
          127                 mflag = 1;
          128                 break;
          129         case 'r':
          130                 ref = EARGF(usage());
          131                 if (stat(ref, &st) < 0)
          132                         eprintf("stat '%s':", ref);
          133                 times[0] = st.st_atim;
          134                 times[1] = st.st_mtim;
          135                 break;
          136         case 'T':
          137                 times[0].tv_sec = estrtonum(EARGF(usage()), 0, LLONG_MAX);
          138                 times[0].tv_nsec = 0;
          139                 break;
          140         default:
          141                 usage();
          142         } ARGEND
          143 
          144         if (!argc)
          145                 usage();
          146         if (!aflag && !mflag)
          147                 aflag = mflag = 1;
          148         if (!ref)
          149                 times[1] = times[0];
          150         if (!aflag)
          151                 times[0].tv_nsec = UTIME_OMIT;
          152         if (!mflag)
          153                 times[1].tv_nsec = UTIME_OMIT;
          154 
          155         for (; *argv; argc--, argv++)
          156                 touch(*argv);
          157 
          158         return 0;
          159 }