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