/**************************************************************/ /* tpax: a topological pax implementation */ /* Copyright (C) 2020--2021 SysDeer Technologies, LLC */ /* Released under GPLv2 and GPLv3; see COPYING.TPAX. */ /**************************************************************/ #include #include #include #include #include #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", [TPAX_ERR_FILE_CHANGED] = "file has changed", [TPAX_ERR_REGION_SIZE] = "file too large for a memory snapshot", }; 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); }