3 * $Id: rspit.c,v 1.5 2000/07/01 11:27:03 mdw Exp $
5 * Spit out random numbers
7 * (c) 1999 Straylight/Edgeware
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of Catacomb.
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
30 /*----- Revision history --------------------------------------------------*
33 * Revision 1.5 2000/07/01 11:27:03 mdw
34 * Portability fix: don't assume that `stdout' is a constant expression.
35 * Remove old type name `bbs_param'.
37 * Revision 1.4 2000/06/17 12:08:28 mdw
38 * Restructure handling of cipher-based generators. Add counter-mode
39 * ciphers and MGF-1 hash functions. Add FIPS 140-1 and Maurer's tests.
41 * Revision 1.3 2000/02/12 18:21:03 mdw
42 * Overhaul of key management (again).
44 * Revision 1.2 1999/12/22 15:59:51 mdw
45 * New prime-search system. Read BBS keys from key files.
47 * Revision 1.1 1999/12/10 23:29:13 mdw
48 * Emit random numbers for statistical tests.
52 /*----- Header files ------------------------------------------------------*/
69 #include <mLib/darray.h>
70 #include <mLib/dstr.h>
71 #include <mLib/mdwopt.h>
72 #include <mLib/quis.h>
73 #include <mLib/report.h>
96 #include "blowfish-ofb.h"
97 #include "twofish-ofb.h"
99 #include "cast128-ofb.h"
100 #include "cast256-ofb.h"
101 #include "rijndael-ofb.h"
102 #include "serpent-ofb.h"
104 #include "des-counter.h"
105 #include "des3-counter.h"
106 #include "rc2-counter.h"
107 #include "rc5-counter.h"
108 #include "blowfish-counter.h"
109 #include "twofish-counter.h"
110 #include "idea-counter.h"
111 #include "cast128-counter.h"
112 #include "cast256-counter.h"
113 #include "rijndael-counter.h"
114 #include "serpent-counter.h"
119 #include "rmd160-mgf.h"
123 /*----- Data structures ---------------------------------------------------*/
127 grand
*(*seed
)(unsigned /*i*/);
132 static gen generators
[];
139 E(BLOWFISH, blowfish) \
140 E(TWOFISH, twofish) \
142 E(CAST128, cast128) \
143 E(CAST256, cast256) \
144 E(RIJNDAEL, rijndael) \
153 #define E(PRE, pre) CIPHER_##PRE,
154 enum { CIPHERS CIPHER__bogus
};
157 #define E(PRE, pre) HASH_##PRE,
158 enum { HASHES HASH__bogus
};
164 grand
*(*ofb
)(const void */
*k*/
, size_t /*sz*/);
165 grand
*(*counter
)(const void */
*k*/
, size_t /*sz*/);
167 #define E(PRE, pre) \
168 { pre##_keysz, PRE##_BLKSZ, pre##_ofbrand, pre##_counterrand },
176 grand
*(*mgf
)(const void */
*k*/
, size_t /*sz*/);
178 #define E(PRE, pre) \
179 { &pre, pre##_mgfkeysz, pre##_mgfrand },
184 /*----- Miscellaneous static data -----------------------------------------*/
187 static size_t outsz
= 0;
192 static unsigned flags
= 0;
201 /*----- Help options ------------------------------------------------------*/
203 static void usage(FILE *fp
)
205 pquis(fp
, "Usage: $ generator [options]\n");
208 static void version(FILE *fp
)
210 pquis(fp
, "$, Catacomb version " VERSION
"\n");
213 static void help(FILE *fp
)
219 Emits a stream of random bytes suitable for, well, all sorts of things.\n\
220 The primary objective is to be able to generate streams of input for\n\
221 statistical tests, such as Diehard.\n\
223 Options are specific to the particular generator, although there's a\n\
226 -h, --help Display this help message.\n\
227 -v, --version Display the program's version number.\n\
228 -u, --usage Display a useless usage message.\n\
230 -l, --list Show a list of the supported generators, with\n\
232 -f, --fipstest Run the FIPS 140-1 randomness test.\n\
233 -m, --maurer Run Maurer's universal statistical test.\n\
234 -o, --output FILE Write output to FILE, not stdout.\n\
235 -z, --size SIZE Emit SIZE bytes, not an unlimited number.\n\
236 -p, --progress Show a little progress meter (on stderr).\n\
238 (A SIZE may be followed by `g' for gigabytes, `m' for megabytes, or\n\
239 `k' for kilobytes. If unqualified, an amount in bytes is assumed.)\n\
243 /*----- Main options parser -----------------------------------------------*/
245 static struct option opts
[] = {
247 /* --- Standard GNU help options --- */
249 { "help", 0, 0, 'h' },
250 { "version", 0, 0, 'v' },
251 { "usage", 0, 0, 'u' },
253 /* --- Other useful things --- */
255 { "list", 0, 0, 'l' },
256 { "fipstest", 0, 0, 'f' },
257 { "maurer", 0, 0, 'm' },
258 { "output", OPTF_ARGREQ
, 0, 'o' },
259 { "size", OPTF_ARGREQ
, 0, 'z' },
260 { "progress", 0, 0, 'p' },
262 /* --- End of main table --- */
267 static const char *sopts
= "hvu lfmo:z:p";
270 DA_DECL(option_v
, struct option
);
274 static option_v optv
= DA_INIT
;
275 static dstr optd
= DSTR_INIT
;
277 /* --- @addopts@ --- *
279 * Arguments: @const char *s@ = pointer to short options
280 * @struct option *l@ = pointer to long options
284 * Use: Adds a collection of options to the table.
287 static void addopts(const char *s
, struct option
*l
)
293 DA_PUSH(&optv
, *l
++);
301 * Returns: Next option from argument array.
303 * Use: Fetches options, handling the standard ones.
309 int i
= mdwopt(argc
, argv
, optd
.buf
, DA(&optv
), 0, 0, 0);
322 puts("Generators supported:");
323 for (g
= generators
; g
->name
; g
++)
324 printf(" %s %s\n", g
->name
, g
->help
);
335 die(EXIT_FAILURE
, "already set an output file");
336 if (strcmp(optarg
, "-") == 0)
339 outfp
= fopen(optarg
, "w");
341 die(EXIT_FAILURE
, "couldn't open output file `%s': %s",
342 optarg
, strerror(errno
));
349 outsz
= strtoul(optarg
, &p
, 0);
351 die(EXIT_FAILURE
, "bad number `%s'", optarg
);
353 case 'G': case 'g': outsz
*= 1024;
354 case 'M': case 'm': outsz
*= 1024;
355 case 'K': case 'k': outsz
*= 1024;
359 die(EXIT_FAILURE
, "bad suffix `%s'", p
);
363 die(EXIT_FAILURE
, "bad suffix `%s'", p
);
374 /*----- Manglers for seed strings -----------------------------------------*/
378 * Arguments: @const char *p@ = pointer to input string
379 * @char **end@ = where the end goes
380 * @dstr *d@ = output buffer
384 * Use: Transforms a hex string into a chunk of binary data.
387 static void unhex(const char *p
, char **end
, dstr
*d
)
389 while (p
[0] && p
[1]) {
390 int x
= p
[0], y
= p
[1];
391 if ('0' <= x
&& x
<= '9') x
-= '0';
392 else if ('A' <= x
&& x
<= 'F') x
-= 'A' - 10;
393 else if ('a' <= x
&& x
<= 'f') x
-= 'a' - 10;
395 if ('0' <= y
&& y
<= '9') y
-= '0';
396 else if ('A' <= y
&& y
<= 'F') y
-= 'A' - 10;
397 else if ('a' <= y
&& y
<= 'f') y
-= 'a' - 10;
399 DPUTC(d
, (x
<< 4) + y
);
405 /* --- Generate a key --- */
407 static void textkey(dstr
*d
, const char *p
, const octet
*ksz
)
409 size_t sz
= strlen(p
);
412 die(EXIT_FAILURE
, "zero-length key string");
413 if (keysz(sz
, ksz
) != sz
)
417 rmd160_mgfinit(&g
, p
, sz
);
420 rmd160_mgfencrypt(&g
, 0, d
->buf
, sz
);
423 assert(((void)"I can't seem to choose a good key size",
424 keysz(d
->len
, ksz
) == d
->len
));
427 static void hexkey(dstr
*d
, const char *p
, const octet
*ksz
)
430 unhex(optarg
, &q
, d
);
432 die(EXIT_FAILURE
, "bad hex key `%s'", p
);
433 if (keysz(d
->len
, ksz
) != d
->len
)
434 die(EXIT_FAILURE
, "bad key length");
437 static void randkey(dstr
*d
, const octet
*ksz
)
439 size_t sz
= keysz(0, ksz
);
441 rand_get(RAND_GLOBAL
, d
->buf
, sz
);
445 /*----- Generators --------------------------------------------------------*/
447 /* --- Blum-Blum-Shub strong generator --- */
449 static grand
*gen_bbs(unsigned i
)
451 /* --- Default modulus --- *
453 * The factors of this number are
455 * @p = 1229936431484295969649886203367009966370895964206162032259292413@
456 * @7754313537966036459299022912838407755462506416274551744201653277@
457 * @313130311731673973886822067@
459 * @q = 9798171783943489959487301695884963889684294764514008432498259742@
460 * @5374320073594018817245784145742769603334292182227671519041431067@
461 * @61344781426317516045890159@
463 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
464 * common factors. They were found using this program, with random
467 * I hope that, by publishing these factors, I'll dissuade people from
468 * actually using this modulus in an attempt to attain real security. The
469 * program is quite quick at finding Blum numbers, so there's no excuse for
470 * not generating your own.
474 "120511284390135742513572142094334711443073194119732569353820828435640527418092392240366088035509890969913081816369160298961490135716255689660470370755013177656905237112577648090277537209936078171554274553448103698084782669252936352843649980105109850503830397166360721262431179505917248447259735253684659338653";
476 /* --- Other things --- */
480 unsigned bits
= 1024;
483 const char *kfile
= 0, *id
= 0, *ktype
= 0;
485 /* --- Parse options --- */
487 static struct option opts
[] = {
488 { "modulus", OPTF_ARGREQ
, 0, 'M' },
489 { "generate", 0, 0, 'g' },
490 { "seed", OPTF_ARGREQ
, 0, 's' },
491 { "bits", OPTF_ARGREQ
, 0, 'b' },
492 { "show", 0, 0, 'S' },
493 { "keyring", OPTF_ARGREQ
, 0, 'k' },
494 { "id", OPTF_ARGREQ
, 0, 'i' },
495 { "type", OPTF_ARGREQ
, 0, 't' },
499 addopts("M:gs:b:Sk:i:t:", opts
);
516 bits
= strtoul(optarg
, 0, 0);
518 die(EXIT_FAILURE
, "bad number of bits `%s'", optarg
);
540 /* --- Generate a modulus if one is requested --- */
544 m
= mp_readstring(MP_NEW
, mt
, &p
, 0);
545 if (!m
|| *p
|| (m
->v
[0] & 3) != 1)
546 die(EXIT_FAILURE
, "bad modulus `%s'", mt
);
547 /* Unfortunately I don't know how to test for a Blum integer */
548 } else if (kfile
|| id
|| ktype
) {
553 /* --- Open the key file --- */
557 if (key_open(&kf
, kfile
, KOPEN_READ
, key_moan
, 0)) {
558 die(EXIT_FAILURE
, "error opening key file `%s': %s",
559 kfile
, strerror(errno
));
562 /* --- Find the key --- */
565 if ((kk
= key_bytag(&kf
, id
)) == 0)
566 die(EXIT_FAILURE
, "key `%s' not found", id
);
570 if ((kk
= key_bytype(&kf
, ktype
)) == 0)
571 die(EXIT_FAILURE
, "no suitable key with type `%s' found", ktype
);
574 /* --- Read the key data --- */
576 if ((kk
->k
.e
& KF_ENCMASK
) != KENC_STRUCT
)
577 die(EXIT_FAILURE
, "key is not structured");
578 if ((kd
= key_structfind(&kk
->k
, "n")) == 0)
579 die(EXIT_FAILURE
, "key has no subkey `n'");
580 if ((kd
->e
& KF_ENCMASK
) != KENC_MP
)
581 die(EXIT_FAILURE
, "incomatible subkey encoding");
582 m
= MP_COPY(kd
->u
.m
);
587 if (bbs_gen(&bp
, bits
, &rand_global
, 0,
588 (flags
& f_progress
) ? pgen_ev
: 0, 0))
589 die(EXIT_FAILURE
, "modulus generation failed");
593 fputs("p = ", stderr
);
594 mp_writefile(bp
.p
, stderr
, 10);
595 fputs("\nq = ", stderr
);
596 mp_writefile(bp
.q
, stderr
, 10);
597 fputs("\nn = ", stderr
);
598 mp_writefile(bp
.n
, stderr
, 10);
606 /* --- Set up a seed --- */
609 x
= mprand(MP_NEW
, mp_bits(m
) - 1, &rand_global
, 1);
612 x
= mp_readstring(MP_NEW
, xt
, &p
, 0);
614 die(EXIT_FAILURE
, "bad modulus `%s'", xt
);
626 /* --- Catacomb's random number generator --- */
628 static grand
*gen_rand(unsigned i
)
630 grand
*r
= rand_create();
633 static struct option opts
[] = {
634 { "key", OPTF_ARGREQ
, 0, 'k' },
635 { "text", OPTF_ARGREQ
, 0, 't' },
636 { "hex", OPTF_ARGREQ
, 0, 'H' },
640 addopts("k:t:H:n", opts
);
642 r
->ops
->misc(r
, RAND_NOISESRC
, &noise_source
);
643 r
->ops
->misc(r
, RAND_SEED
, 160);
652 textkey(&d
, optarg
, rmd160_mackeysz
);
653 r
->ops
->misc(r
, RAND_KEY
, d
.buf
, d
.len
);
656 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, optarg
, strlen(optarg
));
660 hexkey(&d
, optarg
, rmd160_mackeysz
);
661 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, d
.buf
, d
.len
);
670 /* --- RC4 output --- */
672 static grand
*gen_rc4(unsigned i
)
677 static struct option opts
[] = {
678 { "key", OPTF_ARGREQ
, 0, 'k' },
679 { "hex", OPTF_ARGREQ
, 0, 'H' },
683 addopts("k:H:", opts
);
692 textkey(&d
, optarg
, rc4_keysz
);
696 hexkey(&d
, optarg
, rc4_keysz
);
704 randkey(&d
, rc4_keysz
);
705 r
= rc4_rand(d
.buf
, d
.len
);
710 /* --- SEAL output --- */
712 static grand
*gen_seal(unsigned i
)
718 static struct option opts
[] = {
719 { "key", OPTF_ARGREQ
, 0, 'k' },
720 { "hex", OPTF_ARGREQ
, 0, 'H' },
721 { "sequence", OPTF_ARGREQ
, 0, 'n' },
725 addopts("k:H:n:", opts
);
734 textkey(&d
, optarg
, seal_keysz
);
738 hexkey(&d
, optarg
, seal_keysz
);
742 n
= strtoul(optarg
, &p
, 0);
744 die(EXIT_FAILURE
, "bad number `%s'", optarg
);
752 randkey(&d
, seal_keysz
);
753 r
= seal_rand(d
.buf
, d
.len
, n
);
758 /* --- Output feedback generators --- */
760 static grand
*gen_ofb(unsigned i
)
766 static struct option opts
[] = {
767 { "key", OPTF_ARGREQ
, 0, 'k' },
768 { "hex", OPTF_ARGREQ
, 0, 'H' },
769 { "iv", OPTF_ARGREQ
, 0, 'i' },
773 addopts("k:H:i:", opts
);
782 textkey(&d
, optarg
, ciphertab
[i
].keysz
);
786 hexkey(&d
, optarg
, ciphertab
[i
].keysz
);
790 unhex(optarg
, &p
, &iv
);
792 die(EXIT_FAILURE
, "bad hex IV `%s'", optarg
);
800 randkey(&d
, ciphertab
[i
].keysz
);
801 r
= ciphertab
[i
].ofb(d
.buf
, d
.len
);
803 if (iv
.len
!= ciphertab
[i
].blksz
) {
804 die(EXIT_FAILURE
, "bad IV length %lu (must be %lu)",
805 (unsigned long)iv
.len
, (unsigned long)ciphertab
[i
].blksz
);
807 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, iv
.buf
);
815 /* --- Counter generators --- */
817 static grand
*gen_counter(unsigned i
)
823 static struct option opts
[] = {
824 { "key", OPTF_ARGREQ
, 0, 'k' },
825 { "hex", OPTF_ARGREQ
, 0, 'H' },
826 { "iv", OPTF_ARGREQ
, 0, 'i' },
830 addopts("k:H:i:", opts
);
839 textkey(&d
, optarg
, ciphertab
[i
].keysz
);
843 hexkey(&d
, optarg
, ciphertab
[i
].keysz
);
847 unhex(optarg
, &p
, &iv
);
849 die(EXIT_FAILURE
, "bad hex IV `%s'", optarg
);
857 randkey(&d
, ciphertab
[i
].keysz
);
858 r
= ciphertab
[i
].counter(d
.buf
, d
.len
);
860 if (iv
.len
!= ciphertab
[i
].blksz
) {
861 die(EXIT_FAILURE
, "bad IV length %lu (must be %lu)",
862 (unsigned long)iv
.len
, (unsigned long)ciphertab
[i
].blksz
);
864 r
->ops
->misc(r
, GRAND_SEEDBLOCK
, iv
.buf
);
872 /* --- Mask generators --- */
874 static grand
*gen_mgf(unsigned i
)
880 static struct option opts
[] = {
881 { "key", OPTF_ARGREQ
, 0, 'k' },
882 { "hex", OPTF_ARGREQ
, 0, 'H' },
883 { "index", OPTF_ARGREQ
, 0, 'i' },
887 addopts("k:H:i:", opts
);
896 textkey(&d
, optarg
, hashtab
[i
].keysz
);
900 hexkey(&d
, optarg
, hashtab
[i
].keysz
);
904 c
= strtoul(optarg
, &p
, 0);
906 die(EXIT_FAILURE
, "bad index `%s'", optarg
);
914 randkey(&d
, hashtab
[i
].keysz
);
916 r
= hashtab
[i
].mgf(d
.buf
, d
.len
);
918 r
->ops
->misc(r
, GRAND_SEEDUINT32
, c
);
924 /* --- Fibonacci generator --- */
926 static grand
*gen_fib(unsigned i
)
933 static struct option opts
[] = {
934 { "seed", OPTF_ARGREQ
, 0, 's' },
946 s
= strtoul(optarg
, &p
, 0);
948 die(EXIT_FAILURE
, "bad integer `%s'", optarg
);
955 r
= fibrand_create(s
);
957 r
->ops
->misc(r
, GRAND_SEEDRAND
, &rand_global
);
961 /* --- LC generator --- */
963 static grand
*gen_lc(unsigned i
)
969 static struct option opts
[] = {
970 { "seed", OPTF_ARGREQ
, 0, 's' },
982 s
= strtoul(optarg
, &p
, 0);
984 die(EXIT_FAILURE
, "bad integer `%s'", optarg
);
993 s
= rand_global
.ops
->range(&rand_global
, LCRAND_P
);
994 while (s
== LCRAND_FIXEDPT
);
996 return (lcrand_create(s
));
999 /* --- Basic options parser -- can't generate output --- */
1001 static grand
*gen_opts(unsigned i
)
1008 /*----- Generators table --------------------------------------------------*/
1010 static gen generators
[] = {
1011 { "fibonacci", gen_fib
, 0,
1015 #define E(PRE, pre) \
1016 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
1017 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1020 #define E(PRE, pre) \
1021 { #pre "-counter", gen_counter, CIPHER_##PRE, \
1022 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
1025 #define E(PRE, pre) \
1026 { #pre "-mgf", gen_mgf, HASH_##PRE, \
1027 "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
1030 { "rc4", gen_rc4
, 0,
1031 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1032 { "seal", gen_seal
, 0,
1033 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
1034 { "rand", gen_rand
, 0,
1035 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1036 { "bbs", gen_bbs
, 0,
1037 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
1042 static gen optsg
= { "options", gen_opts
, 0,
1043 "This message shouldn't be printed." };
1045 /*----- Main code ---------------------------------------------------------*/
1047 int main(int ac
, char *av
[])
1051 unsigned percent
= 0;
1054 static char baton
[] = "-\\|/";
1057 /* --- Initialize mLib --- */
1062 /* --- Set up the main Catacomb generator --- */
1064 rand_noisesrc(RAND_GLOBAL
, &noise_source
);
1065 rand_seed(RAND_GLOBAL
, 160);
1067 /* --- Initialize the options table --- */
1069 addopts(sopts
, opts
);
1074 /* --- Read the generator out of the first argument --- */
1076 if (argc
> 1 && *argv
[1] != '-') {
1077 const char *arg
= av
[1];
1078 size_t sz
= strlen(arg
);
1082 for (gg
= generators
; gg
->name
; gg
++) {
1083 if (strncmp(arg
, gg
->name
, sz
) == 0) {
1084 if (gg
->name
[sz
] == 0) {
1088 die(EXIT_FAILURE
, "ambiguous generator name `%s'", arg
);
1094 die(EXIT_FAILURE
, "unknown generator name `%s'", arg
);
1099 /* --- Get a generic random number generator --- */
1102 if (!r
|| optind
!= ac
- 1) {
1107 /* --- Do the FIPS test --- */
1109 if (flags
& f_fips
) {
1110 octet buf
[FIPSTEST_BUFSZ
];
1113 r
->ops
->fill(r
, buf
, sizeof(buf
));
1115 if (rc
& FIPSTEST_MONOBIT
)
1116 moan("failed monobit test");
1117 if (rc
& FIPSTEST_POKER
)
1118 moan("failed poker test");
1119 if (rc
& FIPSTEST_RUNS
)
1120 moan("failed runs test");
1121 if (rc
& FIPSTEST_LONGRUNS
)
1122 moan("failed long runs test");
1123 if (!rc
&& (flags
& f_progress
))
1124 puts("test passed");
1125 return (rc ? EXIT_FAILURE
: 0);
1128 /* --- Do Maurer's test --- */
1130 if (flags
& f_maurer
) {
1131 octet buf
[250 * 1024];
1134 unsigned f
= 0, jj
= 0;
1137 static struct { double x
; const char *sig
; } sigtab
[] = {
1145 r
->ops
->fill(r
, buf
, sizeof(buf
));
1146 for (i
= 5; i
< 8; i
++) {
1147 double z
= maurer(buf
, sizeof(buf
), i
+ 1);
1148 double zz
= fabs(z
);
1151 for (j
= 0; sigtab
[j
].sig
; j
++) {
1152 if (zz
> sigtab
[j
].x
) {
1153 if (zz
> fabs(maxz
)) {
1159 moan("failed, bits = %u, sig = %s, Z_u = %g",
1160 i
+ 1, sigtab
[j
].sig
, z
);
1164 if (flags
& f_progress
)
1165 printf("bits = %u, Z_u = %g\n", i
+ 1, z
);
1171 /* --- Make sure we don't write to the terminal --- */
1174 if (!(flags
& f_file
) && isatty(STDOUT_FILENO
))
1175 die(EXIT_FAILURE
, "writing output to a terminal is a bad idea");
1178 /* --- Spit out random data --- */
1182 if (flags
& f_progress
) {
1183 char *errbuf
= xmalloc(BUFSIZ
);
1184 setvbuf(stderr
, errbuf
, _IOLBF
, BUFSIZ
);
1186 fprintf(stderr
, "[%*s] 0%% 0\r[/\b", 50, "");
1188 fputs("[ ] 0\r[/\b", stderr
);
1193 signal(SIGPIPE
, SIG_IGN
);
1198 size_t sz
= sizeof(buf
);
1200 /* --- Emit a bufferful (or less) of data --- */
1203 if (sz
> outsz
- kb
)
1206 r
->ops
->fill(r
, buf
, sz
);
1207 if (fwrite(buf
, 1, sz
, outfp
) != sz
) {
1208 if (flags
& f_progress
)
1209 fputc('\n', stderr
);
1210 die(EXIT_FAILURE
, "error writing data: %s", strerror(errno
));
1214 /* --- Update the display --- */
1216 if (flags
& f_progress
) {
1224 if (difftime(t
, last
) > 1.0) {
1228 fputs(" ] ", stderr
);
1230 unsigned pc
= kb
* 100.0 / outsz
;
1231 if (pc
> percent
|| percent
> 100 || difftime(t
, last
) > 1.0) {
1235 for (; percent
< (pc
& ~1); percent
+= 2)
1238 for (; pc
< 100; pc
+= 2)
1240 fprintf(stderr
, "] %3i%% ", percent
);
1247 char *suff
= " KMG";
1248 while (q
> 8192 && suff
[1]) {
1252 fprintf(stderr
, "%4i%c\r[", q
, *suff
);
1255 for (pc
= 0; pc
< (percent
& ~1); pc
+= 2)
1264 if (percent
< 100) {
1265 putc(*bp
++, stderr
);
1273 /* --- Terminate the loop --- */
1275 if (outsz
&& kb
>= outsz
)
1282 if (flags
& f_progress
)
1283 fputc('\n', stderr
);
1287 /*----- That's all, folks -------------------------------------------------*/