xref: /illumos-gate/usr/src/lib/libzfs/common/libzfs_util.c (revision f94c602698937f2fc025056c894e5a769f39d8fe)
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 2006 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 /*
29  * Internal utility routines for the ZFS library.
30  */
31 
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <libintl.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <strings.h>
39 #include <unistd.h>
40 #include <sys/mnttab.h>
41 
42 #include <libzfs.h>
43 
44 #include "libzfs_impl.h"
45 
46 static int zfs_fd = -1;
47 static FILE *mnttab_file;
48 static FILE *sharetab_file;
49 static int sharetab_opened;
50 
51 void (*error_func)(const char *, va_list);
52 
53 /*
54  * All error handling is kept within libzfs where we have the most information
55  * immediately available.  While this may not be suitable for a general purpose
56  * library, it greatly simplifies our commands.  This command name is used to
57  * prefix all error messages appropriately.
58  */
59 void
60 zfs_error(const char *fmt, ...)
61 {
62 	va_list ap;
63 
64 	va_start(ap, fmt);
65 
66 	if (error_func != NULL) {
67 		error_func(fmt, ap);
68 	} else {
69 		(void) vfprintf(stderr, fmt, ap);
70 		(void) fprintf(stderr, "\n");
71 	}
72 
73 	va_end(ap);
74 }
75 
76 /*
77  * An internal error is something that we cannot recover from, and should never
78  * happen (such as running out of memory).  It should only be used in
79  * exceptional circumstances.
80  */
81 void
82 zfs_fatal(const char *fmt, ...)
83 {
84 	va_list ap;
85 
86 	va_start(ap, fmt);
87 
88 	if (error_func != NULL) {
89 		error_func(fmt, ap);
90 	} else {
91 		(void) vfprintf(stderr, fmt, ap);
92 		(void) fprintf(stderr, "\n");
93 	}
94 
95 	va_end(ap);
96 
97 	exit(1);
98 }
99 
100 /*
101  * Consumers (such as the JNI interface) that need to capture error output can
102  * override the default error handler using this function.
103  */
104 void
105 zfs_set_error_handler(void (*func)(const char *, va_list))
106 {
107 	error_func = func;
108 }
109 
110 /*
111  * Display an out of memory error message and abort the current program.
112  */
113 void
114 no_memory(void)
115 {
116 	assert(errno == ENOMEM);
117 	zfs_fatal(dgettext(TEXT_DOMAIN, "internal error: out of memory\n"));
118 }
119 
120 /*
121  * A safe form of malloc() which will die if the allocation fails.
122  */
123 void *
124 zfs_malloc(size_t size)
125 {
126 	void *data;
127 
128 	if ((data = calloc(1, size)) == NULL)
129 		no_memory();
130 
131 	return (data);
132 }
133 
134 /*
135  * A safe form of strdup() which will die if the allocation fails.
136  */
137 char *
138 zfs_strdup(const char *str)
139 {
140 	char *ret;
141 
142 	if ((ret = strdup(str)) == NULL)
143 		no_memory();
144 
145 	return (ret);
146 }
147 
148 /*
149  * Utility functions around common used files - /dev/zfs, /etc/mnttab, and
150  * /etc/dfs/sharetab.
151  */
152 int
153 zfs_ioctl(int cmd, zfs_cmd_t *zc)
154 {
155 	if (zfs_fd == -1 &&
156 	    (zfs_fd = open(ZFS_DEV, O_RDWR)) < 0)
157 		zfs_fatal(dgettext(TEXT_DOMAIN, "internal error: unable to "
158 		    "open ZFS device\n"), MNTTAB);
159 
160 	return (ioctl(zfs_fd, cmd, zc));
161 }
162 
163 FILE *
164 zfs_mnttab(void)
165 {
166 	if (mnttab_file == NULL &&
167 	    (mnttab_file = fopen(MNTTAB, "r")) == NULL)
168 		zfs_fatal(dgettext(TEXT_DOMAIN, "internal error: unable to "
169 		    "open %s\n"), MNTTAB);
170 
171 	return (mnttab_file);
172 }
173 
174 FILE *
175 zfs_sharetab(void)
176 {
177 	if (sharetab_opened)
178 		return (sharetab_file);
179 
180 	sharetab_opened = TRUE;
181 	return (sharetab_file = fopen("/etc/dfs/sharetab", "r"));
182 }
183 
184 /*
185  * Cleanup function for library.  Close any file descriptors that were
186  * opened as part of the above functions.
187  */
188 #pragma fini(zfs_fini)
189 void
190 zfs_fini(void)
191 {
192 	if (zfs_fd != -1)
193 		(void) close(zfs_fd);
194 	if (sharetab_file)
195 		(void) fclose(sharetab_file);
196 	if (mnttab_file)
197 		(void) fclose(mnttab_file);
198 }
199 
200 /*
201  * Convert a number to an appropriately human-readable output.
202  */
203 void
204 zfs_nicenum(uint64_t num, char *buf, size_t buflen)
205 {
206 	uint64_t n = num;
207 	int index = 0;
208 	char u;
209 
210 	while (n >= 1024) {
211 		n /= 1024;
212 		index++;
213 	}
214 
215 	u = " KMGTPE"[index];
216 
217 	if (index == 0) {
218 		(void) snprintf(buf, buflen, "%llu", n);
219 	} else if ((num & ((1ULL << 10 * index) - 1)) == 0) {
220 		/*
221 		 * If this is an even multiple of the base, always display
222 		 * without any decimal precision.
223 		 */
224 		(void) snprintf(buf, buflen, "%llu%c", n, u);
225 	} else {
226 		/*
227 		 * We want to choose a precision that reflects the best choice
228 		 * for fitting in 5 characters.  This can get rather tricky when
229 		 * we have numbers that are very close to an order of magnitude.
230 		 * For example, when displaying 10239 (which is really 9.999K),
231 		 * we want only a single place of precision for 10.0K.  We could
232 		 * develop some complex heuristics for this, but it's much
233 		 * easier just to try each combination in turn.
234 		 */
235 		int i;
236 		for (i = 2; i >= 0; i--) {
237 			(void) snprintf(buf, buflen, "%.*f%c", i,
238 			    (double)num / (1ULL << 10 * index), u);
239 			if (strlen(buf) <= 5)
240 				break;
241 		}
242 	}
243 }
244