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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 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 <priv.h>
30 #include "libzfs_jni_main.h"
31 #include "libzfs_jni_util.h"
32 #include "libzfs_jni_dataset.h"
33 #include "libzfs_jni_property.h"
34 #include "libzfs_jni_pool.h"
35 #include "libzfs_jni_diskmgt.h"
36 #include "libzfs_jni_disk.h"
37 
38 libzfs_handle_t *g_zfs;
39 
40 /*
41  * Function prototypes
42  */
43 
44 static void handle_error(const char *, va_list);
45 static void init();
46 
47 /*
48  * Static functions
49  */
50 
51 char libdskmgt_err[1024];
52 static void
53 handle_error(const char *fmt, va_list ap)
54 {
55 	/* Save the error message in case it's needed */
56 	(void) vsnprintf(libdskmgt_err, sizeof (libdskmgt_err), fmt, ap);
57 #ifdef	DEBUG
58 	(void) fprintf(stderr, "caught error: %s\n", libdskmgt_err);
59 #endif
60 }
61 
62 /*
63  * Initialize the library.  Sets the error handler.
64  */
65 #pragma init(init)
66 static void
67 init()
68 {
69 	if ((g_zfs = libzfs_init()) == NULL)
70 		abort();
71 
72 	/* diskmgt.o error handler */
73 	dmgt_set_error_handler(handle_error);
74 }
75 
76 /*
77  * JNI functions
78  */
79 
80 /*
81  * Class:     com_sun_zfs_common_model_SystemDataModel
82  * Method:    getImportablePools
83  * Signature: ([Ljava/lang/String;)[Ljava/lang/String;
84  */
85 /* ARGSUSED */
86 JNIEXPORT jobjectArray JNICALL
87 Java_com_sun_zfs_common_model_SystemDataModel_getImportablePools(
88     JNIEnv *env, jobject obj, jobjectArray dirs) {
89 
90 	int error;
91 	int argc = 0;
92 	char **argv = NULL;
93 	zjni_ArrayCallbackData_t data = {0};
94 	zjni_ArrayList_t list_obj = {0};
95 	zjni_ArrayList_t *list = &list_obj;
96 
97 	if (!priv_ineffect(PRIV_SYS_CONFIG)) {
98 		zjni_throw_exception(env,
99 		    "cannot discover pools: permission denied\n");
100 		return (NULL);
101 	}
102 
103 	if (dirs != NULL) {
104 		argv = zjni_java_string_array_to_c(env, dirs);
105 		if (argv == NULL) {
106 			zjni_throw_exception(env, "out of memory");
107 			return (NULL);
108 		}
109 
110 		/* Count elements */
111 		for (argc = 0; argv[argc] != NULL; argc++);
112 	}
113 
114 	/* Create an array list to hold each ImportablePoolBean */
115 	zjni_new_ArrayList(env, list);
116 
117 	data.env = env;
118 	data.list = (zjni_Collection_t *)list;
119 
120 	/* Iterate through all importable pools, building list */
121 	error = zjni_ipool_iter(
122 	    argc, argv, zjni_create_add_ImportablePool, &data);
123 
124 	zjni_free_array((void **)argv, free);
125 
126 	if (error) {
127 		return (NULL);
128 	}
129 
130 	return (zjni_Collection_to_array(env, (zjni_Collection_t *)list,
131 	    ZFSJNI_PACKAGE_DATA "ImportablePool"));
132 }
133 
134 /*
135  * Class:     com_sun_zfs_common_model_SystemDataModel
136  * Method:    getPools
137  * Signature: ()[Lcom/sun/zfs/common/model/Pool;
138  */
139 /* ARGSUSED */
140 JNIEXPORT jobjectArray JNICALL
141 Java_com_sun_zfs_common_model_SystemDataModel_getPools(JNIEnv *env, jobject obj)
142 {
143 	zjni_ArrayCallbackData_t data = {0};
144 	int result;
145 
146 	/* Create an array list */
147 	zjni_ArrayList_t list_obj = {0};
148 	zjni_ArrayList_t *list = &list_obj;
149 	zjni_new_ArrayList(env, list);
150 
151 	data.env = env;
152 	data.list = (zjni_Collection_t *)list;
153 
154 	result = zpool_iter(g_zfs, zjni_create_add_Pool, &data);
155 	if (result && (*env)->ExceptionOccurred(env) != NULL) {
156 		/* Must not call any more Java methods to preserve exception */
157 		return (NULL);
158 	}
159 
160 	return (zjni_Collection_to_array(env, (zjni_Collection_t *)list,
161 	    ZFSJNI_PACKAGE_DATA "Pool"));
162 }
163 
164 /*
165  * Class:     com_sun_zfs_common_model_SystemDataModel
166  * Method:    getPool
167  * Signature: (Ljava/lang/String;)
168  *            Lcom/sun/zfs/common/model/Pool;
169  */
170 /* ARGSUSED */
171 JNIEXPORT jobject JNICALL
172 Java_com_sun_zfs_common_model_SystemDataModel_getPool(JNIEnv *env,
173     jobject obj, jstring poolUTF)
174 {
175 	jobject pool = zjni_get_Dataset(env, poolUTF, ZFS_TYPE_FILESYSTEM);
176 
177 	/* Verify that object is Pool, not some other Dataset */
178 	if (pool != NULL) {
179 	    jclass class = (*env)->FindClass(
180 		env, ZFSJNI_PACKAGE_DATA "Pool");
181 
182 	    jboolean is_pool = (*env)->IsInstanceOf(env, pool, class);
183 
184 	    if (is_pool != JNI_TRUE) {
185 		pool = NULL;
186 	    }
187 	}
188 
189 	return (pool);
190 }
191 
192 /*
193  * Class:     com_sun_zfs_common_model_SystemDataModel
194  * Method:    getFileSystems
195  * Signature: (Ljava/lang/String;)
196  *            [Lcom/sun/zfs/common/model/FileSystem;
197  */
198 /* ARGSUSED */
199 JNIEXPORT jobjectArray JNICALL
200 Java_com_sun_zfs_common_model_SystemDataModel_getFileSystems(JNIEnv *env,
201     jobject obj, jstring containerUTF)
202 {
203 	if (containerUTF == NULL) {
204 		return (Java_com_sun_zfs_common_model_SystemDataModel_getPools(
205 		    env, obj));
206 	}
207 
208 	return (zjni_get_Datasets_below(env, containerUTF,
209 	    ZFS_TYPE_FILESYSTEM, ZFS_TYPE_FILESYSTEM,
210 	    ZFSJNI_PACKAGE_DATA "FileSystem"));
211 }
212 
213 /*
214  * Class:     com_sun_zfs_common_model_SystemDataModel
215  * Method:    getFileSystem
216  * Signature: (Ljava/lang/String;)
217  *            Lcom/sun/zfs/common/model/FileSystem;
218  */
219 /* ARGSUSED */
220 JNIEXPORT jobject JNICALL
221 Java_com_sun_zfs_common_model_SystemDataModel_getFileSystem(JNIEnv *env,
222     jobject obj, jstring nameUTF)
223 {
224 	return (zjni_get_Dataset(env, nameUTF, ZFS_TYPE_FILESYSTEM));
225 }
226 
227 /*
228  * Class:     com_sun_zfs_common_model_SystemDataModel
229  * Method:    getVolumes
230  * Signature: (Ljava/lang/String;)
231  *            [Lcom/sun/zfs/common/model/Volume;
232  */
233 /* ARGSUSED */
234 JNIEXPORT jobjectArray JNICALL
235 Java_com_sun_zfs_common_model_SystemDataModel_getVolumes(JNIEnv *env,
236     jobject obj, jstring containerUTF)
237 {
238 	return (zjni_get_Datasets_below(env, containerUTF,
239 	    ZFS_TYPE_FILESYSTEM, ZFS_TYPE_VOLUME,
240 	    ZFSJNI_PACKAGE_DATA "Volume"));
241 }
242 
243 /*
244  * Class:     com_sun_zfs_common_model_SystemDataModel
245  * Method:    getVolume
246  * Signature: (Ljava/lang/String;)
247  *            Lcom/sun/zfs/common/model/Volume;
248  */
249 /* ARGSUSED */
250 JNIEXPORT jobject JNICALL
251 Java_com_sun_zfs_common_model_SystemDataModel_getVolume(JNIEnv *env,
252     jobject obj, jstring nameUTF)
253 {
254 	return (zjni_get_Dataset(env, nameUTF, ZFS_TYPE_VOLUME));
255 }
256 
257 /*
258  * Class:     com_sun_zfs_common_model_SystemDataModel
259  * Method:    getSnapshots
260  * Signature: (Ljava/lang/String;)
261  *            [Lcom/sun/zfs/common/model/Snapshot;
262  */
263 /* ARGSUSED */
264 JNIEXPORT jobjectArray JNICALL
265 Java_com_sun_zfs_common_model_SystemDataModel_getSnapshots(JNIEnv *env,
266     jobject obj, jstring datasetUTF)
267 {
268 	return (zjni_get_Datasets_below(env, datasetUTF,
269 	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, ZFS_TYPE_SNAPSHOT,
270 	    ZFSJNI_PACKAGE_DATA "Snapshot"));
271 }
272 
273 /*
274  * Class:     com_sun_zfs_common_model_SystemDataModel
275  * Method:    getSnapshot
276  * Signature: (Ljava/lang/String;)
277  *            Lcom/sun/zfs/common/model/Snapshot;
278  */
279 /* ARGSUSED */
280 JNIEXPORT jobject JNICALL
281 Java_com_sun_zfs_common_model_SystemDataModel_getSnapshot(JNIEnv *env,
282     jobject obj, jstring nameUTF)
283 {
284 	return (zjni_get_Dataset(env, nameUTF, ZFS_TYPE_SNAPSHOT));
285 }
286 
287 /*
288  * Class:     com_sun_zfs_common_model_SystemDataModel
289  * Method:    getDatasets
290  * Signature: (Ljava/lang/String;)
291  *            [Lcom/sun/zfs/common/model/Dataset;
292  */
293 /* ARGSUSED */
294 JNIEXPORT jobjectArray JNICALL
295 Java_com_sun_zfs_common_model_SystemDataModel_getDatasets(JNIEnv *env,
296     jobject obj, jstring containerUTF)
297 {
298 	if (containerUTF == NULL) {
299 		return (Java_com_sun_zfs_common_model_SystemDataModel_getPools(
300 		    env, obj));
301 	}
302 
303 	return (zjni_get_Datasets_below(env, containerUTF,
304 	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, ZFS_TYPE_ANY,
305 	    ZFSJNI_PACKAGE_DATA "Dataset"));
306 }
307 
308 /*
309  * Class:     com_sun_zfs_common_model_SystemDataModel
310  * Method:    getDataset
311  * Signature: (Ljava/lang/String;)
312  *            Lcom/sun/zfs/common/model/Dataset;
313  */
314 /* ARGSUSED */
315 JNIEXPORT jobject JNICALL
316 Java_com_sun_zfs_common_model_SystemDataModel_getDataset(JNIEnv *env,
317     jobject obj, jstring nameUTF)
318 {
319 	return (zjni_get_Dataset(env, nameUTF, ZFS_TYPE_ANY));
320 }
321 
322 /*
323  * Class:     com_sun_zfs_common_model_SystemDataModel
324  * Method:    getVirtualDevice
325  * Signature: (Ljava/lang/String;J)Lcom/sun/zfs/common/model/VirtualDevice;
326  */
327 /* ARGSUSED */
328 JNIEXPORT jobject JNICALL
329 Java_com_sun_zfs_common_model_SystemDataModel_getVirtualDevice(JNIEnv *env,
330     jobject obj, jstring poolUTF, jlong index)
331 {
332 	jobject vdev = NULL;
333 
334 	if (poolUTF != NULL) {
335 		const char *pool = (*env)->GetStringUTFChars(env, poolUTF,
336 		    NULL);
337 		zpool_handle_t *zhp = zpool_open_canfail(g_zfs, pool);
338 		(*env)->ReleaseStringUTFChars(env, poolUTF, pool);
339 
340 		if (zhp != NULL) {
341 			uint64_t p_vdev_id;
342 			nvlist_t *vdev_cfg = zjni_get_vdev(
343 			    zhp, NULL, index, &p_vdev_id);
344 
345 			if (vdev_cfg != NULL) {
346 				vdev = zjni_get_VirtualDevice_from_vdev(
347 				    env, zhp, vdev_cfg,
348 				    p_vdev_id == index ? NULL : &p_vdev_id);
349 			}
350 			zpool_close(zhp);
351 		}
352 	}
353 
354 	return (vdev);
355 }
356 
357 /*
358  * Class:     com_sun_zfs_common_model_SystemDataModel
359  * Method:    getVirtualDevices
360  * Signature: (Ljava/lang/String;J)
361  *            [Lcom/sun/zfs/common/model/VirtualDevice;
362  */
363 /* ARGSUSED */
364 JNIEXPORT jobjectArray JNICALL
365 /* CSTYLED */
366 Java_com_sun_zfs_common_model_SystemDataModel_getVirtualDevices__Ljava_lang_String_2J(
367     JNIEnv *env, jobject obj, jstring poolUTF, jlong index)
368 {
369 	jobjectArray vdevs = NULL;
370 
371 	if (poolUTF != NULL) {
372 		const char *pool = (*env)->GetStringUTFChars(env, poolUTF,
373 		    NULL);
374 		zpool_handle_t *zhp = zpool_open_canfail(g_zfs, pool);
375 		(*env)->ReleaseStringUTFChars(env, poolUTF, pool);
376 
377 		/* Is the pool valid? */
378 		if (zhp != NULL) {
379 			uint64_t p_vdev_id = index;
380 			nvlist_t *vdev_cfg = zjni_get_vdev(
381 			    zhp, NULL, index, NULL);
382 
383 			if (vdev_cfg != NULL) {
384 				vdevs = zjni_get_VirtualDevices_from_vdev(
385 				    env, zhp, vdev_cfg, &p_vdev_id);
386 			}
387 			zpool_close(zhp);
388 		}
389 	}
390 
391 	return (vdevs);
392 }
393 
394 /*
395  * Class:     com_sun_zfs_common_model_SystemDataModel
396  * Method:    getVirtualDevices
397  * Signature: (Ljava/lang/String;)
398  *            [Lcom/sun/zfs/common/model/VirtualDevice;
399  */
400 /* ARGSUSED */
401 JNIEXPORT jobjectArray JNICALL
402 /* CSTYLED */
403 Java_com_sun_zfs_common_model_SystemDataModel_getVirtualDevices__Ljava_lang_String_2(
404     JNIEnv *env, jobject obj, jstring poolUTF)
405 {
406 	jobjectArray vdevs = NULL;
407 
408 	if (poolUTF != NULL) {
409 		const char *pool = (*env)->GetStringUTFChars(env,
410 		    poolUTF, NULL);
411 		zpool_handle_t *zhp = zpool_open_canfail(g_zfs, pool);
412 		(*env)->ReleaseStringUTFChars(env, poolUTF, pool);
413 
414 		/* Is the pool valid? */
415 		if (zhp != NULL) {
416 			vdevs = zjni_get_VirtualDevices_from_vdev(env,
417 			    zhp, NULL, NULL);
418 			zpool_close(zhp);
419 		}
420 	}
421 
422 	return (vdevs);
423 }
424 
425 /*
426  * Class:     com_sun_zfs_common_model_SystemDataModel
427  * Method:    getAvailableDisks
428  * Signature: ()[Lcom/sun/zfs/common/model/DiskDevice;
429  */
430 /* ARGSUSED */
431 JNIEXPORT jobjectArray JNICALL
432 Java_com_sun_zfs_common_model_SystemDataModel_getAvailableDisks(JNIEnv *env,
433     jobject obj)
434 {
435 	int error;
436 	zjni_ArrayCallbackData_t data = {0};
437 	jobjectArray array = NULL;
438 
439 	/* Create an array list */
440 	zjni_ArrayList_t list_obj = {0};
441 	zjni_ArrayList_t *list = &list_obj;
442 	zjni_new_ArrayList(env, list);
443 
444 	data.env = env;
445 	data.list = (zjni_Collection_t *)list;
446 	error = dmgt_avail_disk_iter(zjni_create_add_DiskDevice, &data);
447 
448 	if (error) {
449 		zjni_throw_exception(env, "%s", libdskmgt_err);
450 	} else {
451 		array = zjni_Collection_to_array(
452 		    env, (zjni_Collection_t *)list,
453 		    ZFSJNI_PACKAGE_DATA "DiskDevice");
454 	}
455 
456 	return (array);
457 }
458 
459 /*
460  * Class:     com_sun_zfs_common_model_SystemDataModel
461  * Method:    getDependents
462  * Signature: ([Ljava/lang/String;)
463  *            [Lcom/sun/zfs/common/model/Dataset;
464  */
465 /* ARGSUSED */
466 JNIEXPORT jobjectArray JNICALL
467 Java_com_sun_zfs_common_model_SystemDataModel_getDependents(JNIEnv *env,
468     jobject obj, jobjectArray paths)
469 {
470 	return (zjni_get_Datasets_dependents(env, paths));
471 }
472 
473 /*
474  * Class:     com_sun_zfs_common_model_SystemDataModel
475  * Method:    getPropertyDefault
476  * Signature: (Ljava/lang/String;)
477  *            Lcom/sun/zfs/common/model/Property;
478  */
479 /* ARGSUSED */
480 JNIEXPORT jobject JNICALL
481 Java_com_sun_zfs_common_model_SystemDataModel_getPropertyDefault(JNIEnv *env,
482     jobject obj, jstring nameUTF)
483 {
484 	jobject defProperty = NULL;
485 
486 	const char *name = (*env)->GetStringUTFChars(env, nameUTF, NULL);
487 	zfs_prop_t prop = zjni_get_property_from_name(name);
488 	(*env)->ReleaseStringUTFChars(env, nameUTF, name);
489 
490 	if (prop != ZFS_PROP_INVAL) {
491 		defProperty = zjni_get_default_property(env, prop);
492 	}
493 
494 	return (defProperty);
495 }
496 
497 typedef struct zjni_class_type_map {
498 	char *class;
499 	zfs_type_t type;
500 } zjni_class_type_map_t;
501 
502 /*
503  * Class:     com_sun_zfs_common_model_SystemDataModel
504  * Method:    getValidPropertyNames
505  * Signature: (Ljava/lang/Class;)
506  *            [Ljava/lang/String;
507  */
508 /* ARGSUSED */
509 JNIEXPORT jobjectArray JNICALL
510 Java_com_sun_zfs_common_model_SystemDataModel_getValidPropertyNames(JNIEnv *env,
511     jobject obj, jclass class)
512 {
513 	int i;
514 
515 	/* Mappings of class names to zfs_type_t */
516 	static zjni_class_type_map_t mappings[] = {
517 		{ ZFSJNI_PACKAGE_DATA "FileSystem", ZFS_TYPE_FILESYSTEM },
518 		{ ZFSJNI_PACKAGE_DATA "Volume", ZFS_TYPE_VOLUME },
519 		{ ZFSJNI_PACKAGE_DATA "Snapshot", ZFS_TYPE_SNAPSHOT },
520 	};
521 	int nmappings = sizeof (mappings) / sizeof (zjni_class_type_map_t);
522 
523 	jclass class_Class = (*env)->FindClass(env, "java/lang/Class");
524 
525 	jmethodID isAssignableFrom = (*env)->GetMethodID(
526 	    env, class_Class, "isAssignableFrom", "(Ljava/lang/Class;)Z");
527 
528 	/* Create an array list for the property names */
529 	zjni_ArrayList_t list_obj = {0};
530 	zjni_ArrayList_t *list = &list_obj;
531 	zjni_new_ArrayList(env, list);
532 
533 	/* For each mapping... */
534 	for (i = 0; i < nmappings; i++) {
535 		/*
536 		 * Is the given class an instance of the class in the mapping?
537 		 */
538 		jclass typeClass = (*env)->FindClass(env, mappings[i].class);
539 
540 		jboolean isInstance = (*env)->CallBooleanMethod(
541 		    env, typeClass, isAssignableFrom, class);
542 
543 		if (isInstance == JNI_TRUE) {
544 			zfs_prop_t prop;
545 			for (prop = 0; prop < ZFS_NPROP_VISIBLE; prop++) {
546 				if (zfs_prop_valid_for_type(prop,
547 				    mappings[i].type)) {
548 					/* Add name of property to list */
549 					jstring propName =
550 					    (*env)->NewStringUTF(env,
551 						zfs_prop_to_name(prop));
552 					(*env)->CallBooleanMethod(
553 					    env,
554 					    ((zjni_Object_t *)list)->object,
555 					    ((zjni_Collection_t *)list)->
556 					    method_add, propName);
557 				}
558 			}
559 			break;
560 		}
561 	}
562 
563 	return (zjni_Collection_to_array(
564 	    env, (zjni_Collection_t *)list, "java/lang/String"));
565 }
566