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