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