/* @(#)checkerr.c 1.24 09/07/08 Copyright 2003-2009 J. Schilling */ #include #ifndef lint static UConst char sccsid[] = "@(#)checkerr.c 1.24 09/07/08 Copyright 2003-2009 J. Schilling"; #endif /* * Generic error control for programs that do file i/o. * The error control is usually used by archiving programs. * * The current version does not provide a stable interface. * It does not support multi-threaded programs and it may call * comerr() from the parser. If you use the code before there is * an official stable and "library-compliant" interface, be careful * and watch for changes. * * Copyright (c) 2003-2009 J. Schilling */ /* * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * See the file CDDL.Schily.txt in this distribution for details. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file CDDL.Schily.txt from this distribution. */ #include #include #include #include #include #include #include typedef struct errconf { struct errconf *ec_next; /* Next in list */ const Uchar *ec_pat; /* File name pattern */ int *ec_aux; /* Aux array from pattern compiler */ int ec_alt; /* Alt return from pattern compiler */ int ec_plen; /* String length of pattern */ UInt32_t ec_flags; /* Error condition flags */ } ec_t; LOCAL int *ec_state; /* State array for pattern compiler */ LOCAL ec_t *ec_root; /* Root node of error config list */ LOCAL ec_t **ec_last = &ec_root; /* Last pointer in root node list */ LOCAL int maxplen; LOCAL BOOL _errflag = TRUE; /* Abort on all errors */ EXPORT int errconfig __PR((char *name)); LOCAL char *_endword __PR((char *p)); LOCAL void parse_errctl __PR((char *line)); LOCAL UInt32_t errflags __PR((char *eflag, BOOL doexit)); LOCAL ec_t *_errptr __PR((int etype, const char *fname)); EXPORT BOOL errhidden __PR((int etype, const char *fname)); EXPORT BOOL errwarnonly __PR((int etype, const char *fname)); EXPORT BOOL errabort __PR((int etype, const char *fname, BOOL doexit)); /* * Read and parse error configuration file */ EXPORT int errconfig(name) char *name; { char line[8192]; FILE *f; int omaxplen = maxplen; if ((f = fileopen(name, "r")) == NULL) { if (errflags(name, FALSE) != 0) parse_errctl(name); else comerr("Cannot open '%s'.\n", name); } else { while (fgetline(f, line, sizeof (line)) >= 0) { parse_errctl(line); } fclose(f); } if (maxplen > omaxplen) { ec_state = ___realloc(ec_state, (maxplen+1)*sizeof (int), "pattern state"); } return (1); } LOCAL char * _endword(p) char *p; { /* * Find end of word. */ for (; *p != '\0' && *p != '\t' && *p != ' '; p++) { ; /* LINTED */ } return (p); } LOCAL void parse_errctl(line) char *line; { int plen; char *pattern; ec_t *ep; /* * Find end of word. */ pattern = _endword(line); if (pattern == line || *pattern == '\0') { comerrno(EX_BAD, "Bad error configuration line '%s'.\n", line); } /* * Find end of white space after word. */ for (pattern++; *pattern != '\0' && (*pattern == '\t' || *pattern == ' '); pattern++) { ; /* LINTED */ } ep = ___malloc(sizeof (ec_t), "errcheck node"); ep->ec_flags = errflags(line, TRUE); ep->ec_plen = plen = strlen(pattern); if (ep->ec_plen > maxplen) maxplen = ep->ec_plen; ep->ec_pat = (const Uchar *)___savestr(pattern); ep->ec_aux = ___malloc(plen*sizeof (int), "compiled pattern"); if ((ep->ec_alt = patcompile((const Uchar *)pattern, plen, ep->ec_aux)) == 0) comerrno(EX_BAD, "Bad errctl pattern: '%s'.\n", pattern); ep->ec_next = NULL; *ec_last = ep; ec_last = &ep->ec_next; } LOCAL struct eflags { char *fname; UInt32_t fval; } eflags[] = { { "STAT", E_STAT }, { "GETACL", E_GETACL }, { "OPEN", E_OPEN }, { "READ", E_READ }, { "WRITE", E_WRITE }, { "GROW", E_GROW }, { "SHRINK", E_SHRINK }, { "MISSLINK", E_MISSLINK }, { "NAMETOOLONG", E_NAMETOOLONG }, { "FILETOOBIG", E_FILETOOBIG }, { "SPECIALFILE", E_SPECIALFILE }, { "READLINK", E_READLINK }, { "GETXATTR", E_GETXATTR }, { "CHDIR", E_CHDIR }, { "SETTIME", E_SETTIME }, { "SETMODE", E_SETMODE }, { "SECURITY", E_SECURITY }, { "LSECURITY", E_LSECURITY }, { "SAMEFILE", E_SAMEFILE }, { "BADACL", E_BADACL }, { "SETACL", E_SETACL }, { "SETXATTR", E_SETXATTR }, { "ALL", E_ALL }, { "DIFF", E_DIFF }, { "WARN", E_WARN }, { "ABORT", E_ABORT }, { NULL, 0 } }; /* * Convert error condition string into flag word */ LOCAL UInt32_t errflags(eflag, doexit) char *eflag; BOOL doexit; { register char *p = eflag; char *ef = _endword(eflag); register struct eflags *ep; register int slen; register UInt32_t nflags = 0; do { for (ep = eflags; ep->fname; ep++) { slen = strlen(ep->fname); if ((strncmp(ep->fname, p, slen) == 0) && (p[slen] == '|' || p[slen] == ' ' || p[slen] == '\0')) { nflags |= ep->fval; break; } } if (ep->fname == NULL) { if (doexit) comerrno(EX_BAD, "Bad flag '%s'\n", p); return (0); } p = strchr(p, '|'); } while (p < ef && p && *p++ == '|'); if ((nflags & ~(UInt32_t)(E_ABORT|E_WARN)) == 0) { if (doexit) comerrno(EX_BAD, "Bad error condition '%s'.\n", eflag); return (0); } return (nflags); } LOCAL ec_t * _errptr(etype, fname) int etype; const char *fname; { ec_t *ep = ec_root; char *ret; const Uchar *name = (const Uchar *)fname; int nlen; if (fname == NULL) { errmsgno(EX_BAD, "Implementation botch for errhidden(0x%X, NULL)\n", etype); errmsgno(EX_BAD, "Please report this bug!\n"); errmsgno(EX_BAD, "Error cannot be ignored.\n"); return ((ec_t *)NULL); } nlen = strlen(fname); while (ep) { if ((ep->ec_flags & etype) != 0) { ret = (char *)patmatch(ep->ec_pat, ep->ec_aux, name, 0, nlen, ep->ec_alt, ec_state); if (ret != NULL && *ret == '\0') return (ep); } ep = ep->ec_next; } return ((ec_t *)NULL); } /* * Check whether error condition should be ignored for file name. */ EXPORT BOOL errhidden(etype, fname) int etype; const char *fname; { ec_t *ep; if ((ep = _errptr(etype, fname)) != NULL) { if ((ep->ec_flags & (E_ABORT|E_WARN)) != 0) return (FALSE); return (TRUE); } return (FALSE); } /* * Check whether error condition should not affect exit code for file name. */ EXPORT BOOL errwarnonly(etype, fname) int etype; const char *fname; { ec_t *ep; if ((ep = _errptr(etype, fname)) != NULL) { if ((ep->ec_flags & E_WARN) != 0) return (TRUE); return (FALSE); } return (FALSE); } /* * Check whether error condition should be fatal for file name. */ EXPORT BOOL errabort(etype, fname, doexit) int etype; const char *fname; BOOL doexit; { ec_t *ep; if ((ep = _errptr(etype, fname)) == NULL) { if (!_errflag) return (FALSE); } else if ((ep->ec_flags & E_ABORT) == 0) return (FALSE); if (doexit) { errmsgno(EX_BAD, "Error is considered fatal, aborting.\n"); #ifdef CALL_OTHER_FUNCTION if (other_func != NULL) (*other_func)(); else #endif comexit(-3); } return (TRUE); }