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