/*
 * DF-4228 harness: divide-by-zero in cyapa_poll_thread()
 * (sys/dev/smbus/cyapa/cyapa.c:1200)
 *
 *     static int cyapa_idle_freq = 1;    <- sysctl debug.cyapa_idle_freq  RW
 *     static int cyapa_slow_freq = 20;   <- sysctl debug.cyapa_slow_freq RW
 *     static int cyapa_norm_freq = 100;  <- sysctl debug.cyapa_norm_freq RW
 *     (cyapa.c:227-235, root-writable, unbounded)
 *
 *     tsleep(&sc->poll_flags, 0, "cyapw",
 *            (hz + freq - 1) / freq);            <-- cyapa.c:1200
 *
 * freq is re-assigned from one of the three sysctls every poll iteration
 * (cyapa.c:1202-1210).  Setting any of them to 0 makes the kernel thread
 * execute an integer division by zero -> #DE -> kernel panic.
 *
 * This userspace model executes the identical arithmetic in the identical
 * integer types to show the fault (userspace: SIGFPE; kernel: panic).
 */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

static int freq;

static void sigfpe_handler(int sig)
{
	(void)sig;
	printf("RESULT: SIGFPE - integer division by zero raised "
	       "(in kernel context: #DE trap -> panic)\n");
	exit(0);
}

int main(void)
{
	int hz = 100;			/* kern.hz */
	int timeout;

	signal(SIGFPE, sigfpe_handler);

	freq = 0;			/* sysctl debug.cyapa_idle_freq=0 */
	printf("cyapa_poll_thread: freq=%d, computing (hz + freq - 1) / freq\n",
	       freq);
	fflush(stdout);

	timeout = (hz + freq - 1) / freq;	/* cyapa.c:1200 */

	/* not reached when freq == 0 */
	printf("tsleep timeout = %d\n", timeout);
	printf("RESULT: no fault (unexpected)\n");
	return 1;
}
