feat: add comprehensive error handling with typed error codes
Add strict error handling for stk initialization and platform operations. stk_init() now fails fast on critical errors and returns typed error codes that users can handle programmatically. Changes: - Add STK_INIT_* error codes for init failures (memory, tmpdir, watch) - Add STK_PLATFORM_* error codes for platform operation results - Check platform_mkdir() and fail if temp directory cannot be created - Check platform_directory_watch_start() and fail if watch cannot initialize - Add error_cleanup path in platform_directory_watch_start() to properly free resources on critical Windows failures. - Replace all platform error checks with STK_PLATFORM_OPERATION_SUCCESS - Log FATAL errors with when critical operations fail - Add warning logs for non-critical failures Critical failures now return specific error codes: - STK_INIT_MEMORY_ERROR: Module memory allocation failed - STK_INIT_TMPDIR_ERROR: Cannot create temp directory - STK_INIT_WATCH_ERROR: Cannot start directory watching Individual module load failures remain non-fatal and are handled logged.
This commit is contained in:
+14
-1
@@ -10,12 +10,25 @@
|
|||||||
#define STK_PATH_MAX 256
|
#define STK_PATH_MAX 256
|
||||||
#define STK_PATH_MAX_OS 4096
|
#define STK_PATH_MAX_OS 4096
|
||||||
|
|
||||||
/* Modules */
|
/* Initialization return codes */
|
||||||
|
#define STK_INIT_SUCCESS 0
|
||||||
|
#define STK_INIT_MEMORY_ERROR 1
|
||||||
|
#define STK_INIT_TMPDIR_ERROR 2
|
||||||
|
#define STK_INIT_WATCH_ERROR 3
|
||||||
|
|
||||||
|
/* Module loading return codes */
|
||||||
#define STK_MOD_INIT_SUCCESS 0
|
#define STK_MOD_INIT_SUCCESS 0
|
||||||
#define STK_MOD_INIT_FAILURE 1
|
#define STK_MOD_INIT_FAILURE 1
|
||||||
#define STK_MOD_LIBRARY_LOAD_ERROR 2
|
#define STK_MOD_LIBRARY_LOAD_ERROR 2
|
||||||
#define STK_MOD_SYMBOL_NOT_FOUND_ERROR 3
|
#define STK_MOD_SYMBOL_NOT_FOUND_ERROR 3
|
||||||
|
|
||||||
|
/* Platform return codes */
|
||||||
|
#define STK_PLATFORM_OPERATION_SUCCESS 0
|
||||||
|
#define STK_PLATFORM_FILE_COPY_ERROR 1
|
||||||
|
#define STK_PLATFORM_MKDIR_ERROR 2
|
||||||
|
#define STK_PLATFORM_REMOVE_DIR_ERROR 3
|
||||||
|
#define STK_PLATFORM_REMOVE_FILE_ERROR 4
|
||||||
|
|
||||||
#if defined(__linux__) || defined(_WIN32)
|
#if defined(__linux__) || defined(_WIN32)
|
||||||
#define STK_EVENT_BUFFER 4096
|
#define STK_EVENT_BUFFER 4096
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+34
-17
@@ -80,28 +80,32 @@ typedef struct {
|
|||||||
} platform_watch_context_t;
|
} platform_watch_context_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int platform_mkdir(const char *path)
|
uint8_t platform_mkdir(const char *path)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return CreateDirectoryA(path, NULL) ? 0 : -1;
|
return CreateDirectoryA(path, NULL) ? STK_PLATFORM_OPERATION_SUCCESS
|
||||||
|
: STK_PLATFORM_MKDIR_ERROR;
|
||||||
#else
|
#else
|
||||||
return mkdir(path, 0755);
|
return mkdir(path, 0755) == 0 ? STK_PLATFORM_OPERATION_SUCCESS
|
||||||
|
: STK_PLATFORM_MKDIR_ERROR;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int platform_remove_file(const char *path)
|
int platform_remove_file(const char *path)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return DeleteFileA(path) ? 0 : -1;
|
return DeleteFileA(path) ? STK_PLATFORM_OPERATION_SUCCESS
|
||||||
|
: STK_PLATFORM_REMOVE_FILE_ERROR;
|
||||||
#else
|
#else
|
||||||
return unlink(path);
|
return unlink(path) == 0 ? STK_PLATFORM_OPERATION_SUCCESS
|
||||||
|
: STK_PLATFORM_REMOVE_FILE_ERROR;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int platform_copy_file(const char *from, const char *to)
|
uint8_t platform_copy_file(const char *from, const char *to)
|
||||||
{
|
{
|
||||||
char buf[STK_PATH_MAX_OS];
|
char buf[STK_PATH_MAX_OS];
|
||||||
int ret = -1;
|
int ret = STK_PLATFORM_FILE_COPY_ERROR;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
sprintf(buf, "%s.tmp", to);
|
sprintf(buf, "%s.tmp", to);
|
||||||
if (CopyFileA(from, buf, FALSE)) {
|
if (CopyFileA(from, buf, FALSE)) {
|
||||||
@@ -125,7 +129,7 @@ int platform_copy_file(const char *from, const char *to)
|
|||||||
while ((n = fread(buf, 1, sizeof(buf), src)) > 0)
|
while ((n = fread(buf, 1, sizeof(buf), src)) > 0)
|
||||||
fwrite(buf, 1, n, dst);
|
fwrite(buf, 1, n, dst);
|
||||||
|
|
||||||
ret = 0;
|
ret = STK_PLATFORM_OPERATION_SUCCESS;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if (src)
|
if (src)
|
||||||
@@ -137,7 +141,7 @@ cleanup:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int platform_remove_dir(const char *path)
|
uint8_t platform_remove_dir(const char *path)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
WIN32_FIND_DATAA fd;
|
WIN32_FIND_DATAA fd;
|
||||||
@@ -161,7 +165,8 @@ int platform_remove_dir(const char *path)
|
|||||||
FindClose(h);
|
FindClose(h);
|
||||||
|
|
||||||
remove_dir:
|
remove_dir:
|
||||||
return RemoveDirectoryA(path) ? 0 : -1;
|
return RemoveDirectoryA(path) ? STK_PLATFORM_OPERATION_SUCCESS
|
||||||
|
: STK_PLATFORM_REMOVE_DIR_ERROR;
|
||||||
#else
|
#else
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
struct dirent *entry;
|
struct dirent *entry;
|
||||||
@@ -169,7 +174,7 @@ remove_dir:
|
|||||||
|
|
||||||
dir = opendir(path);
|
dir = opendir(path);
|
||||||
if (!dir)
|
if (!dir)
|
||||||
return -1;
|
return STK_PLATFORM_REMOVE_DIR_ERROR;
|
||||||
|
|
||||||
loop:
|
loop:
|
||||||
entry = readdir(dir);
|
entry = readdir(dir);
|
||||||
@@ -185,7 +190,8 @@ loop:
|
|||||||
|
|
||||||
loop_end:
|
loop_end:
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
return rmdir(path);
|
return rmdir(path) == 0 ? STK_PLATFORM_OPERATION_SUCCESS
|
||||||
|
: STK_PLATFORM_REMOVE_DIR_ERROR;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,6 +432,7 @@ void *platform_directory_watch_start(const char *path)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
strncpy(ctx->path, path, STK_PATH_MAX - 1);
|
strncpy(ctx->path, path, STK_PATH_MAX - 1);
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
ctx->watch.change_handle =
|
ctx->watch.change_handle =
|
||||||
CreateFileA(path, FILE_LIST_DIRECTORY,
|
CreateFileA(path, FILE_LIST_DIRECTORY,
|
||||||
@@ -433,12 +440,12 @@ void *platform_directory_watch_start(const char *path)
|
|||||||
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||||
|
|
||||||
if (ctx->watch.change_handle == INVALID_HANDLE_VALUE)
|
if (ctx->watch.change_handle == INVALID_HANDLE_VALUE)
|
||||||
goto done;
|
goto error_cleanup;
|
||||||
|
|
||||||
sprintf(s, "%s\\*", path);
|
sprintf(s, "%s\\*", path);
|
||||||
h = FindFirstFileA(s, &fd);
|
h = FindFirstFileA(s, &fd);
|
||||||
if (h == INVALID_HANDLE_VALUE)
|
if (h == INVALID_HANDLE_VALUE)
|
||||||
goto done;
|
goto error_cleanup;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
|
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
|
||||||
@@ -452,11 +459,11 @@ void *platform_directory_watch_start(const char *path)
|
|||||||
|
|
||||||
ctx->snaps = malloc(count * sizeof(platform_snapshot_t));
|
ctx->snaps = malloc(count * sizeof(platform_snapshot_t));
|
||||||
if (!ctx->snaps)
|
if (!ctx->snaps)
|
||||||
goto done;
|
goto error_cleanup;
|
||||||
|
|
||||||
h = FindFirstFileA(s, &fd);
|
h = FindFirstFileA(s, &fd);
|
||||||
if (h == INVALID_HANDLE_VALUE)
|
if (h == INVALID_HANDLE_VALUE)
|
||||||
goto done;
|
goto error_cleanup;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
|
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
|
||||||
@@ -472,7 +479,6 @@ void *platform_directory_watch_start(const char *path)
|
|||||||
ctx->count = i;
|
ctx->count = i;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
ctx->watch.k.kq = kqueue();
|
ctx->watch.k.kq = kqueue();
|
||||||
ctx->watch.k.dir_fd = open(path, O_RDONLY);
|
ctx->watch.k.dir_fd = open(path, O_RDONLY);
|
||||||
d = opendir(path);
|
d = opendir(path);
|
||||||
@@ -531,6 +537,17 @@ bsd_setup:
|
|||||||
done:
|
done:
|
||||||
#endif
|
#endif
|
||||||
return ctx;
|
return ctx;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
error_cleanup:
|
||||||
|
if (ctx) {
|
||||||
|
if (ctx->watch.change_handle != INVALID_HANDLE_VALUE)
|
||||||
|
CloseHandle(ctx->watch.change_handle);
|
||||||
|
free(ctx->snaps);
|
||||||
|
free(ctx);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,11 +75,28 @@ int stk_init(void)
|
|||||||
char tmp_path[STK_PATH_MAX_OS];
|
char tmp_path[STK_PATH_MAX_OS];
|
||||||
int load_result;
|
int load_result;
|
||||||
|
|
||||||
platform_mkdir(stk_tmp_dir);
|
if (platform_mkdir(stk_tmp_dir) != STK_PLATFORM_OPERATION_SUCCESS) {
|
||||||
|
char (*test_scan)[STK_PATH_MAX];
|
||||||
|
size_t test_count;
|
||||||
|
|
||||||
|
test_scan =
|
||||||
|
platform_directory_init_scan(stk_tmp_dir, &test_count);
|
||||||
|
if (test_scan)
|
||||||
|
free(test_scan);
|
||||||
|
if (!test_scan && test_count == 0) {
|
||||||
|
stk_log(stderr,
|
||||||
|
"[stk] FATAL: Cannot create temp directory: %s",
|
||||||
|
stk_tmp_dir);
|
||||||
|
return STK_INIT_TMPDIR_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
files = platform_directory_init_scan(stk_mod_dir, &file_count);
|
files = platform_directory_init_scan(stk_mod_dir, &file_count);
|
||||||
|
|
||||||
if (file_count > 0 && stk_module_init_memory(file_count) != 0)
|
if (file_count > 0 && stk_module_init_memory(file_count) != 0) {
|
||||||
return -1;
|
stk_log(stderr, "[stk] FATAL: Memory allocation failed");
|
||||||
|
return STK_INIT_MEMORY_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if (!files)
|
if (!files)
|
||||||
goto scanned;
|
goto scanned;
|
||||||
@@ -88,7 +105,8 @@ int stk_init(void)
|
|||||||
build_path(full_path, sizeof(full_path), stk_mod_dir, files[i]);
|
build_path(full_path, sizeof(full_path), stk_mod_dir, files[i]);
|
||||||
build_path(tmp_path, sizeof(tmp_path), stk_tmp_dir, files[i]);
|
build_path(tmp_path, sizeof(tmp_path), stk_tmp_dir, files[i]);
|
||||||
|
|
||||||
if (platform_copy_file(full_path, tmp_path) != 0) {
|
if (platform_copy_file(full_path, tmp_path) !=
|
||||||
|
STK_PLATFORM_OPERATION_SUCCESS) {
|
||||||
stk_log(stderr,
|
stk_log(stderr,
|
||||||
"[stk] Failed to copy %s to temp directory",
|
"[stk] Failed to copy %s to temp directory",
|
||||||
files[i]);
|
files[i]);
|
||||||
@@ -113,12 +131,20 @@ int stk_init(void)
|
|||||||
|
|
||||||
scanned:
|
scanned:
|
||||||
watch_handle = platform_directory_watch_start(stk_mod_dir);
|
watch_handle = platform_directory_watch_start(stk_mod_dir);
|
||||||
|
if (!watch_handle) {
|
||||||
|
stk_log(stderr,
|
||||||
|
"[stk] FATAL: Cannot start directory watch on %s",
|
||||||
|
stk_mod_dir);
|
||||||
|
stk_module_unload_all();
|
||||||
|
return STK_INIT_WATCH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
stk_log(stdout, "[stk] stk v%s initialized! Loaded %lu mod%s from %s/",
|
stk_log(stdout, "[stk] stk v%s initialized! Loaded %lu mod%s from %s/",
|
||||||
STK_VERSION_STRING, module_count, module_count != 1 ? "s" : "",
|
STK_VERSION_STRING, module_count, module_count != 1 ? "s" : "",
|
||||||
stk_mod_dir);
|
stk_mod_dir);
|
||||||
|
|
||||||
stk_initialized = 1;
|
stk_initialized = 1;
|
||||||
return 0;
|
return STK_INIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stk_shutdown(void)
|
void stk_shutdown(void)
|
||||||
@@ -129,7 +155,14 @@ void stk_shutdown(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
stk_module_unload_all();
|
stk_module_unload_all();
|
||||||
platform_remove_dir(stk_tmp_dir);
|
|
||||||
|
if (platform_remove_dir(stk_tmp_dir) !=
|
||||||
|
STK_PLATFORM_OPERATION_SUCCESS) {
|
||||||
|
stk_log(stderr,
|
||||||
|
"[stk] Warning: failed to remove temp directory %s",
|
||||||
|
stk_tmp_dir);
|
||||||
|
}
|
||||||
|
|
||||||
stk_initialized = 0;
|
stk_initialized = 0;
|
||||||
stk_log(stdout, "[stk] stk shutdown");
|
stk_log(stdout, "[stk] stk shutdown");
|
||||||
}
|
}
|
||||||
@@ -220,7 +253,8 @@ begin_operations:
|
|||||||
build_path(tmp_path, sizeof(tmp_path), stk_tmp_dir,
|
build_path(tmp_path, sizeof(tmp_path), stk_tmp_dir,
|
||||||
file_list[file_index]);
|
file_list[file_index]);
|
||||||
|
|
||||||
if (platform_copy_file(full_path, tmp_path) != 0) {
|
if (platform_copy_file(full_path, tmp_path) !=
|
||||||
|
STK_PLATFORM_OPERATION_SUCCESS) {
|
||||||
stk_log(stderr, "[stk] Failed to copy %s for reload",
|
stk_log(stderr, "[stk] Failed to copy %s for reload",
|
||||||
file_list[file_index]);
|
file_list[file_index]);
|
||||||
continue;
|
continue;
|
||||||
@@ -244,7 +278,8 @@ begin_operations:
|
|||||||
build_path(tmp_path, sizeof(tmp_path), stk_tmp_dir,
|
build_path(tmp_path, sizeof(tmp_path), stk_tmp_dir,
|
||||||
file_list[file_index]);
|
file_list[file_index]);
|
||||||
|
|
||||||
if (platform_copy_file(full_path, tmp_path) != 0) {
|
if (platform_copy_file(full_path, tmp_path) !=
|
||||||
|
STK_PLATFORM_OPERATION_SUCCESS) {
|
||||||
stk_log(stderr, "[stk] Failed to copy %s for loading",
|
stk_log(stderr, "[stk] Failed to copy %s for loading",
|
||||||
file_list[file_index]);
|
file_list[file_index]);
|
||||||
continue;
|
continue;
|
||||||
@@ -275,7 +310,8 @@ append_modules:
|
|||||||
build_path(tmp_path, sizeof(tmp_path), stk_tmp_dir,
|
build_path(tmp_path, sizeof(tmp_path), stk_tmp_dir,
|
||||||
file_list[file_index]);
|
file_list[file_index]);
|
||||||
|
|
||||||
if (platform_copy_file(full_path, tmp_path) != 0) {
|
if (platform_copy_file(full_path, tmp_path) !=
|
||||||
|
STK_PLATFORM_OPERATION_SUCCESS) {
|
||||||
stk_log(stderr, "[stk] Failed to copy %s for loading",
|
stk_log(stderr, "[stk] Failed to copy %s for loading",
|
||||||
file_list[file_index]);
|
file_list[file_index]);
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
Reference in New Issue
Block a user