haproxy/addons/deviceatlas/dadwsch.c
David Carlier e9cff619c1 MEDIUM: da: new optional data file download scheduler service.
New specialized service to daily handle the update of download file without
interruption of service and to be preemptively started before HAProxy.
It consists on a standalone utility which shared a memory block with
the DeviceAtlas module which handles the JSON data file update on
a daily basis.

Signed-off-by: David Carlier <dcarlier@deviceatlas.com>
2022-01-28 07:23:07 +01:00

196 lines
4.7 KiB
C

#define _GNU_SOURCE
#include <dac.h>
#include <dadwcurl.h>
#include <dadwarc.h>
#include <getopt.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#define ATLASTOKSZ PATH_MAX
#define ATLASMAPNM "/hapdeviceatlas"
const char *__pgname;
static struct {
da_dwatlas_t o;
int ofd;
void* atlasmap;
} global_deviceatlassch = {
.ofd = -1,
.atlasmap = NULL
};
void usage(void)
{
fprintf(stderr, "%s -u download URL [-d hour (in H:M:S format) current hour by default] [-p path for the downloaded file, /tmp by default]\n", __pgname);
exit(EXIT_FAILURE);
}
static size_t jsonread(void *ctx, size_t count, char *buf)
{
return fread(buf, 1, count, ctx);
}
static da_status_t jsonseek(void *ctx, off_t pos)
{
return fseek(ctx, pos, SEEK_SET) != -1 ? DA_OK : DA_SYS;
}
static void dadwlog(dw_config_t cfg, const char* msg)
{
time_t now = time(NULL);
char buf[26] = {0};
ctime_r(&now, buf);
buf[24] = 0;
fprintf(stderr, "%s: %s\n", buf, msg);
}
static dw_status_t dadwnot(void *a, dw_config_t *cfg)
{
da_dwatlas_t *o = (da_dwatlas_t *)a;
if (!o)
return DW_ERR;
char *e;
char jsondbuf[26] = {0}, buf[26] = {0}, atlasp[ATLASTOKSZ] = {0};
time_t now = time(NULL);
time_t jsond;
int fd = -1;
(void)a;
jsond = da_getdatacreation(&o->atlas);
dwgetfinalp(o->dcfg.info, atlasp, sizeof(atlasp));
ctime_r(&jsond, jsondbuf);
ctime_r(&now, buf);
jsondbuf[24] = 0;
buf[24] = 0;
printf("%s: data file generated on `%s`\n", buf, jsondbuf);
int val = 1;
unsigned char *ptr = (unsigned char *)global_deviceatlassch.atlasmap;
memset(ptr, 0, sizeof(atlasp));
strcpy(ptr, atlasp);
return DW_OK;
}
static da_status_t dadwinit(void)
{
if ((global_deviceatlassch.ofd = shm_open(ATLASMAPNM, O_RDWR | O_CREAT, 0660)) == -1) {
fprintf(stderr, "%s\n", strerror(errno));
return DA_SYS;
}
if (ftruncate(global_deviceatlassch.ofd, ATLASTOKSZ) == -1) {
close(global_deviceatlassch.ofd);
return DA_SYS;
}
lseek(global_deviceatlassch.ofd, 0, SEEK_SET);
global_deviceatlassch.atlasmap = mmap(0, ATLASTOKSZ, PROT_READ | PROT_WRITE, MAP_SHARED, global_deviceatlassch.ofd, 0);
if (global_deviceatlassch.atlasmap == MAP_FAILED) {
fprintf(stderr, "%s\n", strerror(errno));
return DA_SYS;
} else {
memset(global_deviceatlassch.atlasmap, 0, ATLASTOKSZ);
return DA_OK;
}
}
static void dadwexit(int sig __attribute__((unused)), siginfo_t *s __attribute__((unused)), void *ctx __attribute__((unused)))
{
ssize_t w;
fprintf(stderr, "%s: exit\n", __pgname);
dw_daatlas_close(&global_deviceatlassch.o);
da_fini();
munmap(global_deviceatlassch.atlasmap, ATLASTOKSZ);
close(global_deviceatlassch.ofd);
shm_unlink(ATLASMAPNM);
exit(EXIT_SUCCESS);
}
int main(int argc, char **argv)
{
const char *opts = "u:p:d:h";
bool dset = false;
size_t i;
int ch;
da_property_decl_t extraprops[1] = {
{ 0, 0 }
};
__pgname = argv[0];
dw_df_dainit_fn = curldwinit;
dw_df_dacleanup_fn = curldwcleanup;
da_init();
memset(&global_deviceatlassch.o.dcfg, 0, sizeof(global_deviceatlassch.o.dcfg));
while ((ch = getopt(argc, argv, opts)) != -1) {
switch (ch) {
case 'u':
global_deviceatlassch.o.dcfg.info.url = strdup(optarg);
break;
case 'p':
global_deviceatlassch.o.dcfg.info.path = strdup(optarg);
break;
case 'd':
if (strptime(optarg, "%H:%M:%S", &global_deviceatlassch.o.dcfg.info.rtm) != NULL)
dset = true;
else
usage();
break;
case 'h':
default:
usage();
}
}
if (!dset) {
time_t now = time(NULL);
struct tm *cnow = gmtime(&now);
memcpy(&global_deviceatlassch.o.dcfg.info.rtm, cnow, offsetof(struct tm, tm_mday));
}
if (!global_deviceatlassch.o.dcfg.info.url)
usage();
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_flags = SA_SIGINFO | SA_RESTART;
sa.sa_sigaction = dadwexit;
global_deviceatlassch.o.dcfg.info.datatm = 1;
global_deviceatlassch.o.dcfg.info.chksum = 1;
global_deviceatlassch.o.dcfg.info.reload = 1;
global_deviceatlassch.o.dcfg.info.tobin = 1;
global_deviceatlassch.o.dcfg.ep = extraprops;
global_deviceatlassch.o.dcfg.dwproc = curldwproc;
global_deviceatlassch.o.dcfg.dwextract = dadwextract;
global_deviceatlassch.o.dcfg.lptr = (void *)stderr;
global_deviceatlassch.o.dcfg.dwlog = &dadwlog;
global_deviceatlassch.o.dcfg.dwnotify_n = &dadwnot;
global_deviceatlassch.o.rfn = jsonread;
global_deviceatlassch.o.posfn = jsonseek;
if (dadwinit() != DA_OK) {
fprintf(stderr, "%s init failed\n", __pgname);
exit(EXIT_FAILURE);
}
if (da_atlas_open_schedule(&global_deviceatlassch.o) != DA_OK) {
fprintf(stderr, "%s scheduling failed\n", __pgname);
exit(EXIT_FAILURE);
}
sigaction(SIGINT, &sa, NULL);
sigaction(SIGQUIT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
while (true) sleep(1);
return 0;
}