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