[MKISOFS]
[reactos.git] / reactos / sdk / tools / mkisofs / schilytools / libschily / checkerr.c
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 }