xref: /illumos-gate/usr/src/lib/libzfs_jni/common/libzfs_jni_main.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
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 2007 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 	return (pool);
189 }
190 
191 /*
192  * Class:     com_sun_zfs_common_model_SystemDataModel
193  * Method:    getFileSystems
194  * Signature: (Ljava/lang/String;)
195  *            [Lcom/sun/zfs/common/model/FileSystem;
196  */
197 /* ARGSUSED */
198 JNIEXPORT jobjectArray JNICALL
199 Java_com_sun_zfs_common_model_SystemDataModel_getFileSystems(JNIEnv *env,
200     jobject obj, jstring containerUTF)
201 {
202 	if (containerUTF == NULL) {
203 		return (Java_com_sun_zfs_common_model_SystemDataModel_getPools(
204 		    env, obj));
205 	}
206 
207 	return (zjni_get_Datasets_below(env, containerUTF,
208 	    ZFS_TYPE_FILESYSTEM, ZFS_TYPE_FILESYSTEM,
209 	    ZFSJNI_PACKAGE_DATA "FileSystem"));
210 }
211 
212 /*
213  * Class:     com_sun_zfs_common_model_SystemDataModel
214  * Method:    getFileSystem
215  * Signature: (Ljava/lang/String;)
216  *            Lcom/sun/zfs/common/model/FileSystem;
217  */
218 /* ARGSUSED */
219 JNIEXPORT jobject JNICALL
220 Java_com_sun_zfs_common_model_SystemDataModel_getFileSystem(JNIEnv *env,
221     jobject obj, jstring nameUTF)
222 {
223 	return (zjni_get_Dataset(env, nameUTF, ZFS_TYPE_FILESYSTEM));
224 }
225 
226 /*
227  * Class:     com_sun_zfs_common_model_SystemDataModel
228  * Method:    getVolumes
229  * Signature: (Ljava/lang/String;)
230  *            [Lcom/sun/zfs/common/model/Volume;
231  */
232 /* ARGSUSED */
233 JNIEXPORT jobjectArray JNICALL
234 Java_com_sun_zfs_common_model_SystemDataModel_getVolumes(JNIEnv *env,
235     jobject obj, jstring containerUTF)
236 {
237 	return (zjni_get_Datasets_below(env, containerUTF,
238 	    ZFS_TYPE_FILESYSTEM, ZFS_TYPE_VOLUME,
239 	    ZFSJNI_PACKAGE_DATA "Volume"));
240 }
241 
242 /*
243  * Class:     com_sun_zfs_common_model_SystemDataModel
244  * Method:    getVolume
245  * Signature: (Ljava/lang/String;)
246  *            Lcom/sun/zfs/common/model/Volume;
247  */
248 /* ARGSUSED */
249 JNIEXPORT jobject JNICALL
250 Java_com_sun_zfs_common_model_SystemDataModel_getVolume(JNIEnv *env,
251     jobject obj, jstring nameUTF)
252 {
253 	return (zjni_get_Dataset(env, nameUTF, ZFS_TYPE_VOLUME));
254 }
255 
256 /*
257  * Class:     com_sun_zfs_common_model_SystemDataModel
258  * Method:    getSnapshots
259  * Signature: (Ljava/lang/String;)
260  *            [Lcom/sun/zfs/common/model/Snapshot;
261  */
262 /* ARGSUSED */
263 JNIEXPORT jobjectArray JNICALL
264 Java_com_sun_zfs_common_model_SystemDataModel_getSnapshots(JNIEnv *env,
265     jobject obj, jstring datasetUTF)
266 {
267 	return (zjni_get_Datasets_below(env, datasetUTF,
268 	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, ZFS_TYPE_SNAPSHOT,
269 	    ZFSJNI_PACKAGE_DATA "Snapshot"));
270 }
271 
272 /*
273  * Class:     com_sun_zfs_common_model_SystemDataModel
274  * Method:    getSnapshot
275  * Signature: (Ljava/lang/String;)
276  *            Lcom/sun/zfs/common/model/Snapshot;
277  */
278 /* ARGSUSED */
279 JNIEXPORT jobject JNICALL
280 Java_com_sun_zfs_common_model_SystemDataModel_getSnapshot(JNIEnv *env,
281     jobject obj, jstring nameUTF)
282 {
283 	return (zjni_get_Dataset(env, nameUTF, ZFS_TYPE_SNAPSHOT));
284 }
285 
286 /*
287  * Class:     com_sun_zfs_common_model_SystemDataModel
288  * Method:    getDatasets
289  * Signature: (Ljava/lang/String;)
290  *            [Lcom/sun/zfs/common/model/Dataset;
291  */
292 /* ARGSUSED */
293 JNIEXPORT jobjectArray JNICALL
294 Java_com_sun_zfs_common_model_SystemDataModel_getDatasets(JNIEnv *env,
295     jobject obj, jstring containerUTF)
296 {
297 	if (containerUTF == NULL) {
298 		return (Java_com_sun_zfs_common_model_SystemDataModel_getPools(
299 		    env, obj));
300 	}
301 
302 	return (zjni_get_Datasets_below(env, containerUTF,
303 	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, ZFS_TYPE_DATASET,
304 	    ZFSJNI_PACKAGE_DATA "Dataset"));
305 }
306 
307 /*
308  * Class:     com_sun_zfs_common_model_SystemDataModel
309  * Method:    getDataset
310  * Signature: (Ljava/lang/String;)
311  *            Lcom/sun/zfs/common/model/Dataset;
312  */
313 /* ARGSUSED */
314 JNIEXPORT jobject JNICALL
315 Java_com_sun_zfs_common_model_SystemDataModel_getDataset(JNIEnv *env,
316     jobject obj, jstring nameUTF)
317 {
318 	return (zjni_get_Dataset(env, nameUTF, ZFS_TYPE_DATASET));
319 }
320 
321 /*
322  * Class:     com_sun_zfs_common_model_SystemDataModel
323  * Method:    getVirtualDevice
324  * Signature: (Ljava/lang/String;J)Lcom/sun/zfs/common/model/VirtualDevice;
325  */
326 /* ARGSUSED */
327 JNIEXPORT jobject JNICALL
328 Java_com_sun_zfs_common_model_SystemDataModel_getVirtualDevice(JNIEnv *env,
329     jobject obj, jstring poolUTF, jlong index)
330 {
331 	jobject vdev = NULL;
332 
333 	if (poolUTF != NULL) {
334 		const char *pool = (*env)->GetStringUTFChars(env, poolUTF,
335 		    NULL);
336 		zpool_handle_t *zhp = zpool_open_canfail(g_zfs, pool);
337 		(*env)->ReleaseStringUTFChars(env, poolUTF, pool);
338 
339 		if (zhp != NULL) {
340 			uint64_t p_vdev_id;
341 			nvlist_t *vdev_cfg = zjni_get_vdev(
342 			    zhp, NULL, index, &p_vdev_id);
343 
344 			if (vdev_cfg != NULL) {
345 				vdev = zjni_get_VirtualDevice_from_vdev(
346 				    env, zhp, vdev_cfg,
347 				    p_vdev_id == index ? NULL : &p_vdev_id);
348 			}
349 			zpool_close(zhp);
350 		}
351 	}
352 
353 	return (vdev);
354 }
355 
356 /*
357  * Class:     com_sun_zfs_common_model_SystemDataModel
358  * Method:    getVirtualDevices
359  * Signature: (Ljava/lang/String;J)
360  *            [Lcom/sun/zfs/common/model/VirtualDevice;
361  */
362 /* ARGSUSED */
363 JNIEXPORT jobjectArray JNICALL
364 /* CSTYLED */
365 Java_com_sun_zfs_common_model_SystemDataModel_getVirtualDevices__Ljava_lang_String_2J(
366     JNIEnv *env, jobject obj, jstring poolUTF, jlong index)
367 {
368 	jobjectArray vdevs = NULL;
369 
370 	if (poolUTF != NULL) {
371 		const char *pool = (*env)->GetStringUTFChars(env, poolUTF,
372 		    NULL);
373 		zpool_handle_t *zhp = zpool_open_canfail(g_zfs, pool);
374 		(*env)->ReleaseStringUTFChars(env, poolUTF, pool);
375 
376 		/* Is the pool valid? */
377 		if (zhp != NULL) {
378 			uint64_t p_vdev_id = index;
379 			nvlist_t *vdev_cfg = zjni_get_vdev(
380 			    zhp, NULL, index, NULL);
381 
382 			if (vdev_cfg != NULL) {
383 				vdevs = zjni_get_VirtualDevices_from_vdev(
384 				    env, zhp, vdev_cfg, &p_vdev_id);
385 			}
386 			zpool_close(zhp);
387 		}
388 	}
389 
390 	return (vdevs);
391 }
392 
393 /*
394  * Class:     com_sun_zfs_common_model_SystemDataModel
395  * Method:    getVirtualDevices
396  * Signature: (Ljava/lang/String;)
397  *            [Lcom/sun/zfs/common/model/VirtualDevice;
398  */
399 /* ARGSUSED */
400 JNIEXPORT jobjectArray JNICALL
401 /* CSTYLED */
402 Java_com_sun_zfs_common_model_SystemDataModel_getVirtualDevices__Ljava_lang_String_2(
403     JNIEnv *env, jobject obj, jstring poolUTF)
404 {
405 	jobjectArray vdevs = NULL;
406 
407 	if (poolUTF != NULL) {
408 		const char *pool = (*env)->GetStringUTFChars(env,
409 		    poolUTF, NULL);
410 		zpool_handle_t *zhp = zpool_open_canfail(g_zfs, pool);
411 		(*env)->ReleaseStringUTFChars(env, poolUTF, pool);
412 
413 		/* Is the pool valid? */
414 		if (zhp != NULL) {
415 			vdevs = zjni_get_VirtualDevices_from_vdev(env,
416 			    zhp, NULL, NULL);
417 			zpool_close(zhp);
418 		}
419 	}
420 
421 	return (vdevs);
422 }
423 
424 /*
425  * Class:     com_sun_zfs_common_model_SystemDataModel
426  * Method:    getAvailableDisks
427  * Signature: ()[Lcom/sun/zfs/common/model/DiskDevice;
428  */
429 /* ARGSUSED */
430 JNIEXPORT jobjectArray JNICALL
431 Java_com_sun_zfs_common_model_SystemDataModel_getAvailableDisks(JNIEnv *env,
432     jobject obj)
433 {
434 	int error;
435 	zjni_ArrayCallbackData_t data = {0};
436 	jobjectArray array = NULL;
437 
438 	/* Create an array list */
439 	zjni_ArrayList_t list_obj = {0};
440 	zjni_ArrayList_t *list = &list_obj;
441 	zjni_new_ArrayList(env, list);
442 
443 	data.env = env;
444 	data.list = (zjni_Collection_t *)list;
445 	error = dmgt_avail_disk_iter(zjni_create_add_DiskDevice, &data);
446 
447 	if (error) {
448 		zjni_throw_exception(env, "%s", libdskmgt_err);
449 	} else {
450 		array = zjni_Collection_to_array(
451 		    env, (zjni_Collection_t *)list,
452 		    ZFSJNI_PACKAGE_DATA "DiskDevice");
453 	}
454 
455 	return (array);
456 }
457 
458 /*
459  * Class:     com_sun_zfs_common_model_SystemDataModel
460  * Method:    getDependents
461  * Signature: ([Ljava/lang/String;)
462  *            [Lcom/sun/zfs/common/model/Dataset;
463  */
464 /* ARGSUSED */
465 JNIEXPORT jobjectArray JNICALL
466 Java_com_sun_zfs_common_model_SystemDataModel_getDependents(JNIEnv *env,
467     jobject obj, jobjectArray paths)
468 {
469 	return (zjni_get_Datasets_dependents(env, paths));
470 }
471 
472 /*
473  * Class:     com_sun_zfs_common_model_SystemDataModel
474  * Method:    getPropertyDefault
475  * Signature: (Ljava/lang/String;)
476  *            Lcom/sun/zfs/common/model/Property;
477  */
478 /* ARGSUSED */
479 JNIEXPORT jobject JNICALL
480 Java_com_sun_zfs_common_model_SystemDataModel_getPropertyDefault(JNIEnv *env,
481     jobject obj, jstring nameUTF)
482 {
483 	jobject defProperty = NULL;
484 
485 	const char *name = (*env)->GetStringUTFChars(env, nameUTF, NULL);
486 	zfs_prop_t prop = zjni_get_property_from_name(name);
487 	(*env)->ReleaseStringUTFChars(env, nameUTF, name);
488 
489 	if (prop != ZPROP_INVAL) {
490 		defProperty = zjni_get_default_property(env, prop);
491 	}
492 
493 	return (defProperty);
494 }
495 
496 typedef struct zjni_class_type_map {
497 	char *class;
498 	zfs_type_t type;
499 } zjni_class_type_map_t;
500 
501 typedef struct mapping_data {
502 	JNIEnv			*env;
503 	zfs_type_t		type;
504 	zjni_ArrayList_t	*list;
505 } mapping_data_t;
506 
507 static int
508 mapping_cb(int prop, void *cb)
509 {
510 	mapping_data_t *map = cb;
511 	JNIEnv *env = map->env;
512 	zjni_ArrayList_t *list = map->list;
513 
514 	if (zfs_prop_valid_for_type(prop, map->type)) {
515 		/* Add name of property to list */
516 		jstring propName = (*env)->NewStringUTF(env,
517 		    zfs_prop_to_name(prop));
518 		(*env)->CallBooleanMethod(env, ((zjni_Object_t *)list)->object,
519 		    ((zjni_Collection_t *)list)->method_add, propName);
520 	}
521 
522 	return (ZPROP_CONT);
523 }
524 
525 /*
526  * Class:     com_sun_zfs_common_model_SystemDataModel
527  * Method:    getValidPropertyNames
528  * Signature: (Ljava/lang/Class;)
529  *            [Ljava/lang/String;
530  */
531 /* ARGSUSED */
532 JNIEXPORT jobjectArray JNICALL
533 Java_com_sun_zfs_common_model_SystemDataModel_getValidPropertyNames(JNIEnv *env,
534     jobject obj, jclass class)
535 {
536 	int i;
537 
538 	/* Mappings of class names to zfs_type_t */
539 	static zjni_class_type_map_t mappings[] = {
540 		{ ZFSJNI_PACKAGE_DATA "FileSystem", ZFS_TYPE_FILESYSTEM },
541 		{ ZFSJNI_PACKAGE_DATA "Volume", ZFS_TYPE_VOLUME },
542 		{ ZFSJNI_PACKAGE_DATA "Snapshot", ZFS_TYPE_SNAPSHOT },
543 	};
544 	int nmappings = sizeof (mappings) / sizeof (zjni_class_type_map_t);
545 
546 	jclass class_Class = (*env)->FindClass(env, "java/lang/Class");
547 
548 	jmethodID isAssignableFrom = (*env)->GetMethodID(
549 	    env, class_Class, "isAssignableFrom", "(Ljava/lang/Class;)Z");
550 
551 	/* Create an array list for the property names */
552 	zjni_ArrayList_t list_obj = {0};
553 	zjni_ArrayList_t *list = &list_obj;
554 	zjni_new_ArrayList(env, list);
555 
556 	/* For each mapping... */
557 	for (i = 0; i < nmappings; i++) {
558 		/*
559 		 * Is the given class an instance of the class in the mapping?
560 		 */
561 		jclass typeClass = (*env)->FindClass(env, mappings[i].class);
562 
563 		jboolean isInstance = (*env)->CallBooleanMethod(
564 		    env, typeClass, isAssignableFrom, class);
565 
566 		if (isInstance == JNI_TRUE) {
567 			mapping_data_t map_data;
568 
569 			map_data.env = env;
570 			map_data.type = mappings[i].type;
571 			map_data.list = list;
572 			(void) zprop_iter(mapping_cb, &map_data, B_FALSE,
573 			    B_FALSE, ZFS_TYPE_DATASET);
574 			break;
575 		}
576 	}
577 
578 	return (zjni_Collection_to_array(
579 	    env, (zjni_Collection_t *)list, "java/lang/String"));
580 }
581 
582 /*
583  * Class:     com_sun_zfs_common_model_SystemDataModel
584  * Method:    getPoolCurrentVersion
585  * Signature: ()J;
586  */
587 /* ARGSUSED */
588 JNIEXPORT jlong JNICALL
589 Java_com_sun_zfs_common_model_SystemDataModel_getPoolCurrentVersion(
590     JNIEnv *env, jobject obj)
591 {
592 	jlong pool_current_version = SPA_VERSION;
593 
594 	return (pool_current_version);
595 }
596