Alex 'AdUser' Z
8 years ago
24 changed files with 561 additions and 325 deletions
@ -0,0 +1,2 @@ |
|||||||
|
[source:files] |
||||||
|
load = libf2b_source_files.so |
@ -1,58 +0,0 @@ |
|||||||
/* Copyright 2016 Alex 'AdUser' Z (ad_user@runbox.com)
|
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License version 2 as |
|
||||||
* published by the Free Software Foundation. |
|
||||||
*/ |
|
||||||
#include <glob.h> |
|
||||||
|
|
||||||
#include "common.h" |
|
||||||
#include "logfile.h" |
|
||||||
#include "filelist.h" |
|
||||||
#include "log.h" |
|
||||||
|
|
||||||
f2b_logfile_t * |
|
||||||
f2b_filelist_append(f2b_logfile_t *list, f2b_logfile_t *file) { |
|
||||||
assert(file != NULL); |
|
||||||
|
|
||||||
if (list != NULL) |
|
||||||
return file->next = list; |
|
||||||
return file; |
|
||||||
} |
|
||||||
|
|
||||||
f2b_logfile_t * |
|
||||||
f2b_filelist_from_glob(const char *pattern) { |
|
||||||
f2b_logfile_t *file = NULL; |
|
||||||
f2b_logfile_t *files = NULL; |
|
||||||
glob_t globbuf; |
|
||||||
|
|
||||||
assert(pattern != NULL); |
|
||||||
|
|
||||||
if (glob(pattern, GLOB_MARK | GLOB_NOESCAPE, NULL, &globbuf) != 0) |
|
||||||
return NULL; |
|
||||||
|
|
||||||
for (size_t i = 0; i < globbuf.gl_pathc; i++) { |
|
||||||
if ((file = calloc(1, sizeof(f2b_logfile_t))) == NULL) |
|
||||||
continue; |
|
||||||
if (f2b_logfile_open(file, globbuf.gl_pathv[i]) == false) { |
|
||||||
f2b_log_msg(log_error, "can't open file: %s: %s", globbuf.gl_pathv[i], strerror(errno)); |
|
||||||
free(file); |
|
||||||
continue; |
|
||||||
} |
|
||||||
files = f2b_filelist_append(files, file); |
|
||||||
} |
|
||||||
|
|
||||||
globfree(&globbuf); |
|
||||||
return files; |
|
||||||
} |
|
||||||
|
|
||||||
void |
|
||||||
f2b_filelist_destroy(f2b_logfile_t *list) { |
|
||||||
f2b_logfile_t *next = NULL; |
|
||||||
|
|
||||||
for (; list != NULL; list = next) { |
|
||||||
next = list->next; |
|
||||||
f2b_logfile_close(list); |
|
||||||
free(list); |
|
||||||
} |
|
||||||
} |
|
@ -1,19 +0,0 @@ |
|||||||
/* Copyright 2016 Alex 'AdUser' Z (ad_user@runbox.com)
|
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License version 2 as |
|
||||||
* published by the Free Software Foundation. |
|
||||||
*/ |
|
||||||
#ifndef F2B_FILELIST_H_ |
|
||||||
#define F2B_FILELIST_H_ |
|
||||||
|
|
||||||
f2b_logfile_t * |
|
||||||
f2b_filelist_from_glob(const char *pattern); |
|
||||||
|
|
||||||
f2b_logfile_t * |
|
||||||
f2b_filelist_append(f2b_logfile_t *list, f2b_logfile_t *file); |
|
||||||
|
|
||||||
void |
|
||||||
f2b_filelist_destroy(f2b_logfile_t *list); |
|
||||||
|
|
||||||
#endif /* F2B_FILELIST_H_ */ |
|
@ -1,84 +0,0 @@ |
|||||||
/* Copyright 2016 Alex 'AdUser' Z (ad_user@runbox.com)
|
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License version 2 as |
|
||||||
* published by the Free Software Foundation. |
|
||||||
*/ |
|
||||||
#include "common.h" |
|
||||||
#include "logfile.h" |
|
||||||
|
|
||||||
bool |
|
||||||
f2b_logfile_open(f2b_logfile_t *file, const char *path) { |
|
||||||
struct stat st; |
|
||||||
char buf[PATH_MAX] = ""; |
|
||||||
|
|
||||||
assert(file != NULL); |
|
||||||
assert(path != NULL || file->path[0] != '\0'); |
|
||||||
|
|
||||||
strlcpy(buf, path ? path : file->path, sizeof(buf)); |
|
||||||
|
|
||||||
memset(file, 0x0, sizeof(f2b_logfile_t)); |
|
||||||
|
|
||||||
if (stat(buf, &st) != 0) |
|
||||||
return false; |
|
||||||
|
|
||||||
if (!(S_ISREG(st.st_mode) || S_ISFIFO(st.st_mode))) |
|
||||||
return false; |
|
||||||
|
|
||||||
if ((file->fd = fopen(buf, "r")) == NULL) |
|
||||||
return false; |
|
||||||
|
|
||||||
if (S_ISREG(st.st_mode) && fseek(file->fd, 0, SEEK_END) < 0) |
|
||||||
return false; |
|
||||||
|
|
||||||
memcpy(&file->st, &st, sizeof(st)); |
|
||||||
strlcpy(file->path, buf, sizeof(file->path)); |
|
||||||
file->opened = true; |
|
||||||
|
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
void |
|
||||||
f2b_logfile_close(f2b_logfile_t *file) { |
|
||||||
assert(file != NULL); |
|
||||||
|
|
||||||
if (file->fd) |
|
||||||
fclose(file->fd); |
|
||||||
|
|
||||||
file->opened = false; |
|
||||||
file->fd = NULL; |
|
||||||
} |
|
||||||
|
|
||||||
bool |
|
||||||
f2b_logfile_rotated(const f2b_logfile_t *file) { |
|
||||||
struct stat st; |
|
||||||
|
|
||||||
assert(file != NULL); |
|
||||||
|
|
||||||
if (!file->opened) |
|
||||||
return true; |
|
||||||
|
|
||||||
if (stat(file->path, &st) != 0) |
|
||||||
return true; |
|
||||||
|
|
||||||
if (file->st.st_dev != st.st_dev || |
|
||||||
file->st.st_ino != st.st_ino || |
|
||||||
file->st.st_size > st.st_size) |
|
||||||
return true; |
|
||||||
|
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
bool |
|
||||||
f2b_logfile_getline(const f2b_logfile_t *file, char *buf, size_t bufsize) { |
|
||||||
assert(file != NULL); |
|
||||||
assert(buf != NULL); |
|
||||||
|
|
||||||
if (feof(file->fd)) |
|
||||||
clearerr(file->fd); |
|
||||||
/* fread()+EOF set is implementation defined */ |
|
||||||
if (fgets(buf, bufsize, file->fd) != NULL) |
|
||||||
return true; |
|
||||||
|
|
||||||
return false; |
|
||||||
} |
|
@ -1,23 +0,0 @@ |
|||||||
/* Copyright 2016 Alex 'AdUser' Z (ad_user@runbox.com)
|
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU General Public License version 2 as |
|
||||||
* published by the Free Software Foundation. |
|
||||||
*/ |
|
||||||
#ifndef F2B_LOGFILE_H_ |
|
||||||
#define F2B_LOGFILE_H_ |
|
||||||
|
|
||||||
typedef struct f2b_logfile_t { |
|
||||||
struct f2b_logfile_t *next; |
|
||||||
bool opened; |
|
||||||
char path[PATH_MAX]; |
|
||||||
FILE *fd; |
|
||||||
struct stat st; |
|
||||||
} f2b_logfile_t; |
|
||||||
|
|
||||||
bool f2b_logfile_open(f2b_logfile_t *file, const char *path); |
|
||||||
void f2b_logfile_close(f2b_logfile_t *file); |
|
||||||
bool f2b_logfile_rotated(const f2b_logfile_t *file); |
|
||||||
bool f2b_logfile_getline(const f2b_logfile_t *file, char *buf, size_t bufsize); |
|
||||||
|
|
||||||
#endif /* F2B_LOGFILE_H_ */ |
|
@ -0,0 +1,48 @@ |
|||||||
|
/* Copyright 2016 Alex 'AdUser' Z (ad_user@runbox.com)
|
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License version 2 as |
||||||
|
* published by the Free Software Foundation. |
||||||
|
*/ |
||||||
|
#include "common.h" |
||||||
|
#include "log.h" |
||||||
|
#include "config.h" |
||||||
|
#include "source.h" |
||||||
|
|
||||||
|
void usage() { |
||||||
|
fprintf(stderr, "Usage: source-test <library.so> <init string>\n"); |
||||||
|
exit(EXIT_FAILURE); |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char *argv[]) { |
||||||
|
f2b_config_param_t param = { .name = "load", .value = "", .next = 0x0 }; |
||||||
|
f2b_config_section_t config = { .name = "test", .type = t_source, .param = 0x0, .next = 0x0 }; |
||||||
|
f2b_source_t *source = NULL; |
||||||
|
char buf[1024] = ""; |
||||||
|
bool reset; |
||||||
|
|
||||||
|
if (argc < 2) |
||||||
|
usage(); |
||||||
|
|
||||||
|
config.param = ¶m; |
||||||
|
snprintf(param.value, sizeof(param.value), "%s", argv[1]); |
||||||
|
|
||||||
|
if ((source = f2b_source_create(&config, argv[2], f2b_log_error_cb)) == false) |
||||||
|
usage(); |
||||||
|
|
||||||
|
if (f2b_source_start(source) == false) { |
||||||
|
f2b_log_msg(log_error, "source start error: %s", f2b_source_error(source)); |
||||||
|
exit(EXIT_FAILURE); |
||||||
|
} |
||||||
|
|
||||||
|
while (1) { |
||||||
|
reset = true; |
||||||
|
while (f2b_source_next(source, buf, sizeof(buf), reset)) { |
||||||
|
reset = false; |
||||||
|
fputs(buf, stderr); |
||||||
|
} |
||||||
|
sleep(1); |
||||||
|
} |
||||||
|
|
||||||
|
return EXIT_SUCCESS; |
||||||
|
} |
@ -0,0 +1,113 @@ |
|||||||
|
/* Copyright 2016 Alex 'AdUser' Z (ad_user@runbox.com)
|
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License version 2 as |
||||||
|
* published by the Free Software Foundation. |
||||||
|
*/ |
||||||
|
#include "common.h" |
||||||
|
#include "source.h" |
||||||
|
|
||||||
|
#define SOURCE_LIBRARY_PARAM "load" |
||||||
|
|
||||||
|
f2b_source_t * |
||||||
|
f2b_source_create(f2b_config_section_t *config, const char *init, void (*errcb)(const char *)) { |
||||||
|
f2b_config_param_t *param = NULL; |
||||||
|
f2b_source_t *source = NULL; |
||||||
|
int flags = RTLD_NOW | RTLD_LOCAL; |
||||||
|
const char *dlerr = NULL; |
||||||
|
|
||||||
|
assert(config != NULL); |
||||||
|
assert(config->type == t_source); |
||||||
|
|
||||||
|
param = f2b_config_param_find(config->param, SOURCE_LIBRARY_PARAM); |
||||||
|
if (!param) { |
||||||
|
f2b_log_msg(log_error, "can't find '%s' param in source config", SOURCE_LIBRARY_PARAM); |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
if ((source = calloc(1, sizeof(f2b_source_t))) == NULL) |
||||||
|
return NULL; |
||||||
|
|
||||||
|
if ((source->h = dlopen(param->value, flags)) == NULL) |
||||||
|
goto cleanup; |
||||||
|
if ((*(void **) (&source->create) = dlsym(source->h, "create")) == NULL) |
||||||
|
goto cleanup; |
||||||
|
if ((*(void **) (&source->config) = dlsym(source->h, "config")) == NULL) |
||||||
|
goto cleanup; |
||||||
|
if ((*(void **) (&source->ready) = dlsym(source->h, "ready")) == NULL) |
||||||
|
goto cleanup; |
||||||
|
if ((*(void **) (&source->error) = dlsym(source->h, "error")) == NULL) |
||||||
|
goto cleanup; |
||||||
|
if ((*(void **) (&source->errcb) = dlsym(source->h, "errcb")) == NULL) |
||||||
|
goto cleanup; |
||||||
|
if ((*(void **) (&source->start) = dlsym(source->h, "start")) == NULL) |
||||||
|
goto cleanup; |
||||||
|
if ((*(void **) (&source->next) = dlsym(source->h, "next")) == NULL) |
||||||
|
goto cleanup; |
||||||
|
if ((*(void **) (&source->stop) = dlsym(source->h, "stop")) == NULL) |
||||||
|
goto cleanup; |
||||||
|
if ((*(void **) (&source->destroy) = dlsym(source->h, "destroy")) == NULL) |
||||||
|
goto cleanup; |
||||||
|
|
||||||
|
if ((source->cfg = source->create(init)) == NULL) { |
||||||
|
f2b_log_msg(log_error, "source create config failed"); |
||||||
|
goto cleanup; |
||||||
|
} |
||||||
|
|
||||||
|
/* try init */ |
||||||
|
for (param = config->param; param != NULL; param = param->next) { |
||||||
|
if (strcmp(param->name, SOURCE_LIBRARY_PARAM) == 0) |
||||||
|
continue; |
||||||
|
if (source->config(source->cfg, param->name, param->value)) |
||||||
|
continue; |
||||||
|
f2b_log_msg(log_warn, "param pair not accepted by source '%s': %s=%s", |
||||||
|
config->name, param->name, param->value); |
||||||
|
} |
||||||
|
|
||||||
|
if (errcb) |
||||||
|
source->errcb(source->cfg, errcb); |
||||||
|
|
||||||
|
if (source->ready(source->cfg)) |
||||||
|
return source; |
||||||
|
|
||||||
|
/* still not ready */ |
||||||
|
f2b_log_msg(log_error, "source '%s' not fully configured", config->name); |
||||||
|
|
||||||
|
cleanup: |
||||||
|
dlerr = dlerror(); |
||||||
|
if (dlerr) |
||||||
|
f2b_log_msg(log_error, "source load error: %s", dlerr); |
||||||
|
if (source->h) { |
||||||
|
if (source->cfg && source->destroy) |
||||||
|
source->destroy(source->cfg); |
||||||
|
dlclose(source->h); |
||||||
|
} |
||||||
|
free(source); |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
void |
||||||
|
f2b_source_destroy(f2b_source_t *source) { |
||||||
|
assert(source != NULL); |
||||||
|
source->destroy(source->cfg); |
||||||
|
dlclose(source->h); |
||||||
|
free(source); |
||||||
|
} |
||||||
|
|
||||||
|
bool |
||||||
|
f2b_source_next(f2b_source_t *source, char *buf, size_t bufsize, bool reset) { |
||||||
|
assert(source != NULL); |
||||||
|
return source->next(source->cfg, buf, bufsize, reset); |
||||||
|
} |
||||||
|
|
||||||
|
#define SOURCE_CMD_ARG0(CMD, RETURNS) \ |
||||||
|
RETURNS \
|
||||||
|
f2b_source_ ## CMD(f2b_source_t *source) { \
|
||||||
|
assert(source != NULL); \
|
||||||
|
return source->CMD(source->cfg); \
|
||||||
|
} |
||||||
|
|
||||||
|
SOURCE_CMD_ARG0(error, const char *) |
||||||
|
SOURCE_CMD_ARG0(start, bool) |
||||||
|
SOURCE_CMD_ARG0(stop, bool) |
||||||
|
SOURCE_CMD_ARG0(ready, bool) |
@ -0,0 +1,34 @@ |
|||||||
|
/* Copyright 2016 Alex 'AdUser' Z (ad_user@runbox.com)
|
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License version 2 as |
||||||
|
* published by the Free Software Foundation. |
||||||
|
*/ |
||||||
|
#ifndef F2B_SOURCE_H_ |
||||||
|
#define F2B_SOURCE_H_ |
||||||
|
|
||||||
|
#include "config.h" |
||||||
|
#include "log.h" |
||||||
|
|
||||||
|
typedef struct f2b_source_t { |
||||||
|
void *h; |
||||||
|
void *cfg; |
||||||
|
void *(*create) (const char *init); |
||||||
|
bool (*config) (void *cfg, const char *key, const char *value); |
||||||
|
bool (*ready) (void *cfg); |
||||||
|
char *(*error) (void *cfg); |
||||||
|
void (*errcb) (void *cfg, void (*cb)(const char *errstr)); |
||||||
|
bool (*start) (void *cfg); |
||||||
|
bool (*next) (void *cfg, char *buf, size_t bufsize, bool reset); |
||||||
|
bool (*stop) (void *cfg); |
||||||
|
void (*destroy) (void *cfg); |
||||||
|
} f2b_source_t; |
||||||
|
|
||||||
|
f2b_source_t * f2b_source_create (f2b_config_section_t *config, const char *init, void (*errcb)(const char *)); |
||||||
|
void f2b_source_destroy (f2b_source_t *s); |
||||||
|
bool f2b_source_start (f2b_source_t *s); |
||||||
|
bool f2b_source_next (f2b_source_t *s, char *buf, size_t bufsize, bool reset); |
||||||
|
bool f2b_source_stop (f2b_source_t *s); |
||||||
|
const char * f2b_source_error (f2b_source_t *s); |
||||||
|
|
||||||
|
#endif /* F2B_SOURCE_H_ */ |
@ -0,0 +1,10 @@ |
|||||||
|
set(CMAKE_INCLUDE_CURRENT_DIR ON) |
||||||
|
set(SOURCES "") |
||||||
|
|
||||||
|
add_library("f2b_source_files" MODULE "files.c" "../strlcpy.c") |
||||||
|
list(APPEND SOURCES "f2b_source_files") |
||||||
|
|
||||||
|
message(STATUS "- Sources : ${SOURCES}") |
||||||
|
|
||||||
|
install(TARGETS ${SOURCES} |
||||||
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) |
@ -0,0 +1,227 @@ |
|||||||
|
/* Copyright 2016 Alex 'AdUser' Z (ad_user@runbox.com)
|
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License version 2 as |
||||||
|
* published by the Free Software Foundation. |
||||||
|
*/ |
||||||
|
#include "source.h" |
||||||
|
|
||||||
|
#include <limits.h> |
||||||
|
#include <sys/file.h> |
||||||
|
#include <sys/stat.h> |
||||||
|
|
||||||
|
#include <glob.h> |
||||||
|
|
||||||
|
typedef struct f2b_file_t { |
||||||
|
struct f2b_file_t *next; |
||||||
|
bool opened; |
||||||
|
char path[PATH_MAX]; |
||||||
|
FILE *fd; |
||||||
|
struct stat st; |
||||||
|
} f2b_file_t; |
||||||
|
|
||||||
|
struct _config { |
||||||
|
char path[256]; |
||||||
|
char error[256]; |
||||||
|
void (*errcb)(char *errstr); |
||||||
|
f2b_file_t *files; |
||||||
|
f2b_file_t *current; |
||||||
|
}; |
||||||
|
|
||||||
|
static bool |
||||||
|
file_open(f2b_file_t *file, const char *path) { |
||||||
|
struct stat st; |
||||||
|
char buf[PATH_MAX] = ""; |
||||||
|
|
||||||
|
assert(file != NULL); |
||||||
|
assert(path != NULL || file->path[0] != '\0'); |
||||||
|
|
||||||
|
strlcpy(buf, path ? path : file->path, sizeof(buf)); |
||||||
|
|
||||||
|
memset(file, 0x0, sizeof(f2b_file_t)); |
||||||
|
|
||||||
|
if (stat(buf, &st) != 0) |
||||||
|
return false; |
||||||
|
|
||||||
|
if (!(S_ISREG(st.st_mode) || S_ISFIFO(st.st_mode))) |
||||||
|
return false; |
||||||
|
|
||||||
|
if ((file->fd = fopen(buf, "r")) == NULL) |
||||||
|
return false; |
||||||
|
|
||||||
|
if (S_ISREG(st.st_mode) && fseek(file->fd, 0, SEEK_END) < 0) |
||||||
|
return false; |
||||||
|
|
||||||
|
memcpy(&file->st, &st, sizeof(st)); |
||||||
|
strlcpy(file->path, buf, sizeof(file->path)); |
||||||
|
file->opened = true; |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
static void |
||||||
|
file_close(f2b_file_t *file) { |
||||||
|
assert(file != NULL); |
||||||
|
|
||||||
|
if (file->fd) |
||||||
|
fclose(file->fd); |
||||||
|
|
||||||
|
file->opened = false; |
||||||
|
file->fd = NULL; |
||||||
|
} |
||||||
|
|
||||||
|
static bool |
||||||
|
file_rotated(const f2b_file_t *file) { |
||||||
|
struct stat st; |
||||||
|
|
||||||
|
assert(file != NULL); |
||||||
|
|
||||||
|
if (!file->opened) |
||||||
|
return true; |
||||||
|
|
||||||
|
if (stat(file->path, &st) != 0) |
||||||
|
return true; |
||||||
|
|
||||||
|
if (file->st.st_dev != st.st_dev || |
||||||
|
file->st.st_ino != st.st_ino || |
||||||
|
file->st.st_size > st.st_size) |
||||||
|
return true; |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
static bool |
||||||
|
file_getline(const f2b_file_t *file, char *buf, size_t bufsize) { |
||||||
|
assert(file != NULL); |
||||||
|
assert(buf != NULL); |
||||||
|
|
||||||
|
if (feof(file->fd)) |
||||||
|
clearerr(file->fd); |
||||||
|
/* fread()+EOF set is implementation defined */ |
||||||
|
if (fgets(buf, bufsize, file->fd) != NULL) |
||||||
|
return true; |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
cfg_t * |
||||||
|
create(const char *init) { |
||||||
|
cfg_t *cfg = NULL; |
||||||
|
assert(init != NULL); |
||||||
|
if ((cfg = calloc(1, sizeof(cfg_t))) == NULL) |
||||||
|
return NULL; |
||||||
|
strlcpy(cfg->path, init, sizeof(cfg->path)); |
||||||
|
return cfg; |
||||||
|
} |
||||||
|
|
||||||
|
bool |
||||||
|
config(cfg_t *cfg, const char *key, const char *value) { |
||||||
|
assert(cfg != NULL); |
||||||
|
assert(key != NULL); |
||||||
|
assert(value != NULL); |
||||||
|
/* no options */ |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
bool |
||||||
|
ready(cfg_t *cfg) { |
||||||
|
assert(cfg != NULL); |
||||||
|
if (cfg->path[0] == '\0') |
||||||
|
return false; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
char * |
||||||
|
error(cfg_t *cfg) { |
||||||
|
assert(cfg != NULL); |
||||||
|
|
||||||
|
return cfg->error; |
||||||
|
} |
||||||
|
|
||||||
|
void |
||||||
|
errcb(cfg_t *cfg, void (*cb)(char *errstr)) { |
||||||
|
assert(cfg != NULL); |
||||||
|
assert(cb != NULL); |
||||||
|
|
||||||
|
cfg->errcb = cb; |
||||||
|
} |
||||||
|
|
||||||
|
bool |
||||||
|
start(cfg_t *cfg) { |
||||||
|
f2b_file_t *file = NULL; |
||||||
|
glob_t globbuf; |
||||||
|
|
||||||
|
assert(cfg != NULL); |
||||||
|
|
||||||
|
if (glob(cfg->path, GLOB_MARK | GLOB_NOESCAPE, NULL, &globbuf) != 0) |
||||||
|
return NULL; |
||||||
|
|
||||||
|
for (size_t i = 0; i < globbuf.gl_pathc; i++) { |
||||||
|
if ((file = calloc(1, sizeof(f2b_file_t))) == NULL) |
||||||
|
continue; |
||||||
|
if (file_open(file, globbuf.gl_pathv[i]) == false) { |
||||||
|
if (cfg->errcb) { |
||||||
|
snprintf(cfg->error, sizeof(cfg->error), "can't open file: %s -- %s", |
||||||
|
globbuf.gl_pathv[i], strerror(errno)); |
||||||
|
cfg->errcb(cfg->error); |
||||||
|
} |
||||||
|
free(file); |
||||||
|
continue; |
||||||
|
} |
||||||
|
if (cfg->files == NULL) { |
||||||
|
cfg->files = file; |
||||||
|
} else { |
||||||
|
file->next = cfg->files; |
||||||
|
cfg->files = file; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
globfree(&globbuf); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
bool |
||||||
|
stop(cfg_t *cfg) { |
||||||
|
f2b_file_t *next = NULL; |
||||||
|
|
||||||
|
for (; cfg->files != NULL; cfg->files = next) { |
||||||
|
next = cfg->files->next; |
||||||
|
file_close(cfg->files); |
||||||
|
free(cfg->files); |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
bool |
||||||
|
next(cfg_t *cfg, char *buf, size_t bufsize, bool reset) { |
||||||
|
assert(cfg != NULL); |
||||||
|
assert(buf != NULL); |
||||||
|
assert(bufsize > 0); |
||||||
|
|
||||||
|
if (reset || cfg->current == NULL) |
||||||
|
cfg->current = cfg->files; |
||||||
|
|
||||||
|
for (f2b_file_t *file = cfg->current; file != NULL; file = file->next) { |
||||||
|
if (file_rotated(file)) |
||||||
|
file_close(file); |
||||||
|
if (!file->opened && !file_open(file, NULL)) { |
||||||
|
if (cfg->errcb) { |
||||||
|
snprintf(cfg->error, sizeof(cfg->error), "can't open file -- %s", file->path); |
||||||
|
cfg->errcb(cfg->error); |
||||||
|
} |
||||||
|
continue; |
||||||
|
} |
||||||
|
if (file_getline(file, buf, bufsize)) |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
void |
||||||
|
destroy(cfg_t *cfg) { |
||||||
|
assert(cfg != NULL); |
||||||
|
|
||||||
|
free(cfg); |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
/* Copyright 2016 Alex 'AdUser' Z (ad_user@runbox.com)
|
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License version 2 as |
||||||
|
* published by the Free Software Foundation. |
||||||
|
*/ |
||||||
|
#include <assert.h> |
||||||
|
#include <errno.h> |
||||||
|
#include <stdbool.h> |
||||||
|
#include <stdio.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <string.h> |
||||||
|
#include <unistd.h> |
||||||
|
|
||||||
|
#include "../strlcpy.h" |
||||||
|
|
||||||
|
#define INIT_MAX 256 |
||||||
|
|
||||||
|
typedef struct _config cfg_t; |
||||||
|
|
||||||
|
extern cfg_t *create(const char *init); |
||||||
|
extern bool config(cfg_t *c, const char *key, const char *value); |
||||||
|
extern bool ready(cfg_t *c); |
||||||
|
extern char *error(cfg_t *c); |
||||||
|
extern void errcb(cfg_t *c, void (*cb)(char *errstr)); |
||||||
|
extern bool start(cfg_t *c); |
||||||
|
extern bool next(cfg_t *c, char *buf, size_t bufsize, bool reset); |
||||||
|
extern bool stop(cfg_t *c); |
||||||
|
extern void destroy(cfg_t *c); |
@ -1,58 +0,0 @@ |
|||||||
#include "../src/common.h" |
|
||||||
#include "../src/logfile.h" |
|
||||||
|
|
||||||
int main() { |
|
||||||
f2b_logfile_t file; |
|
||||||
char filename[] = "/tmp/f2b-test.XXXXXX"; |
|
||||||
int fd = 0; |
|
||||||
int ret; |
|
||||||
bool res; |
|
||||||
FILE *wfd = NULL; |
|
||||||
char buf[2048]; |
|
||||||
|
|
||||||
UNUSED(res); |
|
||||||
UNUSED(ret); |
|
||||||
|
|
||||||
fd = mkstemp(filename); |
|
||||||
assert(fd > 0); |
|
||||||
wfd = fdopen(fd, "a"); |
|
||||||
assert(wfd != NULL); |
|
||||||
ret = fputs("test1\n", wfd); |
|
||||||
assert(ret > 0); |
|
||||||
ret = fflush(wfd); |
|
||||||
assert(ret == 0); |
|
||||||
|
|
||||||
res = f2b_logfile_open(&file, filename); |
|
||||||
assert(res == true); |
|
||||||
res = f2b_logfile_getline(&file, buf, sizeof(buf)); |
|
||||||
assert(res == false); |
|
||||||
|
|
||||||
ret = fputs("test2\n", wfd); |
|
||||||
assert(ret > 0); |
|
||||||
ret = fflush(wfd); |
|
||||||
assert(ret == 0); |
|
||||||
|
|
||||||
res = f2b_logfile_getline(&file, buf, sizeof(buf)); |
|
||||||
assert(res == true); |
|
||||||
ret = strncmp(buf, "test2\n", sizeof(buf)); |
|
||||||
assert(ret == 0); |
|
||||||
|
|
||||||
res = f2b_logfile_getline(&file, buf, sizeof(buf)); |
|
||||||
assert(res == false); |
|
||||||
|
|
||||||
fclose(wfd); |
|
||||||
close(fd); |
|
||||||
unlink(filename); |
|
||||||
|
|
||||||
wfd = fopen(filename, "a"); |
|
||||||
assert(wfd != NULL); |
|
||||||
|
|
||||||
res = f2b_logfile_rotated(&file); |
|
||||||
assert(res == true); |
|
||||||
|
|
||||||
f2b_logfile_close(&file); |
|
||||||
fclose(wfd); |
|
||||||
unlink(filename); |
|
||||||
|
|
||||||
exit(0); |
|
||||||
} |
|
Loading…
Reference in new issue