xref: /netbsd-src/bin/dd/misc.c (revision 4cea8ecbb7a1609e0c56cde1bdccc6534838eb9f)
1*4cea8ecbSrillig /*	$NetBSD: misc.c,v 1.26 2021/10/09 20:44:55 rillig Exp $	*/
249f0ad86Scgd 
328bef396Sglass /*-
4667b5ea1Smycroft  * Copyright (c) 1991, 1993, 1994
5667b5ea1Smycroft  *	The Regents of the University of California.  All rights reserved.
628bef396Sglass  *
728bef396Sglass  * This code is derived from software contributed to Berkeley by
828bef396Sglass  * Keith Muller of the University of California, San Diego and Lance
928bef396Sglass  * Visser of Convex Computer Corporation.
1028bef396Sglass  *
1128bef396Sglass  * Redistribution and use in source and binary forms, with or without
1228bef396Sglass  * modification, are permitted provided that the following conditions
1328bef396Sglass  * are met:
1428bef396Sglass  * 1. Redistributions of source code must retain the above copyright
1528bef396Sglass  *    notice, this list of conditions and the following disclaimer.
1628bef396Sglass  * 2. Redistributions in binary form must reproduce the above copyright
1728bef396Sglass  *    notice, this list of conditions and the following disclaimer in the
1828bef396Sglass  *    documentation and/or other materials provided with the distribution.
19b5b29542Sagc  * 3. Neither the name of the University nor the names of its contributors
2028bef396Sglass  *    may be used to endorse or promote products derived from this software
2128bef396Sglass  *    without specific prior written permission.
2228bef396Sglass  *
2328bef396Sglass  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2428bef396Sglass  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2528bef396Sglass  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2628bef396Sglass  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2728bef396Sglass  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2828bef396Sglass  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2928bef396Sglass  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3028bef396Sglass  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3128bef396Sglass  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3228bef396Sglass  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3328bef396Sglass  * SUCH DAMAGE.
3428bef396Sglass  */
3528bef396Sglass 
364a3a58b6Schristos #include <sys/cdefs.h>
3728bef396Sglass #ifndef lint
3849f0ad86Scgd #if 0
3949f0ad86Scgd static char sccsid[] = "@(#)misc.c	8.3 (Berkeley) 4/2/94";
4049f0ad86Scgd #else
41*4cea8ecbSrillig __RCSID("$NetBSD: misc.c,v 1.26 2021/10/09 20:44:55 rillig Exp $");
4249f0ad86Scgd #endif
4328bef396Sglass #endif /* not lint */
4428bef396Sglass 
45458ed234Sjschauma #include <sys/param.h>
4628bef396Sglass #include <sys/types.h>
47aecbd4c4Sross #include <sys/time.h>
4828bef396Sglass 
49667b5ea1Smycroft #include <err.h>
5028bef396Sglass #include <stdio.h>
5128bef396Sglass #include <stdlib.h>
5228bef396Sglass #include <string.h>
5328bef396Sglass #include <unistd.h>
54db822d22Slukem #include <util.h>
55aecbd4c4Sross #include <inttypes.h>
5628bef396Sglass 
5728bef396Sglass #include "dd.h"
5828bef396Sglass #include "extern.h"
5928bef396Sglass 
60aecbd4c4Sross #define	tv2mS(tv) ((tv).tv_sec * 1000LL + ((tv).tv_usec + 500) / 1000)
61aecbd4c4Sross 
62234ccf06Sjym static void posix_summary(void);
63234ccf06Sjym #ifndef NO_MSGFMT
64234ccf06Sjym static void custom_summary(void);
65234ccf06Sjym static void human_summary(void);
66234ccf06Sjym static void quiet_summary(void);
67234ccf06Sjym 
68234ccf06Sjym static void buffer_write(const char *, size_t, int);
69234ccf06Sjym #endif /* NO_MSGFMT */
70234ccf06Sjym 
7128bef396Sglass void
summary(void)728605a1aaSlukem summary(void)
7328bef396Sglass {
74234ccf06Sjym 
75234ccf06Sjym 	if (progress)
76234ccf06Sjym 		(void)write(STDERR_FILENO, "\n", 1);
77234ccf06Sjym 
78234ccf06Sjym #ifdef NO_MSGFMT
792dcff222Srillig 	posix_summary();
80234ccf06Sjym #else /* NO_MSGFMT */
81*4cea8ecbSrillig 	if (strcmp(msgfmt, "human") == 0)
822dcff222Srillig 		human_summary();
83*4cea8ecbSrillig 	else if (strcmp(msgfmt, "posix") == 0)
842dcff222Srillig 		posix_summary();
85*4cea8ecbSrillig 	else if (strcmp(msgfmt, "quiet") == 0)
862dcff222Srillig 		quiet_summary();
872dcff222Srillig 	else
882dcff222Srillig 		custom_summary();
89234ccf06Sjym #endif /* NO_MSGFMT */
90234ccf06Sjym }
91234ccf06Sjym 
92234ccf06Sjym static void
posix_summary(void)93234ccf06Sjym posix_summary(void)
94234ccf06Sjym {
9528bef396Sglass 	char buf[100];
96aecbd4c4Sross 	int64_t mS;
97aecbd4c4Sross 	struct timeval tv;
9828bef396Sglass 
994d486ab6Shubertf 	if (progress)
1004d486ab6Shubertf 		(void)write(STDERR_FILENO, "\n", 1);
1014d486ab6Shubertf 
102aecbd4c4Sross 	(void)gettimeofday(&tv, NULL);
103aecbd4c4Sross 	mS = tv2mS(tv) - tv2mS(st.start);
104aecbd4c4Sross 	if (mS == 0)
105aecbd4c4Sross 		mS = 1;
106234ccf06Sjym 
10728bef396Sglass 	/* Use snprintf(3) so that we don't reenter stdio(3). */
10828bef396Sglass 	(void)snprintf(buf, sizeof(buf),
109b6ce735cSlukem 	    "%llu+%llu records in\n%llu+%llu records out\n",
110b6ce735cSlukem 	    (unsigned long long)st.in_full,  (unsigned long long)st.in_part,
111b6ce735cSlukem 	    (unsigned long long)st.out_full, (unsigned long long)st.out_part);
11228bef396Sglass 	(void)write(STDERR_FILENO, buf, strlen(buf));
11328bef396Sglass 	if (st.swab) {
114b6ce735cSlukem 		(void)snprintf(buf, sizeof(buf), "%llu odd length swab %s\n",
115b6ce735cSlukem 		    (unsigned long long)st.swab,
116b6ce735cSlukem 		    (st.swab == 1) ? "block" : "blocks");
11728bef396Sglass 		(void)write(STDERR_FILENO, buf, strlen(buf));
11828bef396Sglass 	}
11928bef396Sglass 	if (st.trunc) {
120b6ce735cSlukem 		(void)snprintf(buf, sizeof(buf), "%llu truncated %s\n",
121b6ce735cSlukem 		    (unsigned long long)st.trunc,
122b6ce735cSlukem 		    (st.trunc == 1) ? "block" : "blocks");
12328bef396Sglass 		(void)write(STDERR_FILENO, buf, strlen(buf));
12428bef396Sglass 	}
1256b493373Sdbj 	if (st.sparse) {
1266b493373Sdbj 		(void)snprintf(buf, sizeof(buf), "%llu sparse output %s\n",
1276b493373Sdbj 		    (unsigned long long)st.sparse,
1286b493373Sdbj 		    (st.sparse == 1) ? "block" : "blocks");
1296b493373Sdbj 		(void)write(STDERR_FILENO, buf, strlen(buf));
1306b493373Sdbj 	}
13128bef396Sglass 	(void)snprintf(buf, sizeof(buf),
132aecbd4c4Sross 	    "%llu bytes transferred in %lu.%03d secs (%llu bytes/sec)\n",
133b6ce735cSlukem 	    (unsigned long long) st.bytes,
134aecbd4c4Sross 	    (long) (mS / 1000),
135aecbd4c4Sross 	    (int) (mS % 1000),
136b6ce735cSlukem 	    (unsigned long long) (st.bytes * 1000LL / mS));
13728bef396Sglass 	(void)write(STDERR_FILENO, buf, strlen(buf));
13828bef396Sglass }
13928bef396Sglass 
14028bef396Sglass /* ARGSUSED */
14128bef396Sglass void
summaryx(int notused)1428605a1aaSlukem summaryx(int notused)
143667b5ea1Smycroft {
144667b5ea1Smycroft 
145667b5ea1Smycroft 	summary();
146667b5ea1Smycroft }
147667b5ea1Smycroft 
148667b5ea1Smycroft /* ARGSUSED */
149667b5ea1Smycroft void
terminate(int signo)1504cac80e3Slukem terminate(int signo)
15128bef396Sglass {
152667b5ea1Smycroft 
1534cac80e3Slukem 	summary();
154db822d22Slukem 	(void)raise_default_signal(signo);
155db822d22Slukem 	_exit(127);
15628bef396Sglass }
157234ccf06Sjym 
158234ccf06Sjym #ifndef NO_MSGFMT
159234ccf06Sjym /*
160234ccf06Sjym  * Buffer write(2) calls
161234ccf06Sjym  */
162234ccf06Sjym static void
buffer_write(const char * str,size_t size,int flush)163234ccf06Sjym buffer_write(const char *str, size_t size, int flush)
164234ccf06Sjym {
165234ccf06Sjym 	static char wbuf[128];
166234ccf06Sjym 	static size_t cnt = 0; /* Internal counter to allow wbuf to wrap */
167234ccf06Sjym 
168234ccf06Sjym 	unsigned int i;
169234ccf06Sjym 
170234ccf06Sjym 	for (i = 0; i < size; i++) {
171331bd1b0Sjym 		if (str != NULL) {
172234ccf06Sjym 			wbuf[cnt++] = str[i];
173331bd1b0Sjym 		}
174331bd1b0Sjym 		if (cnt >= sizeof(wbuf)) {
175234ccf06Sjym 			(void)write(STDERR_FILENO, wbuf, cnt);
176234ccf06Sjym 			cnt = 0;
177234ccf06Sjym 		}
178234ccf06Sjym 	}
179331bd1b0Sjym 
180331bd1b0Sjym 	if (flush != 0) {
181331bd1b0Sjym 		(void)write(STDERR_FILENO, wbuf, cnt);
182331bd1b0Sjym 		cnt = 0;
183331bd1b0Sjym 	}
184234ccf06Sjym }
185234ccf06Sjym 
186331bd1b0Sjym /*
187331bd1b0Sjym  * Write summary to stderr according to format 'fmt'. If 'enable' is 0, it
188331bd1b0Sjym  * will not attempt to write anything. Can be used to validate the
189331bd1b0Sjym  * correctness of the 'fmt' string.
190331bd1b0Sjym  */
191331bd1b0Sjym int
dd_write_msg(const char * fmt,int enable)192331bd1b0Sjym dd_write_msg(const char *fmt, int enable)
193234ccf06Sjym {
194234ccf06Sjym 	char hbuf[7], nbuf[32];
195234ccf06Sjym 	const char *ptr;
196234ccf06Sjym 	int64_t mS;
197234ccf06Sjym 	struct timeval tv;
198234ccf06Sjym 
199234ccf06Sjym 	(void)gettimeofday(&tv, NULL);
200234ccf06Sjym 	mS = tv2mS(tv) - tv2mS(st.start);
201234ccf06Sjym 	if (mS == 0)
202234ccf06Sjym 		mS = 1;
203234ccf06Sjym 
204331bd1b0Sjym #define ADDC(c) do { if (enable != 0) buffer_write(&c, 1, 0); } \
2054cb87529Srillig 	while (0)
206331bd1b0Sjym #define ADDS(p) do { if (enable != 0) buffer_write(p, strlen(p), 0); } \
2074cb87529Srillig 	while (0)
208234ccf06Sjym 
209234ccf06Sjym 	for (ptr = fmt; *ptr; ptr++) {
210234ccf06Sjym 		if (*ptr != '%') {
211234ccf06Sjym 			ADDC(*ptr);
212234ccf06Sjym 			continue;
213234ccf06Sjym 		}
214234ccf06Sjym 
215234ccf06Sjym  		switch (*++ptr) {
216234ccf06Sjym 		case 'b':
217234ccf06Sjym 			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
218234ccf06Sjym 			    (unsigned long long)st.bytes);
219234ccf06Sjym 			ADDS(nbuf);
220234ccf06Sjym 			break;
221234ccf06Sjym 		case 'B':
222234ccf06Sjym 			if (humanize_number(hbuf, sizeof(hbuf),
223234ccf06Sjym 			    st.bytes, "B",
224234ccf06Sjym 			    HN_AUTOSCALE, HN_DECIMAL) == -1)
225234ccf06Sjym 				warnx("humanize_number (bytes transferred)");
226234ccf06Sjym 			ADDS(hbuf);
227234ccf06Sjym 			break;
228234ccf06Sjym 		case 'e':
229234ccf06Sjym 			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
230234ccf06Sjym 			    (unsigned long long) (st.bytes * 1000LL / mS));
231234ccf06Sjym 			ADDS(nbuf);
232234ccf06Sjym 			break;
233234ccf06Sjym 		case 'E':
234234ccf06Sjym 			if (humanize_number(hbuf, sizeof(hbuf),
235234ccf06Sjym 			    st.bytes * 1000LL / mS, "B",
236234ccf06Sjym 			    HN_AUTOSCALE, HN_DECIMAL) == -1)
237234ccf06Sjym 				warnx("humanize_number (bytes per second)");
238234ccf06Sjym 			ADDS(hbuf); ADDS("/sec");
239234ccf06Sjym 			break;
240234ccf06Sjym 		case 'i':
241234ccf06Sjym 			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
242234ccf06Sjym 			    (unsigned long long)st.in_part);
243234ccf06Sjym 			ADDS(nbuf);
244234ccf06Sjym 			break;
245234ccf06Sjym 		case 'I':
246234ccf06Sjym 			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
247234ccf06Sjym 			    (unsigned long long)st.in_full);
248234ccf06Sjym 			ADDS(nbuf);
249234ccf06Sjym 			break;
250234ccf06Sjym 		case 'o':
251234ccf06Sjym 			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
252234ccf06Sjym 			    (unsigned long long)st.out_part);
253234ccf06Sjym 			ADDS(nbuf);
254234ccf06Sjym 			break;
255234ccf06Sjym 		case 'O':
256234ccf06Sjym 			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
257234ccf06Sjym 			    (unsigned long long)st.out_full);
258234ccf06Sjym 			ADDS(nbuf);
259234ccf06Sjym 			break;
260234ccf06Sjym 		case 's':
261234ccf06Sjym 			(void)snprintf(nbuf, sizeof(nbuf), "%li.%03d",
262234ccf06Sjym 			    (long) (mS / 1000), (int) (mS % 1000));
263234ccf06Sjym 			ADDS(nbuf);
264234ccf06Sjym 			break;
265234ccf06Sjym 		case 'p':
266234ccf06Sjym 			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
267234ccf06Sjym 			    (unsigned long long)st.sparse);
268234ccf06Sjym 			ADDS(nbuf);
269234ccf06Sjym 			break;
270234ccf06Sjym 		case 't':
271234ccf06Sjym 			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
272234ccf06Sjym 			    (unsigned long long)st.trunc);
273234ccf06Sjym 			ADDS(nbuf);
274234ccf06Sjym 			break;
275234ccf06Sjym 		case 'w':
276234ccf06Sjym 			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
277234ccf06Sjym 			    (unsigned long long)st.swab);
278234ccf06Sjym 			ADDS(nbuf);
279234ccf06Sjym 			break;
280234ccf06Sjym 		case 'P':
281234ccf06Sjym 			ADDS("block");
282234ccf06Sjym 			if (st.sparse != 1) ADDS("s");
283234ccf06Sjym 			break;
284234ccf06Sjym 		case 'T':
285234ccf06Sjym 			ADDS("block");
286234ccf06Sjym 			if (st.trunc != 1) ADDS("s");
287234ccf06Sjym 			break;
288234ccf06Sjym 		case 'W':
289234ccf06Sjym 			ADDS("block");
290234ccf06Sjym 			if (st.swab != 1) ADDS("s");
291234ccf06Sjym 			break;
292234ccf06Sjym 		case '%':
293234ccf06Sjym 			ADDC(*ptr);
294234ccf06Sjym 			break;
295331bd1b0Sjym 		default:
296331bd1b0Sjym 			if (*ptr == '\0')
297331bd1b0Sjym 				goto done;
298331bd1b0Sjym 			errx(EXIT_FAILURE, "unknown specifier '%c' in "
299331bd1b0Sjym 			    "msgfmt string", *ptr);
300331bd1b0Sjym 			/* NOTREACHED */
301234ccf06Sjym 		}
302234ccf06Sjym 	}
303234ccf06Sjym 
304234ccf06Sjym done:
305234ccf06Sjym 	/* flush buffer */
306331bd1b0Sjym 	buffer_write(NULL, 0, 1);
307234ccf06Sjym 	return 0;
308234ccf06Sjym }
309234ccf06Sjym 
310234ccf06Sjym static void
custom_summary(void)311234ccf06Sjym custom_summary(void)
312234ccf06Sjym {
313234ccf06Sjym 
314331bd1b0Sjym 	dd_write_msg(msgfmt, 1);
315234ccf06Sjym }
316234ccf06Sjym 
317234ccf06Sjym static void
human_summary(void)318234ccf06Sjym human_summary(void)
319234ccf06Sjym {
320331bd1b0Sjym 	(void)dd_write_msg("%I+%i records in\n%O+%o records out\n", 1);
321234ccf06Sjym 	if (st.swab) {
322331bd1b0Sjym 		(void)dd_write_msg("%w odd length swab %W\n", 1);
323234ccf06Sjym 	}
324234ccf06Sjym 	if (st.trunc) {
325331bd1b0Sjym 		(void)dd_write_msg("%t truncated %T\n", 1);
326234ccf06Sjym 	}
327234ccf06Sjym 	if (st.sparse) {
328331bd1b0Sjym 		(void)dd_write_msg("%p sparse output %P\n", 1);
329234ccf06Sjym 	}
330234ccf06Sjym 	(void)dd_write_msg("%b bytes (%B) transferred in %s secs "
331331bd1b0Sjym 	    "(%e bytes/sec - %E)\n", 1);
332234ccf06Sjym }
333234ccf06Sjym 
334234ccf06Sjym static void
quiet_summary(void)335234ccf06Sjym quiet_summary(void)
336234ccf06Sjym {
337234ccf06Sjym 
338234ccf06Sjym 	/* stay quiet */
339234ccf06Sjym }
340234ccf06Sjym #endif /* NO_MSGFMT */
341