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
81 static void
throw_exception(JNIEnv * env,const char * name,const char * msgid,int nargs,...)82 throw_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 */
177 static void
throw_exists_exception(JNIEnv * env,const char * obj)178 throw_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 */
185 static void
throw_table_exists_exception(JNIEnv * env,const char * obj)186 throw_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 */
193 static void
throw_notable_exception(JNIEnv * env,const char * obj)194 throw_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 */
201 void
throw_bridge_exception(JNIEnv * env,const char * msgid)202 throw_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 */
209 void
throw_remove_dd_exception(JNIEnv * env,int rcode,const char * obj)210 throw_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 */
222 void
throw_open_dd_exception(JNIEnv * env,int rcode,const char * obj)223 throw_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 */
238 void
throw_add_dd_entry_exception(JNIEnv * env,int rcode,const char * obj)239 throw_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 */
251 void
throw_delete_dd_entry_exception(JNIEnv * env,int rcode,const char * obj)252 throw_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 */
264 void
throw_modify_dd_entry_exception(JNIEnv * env,int rcode,const char * orig,const char * new)265 throw_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 */
281 void
throw_memory_exception(JNIEnv * env)282 throw_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 */
288 void
throw_no_defaults_exception(JNIEnv * env)289 throw_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 */
296 void
throw_noent_exception(JNIEnv * env,const char * obj)297 throw_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 */
304 void
throw_invalid_resource_exception(JNIEnv * env,const char * obj)305 throw_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 */
312 void
throw_invalid_path_exception(JNIEnv * env,const char * obj)313 throw_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 */
320 void
throw_not_running_exception(JNIEnv * env)321 throw_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 */
328 void
throw_libdhcpsvc_exception(JNIEnv * env,int rcode)329 throw_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 */
413 boolean_t
is_no_defaults_exception(JNIEnv * env,jthrowable e)414 is_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] */
433 void
throw_dsym_parser_exception(JNIEnv * env,const char * key,char ** fields,int field,dsym_errcode_t rcode)434 throw_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 */
490 void
throw_dsym_parser_init_exception(JNIEnv * env,const char * key,dsym_errcode_t rcode)491 throw_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 */
516 void
throw_wordexp_exception(JNIEnv * env,int code)517 throw_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