commit: 2e7604927c930e333d46a4b4c061db4601b8b672
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Sun, 15 Jun 2025 23:51:14 +0200
init
Diffstat:
5 files changed, 175 insertions(+), 0 deletions(-)
diff --git a/.clang-format b/.clang-format
@@ -0,0 +1,23 @@
+# SPDX-FileCopyrightText: 2025 Haelwenn (lanodan) Monnier <contact+cmd-timer@hacktivis.me>
+# SPDX-License-Identifier: MIT
+AlignAfterOpenBracket: true
+AlignConsecutiveAssignments: false
+AlignOperands: true
+AlignTrailingComments: true
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: true
+AllowShortIfStatementsOnASingleLine: true
+AlwaysBreakAfterReturnType: AllDefinitions
+BinPackArguments: false
+BinPackParameters: false
+BreakBeforeBraces: Allman
+SpaceBeforeParens: Never
+IncludeBlocks: Regroup
+ReflowComments: false
+SortIncludes: true
+UseTab: ForIndentation
+IndentWidth: 2
+TabWidth: 2
+ColumnLimit: 100
+
+NamespaceIndentation: All
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,4 @@
+# SPDX-FileCopyrightText: 2025 Haelwenn (lanodan) Monnier <contact+cmd-timer@hacktivis.me>
+# SPDX-License-Identifier: MIT
+
+/timer
diff --git a/LICENSES/MIT.txt b/LICENSES/MIT.txt
@@ -0,0 +1,18 @@
+MIT License
+
+Copyright (c) <year> <copyright holders>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial
+portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
+EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Makefile b/Makefile
@@ -0,0 +1,20 @@
+# SPDX-FileCopyrightText: 2025 Haelwenn (lanodan) Monnier <contact+cmd-timer@hacktivis.me>
+# SPDX-License-Identifier: MIT
+
+PREFIX ?= /usr/local
+BINDIR ?= ${PREFIX}/bin
+
+timer: timer.c
+ ${CC} -std=c99 ${CFLAGS} -o $@ $< ${LDFLAGS} $[LDSTATIC}
+
+clean:
+ rm -f timer
+
+.PHONY: format
+format:
+ clang-format -style=file -assume-filename=.clang-format -i timer.c
+
+.PHONY: install
+install:
+ mkdir -p ${DESTDIR}${BINDIR}/
+ cp -p ./timer ${DESTDIR}${BINDIR}/timer
diff --git a/timer.c b/timer.c
@@ -0,0 +1,110 @@
+// SPDX-FileCopyrightText: 2025 Haelwenn (lanodan) Monnier <contact+cmd-timer@hacktivis.me>
+// SPDX-License-Identifier: MIT
+
+#define _POSIX_C_SOURCE 200809L
+#include <errno.h>
+#include <limits.h> // UINT_MAX
+#include <signal.h> // sigaction
+#include <spawn.h> // posix_spawnp
+#include <stdio.h> // fprintf, fputs
+#include <stdlib.h> // exit
+#include <string.h> // strerror
+#include <time.h> // timer_create
+#include <unistd.h> // sleep
+
+extern char **environ;
+static char **args;
+
+static void
+sig_timer(int sig)
+{
+ pid_t child = -1;
+ errno = 0;
+ int ret = posix_spawnp(&child, args[0], NULL, NULL, args, environ);
+ if(ret != 0)
+ {
+ fprintf(stderr, "timer: error: Failed spawning command '%s': %s\n", args[0], strerror(ret));
+ exit(1);
+ }
+}
+
+static void
+bad_usage()
+{
+ fputs("Usage: timer <interval> <command> [arguments...]\n", stderr);
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ argc--;
+ argv++;
+
+ if(argc < 2)
+ {
+ fprintf(stderr, "timer: error: Got '%d' arguments instead of at least 2\n", argc);
+ bad_usage();
+ }
+
+ char *durend = NULL;
+ errno = 0;
+ unsigned long dur = strtoul(*argv, &durend, 0);
+ if(errno != 0)
+ {
+ fprintf(stderr,
+ "timer: error: Failed parsing argument '%s' as integer: %s\n",
+ *argv,
+ strerror(errno));
+ return 1;
+ }
+
+ if(dur == 0)
+ {
+ fputs("timer: error: Got a duration of 0\n", stderr);
+ return 1;
+ }
+
+ argc--;
+ argv++;
+
+ struct sigaction sa;
+ sa.sa_handler = &sig_timer;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
+
+ if(sigaction(SIGALRM, &sa, NULL) != 0)
+ {
+ fprintf(stderr, "timer: error: Failed registering signal handler: %s\n", strerror(errno));
+ return 1;
+ }
+
+ struct sigevent timer_se;
+ timer_se.sigev_signo = SIGALRM;
+ timer_se.sigev_notify = SIGEV_SIGNAL;
+
+ timer_t timer;
+ if(timer_create(0, &timer_se, &timer) != 0)
+ {
+ fprintf(stderr, "timer: error: Failed creating timer: %s\n", strerror(errno));
+ return 1;
+ }
+
+ struct itimerspec timerspec = {
+ .it_value = dur,
+ .it_interval = dur,
+ };
+
+ if(timer_settime(timer, 0, &timerspec, NULL) != 0)
+ {
+ fprintf(stderr, "timer: error: Failed setting timer: %s\n", strerror(errno));
+ return 1;
+ }
+
+ args = argv;
+
+ while(sigsuspend(&sa.sa_mask))
+ ;
+
+ return 0;
+}