task

creates a plain-text task file in the current directory
git clone git://brookjeynes.dev/bjeynes/task.git
Log | Files | Refs | README | LICENSE

commit fce64992872e631359ff140a12f074be3468d5e4
parent 89a943569cf8f229140fbac4dce74f85ac2f0f7f
Author: brookjeynes <me@brookjeynes.dev>
Date:   Fri, 24 Jul 2026 08:11:37 +1000

feat: make posix compatible

Task-id: nntqunykwpzpuxyw
Signed-off-by: brookjeynes <me@brookjeynes.dev>

Diffstat:
Mtask.c | 70++++++++++++++++++++++++++++++++++++----------------------------------
Atasks/done/make_posix_compatible.txt | 2++
2 files changed, 38 insertions(+), 34 deletions(-)

diff --git a/task.c b/task.c @@ -1,6 +1,7 @@ #define _DEFAULT_SOURCE #include <dirent.h> #include <errno.h> +#include <fcntl.h> #include <git2.h> #include <git2/commit.h> #include <stdint.h> @@ -38,18 +39,27 @@ static int filter_entries(const struct dirent *dp) { } static int count_files_scandir(const char *dir_path) { - struct dirent **namelist; - int count; + DIR *dirp = opendir(dir_path); + if (dirp == NULL) { + return -1; + } + + int count = 0; + struct dirent *dp; + while ((dp = readdir(dirp)) != NULL) { + if (filter_entries(dp)) { + count++; + } + } - count = scandir(dir_path, &namelist, filter_entries, alphasort); - if (count == -1) { + if (errno != 0) { + closedir(dirp); return -1; } - for (int i = 0; i < count; i++) { - free(namelist[i]); + if (closedir(dirp) != 0) { + return -1; } - free(namelist); return count; } @@ -73,15 +83,7 @@ static int has_txt_extension(const char *name) { static int generate_task_id(char out[TASK_ID_CHARS + 1]) { uint8_t bytes[TASK_ID_BYTES]; - - size_t got = 0; - while (got < sizeof(bytes)) { - ssize_t n = getrandom(bytes + got, sizeof(bytes) - got, 0); - if (n == -1) { - return -1; - } - got += n; - } + arc4random_buf(bytes, sizeof(bytes)); for (size_t i = 0; i < TASK_ID_BYTES; i++) { out[i * 2] = reverse_hex[bytes[i] >> 4]; @@ -119,10 +121,6 @@ static int task_id_exists_in_dir(const char *dir, const char *id, goto cleanup; } - if (dp->d_type != DT_REG) { - continue; - } - if (has_txt_extension(dp->d_name) == 0) { continue; } @@ -262,16 +260,17 @@ static void print_properties(char identifier) { goto cleanup; } - if (dp->d_type != DT_REG) { - continue; - } - if (has_txt_extension(dp->d_name) == 0) { continue; } char path[4096]; - snprintf(path, sizeof(path), "%s/%s", TASKS_PATH, dp->d_name); + int path_len = + snprintf(path, sizeof(path), "%s/%s", TASKS_PATH, dp->d_name); + if (path_len < 0 || (size_t)path_len >= sizeof path) { + fprintf(stderr, "err: task file path too long\n"); + goto cleanup; + } fd = fopen(path, "r"); if (fd == NULL) { @@ -319,9 +318,7 @@ static void print_properties(char identifier) { goto cleanup; } - if (property_len < sizeof(property)) { - memcpy(property_ptr, property, property_len); - } + memcpy(property_ptr, property, property_len); if (properties_len == sizeof(properties) / sizeof(properties[0])) { fprintf(stderr, "err: too many properties\n"); @@ -465,22 +462,26 @@ static int new_command(int argc, char *argv[], struct options *cli_args) { struct stat st = {0}; if (stat(TASKS_PATH, &st) == -1) { - mkdir(TASKS_PATH, 0700); + if (mkdir(TASKS_PATH, 0700) == -1) { + perror("err: failed to create tasks directory"); + return 1; + }; } DIR *tasks_dir = opendir(TASKS_PATH); if (tasks_dir == NULL) { - if (errno == ENOENT) { - } - fprintf(stderr, "err: failed to check for %s: %s\n", TASKS_PATH, strerror(errno)); return 1; } closedir(tasks_dir); - FILE *f = fopen(path, "wx"); + int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0666); + FILE *f = fdopen(fd, "w"); if (f == NULL) { + if (fd != -1) { + close(fd); + } perror("err: failed to open files"); return 1; } @@ -526,6 +527,7 @@ static int new_command(int argc, char *argv[], struct options *cli_args) { char id[TASK_ID_CHARS + 1]; if (generate_unique_task_id(id) != 0) { + fclose(f); perror("err: failed to generate unique id"); return 1; } @@ -550,7 +552,7 @@ static int new_command(int argc, char *argv[], struct options *cli_args) { return 0; } - execlp("sh", "sh", "-c", "exec $1 \"$2\"", "task", editor, path, NULL); + execlp("sh", "sh", "-c", "exec \"$1\" \"$2\"", "task", editor, path, NULL); perror("err: failed to open editor"); return 1; diff --git a/tasks/done/make_posix_compatible.txt b/tasks/done/make_posix_compatible.txt @@ -0,0 +1,2 @@ +make posix compatible @feat +id: nntqunykwpzpuxyw