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