/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Error handling support for directory lookup.
* Actually, this is intended to be a very generic and extensible error
* reporting mechanism.
*/
#include <stdio.h>
#include <stdlib.h>
#include <thread.h>
#include <errno.h>
#include <stdarg.h>
#include <malloc.h>
#include <string.h>
#include <ctype.h>
#include <syslog.h>
#include <idmap_impl.h>
#include <rpcsvc/idmap_prot.h>
#include <libintl.h>
#include "directory.h"
/*
* This is the actual implementation of the opaque directory_error_t structure.
*/
struct directory_error {
/*
* True if this directory_error_t is statically allocated. Used to
* handle out of memory errors during error reporting.
*/
/*
* The error code. This is a locale-independent string that
* represents the precise error (to some level of granularity)
* that occurred. Internationalization processing could map it
* to an message. Errors may be subclassed by appending a dot
* and a name for the subclass.
*
* Note that this code plus the parameters allows for structured
* processing of error results.
*/
char *code;
/*
* The default (in the absence of internationalization) format for
* the error message. %n interposes params[n - 1].
*/
char *fmt;
/*
* Parameters to the error message. Note that subclasses are
* required to have the same initial parameters as their superclasses,
* so that code that processes the superclass can work on the subclass.
*/
int nparams;
char **params;
/*
* Cached printable form (that is, with params[] interpolated into
* fmt) of the error message. Created when requested.
*/
char *printable;
};
/*
* For debugging, reference count of directory_error instances still in
* existence. When the system is idle, this should be zero.
* Note that no attempt is made to make this MT safe, so it is not reliable
* in an MT environment.
*/
static int directory_errors_outstanding = 0;
/*
* Free the specified directory_error_t. Note that this invalidates all strings
* returned based on it.
*
* Does nothing when de==NULL.
*/
void
{
int i;
return;
/* Don't free our internal static directory_error_ts! */
return;
/* Free parameters, if any */
}
}
/* Free cached printable */
}
/*
* de = directory_error(code, fmt [, arg1 ... ]);
* Code, fmt, and arguments must be strings and will be copied.
*/
{
int i;
goto nomem;
goto nomem;
goto nomem;
/* Count our parameters */
/* LOOP */;
/*
* Note that we do not copy the terminating NULL because we have
* a count.
*/
goto nomem;
goto nomem;
}
}
return (de);
nomem:;
return (directory_error_internal_error(err));
}
/*
* Transform a directory_error returned by RPC into a directory_error_t.
*/
{
int i;
goto nomem;
goto nomem;
goto nomem;
goto nomem;
goto nomem;
}
return (de);
nomem:;
return (directory_error_internal_error(err));
}
/*
* Convert a directory_error_t into a directory_error to send over RPC.
*
* Returns TRUE on successful conversion, FALSE on failure.
*
* Frees the directory_error_t.
*
* Note that most functions in this suite return boolean_t, as defined
* by types.h. This function is intended to be used directly as the
* return value from an RPC service function, and so it returns bool_t.
*/
{
int i;
goto nomem;
goto nomem;
goto nomem;
goto nomem;
}
return (TRUE);
"Original error: %s\n"
"Conversion error: %s\n",
return (FALSE);
}
/*
* Determines whether this directory_error_t is an instance of the
* particular error, or a subclass of that error.
*/
{
int len;
return (B_FALSE);
return (B_FALSE);
return (B_TRUE);
return (B_FALSE);
}
/*
* Expand the directory_error_t in de into buf, returning the size of the
* resulting string including terminating \0. If buf is NULL, just
* return the size.
*
* Return -1 if there are no substitutions, so that the caller can
* avoid memory allocation.
*/
static
int
{
int bufsiz;
const char *p;
char c;
long n;
const char *s;
char *newp;
bufsiz = 0;
c = *p++;
if (c == '%') {
if (isdigit(*p)) {
p = newp;
n < 1 ||
else
continue;
}
}
bufsiz++;
}
bufsiz++;
}
/*
* Returns a printable version of this directory_error_t, suitable for
* human consumption.
*
* The value returned is valid as long as the directory_error_t is valid,
* and is freed when the directory_error_t is freed.
*/
const char *
{
char *s;
int bufsiz;
/*
* Short circuit case to avoid memory allocation when there is
* no parameter substitution.
*/
if (bufsiz < 0)
if (s == NULL) {
return (dgettext(TEXT_DOMAIN,
"Out of memory while expanding directory_error_t"));
}
(void) directory_error_expand(s, de);
/*
* Stash the expansion away for later free, and to short-circuit
* repeated expansions.
*/
}
/*
* Returns the error code for the particular error, as a string.
* Note that this function should not normally be used to answer
* the question "did error X happen", since the value returned
* could be a subclass of X. directory_error_is_instance_of is intended
* to answer that question.
*
* The value returned is valid as long as the directory_error_t is valid,
* and is freed when the directory_error_t is freed.
*/
const char *
{
}
/*
* Returns one of the parameters of the directory_error_t, or NULL if
* the parameter does not exist.
*
* Note that it is required that error subclasses have initial parameters
* the same as their superclasses.
*
* The value returned is valid as long as the directory_error_t is valid,
* and is freed when the directory_error_t is freed.
*/
const char *
{
return (NULL);
}
/*
* Here are some (almost) constant directory_error_t structures
* for use in reporting errors encountered while creating a
* directory_error_t structure. Unfortunately, the original error
* report is lost.
*/
"ENOMEM.directory_error_t",
gettext("Out of memory while creating a directory_error_t"),
0, NULL,
NULL,
};
"EAGAIN.directory_error_t",
gettext("Out of resources while creating a directory_error_t"),
0, NULL,
NULL,
};
/* 40 is big enough for even 128 bits */
static char *directory_error_unknown_params[] = {
};
"Unknown.directory_error_t",
gettext("Unknown error (%1) while creating a directory_error_t"),
NULL,
};
static
{
switch (err) {
case ENOMEM: return (&directory_error_ENOMEM);
case EAGAIN: return (&directory_error_EAGAIN);
default:
/* Pray that we don't have a reentrancy problem ... */
return (&directory_error_unknown);
}
}