1*1fcced4cSJordan Brown /*
2*1fcced4cSJordan Brown * CDDL HEADER START
3*1fcced4cSJordan Brown *
4*1fcced4cSJordan Brown * The contents of this file are subject to the terms of the
5*1fcced4cSJordan Brown * Common Development and Distribution License (the "License").
6*1fcced4cSJordan Brown * You may not use this file except in compliance with the License.
7*1fcced4cSJordan Brown *
8*1fcced4cSJordan Brown * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1fcced4cSJordan Brown * or http://www.opensolaris.org/os/licensing.
10*1fcced4cSJordan Brown * See the License for the specific language governing permissions
11*1fcced4cSJordan Brown * and limitations under the License.
12*1fcced4cSJordan Brown *
13*1fcced4cSJordan Brown * When distributing Covered Code, include this CDDL HEADER in each
14*1fcced4cSJordan Brown * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1fcced4cSJordan Brown * If applicable, add the following below this CDDL HEADER, with the
16*1fcced4cSJordan Brown * fields enclosed by brackets "[]" replaced with your own identifying
17*1fcced4cSJordan Brown * information: Portions Copyright [yyyy] [name of copyright owner]
18*1fcced4cSJordan Brown *
19*1fcced4cSJordan Brown * CDDL HEADER END
20*1fcced4cSJordan Brown */
21*1fcced4cSJordan Brown
22*1fcced4cSJordan Brown /*
23*1fcced4cSJordan Brown * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24*1fcced4cSJordan Brown * Use is subject to license terms.
25*1fcced4cSJordan Brown */
26*1fcced4cSJordan Brown
27*1fcced4cSJordan Brown /*
28*1fcced4cSJordan Brown * Error handling support for directory lookup.
29*1fcced4cSJordan Brown * Actually, this is intended to be a very generic and extensible error
30*1fcced4cSJordan Brown * reporting mechanism.
31*1fcced4cSJordan Brown */
32*1fcced4cSJordan Brown
33*1fcced4cSJordan Brown #include <stdio.h>
34*1fcced4cSJordan Brown #include <stdlib.h>
35*1fcced4cSJordan Brown #include <thread.h>
36*1fcced4cSJordan Brown #include <errno.h>
37*1fcced4cSJordan Brown #include <stdarg.h>
38*1fcced4cSJordan Brown #include <malloc.h>
39*1fcced4cSJordan Brown #include <string.h>
40*1fcced4cSJordan Brown #include <ctype.h>
41*1fcced4cSJordan Brown #include <syslog.h>
42*1fcced4cSJordan Brown #include <idmap_impl.h>
43*1fcced4cSJordan Brown #include <rpcsvc/idmap_prot.h>
44*1fcced4cSJordan Brown #include <libintl.h>
45*1fcced4cSJordan Brown #include "directory.h"
46*1fcced4cSJordan Brown
47*1fcced4cSJordan Brown /*
48*1fcced4cSJordan Brown * This is the actual implementation of the opaque directory_error_t structure.
49*1fcced4cSJordan Brown */
50*1fcced4cSJordan Brown struct directory_error {
51*1fcced4cSJordan Brown /*
52*1fcced4cSJordan Brown * True if this directory_error_t is statically allocated. Used to
53*1fcced4cSJordan Brown * handle out of memory errors during error reporting.
54*1fcced4cSJordan Brown */
55*1fcced4cSJordan Brown boolean_t is_static;
56*1fcced4cSJordan Brown
57*1fcced4cSJordan Brown /*
58*1fcced4cSJordan Brown * The error code. This is a locale-independent string that
59*1fcced4cSJordan Brown * represents the precise error (to some level of granularity)
60*1fcced4cSJordan Brown * that occurred. Internationalization processing could map it
61*1fcced4cSJordan Brown * to an message. Errors may be subclassed by appending a dot
62*1fcced4cSJordan Brown * and a name for the subclass.
63*1fcced4cSJordan Brown *
64*1fcced4cSJordan Brown * Note that this code plus the parameters allows for structured
65*1fcced4cSJordan Brown * processing of error results.
66*1fcced4cSJordan Brown */
67*1fcced4cSJordan Brown char *code;
68*1fcced4cSJordan Brown
69*1fcced4cSJordan Brown /*
70*1fcced4cSJordan Brown * The default (in the absence of internationalization) format for
71*1fcced4cSJordan Brown * the error message. %n interposes params[n - 1].
72*1fcced4cSJordan Brown */
73*1fcced4cSJordan Brown char *fmt;
74*1fcced4cSJordan Brown
75*1fcced4cSJordan Brown /*
76*1fcced4cSJordan Brown * Parameters to the error message. Note that subclasses are
77*1fcced4cSJordan Brown * required to have the same initial parameters as their superclasses,
78*1fcced4cSJordan Brown * so that code that processes the superclass can work on the subclass.
79*1fcced4cSJordan Brown */
80*1fcced4cSJordan Brown int nparams;
81*1fcced4cSJordan Brown char **params;
82*1fcced4cSJordan Brown
83*1fcced4cSJordan Brown /*
84*1fcced4cSJordan Brown * Cached printable form (that is, with params[] interpolated into
85*1fcced4cSJordan Brown * fmt) of the error message. Created when requested.
86*1fcced4cSJordan Brown */
87*1fcced4cSJordan Brown char *printable;
88*1fcced4cSJordan Brown };
89*1fcced4cSJordan Brown
90*1fcced4cSJordan Brown static directory_error_t directory_error_internal_error(int err);
91*1fcced4cSJordan Brown
92*1fcced4cSJordan Brown /*
93*1fcced4cSJordan Brown * For debugging, reference count of directory_error instances still in
94*1fcced4cSJordan Brown * existence. When the system is idle, this should be zero.
95*1fcced4cSJordan Brown * Note that no attempt is made to make this MT safe, so it is not reliable
96*1fcced4cSJordan Brown * in an MT environment.
97*1fcced4cSJordan Brown */
98*1fcced4cSJordan Brown static int directory_errors_outstanding = 0;
99*1fcced4cSJordan Brown
100*1fcced4cSJordan Brown /*
101*1fcced4cSJordan Brown * Free the specified directory_error_t. Note that this invalidates all strings
102*1fcced4cSJordan Brown * returned based on it.
103*1fcced4cSJordan Brown *
104*1fcced4cSJordan Brown * Does nothing when de==NULL.
105*1fcced4cSJordan Brown */
106*1fcced4cSJordan Brown void
directory_error_free(directory_error_t de)107*1fcced4cSJordan Brown directory_error_free(directory_error_t de)
108*1fcced4cSJordan Brown {
109*1fcced4cSJordan Brown int i;
110*1fcced4cSJordan Brown
111*1fcced4cSJordan Brown if (de == NULL)
112*1fcced4cSJordan Brown return;
113*1fcced4cSJordan Brown
114*1fcced4cSJordan Brown /* Don't free our internal static directory_error_ts! */
115*1fcced4cSJordan Brown if (de->is_static)
116*1fcced4cSJordan Brown return;
117*1fcced4cSJordan Brown
118*1fcced4cSJordan Brown free(de->code);
119*1fcced4cSJordan Brown de->code = NULL;
120*1fcced4cSJordan Brown free(de->fmt);
121*1fcced4cSJordan Brown de->fmt = NULL;
122*1fcced4cSJordan Brown
123*1fcced4cSJordan Brown /* Free parameters, if any */
124*1fcced4cSJordan Brown if (de->params != NULL) {
125*1fcced4cSJordan Brown for (i = 0; i < de->nparams; i++) {
126*1fcced4cSJordan Brown free(de->params[i]);
127*1fcced4cSJordan Brown de->params[i] = NULL;
128*1fcced4cSJordan Brown }
129*1fcced4cSJordan Brown free(de->params);
130*1fcced4cSJordan Brown de->params = NULL;
131*1fcced4cSJordan Brown }
132*1fcced4cSJordan Brown
133*1fcced4cSJordan Brown /* Free cached printable */
134*1fcced4cSJordan Brown free(de->printable);
135*1fcced4cSJordan Brown de->printable = NULL;
136*1fcced4cSJordan Brown
137*1fcced4cSJordan Brown free(de);
138*1fcced4cSJordan Brown
139*1fcced4cSJordan Brown directory_errors_outstanding--;
140*1fcced4cSJordan Brown }
141*1fcced4cSJordan Brown
142*1fcced4cSJordan Brown /*
143*1fcced4cSJordan Brown * de = directory_error(code, fmt [, arg1 ... ]);
144*1fcced4cSJordan Brown * Code, fmt, and arguments must be strings and will be copied.
145*1fcced4cSJordan Brown */
146*1fcced4cSJordan Brown directory_error_t
directory_error(const char * code,const char * fmt,...)147*1fcced4cSJordan Brown directory_error(const char *code, const char *fmt, ...)
148*1fcced4cSJordan Brown {
149*1fcced4cSJordan Brown directory_error_t de = NULL;
150*1fcced4cSJordan Brown va_list va;
151*1fcced4cSJordan Brown int i;
152*1fcced4cSJordan Brown
153*1fcced4cSJordan Brown de = calloc(1, sizeof (*de));
154*1fcced4cSJordan Brown if (de == NULL)
155*1fcced4cSJordan Brown goto nomem;
156*1fcced4cSJordan Brown
157*1fcced4cSJordan Brown directory_errors_outstanding++;
158*1fcced4cSJordan Brown
159*1fcced4cSJordan Brown de->is_static = B_FALSE;
160*1fcced4cSJordan Brown
161*1fcced4cSJordan Brown de->code = strdup(code);
162*1fcced4cSJordan Brown if (de->code == NULL)
163*1fcced4cSJordan Brown goto nomem;
164*1fcced4cSJordan Brown
165*1fcced4cSJordan Brown de->fmt = strdup(fmt);
166*1fcced4cSJordan Brown if (de->fmt == NULL)
167*1fcced4cSJordan Brown goto nomem;
168*1fcced4cSJordan Brown
169*1fcced4cSJordan Brown /* Count our parameters */
170*1fcced4cSJordan Brown va_start(va, fmt);
171*1fcced4cSJordan Brown for (i = 0; va_arg(va, char *) != NULL; i++)
172*1fcced4cSJordan Brown /* LOOP */;
173*1fcced4cSJordan Brown va_end(va);
174*1fcced4cSJordan Brown
175*1fcced4cSJordan Brown de->nparams = i;
176*1fcced4cSJordan Brown
177*1fcced4cSJordan Brown /*
178*1fcced4cSJordan Brown * Note that we do not copy the terminating NULL because we have
179*1fcced4cSJordan Brown * a count.
180*1fcced4cSJordan Brown */
181*1fcced4cSJordan Brown de->params = calloc(de->nparams, sizeof (char *));
182*1fcced4cSJordan Brown if (de->params == NULL)
183*1fcced4cSJordan Brown goto nomem;
184*1fcced4cSJordan Brown
185*1fcced4cSJordan Brown va_start(va, fmt);
186*1fcced4cSJordan Brown for (i = 0; i < de->nparams; i++) {
187*1fcced4cSJordan Brown de->params[i] = strdup((char *)va_arg(va, char *));
188*1fcced4cSJordan Brown if (de->params[i] == NULL) {
189*1fcced4cSJordan Brown va_end(va);
190*1fcced4cSJordan Brown goto nomem;
191*1fcced4cSJordan Brown }
192*1fcced4cSJordan Brown }
193*1fcced4cSJordan Brown va_end(va);
194*1fcced4cSJordan Brown
195*1fcced4cSJordan Brown return (de);
196*1fcced4cSJordan Brown
197*1fcced4cSJordan Brown nomem:;
198*1fcced4cSJordan Brown int err = errno;
199*1fcced4cSJordan Brown directory_error_free(de);
200*1fcced4cSJordan Brown return (directory_error_internal_error(err));
201*1fcced4cSJordan Brown }
202*1fcced4cSJordan Brown
203*1fcced4cSJordan Brown /*
204*1fcced4cSJordan Brown * Transform a directory_error returned by RPC into a directory_error_t.
205*1fcced4cSJordan Brown */
206*1fcced4cSJordan Brown directory_error_t
directory_error_from_rpc(directory_error_rpc * de_rpc)207*1fcced4cSJordan Brown directory_error_from_rpc(directory_error_rpc *de_rpc)
208*1fcced4cSJordan Brown {
209*1fcced4cSJordan Brown directory_error_t de;
210*1fcced4cSJordan Brown int i;
211*1fcced4cSJordan Brown
212*1fcced4cSJordan Brown de = calloc(1, sizeof (*de));
213*1fcced4cSJordan Brown if (de == NULL)
214*1fcced4cSJordan Brown goto nomem;
215*1fcced4cSJordan Brown
216*1fcced4cSJordan Brown directory_errors_outstanding++;
217*1fcced4cSJordan Brown
218*1fcced4cSJordan Brown de->is_static = B_FALSE;
219*1fcced4cSJordan Brown de->code = strdup(de_rpc->code);
220*1fcced4cSJordan Brown if (de->code == NULL)
221*1fcced4cSJordan Brown goto nomem;
222*1fcced4cSJordan Brown de->fmt = strdup(de_rpc->fmt);
223*1fcced4cSJordan Brown if (de->fmt == NULL)
224*1fcced4cSJordan Brown goto nomem;
225*1fcced4cSJordan Brown
226*1fcced4cSJordan Brown de->nparams = de_rpc->params.params_len;
227*1fcced4cSJordan Brown
228*1fcced4cSJordan Brown de->params = calloc(de->nparams, sizeof (char *));
229*1fcced4cSJordan Brown if (de->params == NULL)
230*1fcced4cSJordan Brown goto nomem;
231*1fcced4cSJordan Brown
232*1fcced4cSJordan Brown for (i = 0; i < de->nparams; i++) {
233*1fcced4cSJordan Brown de->params[i] = strdup(de_rpc->params.params_val[i]);
234*1fcced4cSJordan Brown if (de->params[i] == NULL)
235*1fcced4cSJordan Brown goto nomem;
236*1fcced4cSJordan Brown }
237*1fcced4cSJordan Brown
238*1fcced4cSJordan Brown return (de);
239*1fcced4cSJordan Brown
240*1fcced4cSJordan Brown nomem:;
241*1fcced4cSJordan Brown int err = errno;
242*1fcced4cSJordan Brown directory_error_free(de);
243*1fcced4cSJordan Brown return (directory_error_internal_error(err));
244*1fcced4cSJordan Brown }
245*1fcced4cSJordan Brown
246*1fcced4cSJordan Brown /*
247*1fcced4cSJordan Brown * Convert a directory_error_t into a directory_error to send over RPC.
248*1fcced4cSJordan Brown *
249*1fcced4cSJordan Brown * Returns TRUE on successful conversion, FALSE on failure.
250*1fcced4cSJordan Brown *
251*1fcced4cSJordan Brown * Frees the directory_error_t.
252*1fcced4cSJordan Brown *
253*1fcced4cSJordan Brown * Note that most functions in this suite return boolean_t, as defined
254*1fcced4cSJordan Brown * by types.h. This function is intended to be used directly as the
255*1fcced4cSJordan Brown * return value from an RPC service function, and so it returns bool_t.
256*1fcced4cSJordan Brown */
257*1fcced4cSJordan Brown bool_t
directory_error_to_rpc(directory_error_rpc * de_rpc,directory_error_t de)258*1fcced4cSJordan Brown directory_error_to_rpc(directory_error_rpc *de_rpc, directory_error_t de)
259*1fcced4cSJordan Brown {
260*1fcced4cSJordan Brown int i;
261*1fcced4cSJordan Brown idmap_utf8str *params;
262*1fcced4cSJordan Brown
263*1fcced4cSJordan Brown de_rpc->code = strdup(de->code);
264*1fcced4cSJordan Brown if (de_rpc->code == NULL)
265*1fcced4cSJordan Brown goto nomem;
266*1fcced4cSJordan Brown
267*1fcced4cSJordan Brown de_rpc->fmt = strdup(de->fmt);
268*1fcced4cSJordan Brown if (de_rpc->fmt == NULL)
269*1fcced4cSJordan Brown goto nomem;
270*1fcced4cSJordan Brown
271*1fcced4cSJordan Brown params = calloc(de->nparams, sizeof (idmap_utf8str));
272*1fcced4cSJordan Brown if (params == NULL)
273*1fcced4cSJordan Brown goto nomem;
274*1fcced4cSJordan Brown de_rpc->params.params_val = params;
275*1fcced4cSJordan Brown de_rpc->params.params_len = de->nparams;
276*1fcced4cSJordan Brown
277*1fcced4cSJordan Brown for (i = 0; i < de->nparams; i++) {
278*1fcced4cSJordan Brown params[i] = strdup(de->params[i]);
279*1fcced4cSJordan Brown if (params[i] == NULL)
280*1fcced4cSJordan Brown goto nomem;
281*1fcced4cSJordan Brown }
282*1fcced4cSJordan Brown
283*1fcced4cSJordan Brown directory_error_free(de);
284*1fcced4cSJordan Brown return (TRUE);
285*1fcced4cSJordan Brown
286*1fcced4cSJordan Brown nomem:
287*1fcced4cSJordan Brown logger(LOG_ERR, "Warning: failed to convert error for RPC\n"
288*1fcced4cSJordan Brown "Original error: %s\n"
289*1fcced4cSJordan Brown "Conversion error: %s\n",
290*1fcced4cSJordan Brown strerror(errno),
291*1fcced4cSJordan Brown directory_error_printable(de));
292*1fcced4cSJordan Brown directory_error_free(de);
293*1fcced4cSJordan Brown return (FALSE);
294*1fcced4cSJordan Brown }
295*1fcced4cSJordan Brown
296*1fcced4cSJordan Brown /*
297*1fcced4cSJordan Brown * Determines whether this directory_error_t is an instance of the
298*1fcced4cSJordan Brown * particular error, or a subclass of that error.
299*1fcced4cSJordan Brown */
300*1fcced4cSJordan Brown boolean_t
directory_error_is_instance_of(directory_error_t de,char * code)301*1fcced4cSJordan Brown directory_error_is_instance_of(directory_error_t de, char *code)
302*1fcced4cSJordan Brown {
303*1fcced4cSJordan Brown int len;
304*1fcced4cSJordan Brown
305*1fcced4cSJordan Brown if (de == NULL || de->code == NULL)
306*1fcced4cSJordan Brown return (B_FALSE);
307*1fcced4cSJordan Brown
308*1fcced4cSJordan Brown len = strlen(code);
309*1fcced4cSJordan Brown
310*1fcced4cSJordan Brown if (strncasecmp(de->code, code, len) != 0)
311*1fcced4cSJordan Brown return (B_FALSE);
312*1fcced4cSJordan Brown
313*1fcced4cSJordan Brown if (de->code[len] == '\0' || de->code[len] == '.')
314*1fcced4cSJordan Brown return (B_TRUE);
315*1fcced4cSJordan Brown
316*1fcced4cSJordan Brown return (B_FALSE);
317*1fcced4cSJordan Brown }
318*1fcced4cSJordan Brown
319*1fcced4cSJordan Brown /*
320*1fcced4cSJordan Brown * Expand the directory_error_t in de into buf, returning the size of the
321*1fcced4cSJordan Brown * resulting string including terminating \0. If buf is NULL, just
322*1fcced4cSJordan Brown * return the size.
323*1fcced4cSJordan Brown *
324*1fcced4cSJordan Brown * Return -1 if there are no substitutions, so that the caller can
325*1fcced4cSJordan Brown * avoid memory allocation.
326*1fcced4cSJordan Brown */
327*1fcced4cSJordan Brown static
328*1fcced4cSJordan Brown int
directory_error_expand(char * buf,directory_error_t de)329*1fcced4cSJordan Brown directory_error_expand(char *buf, directory_error_t de)
330*1fcced4cSJordan Brown {
331*1fcced4cSJordan Brown int bufsiz;
332*1fcced4cSJordan Brown boolean_t has_subst;
333*1fcced4cSJordan Brown const char *p;
334*1fcced4cSJordan Brown char c;
335*1fcced4cSJordan Brown long n;
336*1fcced4cSJordan Brown const char *s;
337*1fcced4cSJordan Brown char *newp;
338*1fcced4cSJordan Brown
339*1fcced4cSJordan Brown bufsiz = 0;
340*1fcced4cSJordan Brown has_subst = B_FALSE;
341*1fcced4cSJordan Brown
342*1fcced4cSJordan Brown for (p = dgettext(TEXT_DOMAIN, de->fmt); *p != '\0'; ) {
343*1fcced4cSJordan Brown c = *p++;
344*1fcced4cSJordan Brown if (c == '%') {
345*1fcced4cSJordan Brown has_subst = B_TRUE;
346*1fcced4cSJordan Brown if (isdigit(*p)) {
347*1fcced4cSJordan Brown n = strtol(p, &newp, 10);
348*1fcced4cSJordan Brown p = newp;
349*1fcced4cSJordan Brown if (de->params == NULL ||
350*1fcced4cSJordan Brown n < 1 ||
351*1fcced4cSJordan Brown n > de->nparams)
352*1fcced4cSJordan Brown s = dgettext(TEXT_DOMAIN, "(missing)");
353*1fcced4cSJordan Brown else
354*1fcced4cSJordan Brown s = de->params[n - 1];
355*1fcced4cSJordan Brown if (buf != NULL)
356*1fcced4cSJordan Brown (void) strcpy(buf + bufsiz, s);
357*1fcced4cSJordan Brown bufsiz += strlen(s);
358*1fcced4cSJordan Brown continue;
359*1fcced4cSJordan Brown }
360*1fcced4cSJordan Brown }
361*1fcced4cSJordan Brown if (buf != NULL)
362*1fcced4cSJordan Brown buf[bufsiz] = c;
363*1fcced4cSJordan Brown bufsiz++;
364*1fcced4cSJordan Brown }
365*1fcced4cSJordan Brown
366*1fcced4cSJordan Brown if (buf != NULL)
367*1fcced4cSJordan Brown buf[bufsiz] = '\0';
368*1fcced4cSJordan Brown bufsiz++;
369*1fcced4cSJordan Brown
370*1fcced4cSJordan Brown return (has_subst ? bufsiz : -1);
371*1fcced4cSJordan Brown }
372*1fcced4cSJordan Brown
373*1fcced4cSJordan Brown /*
374*1fcced4cSJordan Brown * Returns a printable version of this directory_error_t, suitable for
375*1fcced4cSJordan Brown * human consumption.
376*1fcced4cSJordan Brown *
377*1fcced4cSJordan Brown * The value returned is valid as long as the directory_error_t is valid,
378*1fcced4cSJordan Brown * and is freed when the directory_error_t is freed.
379*1fcced4cSJordan Brown */
380*1fcced4cSJordan Brown const char *
directory_error_printable(directory_error_t de)381*1fcced4cSJordan Brown directory_error_printable(directory_error_t de)
382*1fcced4cSJordan Brown {
383*1fcced4cSJordan Brown char *s;
384*1fcced4cSJordan Brown int bufsiz;
385*1fcced4cSJordan Brown
386*1fcced4cSJordan Brown if (de->printable != NULL)
387*1fcced4cSJordan Brown return (de->printable);
388*1fcced4cSJordan Brown
389*1fcced4cSJordan Brown bufsiz = directory_error_expand(NULL, de);
390*1fcced4cSJordan Brown
391*1fcced4cSJordan Brown /*
392*1fcced4cSJordan Brown * Short circuit case to avoid memory allocation when there is
393*1fcced4cSJordan Brown * no parameter substitution.
394*1fcced4cSJordan Brown */
395*1fcced4cSJordan Brown if (bufsiz < 0)
396*1fcced4cSJordan Brown return (dgettext(TEXT_DOMAIN, de->fmt));
397*1fcced4cSJordan Brown
398*1fcced4cSJordan Brown s = malloc(bufsiz);
399*1fcced4cSJordan Brown if (s == NULL) {
400*1fcced4cSJordan Brown return (dgettext(TEXT_DOMAIN,
401*1fcced4cSJordan Brown "Out of memory while expanding directory_error_t"));
402*1fcced4cSJordan Brown }
403*1fcced4cSJordan Brown
404*1fcced4cSJordan Brown (void) directory_error_expand(s, de);
405*1fcced4cSJordan Brown
406*1fcced4cSJordan Brown /*
407*1fcced4cSJordan Brown * Stash the expansion away for later free, and to short-circuit
408*1fcced4cSJordan Brown * repeated expansions.
409*1fcced4cSJordan Brown */
410*1fcced4cSJordan Brown de->printable = s;
411*1fcced4cSJordan Brown
412*1fcced4cSJordan Brown return (de->printable);
413*1fcced4cSJordan Brown }
414*1fcced4cSJordan Brown
415*1fcced4cSJordan Brown /*
416*1fcced4cSJordan Brown * Returns the error code for the particular error, as a string.
417*1fcced4cSJordan Brown * Note that this function should not normally be used to answer
418*1fcced4cSJordan Brown * the question "did error X happen", since the value returned
419*1fcced4cSJordan Brown * could be a subclass of X. directory_error_is_instance_of is intended
420*1fcced4cSJordan Brown * to answer that question.
421*1fcced4cSJordan Brown *
422*1fcced4cSJordan Brown * The value returned is valid as long as the directory_error_t is valid,
423*1fcced4cSJordan Brown * and is freed when the directory_error_t is freed.
424*1fcced4cSJordan Brown */
425*1fcced4cSJordan Brown const char *
directory_error_code(directory_error_t de)426*1fcced4cSJordan Brown directory_error_code(directory_error_t de)
427*1fcced4cSJordan Brown {
428*1fcced4cSJordan Brown return (de->code);
429*1fcced4cSJordan Brown }
430*1fcced4cSJordan Brown
431*1fcced4cSJordan Brown /*
432*1fcced4cSJordan Brown * Returns one of the parameters of the directory_error_t, or NULL if
433*1fcced4cSJordan Brown * the parameter does not exist.
434*1fcced4cSJordan Brown *
435*1fcced4cSJordan Brown * Note that it is required that error subclasses have initial parameters
436*1fcced4cSJordan Brown * the same as their superclasses.
437*1fcced4cSJordan Brown *
438*1fcced4cSJordan Brown * The value returned is valid as long as the directory_error_t is valid,
439*1fcced4cSJordan Brown * and is freed when the directory_error_t is freed.
440*1fcced4cSJordan Brown */
441*1fcced4cSJordan Brown const char *
directory_error_param(directory_error_t de,int param)442*1fcced4cSJordan Brown directory_error_param(directory_error_t de, int param)
443*1fcced4cSJordan Brown {
444*1fcced4cSJordan Brown if (param >= de->nparams)
445*1fcced4cSJordan Brown return (NULL);
446*1fcced4cSJordan Brown return (de->params[param]);
447*1fcced4cSJordan Brown }
448*1fcced4cSJordan Brown
449*1fcced4cSJordan Brown /*
450*1fcced4cSJordan Brown * Here are some (almost) constant directory_error_t structures
451*1fcced4cSJordan Brown * for use in reporting errors encountered while creating a
452*1fcced4cSJordan Brown * directory_error_t structure. Unfortunately, the original error
453*1fcced4cSJordan Brown * report is lost.
454*1fcced4cSJordan Brown */
455*1fcced4cSJordan Brown #define gettext(x) x /* let xgettext see these messages */
456*1fcced4cSJordan Brown static struct directory_error directory_error_ENOMEM = {
457*1fcced4cSJordan Brown B_TRUE,
458*1fcced4cSJordan Brown "ENOMEM.directory_error_t",
459*1fcced4cSJordan Brown gettext("Out of memory while creating a directory_error_t"),
460*1fcced4cSJordan Brown 0, NULL,
461*1fcced4cSJordan Brown NULL,
462*1fcced4cSJordan Brown };
463*1fcced4cSJordan Brown
464*1fcced4cSJordan Brown static struct directory_error directory_error_EAGAIN = {
465*1fcced4cSJordan Brown B_TRUE,
466*1fcced4cSJordan Brown "EAGAIN.directory_error_t",
467*1fcced4cSJordan Brown gettext("Out of resources while creating a directory_error_t"),
468*1fcced4cSJordan Brown 0, NULL,
469*1fcced4cSJordan Brown NULL,
470*1fcced4cSJordan Brown };
471*1fcced4cSJordan Brown
472*1fcced4cSJordan Brown /* 40 is big enough for even 128 bits */
473*1fcced4cSJordan Brown static char directory_error_unknown_errno[40] = "0";
474*1fcced4cSJordan Brown static char *directory_error_unknown_params[] = {
475*1fcced4cSJordan Brown directory_error_unknown_errno
476*1fcced4cSJordan Brown };
477*1fcced4cSJordan Brown static struct directory_error directory_error_unknown = {
478*1fcced4cSJordan Brown B_TRUE,
479*1fcced4cSJordan Brown "Unknown.directory_error_t",
480*1fcced4cSJordan Brown gettext("Unknown error (%1) while creating a directory_error_t"),
481*1fcced4cSJordan Brown 1, directory_error_unknown_params,
482*1fcced4cSJordan Brown NULL,
483*1fcced4cSJordan Brown };
484*1fcced4cSJordan Brown #undef gettext
485*1fcced4cSJordan Brown
486*1fcced4cSJordan Brown static
487*1fcced4cSJordan Brown directory_error_t
directory_error_internal_error(int err)488*1fcced4cSJordan Brown directory_error_internal_error(int err)
489*1fcced4cSJordan Brown {
490*1fcced4cSJordan Brown switch (err) {
491*1fcced4cSJordan Brown case ENOMEM: return (&directory_error_ENOMEM);
492*1fcced4cSJordan Brown case EAGAIN: return (&directory_error_EAGAIN);
493*1fcced4cSJordan Brown default:
494*1fcced4cSJordan Brown /* Pray that we don't have a reentrancy problem ... */
495*1fcced4cSJordan Brown (void) sprintf(directory_error_unknown_errno, "%u", err);
496*1fcced4cSJordan Brown return (&directory_error_unknown);
497*1fcced4cSJordan Brown }
498*1fcced4cSJordan Brown }
499