1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <stdarg.h>
30#include <dhcp_svc_private.h>
31#include <dhcp_symbol.h>
32#include <libintl.h>
33#include <jni.h>
34
35#include "dd_misc.h"
36#include "exception.h"
37
38/*
39 * Note: These must match exactly with the message ids defined in the
40 * bridge ResourceBundle.properties file.
41 */
42#define	DSVC_EXISTS_EX			"dsvc_exists_exception"
43#define	DSVC_ACCESS_EX			"dsvc_access_exception"
44#define	DSVC_CREDENTIAL_EX		"dsvc_credential_exception"
45#define	DSVC_NO_ENT_EX			"dsvc_no_ent_exception"
46#define	DSVC_BUSY_EX			"dsvc_busy_exception"
47#define	DSVC_INVALID_ARGS_EX		"dsvc_invalid_args_exception"
48#define	DSVC_INTERNAL_EX		"dsvc_internal_exception"
49#define	DSVC_UNAVAILABLE_EX		"dsvc_unavailable_exception"
50#define	DSVC_COLLISION_EX		"dsvc_collision_exception"
51#define	DSVC_UNSUPPORTED_EX		"dsvc_unsupported_exception"
52#define	DSVC_NO_MEMORY_EX		"dsvc_no_memory_exception"
53#define	DSVC_NO_RESOURCES_EX		"dsvc_no_resources_exception"
54#define	DSVC_BAD_RESOURCE_EX		"dsvc_bad_resource_exception"
55#define	DSVC_BAD_PATH_EX		"dsvc_bad_path_exception"
56#define	DSVC_MOD_VERSION_EX		"dsvc_mod_version_exception"
57#define	DSVC_MOD_ERR_EX			"dsvc_mod_err_exception"
58#define	DSVC_MOD_LOAD_ERR_EX		"dsvc_mod_load_err_exception"
59#define	DSVC_MOD_UNLOAD_ERR_EX		"dsvc_mod_unload_err_exception"
60#define	DSVC_MOD_CFG_ERR_EX		"dsvc_mod_cfg_err_exception"
61#define	DSVC_SYNCH_ERR_EX		"dsvc_synch_err_exception"
62#define	DSVC_NO_LOCKMGR_EX		"dsvc_no_lockmgr_exception"
63#define	DSVC_NO_LOCATION_EX		"dsvc_no_location_exception"
64#define	DSVC_NO_TABLE_EX		"dsvc_no_table_exception"
65#define	DSVC_TABLE_EXISTS_EX		"dsvc_table_exists_exception"
66#define	DSVC_BAD_CONVER_EX		"dsvc_bad_conver_exception"
67#define	DSVC_INTERNAL_ERROR		"dsvc_internal_error"
68
69#define	DSYM_CODE_OUT_OF_RANGE_EX	"dsym_code_out_of_range_exception"
70#define	DSYM_EXCEEDS_CLASS_SIZE_EX	"dsym_exceeds_class_size_exception"
71#define	DSYM_EXCEEDS_MAX_CLASS_SIZE_EX	"dsym_exceeds_max_class_size_exception"
72#define	DSYM_INTERNAL_EX		"dsym_internal_exception"
73#define	DSYM_INVALID_CAT_EX		"dsym_invalid_cat_exception"
74#define	DSYM_INVALID_TYPE_EX		"dsym_invalid_type_exception"
75#define	DSYM_NO_MEMORY_EX		"dsym_no_memory_exception"
76#define	DSYM_TOO_FEW_FIELDS_EX		"dsym_too_few_fields_exception"
77#define	DSYM_SYNTAX_EX			"dsym_syntax_exception"
78#define	DSYM_TOO_MANY_FIELDS_EX		"dsym_too_many_fields_exception"
79#define	DSYM_VALUE_OUT_OF_RANGE_EX	"dsym_value_out_of_range_exception"
80
81static void
82throw_exception(JNIEnv *env, const char *name, const char *msgid,
83    int nargs, ...)
84{
85	va_list ap;
86
87	jclass class;
88	jmethodID mid;
89	jstring jmsgid = NULL;
90	jobjectArray jlist = NULL;
91	jthrowable throwObj;
92
93	va_start(ap, nargs);
94
95	class = (*env)->FindClass(env, name);
96	if (class == NULL) {
97		/* exception thrown */
98		va_end(ap);
99		return;
100	}
101
102	mid = (*env)->GetMethodID(env, class, "<init>",
103	    "(Ljava/lang/String;[Ljava/lang/Object;)V");
104	if (mid == NULL) {
105		/* exception thrown */
106		va_end(ap);
107		return;
108	}
109
110	if (msgid != NULL) {
111		jmsgid = dd_native_to_jstring(env, msgid);
112		if (jmsgid == NULL) {
113			/* exception thrown */
114			va_end(ap);
115			return;
116		}
117	}
118
119	/* The arguments (if any) are arguments to the message */
120	if (nargs != 0) {
121
122		jclass strclass;
123		int i;
124		strclass = (*env)->FindClass(env, "java/lang/String");
125		if (strclass == NULL) {
126			/* exception thrown */
127			va_end(ap);
128			return;
129		}
130
131		jlist = (*env)->NewObjectArray(env, nargs, strclass, NULL);
132		if (jlist == NULL) {
133			/* exception thrown */
134			va_end(ap);
135			return;
136		}
137
138		for (i = 0; i < nargs; i++) {
139			jstring jarg;
140			char *arg;
141
142			if ((arg = va_arg(ap, char *)) == 0) {
143				break;
144			}
145
146			jarg = dd_native_to_jstring(env, arg);
147			if (jarg == NULL) {
148				/* exception thrown */
149				break;
150			}
151
152			(*env)->SetObjectArrayElement(env, jlist, i, jarg);
153			if ((*env)->ExceptionOccurred(env) != NULL) {
154				break;
155			}
156		}
157
158	}
159
160	if ((*env)->ExceptionOccurred(env) == NULL) {
161		throwObj = (jthrowable)(*env)->NewObject(env, class, mid,
162		    jmsgid, jlist);
163		if (throwObj == NULL) {
164			/* exception thrown */
165			va_end(ap);
166			return;
167		}
168
169		/* finally! */
170		(*env)->Throw(env, throwObj);
171	}
172
173	va_end(ap);
174}
175
176/* Throw an exception indicating record or file exists */
177static void
178throw_exists_exception(JNIEnv *env, const char *obj)
179{
180	throw_exception(env,
181	    "com/sun/dhcpmgr/bridge/ExistsException", NULL, 1, obj);
182}
183
184/* Throw an exception indicating a table already exists */
185static void
186throw_table_exists_exception(JNIEnv *env, const char *obj)
187{
188	throw_exception(env, "com/sun/dhcpmgr/bridge/TableExistsException",
189	    NULL, 1, obj);
190}
191
192/* Throw an exception indicating a table does not exist */
193static void
194throw_notable_exception(JNIEnv *env, const char *obj)
195{
196	throw_exception(env,
197	    "com/sun/dhcpmgr/bridge/NoTableException", NULL, 1, obj);
198}
199
200/* Throw a generic bridge exception with a specified message */
201void
202throw_bridge_exception(JNIEnv *env, const char *msgid)
203{
204	throw_exception(env,
205	    "com/sun/dhcpmgr/bridge/BridgeException", msgid, 0);
206}
207
208/* Throw an exception as a result of an remove_dd() error */
209void
210throw_remove_dd_exception(JNIEnv *env, int rcode, const char *obj)
211{
212	switch (rcode) {
213	case DSVC_NO_TABLE:
214		throw_notable_exception(env, obj);
215		break;
216	default:
217		throw_libdhcpsvc_exception(env, rcode);
218	}
219}
220
221/* Throw an exception as a result of an open_dd() error */
222void
223throw_open_dd_exception(JNIEnv *env, int rcode, const char *obj)
224{
225	switch (rcode) {
226	case DSVC_TABLE_EXISTS:
227		throw_table_exists_exception(env, obj);
228		break;
229	case DSVC_NO_TABLE:
230		throw_notable_exception(env, obj);
231		break;
232	default:
233		throw_libdhcpsvc_exception(env, rcode);
234	}
235}
236
237/* Throw an exception as a result of an add_dd_entry() error */
238void
239throw_add_dd_entry_exception(JNIEnv *env, int rcode, const char *obj)
240{
241	switch (rcode) {
242	case DSVC_EXISTS:
243		throw_exists_exception(env, obj);
244		break;
245	default:
246		throw_libdhcpsvc_exception(env, rcode);
247	}
248}
249
250/* Throw an exception as a result of an delete_dd_entry() error */
251void
252throw_delete_dd_entry_exception(JNIEnv *env, int rcode, const char *obj)
253{
254	switch (rcode) {
255	case DSVC_NOENT:
256		throw_noent_exception(env, obj);
257		break;
258	default:
259		throw_libdhcpsvc_exception(env, rcode);
260	}
261}
262
263/* Throw an exception as a result of an modify_dd_entry() error */
264void
265throw_modify_dd_entry_exception(JNIEnv *env, int rcode, const char *orig,
266	const char *new)
267{
268	switch (rcode) {
269	case DSVC_EXISTS:
270		throw_exists_exception(env, new);
271		break;
272	case DSVC_NOENT:
273		throw_noent_exception(env, orig);
274		break;
275	default:
276		throw_libdhcpsvc_exception(env, rcode);
277	}
278}
279
280/* Throw an out of memory exception */
281void
282throw_memory_exception(JNIEnv *env)
283{
284	throw_libdhcpsvc_exception(env, DSVC_NO_MEMORY);
285}
286
287/* Throw an exception indicating that there is no DHCP config file */
288void
289throw_no_defaults_exception(JNIEnv *env)
290{
291	throw_exception(env,
292	    "com/sun/dhcpmgr/bridge/NoDefaultsException", NULL, 0);
293}
294
295/* Throw an exception indicating record or file does not exist */
296void
297throw_noent_exception(JNIEnv *env, const char *obj)
298{
299	throw_exception(env,
300	    "com/sun/dhcpmgr/bridge/NoEntryException", NULL, 1, obj);
301}
302
303/* Throw an exception indicating an invalid resource */
304void
305throw_invalid_resource_exception(JNIEnv *env, const char *obj)
306{
307	throw_exception(env, "com/sun/dhcpmgr/bridge/InvalidRsrcException",
308	    NULL, 1, obj);
309}
310
311/* Throw an exception indicating an invalid path */
312void
313throw_invalid_path_exception(JNIEnv *env, const char *obj)
314{
315	throw_exception(env, "com/sun/dhcpmgr/bridge/InvalidPathException",
316	    NULL, 1, obj);
317}
318
319/* Throw an exception indicating that the service is not currently running */
320void
321throw_not_running_exception(JNIEnv *env)
322{
323	throw_exception(env,
324	    "com/sun/dhcpmgr/bridge/NotRunningException", NULL, 0);
325}
326
327/* Throw exception for a libdhcpsvc error that requires no special treatment */
328void
329throw_libdhcpsvc_exception(JNIEnv *env, int rcode)
330{
331	const char *msgid;
332
333	switch (rcode) {
334	case DSVC_SUCCESS:
335		break;
336	case DSVC_EXISTS:
337		msgid = DSVC_EXISTS_EX;
338		break;
339	case DSVC_ACCESS:
340		msgid = DSVC_ACCESS_EX;
341		break;
342	case DSVC_NO_CRED:
343		msgid = DSVC_CREDENTIAL_EX;
344		break;
345	case DSVC_NOENT:
346		msgid = DSVC_NO_ENT_EX;
347		break;
348	case DSVC_BUSY:
349		msgid = DSVC_BUSY_EX;
350		break;
351	case DSVC_INVAL:
352		msgid = DSVC_INVALID_ARGS_EX;
353		break;
354	case DSVC_INTERNAL:
355		msgid = DSVC_INTERNAL_EX;
356		break;
357	case DSVC_UNAVAILABLE:
358		msgid = DSVC_UNAVAILABLE_EX;
359		break;
360	case DSVC_COLLISION:
361		msgid = DSVC_COLLISION_EX;
362		break;
363	case DSVC_UNSUPPORTED:
364		msgid = DSVC_UNSUPPORTED_EX;
365		break;
366	case DSVC_NO_MEMORY:
367		msgid = DSVC_NO_MEMORY_EX;
368		break;
369	case DSVC_NO_RESOURCES:
370		msgid = DSVC_NO_RESOURCES_EX;
371		break;
372	case DSVC_BAD_RESOURCE:
373		msgid = DSVC_BAD_RESOURCE_EX;
374		break;
375	case DSVC_BAD_PATH:
376		msgid = DSVC_BAD_PATH_EX;
377		break;
378	case DSVC_MODULE_VERSION:
379		msgid = DSVC_MOD_VERSION_EX;
380		break;
381	case DSVC_MODULE_ERR:
382		msgid = DSVC_MOD_ERR_EX;
383		break;
384	case DSVC_MODULE_LOAD_ERR:
385		msgid = DSVC_MOD_LOAD_ERR_EX;
386		break;
387	case DSVC_MODULE_UNLOAD_ERR:
388		msgid = DSVC_MOD_UNLOAD_ERR_EX;
389		break;
390	case DSVC_MODULE_CFG_ERR:
391		msgid = DSVC_MOD_CFG_ERR_EX;
392		break;
393	case DSVC_SYNCH_ERR:
394		msgid = DSVC_SYNCH_ERR_EX;
395		break;
396	case DSVC_NO_LOCKMGR:
397		msgid = DSVC_NO_LOCKMGR_EX;
398		break;
399	case DSVC_NO_LOCATION:
400		msgid = DSVC_NO_LOCATION_EX;
401		break;
402	case DSVC_BAD_CONVER:
403		msgid = DSVC_BAD_CONVER_EX;
404		break;
405	default:
406		msgid = DSVC_INTERNAL_ERROR;
407	}
408
409	throw_bridge_exception(env, msgid);
410}
411
412/* Determine whether an exception is a defaults file doesn't exist exception */
413boolean_t
414is_no_defaults_exception(JNIEnv *env, jthrowable e)
415{
416	jclass class;
417	boolean_t result = B_FALSE;
418
419	class = (*env)->FindClass(env,
420	    "com/sun/dhcpmgr/bridge/NoDefaultsException");
421	if (class != NULL) {
422		if ((*env)->IsInstanceOf(env, e, class) == JNI_TRUE &&
423		    e != NULL) {
424			result = B_TRUE;
425		}
426	}
427
428	return (result);
429}
430
431/* Throw a symbol parsing error */
432/* ARGSUSED [one day we should use the `key' argument in messages] */
433void
434throw_dsym_parser_exception(JNIEnv *env, const char *key, char **fields,
435    int field, dsym_errcode_t rcode)
436{
437	const char *dsym_exception  = "com/sun/dhcpmgr/bridge/DsymException";
438
439	char ascii_long_1[ULONG_MAX_CHAR + 1];
440	char ascii_long_2[ULONG_MAX_CHAR + 1];
441	ushort_t min;
442	ushort_t max;
443
444	switch (rcode) {
445	case DSYM_SUCCESS:
446		break;
447	case DSYM_SYNTAX_ERROR:
448		throw_exception(env,
449		    dsym_exception, DSYM_SYNTAX_EX, 1, fields[field]);
450		break;
451	case DSYM_CODE_OUT_OF_RANGE:
452		(void) dsym_get_code_ranges(fields[DSYM_CAT_FIELD],
453		    &min, &max, B_TRUE);
454		(void) sprintf(ascii_long_1, "%d", min);
455		(void) sprintf(ascii_long_2, "%d", max);
456		throw_exception(env, dsym_exception, DSYM_CODE_OUT_OF_RANGE_EX,
457		    3, fields[DSYM_CAT_FIELD], ascii_long_1, ascii_long_2);
458		break;
459	case DSYM_VALUE_OUT_OF_RANGE:
460		throw_exception(env, dsym_exception,
461		    DSYM_VALUE_OUT_OF_RANGE_EX, 1, fields[field]);
462		break;
463	case DSYM_INVALID_CAT:
464		throw_exception(env, dsym_exception,
465		    DSYM_INVALID_CAT_EX, 1, fields[DSYM_CAT_FIELD]);
466		break;
467	case DSYM_INVALID_TYPE:
468		throw_exception(env, dsym_exception,
469		    DSYM_INVALID_TYPE_EX, 1, fields[DSYM_TYPE_FIELD]);
470		break;
471	case DSYM_EXCEEDS_CLASS_SIZE:
472		(void) sprintf(ascii_long_1, "%d", DSYM_CLASS_SIZE);
473		throw_exception(env, dsym_exception,
474		    DSYM_EXCEEDS_CLASS_SIZE_EX, 1, ascii_long_1);
475		break;
476	case DSYM_EXCEEDS_MAX_CLASS_SIZE:
477		(void) sprintf(ascii_long_1, "%d", DSYM_MAX_CLASS_SIZE);
478		throw_exception(env, dsym_exception,
479		    DSYM_EXCEEDS_MAX_CLASS_SIZE_EX, 1, ascii_long_1);
480		break;
481	case DSYM_NO_MEMORY:
482		throw_exception(env, dsym_exception, DSYM_NO_MEMORY_EX, 0);
483		break;
484	default:
485		throw_exception(env, dsym_exception, DSYM_INTERNAL_EX, 0);
486	}
487}
488
489/* Throw a symbol init parsing error */
490void
491throw_dsym_parser_init_exception(JNIEnv *env, const char *key,
492    dsym_errcode_t rcode)
493{
494	const char *dsym_exception  = "com/sun/dhcpmgr/bridge/DsymException";
495
496	switch (rcode) {
497	case DSYM_SUCCESS:
498		break;
499	case DSYM_NULL_FIELD:
500		throw_exception(env,
501		    dsym_exception, DSYM_TOO_FEW_FIELDS_EX, 1, key);
502		break;
503	case DSYM_TOO_MANY_FIELDS:
504		throw_exception(env,
505		    dsym_exception, DSYM_TOO_MANY_FIELDS_EX, 1, key);
506		break;
507	case DSYM_NO_MEMORY:
508		throw_exception(env, dsym_exception, DSYM_NO_MEMORY_EX, 0);
509		break;
510	default:
511		throw_exception(env, dsym_exception, DSYM_INTERNAL_EX, 0);
512	}
513}
514
515/* Throw an exception indicating an error in wordexp */
516void
517throw_wordexp_exception(JNIEnv *env, int code)
518{
519	char buf[UINT64_MAX_CHAR + 1];
520
521	(void) snprintf(buf, sizeof (buf), "%d", code);
522	throw_exception(env, "com/sun/dhcpmgr/bridge/WordexpException",
523	    NULL, 1, buf);
524}
525