diff options
author | midipix <writeonce@midipix.org> | 2020-01-27 08:36:51 -0500 |
---|---|---|
committer | midipix <writeonce@midipix.org> | 2020-05-23 05:59:01 +0000 |
commit | 88751e9e5ee3726b8a6987aeaae04e956c2234f5 (patch) | |
tree | 1ba3549be38e7a9348ad5b48bb35869e3e733daa | |
parent | fa6b3e3522edcd8c202669c5587f2b5c77ac150d (diff) | |
download | tpax-88751e9e5ee3726b8a6987aeaae04e956c2234f5.tar.bz2 tpax-88751e9e5ee3726b8a6987aeaae04e956c2234f5.tar.xz |
created lib-app skeleton (foss21.org lib-app model).
-rw-r--r-- | config.project | 2 | ||||
-rw-r--r-- | include/empty.dir | 0 | ||||
-rw-r--r-- | include/tpax/tpax.h | 142 | ||||
-rw-r--r-- | include/tpax/tpax_api.h | 35 | ||||
-rw-r--r-- | project/common.mk | 8 | ||||
-rw-r--r-- | project/extras.mk | 6 | ||||
-rw-r--r-- | project/headers.mk | 6 | ||||
-rw-r--r-- | project/tagver.mk | 2 | ||||
-rw-r--r-- | project/tree.mk | 6 | ||||
-rw-r--r-- | src/driver/tpax_amain.c | 94 | ||||
-rw-r--r-- | src/driver/tpax_driver_ctx.c | 248 | ||||
-rw-r--r-- | src/driver/tpax_unit_ctx.c | 61 | ||||
-rw-r--r-- | src/internal/tpax_dprintf_impl.c | 62 | ||||
-rw-r--r-- | src/internal/tpax_dprintf_impl.h | 10 | ||||
-rw-r--r-- | src/internal/tpax_driver_impl.h | 112 | ||||
-rw-r--r-- | src/internal/tpax_errinfo_impl.c | 45 | ||||
-rw-r--r-- | src/internal/tpax_errinfo_impl.h | 80 | ||||
-rw-r--r-- | src/internal/tpax_readlink_impl.h | 31 | ||||
-rw-r--r-- | src/output/tpax_output_error.c | 230 | ||||
-rw-r--r-- | src/skin/tpax_skin_default.c | 12 | ||||
-rw-r--r-- | src/tpax.c | 12 |
21 files changed, 1201 insertions, 3 deletions
diff --git a/config.project b/config.project index c921c48..c8c7c22 100644 --- a/config.project +++ b/config.project @@ -7,7 +7,7 @@ mb_avoid_version=no # config mb_all_static= mb_all_shared= -mb_disable_frontend=yes +mb_disable_frontend=no mb_disable_static=yes mb_disable_shared=yes diff --git a/include/empty.dir b/include/empty.dir deleted file mode 100644 index e69de29..0000000 --- a/include/empty.dir +++ /dev/null diff --git a/include/tpax/tpax.h b/include/tpax/tpax.h new file mode 100644 index 0000000..e89076d --- /dev/null +++ b/include/tpax/tpax.h @@ -0,0 +1,142 @@ +#ifndef TPAX_H +#define TPAX_H + +#include <stdint.h> +#include <stddef.h> + +#include "tpax_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* pre-alpha */ +#ifndef TPAX_APP +#ifndef TPAX_PRE_ALPHA +#error libtpax: pre-alpha: ABI is not final! +#error to use the library, compile with -DTPAX_PRE_ALPHA. +#endif +#endif + +/* status codes */ +#define TPAX_OK 0x00 +#define TPAX_USAGE 0x01 +#define TPAX_ERROR 0x02 + +/* driver flags */ +#define TPAX_DRIVER_VERBOSITY_NONE 0x0000 +#define TPAX_DRIVER_VERBOSITY_ERRORS 0x0001 +#define TPAX_DRIVER_VERBOSITY_STATUS 0x0002 +#define TPAX_DRIVER_VERBOSITY_USAGE 0x0004 +#define TPAX_DRIVER_CLONE_VECTOR 0x0008 + +#define TPAX_DRIVER_VERSION 0x0010 +#define TPAX_DRIVER_DRY_RUN 0x0020 + +#define TPAX_DRIVER_ANNOTATE_ALWAYS 0x1000 +#define TPAX_DRIVER_ANNOTATE_NEVER 0x2000 +#define TPAX_DRIVER_ANNOTATE_FULL 0x4000 + +/* error flags */ +#define TPAX_ERROR_TOP_LEVEL 0x0001 +#define TPAX_ERROR_NESTED 0x0002 +#define TPAX_ERROR_CHILD 0x0004 +#define TPAX_ERROR_CUSTOM 0x0008 + +enum tpax_custom_error { + TPAX_ERR_FLOW_ERROR, + TPAX_ERR_FLEE_ERROR, + TPAX_ERR_NULL_CONTEXT, + TPAX_ERR_BAD_DATA, + TPAX_ERR_CAP, +}; + +enum tpax_warning_level { + TPAX_WARNING_LEVEL_UNKNOWN, + TPAX_WARNING_LEVEL_ALL, + TPAX_WARNING_LEVEL_ERROR, + TPAX_WARNING_LEVEL_NONE, +}; + +struct tpax_source_version { + int major; + int minor; + int revision; + const char * commit; +}; + +struct tpax_fd_ctx { + int fdin; + int fdout; + int fderr; + int fdlog; + int fdcwd; + int fddst; +}; + +struct tpax_error_info { + const struct tpax_driver_ctx * edctx; + const struct tpax_unit_ctx * euctx; + const char * eunit; + int esyscode; + int elibcode; + const char * efunction; + int eline; + unsigned eflags; + void * eany; +}; + +struct tpax_common_ctx { + uint64_t drvflags; + uint64_t actflags; + uint64_t fmtflags; +}; + +struct tpax_driver_ctx { + const char ** units; + const char * program; + const char * module; + const struct tpax_common_ctx * cctx; + struct tpax_error_info ** errv; + void * any; +}; + +struct tpax_unit_ctx { + const char * const * path; + void * any; +}; + +/* driver api */ +tpax_api int tpax_get_driver_ctx (char ** argv, char ** envp, uint32_t flags, + const struct tpax_fd_ctx *, + struct tpax_driver_ctx **); + +tpax_api void tpax_free_driver_ctx (struct tpax_driver_ctx *); + +tpax_api int tpax_get_unit_ctx (const struct tpax_driver_ctx *, const char * path, + struct tpax_unit_ctx **); + +tpax_api void tpax_free_unit_ctx (struct tpax_unit_ctx *); + +tpax_api int tpax_get_driver_fdctx (const struct tpax_driver_ctx *, struct tpax_fd_ctx *); +tpax_api int tpax_set_driver_fdctx (struct tpax_driver_ctx *, const struct tpax_fd_ctx *); + +/* core api */ + +/* helper api */ + +/* utility api */ +tpax_api int tpax_main (char **, char **, + const struct tpax_fd_ctx *); +/* error trace api */ +tpax_api int tpax_output_error_record (const struct tpax_driver_ctx *, const struct tpax_error_info *); +tpax_api int tpax_output_error_vector (const struct tpax_driver_ctx *); + +/* package info */ +tpax_api const struct tpax_source_version * tpax_source_version(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/tpax/tpax_api.h b/include/tpax/tpax_api.h new file mode 100644 index 0000000..0e6db99 --- /dev/null +++ b/include/tpax/tpax_api.h @@ -0,0 +1,35 @@ +#ifndef TPAX_API_H +#define TPAX_API_H + +#include <limits.h> + +/* tpax_export */ +#if defined(__dllexport) +#define tpax_export __dllexport +#else +#define tpax_export +#endif + +/* tpax_import */ +#if defined(__dllimport) +#define tpax_import __dllimport +#else +#define tpax_import +#endif + +/* tpax_api */ +#ifndef TPAX_APP +#if defined (TPAX_EXPORT) +#define tpax_api tpax_export +#elif defined (TPAX_IMPORT) +#define tpax_api tpax_import +#elif defined (TPAX_STATIC) +#define tpax_api +#else +#define tpax_api +#endif +#else +#define tpax_api +#endif + +#endif diff --git a/project/common.mk b/project/common.mk index 4b72987..204f473 100644 --- a/project/common.mk +++ b/project/common.mk @@ -1,7 +1,15 @@ API_SRCS = \ + src/driver/tpax_amain.c \ + src/driver/tpax_driver_ctx.c \ + src/driver/tpax_unit_ctx.c \ + src/output/tpax_output_error.c \ + src/skin/tpax_skin_default.c \ INTERNAL_SRCS = \ + src/internal/$(PACKAGE)_dprintf_impl.c \ + src/internal/$(PACKAGE)_errinfo_impl.c \ APP_SRCS = \ + src/tpax.c COMMON_SRCS = $(API_SRCS) $(INTERNAL_SRCS) diff --git a/project/extras.mk b/project/extras.mk index e69de29..f07c781 100644 --- a/project/extras.mk +++ b/project/extras.mk @@ -0,0 +1,6 @@ +CFLAGS_SHARED_ATTR += -DTPAX_PRE_ALPHA -DTPAX_EXPORT +CFLAGS_STATIC_ATTR += -DTPAX_PRE_ALPHA -DTPAX_STATIC +CFLAGS_APP_ATTR += -DTPAX_APP + +src/driver/tpax_driver_ctx.o: version.tag +src/driver/tpax_driver_ctx.lo: version.tag diff --git a/project/headers.mk b/project/headers.mk index e7c0af7..2427d74 100644 --- a/project/headers.mk +++ b/project/headers.mk @@ -1,6 +1,12 @@ API_HEADERS = \ + $(SOURCE_DIR)/include/$(PACKAGE)/tpax.h \ + $(SOURCE_DIR)/include/$(PACKAGE)/tpax_api.h \ INTERNAL_HEADERS = \ $(SOURCE_DIR)/src/internal/argv/argv.h \ + $(SOURCE_DIR)/src/internal/tpax_dprintf_impl.h \ + $(SOURCE_DIR)/src/internal/tpax_driver_impl.h \ + $(SOURCE_DIR)/src/internal/tpax_errinfo_impl.h \ + $(SOURCE_DIR)/src/internal/tpax_readlink_impl.h \ ALL_HEADERS = $(API_HEADERS) $(INTERNAL_HEADERS) diff --git a/project/tagver.mk b/project/tagver.mk index 6a5d8d6..fdc4cec 100644 --- a/project/tagver.mk +++ b/project/tagver.mk @@ -1,4 +1,4 @@ -VER_NAMESPACE = +VER_NAMESPACE = TPAX VER_MAJOR = 0 VER_MINOR = 0 diff --git a/project/tree.mk b/project/tree.mk index ed9e1f8..e78a86d 100644 --- a/project/tree.mk +++ b/project/tree.mk @@ -1,4 +1,8 @@ -TREE_DIRS = bin src lib +TREE_DIRS = bin lib src \ + src/driver \ + src/internal \ + src/output \ + src/skin \ tree.tag: mkdir -p $(TREE_DIRS) diff --git a/src/driver/tpax_amain.c b/src/driver/tpax_amain.c new file mode 100644 index 0000000..f71f16c --- /dev/null +++ b/src/driver/tpax_amain.c @@ -0,0 +1,94 @@ +/******************************************************/ +/* tpax: a topological pax implementation */ +/* Copyright (C) 2020 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */ +/******************************************************/ + +#include <stdio.h> +#include <unistd.h> +#include <tpax/tpax.h> +#include "tpax_driver_impl.h" +#include "tpax_dprintf_impl.h" + +#ifndef TPAX_DRIVER_FLAGS +#define TPAX_DRIVER_FLAGS TPAX_DRIVER_VERBOSITY_ERRORS \ + | TPAX_DRIVER_VERBOSITY_USAGE +#endif + +static const char vermsg[] = "%s%s%s (https://git.foss21.org/tpax): " + "version %s%d.%d.%d%s.\n" + "[commit reference: %s%s%s]\n"; + +static const char * const tpax_ver_color[6] = { + "\x1b[1m\x1b[35m","\x1b[0m", + "\x1b[1m\x1b[32m","\x1b[0m", + "\x1b[1m\x1b[34m","\x1b[0m" +}; + +static const char * const tpax_ver_plain[6] = { + "","", + "","", + "","" +}; + +static ssize_t tpax_version(struct tpax_driver_ctx * dctx, int fdout) +{ + const struct tpax_source_version * verinfo; + const char * const * verclr; + + verinfo = tpax_source_version(); + verclr = isatty(fdout) ? tpax_ver_color : tpax_ver_plain; + + return tpax_dprintf( + fdout,vermsg, + verclr[0],dctx->program,verclr[1], + verclr[2],verinfo->major,verinfo->minor, + verinfo->revision,verclr[3], + verclr[4],verinfo->commit,verclr[5]); +} + +static void tpax_perform_unit_actions( + const struct tpax_driver_ctx * dctx, + struct tpax_unit_ctx * uctx) +{ + (void)dctx; + (void)uctx; +} + +static int tpax_exit(struct tpax_driver_ctx * dctx, int ret) +{ + tpax_output_error_vector(dctx); + tpax_free_driver_ctx(dctx); + return ret; +} + +int tpax_main(char ** argv, char ** envp, const struct tpax_fd_ctx * fdctx) +{ + int ret; + int fdout; + uint64_t flags; + struct tpax_driver_ctx * dctx; + struct tpax_unit_ctx * uctx; + const char ** unit; + + flags = TPAX_DRIVER_FLAGS; + fdout = fdctx ? fdctx->fdout : STDOUT_FILENO; + + if ((ret = tpax_get_driver_ctx(argv,envp,flags,fdctx,&dctx))) + return (ret == TPAX_USAGE) + ? !argv || !argv[0] || !argv[1] + : TPAX_ERROR; + + if (dctx->cctx->drvflags & TPAX_DRIVER_VERSION) + if ((tpax_version(dctx,fdout)) < 0) + return tpax_exit(dctx,TPAX_ERROR); + + for (unit=dctx->units; *unit; unit++) { + if (!(tpax_get_unit_ctx(dctx,*unit,&uctx))) { + tpax_perform_unit_actions(dctx,uctx); + tpax_free_unit_ctx(uctx); + } + } + + return tpax_exit(dctx,dctx->errv[0] ? TPAX_ERROR : TPAX_OK); +} diff --git a/src/driver/tpax_driver_ctx.c b/src/driver/tpax_driver_ctx.c new file mode 100644 index 0000000..96fe8ff --- /dev/null +++ b/src/driver/tpax_driver_ctx.c @@ -0,0 +1,248 @@ +/******************************************************/ +/* tpax: a topological pax implementation */ +/* Copyright (C) 2020 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */ +/******************************************************/ + +#include <stdint.h> +#include <unistd.h> +#include <fcntl.h> + +#define ARGV_DRIVER + +#include <tpax/tpax.h> +#include "tpax_version.h" +#include "tpax_driver_impl.h" +#include "argv/argv.h" + +/* package info */ +static const struct tpax_source_version tpax_src_version = { + TPAX_TAG_VER_MAJOR, + TPAX_TAG_VER_MINOR, + TPAX_TAG_VER_PATCH, + TPAX_GIT_VERSION +}; + +/* default fd context */ +static const struct tpax_fd_ctx tpax_default_fdctx = { + .fdin = STDIN_FILENO, + .fdout = STDOUT_FILENO, + .fderr = STDERR_FILENO, + .fdcwd = AT_FDCWD, + .fddst = AT_FDCWD, + .fdlog = (-1), +}; + +struct tpax_driver_ctx_alloc { + struct argv_meta * meta; + struct tpax_driver_ctx_impl ctx; + uint64_t guard; + const char * units[]; +}; + +static uint32_t tpax_argv_flags(uint32_t flags) +{ + uint32_t ret = ARGV_CLONE_VECTOR; + + if (flags & TPAX_DRIVER_VERBOSITY_NONE) + ret |= ARGV_VERBOSITY_NONE; + + if (flags & TPAX_DRIVER_VERBOSITY_ERRORS) + ret |= ARGV_VERBOSITY_ERRORS; + + if (flags & TPAX_DRIVER_VERBOSITY_STATUS) + ret |= ARGV_VERBOSITY_STATUS; + + return ret; +} + +static int tpax_driver_usage( + int fdout, + const char * program, + const char * arg, + const struct argv_option ** optv, + struct argv_meta * meta) +{ + char header[512]; + + snprintf(header,sizeof(header), + "Usage: %s [options] <file>...\n" "Options:\n", + program); + + argv_usage(fdout,header,optv,arg); + argv_free(meta); + + return TPAX_USAGE; +} + +static struct tpax_driver_ctx_impl * tpax_driver_ctx_alloc( + struct argv_meta * meta, + const struct tpax_fd_ctx * fdctx, + const struct tpax_common_ctx * cctx, + size_t nunits) +{ + struct tpax_driver_ctx_alloc * ictx; + size_t size; + struct argv_entry * entry; + const char ** units; + int elements; + + size = sizeof(struct tpax_driver_ctx_alloc); + size += (nunits+1)*sizeof(const char *); + + if (!(ictx = calloc(1,size))) + return 0; + + memcpy(&ictx->ctx.fdctx,fdctx,sizeof(*fdctx)); + memcpy(&ictx->ctx.cctx,cctx,sizeof(*cctx)); + + elements = sizeof(ictx->ctx.erribuf) / sizeof(*ictx->ctx.erribuf); + + ictx->ctx.errinfp = &ictx->ctx.erriptr[0]; + ictx->ctx.erricap = &ictx->ctx.erriptr[--elements]; + + ictx->meta = meta; + + for (entry=meta->entries,units=ictx->units; entry->fopt || entry->arg; entry++) + if (!entry->fopt) + *units++ = entry->arg; + + ictx->ctx.ctx.units = ictx->units; + ictx->ctx.ctx.errv = ictx->ctx.errinfp; + return &ictx->ctx; +} + +static int tpax_get_driver_ctx_fail(struct argv_meta * meta) +{ + argv_free(meta); + return -1; +} + +int tpax_get_driver_ctx( + char ** argv, + char ** envp, + uint32_t flags, + const struct tpax_fd_ctx * fdctx, + struct tpax_driver_ctx ** pctx) +{ + struct tpax_driver_ctx_impl * ctx; + struct tpax_common_ctx cctx; + const struct argv_option * optv[TPAX_OPTV_ELEMENTS]; + struct argv_meta * meta; + struct argv_entry * entry; + size_t nunits; + const char * program; + + (void)envp; + + if (!fdctx) + fdctx = &tpax_default_fdctx; + + argv_optv_init(tpax_default_options,optv); + + if (!(meta = argv_get( + argv,optv, + tpax_argv_flags(flags), + fdctx->fderr))) + return -1; + + nunits = 0; + program = argv_program_name(argv[0]); + memset(&cctx,0,sizeof(cctx)); + cctx.drvflags = flags; + + if (!argv[1] && (flags & TPAX_DRIVER_VERBOSITY_USAGE)) + return tpax_driver_usage( + fdctx->fderr, + program, + 0,optv,meta); + + /* get options, count units */ + for (entry=meta->entries; entry->fopt || entry->arg; entry++) { + if (entry->fopt) { + switch (entry->tag) { + case TAG_HELP: + if (flags & TPAX_DRIVER_VERBOSITY_USAGE) + return tpax_driver_usage( + fdctx->fdout, + program,entry->arg, + optv,meta); + break; + + case TAG_VERSION: + cctx.drvflags |= TPAX_DRIVER_VERSION; + break; + } + } else + nunits++; + } + + if (!(ctx = tpax_driver_ctx_alloc(meta,fdctx,&cctx,nunits))) + return tpax_get_driver_ctx_fail(meta); + + ctx->ctx.program = program; + ctx->ctx.cctx = &ctx->cctx; + + *pctx = &ctx->ctx; + return TPAX_OK; +} + +static void tpax_free_driver_ctx_impl(struct tpax_driver_ctx_alloc * ictx) +{ + argv_free(ictx->meta); + free(ictx); +} + +void tpax_free_driver_ctx(struct tpax_driver_ctx * ctx) +{ + struct tpax_driver_ctx_alloc * ictx; + uintptr_t addr; + + if (ctx) { + addr = (uintptr_t)ctx - offsetof(struct tpax_driver_ctx_impl,ctx); + addr = addr - offsetof(struct tpax_driver_ctx_alloc,ctx); + ictx = (struct tpax_driver_ctx_alloc *)addr; + tpax_free_driver_ctx_impl(ictx); + } +} + +const struct tpax_source_version * tpax_source_version(void) +{ + return &tpax_src_version; +} + +int tpax_get_driver_fdctx( + const struct tpax_driver_ctx * dctx, + struct tpax_fd_ctx * fdctx) +{ + struct tpax_driver_ctx_impl * ictx; + + ictx = tpax_get_driver_ictx(dctx); + + fdctx->fdin = ictx->fdctx.fdin; + fdctx->fdout = ictx->fdctx.fdout; + fdctx->fderr = ictx->fdctx.fderr; + fdctx->fdlog = ictx->fdctx.fdlog; + fdctx->fdcwd = ictx->fdctx.fdcwd; + fdctx->fddst = ictx->fdctx.fddst; + + return 0; +} + +int tpax_set_driver_fdctx( + struct tpax_driver_ctx * dctx, + const struct tpax_fd_ctx * fdctx) +{ + struct tpax_driver_ctx_impl * ictx; + + ictx = tpax_get_driver_ictx(dctx); + + ictx->fdctx.fdin = fdctx->fdin; + ictx->fdctx.fdout = fdctx->fdout; + ictx->fdctx.fderr = fdctx->fderr; + ictx->fdctx.fdlog = fdctx->fdlog; + ictx->fdctx.fdcwd = fdctx->fdcwd; + ictx->fdctx.fddst = fdctx->fddst; + + return 0; +} diff --git a/src/driver/tpax_unit_ctx.c b/src/driver/tpax_unit_ctx.c new file mode 100644 index 0000000..a6a91b6 --- /dev/null +++ b/src/driver/tpax_unit_ctx.c @@ -0,0 +1,61 @@ +/******************************************************/ +/* tpax: a topological pax implementation */ +/* Copyright (C) 2020 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */ +/******************************************************/ + +#include <stdint.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> + +#include <tpax/tpax.h> +#include "tpax_driver_impl.h" +#include "tpax_errinfo_impl.h" + +static int tpax_free_unit_ctx_impl(struct tpax_unit_ctx_impl * ctx, int ret) +{ + if (ctx) { + free(ctx); + } + + return ret; +} + +int tpax_get_unit_ctx( + const struct tpax_driver_ctx * dctx, + const char * path, + struct tpax_unit_ctx ** pctx) +{ + struct tpax_unit_ctx_impl * ctx; + + if (!dctx) + return TPAX_CUSTOM_ERROR( + dctx,TPAX_ERR_NULL_CONTEXT); + + else if (!(ctx = calloc(1,sizeof(*ctx)))) + return TPAX_BUFFER_ERROR(dctx); + + tpax_driver_set_ectx( + dctx,0,path); + + ctx->path = path; + ctx->uctx.path = &ctx->path; + + *pctx = &ctx->uctx; + + return 0; +} + +void tpax_free_unit_ctx(struct tpax_unit_ctx * ctx) +{ + struct tpax_unit_ctx_impl * ictx; + uintptr_t addr; + + if (ctx) { + addr = (uintptr_t)ctx - offsetof(struct tpax_unit_ctx_impl,uctx); + ictx = (struct tpax_unit_ctx_impl *)addr; + tpax_free_unit_ctx_impl(ictx,0); + } +} diff --git a/src/internal/tpax_dprintf_impl.c b/src/internal/tpax_dprintf_impl.c new file mode 100644 index 0000000..5d2f5f8 --- /dev/null +++ b/src/internal/tpax_dprintf_impl.c @@ -0,0 +1,62 @@ +/******************************************************/ +/* tpax: a topological pax implementation */ +/* Copyright (C) 2020 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */ +/******************************************************/ + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> + +int tpax_dprintf(int fd, const char * fmt, ...) +{ + int ret; + int cnt; + int size; + va_list ap; + char * ch; + char * buf; + char chbuf[2048]; + + va_start(ap,fmt); + + size = sizeof(chbuf); + buf = ((cnt = vsnprintf(chbuf,size,fmt,ap)) < size) + ? chbuf : malloc(cnt + 1); + + va_end(ap); + + if (buf == chbuf) { + (void)0; + + } else if (buf) { + va_start(ap,fmt); + vsprintf(buf,fmt,ap); + va_end(ap); + + } else { + return -1; + } + + ret = 0; + ch = buf; + + for (; cnt && ret>=0; ) { + ret = write(fd,ch,cnt); + + while ((ret < 0) && (errno == EINTR)) + ret = write(fd,ch,cnt); + + ch += ret; + cnt -= ret; + } + + ret = (ret < 0) ? -1 : ch - buf; + + if (buf != chbuf) + free(buf); + + return ret; +} diff --git a/src/internal/tpax_dprintf_impl.h b/src/internal/tpax_dprintf_impl.h new file mode 100644 index 0000000..d83d0d3 --- /dev/null +++ b/src/internal/tpax_dprintf_impl.h @@ -0,0 +1,10 @@ +#ifndef TPAX_DPRINTF_IMPL_H +#define TPAX_DPRINTF_IMPL_H + +#ifdef ARGV_DRIVER +#define argv_dprintf tpax_dprintf +#endif + +int tpax_dprintf(int fd, const char * fmt, ...); + +#endif diff --git a/src/internal/tpax_driver_impl.h b/src/internal/tpax_driver_impl.h new file mode 100644 index 0000000..49dea15 --- /dev/null +++ b/src/internal/tpax_driver_impl.h @@ -0,0 +1,112 @@ +/******************************************************/ +/* tpax: a topological pax implementation */ +/* Copyright (C) 2020 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */ +/******************************************************/ + +#ifndef TPAX_DRIVER_IMPL_H +#define TPAX_DRIVER_IMPL_H + +#include <stdint.h> +#include <stdio.h> +#include <sys/types.h> + +#include <tpax/tpax.h> +#include "tpax_dprintf_impl.h" +#include "argv/argv.h" + +#define TPAX_OPTV_ELEMENTS 64 + +extern const struct argv_option tpax_default_options[]; + +enum app_tags { + TAG_HELP, + TAG_VERSION, +}; + +struct tpax_driver_ctx_impl { + struct tpax_common_ctx cctx; + struct tpax_driver_ctx ctx; + struct tpax_fd_ctx fdctx; + const struct tpax_unit_ctx * euctx; + const char * eunit; + struct tpax_error_info ** errinfp; + struct tpax_error_info ** erricap; + struct tpax_error_info * erriptr[64]; + struct tpax_error_info erribuf[64]; +}; + +struct tpax_unit_ctx_impl { + const char * path; + struct tpax_unit_ctx uctx; +}; + + +static inline struct tpax_driver_ctx_impl * tpax_get_driver_ictx( + const struct tpax_driver_ctx * dctx) +{ + uintptr_t addr; + + if (dctx) { + addr = (uintptr_t)dctx - offsetof(struct tpax_driver_ctx_impl,ctx); + return (struct tpax_driver_ctx_impl *)addr; + } + + return 0; +} + +static inline void tpax_driver_set_ectx( + const struct tpax_driver_ctx * dctx, + const struct tpax_unit_ctx * uctx, + const char * unit) +{ + struct tpax_driver_ctx_impl * ictx; + + ictx = tpax_get_driver_ictx(dctx); + ictx->euctx = uctx; + ictx->eunit = unit; +} + +static inline int tpax_driver_fdin(const struct tpax_driver_ctx * dctx) +{ + struct tpax_fd_ctx fdctx; + tpax_get_driver_fdctx(dctx,&fdctx); + return fdctx.fdin; +} + +static inline int tpax_driver_fdout(const struct tpax_driver_ctx * dctx) +{ + struct tpax_fd_ctx fdctx; + tpax_get_driver_fdctx(dctx,&fdctx); + return fdctx.fdout; +} + +static inline int tpax_driver_fderr(const struct tpax_driver_ctx * dctx) +{ + struct tpax_fd_ctx fdctx; + tpax_get_driver_fdctx(dctx,&fdctx); + return fdctx.fderr; +} + +static inline int tpax_driver_fdlog(const struct tpax_driver_ctx * dctx) +{ + struct tpax_fd_ctx fdctx; + tpax_get_driver_fdctx(dctx,&fdctx); + return fdctx.fdlog; +} + +static inline int tpax_driver_fdcwd(const struct tpax_driver_ctx * dctx) +{ + struct tpax_fd_ctx fdctx; + tpax_get_driver_fdctx(dctx,&fdctx); + return fdctx.fdcwd; +} + +static inline int tpax_driver_fddst(const struct tpax_driver_ctx * dctx) +{ + struct tpax_fd_ctx fdctx; + tpax_get_driver_fdctx(dctx,&fdctx); + return fdctx.fddst; +} + +#endif diff --git a/src/internal/tpax_errinfo_impl.c b/src/internal/tpax_errinfo_impl.c new file mode 100644 index 0000000..b610869 --- /dev/null +++ b/src/internal/tpax_errinfo_impl.c @@ -0,0 +1,45 @@ +/******************************************************/ +/* tpax: a topological pax implementation */ +/* Copyright (C) 2020 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */ +/******************************************************/ + +#include <tpax/tpax.h> +#include "tpax_driver_impl.h" +#include "tpax_errinfo_impl.h" + +int tpax_record_error( + const struct tpax_driver_ctx * dctx, + int esyscode, + int elibcode, + const char * efunction, + int eline, + unsigned eflags, + void * eany) +{ + struct tpax_driver_ctx_impl * ictx; + struct tpax_error_info * erri; + + ictx = tpax_get_driver_ictx(dctx); + + if (ictx->errinfp == ictx->erricap) + return -1; + + *ictx->errinfp = &ictx->erribuf[ictx->errinfp - ictx->erriptr]; + erri = *ictx->errinfp; + + erri->euctx = ictx->euctx; + erri->eunit = ictx->eunit; + + erri->edctx = dctx; + erri->esyscode = esyscode; + erri->elibcode = elibcode; + erri->efunction = efunction; + erri->eline = eline; + erri->eflags = eflags; + erri->eany = eany; + + ictx->errinfp++; + + return -1; +} diff --git a/src/internal/tpax_errinfo_impl.h b/src/internal/tpax_errinfo_impl.h new file mode 100644 index 0000000..d85d159 --- /dev/null +++ b/src/internal/tpax_errinfo_impl.h @@ -0,0 +1,80 @@ +/******************************************************/ +/* tpax: a topological pax implementation */ +/* Copyright (C) 2020 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */ +/******************************************************/ + +#include <errno.h> +#include <tpax/tpax.h> + +int tpax_record_error( + const struct tpax_driver_ctx *, + int esyscode, + int elibcode, + const char * efunction, + int eline, + unsigned eflags, + void * ectx); + +#define TPAX_SYSTEM_ERROR(dctx) \ + tpax_record_error( \ + dctx, \ + errno, \ + 0, \ + __func__, \ + __LINE__, \ + TPAX_ERROR_TOP_LEVEL, \ + 0) + +#define TPAX_BUFFER_ERROR(dctx) \ + tpax_record_error( \ + dctx, \ + ENOBUFS, \ + 0, \ + __func__, \ + __LINE__, \ + TPAX_ERROR_TOP_LEVEL, \ + 0) + +#define TPAX_SPAWN_ERROR(dctx) \ + tpax_record_error( \ + dctx, \ + errno, \ + 0, \ + __func__, \ + __LINE__, \ + TPAX_ERROR_TOP_LEVEL \ + | (errno ? 0 \ + : TPAX_ERROR_CHILD), \ + 0) + +#define TPAX_FILE_ERROR(dctx) \ + tpax_record_error( \ + dctx, \ + EIO, \ + 0, \ + __func__, \ + __LINE__, \ + TPAX_ERROR_TOP_LEVEL, \ + 0) + +#define TPAX_CUSTOM_ERROR(dctx,elibcode) \ + tpax_record_error( \ + dctx, \ + 0, \ + elibcode, \ + __func__, \ + __LINE__, \ + TPAX_ERROR_TOP_LEVEL \ + | TPAX_ERROR_CUSTOM, \ + 0) + +#define TPAX_NESTED_ERROR(dctx) \ + tpax_record_error( \ + dctx, \ + 0, \ + 0, \ + __func__, \ + __LINE__, \ + TPAX_ERROR_NESTED, \ + 0) diff --git a/src/internal/tpax_readlink_impl.h b/src/internal/tpax_readlink_impl.h new file mode 100644 index 0000000..328b302 --- /dev/null +++ b/src/internal/tpax_readlink_impl.h @@ -0,0 +1,31 @@ +/******************************************************/ +/* tpax: a topological pax implementation */ +/* Copyright (C) 2020 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */ +/******************************************************/ + +#ifndef TPAX_READLINK_IMPL_H +#define TPAX_READLINK_IMPL_H + +#include <unistd.h> +#include <errno.h> + +static inline int tpax_readlink( + const char * restrict path, + char * restrict buf, + ssize_t bufsize) +{ + ssize_t ret; + + if ((ret = readlink(path,buf,bufsize)) <= 0) { + return -1; + } else if (ret == bufsize) { + errno = ENOBUFS; + return -1; + } else { + buf[ret] = 0; + return 0; + } +} + +#endif diff --git a/src/output/tpax_output_error.c b/src/output/tpax_output_error.c new file mode 100644 index 0000000..69c4938 --- /dev/null +++ b/src/output/tpax_output_error.c @@ -0,0 +1,230 @@ +/******************************************************/ +/* tpax: a topological pax implementation */ +/* Copyright (C) 2020 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */ +/******************************************************/ + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <tpax/tpax.h> + +#include "tpax_driver_impl.h" +#include "tpax_dprintf_impl.h" + +static const char aclr_reset[] = "\x1b[0m"; +static const char aclr_bold[] = "\x1b[1m"; + +static const char aclr_red[] = "\x1b[31m"; +static const char aclr_green[] = "\x1b[32m"; +static const char aclr_blue[] = "\x1b[34m"; +static const char aclr_magenta[] = "\x1b[35m"; + +static const char * const tpax_error_strings[TPAX_ERR_CAP] = { + [TPAX_ERR_FLOW_ERROR] = "flow error: unexpected condition or other", + [TPAX_ERR_FLEE_ERROR] = "flees and bugs and cats and mice", + [TPAX_ERR_NULL_CONTEXT] = "null driver or unit context", + [TPAX_ERR_BAD_DATA] = "corrupt or wrong daata", +}; + +static const char * tpax_output_error_header(const struct tpax_error_info * erri) +{ + if (erri->eflags & TPAX_ERROR_CHILD) + return "exec error upon"; + + else if (erri->eflags & TPAX_ERROR_TOP_LEVEL) + return "error logged in"; + + else if (erri->eflags & TPAX_ERROR_NESTED) + return "< returned to >"; + + else + return "distorted state"; +} + +static const char * tpax_output_unit_header(const struct tpax_error_info * erri) +{ + if (!(erri->eflags & TPAX_ERROR_CUSTOM)) + return "while opening"; + + else + return "while parsing"; +} + +static const char * tpax_output_strerror( + const struct tpax_error_info * erri, + char (*errbuf)[256]) +{ + if (erri->eflags & TPAX_ERROR_CUSTOM) + return ((erri->elibcode < 0) || (erri->elibcode >= TPAX_ERR_CAP)) + ? "internal error: please report to the maintainer" + : tpax_error_strings[erri->elibcode]; + + else if (erri->eflags & TPAX_ERROR_NESTED) + return ""; + + else if (erri->eflags & TPAX_ERROR_CHILD) + return "(see child process error messages)"; + + else if (erri->esyscode == ENOBUFS) + return "input error: string length exceeds buffer size"; + + else + return strerror_r(erri->esyscode,*errbuf,sizeof(*errbuf)) + ? "internal error: strerror_r(3) call failed" + : *errbuf; + +} + +static int tpax_output_error_record_plain( + const struct tpax_driver_ctx * dctx, + const struct tpax_error_info * erri) +{ + const char * epath; + char errbuf[256]; + + int fderr = tpax_driver_fderr(dctx); + const char * errdesc = tpax_output_strerror(erri,&errbuf); + + epath = erri->euctx + ? *erri->euctx->path + : erri->eunit; + + if (epath && !(erri->eflags & TPAX_ERROR_NESTED)) + if (tpax_dprintf( + fderr, + "%s: [%s] '%s':\n", + dctx->program, + tpax_output_unit_header(erri), + epath) < 0) + return -1; + + if (tpax_dprintf( + fderr, + "%s: %s %s(), line %d%s%s.\n", + dctx->program, + tpax_output_error_header(erri), + erri->efunction, + erri->eline, + strlen(errdesc) ? ": " : "", + errdesc) < 0) + return -1; + + return 0; +} + +static int tpax_output_error_record_annotated( + const struct tpax_driver_ctx * dctx, + const struct tpax_error_info * erri) +{ + const char * epath; + char errbuf[256]; + + int fderr = tpax_driver_fderr(dctx); + const char * errdesc = tpax_output_strerror(erri,&errbuf); + + epath = erri->euctx + ? *erri->euctx->path + : erri->eunit; + + if (epath && !(erri->eflags & TPAX_ERROR_NESTED)) + if (tpax_dprintf( + fderr, + "%s%s%s:%s %s[%s]%s %s%s'%s'%s:\n", + + aclr_bold,aclr_magenta, + dctx->program, + aclr_reset, + + aclr_bold, + tpax_output_unit_header(erri), + aclr_reset, + + aclr_bold,aclr_red, + epath, + aclr_reset) < 0) + return -1; + + if (tpax_dprintf( + fderr, + "%s%s%s:%s %s%s%s %s%s%s()%s, %s%sline %d%s%s%s%s%s.\n", + + aclr_bold,aclr_magenta, + dctx->program, + aclr_reset, + + aclr_bold, + tpax_output_error_header(erri), + aclr_reset, + + aclr_bold,aclr_blue, + erri->efunction, + aclr_reset, + + aclr_bold,aclr_green, + erri->eline, + aclr_reset, + strlen(errdesc) ? ": " : "", + + aclr_bold, + errdesc, + aclr_reset) < 0) + return -1; + + return 0; +} + +int tpax_output_error_record( + const struct tpax_driver_ctx * dctx, + const struct tpax_error_info * erri) +{ + if (dctx->cctx->drvflags & TPAX_DRIVER_ANNOTATE_NEVER) + return tpax_output_error_record_plain(dctx,erri); + + else if (dctx->cctx->drvflags & TPAX_DRIVER_ANNOTATE_ALWAYS) + return tpax_output_error_record_annotated(dctx,erri); + + else if (isatty(tpax_driver_fderr(dctx))) + return tpax_output_error_record_annotated(dctx,erri); + + else + return tpax_output_error_record_plain(dctx,erri); +} + +static int tpax_output_error_vector_plain(const struct tpax_driver_ctx * dctx) +{ + struct tpax_error_info ** perr; + + for (perr=dctx->errv; *perr; perr++) + if (tpax_output_error_record_plain(dctx,*perr)) + return -1; + + return 0; +} + +static int tpax_output_error_vector_annotated(const struct tpax_driver_ctx * dctx) +{ + struct tpax_error_info ** perr; + + for (perr=dctx->errv; *perr; perr++) + if (tpax_output_error_record_annotated(dctx,*perr)) + return -1; + + return 0; +} + +int tpax_output_error_vector(const struct tpax_driver_ctx * dctx) +{ + if (dctx->cctx->drvflags & TPAX_DRIVER_ANNOTATE_NEVER) + return tpax_output_error_vector_plain(dctx); + + else if (dctx->cctx->drvflags & TPAX_DRIVER_ANNOTATE_ALWAYS) + return tpax_output_error_vector_annotated(dctx); + + else if (isatty(tpax_driver_fderr(dctx))) + return tpax_output_error_vector_annotated(dctx); + + else + return tpax_output_error_vector_plain(dctx); +} diff --git a/src/skin/tpax_skin_default.c b/src/skin/tpax_skin_default.c new file mode 100644 index 0000000..c969ff3 --- /dev/null +++ b/src/skin/tpax_skin_default.c @@ -0,0 +1,12 @@ +#include "tpax_driver_impl.h" +#include "argv/argv.h" + +const struct argv_option tpax_default_options[] = { + {"version", 0,TAG_VERSION,ARGV_OPTARG_NONE,0,0,0, + "show version information"}, + + {"help", 0,TAG_HELP,ARGV_OPTARG_OPTIONAL,0,"short|long",0, + "show usage information [listing %s options only]"}, + + {0,0,0,0,0,0,0,0} +}; diff --git a/src/tpax.c b/src/tpax.c new file mode 100644 index 0000000..a2af3b7 --- /dev/null +++ b/src/tpax.c @@ -0,0 +1,12 @@ +/******************************************************/ +/* tpax: a topological pax implementation */ +/* Copyright (C) 2020 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */ +/******************************************************/ + +#include <tpax/tpax.h> + +int main(int argc, char ** argv, char ** envp) +{ + return tpax_main(argv,envp,0); +} |