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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Internal utility routines for the ZFS library.
31  */
32 
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <libintl.h>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <strings.h>
40 #include <unistd.h>
41 #include <sys/mnttab.h>
42 
43 #include <libzfs.h>
44 
45 #include "libzfs_impl.h"
46 
47 int zfs_fd;
48 
49 void (*error_func)(const char *, va_list);
50 
51 /*
52  * All error handling is kept within libzfs where we have the most information
53  * immediately available.  While this may not be suitable for a general purpose
54  * library, it greatly simplifies our commands.  This command name is used to
55  * prefix all error messages appropriately.
56  */
57 void
58 zfs_error(const char *fmt, ...)
59 {
60 	va_list ap;
61 
62 	va_start(ap, fmt);
63 
64 	if (error_func != NULL) {
65 		error_func(fmt, ap);
66 	} else {
67 		(void) vfprintf(stderr, fmt, ap);
68 		(void) fprintf(stderr, "\n");
69 	}
70 
71 	va_end(ap);
72 }
73 
74 /*
75  * An internal error is something that we cannot recover from, and should never
76  * happen (such as running out of memory).  It should only be used in
77  * exceptional circumstances.
78  */
79 void
80 zfs_fatal(const char *fmt, ...)
81 {
82 	va_list ap;
83 
84 	va_start(ap, fmt);
85 
86 	if (error_func != NULL) {
87 		error_func(fmt, ap);
88 	} else {
89 		(void) vfprintf(stderr, fmt, ap);
90 		(void) fprintf(stderr, "\n");
91 	}
92 
93 	va_end(ap);
94 
95 	exit(1);
96 }
97 
98 /*
99  * Consumers (such as the JNI interface) that need to capture error output can
100  * override the default error handler using this function.
101  */
102 void
103 zfs_set_error_handler(void (*func)(const char *, va_list))
104 {
105 	error_func = func;
106 }
107 
108 /*
109  * Display an out of memory error message and abort the current program.
110  */
111 void
112 no_memory(void)
113 {
114 	assert(errno == ENOMEM);
115 	zfs_fatal(dgettext(TEXT_DOMAIN, "internal error: out of memory\n"));
116 }
117 
118 /*
119  * A safe form of malloc() which will die if the allocation fails.
120  */
121 void *
122 zfs_malloc(size_t size)
123 {
124 	void *data;
125 
126 	if ((data = calloc(1, size)) == NULL)
127 		no_memory();
128 
129 	return (data);
130 }
131 
132 /*
133  * A safe form of strdup() which will die if the allocation fails.
134  */
135 char *
136 zfs_strdup(const char *str)
137 {
138 	char *ret;
139 
140 	if ((ret = strdup(str)) == NULL)
141 		no_memory();
142 
143 	return (ret);
144 }
145 
146 /*
147  * Initialize the library.  Sets the command name used when reporting errors.
148  * This command name is used to prefix all error messages appropriately.
149  * Also opens /dev/zfs and dies if it cannot be opened.
150  */
151 #pragma init(zfs_init)
152 void
153 zfs_init(void)
154 {
155 	if ((zfs_fd = open(ZFS_DEV, O_RDWR)) < 0)
156 		zfs_fatal(dgettext(TEXT_DOMAIN,
157 		    "internal error: cannot open zfs device"));
158 
159 	if ((mnttab_file = fopen(MNTTAB, "r")) == NULL)
160 		zfs_fatal(dgettext(TEXT_DOMAIN, "internal error: unable to "
161 		    "open %s\n"), MNTTAB);
162 
163 	sharetab_file = fopen("/etc/dfs/sharetab", "r");
164 }
165 
166 /*
167  * Cleanup function for library.  Simply close the file descriptors that we
168  * opened as part of libzfs_init().
169  */
170 #pragma fini(zfs_fini)
171 void
172 zfs_fini(void)
173 {
174 	(void) close(zfs_fd);
175 }
176 
177 /*
178  * Convert a number to an appropriately human-readable output.
179  */
180 void
181 zfs_nicenum(uint64_t num, char *buf, size_t buflen)
182 {
183 	uint64_t n = num;
184 	int index = 0;
185 	char u;
186 
187 	while (n >= 1024) {
188 		n /= 1024;
189 		index++;
190 	}
191 
192 	u = " KMGTPE"[index];
193 
194 	if (index == 0) {
195 		(void) snprintf(buf, buflen, "%llu", n);
196 	} else if ((num & ((1ULL << 10 * index) - 1)) == 0) {
197 		/*
198 		 * If this is an even multiple of the base, always display
199 		 * without any decimal precision.
200 		 */
201 		(void) snprintf(buf, buflen, "%llu%c", n, u);
202 	} else {
203 		/*
204 		 * We want to choose a precision that reflects the best choice
205 		 * for fitting in 5 characters.  This can get rather tricky when
206 		 * we have numbers that are very close to an order of magnitude.
207 		 * For example, when displaying 10239 (which is really 9.999K),
208 		 * we want only a single place of precision for 10.0K.  We could
209 		 * develop some complex heuristics for this, but it's much
210 		 * easier just to try each combination in turn.
211 		 */
212 		int i;
213 		for (i = 2; i >= 0; i--) {
214 			(void) snprintf(buf, buflen, "%.*f%c", i,
215 			    (double)num / (1ULL << 10 * index), u);
216 			if (strlen(buf) <= 5)
217 				break;
218 		}
219 	}
220 }
221