xref: /minix3/bin/dd/misc.c (revision c19d619d42588dfcfbd5c23c7290d975d0294e65)
1*c19d619dSJacob Adams /*	$NetBSD: misc.c,v 1.23 2011/11/07 22:24:23 jym Exp $	*/
2*c19d619dSJacob Adams 
3*c19d619dSJacob Adams /*-
4*c19d619dSJacob Adams  * Copyright (c) 1991, 1993, 1994
5*c19d619dSJacob Adams  *	The Regents of the University of California.  All rights reserved.
6*c19d619dSJacob Adams  *
7*c19d619dSJacob Adams  * This code is derived from software contributed to Berkeley by
8*c19d619dSJacob Adams  * Keith Muller of the University of California, San Diego and Lance
9*c19d619dSJacob Adams  * Visser of Convex Computer Corporation.
10*c19d619dSJacob Adams  *
11*c19d619dSJacob Adams  * Redistribution and use in source and binary forms, with or without
12*c19d619dSJacob Adams  * modification, are permitted provided that the following conditions
13*c19d619dSJacob Adams  * are met:
14*c19d619dSJacob Adams  * 1. Redistributions of source code must retain the above copyright
15*c19d619dSJacob Adams  *    notice, this list of conditions and the following disclaimer.
16*c19d619dSJacob Adams  * 2. Redistributions in binary form must reproduce the above copyright
17*c19d619dSJacob Adams  *    notice, this list of conditions and the following disclaimer in the
18*c19d619dSJacob Adams  *    documentation and/or other materials provided with the distribution.
19*c19d619dSJacob Adams  * 3. Neither the name of the University nor the names of its contributors
20*c19d619dSJacob Adams  *    may be used to endorse or promote products derived from this software
21*c19d619dSJacob Adams  *    without specific prior written permission.
22*c19d619dSJacob Adams  *
23*c19d619dSJacob Adams  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24*c19d619dSJacob Adams  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25*c19d619dSJacob Adams  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26*c19d619dSJacob Adams  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27*c19d619dSJacob Adams  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28*c19d619dSJacob Adams  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29*c19d619dSJacob Adams  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30*c19d619dSJacob Adams  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31*c19d619dSJacob Adams  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32*c19d619dSJacob Adams  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33*c19d619dSJacob Adams  * SUCH DAMAGE.
34*c19d619dSJacob Adams  */
35*c19d619dSJacob Adams 
36*c19d619dSJacob Adams #include <sys/cdefs.h>
37*c19d619dSJacob Adams #ifndef lint
38*c19d619dSJacob Adams #if 0
39*c19d619dSJacob Adams static char sccsid[] = "@(#)misc.c	8.3 (Berkeley) 4/2/94";
40*c19d619dSJacob Adams #else
41*c19d619dSJacob Adams __RCSID("$NetBSD: misc.c,v 1.23 2011/11/07 22:24:23 jym Exp $");
42*c19d619dSJacob Adams #endif
43*c19d619dSJacob Adams #endif /* not lint */
44*c19d619dSJacob Adams 
45*c19d619dSJacob Adams #include <sys/param.h>
46*c19d619dSJacob Adams #include <sys/types.h>
47*c19d619dSJacob Adams #include <sys/time.h>
48*c19d619dSJacob Adams 
49*c19d619dSJacob Adams #include <err.h>
50*c19d619dSJacob Adams #include <stdio.h>
51*c19d619dSJacob Adams #include <stdlib.h>
52*c19d619dSJacob Adams #include <string.h>
53*c19d619dSJacob Adams #include <unistd.h>
54*c19d619dSJacob Adams #include <util.h>
55*c19d619dSJacob Adams #include <inttypes.h>
56*c19d619dSJacob Adams 
57*c19d619dSJacob Adams #include "dd.h"
58*c19d619dSJacob Adams #include "extern.h"
59*c19d619dSJacob Adams 
60*c19d619dSJacob Adams #define	tv2mS(tv) ((tv).tv_sec * 1000LL + ((tv).tv_usec + 500) / 1000)
61*c19d619dSJacob Adams 
62*c19d619dSJacob Adams static void posix_summary(void);
63*c19d619dSJacob Adams #ifndef NO_MSGFMT
64*c19d619dSJacob Adams static void custom_summary(void);
65*c19d619dSJacob Adams static void human_summary(void);
66*c19d619dSJacob Adams static void quiet_summary(void);
67*c19d619dSJacob Adams 
68*c19d619dSJacob Adams static void buffer_write(const char *, size_t, int);
69*c19d619dSJacob Adams #endif /* NO_MSGFMT */
70*c19d619dSJacob Adams 
71*c19d619dSJacob Adams void
summary(void)72*c19d619dSJacob Adams summary(void)
73*c19d619dSJacob Adams {
74*c19d619dSJacob Adams 
75*c19d619dSJacob Adams 	if (progress)
76*c19d619dSJacob Adams 		(void)write(STDERR_FILENO, "\n", 1);
77*c19d619dSJacob Adams 
78*c19d619dSJacob Adams #ifdef NO_MSGFMT
79*c19d619dSJacob Adams 	return posix_summary();
80*c19d619dSJacob Adams #else /* NO_MSGFMT */
81*c19d619dSJacob Adams 	if (strncmp(msgfmt, "human", sizeof("human")) == 0)
82*c19d619dSJacob Adams 		return human_summary();
83*c19d619dSJacob Adams 
84*c19d619dSJacob Adams 	if (strncmp(msgfmt, "posix", sizeof("posix")) == 0)
85*c19d619dSJacob Adams 		return posix_summary();
86*c19d619dSJacob Adams 
87*c19d619dSJacob Adams 	if (strncmp(msgfmt, "quiet", sizeof("quiet")) == 0)
88*c19d619dSJacob Adams 		return quiet_summary();
89*c19d619dSJacob Adams 
90*c19d619dSJacob Adams 	return custom_summary();
91*c19d619dSJacob Adams #endif /* NO_MSGFMT */
92*c19d619dSJacob Adams }
93*c19d619dSJacob Adams 
94*c19d619dSJacob Adams static void
posix_summary(void)95*c19d619dSJacob Adams posix_summary(void)
96*c19d619dSJacob Adams {
97*c19d619dSJacob Adams 	char buf[100];
98*c19d619dSJacob Adams 	int64_t mS;
99*c19d619dSJacob Adams 	struct timeval tv;
100*c19d619dSJacob Adams 
101*c19d619dSJacob Adams 	if (progress)
102*c19d619dSJacob Adams 		(void)write(STDERR_FILENO, "\n", 1);
103*c19d619dSJacob Adams 
104*c19d619dSJacob Adams 	(void)gettimeofday(&tv, NULL);
105*c19d619dSJacob Adams 	mS = tv2mS(tv) - tv2mS(st.start);
106*c19d619dSJacob Adams 	if (mS == 0)
107*c19d619dSJacob Adams 		mS = 1;
108*c19d619dSJacob Adams 
109*c19d619dSJacob Adams 	/* Use snprintf(3) so that we don't reenter stdio(3). */
110*c19d619dSJacob Adams 	(void)snprintf(buf, sizeof(buf),
111*c19d619dSJacob Adams 	    "%llu+%llu records in\n%llu+%llu records out\n",
112*c19d619dSJacob Adams 	    (unsigned long long)st.in_full,  (unsigned long long)st.in_part,
113*c19d619dSJacob Adams 	    (unsigned long long)st.out_full, (unsigned long long)st.out_part);
114*c19d619dSJacob Adams 	(void)write(STDERR_FILENO, buf, strlen(buf));
115*c19d619dSJacob Adams 	if (st.swab) {
116*c19d619dSJacob Adams 		(void)snprintf(buf, sizeof(buf), "%llu odd length swab %s\n",
117*c19d619dSJacob Adams 		    (unsigned long long)st.swab,
118*c19d619dSJacob Adams 		    (st.swab == 1) ? "block" : "blocks");
119*c19d619dSJacob Adams 		(void)write(STDERR_FILENO, buf, strlen(buf));
120*c19d619dSJacob Adams 	}
121*c19d619dSJacob Adams 	if (st.trunc) {
122*c19d619dSJacob Adams 		(void)snprintf(buf, sizeof(buf), "%llu truncated %s\n",
123*c19d619dSJacob Adams 		    (unsigned long long)st.trunc,
124*c19d619dSJacob Adams 		    (st.trunc == 1) ? "block" : "blocks");
125*c19d619dSJacob Adams 		(void)write(STDERR_FILENO, buf, strlen(buf));
126*c19d619dSJacob Adams 	}
127*c19d619dSJacob Adams 	if (st.sparse) {
128*c19d619dSJacob Adams 		(void)snprintf(buf, sizeof(buf), "%llu sparse output %s\n",
129*c19d619dSJacob Adams 		    (unsigned long long)st.sparse,
130*c19d619dSJacob Adams 		    (st.sparse == 1) ? "block" : "blocks");
131*c19d619dSJacob Adams 		(void)write(STDERR_FILENO, buf, strlen(buf));
132*c19d619dSJacob Adams 	}
133*c19d619dSJacob Adams 	(void)snprintf(buf, sizeof(buf),
134*c19d619dSJacob Adams 	    "%llu bytes transferred in %lu.%03d secs (%llu bytes/sec)\n",
135*c19d619dSJacob Adams 	    (unsigned long long) st.bytes,
136*c19d619dSJacob Adams 	    (long) (mS / 1000),
137*c19d619dSJacob Adams 	    (int) (mS % 1000),
138*c19d619dSJacob Adams 	    (unsigned long long) (st.bytes * 1000LL / mS));
139*c19d619dSJacob Adams 	(void)write(STDERR_FILENO, buf, strlen(buf));
140*c19d619dSJacob Adams }
141*c19d619dSJacob Adams 
142*c19d619dSJacob Adams /* ARGSUSED */
143*c19d619dSJacob Adams void
summaryx(int notused)144*c19d619dSJacob Adams summaryx(int notused)
145*c19d619dSJacob Adams {
146*c19d619dSJacob Adams 
147*c19d619dSJacob Adams 	summary();
148*c19d619dSJacob Adams }
149*c19d619dSJacob Adams 
150*c19d619dSJacob Adams /* ARGSUSED */
151*c19d619dSJacob Adams void
terminate(int signo)152*c19d619dSJacob Adams terminate(int signo)
153*c19d619dSJacob Adams {
154*c19d619dSJacob Adams 
155*c19d619dSJacob Adams 	summary();
156*c19d619dSJacob Adams 	(void)raise_default_signal(signo);
157*c19d619dSJacob Adams 	_exit(127);
158*c19d619dSJacob Adams }
159*c19d619dSJacob Adams 
160*c19d619dSJacob Adams #ifndef NO_MSGFMT
161*c19d619dSJacob Adams /*
162*c19d619dSJacob Adams  * Buffer write(2) calls
163*c19d619dSJacob Adams  */
164*c19d619dSJacob Adams static void
buffer_write(const char * str,size_t size,int flush)165*c19d619dSJacob Adams buffer_write(const char *str, size_t size, int flush)
166*c19d619dSJacob Adams {
167*c19d619dSJacob Adams 	static char wbuf[128];
168*c19d619dSJacob Adams 	static size_t cnt = 0; /* Internal counter to allow wbuf to wrap */
169*c19d619dSJacob Adams 
170*c19d619dSJacob Adams 	unsigned int i;
171*c19d619dSJacob Adams 
172*c19d619dSJacob Adams 	for (i = 0; i < size; i++) {
173*c19d619dSJacob Adams 		if (str != NULL) {
174*c19d619dSJacob Adams 			wbuf[cnt++] = str[i];
175*c19d619dSJacob Adams 		}
176*c19d619dSJacob Adams 		if (cnt >= sizeof(wbuf)) {
177*c19d619dSJacob Adams 			(void)write(STDERR_FILENO, wbuf, cnt);
178*c19d619dSJacob Adams 			cnt = 0;
179*c19d619dSJacob Adams 		}
180*c19d619dSJacob Adams 	}
181*c19d619dSJacob Adams 
182*c19d619dSJacob Adams 	if (flush != 0) {
183*c19d619dSJacob Adams 		(void)write(STDERR_FILENO, wbuf, cnt);
184*c19d619dSJacob Adams 		cnt = 0;
185*c19d619dSJacob Adams 	}
186*c19d619dSJacob Adams }
187*c19d619dSJacob Adams 
188*c19d619dSJacob Adams /*
189*c19d619dSJacob Adams  * Write summary to stderr according to format 'fmt'. If 'enable' is 0, it
190*c19d619dSJacob Adams  * will not attempt to write anything. Can be used to validate the
191*c19d619dSJacob Adams  * correctness of the 'fmt' string.
192*c19d619dSJacob Adams  */
193*c19d619dSJacob Adams int
dd_write_msg(const char * fmt,int enable)194*c19d619dSJacob Adams dd_write_msg(const char *fmt, int enable)
195*c19d619dSJacob Adams {
196*c19d619dSJacob Adams 	char hbuf[7], nbuf[32];
197*c19d619dSJacob Adams 	const char *ptr;
198*c19d619dSJacob Adams 	int64_t mS;
199*c19d619dSJacob Adams 	struct timeval tv;
200*c19d619dSJacob Adams 
201*c19d619dSJacob Adams 	(void)gettimeofday(&tv, NULL);
202*c19d619dSJacob Adams 	mS = tv2mS(tv) - tv2mS(st.start);
203*c19d619dSJacob Adams 	if (mS == 0)
204*c19d619dSJacob Adams 		mS = 1;
205*c19d619dSJacob Adams 
206*c19d619dSJacob Adams #define ADDC(c) do { if (enable != 0) buffer_write(&c, 1, 0); } \
207*c19d619dSJacob Adams 	while (/*CONSTCOND*/0)
208*c19d619dSJacob Adams #define ADDS(p) do { if (enable != 0) buffer_write(p, strlen(p), 0); } \
209*c19d619dSJacob Adams 	while (/*CONSTCOND*/0)
210*c19d619dSJacob Adams 
211*c19d619dSJacob Adams 	for (ptr = fmt; *ptr; ptr++) {
212*c19d619dSJacob Adams 		if (*ptr != '%') {
213*c19d619dSJacob Adams 			ADDC(*ptr);
214*c19d619dSJacob Adams 			continue;
215*c19d619dSJacob Adams 		}
216*c19d619dSJacob Adams 
217*c19d619dSJacob Adams  		switch (*++ptr) {
218*c19d619dSJacob Adams 		case 'b':
219*c19d619dSJacob Adams 			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
220*c19d619dSJacob Adams 			    (unsigned long long)st.bytes);
221*c19d619dSJacob Adams 			ADDS(nbuf);
222*c19d619dSJacob Adams 			break;
223*c19d619dSJacob Adams 		case 'B':
224*c19d619dSJacob Adams 			if (humanize_number(hbuf, sizeof(hbuf),
225*c19d619dSJacob Adams 			    st.bytes, "B",
226*c19d619dSJacob Adams 			    HN_AUTOSCALE, HN_DECIMAL) == -1)
227*c19d619dSJacob Adams 				warnx("humanize_number (bytes transferred)");
228*c19d619dSJacob Adams 			ADDS(hbuf);
229*c19d619dSJacob Adams 			break;
230*c19d619dSJacob Adams 		case 'e':
231*c19d619dSJacob Adams 			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
232*c19d619dSJacob Adams 			    (unsigned long long) (st.bytes * 1000LL / mS));
233*c19d619dSJacob Adams 			ADDS(nbuf);
234*c19d619dSJacob Adams 			break;
235*c19d619dSJacob Adams 		case 'E':
236*c19d619dSJacob Adams 			if (humanize_number(hbuf, sizeof(hbuf),
237*c19d619dSJacob Adams 			    st.bytes * 1000LL / mS, "B",
238*c19d619dSJacob Adams 			    HN_AUTOSCALE, HN_DECIMAL) == -1)
239*c19d619dSJacob Adams 				warnx("humanize_number (bytes per second)");
240*c19d619dSJacob Adams 			ADDS(hbuf); ADDS("/sec");
241*c19d619dSJacob Adams 			break;
242*c19d619dSJacob Adams 		case 'i':
243*c19d619dSJacob Adams 			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
244*c19d619dSJacob Adams 			    (unsigned long long)st.in_part);
245*c19d619dSJacob Adams 			ADDS(nbuf);
246*c19d619dSJacob Adams 			break;
247*c19d619dSJacob Adams 		case 'I':
248*c19d619dSJacob Adams 			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
249*c19d619dSJacob Adams 			    (unsigned long long)st.in_full);
250*c19d619dSJacob Adams 			ADDS(nbuf);
251*c19d619dSJacob Adams 			break;
252*c19d619dSJacob Adams 		case 'o':
253*c19d619dSJacob Adams 			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
254*c19d619dSJacob Adams 			    (unsigned long long)st.out_part);
255*c19d619dSJacob Adams 			ADDS(nbuf);
256*c19d619dSJacob Adams 			break;
257*c19d619dSJacob Adams 		case 'O':
258*c19d619dSJacob Adams 			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
259*c19d619dSJacob Adams 			    (unsigned long long)st.out_full);
260*c19d619dSJacob Adams 			ADDS(nbuf);
261*c19d619dSJacob Adams 			break;
262*c19d619dSJacob Adams 		case 's':
263*c19d619dSJacob Adams 			(void)snprintf(nbuf, sizeof(nbuf), "%li.%03d",
264*c19d619dSJacob Adams 			    (long) (mS / 1000), (int) (mS % 1000));
265*c19d619dSJacob Adams 			ADDS(nbuf);
266*c19d619dSJacob Adams 			break;
267*c19d619dSJacob Adams 		case 'p':
268*c19d619dSJacob Adams 			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
269*c19d619dSJacob Adams 			    (unsigned long long)st.sparse);
270*c19d619dSJacob Adams 			ADDS(nbuf);
271*c19d619dSJacob Adams 			break;
272*c19d619dSJacob Adams 		case 't':
273*c19d619dSJacob Adams 			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
274*c19d619dSJacob Adams 			    (unsigned long long)st.trunc);
275*c19d619dSJacob Adams 			ADDS(nbuf);
276*c19d619dSJacob Adams 			break;
277*c19d619dSJacob Adams 		case 'w':
278*c19d619dSJacob Adams 			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
279*c19d619dSJacob Adams 			    (unsigned long long)st.swab);
280*c19d619dSJacob Adams 			ADDS(nbuf);
281*c19d619dSJacob Adams 			break;
282*c19d619dSJacob Adams 		case 'P':
283*c19d619dSJacob Adams 			ADDS("block");
284*c19d619dSJacob Adams 			if (st.sparse != 1) ADDS("s");
285*c19d619dSJacob Adams 			break;
286*c19d619dSJacob Adams 		case 'T':
287*c19d619dSJacob Adams 			ADDS("block");
288*c19d619dSJacob Adams 			if (st.trunc != 1) ADDS("s");
289*c19d619dSJacob Adams 			break;
290*c19d619dSJacob Adams 		case 'W':
291*c19d619dSJacob Adams 			ADDS("block");
292*c19d619dSJacob Adams 			if (st.swab != 1) ADDS("s");
293*c19d619dSJacob Adams 			break;
294*c19d619dSJacob Adams 		case '%':
295*c19d619dSJacob Adams 			ADDC(*ptr);
296*c19d619dSJacob Adams 			break;
297*c19d619dSJacob Adams 		default:
298*c19d619dSJacob Adams 			if (*ptr == '\0')
299*c19d619dSJacob Adams 				goto done;
300*c19d619dSJacob Adams 			errx(EXIT_FAILURE, "unknown specifier '%c' in "
301*c19d619dSJacob Adams 			    "msgfmt string", *ptr);
302*c19d619dSJacob Adams 			/* NOTREACHED */
303*c19d619dSJacob Adams 		}
304*c19d619dSJacob Adams 	}
305*c19d619dSJacob Adams 
306*c19d619dSJacob Adams done:
307*c19d619dSJacob Adams 	/* flush buffer */
308*c19d619dSJacob Adams 	buffer_write(NULL, 0, 1);
309*c19d619dSJacob Adams 	return 0;
310*c19d619dSJacob Adams }
311*c19d619dSJacob Adams 
312*c19d619dSJacob Adams static void
custom_summary(void)313*c19d619dSJacob Adams custom_summary(void)
314*c19d619dSJacob Adams {
315*c19d619dSJacob Adams 
316*c19d619dSJacob Adams 	dd_write_msg(msgfmt, 1);
317*c19d619dSJacob Adams }
318*c19d619dSJacob Adams 
319*c19d619dSJacob Adams static void
human_summary(void)320*c19d619dSJacob Adams human_summary(void)
321*c19d619dSJacob Adams {
322*c19d619dSJacob Adams 	(void)dd_write_msg("%I+%i records in\n%O+%o records out\n", 1);
323*c19d619dSJacob Adams 	if (st.swab) {
324*c19d619dSJacob Adams 		(void)dd_write_msg("%w odd length swab %W\n", 1);
325*c19d619dSJacob Adams 	}
326*c19d619dSJacob Adams 	if (st.trunc) {
327*c19d619dSJacob Adams 		(void)dd_write_msg("%t truncated %T\n", 1);
328*c19d619dSJacob Adams 	}
329*c19d619dSJacob Adams 	if (st.sparse) {
330*c19d619dSJacob Adams 		(void)dd_write_msg("%p sparse output %P\n", 1);
331*c19d619dSJacob Adams 	}
332*c19d619dSJacob Adams 	(void)dd_write_msg("%b bytes (%B) transferred in %s secs "
333*c19d619dSJacob Adams 	    "(%e bytes/sec - %E)\n", 1);
334*c19d619dSJacob Adams }
335*c19d619dSJacob Adams 
336*c19d619dSJacob Adams static void
quiet_summary(void)337*c19d619dSJacob Adams quiet_summary(void)
338*c19d619dSJacob Adams {
339*c19d619dSJacob Adams 
340*c19d619dSJacob Adams 	/* stay quiet */
341*c19d619dSJacob Adams }
342*c19d619dSJacob Adams #endif /* NO_MSGFMT */
343