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