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