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 https://opensource.org/licenses/CDDL-1.0.
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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/nvpair.h>
30 #include <sys/fs/zfs.h>
31 #include <math.h>
32 
33 #include <libzutil.h>
34 
35 static void
36 dump_ddt_stat(const ddt_stat_t *dds, int h)
37 {
38 	char refcnt[6];
39 	char blocks[6], lsize[6], psize[6], dsize[6];
40 	char ref_blocks[6], ref_lsize[6], ref_psize[6], ref_dsize[6];
41 
42 	if (dds == NULL || dds->dds_blocks == 0)
43 		return;
44 
45 	if (h == -1)
46 		(void) strcpy(refcnt, "Total");
47 	else
48 		zfs_nicenum(1ULL << h, refcnt, sizeof (refcnt));
49 
50 	zfs_nicenum(dds->dds_blocks, blocks, sizeof (blocks));
51 	zfs_nicebytes(dds->dds_lsize, lsize, sizeof (lsize));
52 	zfs_nicebytes(dds->dds_psize, psize, sizeof (psize));
53 	zfs_nicebytes(dds->dds_dsize, dsize, sizeof (dsize));
54 	zfs_nicenum(dds->dds_ref_blocks, ref_blocks, sizeof (ref_blocks));
55 	zfs_nicebytes(dds->dds_ref_lsize, ref_lsize, sizeof (ref_lsize));
56 	zfs_nicebytes(dds->dds_ref_psize, ref_psize, sizeof (ref_psize));
57 	zfs_nicebytes(dds->dds_ref_dsize, ref_dsize, sizeof (ref_dsize));
58 
59 	(void) printf("%6s   %6s   %5s   %5s   %5s   %6s   %5s   %5s   %5s\n",
60 	    refcnt,
61 	    blocks, lsize, psize, dsize,
62 	    ref_blocks, ref_lsize, ref_psize, ref_dsize);
63 }
64 
65 /*
66  * Print the DDT histogram and the column totals.
67  */
68 void
69 zpool_dump_ddt(const ddt_stat_t *dds_total, const ddt_histogram_t *ddh)
70 {
71 	int h;
72 
73 	(void) printf("\n");
74 
75 	(void) printf("bucket   "
76 	    "           allocated             "
77 	    "          referenced          \n");
78 	(void) printf("______   "
79 	    "______________________________   "
80 	    "______________________________\n");
81 
82 	(void) printf("%6s   %6s   %5s   %5s   %5s   %6s   %5s   %5s   %5s\n",
83 	    "refcnt",
84 	    "blocks", "LSIZE", "PSIZE", "DSIZE",
85 	    "blocks", "LSIZE", "PSIZE", "DSIZE");
86 
87 	(void) printf("%6s   %6s   %5s   %5s   %5s   %6s   %5s   %5s   %5s\n",
88 	    "------",
89 	    "------", "-----", "-----", "-----",
90 	    "------", "-----", "-----", "-----");
91 
92 	for (h = 0; h < 64; h++)
93 		dump_ddt_stat(&ddh->ddh_stat[h], h);
94 
95 	dump_ddt_stat(dds_total, -1);
96 
97 	(void) printf("\n");
98 }
99 
100 /*
101  * Process the buffer of nvlists, unpacking and storing each nvlist record
102  * into 'records'.  'leftover' is set to the number of bytes that weren't
103  * processed as there wasn't a complete record.
104  */
105 int
106 zpool_history_unpack(char *buf, uint64_t bytes_read, uint64_t *leftover,
107     nvlist_t ***records, uint_t *numrecords)
108 {
109 	uint64_t reclen;
110 	nvlist_t *nv;
111 	int i;
112 	void *tmp;
113 
114 	while (bytes_read > sizeof (reclen)) {
115 
116 		/* get length of packed record (stored as little endian) */
117 		for (i = 0, reclen = 0; i < sizeof (reclen); i++)
118 			reclen += (uint64_t)(((uchar_t *)buf)[i]) << (8*i);
119 
120 		if (bytes_read < sizeof (reclen) + reclen)
121 			break;
122 
123 		/* unpack record */
124 		int err = nvlist_unpack(buf + sizeof (reclen), reclen, &nv, 0);
125 		if (err != 0)
126 			return (err);
127 		bytes_read -= sizeof (reclen) + reclen;
128 		buf += sizeof (reclen) + reclen;
129 
130 		/* add record to nvlist array */
131 		(*numrecords)++;
132 		if (ISP2(*numrecords + 1)) {
133 			tmp = realloc(*records,
134 			    *numrecords * 2 * sizeof (nvlist_t *));
135 			if (tmp == NULL) {
136 				nvlist_free(nv);
137 				(*numrecords)--;
138 				return (ENOMEM);
139 			}
140 			*records = tmp;
141 		}
142 		(*records)[*numrecords - 1] = nv;
143 	}
144 
145 	*leftover = bytes_read;
146 	return (0);
147 }
148 
149 /*
150  * Floating point sleep().  Allows you to pass in a floating point value for
151  * seconds.
152  */
153 void
154 fsleep(float sec)
155 {
156 	struct timespec req;
157 	req.tv_sec = floor(sec);
158 	req.tv_nsec = (sec - (float)req.tv_sec) * NANOSEC;
159 	nanosleep(&req, NULL);
160 }
161 
162 /*
163  * Get environment variable 'env' and return it as an integer.
164  * If 'env' is not set, then return 'default_val' instead.
165  */
166 int
167 zpool_getenv_int(const char *env, int default_val)
168 {
169 	char *str;
170 	int val;
171 	str = getenv(env);
172 	if ((str == NULL) || sscanf(str, "%d", &val) != 1 ||
173 	    val < 0) {
174 		val = default_val;
175 	}
176 	return (val);
177 }
178