xref: /illumos-gate/usr/src/cmd/sbdadm/sbdadm.c (revision 2654012f83cec5dc15b61dfe3e4a4915f186e7a6)
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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <libintl.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <assert.h>
35 #include <getopt.h>
36 #include <strings.h>
37 #include <ctype.h>
38 #include <libnvpair.h>
39 
40 #include <cmdparse.h>
41 #include <sys/stmf_defines.h>
42 #include <libstmf.h>
43 #include <sys/stmf_sbd_ioctl.h>
44 
45 #define	BIG_BUF_SIZE	512
46 #define	MAX_LU_LIST	8192
47 #define	LU_LIST_MAX_RETRIES 3
48 
49 uint8_t big_buf[BIG_BUF_SIZE];
50 
51 int delete_lu(int argc, char *argv[], cmdOptions_t *options,
52     void *callData);
53 int create_lu(int argc, char *argv[], cmdOptions_t *options, void *callData);
54 int import_lu(int argc, char *argv[], cmdOptions_t *options, void *callData);
55 int list_lus(int argc, char *argv[], cmdOptions_t *options, void *callData);
56 int modify_lu(int argc, char *argv[], cmdOptions_t *options, void *callData);
57 static int persist_lu_register(char *, char *);
58 int print_lu_attr(uint64_t handle, char **s);
59 void print_guid(uint8_t *g, FILE *f);
60 void print_attr_header();
61 
62 char	*rlc_ret[] = {	"", "Metadata creation failed",
63 	"LU is not initialized",
64 	"File is already loaded",
65 	"GUID in the file is already registered",
66 	"Registration with framework failed",
67 	"Deregistration with stmf failed",
68 	"Unable to lookup file",
69 	"Incorrect file type to export as LU. Only regular \n"
70 	    "files and raw storage devices (disks/volumes) can be exported "
71 	    "as LUs",
72 	"Unable to open file",
73 	"Unable to get file attributes",
74 	"File size has to be at least 1M",
75 	"File size is not a multiple of blocksize",
76 	"LU size is out of range",
77 	"LU size is not supported by underlying Filesystem"
78 };
79 
80 char sbdadm_ver[] = "sbdadm version 1.0";
81 
82 optionTbl_t options[] = {
83 	{ "disk-size", required_argument, 's',
84 			"Size with <none>/k/m/g/t/p/e modifier" },
85 	{ "keep-views", no_arg, 'k',
86 			"Dont delete view entries related to the LU" },
87 	{ NULL, 0, 0 }
88 };
89 
90 subCommandProps_t subCommands[] = {
91 	{ "create-lu", create_lu, "s", NULL, NULL,
92 		OPERAND_MANDATORY_SINGLE,
93 		"Full path of the file to initialize" },
94 	{ "delete-lu", delete_lu, "k", NULL, NULL,
95 		OPERAND_MANDATORY_SINGLE, "GUID of the LU to deregister" },
96 	{ "import-lu", import_lu, NULL, NULL, NULL,
97 		OPERAND_MANDATORY_SINGLE, "filename of the LU to import" },
98 	{ "list-lu", list_lus, NULL, NULL, NULL,
99 		OPERAND_NONE, "List all the exported LUs" },
100 	{ "modify-lu", modify_lu, "s", "s", NULL,
101 		OPERAND_MANDATORY_SINGLE,
102 		"Full path of the LU or GUID of a registered LU" },
103 	{ NULL, 0, 0, NULL, 0, NULL}
104 };
105 
106 int sbd_fd;
107 
108 int
109 main(int argc, char *argv[])
110 {
111 	int ret, func_ret;
112 	synTables_t sbdt = { sbdadm_ver, options, subCommands };
113 
114 	sbd_fd = open("/devices/pseudo/stmf_sbd@0:admin", O_RDONLY);
115 	if (sbd_fd < 0) {
116 		if (errno == EPERM) {
117 			(void) fprintf(stderr, "Not enough permissions to open "
118 			    "device\n");
119 		} else {
120 			(void) fprintf(stderr,
121 			    "Unable to open device. Is the driver "
122 			    "attached ?\n");
123 		}
124 		exit(1);
125 	}
126 	ret = cmdParse(argc, argv, sbdt, NULL, &func_ret);
127 
128 	if (ret)
129 		return (ret);
130 	return (func_ret);
131 }
132 
133 /*
134  * Supports upto 8 Exabytes.
135  *
136  * Returns zero upon success and the size in sizep.
137  * returns 2 if the string format is invalid.
138  * returns 1 if the specified size is out of range.
139  */
140 int
141 str_to_size(char *str, uint64_t *sizep)
142 {
143 	uint64_t cur_size, m;
144 	uint64_t new_cur_size;
145 	int i;
146 	char c;
147 
148 	m = 1;
149 	cur_size = 0;
150 
151 	for (i = 0; str[i] != NULL; i++) {
152 		if (m != 1) {
153 			/* We should have been done after the modifier */
154 			return (2);
155 		}
156 		c = str[i];
157 		if (isdigit(c)) {
158 			new_cur_size = (cur_size * 10) +
159 			    (((uint64_t)c) - '0');
160 			if (new_cur_size < cur_size) {
161 				/* Overflow */
162 				return (1);
163 			}
164 			cur_size = new_cur_size;
165 			continue;
166 		}
167 		if (cur_size == 0) {
168 			/* Direct format modifier ?? */
169 			return (2);
170 		}
171 		c = toupper(c);
172 		if (c == 'K') {
173 			m = 1024;
174 		} else if (c == 'M') {
175 			m = 1024 * 1024;
176 		} else if (c == 'G') {
177 			m = 1024 * 1024 * 1024;
178 		} else if (c == 'T') {
179 			m = 1024ll * 1024 * 1024 * 1024;
180 		} else if (c == 'P') {
181 			m = 1024ll * 1024 * 1024 * 1024 * 1024;
182 		} else if (c == 'E') {
183 			m = 1024ll * 1024 * 1024 * 1024 * 1024 * 1024;
184 		} else {
185 			return (2);
186 		}
187 	}
188 
189 	while (m > 1) {
190 		if (cur_size & 0x8000000000000000ull) {
191 			/* Overflow */
192 			return (1);
193 		}
194 		cur_size <<= 1;
195 		m >>= 1;
196 	}
197 
198 	if (cur_size > 0x8000000000000000ull) {
199 		/* We cannot allow more than 8 Exabytes */
200 		return (1);
201 	}
202 
203 	*sizep = cur_size;
204 
205 	return (0);
206 }
207 
208 static int
209 persist_lu_register(char *guid, char *filename)
210 {
211 	int ret = 0;
212 	nvlist_t *nvl = NULL;
213 	uint64_t setToken;
214 	boolean_t		retryGetProviderData;
215 
216 	do {
217 		retryGetProviderData = B_FALSE;
218 		ret = stmfGetProviderDataProt("sbd", &nvl,
219 		    STMF_LU_PROVIDER_TYPE, &setToken);
220 		if (ret != STMF_STATUS_SUCCESS) {
221 			if (ret == STMF_ERROR_NOT_FOUND) {
222 				(void) nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
223 			} else {
224 				(void) fprintf(stderr,
225 				    "could not access persistent store\n");
226 				ret = 1;
227 				goto out;
228 			}
229 		}
230 
231 		ret = nvlist_add_string(nvl, guid, filename);
232 		if (ret != 0) {
233 			(void) fprintf(stderr,
234 			    "could not add data to nvlist\n");
235 			ret = 1;
236 			goto out;
237 		}
238 
239 		ret = stmfSetProviderDataProt("sbd", nvl, STMF_LU_PROVIDER_TYPE,
240 		    &setToken);
241 		if (ret != STMF_STATUS_SUCCESS) {
242 			if (ret == STMF_ERROR_BUSY) {
243 				(void) fprintf(stderr,
244 				    "stmf framework resource busy\n");
245 			} else if (ret == STMF_ERROR_PROV_DATA_STALE) {
246 				nvlist_free(nvl);
247 				nvl = NULL;
248 				retryGetProviderData = B_TRUE;
249 				continue;
250 			} else {
251 				(void) fprintf(stderr,
252 				    "unable to set persistent store data\n");
253 			}
254 			ret = 1;
255 			goto out;
256 		}
257 	} while (retryGetProviderData);
258 out:
259 	nvlist_free(nvl);
260 	return (ret);
261 }
262 
263 /*ARGSUSED*/
264 int
265 create_lu(int argc, char *argv[], cmdOptions_t *options, void *callData)
266 {
267 	register_lu_cmd_t *rlc;
268 	uint32_t fl;
269 	int ret = 0, err;
270 	uint64_t size;
271 	char guidAsciiBuf[33];
272 
273 	/* Check whether this file path is absolute path */
274 	if (argv[argc - 1][0] != '/') {
275 		(void) fprintf(stderr, "File name should be an absolute path"
276 		    " i.e. it should start with a /\n");
277 		return (1);
278 	}
279 
280 	fl = strlen(argv[argc - 1]) + 1;
281 	rlc = (register_lu_cmd_t *)malloc(sizeof (register_lu_cmd_t) + fl - 8);
282 	if (rlc == NULL) {
283 		(void) fprintf(stderr, "Unable to allocate memory\n");
284 		return (1);
285 	}
286 	bzero(rlc, sizeof (register_lu_cmd_t));
287 	rlc->total_struct_size = sizeof (register_lu_cmd_t) + fl - 8;
288 
289 	rlc->flags = RLC_LU_TYPE_FILEDISK | RLC_CREATE_LU | RLC_REGISTER_LU;
290 	for (; options->optval; options++) {
291 		if (options->optval == 's') {
292 			err = str_to_size(options->optarg, &size);
293 			if (err == 1) {
294 				(void) fprintf(stderr,
295 				    "Size out of range: maximum"
296 				    " supported size is 9223372036854710272"
297 				    " (8 Exabytes - 64 Kilobytes)\n");
298 				ret = 1;
299 				goto create_lu_done;
300 			} else if (err == 2) {
301 				(void) fprintf(stderr,
302 				    "Invalid size specified\n");
303 				ret = 1;
304 				goto create_lu_done;
305 			}
306 			rlc->lu_size = size;
307 		}
308 	}
309 	(void) strcpy(rlc->name, argv[argc-1]);
310 	if ((ioctl(sbd_fd, SBD_REGISTER_LU, rlc) < 0) ||
311 	    (rlc->return_code != 0) || (rlc->op_ret != STMF_SUCCESS)) {
312 		if (rlc->return_code && (rlc->return_code < RLC_RET_MAX_VAL)) {
313 			(void) fprintf(stderr, "LU Create failed : %s.\n",
314 			    rlc_ret[rlc->return_code]);
315 			if (rlc->return_code ==
316 			    RLC_RET_SIZE_NOT_SUPPORTED_BY_FS) {
317 				(void) fprintf(stderr, "Maximum LU size on "
318 				    "the underlying filesystem can be %llu "
319 				    "bytes.\n",
320 				    ((((uint64_t)1) << rlc->filesize_nbits)
321 				    - 1 - 64 * 1024) & 0xfffffffffffffe00ull);
322 			}
323 			if (rlc->return_code ==
324 			    RLC_RET_GUID_ALREADY_REGISTERED) {
325 				(void) fprintf(stderr, "Registered GUID is ");
326 				print_guid(rlc->guid, stderr);
327 				(void) fprintf(stderr, "\n");
328 			}
329 		} else {
330 			(void) fprintf(stderr, "LU Create failed(%llx) : %s.\n",
331 			    rlc->op_ret, strerror(errno));
332 		}
333 		ret = 1;
334 	} else {
335 		if (rlc->flags & RLC_REGISTER_LU) {
336 			(void) printf("\nCreated the following LU:\n");
337 			print_attr_header();
338 			(void) print_lu_attr(rlc->lu_handle, NULL);
339 			(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
340 			    "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
341 			    "%02x%02x%02x%02x%02x%02x",
342 			    rlc->guid[0], rlc->guid[1], rlc->guid[2],
343 			    rlc->guid[3], rlc->guid[4], rlc->guid[5],
344 			    rlc->guid[6], rlc->guid[7], rlc->guid[8],
345 			    rlc->guid[9], rlc->guid[10], rlc->guid[11],
346 			    rlc->guid[12], rlc->guid[13], rlc->guid[14],
347 			    rlc->guid[15]);
348 
349 			ret = persist_lu_register(guidAsciiBuf, argv[argc - 1]);
350 		}
351 	}
352 
353 create_lu_done:;
354 	free(rlc);
355 	return (ret);
356 }
357 
358 /*ARGSUSED*/
359 int
360 import_lu(int argc, char *argv[], cmdOptions_t *options, void *callData)
361 {
362 	register_lu_cmd_t *rlc;
363 	uint32_t fl;
364 	int ret = 0;
365 	char guidAsciiBuf[33];
366 
367 	/* Check whether this file path is absolute path */
368 	if (argv[argc - 1][0] != '/') {
369 		(void) fprintf(stderr, "File name should be an absolute path"
370 		    " i.e. it should start with a /\n");
371 		return (1);
372 	}
373 
374 	fl = strlen(argv[argc - 1]) + 1;
375 	rlc = (register_lu_cmd_t *)malloc(sizeof (register_lu_cmd_t) + fl - 8);
376 	if (rlc == NULL) {
377 		(void) fprintf(stderr, "Unable to allocate memory\n");
378 		return (1);
379 	}
380 	bzero(rlc, sizeof (register_lu_cmd_t));
381 	rlc->total_struct_size = sizeof (register_lu_cmd_t) + fl - 8;
382 
383 	rlc->flags = RLC_LU_TYPE_FILEDISK | RLC_REGISTER_LU;
384 	(void) strcpy(rlc->name, argv[argc-1]);
385 	if ((ioctl(sbd_fd, SBD_REGISTER_LU, rlc) < 0) ||
386 	    (rlc->return_code != 0) || (rlc->op_ret != STMF_SUCCESS)) {
387 		if (rlc->return_code && (rlc->return_code < RLC_RET_MAX_VAL)) {
388 			(void) fprintf(stderr, "LU import failed : %s.\n",
389 			    rlc_ret[rlc->return_code]);
390 			if (rlc->return_code ==
391 			    RLC_RET_SIZE_NOT_SUPPORTED_BY_FS) {
392 				(void) fprintf(stderr, "Maximum LU size on "
393 				    "the underlying filesystem can be %llu "
394 				    "bytes.\n",
395 				    ((((uint64_t)1) << rlc->filesize_nbits)
396 				    - 1 - 64 * 1024) & 0xfffffffffffffe00ull);
397 			}
398 			if (rlc->return_code ==
399 			    RLC_RET_GUID_ALREADY_REGISTERED) {
400 				(void) fprintf(stderr, "Registered GUID is ");
401 				print_guid(rlc->guid, stderr);
402 				(void) fprintf(stderr, "\n");
403 			}
404 		} else {
405 			(void) fprintf(stderr, "LU import failed(%llx) : %s.\n",
406 			    rlc->op_ret, strerror(errno));
407 		}
408 		ret = 1;
409 	} else {
410 		if (rlc->flags & RLC_REGISTER_LU) {
411 			(void) printf("\nImported the following LU:\n");
412 			print_attr_header();
413 			(void) print_lu_attr(rlc->lu_handle, NULL);
414 			(void) snprintf(guidAsciiBuf, sizeof (guidAsciiBuf),
415 			    "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
416 			    "%02x%02x%02x%02x%02x%02x",
417 			    rlc->guid[0], rlc->guid[1], rlc->guid[2],
418 			    rlc->guid[3], rlc->guid[4], rlc->guid[5],
419 			    rlc->guid[6], rlc->guid[7], rlc->guid[8],
420 			    rlc->guid[9], rlc->guid[10], rlc->guid[11],
421 			    rlc->guid[12], rlc->guid[13], rlc->guid[14],
422 			    rlc->guid[15]);
423 
424 			ret = persist_lu_register(guidAsciiBuf, argv[argc - 1]);
425 		}
426 	}
427 
428 import_lu_done:;
429 	free(rlc);
430 	return (ret);
431 }
432 
433 /*ARGSUSED*/
434 int
435 delete_lu(int argc, char *argv[], cmdOptions_t *options, void *callData)
436 {
437 	deregister_lu_cmd_t	drlc;
438 	int			ret = 0, i;
439 	char			chstr[3], *pend = NULL;
440 	uint32_t		ch, off = 0;
441 	int			exists = 0;
442 	char			guidAsciiBuf[33];
443 	nvlist_t		*nvl = NULL;
444 
445 	int			stmf_ret;
446 	int			keep_view = 0;
447 	uint64_t		setToken;
448 	stmfGuid		inGuid;
449 	stmfViewEntryList	*viewEntryList;
450 	boolean_t		retryGetProviderData;
451 
452 	for (; options->optval; options++) {
453 		switch (options->optval) {
454 		case 'k':
455 			keep_view = 1;
456 			break;
457 		}
458 	}
459 
460 	if (strlen(argv[argc - 1]) != 32) {
461 		(void) fprintf(stderr, "GUID must be 32 characters\n");
462 		ret = 1;
463 		goto delete_lu_done;
464 	}
465 
466 	for (i = 0; i < 32; i++) {
467 		guidAsciiBuf[i] = tolower(argv[argc - 1][i]);
468 	}
469 
470 	guidAsciiBuf[i] = 0;
471 
472 	do {
473 		retryGetProviderData = B_FALSE;
474 		stmf_ret = stmfGetProviderDataProt("sbd", &nvl,
475 		    STMF_LU_PROVIDER_TYPE, &setToken);
476 		if (stmf_ret != STMF_STATUS_SUCCESS) {
477 			(void) fprintf(stderr,
478 			    "Could not access persistent store\n");
479 			ret = 1;
480 			goto delete_lu_done;
481 		}
482 		ret = nvlist_remove(nvl, guidAsciiBuf, DATA_TYPE_STRING);
483 		if (ret == 0) {
484 			exists = 1;
485 			stmf_ret = stmfSetProviderDataProt("sbd", nvl,
486 			    STMF_LU_PROVIDER_TYPE, &setToken);
487 			if (stmf_ret != STMF_STATUS_SUCCESS) {
488 				if (stmf_ret == STMF_ERROR_BUSY) {
489 					(void) fprintf(stderr,
490 					    "stmf framework resource busy\n");
491 				} else if (stmf_ret ==
492 				    STMF_ERROR_PROV_DATA_STALE) {
493 					/*
494 					 * update failed, try again
495 					 */
496 					nvlist_free(nvl);
497 					nvl = NULL;
498 					retryGetProviderData = B_TRUE;
499 					continue;
500 				} else {
501 					(void) fprintf(stderr,
502 					    "unable to set persistent store "
503 					    "data\n");
504 				}
505 				ret = 1;
506 				goto delete_lu_done;
507 			}
508 		}
509 	} while (retryGetProviderData);
510 
511 	bzero(&drlc, sizeof (drlc));
512 	drlc.total_struct_size = sizeof (drlc);
513 	drlc.flags = RLC_DEREGISTER_LU;
514 
515 	chstr[2] = 0;
516 	i = 0;
517 	while ((off + 2) <= strlen(argv[argc - 1])) {
518 		bcopy(argv[argc -1] + off, chstr, 2);
519 		off += 2;
520 
521 		if (!isxdigit(chstr[0]) || !isxdigit(chstr[1])) {
522 			(void) fprintf(stderr, "Invalid LU GUID specified.\n");
523 			ret = 1;
524 			goto delete_lu_done;
525 		}
526 		errno = 0;
527 		ch = strtoul(chstr, &pend, 16);
528 		if (errno != 0) {
529 			(void) fprintf(stderr, "Invalid LU GUID specified.\n");
530 			ret = 1;
531 			goto delete_lu_done;
532 		}
533 		drlc.guid[i++] = ch;
534 
535 	}
536 
537 	if (ioctl(sbd_fd, SBD_DEREGISTER_LU, &drlc) < 0) {
538 		if (errno != ENODEV) {
539 			(void) fprintf(stderr,
540 			    "Request to delete LU failed: %s\n",
541 			    strerror(errno));
542 			ret = 1;
543 			goto delete_lu_done;
544 		}
545 	} else if (drlc.return_code != 0) {
546 		(void) fprintf(stderr, "LU deregister failed: ret_code-%x",
547 		    drlc.return_code);
548 		ret = 1;
549 		goto delete_lu_done;
550 	} else {
551 		exists = 1;
552 	}
553 
554 	if (!keep_view) {
555 		for (i = 0; i < 16; i++)
556 			inGuid.guid[i] = drlc.guid[i];
557 
558 		if ((stmf_ret = stmfGetViewEntryList(&inGuid,
559 		    &viewEntryList)) == STMF_STATUS_SUCCESS) {
560 			for (i = 0; i < viewEntryList->cnt; i++) {
561 				(void) stmfRemoveViewEntry(&inGuid,
562 				    viewEntryList->ve[i].veIndex);
563 			}
564 		} else if (stmf_ret != STMF_ERROR_NOT_FOUND) {
565 			(void) fprintf(stderr,
566 			    "unable to remove view entries\n");
567 			ret = 1;
568 		}
569 	}
570 
571 	if (!exists) {
572 		(void) fprintf(stderr, "GUID not found.\n");
573 		ret = 1;
574 		goto delete_lu_done;
575 	}
576 
577 delete_lu_done:;
578 	return (ret);
579 }
580 
581 /*ARGSUSED*/
582 int
583 modify_lu(int argc, char *argv[], cmdOptions_t *options, void *callData)
584 {
585 	modify_lu_cmd_t *mlc;
586 	uint32_t fl = 0, struct_size;
587 	int ret = 0, err;
588 	int i = 0;
589 	uint64_t size;
590 	int is_filename = 0;
591 	char chstr[3], *pend = NULL;
592 	uint32_t ch;
593 	uint32_t off = 0;
594 
595 	if (argv[argc - 1][0] == '/') {
596 		is_filename = 1;
597 		fl = strlen(argv[argc - 1]) + 1;
598 		struct_size = sizeof (modify_lu_cmd_t) + fl - 8;
599 	} else {
600 		struct_size = sizeof (modify_lu_cmd_t);
601 	}
602 	mlc = (modify_lu_cmd_t *)malloc(struct_size);
603 	if (mlc == NULL) {
604 		(void) fprintf(stderr, "Unable to allocate memory\n");
605 		return (1);
606 	}
607 	bzero(mlc, sizeof (modify_lu_cmd_t));
608 	mlc->total_struct_size = struct_size;
609 
610 	mlc->flags = RLC_LU_TYPE_FILEDISK | RLC_CREATE_LU;
611 	for (; options->optval; options++) {
612 		if (options->optval == 's') {
613 			err = str_to_size(options->optarg, &size);
614 			if (err == 1) {
615 				(void) fprintf(stderr,
616 				    "Size out of range: maximum"
617 				    " supported size is 9223372036854775808"
618 				    " (8 Exabytes)\n");
619 				ret = 1;
620 				goto modify_lu_done;
621 			} else if (err == 2) {
622 				(void) fprintf(stderr,
623 				    "Invalid size specified\n");
624 				ret = 1;
625 				goto modify_lu_done;
626 			}
627 			mlc->lu_size = size;
628 		}
629 	}
630 	if (is_filename) {
631 		(void) strcpy(mlc->name, argv[argc-1]);
632 		(void) memset(mlc->guid, 0, 16);
633 	} else {
634 		if (strlen(argv[argc - 1]) != 32) {
635 			(void) fprintf(stderr,
636 			    "Invalid device identifier or filename"
637 			    " specified.\nIf it is a filename, it should be an"
638 			    " absolute path i.e. it should start with a /\n");
639 			goto modify_lu_done;
640 		}
641 		chstr[2] = 0;
642 		i = 0;
643 		while ((off + 2) <= strlen(argv[argc - 1])) {
644 			bcopy(argv[argc -1] + off, chstr, 2);
645 			off += 2;
646 
647 			ch = strtoul(chstr, &pend, 16);
648 			if (errno != 0) {
649 				(void) fprintf(stderr,
650 				    "Invalid device identifier or"
651 				    " filename specified.\nIf it is a"
652 				    " filename, it should be an absolute path"
653 				    " i.e. it should start with a /\n");
654 				ret = 1;
655 				goto modify_lu_done;
656 			}
657 			mlc->guid[i++] = ch;
658 
659 		}
660 		mlc->name[0] = '\0';
661 	}
662 	if ((ioctl(sbd_fd, SBD_MODIFY_LU, mlc) < 0) ||
663 	    (mlc->return_code != 0) || (mlc->op_ret |= STMF_SUCCESS)) {
664 		if (mlc->return_code && (mlc->return_code < RLC_RET_MAX_VAL)) {
665 			(void) fprintf(stderr, "LU modify failed : %s.\n",
666 			    rlc_ret[mlc->return_code]);
667 			if (mlc->return_code ==
668 			    RLC_RET_SIZE_NOT_SUPPORTED_BY_FS) {
669 				(void) fprintf(stderr, "Maximum LU size on "
670 				    "the underlying filesystem can be %llu "
671 				    "bytes.\n",
672 				    ((((uint64_t)1) << mlc->filesize_nbits)
673 				    - 1) & 0xfffffffffffffe00ull);
674 			} else if (mlc->return_code ==
675 			    RLC_RET_LU_NOT_INITIALIZED) {
676 				(void) fprintf(stderr, "Use 'sbdadm lu-create' "
677 				    "to initialize the LU.\n");
678 			}
679 		} else {
680 			(void) fprintf(stderr, "LU modify failed(%llx) : %s.\n",
681 			    mlc->op_ret, strerror(errno));
682 		}
683 		ret = 1;
684 	} else {
685 		(void) printf("LU modified Successfully.\n");
686 	}
687 
688 modify_lu_done:;
689 	free(mlc);
690 	return (ret);
691 }
692 
693 
694 /*ARGSUSED*/
695 int
696 list_lus(int argc, char *argv[], cmdOptions_t *options, void *callData)
697 {
698 	sbd_lu_list_t *sll;
699 	uint32_t i;
700 	ssize_t list_size;
701 	int retry_count = 0;
702 	uint32_t lu_count_in = MAX_LU_LIST;
703 	int ret;
704 	nvlist_t *nvl = NULL;
705 	nvpair_t *np;
706 	char *s;
707 
708 	ret = stmfGetProviderDataProt("sbd", &nvl, STMF_LU_PROVIDER_TYPE,
709 	    NULL);
710 	if (ret != STMF_STATUS_SUCCESS) {
711 		if (ret == STMF_ERROR_NOT_FOUND) {
712 			(void) nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);
713 		} else {
714 			(void) fprintf(stderr,
715 			    "Could not access persistent store\n");
716 			return (1);
717 		}
718 	}
719 
720 retry_get_lu_list:
721 	list_size = (lu_count_in * 8) + sizeof (sbd_lu_list_t) - 8;
722 	sll = (sbd_lu_list_t *)calloc(1, list_size);
723 	if (sll == NULL) {
724 		(void) fprintf(stderr, "Memory allocation failure\n");
725 		nvlist_free(nvl);
726 		return (1);
727 	}
728 
729 	sll->total_struct_size = list_size;
730 
731 	sll->count_in = lu_count_in;
732 	if (ioctl(sbd_fd, SBD_GET_LU_LIST, sll) < 0) {
733 		(void) fprintf(stderr, "Unable to get LU list : %s\n",
734 		    strerror(errno));
735 		free(sll);
736 		nvlist_free(nvl);
737 		return (1);
738 	}
739 	if (sll->count_out > sll->count_in) {
740 		lu_count_in = sll->count_out;
741 		free(sll);
742 		if (retry_count < LU_LIST_MAX_RETRIES) {
743 			retry_count++;
744 			goto retry_get_lu_list;
745 		} else {
746 			(void) fprintf(stderr, "Unable to get LU list after %d"
747 			    " retries\n", retry_count);
748 			nvlist_free(nvl);
749 			return (1);
750 		}
751 	}
752 
753 	(void) printf("\nFound %d LU(s)\n", sll->count_out);
754 	if (sll->count_out == 0)
755 		goto over_print_attr;
756 
757 	print_attr_header();
758 	for (i = 0; i < sll->count_out; i++) {
759 		if (!print_lu_attr(sll->handles[i], &s))
760 			continue;
761 		if (nvlist_remove(nvl, s, DATA_TYPE_STRING) != 0) {
762 			(void) fprintf(stderr,
763 			    "Error: GUID %s does not exist in "
764 			    "persistent store\n", s);
765 		}
766 	}
767 over_print_attr:
768 	free(sll);
769 	np = NULL;
770 	while ((np = nvlist_next_nvpair(nvl, np)) != NULL) {
771 		if (nvpair_type(np) != DATA_TYPE_STRING)
772 			continue;
773 		if (nvpair_value_string(np, &s) != 0)
774 			continue;
775 
776 		(void) fprintf(stderr, "%s   <Failed to load>    %s\n",
777 		    nvpair_name(np), s);
778 	}
779 	nvlist_free(nvl);
780 	return (0);
781 }
782 
783 void
784 print_attr_header()
785 {
786 	(void) printf("\n");
787 	(void) printf("	      GUID                    DATA SIZE      "
788 	    "     SOURCE\n");
789 	(void) printf("--------------------------------  -------------------"
790 	    "  ----------------\n");
791 }
792 
793 void
794 print_guid(uint8_t *g, FILE *f)
795 {
796 	int i;
797 
798 	for (i = 0; i < 16; i++) {
799 		(void) fprintf(f, "%02x", g[i]);
800 	}
801 }
802 
803 int
804 print_lu_attr(uint64_t handle, char **s)
805 {
806 	sbd_lu_attr_t *sla;
807 
808 	sla = (sbd_lu_attr_t *)big_buf;
809 
810 	bzero(sla, BIG_BUF_SIZE);
811 
812 	sla->lu_handle = handle;
813 	sla->total_struct_size = BIG_BUF_SIZE;
814 	sla->max_name_length = BIG_BUF_SIZE - sizeof (*sla) + 7;
815 
816 	if (ioctl(sbd_fd, SBD_GET_LU_ATTR, sla) < 0) {
817 		(void) fprintf(stderr, "Request to get LU attr failed: %s\n",
818 		    strerror(errno));
819 		return (0);
820 	}
821 
822 	print_guid(sla->guid, stdout);
823 
824 	if (sla->data_size > 9999999999999ull)
825 		(void) printf("  %-19llu  ", sla->data_size);
826 	else
827 		(void) printf("      %-13llu    ", sla->data_size);
828 
829 	if (sla->flags & RLC_LU_TYPE_MEMDISK) {
830 		(void) printf("<RAM : %llu bytes>\n", sla->total_size);
831 	} else {
832 		(void) printf("%s\n", sla->name);
833 	}
834 	if (s != NULL) {
835 		(void) snprintf((char *)big_buf, sizeof (big_buf),
836 		    "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
837 		    "%02x%02x%02x%02x%02x%02x",
838 		    sla->guid[0], sla->guid[1], sla->guid[2],
839 		    sla->guid[3], sla->guid[4], sla->guid[5],
840 		    sla->guid[6], sla->guid[7], sla->guid[8],
841 		    sla->guid[9], sla->guid[10], sla->guid[11],
842 		    sla->guid[12], sla->guid[13], sla->guid[14],
843 		    sla->guid[15]);
844 		*s = (char *)big_buf;
845 	}
846 	return (1);
847 }
848