diff options
| -rw-r--r-- | Makefile | 16 | ||||
| -rw-r--r-- | dir_monitor.c | 219 |
2 files changed, 235 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6e30ed9 --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +all: dir_monitor dir_monitor_debug dir_monitor_debug_asan dir_monitor_asan + +clean: + rm -vf dir_monitor dir_monitor_debug dir_monitor_debug_asan dir_monitor_asan + +dir_monitor: dir_monitor.c + gcc -o dir_monitor dir_monitor.c -O2 + +dir_monitor_debug: dir_monitor.c + gcc -o dir_monitor dir_monitor.c -g -DDEBUGBUILD + +dir_monitor_debug_asan: dir_monitor.c + gcc -o dir_monitor dir_monitor.c -g -DDEBUGBUILD -fsanitize=address + +dir_monitor_asan: dir_monitor.c + gcc -o dir_monitor dir_monitor.c -g -fsanitize=address diff --git a/dir_monitor.c b/dir_monitor.c new file mode 100644 index 0000000..42d90dc --- /dev/null +++ b/dir_monitor.c @@ -0,0 +1,219 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* Copyright 2025 Thorsten Töpper + * + * dir_monitor - print specified stat() information from entries of a given + * directory to stdout. Call it via watch for repeated output to a terminal. + * + * vim:ts=4:sw=4:expandtab + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <stdint.h> +#include <errno.h> +#include <sys/types.h> +#include <dirent.h> +#include <sys/stat.h> +#include <time.h> + + +#define LOGERR(...) {fprintf(stderr, "[%s:%d] %s: ", __FILE__, __LINE__, __func__); fprintf(stderr, __VA_ARGS__);} + +#ifdef DEBUGBUILD +#define DBGTRC(...) LOGERR(__VA_ARGS__) +#else +#define DBGTRC(...) +#endif + + + +/* === DEFINITIONS === */ +#define PATH_SEP '/' + +struct list_node { + struct list_node *next; + size_t fsize; + char fname[256]; + time_t ftime; /* can be creation, access or modification */ +}; + +struct list_head { + struct list_node *first; +}; + +struct list_node *create_node(char *fname, size_t fsize, time_t ftime); +void destroy_list(struct list_head *list); +int insert_sorted_by_size(struct list_head *list, struct list_node *node); +void print_list(struct list_head *list); + + + +/* === GLOBAL VARIABLES === */ +bool show_hidden_entries = false; + + + +/* === IMPLEMENTATION === */ +inline struct list_node *create_node(char *fname, size_t fsize, time_t ftime) { + struct list_node *node = NULL; + + if (fname == NULL || fname[0] == '\0') { + LOGERR("ERROR: No valid filename given\n"); + return NULL; + } + + if ((node = calloc(1, sizeof(struct list_node))) == NULL) { + LOGERR("ERROR: Failed allocate memory for node: %s\n", strerror(errno)); + return NULL; + } + + node->next = NULL; + node->fsize = fsize; + node->ftime = ftime; + strncpy(node->fname, fname, 256); + return node; +} + + +inline void destroy_list(struct list_head *list) { + struct list_node *ptr = NULL; + if (list == NULL) + return; + while (list->first != NULL) { + ptr = list->first->next; + if (ptr == NULL) { + free(list->first); + break; + } + list->first->next = ptr->next; + free(ptr); + } + free(list); +} + + +/* TODO: later when, other parameters are actively used move the action to a template */ +inline int insert_sorted_by_size(struct list_head *list, struct list_node *node) { + struct list_node *ptr = NULL; + + if (list == NULL) { LOGERR("ERROR: No list given.\n"); return -1; } + if (node == NULL) { LOGERR("ERROR: No node given.\n"); return -2; } + + if (list->first == NULL) { + list->first = node; + return 0; + } + + if (node->fsize > list->first->fsize) { + node->next = list->first; + list->first = node; + return 0; + } + + ptr = list->first; + while (ptr != NULL) { + if (ptr->next == NULL) { + ptr->next = node; + return 0; + } + if (node->fsize > ptr->next->fsize) { + node->next = ptr->next; + ptr->next = node; + return 0; + } + ptr = ptr->next; + } + + return -3; +} + + +/* The most simple default output, formatted output is planned */ +void print_list(struct list_head *list) { + struct list_node *ptr; + struct tm *tm = NULL; + + if (list == NULL) return; + + ptr = list->first; + while (ptr != NULL) { + printf(" %8lu %2s ", ((ptr->fsize>=1024) ? (ptr->fsize/1024) : ptr->fsize), + ((ptr->fsize >= 1024) ? "kB" : "")); + /* TODO: time here */ + printf(" %s\n", ptr->fname); + ptr = ptr->next; + } +} + + +/* TODO: When sorting via different parameters is possible, the call needs adjustments */ +struct list_head *get_data_from_directory(char *path) { + char *fullpath = NULL, *fname_in_path = NULL; + DIR *dir = NULL; + size_t l; + struct dirent *de = NULL; + struct list_node *tmp = NULL; + struct list_head *list = NULL; + struct stat stat_res; + + if (path == NULL) { + LOGERR("ERROR: No path given.\n"); + return NULL; + } + + l = strlen(path); + /* +2 due to possibly required / and of course string termination */ + if ((fullpath = calloc(l+256+2, sizeof(char))) == NULL) { + LOGERR("ERROR: Failed to allocate memory for list head.\n"); + return NULL; + } + sprintf(fullpath, "%s%c", path, ((path[l-1] == PATH_SEP) ? '\0' : PATH_SEP)); + fname_in_path = (fullpath[l] == PATH_SEP) ? &(fullpath[l+1]) : &(fullpath[l]) ; + + if ((dir = opendir(path)) == NULL) { + LOGERR("ERROR: Failed to open directory '%s': %s (errno %d)\n", + path, strerror(errno), errno); + return NULL; + } + + /* TBH: In case those few bytes are not available, the process will be killed anyways */ + if ((list = calloc(1, sizeof(struct list_head))) == NULL) { + LOGERR("ERROR: Failed to allocate memory for list head.\n"); + closedir(dir); + return NULL; + } + + errno = 0; + /* Show hidden entries code is UNIXoid specific, needs to be adjusted for portability */ + while ((de = readdir(dir)) != NULL) { + if (de->d_name[0] == '.' && show_hidden_entries == false) + continue; + + sprintf(fname_in_path, "%s", de->d_name); + DBGTRC("DEBUG: fullpath: '%s'\n", fullpath); + if (lstat(fullpath, &stat_res) != 0) { + LOGERR("ERROR: lstat call on '%s' failed: %s (errno %d)\n", + fullpath, strerror(errno), errno); + continue; + } + /* currently ignoring return values */ + tmp = create_node(de->d_name, stat_res.st_size, stat_res.st_mtime); + insert_sorted_by_size(list, tmp); + } + + free(fullpath); + closedir(dir); + return list; +} + + +int main(int argc, char **argv) { + struct list_head *list = NULL; + list = get_data_from_directory(argv[1]); + print_list(list); + destroy_list(list); + return EXIT_SUCCESS; +} + |
