1*dfc11533SChris Williamson /*
2*dfc11533SChris Williamson * CDDL HEADER START
3*dfc11533SChris Williamson *
4*dfc11533SChris Williamson * This file and its contents are supplied under the terms of the
5*dfc11533SChris Williamson * Common Development and Distribution License ("CDDL"), version 1.0.
6*dfc11533SChris Williamson * You may only use this file in accordance with the terms of version
7*dfc11533SChris Williamson * 1.0 of the CDDL.
8*dfc11533SChris Williamson *
9*dfc11533SChris Williamson * A full copy of the text of the CDDL should have accompanied this
10*dfc11533SChris Williamson * source. A copy of the CDDL is also available via the Internet at
11*dfc11533SChris Williamson * http://www.illumos.org/license/CDDL.
12*dfc11533SChris Williamson *
13*dfc11533SChris Williamson * CDDL HEADER END
14*dfc11533SChris Williamson */
15*dfc11533SChris Williamson
16*dfc11533SChris Williamson /*
17*dfc11533SChris Williamson * Copyright (c) 2016 by Delphix. All rights reserved.
18*dfc11533SChris Williamson */
19*dfc11533SChris Williamson
20*dfc11533SChris Williamson #include <stdio.h>
21*dfc11533SChris Williamson #include <stdlib.h>
22*dfc11533SChris Williamson #include <string.h>
23*dfc11533SChris Williamson #include <strings.h>
24*dfc11533SChris Williamson #include <libzfs_core.h>
25*dfc11533SChris Williamson #include <sys/nvpair.h>
26*dfc11533SChris Williamson
27*dfc11533SChris Williamson nvlist_t *nvl;
28*dfc11533SChris Williamson const char *pool;
29*dfc11533SChris Williamson boolean_t unexpected_failures;
30*dfc11533SChris Williamson
31*dfc11533SChris Williamson static boolean_t
nvlist_equal(nvlist_t * nvla,nvlist_t * nvlb)32*dfc11533SChris Williamson nvlist_equal(nvlist_t *nvla, nvlist_t *nvlb)
33*dfc11533SChris Williamson {
34*dfc11533SChris Williamson if (fnvlist_num_pairs(nvla) != fnvlist_num_pairs(nvlb))
35*dfc11533SChris Williamson return (B_FALSE);
36*dfc11533SChris Williamson /*
37*dfc11533SChris Williamson * The nvlists have the same number of pairs and keys are unique, so
38*dfc11533SChris Williamson * if every key in A is also in B and assigned to the same value, the
39*dfc11533SChris Williamson * lists are identical.
40*dfc11533SChris Williamson */
41*dfc11533SChris Williamson for (nvpair_t *pair = nvlist_next_nvpair(nvla, NULL);
42*dfc11533SChris Williamson pair != NULL; pair = nvlist_next_nvpair(nvla, pair)) {
43*dfc11533SChris Williamson char *key = nvpair_name(pair);
44*dfc11533SChris Williamson
45*dfc11533SChris Williamson if (!nvlist_exists(nvlb, key))
46*dfc11533SChris Williamson return (B_FALSE);
47*dfc11533SChris Williamson
48*dfc11533SChris Williamson if (nvpair_type(pair) !=
49*dfc11533SChris Williamson nvpair_type(fnvlist_lookup_nvpair(nvlb, key)))
50*dfc11533SChris Williamson return (B_FALSE);
51*dfc11533SChris Williamson
52*dfc11533SChris Williamson switch (nvpair_type(pair)) {
53*dfc11533SChris Williamson case DATA_TYPE_BOOLEAN_VALUE:
54*dfc11533SChris Williamson if (fnvpair_value_boolean_value(pair) !=
55*dfc11533SChris Williamson fnvlist_lookup_boolean_value(nvlb, key)) {
56*dfc11533SChris Williamson return (B_FALSE);
57*dfc11533SChris Williamson }
58*dfc11533SChris Williamson break;
59*dfc11533SChris Williamson case DATA_TYPE_STRING:
60*dfc11533SChris Williamson if (strcmp(fnvpair_value_string(pair),
61*dfc11533SChris Williamson fnvlist_lookup_string(nvlb, key))) {
62*dfc11533SChris Williamson return (B_FALSE);
63*dfc11533SChris Williamson }
64*dfc11533SChris Williamson break;
65*dfc11533SChris Williamson case DATA_TYPE_INT64:
66*dfc11533SChris Williamson if (fnvpair_value_int64(pair) !=
67*dfc11533SChris Williamson fnvlist_lookup_int64(nvlb, key)) {
68*dfc11533SChris Williamson return (B_FALSE);
69*dfc11533SChris Williamson }
70*dfc11533SChris Williamson break;
71*dfc11533SChris Williamson case DATA_TYPE_NVLIST:
72*dfc11533SChris Williamson if (!nvlist_equal(fnvpair_value_nvlist(pair),
73*dfc11533SChris Williamson fnvlist_lookup_nvlist(nvlb, key))) {
74*dfc11533SChris Williamson return (B_FALSE);
75*dfc11533SChris Williamson }
76*dfc11533SChris Williamson break;
77*dfc11533SChris Williamson default:
78*dfc11533SChris Williamson (void) printf("Unexpected type for nvlist_equal\n");
79*dfc11533SChris Williamson return (B_FALSE);
80*dfc11533SChris Williamson }
81*dfc11533SChris Williamson }
82*dfc11533SChris Williamson return (B_TRUE);
83*dfc11533SChris Williamson }
84*dfc11533SChris Williamson
85*dfc11533SChris Williamson static void
test(const char * testname,boolean_t expect_success,boolean_t expect_match)86*dfc11533SChris Williamson test(const char *testname, boolean_t expect_success, boolean_t expect_match)
87*dfc11533SChris Williamson {
88*dfc11533SChris Williamson char *progstr = "input = ...; return {output=input}";
89*dfc11533SChris Williamson
90*dfc11533SChris Williamson nvlist_t *outnvl;
91*dfc11533SChris Williamson
92*dfc11533SChris Williamson (void) printf("\nrunning test '%s'; input:\n", testname);
93*dfc11533SChris Williamson dump_nvlist(nvl, 4);
94*dfc11533SChris Williamson
95*dfc11533SChris Williamson int err = lzc_channel_program(pool, progstr,
96*dfc11533SChris Williamson 10 * 1000 * 1000, 10 * 1024 * 1024, nvl, &outnvl);
97*dfc11533SChris Williamson
98*dfc11533SChris Williamson (void) printf("lzc_channel_program returned %u\n", err);
99*dfc11533SChris Williamson dump_nvlist(outnvl, 5);
100*dfc11533SChris Williamson
101*dfc11533SChris Williamson if (err == 0 && expect_match) {
102*dfc11533SChris Williamson /*
103*dfc11533SChris Williamson * Verify that outnvl is the same as input nvl, if we expect
104*dfc11533SChris Williamson * them to be. The input and output will never match if the
105*dfc11533SChris Williamson * input contains an array (since arrays are converted to lua
106*dfc11533SChris Williamson * tables), so this is only asserted for some test cases.
107*dfc11533SChris Williamson */
108*dfc11533SChris Williamson nvlist_t *real_outnvl = fnvlist_lookup_nvlist(outnvl, "return");
109*dfc11533SChris Williamson real_outnvl = fnvlist_lookup_nvlist(real_outnvl, "output");
110*dfc11533SChris Williamson if (!nvlist_equal(nvl, real_outnvl)) {
111*dfc11533SChris Williamson unexpected_failures = B_TRUE;
112*dfc11533SChris Williamson (void) printf("unexpected input/output mismatch for "
113*dfc11533SChris Williamson "case: %s\n", testname);
114*dfc11533SChris Williamson }
115*dfc11533SChris Williamson }
116*dfc11533SChris Williamson if (err != 0 && expect_success) {
117*dfc11533SChris Williamson unexpected_failures = B_TRUE;
118*dfc11533SChris Williamson (void) printf("unexpected FAIL of case: %s\n", testname);
119*dfc11533SChris Williamson }
120*dfc11533SChris Williamson
121*dfc11533SChris Williamson fnvlist_free(nvl);
122*dfc11533SChris Williamson nvl = fnvlist_alloc();
123*dfc11533SChris Williamson }
124*dfc11533SChris Williamson
125*dfc11533SChris Williamson static void
run_tests(void)126*dfc11533SChris Williamson run_tests(void)
127*dfc11533SChris Williamson {
128*dfc11533SChris Williamson const char *key = "key";
129*dfc11533SChris Williamson
130*dfc11533SChris Williamson /* Note: maximum nvlist key length is 32KB */
131*dfc11533SChris Williamson int len = 1024 * 31;
132*dfc11533SChris Williamson char *bigstring = malloc(len);
133*dfc11533SChris Williamson for (int i = 0; i < len; i++)
134*dfc11533SChris Williamson bigstring[i] = 'a' + i % 26;
135*dfc11533SChris Williamson bigstring[len - 1] = '\0';
136*dfc11533SChris Williamson
137*dfc11533SChris Williamson nvl = fnvlist_alloc();
138*dfc11533SChris Williamson
139*dfc11533SChris Williamson fnvlist_add_boolean(nvl, key);
140*dfc11533SChris Williamson test("boolean", B_TRUE, B_FALSE);
141*dfc11533SChris Williamson
142*dfc11533SChris Williamson fnvlist_add_boolean_value(nvl, key, B_TRUE);
143*dfc11533SChris Williamson test("boolean_value", B_FALSE, B_FALSE);
144*dfc11533SChris Williamson
145*dfc11533SChris Williamson fnvlist_add_byte(nvl, key, 1);
146*dfc11533SChris Williamson test("byte", B_FALSE, B_FALSE);
147*dfc11533SChris Williamson
148*dfc11533SChris Williamson fnvlist_add_int8(nvl, key, 1);
149*dfc11533SChris Williamson test("int8", B_FALSE, B_FALSE);
150*dfc11533SChris Williamson
151*dfc11533SChris Williamson fnvlist_add_uint8(nvl, key, 1);
152*dfc11533SChris Williamson test("uint8", B_FALSE, B_FALSE);
153*dfc11533SChris Williamson
154*dfc11533SChris Williamson fnvlist_add_int16(nvl, key, 1);
155*dfc11533SChris Williamson test("int16", B_FALSE, B_FALSE);
156*dfc11533SChris Williamson
157*dfc11533SChris Williamson fnvlist_add_uint16(nvl, key, 1);
158*dfc11533SChris Williamson test("uint16", B_FALSE, B_FALSE);
159*dfc11533SChris Williamson
160*dfc11533SChris Williamson fnvlist_add_int32(nvl, key, 1);
161*dfc11533SChris Williamson test("int32", B_FALSE, B_FALSE);
162*dfc11533SChris Williamson
163*dfc11533SChris Williamson fnvlist_add_uint32(nvl, key, 1);
164*dfc11533SChris Williamson test("uint32", B_FALSE, B_FALSE);
165*dfc11533SChris Williamson
166*dfc11533SChris Williamson fnvlist_add_int64(nvl, key, 1);
167*dfc11533SChris Williamson test("int64", B_TRUE, B_TRUE);
168*dfc11533SChris Williamson
169*dfc11533SChris Williamson fnvlist_add_uint64(nvl, key, 1);
170*dfc11533SChris Williamson test("uint64", B_FALSE, B_FALSE);
171*dfc11533SChris Williamson
172*dfc11533SChris Williamson fnvlist_add_string(nvl, key, "1");
173*dfc11533SChris Williamson test("string", B_TRUE, B_TRUE);
174*dfc11533SChris Williamson
175*dfc11533SChris Williamson
176*dfc11533SChris Williamson {
177*dfc11533SChris Williamson nvlist_t *val = fnvlist_alloc();
178*dfc11533SChris Williamson fnvlist_add_string(val, "subkey", "subvalue");
179*dfc11533SChris Williamson fnvlist_add_nvlist(nvl, key, val);
180*dfc11533SChris Williamson fnvlist_free(val);
181*dfc11533SChris Williamson test("nvlist", B_TRUE, B_TRUE);
182*dfc11533SChris Williamson }
183*dfc11533SChris Williamson {
184*dfc11533SChris Williamson boolean_t val[2] = { B_FALSE, B_TRUE };
185*dfc11533SChris Williamson fnvlist_add_boolean_array(nvl, key, val, 2);
186*dfc11533SChris Williamson test("boolean_array", B_FALSE, B_FALSE);
187*dfc11533SChris Williamson }
188*dfc11533SChris Williamson {
189*dfc11533SChris Williamson uchar_t val[2] = { 0, 1 };
190*dfc11533SChris Williamson fnvlist_add_byte_array(nvl, key, val, 2);
191*dfc11533SChris Williamson test("byte_array", B_FALSE, B_FALSE);
192*dfc11533SChris Williamson }
193*dfc11533SChris Williamson {
194*dfc11533SChris Williamson int8_t val[2] = { 0, 1 };
195*dfc11533SChris Williamson fnvlist_add_int8_array(nvl, key, val, 2);
196*dfc11533SChris Williamson test("int8_array", B_FALSE, B_FALSE);
197*dfc11533SChris Williamson }
198*dfc11533SChris Williamson {
199*dfc11533SChris Williamson uint8_t val[2] = { 0, 1 };
200*dfc11533SChris Williamson fnvlist_add_uint8_array(nvl, key, val, 2);
201*dfc11533SChris Williamson test("uint8_array", B_FALSE, B_FALSE);
202*dfc11533SChris Williamson }
203*dfc11533SChris Williamson {
204*dfc11533SChris Williamson int16_t val[2] = { 0, 1 };
205*dfc11533SChris Williamson fnvlist_add_int16_array(nvl, key, val, 2);
206*dfc11533SChris Williamson test("int16_array", B_FALSE, B_FALSE);
207*dfc11533SChris Williamson }
208*dfc11533SChris Williamson {
209*dfc11533SChris Williamson uint16_t val[2] = { 0, 1 };
210*dfc11533SChris Williamson fnvlist_add_uint16_array(nvl, key, val, 2);
211*dfc11533SChris Williamson test("uint16_array", B_FALSE, B_FALSE);
212*dfc11533SChris Williamson }
213*dfc11533SChris Williamson {
214*dfc11533SChris Williamson int32_t val[2] = { 0, 1 };
215*dfc11533SChris Williamson fnvlist_add_int32_array(nvl, key, val, 2);
216*dfc11533SChris Williamson test("int32_array", B_FALSE, B_FALSE);
217*dfc11533SChris Williamson }
218*dfc11533SChris Williamson {
219*dfc11533SChris Williamson uint32_t val[2] = { 0, 1 };
220*dfc11533SChris Williamson fnvlist_add_uint32_array(nvl, key, val, 2);
221*dfc11533SChris Williamson test("uint32_array", B_FALSE, B_FALSE);
222*dfc11533SChris Williamson }
223*dfc11533SChris Williamson {
224*dfc11533SChris Williamson int64_t val[2] = { 0, 1 };
225*dfc11533SChris Williamson fnvlist_add_int64_array(nvl, key, val, 2);
226*dfc11533SChris Williamson test("int64_array", B_TRUE, B_FALSE);
227*dfc11533SChris Williamson }
228*dfc11533SChris Williamson {
229*dfc11533SChris Williamson uint64_t val[2] = { 0, 1 };
230*dfc11533SChris Williamson fnvlist_add_uint64_array(nvl, key, val, 2);
231*dfc11533SChris Williamson test("uint64_array", B_FALSE, B_FALSE);
232*dfc11533SChris Williamson }
233*dfc11533SChris Williamson {
234*dfc11533SChris Williamson char *const val[2] = { "0", "1" };
235*dfc11533SChris Williamson fnvlist_add_string_array(nvl, key, val, 2);
236*dfc11533SChris Williamson test("string_array", B_TRUE, B_FALSE);
237*dfc11533SChris Williamson }
238*dfc11533SChris Williamson {
239*dfc11533SChris Williamson nvlist_t *val[2];
240*dfc11533SChris Williamson val[0] = fnvlist_alloc();
241*dfc11533SChris Williamson fnvlist_add_string(val[0], "subkey", "subvalue");
242*dfc11533SChris Williamson val[1] = fnvlist_alloc();
243*dfc11533SChris Williamson fnvlist_add_string(val[1], "subkey2", "subvalue2");
244*dfc11533SChris Williamson fnvlist_add_nvlist_array(nvl, key, val, 2);
245*dfc11533SChris Williamson fnvlist_free(val[0]);
246*dfc11533SChris Williamson fnvlist_free(val[1]);
247*dfc11533SChris Williamson test("nvlist_array", B_FALSE, B_FALSE);
248*dfc11533SChris Williamson }
249*dfc11533SChris Williamson {
250*dfc11533SChris Williamson fnvlist_add_string(nvl, bigstring, "1");
251*dfc11533SChris Williamson test("large_key", B_TRUE, B_TRUE);
252*dfc11533SChris Williamson }
253*dfc11533SChris Williamson {
254*dfc11533SChris Williamson fnvlist_add_string(nvl, key, bigstring);
255*dfc11533SChris Williamson test("large_value", B_TRUE, B_TRUE);
256*dfc11533SChris Williamson }
257*dfc11533SChris Williamson {
258*dfc11533SChris Williamson for (int i = 0; i < 1024; i++) {
259*dfc11533SChris Williamson char buf[32];
260*dfc11533SChris Williamson (void) snprintf(buf, sizeof (buf), "key-%u", i);
261*dfc11533SChris Williamson fnvlist_add_int64(nvl, buf, i);
262*dfc11533SChris Williamson }
263*dfc11533SChris Williamson test("many_keys", B_TRUE, B_TRUE);
264*dfc11533SChris Williamson }
265*dfc11533SChris Williamson {
266*dfc11533SChris Williamson for (int i = 0; i < 10; i++) {
267*dfc11533SChris Williamson nvlist_t *newval = fnvlist_alloc();
268*dfc11533SChris Williamson fnvlist_add_nvlist(newval, "key", nvl);
269*dfc11533SChris Williamson fnvlist_free(nvl);
270*dfc11533SChris Williamson nvl = newval;
271*dfc11533SChris Williamson }
272*dfc11533SChris Williamson test("deeply_nested_pos", B_TRUE, B_TRUE);
273*dfc11533SChris Williamson }
274*dfc11533SChris Williamson {
275*dfc11533SChris Williamson for (int i = 0; i < 90; i++) {
276*dfc11533SChris Williamson nvlist_t *newval = fnvlist_alloc();
277*dfc11533SChris Williamson fnvlist_add_nvlist(newval, "key", nvl);
278*dfc11533SChris Williamson fnvlist_free(nvl);
279*dfc11533SChris Williamson nvl = newval;
280*dfc11533SChris Williamson }
281*dfc11533SChris Williamson test("deeply_nested_neg", B_FALSE, B_FALSE);
282*dfc11533SChris Williamson }
283*dfc11533SChris Williamson
284*dfc11533SChris Williamson free(bigstring);
285*dfc11533SChris Williamson fnvlist_free(nvl);
286*dfc11533SChris Williamson }
287*dfc11533SChris Williamson
288*dfc11533SChris Williamson int
main(int argc,const char * argv[])289*dfc11533SChris Williamson main(int argc, const char *argv[])
290*dfc11533SChris Williamson {
291*dfc11533SChris Williamson (void) libzfs_core_init();
292*dfc11533SChris Williamson
293*dfc11533SChris Williamson if (argc != 2) {
294*dfc11533SChris Williamson (void) printf("usage: %s <pool>\n",
295*dfc11533SChris Williamson argv[0]);
296*dfc11533SChris Williamson exit(2);
297*dfc11533SChris Williamson }
298*dfc11533SChris Williamson pool = argv[1];
299*dfc11533SChris Williamson
300*dfc11533SChris Williamson run_tests();
301*dfc11533SChris Williamson
302*dfc11533SChris Williamson libzfs_core_fini();
303*dfc11533SChris Williamson return (unexpected_failures);
304*dfc11533SChris Williamson }
305