summaryrefslogtreecommitdiff
path: root/util/sbase/touch.c
diff options
context:
space:
mode:
authorLeah Rowe <leah@libreboot.org>2025-10-04 09:14:33 +0100
committerLeah Rowe <leah@libreboot.org>2025-10-04 09:20:12 +0100
commite9a910b33c7837b4b868e3abda18eb4810df7f02 (patch)
tree749e1830cb0607952df1a1afc0ae09ec1db54140 /util/sbase/touch.c
parent2cfaba181b3c68761871fa47b32725c934423c14 (diff)
config/git: import suckless sbase
i currently use the output of sha512sum in several places of xbmk, which is a bit unreliable in case output changes. other cases where i use util outputs in variables are probably reliable, because i'm using mostly posix utilities in those. to mitigate this, i now import suckless sbase, which has a reasonable sha512sum implementation. *every* binary it builds is being placed in build.list, because i'll probably start using more of them. for example, i may start modifying the "date" implementation, adding the GNU-specific options that i need as mentioned on init.sh i'm importing it in util/ because the sha512sum util is needed for verifying project sources, so if sbase itself is a "project source", that means we can into a chicken and egg bootstrapping problem. this is sbase at revision: 055cc1ae1b3a13c3d8f25af0a4a3316590efcd48 Signed-off-by: Leah Rowe <leah@libreboot.org>
Diffstat (limited to 'util/sbase/touch.c')
-rw-r--r--util/sbase/touch.c159
1 files changed, 159 insertions, 0 deletions
diff --git a/util/sbase/touch.c b/util/sbase/touch.c
new file mode 100644
index 00000000..6e63bf80
--- /dev/null
+++ b/util/sbase/touch.c
@@ -0,0 +1,159 @@
+/* See LICENSE file for copyright and license details. */
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "util.h"
+
+static int aflag;
+static int cflag;
+static int mflag;
+static struct timespec times[2] = {{.tv_nsec = UTIME_NOW}};
+
+static void
+touch(const char *file)
+{
+ int fd, ret;
+
+ if (utimensat(AT_FDCWD, file, times, 0) == 0)
+ return;
+ if (errno != ENOENT)
+ eprintf("utimensat %s:", file);
+ if (cflag)
+ return;
+ if ((fd = open(file, O_WRONLY | O_CREAT | O_EXCL, 0666)) < 0)
+ eprintf("open %s:", file);
+ ret = futimens(fd, times);
+ close(fd);
+ if (ret < 0)
+ eprintf("futimens %s:", file);
+}
+
+static time_t
+parsetime(char *str)
+{
+ time_t now;
+ struct tm *cur, t = { 0 };
+ int zulu = 0;
+ char *format;
+ size_t len = strlen(str);
+
+ if ((now = time(NULL)) == -1)
+ eprintf("time:");
+ if (!(cur = localtime(&now)))
+ eprintf("localtime:");
+ t.tm_isdst = -1;
+
+ switch (len) {
+ /* -t flag argument */
+ case 8:
+ t.tm_year = cur->tm_year;
+ format = "%m%d%H%M";
+ break;
+ case 10:
+ format = "%y%m%d%H%M";
+ break;
+ case 11:
+ t.tm_year = cur->tm_year;
+ format = "%m%d%H%M.%S";
+ break;
+ case 12:
+ format = "%Y%m%d%H%M";
+ break;
+ case 13:
+ format = "%y%m%d%H%M.%S";
+ break;
+ case 15:
+ format = "%Y%m%d%H%M.%S";
+ break;
+ /* -d flag argument */
+ case 19:
+ format = "%Y-%m-%dT%H:%M:%S";
+ break;
+ case 20:
+ /* only Zulu-timezone supported */
+ if (str[19] != 'Z')
+ eprintf("Invalid time zone\n");
+ str[19] = 0;
+ zulu = 1;
+ format = "%Y-%m-%dT%H:%M:%S";
+ break;
+ default:
+ eprintf("Invalid date format length\n", str);
+ }
+
+ if (!strptime(str, format, &t))
+ eprintf("strptime %s: Invalid date format\n", str);
+ if (zulu) {
+ t.tm_hour += t.tm_gmtoff / 60;
+ t.tm_gmtoff = 0;
+ t.tm_zone = "Z";
+ }
+
+ return mktime(&t);
+}
+
+static void
+usage(void)
+{
+ eprintf("usage: %s [-acm] [-d time | -r ref_file | -t time | -T time] "
+ "file ...\n", argv0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct stat st;
+ char *ref = NULL;
+
+ ARGBEGIN {
+ case 'a':
+ aflag = 1;
+ break;
+ case 'c':
+ cflag = 1;
+ break;
+ case 'd':
+ case 't':
+ times[0].tv_sec = parsetime(EARGF(usage()));
+ times[0].tv_nsec = 0;
+ break;
+ case 'm':
+ mflag = 1;
+ break;
+ case 'r':
+ ref = EARGF(usage());
+ if (stat(ref, &st) < 0)
+ eprintf("stat '%s':", ref);
+ times[0] = st.st_atim;
+ times[1] = st.st_mtim;
+ break;
+ case 'T':
+ times[0].tv_sec = estrtonum(EARGF(usage()), 0, LLONG_MAX);
+ times[0].tv_nsec = 0;
+ break;
+ default:
+ usage();
+ } ARGEND
+
+ if (!argc)
+ usage();
+ if (!aflag && !mflag)
+ aflag = mflag = 1;
+ if (!ref)
+ times[1] = times[0];
+ if (!aflag)
+ times[0].tv_nsec = UTIME_OMIT;
+ if (!mflag)
+ times[1].tv_nsec = UTIME_OMIT;
+
+ for (; *argv; argc--, argv++)
+ touch(*argv);
+
+ return 0;
+}