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 /src | |
parent | fa6b3e3522edcd8c202669c5587f2b5c77ac150d (diff) | |
download | tpax-88751e9e5ee3726b8a6987aeaae04e956c2234f5.tar.bz2 tpax-88751e9e5ee3726b8a6987aeaae04e956c2234f5.tar.xz |
created lib-app skeleton (foss21.org lib-app model).
Diffstat (limited to 'src')
-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 |
12 files changed, 997 insertions, 0 deletions
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); +} |