xref: /illumos-gate/usr/src/lib/libdiskmgt/common/entry.c (revision a83cadce5d3331b64803bfc641036cec23602c74)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23   * Use is subject to license terms.
24   */
25  
26  #pragma ident	"%Z%%M%	%I%	%E% SMI"
27  
28  #include <fcntl.h>
29  #include <libdevinfo.h>
30  #include <stdio.h>
31  #include <sys/sunddi.h>
32  #include <sys/types.h>
33  #include <unistd.h>
34  #include <stdlib.h>
35  #include <string.h>
36  #include <libintl.h>
37  #include <locale.h>
38  #include <sys/debug.h>
39  #include <strings.h>
40  #include <sys/stat.h>
41  #include <sys/swap.h>
42  
43  #include "libdiskmgt.h"
44  #include "disks_private.h"
45  #include "partition.h"
46  
47  #define	ANY_ZPOOL_USE(who) \
48  	(((who) == DM_WHO_ZPOOL_FORCE) || \
49  	((who) == DM_WHO_ZPOOL) || \
50  	((who) == DM_WHO_ZPOOL_SPARE))
51  
52  extern	char	*getfullblkname();
53  
54  extern dm_desc_type_t drive_assoc_types[];
55  extern dm_desc_type_t bus_assoc_types[];
56  extern dm_desc_type_t controller_assoc_types[];
57  extern dm_desc_type_t media_assoc_types[];
58  extern dm_desc_type_t slice_assoc_types[];
59  extern dm_desc_type_t partition_assoc_types[];
60  extern dm_desc_type_t path_assoc_types[];
61  extern dm_desc_type_t alias_assoc_types[];
62  
63  
64  static dm_descriptor_t *ptr_array_to_desc_array(descriptor_t **ptrs, int *errp);
65  static descriptor_t **desc_array_to_ptr_array(dm_descriptor_t *da, int *errp);
66  static int build_usage_string(char *dname, char *by, char *data, char **use,
67  	int *found, int *errp);
68  
69  void
70  dm_free_descriptor(dm_descriptor_t desc)
71  {
72  	descriptor_t	*dp;
73  
74  	if (desc == NULL) {
75  	    return;
76  	}
77  	dp = (descriptor_t *)(uintptr_t)desc;
78  
79  	cache_wlock();
80  	cache_free_descriptor(dp);
81  	cache_unlock();
82  }
83  
84  void
85  dm_free_descriptors(dm_descriptor_t *desc_list)
86  {
87  	descriptor_t	**dp;
88  	int		error;
89  
90  	if (desc_list == NULL) {
91  	    return;
92  	}
93  	dp = desc_array_to_ptr_array(desc_list, &error);
94  	if (error != 0) {
95  	    free(desc_list);
96  	    return;
97  	}
98  
99  	cache_wlock();
100  	cache_free_descriptors(dp);
101  	cache_unlock();
102  }
103  
104  /*ARGSUSED*/
105  void
106  dm_free_name(char *name)
107  {
108  	free(name);
109  }
110  
111  dm_descriptor_t *
112  dm_get_associated_descriptors(dm_descriptor_t desc, dm_desc_type_t type,
113      int *errp)
114  {
115  	descriptor_t **descs = NULL;
116  	descriptor_t  *dp;
117  
118  
119  	dp = (descriptor_t *)(uintptr_t)desc;
120  
121  	cache_wlock();
122  
123  	if (!cache_is_valid_desc(dp)) {
124  	    cache_unlock();
125  	    *errp = EBADF;
126  	    return (NULL);
127  	}
128  
129  	/* verify that the descriptor is still valid */
130  	if (dp->p.generic == NULL) {
131  	    cache_unlock();
132  	    *errp = ENODEV;
133  	    return (NULL);
134  	}
135  
136  	switch (dp->type) {
137  	case DM_DRIVE:
138  	    descs = drive_get_assoc_descriptors(dp, type, errp);
139  	    break;
140  	case DM_BUS:
141  	    descs = bus_get_assoc_descriptors(dp, type, errp);
142  	    break;
143  	case DM_CONTROLLER:
144  	    descs = controller_get_assoc_descriptors(dp, type, errp);
145  	    break;
146  	case DM_MEDIA:
147  	    descs = media_get_assoc_descriptors(dp, type, errp);
148  	    break;
149  	case DM_SLICE:
150  	    descs = slice_get_assoc_descriptors(dp, type, errp);
151  	    break;
152  	case DM_PARTITION:
153  	    descs = partition_get_assoc_descriptors(dp, type, errp);
154  	    break;
155  	case DM_PATH:
156  	    descs = path_get_assoc_descriptors(dp, type, errp);
157  	    break;
158  	case DM_ALIAS:
159  	    descs = alias_get_assoc_descriptors(dp, type, errp);
160  	    break;
161  	default:
162  	    *errp = EINVAL;
163  	    break;
164  	}
165  
166  	cache_unlock();
167  
168  	return (ptr_array_to_desc_array(descs, errp));
169  }
170  
171  dm_desc_type_t *
172  dm_get_associated_types(dm_desc_type_t type)
173  {
174  	switch (type) {
175  	case DM_DRIVE:
176  	    return (drive_assoc_types);
177  	case DM_BUS:
178  	    return (bus_assoc_types);
179  	case DM_CONTROLLER:
180  	    return (controller_assoc_types);
181  	case DM_MEDIA:
182  	    return (media_assoc_types);
183  	case DM_SLICE:
184  	    return (slice_assoc_types);
185  	case DM_PARTITION:
186  	    return (partition_assoc_types);
187  	case DM_PATH:
188  	    return (path_assoc_types);
189  	case DM_ALIAS:
190  	    return (alias_assoc_types);
191  	}
192  
193  	return (NULL);
194  }
195  
196  nvlist_t *
197  dm_get_attributes(dm_descriptor_t desc, int *errp)
198  {
199  	descriptor_t	*dp;
200  	nvlist_t	*attrs = NULL;
201  
202  
203  	dp = (descriptor_t *)(uintptr_t)desc;
204  
205  	cache_rlock();
206  
207  	if (!cache_is_valid_desc(dp)) {
208  	    cache_unlock();
209  	    *errp = EBADF;
210  	    return (NULL);
211  	}
212  
213  	/* verify that the descriptor is still valid */
214  	if (dp->p.generic == NULL) {
215  	    cache_unlock();
216  	    *errp = ENODEV;
217  	    return (NULL);
218  	}
219  
220  	switch (dp->type) {
221  	case DM_DRIVE:
222  	    attrs = drive_get_attributes(dp, errp);
223  	    break;
224  	case DM_BUS:
225  	    attrs = bus_get_attributes(dp, errp);
226  	    break;
227  	case DM_CONTROLLER:
228  	    attrs = controller_get_attributes(dp, errp);
229  	    break;
230  	case DM_MEDIA:
231  	    attrs = media_get_attributes(dp, errp);
232  	    break;
233  	case DM_SLICE:
234  	    attrs = slice_get_attributes(dp, errp);
235  	    break;
236  	case DM_PARTITION:
237  	    attrs = partition_get_attributes(dp, errp);
238  	    break;
239  	case DM_PATH:
240  	    attrs = path_get_attributes(dp, errp);
241  	    break;
242  	case DM_ALIAS:
243  	    attrs = alias_get_attributes(dp, errp);
244  	    break;
245  	default:
246  	    *errp = EINVAL;
247  	    break;
248  	}
249  
250  	cache_unlock();
251  
252  	return (attrs);
253  }
254  
255  dm_descriptor_t
256  dm_get_descriptor_by_name(dm_desc_type_t desc_type, char *name, int *errp)
257  {
258  	dm_descriptor_t desc = NULL;
259  
260  
261  	cache_wlock();
262  
263  	switch (desc_type) {
264  	case DM_DRIVE:
265  	    desc = (uintptr_t)drive_get_descriptor_by_name(name, errp);
266  	    break;
267  	case DM_BUS:
268  	    desc = (uintptr_t)bus_get_descriptor_by_name(name, errp);
269  	    break;
270  	case DM_CONTROLLER:
271  	    desc = (uintptr_t)controller_get_descriptor_by_name(name,
272  		errp);
273  	    break;
274  	case DM_MEDIA:
275  	    desc = (uintptr_t)media_get_descriptor_by_name(name, errp);
276  	    break;
277  	case DM_SLICE:
278  	    desc = (uintptr_t)slice_get_descriptor_by_name(name, errp);
279  	    break;
280  	case DM_PARTITION:
281  	    desc = (uintptr_t)partition_get_descriptor_by_name(name,
282  		errp);
283  	    break;
284  	case DM_PATH:
285  	    desc = (uintptr_t)path_get_descriptor_by_name(name, errp);
286  	    break;
287  	case DM_ALIAS:
288  	    desc = (uintptr_t)alias_get_descriptor_by_name(name, errp);
289  	    break;
290  	default:
291  	    *errp = EINVAL;
292  	    break;
293  	}
294  
295  	cache_unlock();
296  
297  	return (desc);
298  }
299  
300  dm_descriptor_t *
301  dm_get_descriptors(dm_desc_type_t type, int filter[], int *errp)
302  {
303  	descriptor_t **descs = NULL;
304  
305  
306  	cache_wlock();
307  
308  	switch (type) {
309  	case DM_DRIVE:
310  	    descs = drive_get_descriptors(filter, errp);
311  	    break;
312  	case DM_BUS:
313  	    descs = bus_get_descriptors(filter, errp);
314  	    break;
315  	case DM_CONTROLLER:
316  	    descs = controller_get_descriptors(filter, errp);
317  	    break;
318  	case DM_MEDIA:
319  	    descs = media_get_descriptors(filter, errp);
320  	    break;
321  	case DM_SLICE:
322  	    descs = slice_get_descriptors(filter, errp);
323  	    break;
324  	case DM_PARTITION:
325  	    descs = partition_get_descriptors(filter, errp);
326  	    break;
327  	case DM_PATH:
328  	    descs = path_get_descriptors(filter, errp);
329  	    break;
330  	case DM_ALIAS:
331  	    descs = alias_get_descriptors(filter, errp);
332  	    break;
333  	default:
334  	    *errp = EINVAL;
335  	    break;
336  	}
337  
338  	cache_unlock();
339  
340  	return (ptr_array_to_desc_array(descs, errp));
341  }
342  
343  char *
344  dm_get_name(dm_descriptor_t desc, int *errp)
345  {
346  	descriptor_t	*dp;
347  	char		*nm = NULL;
348  	char		*name = NULL;
349  
350  	dp = (descriptor_t *)(uintptr_t)desc;
351  
352  	cache_rlock();
353  
354  	if (!cache_is_valid_desc(dp)) {
355  	    cache_unlock();
356  	    *errp = EBADF;
357  	    return (NULL);
358  	}
359  
360  	/* verify that the descriptor is still valid */
361  	if (dp->p.generic == NULL) {
362  	    cache_unlock();
363  	    *errp = ENODEV;
364  	    return (NULL);
365  	}
366  
367  	switch (dp->type) {
368  	case DM_DRIVE:
369  	    nm = (drive_get_name(dp));
370  	    break;
371  	case DM_BUS:
372  	    nm = (bus_get_name(dp));
373  	    break;
374  	case DM_CONTROLLER:
375  	    nm = (controller_get_name(dp));
376  	    break;
377  	case DM_MEDIA:
378  	    nm = (media_get_name(dp));
379  	    break;
380  	case DM_SLICE:
381  	    nm = (slice_get_name(dp));
382  	    break;
383  	case DM_PARTITION:
384  	    nm = (partition_get_name(dp));
385  	    break;
386  	case DM_PATH:
387  	    nm = (path_get_name(dp));
388  	    break;
389  	case DM_ALIAS:
390  	    nm = (alias_get_name(dp));
391  	    break;
392  	}
393  
394  	cache_unlock();
395  
396  	*errp = 0;
397  	if (nm != NULL) {
398  	    name = strdup(nm);
399  	    if (name == NULL) {
400  		*errp = ENOMEM;
401  		return (NULL);
402  	    }
403  	    return (name);
404  	}
405  	return (NULL);
406  }
407  
408  nvlist_t *
409  dm_get_stats(dm_descriptor_t desc, int stat_type, int *errp)
410  {
411  	descriptor_t  *dp;
412  	nvlist_t	*stats = NULL;
413  
414  
415  	dp = (descriptor_t *)(uintptr_t)desc;
416  
417  	cache_rlock();
418  
419  	if (!cache_is_valid_desc(dp)) {
420  		cache_unlock();
421  		*errp = EBADF;
422  		return (NULL);
423  	}
424  
425  	/* verify that the descriptor is still valid */
426  	if (dp->p.generic == NULL) {
427  		cache_unlock();
428  		*errp = ENODEV;
429  		return (NULL);
430  	}
431  
432  	switch (dp->type) {
433  	case DM_DRIVE:
434  		stats = drive_get_stats(dp, stat_type, errp);
435  		break;
436  	case DM_BUS:
437  		stats = bus_get_stats(dp, stat_type, errp);
438  		break;
439  	case DM_CONTROLLER:
440  		stats = controller_get_stats(dp, stat_type, errp);
441  		break;
442  	case DM_MEDIA:
443  		stats = media_get_stats(dp, stat_type, errp);
444  		break;
445  	case DM_SLICE:
446  		if (stat_type == DM_SLICE_STAT_USE) {
447  			/*
448  			 * If NOINUSE_CHECK is set, we do not perform
449  			 * the in use checking if the user has set stat_type
450  			 * DM_SLICE_STAT_USE
451  			 */
452  			if (NOINUSE_SET) {
453  				stats = NULL;
454  				break;
455  			}
456  		}
457  		stats = slice_get_stats(dp, stat_type, errp);
458  		break;
459  	case DM_PARTITION:
460  		stats = partition_get_stats(dp, stat_type, errp);
461  		break;
462  	case DM_PATH:
463  		stats = path_get_stats(dp, stat_type, errp);
464  		break;
465  	case DM_ALIAS:
466  		stats = alias_get_stats(dp, stat_type, errp);
467  		break;
468  	default:
469  		*errp = EINVAL;
470  		break;
471  	}
472  
473  	cache_unlock();
474  
475  	return (stats);
476  }
477  
478  dm_desc_type_t
479  dm_get_type(dm_descriptor_t desc)
480  {
481  	descriptor_t  *dp;
482  
483  	dp = (descriptor_t *)(uintptr_t)desc;
484  
485  	cache_rlock();
486  
487  	if (!cache_is_valid_desc(dp)) {
488  	    cache_unlock();
489  	    return (-1);
490  	}
491  
492  	cache_unlock();
493  
494  	return (dp->type);
495  }
496  /*
497   * Returns, via slices paramater, a dm_descriptor_t list of
498   * slices for the named disk drive.
499   */
500  void
501  dm_get_slices(char *drive, dm_descriptor_t **slices, int *errp)
502  {
503  	dm_descriptor_t alias;
504  	dm_descriptor_t	*media;
505  	dm_descriptor_t *disk;
506  
507  	*slices = NULL;
508  	*errp = 0;
509  
510  	if (drive == NULL) {
511  		return;
512  	}
513  
514  	alias = dm_get_descriptor_by_name(DM_ALIAS, drive, errp);
515  
516  	/*
517  	 * Errors must be handled by the caller. The dm_descriptor_t *
518  	 * values will be NULL if an error occured in these calls.
519  	 */
520  
521  	if (alias != NULL) {
522  		disk = dm_get_associated_descriptors(alias, DM_DRIVE, errp);
523  		dm_free_descriptor(alias);
524  		if (disk != NULL) {
525  			media = dm_get_associated_descriptors(*disk,
526  			    DM_MEDIA, errp);
527  			dm_free_descriptors(disk);
528  			if (media != NULL) {
529  				*slices = dm_get_associated_descriptors(*media,
530  				    DM_SLICE, errp);
531  				dm_free_descriptors(media);
532  			}
533  		}
534  	}
535  }
536  /*
537   * Convenience function to get slice stats
538   */
539  void
540  dm_get_slice_stats(char *slice, nvlist_t **dev_stats, int *errp)
541  {
542  	dm_descriptor_t	devp;
543  
544  	*dev_stats = NULL;
545  	*errp = 0;
546  
547  	if (slice == NULL) {
548  		return;
549  	}
550  
551  	/*
552  	 * Errors must be handled by the caller. The dm_descriptor_t *
553  	 * values will be NULL if an error occured in these calls.
554  	 */
555  	devp = dm_get_descriptor_by_name(DM_SLICE, slice, errp);
556  	if (devp != NULL) {
557  		*dev_stats = dm_get_stats(devp, DM_SLICE_STAT_USE,
558  		    errp);
559  		dm_free_descriptor(devp);
560  	}
561  }
562  
563  /*
564   * Checks for overlapping slices.   If the given device is a slice, and it
565   * overlaps with any non-backup slice on the disk, return true with a detailed
566   * description similar to dm_inuse().
567   */
568  int
569  dm_isoverlapping(char *slicename, char **overlaps_with, int *errp)
570  {
571  	dm_descriptor_t slice = NULL;
572  	dm_descriptor_t *media = NULL;
573  	dm_descriptor_t *slices = NULL;
574  	int 		i = 0;
575  	uint32_t	in_snum;
576  	uint64_t 	start_block = 0;
577  	uint64_t 	end_block = 0;
578  	uint64_t 	media_size = 0;
579  	uint64_t 	size = 0;
580  	nvlist_t 	*media_attrs = NULL;
581  	nvlist_t 	*slice_attrs = NULL;
582  	int		ret = 0;
583  
584  	slice = dm_get_descriptor_by_name(DM_SLICE, slicename, errp);
585  	if (slice == NULL)
586  		goto out;
587  
588  	/*
589  	 * Get the list of slices be fetching the associated media, and then all
590  	 * associated slices.
591  	 */
592  	media = dm_get_associated_descriptors(slice, DM_MEDIA, errp);
593  	if (media == NULL || *media == NULL || *errp != 0)
594  		goto out;
595  
596  	slices = dm_get_associated_descriptors(*media, DM_SLICE, errp);
597  	if (slices == NULL || *slices == NULL || *errp != 0)
598  		goto out;
599  
600  	media_attrs = dm_get_attributes(*media, errp);
601  	if (media_attrs == NULL || *errp)
602  		goto out;
603  
604  	*errp = nvlist_lookup_uint64(media_attrs, DM_NACCESSIBLE, &media_size);
605  	if (*errp != 0)
606  		goto out;
607  
608  	slice_attrs = dm_get_attributes(slice, errp);
609  	if (slice_attrs == NULL || *errp != 0)
610  		goto out;
611  
612  	*errp = nvlist_lookup_uint64(slice_attrs, DM_START, &start_block);
613  	if (*errp != 0)
614  		goto out;
615  
616  	*errp = nvlist_lookup_uint64(slice_attrs, DM_SIZE, &size);
617  	if (*errp != 0)
618  		goto out;
619  
620  	*errp = nvlist_lookup_uint32(slice_attrs, DM_INDEX, &in_snum);
621  	if (*errp != 0)
622  		goto out;
623  
624  	end_block = (start_block + size) - 1;
625  
626  	for (i = 0; slices[i]; i ++) {
627  		uint64_t other_start;
628  		uint64_t other_end;
629  		uint64_t other_size;
630  		uint32_t snum;
631  
632  		nvlist_t *other_attrs = dm_get_attributes(slices[i], errp);
633  
634  		if (other_attrs == NULL)
635  			continue;
636  
637  		if (*errp != 0)
638  			goto out;
639  
640  		*errp = nvlist_lookup_uint64(other_attrs, DM_START,
641  		    &other_start);
642  		if (*errp) {
643  			nvlist_free(other_attrs);
644  			goto out;
645  		}
646  
647  		*errp = nvlist_lookup_uint64(other_attrs, DM_SIZE,
648  		    &other_size);
649  
650  		if (*errp) {
651  			nvlist_free(other_attrs);
652  			ret = -1;
653  			goto out;
654  		}
655  
656  		other_end = (other_size + other_start) - 1;
657  
658  		*errp = nvlist_lookup_uint32(other_attrs, DM_INDEX,
659  		    &snum);
660  
661  		if (*errp) {
662  			nvlist_free(other_attrs);
663  			ret = -1;
664  			goto out;
665  		}
666  
667  		/*
668  		 * Check to see if there are > 2 overlapping regions
669  		 * on this media in the same region as this slice.
670  		 * This is done by assuming the following:
671  		 *   	Slice 2 is the backup slice if it is the size
672  		 *	of the whole disk
673  		 * If slice 2 is the overlap and slice 2 is the size of
674  		 * the whole disk, continue. If another slice is found
675  		 * that overlaps with our slice, return it.
676  		 * There is the potential that there is more than one slice
677  		 * that our slice overlaps with, however, we only return
678  		 * the first overlapping slice we find.
679  		 *
680  		 */
681  		if (start_block >= other_start && start_block <= other_end) {
682  			if ((snum == 2 && (other_size == media_size)) ||
683  			    snum == in_snum) {
684  				continue;
685  			} else {
686  				char *str = dm_get_name(slices[i], errp);
687  				if (*errp != 0) {
688  					nvlist_free(other_attrs);
689  					ret = -1;
690  					goto out;
691  				}
692  				*overlaps_with = strdup(str);
693  				dm_free_name(str);
694  				nvlist_free(other_attrs);
695  				ret = 1;
696  				goto out;
697  			}
698  		} else if (other_start >= start_block &&
699  		    other_start <= end_block) {
700  			if ((snum == 2 && (other_size == media_size)) ||
701  			    snum == in_snum) {
702  				continue;
703  			} else {
704  				char *str = dm_get_name(slices[i], errp);
705  				if (*errp != 0) {
706  					nvlist_free(other_attrs);
707  					ret = -1;
708  					goto out;
709  				}
710  				*overlaps_with = strdup(str);
711  				dm_free_name(str);
712  				nvlist_free(other_attrs);
713  				ret = 1;
714  				goto out;
715  			}
716  		}
717  		nvlist_free(other_attrs);
718  	}
719  
720  out:
721  	if (media_attrs)
722  		nvlist_free(media_attrs);
723  	if (slice_attrs)
724  		nvlist_free(slice_attrs);
725  
726  	if (slices)
727  		dm_free_descriptors(slices);
728  	if (media)
729  		dm_free_descriptors(media);
730  	if (slice)
731  		dm_free_descriptor(slice);
732  
733  	return (ret);
734  }
735  
736  /*
737   * Get the full list of swap entries.  Returns -1 on error, or >= 0 to
738   * indicate the number of entries in the list.  Callers are responsible
739   * for calling dm_free_swapentries() to deallocate memory.  If this
740   * returns 0, the swaptbl_t still needs to be freed.
741   */
742  int
743  dm_get_swapentries(swaptbl_t **stp, int *errp)
744  {
745  	int count, i;
746  	swaptbl_t *tbl;
747  	char *ptr;
748  
749  	*stp = NULL;
750  
751  	/* get number of swap entries */
752  	if ((count = swapctl(SC_GETNSWP, NULL)) < 0) {
753  		*errp = errno;
754  		return (-1);
755  	}
756  
757  	if (count == 0) {
758  		return (0);
759  	}
760  
761  	/* allocate space */
762  	tbl = calloc(1, sizeof (int) + count * sizeof (swapent_t));
763  	if (tbl == NULL) {
764  		*errp = ENOMEM;
765  		return (-1);
766  	}
767  
768  	ptr = calloc(1, count * MAXPATHLEN);
769  	if (ptr == NULL) {
770  		*errp = ENOMEM;
771  		free(tbl);
772  		return (-1);
773  	}
774  
775  	/* set up pointers to the pathnames */
776  	tbl->swt_n = count;
777  	for (i = 0; i < count; i++) {
778  		tbl->swt_ent[i].ste_path = ptr;
779  		ptr += MAXPATHLEN;
780  	}
781  
782  	/* get list of swap paths */
783  	count = swapctl(SC_LIST, tbl);
784  	if (count < 0) {
785  		*errp = errno;
786  		free(ptr);
787  		free(tbl);
788  		return (-1);
789  	}
790  
791  	*stp = tbl;
792  	return (count);
793  }
794  
795  /* ARGSUSED */
796  void
797  dm_free_swapentries(swaptbl_t *stp)
798  {
799  	ASSERT(stp != NULL);
800  
801  	free(stp->swt_ent[0].ste_path);
802  	free(stp);
803  }
804  
805  /*
806   * Check a slice to see if it's being used by swap.
807   */
808  int
809  dm_inuse_swap(const char *dev_name, int *errp)
810  {
811  	int count;
812  	int found;
813  	swaptbl_t *tbl = NULL;
814  
815  	*errp = 0;
816  
817  	count = dm_get_swapentries(&tbl, errp);
818  	if (count < 0 || *errp) {
819  		if (tbl)
820  			dm_free_swapentries(tbl);
821  		return (-1);
822  	}
823  
824  	/* if there are no swap entries, we're done */
825  	if (!count) {
826  		return (0);
827  	}
828  
829  	ASSERT(tbl != NULL);
830  
831  	found = 0;
832  	while (count--) {
833  		if (strcmp(dev_name, tbl->swt_ent[count].ste_path) == 0) {
834  			found = 1;
835  			break;
836  		}
837  	}
838  
839  	dm_free_swapentries(tbl);
840  	return (found);
841  }
842  
843  /*
844   * Returns 'in use' details, if found, about a specific dev_name,
845   * based on the caller(who). It is important to note that it is possible
846   * for there to be more than one 'in use' statistic regarding a dev_name.
847   * The **msg parameter returns a list of 'in use' details. This message
848   * is formatted via gettext().
849   */
850  int
851  dm_inuse(char *dev_name, char **msg, dm_who_type_t who, int *errp)
852  {
853  	nvlist_t *dev_stats = NULL;
854  	char *by, *data;
855  	nvpair_t *nvwhat = NULL;
856  	nvpair_t *nvdesc = NULL;
857  	int	found = 0;
858  	int	err;
859  	char	*dname = NULL;
860  
861  	*errp = 0;
862  	*msg = NULL;
863  
864  	/*
865  	 * If the user doesn't want to do in use checking, return.
866  	 */
867  
868  	if (NOINUSE_SET)
869  		return (0);
870  
871  	dname = getfullblkname(dev_name);
872  	/*
873  	 * If we cannot find the block name, we cannot check the device
874  	 * for in use statistics. So, return found, which is == 0.
875  	 */
876  	if (dname == NULL || *dname == '\0') {
877  		return (found);
878  	}
879  
880  	/*
881  	 * Slice stats for swap devices are only returned if mounted
882  	 * (e.g. /tmp).  Other devices or files being used for swap
883  	 * are ignored, so we add a special check here to use swapctl(2)
884  	 * to perform in-use checking.
885  	 */
886  	if (ANY_ZPOOL_USE(who) && (err = dm_inuse_swap(dname, errp))) {
887  
888  		/* on error, dm_inuse_swap sets errp */
889  		if (err < 0) {
890  			free(dname);
891  			return (err);
892  		}
893  
894  		/* simulate a mounted swap device */
895  		(void) build_usage_string(dname, DM_USE_MOUNT, "swap", msg,
896  		    &found, errp);
897  
898  		/* if this fails, dm_get_usage_string changed */
899  		ASSERT(found == 1);
900  
901  		free(dname);
902  		return (found);
903  	}
904  
905  	dm_get_slice_stats(dname, &dev_stats, errp);
906  	if (dev_stats == NULL) {
907  		/*
908  		 * If there is an error, but it isn't a no device found error
909  		 * return the error as recorded. Otherwise, with a full
910  		 * block name, we might not be able to get the slice
911  		 * associated, and will get an ENODEV error. For example,
912  		 * an SVM metadevice will return a value from getfullblkname()
913  		 * but libdiskmgt won't be able to find this device for
914  		 * statistics gathering. This is expected and we should not
915  		 * report errnoneous errors.
916  		 */
917  		if (*errp) {
918  			if (*errp == ENODEV) {
919  				*errp = 0;
920  			}
921  		}
922  		free(dname);
923  		return (found);
924  	}
925  
926  	for (;;) {
927  
928  		nvwhat = nvlist_next_nvpair(dev_stats, nvdesc);
929  		nvdesc = nvlist_next_nvpair(dev_stats, nvwhat);
930  
931  		/*
932  		 * End of the list found.
933  		 */
934  		if (nvwhat == NULL || nvdesc == NULL) {
935  			break;
936  		}
937  		/*
938  		 * Otherwise, we check to see if this client(who) cares
939  		 * about this in use scenario
940  		 */
941  
942  		ASSERT(strcmp(nvpair_name(nvwhat), DM_USED_BY) == 0);
943  		ASSERT(strcmp(nvpair_name(nvdesc), DM_USED_NAME) == 0);
944  		/*
945  		 * If we error getting the string value continue on
946  		 * to the next pair(if there is one)
947  		 */
948  		if (nvpair_value_string(nvwhat, &by)) {
949  			continue;
950  		}
951  		if (nvpair_value_string(nvdesc, &data)) {
952  			continue;
953  		}
954  
955  		switch (who) {
956  			case DM_WHO_MKFS:
957  				/*
958  				 * mkfs is not in use for these cases.
959  				 * All others are in use.
960  				 */
961  				if (strcmp(by, DM_USE_LU) == 0 ||
962  				    strcmp(by, DM_USE_FS) == 0 ||
963  				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) {
964  					break;
965  				}
966  				if (build_usage_string(dname,
967  				    by, data, msg, &found, errp) != 0) {
968  					if (*errp) {
969  						goto out;
970  					}
971  				}
972  				break;
973  			case DM_WHO_SWAP:
974  				/*
975  				 * Not in use for this.
976  				 */
977  				if (strcmp(by, DM_USE_DUMP) == 0 ||
978  				    strcmp(by, DM_USE_FS) == 0 ||
979  				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) {
980  					break;
981  				}
982  
983  				if (build_usage_string(dname,
984  				    by, data, msg, &found, errp) != 0) {
985  					if (*errp) {
986  						goto out;
987  					}
988  				}
989  				break;
990  			case DM_WHO_DUMP:
991  				/*
992  				 * Not in use for this.
993  				 */
994  				if ((strcmp(by, DM_USE_MOUNT) == 0 &&
995  				    strcmp(data, "swap") == 0) ||
996  				    strcmp(by, DM_USE_DUMP) == 0 ||
997  				    strcmp(by, DM_USE_FS) == 0 ||
998  				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) {
999  					break;
1000  				}
1001  				if (build_usage_string(dname,
1002  				    by, data, msg, &found, errp)) {
1003  					if (*errp) {
1004  						goto out;
1005  					}
1006  				}
1007  				break;
1008  
1009  			case DM_WHO_FORMAT:
1010  				if (strcmp(by, DM_USE_FS) == 0 ||
1011  				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0)
1012  					break;
1013  				if (build_usage_string(dname,
1014  				    by, data, msg, &found, errp) != 0) {
1015  					if (*errp) {
1016  						goto out;
1017  					}
1018  				}
1019  				break;
1020  
1021  			case DM_WHO_ZPOOL_FORCE:
1022  				if (strcmp(by, DM_USE_FS) == 0 ||
1023  				    strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0)
1024  					break;
1025  				/* FALLTHROUGH */
1026  			case DM_WHO_ZPOOL:
1027  				if (build_usage_string(dname,
1028  				    by, data, msg, &found, errp) != 0) {
1029  					if (*errp)
1030  						goto out;
1031  				}
1032  				break;
1033  
1034  			case DM_WHO_ZPOOL_SPARE:
1035  				if (strcmp(by, DM_USE_SPARE_ZPOOL) != 0) {
1036  					if (build_usage_string(dname, by,
1037  					    data, msg, &found, errp) != 0) {
1038  						if (*errp)
1039  							goto out;
1040  					}
1041  				}
1042  				break;
1043  
1044  			default:
1045  				/*
1046  				 * nothing found in use for this client
1047  				 * of libdiskmgt. Default is 'not in use'.
1048  				 */
1049  				break;
1050  		}
1051  	}
1052  out:
1053  	if (dname != NULL)
1054  		free(dname);
1055  	if (dev_stats != NULL)
1056  		nvlist_free(dev_stats);
1057  
1058  	return (found);
1059  }
1060  
1061  void
1062  dm_get_usage_string(char *what, char *how, char **usage_string)
1063  {
1064  
1065  
1066  	if (usage_string == NULL || what == NULL) {
1067  		return;
1068  	}
1069  	*usage_string = NULL;
1070  
1071  	if (strcmp(what, DM_USE_MOUNT) == 0) {
1072  		if (strcmp(how, "swap") == 0) {
1073  			*usage_string = dgettext(TEXT_DOMAIN,
1074  			    "%s is currently used by swap. Please see swap(1M)."
1075  			    "\n");
1076  		} else {
1077  			*usage_string = dgettext(TEXT_DOMAIN,
1078  			    "%s is currently mounted on %s."
1079  			    " Please see umount(1M).\n");
1080  		}
1081  	} else if (strcmp(what, DM_USE_VFSTAB) == 0) {
1082  		*usage_string = dgettext(TEXT_DOMAIN,
1083  		    "%s is normally mounted on %s according to /etc/vfstab. "
1084  		    "Please remove this entry to use this device.\n");
1085  	} else if (strcmp(what, DM_USE_FS) == 0) {
1086  		*usage_string = dgettext(TEXT_DOMAIN,
1087  		    "%s contains a %s filesystem.\n");
1088  	} else if (strcmp(what, DM_USE_SVM) == 0) {
1089  		if (strcmp(how, "mdb") == 0) {
1090  			*usage_string = dgettext(TEXT_DOMAIN,
1091  			    "%s contains an SVM %s. Please see "
1092  			    "metadb(1M).\n");
1093  		} else {
1094  			*usage_string = dgettext(TEXT_DOMAIN,
1095  			    "%s is part of SVM volume %s. "
1096  			    "Please see metaclear(1M).\n");
1097  		}
1098  	} else if (strcmp(what, DM_USE_VXVM) == 0) {
1099  		*usage_string = dgettext(TEXT_DOMAIN,
1100  		    "%s is part of VxVM volume %s.\n");
1101  	} else if (strcmp(what, DM_USE_LU) == 0) {
1102  		*usage_string = dgettext(TEXT_DOMAIN,
1103  		    "%s is in use for live upgrade %s. Please see ludelete(1M)."
1104  		    "\n");
1105  	} else if (strcmp(what, DM_USE_DUMP) == 0) {
1106  		*usage_string = dgettext(TEXT_DOMAIN,
1107  		    "%s is in use by %s. Please see dumpadm(1M)."
1108  		    "\n");
1109  	} else if (strcmp(what, DM_USE_EXPORTED_ZPOOL) == 0) {
1110  		*usage_string = dgettext(TEXT_DOMAIN,
1111  		    "%s is part of exported or potentially active ZFS pool %s. "
1112  		    "Please see zpool(1M).\n");
1113  	} else if (strcmp(what, DM_USE_ACTIVE_ZPOOL) == 0) {
1114  		*usage_string = dgettext(TEXT_DOMAIN,
1115  		    "%s is part of active ZFS pool %s. Please see zpool(1M)."
1116  		    "\n");
1117  	} else if (strcmp(what, DM_USE_SPARE_ZPOOL) == 0) {
1118  		*usage_string = dgettext(TEXT_DOMAIN,
1119  		    "%s is reserved as a hot spare for ZFS pool %s.  Please "
1120  		    "see zpool(1M).\n");
1121  	}
1122  }
1123  void
1124  libdiskmgt_add_str(nvlist_t *attrs, char *name, char *val, int *errp)
1125  {
1126  	if (*errp == 0) {
1127  		*errp = nvlist_add_string(attrs, name, val);
1128  	}
1129  }
1130  
1131  descriptor_t **
1132  libdiskmgt_empty_desc_array(int *errp)
1133  {
1134  	descriptor_t	**empty;
1135  
1136  	empty = (descriptor_t **)calloc(1, sizeof (descriptor_t *));
1137  	if (empty == NULL) {
1138  	    *errp = ENOMEM;
1139  	    return (NULL);
1140  	}
1141  	empty[0] = NULL;
1142  
1143  	*errp = 0;
1144  	return (empty);
1145  }
1146  
1147  void
1148  libdiskmgt_init_debug()
1149  {
1150  	char	*valp;
1151  
1152  	if ((valp = getenv(DM_DEBUG)) != NULL) {
1153  	    dm_debug = atoi(valp);
1154  	}
1155  }
1156  
1157  int
1158  libdiskmgt_str_eq(char *nm1, char *nm2)
1159  {
1160  	if (nm1 == NULL) {
1161  	    if (dm_debug) {
1162  		(void) fprintf(stderr, "WARNING: str_eq nm1 NULL\n");
1163  	    }
1164  
1165  	    if (nm2 == NULL) {
1166  		return (1);
1167  	    } else {
1168  		return (0);
1169  	    }
1170  	}
1171  
1172  	/* nm1 != NULL */
1173  
1174  	if (nm2 == NULL) {
1175  	    if (dm_debug) {
1176  		(void) fprintf(stderr, "WARNING: str_eq nm2 NULL\n");
1177  	    }
1178  	    return (0);
1179  	}
1180  
1181  	if (strcmp(nm1, nm2) == 0) {
1182  	    return (1);
1183  	}
1184  
1185  	return (0);
1186  }
1187  
1188  /*ARGSUSED*/
1189  static descriptor_t **
1190  desc_array_to_ptr_array(dm_descriptor_t *descs, int *errp)
1191  {
1192  #ifdef _LP64
1193  	return ((descriptor_t **)descs);
1194  #else
1195  	/* convert the 64 bit descriptors to 32 bit ptrs */
1196  	int	cnt;
1197  	int	i;
1198  	descriptor_t **da;
1199  
1200  	for (cnt = 0; descs[cnt]; cnt++);
1201  
1202  	da = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
1203  	if (da == NULL) {
1204  	    *errp = ENOMEM;
1205  	    return (NULL);
1206  	}
1207  
1208  	for (i = 0; descs[i]; i++) {
1209  	    da[i] = (descriptor_t *)(uintptr_t)descs[i];
1210  	}
1211  	*errp = 0;
1212  	free(descs);
1213  
1214  	return (da);
1215  #endif
1216  }
1217  
1218  /*ARGSUSED*/
1219  static dm_descriptor_t *
1220  ptr_array_to_desc_array(descriptor_t **ptrs, int *errp)
1221  {
1222  #ifdef _LP64
1223  	return ((dm_descriptor_t *)ptrs);
1224  #else
1225  	/* convert the 32 bit ptrs to the 64 bit descriptors */
1226  	int	cnt;
1227  	int	i;
1228  	dm_descriptor_t *da;
1229  
1230  	if (*errp != 0 || ptrs == NULL) {
1231  	    return (NULL);
1232  	}
1233  
1234  	for (cnt = 0; ptrs[cnt]; cnt++);
1235  
1236  	da = (dm_descriptor_t *)calloc(cnt + 1, sizeof (dm_descriptor_t));
1237  	if (da == NULL) {
1238  	    *errp = ENOMEM;
1239  	    return (NULL);
1240  	}
1241  
1242  	for (i = 0; ptrs[i]; i++) {
1243  	    da[i] = (uintptr_t)ptrs[i];
1244  	}
1245  	*errp = 0;
1246  	free(ptrs);
1247  
1248  	return (da);
1249  #endif
1250  }
1251  /*
1252   * Build the usage string for the in use data. Return the build string in
1253   * the msg parameter. This function takes care of reallocing all the memory
1254   * for this usage string. Usage string is returned already formatted for
1255   * localization.
1256   */
1257  static int
1258  build_usage_string(char *dname, char *by, char *data, char **msg,
1259      int *found, int *errp)
1260  {
1261  	int	len0;
1262  	int	len1;
1263  	char	*use;
1264  	char	*p;
1265  
1266  	*errp = 0;
1267  
1268  	dm_get_usage_string(by, data, &use);
1269  	if (!use) {
1270  		return (-1);
1271  	}
1272  
1273  	if (*msg)
1274  		len0 = strlen(*msg);
1275  	else
1276  		len0 = 0;
1277  	/* LINTED */
1278  	len1 = snprintf(NULL, 0, use, dname, data);
1279  
1280  	/*
1281  	 * If multiple in use details they
1282  	 * are listed 1 per line for ease of
1283  	 * reading. dm_find_usage_string
1284  	 * formats these appropriately.
1285  	 */
1286  	if ((p = realloc(*msg, len0 + len1 + 1)) == NULL) {
1287  		*errp = errno;
1288  		free(*msg);
1289  		return (-1);
1290  	}
1291  	*msg = p;
1292  
1293  	/* LINTED */
1294  	(void) snprintf(*msg + len0, len1 + 1, use, dname, data);
1295  	(*found)++;
1296  	return (0);
1297  }
1298