random.c revision 24420
12490Sjkh/*
22490Sjkh * Copyright (c) 1994
32490Sjkh *	The Regents of the University of California.  All rights reserved.
42490Sjkh *
52490Sjkh * This code is derived from software contributed to Berkeley by
62490Sjkh * Guy Harris at Network Appliance Corp.
72490Sjkh *
82490Sjkh * Redistribution and use in source and binary forms, with or without
92490Sjkh * modification, are permitted provided that the following conditions
102490Sjkh * are met:
112490Sjkh * 1. Redistributions of source code must retain the above copyright
122490Sjkh *    notice, this list of conditions and the following disclaimer.
132490Sjkh * 2. Redistributions in binary form must reproduce the above copyright
142490Sjkh *    notice, this list of conditions and the following disclaimer in the
152490Sjkh *    documentation and/or other materials provided with the distribution.
162490Sjkh * 3. All advertising materials mentioning features or use of this software
172490Sjkh *    must display the following acknowledgement:
182490Sjkh *	This product includes software developed by the University of
192490Sjkh *	California, Berkeley and its contributors.
202490Sjkh * 4. Neither the name of the University nor the names of its contributors
212490Sjkh *    may be used to endorse or promote products derived from this software
222490Sjkh *    without specific prior written permission.
232490Sjkh *
242490Sjkh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
252490Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
262490Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
272490Sjkh * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
282490Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
292490Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
302490Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
312490Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
322490Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
332490Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
342490Sjkh * SUCH DAMAGE.
352490Sjkh */
362490Sjkh
372490Sjkh#ifndef lint
382490Sjkhstatic char copyright[] =
392490Sjkh"@(#) Copyright (c) 1994\n\
402490Sjkh	The Regents of the University of California.  All rights reserved.\n";
412490Sjkh#endif /* not lint */
422490Sjkh
432490Sjkh#ifndef lint
442490Sjkhstatic char sccsid[] = "@(#)random.c	8.5 (Berkeley) 4/5/94";
452490Sjkh#endif /* not lint */
462490Sjkh
472490Sjkh#include <sys/types.h>
482490Sjkh
492490Sjkh#include <err.h>
502490Sjkh#include <errno.h>
516160Sbde#include <limits.h>
522490Sjkh#include <stdio.h>
532490Sjkh#include <stdlib.h>
542490Sjkh#include <time.h>
552490Sjkh#include <unistd.h>
562490Sjkh
572490Sjkhvoid usage __P((void));
582490Sjkh
592490Sjkhint
602490Sjkhmain(argc, argv)
612490Sjkh	int argc;
622490Sjkh	char *argv[];
632490Sjkh{
642490Sjkh	extern int optind;
652490Sjkh	double denom;
662490Sjkh	int ch, random_exit, selected, unbuffer_output;
672490Sjkh	char *ep;
682490Sjkh
692490Sjkh	random_exit = unbuffer_output = 0;
702490Sjkh	while ((ch = getopt(argc, argv, "er")) != EOF)
712490Sjkh		switch (ch) {
722490Sjkh		case 'e':
732490Sjkh			random_exit = 1;
742490Sjkh			break;
752490Sjkh		case 'r':
762490Sjkh			unbuffer_output = 1;
772490Sjkh			break;
782490Sjkh		default:
792490Sjkh		case '?':
802490Sjkh			usage();
812490Sjkh			/* NOTREACHED */
822490Sjkh		}
832490Sjkh
842490Sjkh	argc -= optind;
852490Sjkh	argv += optind;
862490Sjkh
872490Sjkh	switch (argc) {
882490Sjkh	case 0:
892490Sjkh		denom = 2;
902490Sjkh		break;
912490Sjkh	case 1:
922490Sjkh		errno = 0;
932490Sjkh		denom = strtod(*argv, &ep);
942490Sjkh		if (errno == ERANGE)
952490Sjkh			err(1, "%s", *argv);
9624420Sache		if (denom <= 0 || *ep != '\0')
972490Sjkh			errx(1, "denominator is not valid.");
9824420Sache		if (random_exit && denom > 255)
9924420Sache			errx(1, "denominator must be <= 255 for random exit.");
1002490Sjkh		break;
1012490Sjkh	default:
1028856Srgrimes		usage();
1032490Sjkh		/* NOTREACHED */
1042490Sjkh	}
1052490Sjkh
10624420Sache	if (srandomdev() < 0)
10724420Sache		srandom(time(NULL) ^ getpid());
1082490Sjkh
1092490Sjkh	/* Compute a random exit status between 0 and denom - 1. */
1102490Sjkh	if (random_exit)
1112490Sjkh		return ((denom * random()) / LONG_MAX);
1122490Sjkh
1132490Sjkh	/*
1142490Sjkh	 * Act as a filter, randomly choosing lines of the standard input
1152490Sjkh	 * to write to the standard output.
1162490Sjkh	 */
1172490Sjkh	if (unbuffer_output)
1182490Sjkh		setbuf(stdout, NULL);
1198856Srgrimes
1202490Sjkh	/*
1212490Sjkh	 * Select whether to print the first line.  (Prime the pump.)
1222490Sjkh	 * We find a random number between 0 and denom - 1 and, if it's
1232490Sjkh	 * 0 (which has a 1 / denom chance of being true), we select the
1242490Sjkh	 * line.
1252490Sjkh	 */
1262490Sjkh	selected = (int)(denom * random() / LONG_MAX) == 0;
1272490Sjkh	while ((ch = getchar()) != EOF) {
1282490Sjkh		if (selected)
1292490Sjkh			(void)putchar(ch);
1302490Sjkh		if (ch == '\n') {
1312490Sjkh			/* End of that line.  See if we got an error. */
1322490Sjkh			if (ferror(stdout))
1332490Sjkh				err(2, "stdout");
1342490Sjkh
1352490Sjkh			/* Now see if the next line is to be printed. */
1362490Sjkh			selected = (int)(denom * random() / LONG_MAX) == 0;
1372490Sjkh		}
1382490Sjkh	}
1392490Sjkh	if (ferror(stdin))
1402490Sjkh		err(2, "stdin");
1412490Sjkh	exit (0);
1422490Sjkh}
1432490Sjkh
1442490Sjkhvoid
1452490Sjkhusage()
1462490Sjkh{
1472490Sjkh
1482490Sjkh	(void)fprintf(stderr, "usage: random [-er] [denominator]\n");
1492490Sjkh	exit(1);
1502490Sjkh}
151