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