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