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