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