1 /* @(#)checkerr.c 1.24 09/07/08 Copyright 2003-2009 J. Schilling */ 2 #include <schily/mconfig.h> 3 #ifndef lint 4 static UConst char sccsid[] = 5 "@(#)checkerr.c 1.24 09/07/08 Copyright 2003-2009 J. Schilling"; 6 #endif 7 /* 8 * Generic error control for programs that do file i/o. 9 * The error control is usually used by archiving programs. 10 * 11 * The current version does not provide a stable interface. 12 * It does not support multi-threaded programs and it may call 13 * comerr() from the parser. If you use the code before there is 14 * an official stable and "library-compliant" interface, be careful 15 * and watch for changes. 16 * 17 * Copyright (c) 2003-2009 J. Schilling 18 */ 19 /* 20 * The contents of this file are subject to the terms of the 21 * Common Development and Distribution License, Version 1.0 only 22 * (the "License"). You may not use this file except in compliance 23 * with the License. 24 * 25 * See the file CDDL.Schily.txt in this distribution for details. 26 * 27 * When distributing Covered Code, include this CDDL HEADER in each 28 * file and include the License file CDDL.Schily.txt from this distribution. 29 */ 30 31 #include <schily/stdio.h> 32 #include <schily/standard.h> 33 #include <schily/patmatch.h> 34 #include <schily/string.h> 35 #include <schily/utypes.h> 36 #include <schily/schily.h> 37 #include <schily/checkerr.h> 38 39 typedef struct errconf { 40 struct errconf *ec_next; /* Next in list */ 41 const Uchar *ec_pat; /* File name pattern */ 42 int *ec_aux; /* Aux array from pattern compiler */ 43 int ec_alt; /* Alt return from pattern compiler */ 44 int ec_plen; /* String length of pattern */ 45 UInt32_t ec_flags; /* Error condition flags */ 46 } ec_t; 47 48 LOCAL int *ec_state; /* State array for pattern compiler */ 49 LOCAL ec_t *ec_root; /* Root node of error config list */ 50 LOCAL ec_t **ec_last = &ec_root; /* Last pointer in root node list */ 51 LOCAL int maxplen; 52 LOCAL BOOL _errflag = TRUE; /* Abort on all errors */ 53 54 EXPORT int errconfig __PR((char *name)); 55 LOCAL char *_endword __PR((char *p)); 56 LOCAL void parse_errctl __PR((char *line)); 57 LOCAL UInt32_t errflags __PR((char *eflag, BOOL doexit)); 58 LOCAL ec_t *_errptr __PR((int etype, const char *fname)); 59 EXPORT BOOL errhidden __PR((int etype, const char *fname)); 60 EXPORT BOOL errwarnonly __PR((int etype, const char *fname)); 61 EXPORT BOOL errabort __PR((int etype, const char *fname, BOOL doexit)); 62 63 /* 64 * Read and parse error configuration file 65 */ 66 EXPORT int 67 errconfig(name) 68 char *name; 69 { 70 char line[8192]; 71 FILE *f; 72 int omaxplen = maxplen; 73 74 if ((f = fileopen(name, "r")) == NULL) { 75 if (errflags(name, FALSE) != 0) 76 parse_errctl(name); 77 else 78 comerr("Cannot open '%s'.\n", name); 79 } else { 80 while (fgetline(f, line, sizeof (line)) >= 0) { 81 parse_errctl(line); 82 } 83 fclose(f); 84 } 85 if (maxplen > omaxplen) { 86 ec_state = ___realloc(ec_state, (maxplen+1)*sizeof (int), 87 "pattern state"); 88 } 89 return (1); 90 } 91 92 LOCAL char * 93 _endword(p) 94 char *p; 95 { 96 /* 97 * Find end of word. 98 */ 99 for (; *p != '\0' && 100 *p != '\t' && 101 *p != ' '; 102 p++) { 103 ; 104 /* LINTED */ 105 } 106 return (p); 107 } 108 109 LOCAL void 110 parse_errctl(line) 111 char *line; 112 { 113 int plen; 114 char *pattern; 115 ec_t *ep; 116 117 /* 118 * Find end of word. 119 */ 120 pattern = _endword(line); 121 122 if (pattern == line || *pattern == '\0') { 123 comerrno(EX_BAD, 124 "Bad error configuration line '%s'.\n", line); 125 } 126 /* 127 * Find end of white space after word. 128 */ 129 for (pattern++; *pattern != '\0' && 130 (*pattern == '\t' || *pattern == ' '); 131 pattern++) { 132 ; 133 /* LINTED */ 134 } 135 ep = ___malloc(sizeof (ec_t), "errcheck node"); 136 ep->ec_flags = errflags(line, TRUE); 137 ep->ec_plen = plen = strlen(pattern); 138 if (ep->ec_plen > maxplen) 139 maxplen = ep->ec_plen; 140 ep->ec_pat = (const Uchar *)___savestr(pattern); 141 ep->ec_aux = ___malloc(plen*sizeof (int), "compiled pattern"); 142 if ((ep->ec_alt = patcompile((const Uchar *)pattern, 143 plen, ep->ec_aux)) == 0) 144 comerrno(EX_BAD, "Bad errctl pattern: '%s'.\n", pattern); 145 146 ep->ec_next = NULL; 147 *ec_last = ep; 148 ec_last = &ep->ec_next; 149 } 150 151 LOCAL struct eflags { 152 char *fname; 153 UInt32_t fval; 154 } eflags[] = { 155 { "STAT", E_STAT }, 156 { "GETACL", E_GETACL }, 157 { "OPEN", E_OPEN }, 158 { "READ", E_READ }, 159 { "WRITE", E_WRITE }, 160 { "GROW", E_GROW }, 161 { "SHRINK", E_SHRINK }, 162 { "MISSLINK", E_MISSLINK }, 163 { "NAMETOOLONG", E_NAMETOOLONG }, 164 { "FILETOOBIG", E_FILETOOBIG }, 165 { "SPECIALFILE", E_SPECIALFILE }, 166 { "READLINK", E_READLINK }, 167 { "GETXATTR", E_GETXATTR }, 168 { "CHDIR", E_CHDIR }, 169 170 { "SETTIME", E_SETTIME }, 171 { "SETMODE", E_SETMODE }, 172 { "SECURITY", E_SECURITY }, 173 { "LSECURITY", E_LSECURITY }, 174 { "SAMEFILE", E_SAMEFILE }, 175 { "BADACL", E_BADACL }, 176 { "SETACL", E_SETACL }, 177 { "SETXATTR", E_SETXATTR }, 178 179 { "ALL", E_ALL }, 180 181 { "DIFF", E_DIFF }, 182 { "WARN", E_WARN }, 183 { "ABORT", E_ABORT }, 184 185 { NULL, 0 } 186 }; 187 188 /* 189 * Convert error condition string into flag word 190 */ 191 LOCAL UInt32_t 192 errflags(eflag, doexit) 193 char *eflag; 194 BOOL doexit; 195 { 196 register char *p = eflag; 197 char *ef = _endword(eflag); 198 register struct eflags *ep; 199 register int slen; 200 register UInt32_t nflags = 0; 201 202 do { 203 for (ep = eflags; ep->fname; ep++) { 204 slen = strlen(ep->fname); 205 if ((strncmp(ep->fname, p, slen) == 0) && 206 (p[slen] == '|' || p[slen] == ' ' || 207 p[slen] == '\0')) { 208 nflags |= ep->fval; 209 break; 210 } 211 } 212 if (ep->fname == NULL) { 213 if (doexit) 214 comerrno(EX_BAD, "Bad flag '%s'\n", p); 215 return (0); 216 } 217 p = strchr(p, '|'); 218 } while (p < ef && p && *p++ == '|'); 219 220 if ((nflags & ~(UInt32_t)(E_ABORT|E_WARN)) == 0) { 221 if (doexit) 222 comerrno(EX_BAD, "Bad error condition '%s'.\n", eflag); 223 return (0); 224 } 225 return (nflags); 226 } 227 228 LOCAL ec_t * 229 _errptr(etype, fname) 230 int etype; 231 const char *fname; 232 { 233 ec_t *ep = ec_root; 234 char *ret; 235 const Uchar *name = (const Uchar *)fname; 236 int nlen; 237 238 if (fname == NULL) { 239 errmsgno(EX_BAD, 240 "Implementation botch for errhidden(0x%X, NULL)\n", 241 etype); 242 errmsgno(EX_BAD, "Please report this bug!\n"); 243 errmsgno(EX_BAD, "Error cannot be ignored.\n"); 244 return ((ec_t *)NULL); 245 } 246 nlen = strlen(fname); 247 while (ep) { 248 if ((ep->ec_flags & etype) != 0) { 249 ret = (char *)patmatch(ep->ec_pat, ep->ec_aux, 250 name, 0, 251 nlen, ep->ec_alt, ec_state); 252 if (ret != NULL && *ret == '\0') 253 return (ep); 254 } 255 ep = ep->ec_next; 256 } 257 return ((ec_t *)NULL); 258 } 259 260 /* 261 * Check whether error condition should be ignored for file name. 262 */ 263 EXPORT BOOL 264 errhidden(etype, fname) 265 int etype; 266 const char *fname; 267 { 268 ec_t *ep; 269 270 if ((ep = _errptr(etype, fname)) != NULL) { 271 if ((ep->ec_flags & (E_ABORT|E_WARN)) != 0) 272 return (FALSE); 273 return (TRUE); 274 } 275 return (FALSE); 276 } 277 278 /* 279 * Check whether error condition should not affect exit code for file name. 280 */ 281 EXPORT BOOL 282 errwarnonly(etype, fname) 283 int etype; 284 const char *fname; 285 { 286 ec_t *ep; 287 288 if ((ep = _errptr(etype, fname)) != NULL) { 289 if ((ep->ec_flags & E_WARN) != 0) 290 return (TRUE); 291 return (FALSE); 292 } 293 return (FALSE); 294 } 295 296 /* 297 * Check whether error condition should be fatal for file name. 298 */ 299 EXPORT BOOL 300 errabort(etype, fname, doexit) 301 int etype; 302 const char *fname; 303 BOOL doexit; 304 { 305 ec_t *ep; 306 307 if ((ep = _errptr(etype, fname)) == NULL) { 308 if (!_errflag) 309 return (FALSE); 310 } else if ((ep->ec_flags & E_ABORT) == 0) 311 return (FALSE); 312 313 if (doexit) { 314 errmsgno(EX_BAD, "Error is considered fatal, aborting.\n"); 315 #ifdef CALL_OTHER_FUNCTION 316 if (other_func != NULL) 317 (*other_func)(); 318 else 319 #endif 320 comexit(-3); 321 } 322 return (TRUE); 323 } 324