/* orginal written by E. Mattes */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#ifdef __EMX__
#include <process.h>
#include <signal.h>
#else
#include <sys\_signal.h>
#endif

static int v = 1;

static void usage(void)
{
    puts("Usage: fork [-r#] [-svw]");
    puts("Options:");
    puts("  -r#  Set number of recursion levels");
    puts("  -s   Set SIGCLD handler");
    puts("  -v   Be verbose");
    puts("  -w   Wait for children");
    exit(1);
}

static void handler(int sig)
{
    switch (sig) {
	case SIGCLD:
	printf("process %d get SIGCLD\n", getpid());
	break;
    default:
	printf("Signal %d\n", sig);
	break;
    }
    fflush(stdout);
    signal(SIGCLD, SIG_ACK);
}


int main(int argc, char *argv[])
{
    int c, i, n, p, t, v0, rep, opt_s, opt_w, verb;
    char buf[32], *fork_name;

    rep = 0;
    opt_s = 0;
    opt_w = 0;
    verb = 1;

    for (i = 0; i < argc; i++)
	if (*(argv[i]) != '-')
	    continue;
	else
	    switch (*(argv[i] + 1)) {
	    case 'r':
		rep = atoi(argv[i] + 2);
		break;
	    case 's':
		opt_s = 1;
		break;
	    case 'v':
		verb = 2;
		break;
	    case 'w':
		opt_w = 1;
		break;
	    default:
		usage();
	    }
    if (rep > 6) {
	printf("*** That's too dangerous ***\n");
	return (1);
    }
    if (opt_s)
	signal(SIGCLD, handler);
    v0 = v;
    printf("Here's fork%d (pid=%d, ppid=%d)\n", v0,
	   getpid(), getppid());
    fork_name = strdup("fork"); /* test heap */
    n = 0;
    do {
	++v;
	i = fork();
	if (verb >= 1)
	    printf("fork() call returns: %d\n", i);

	if (i < 0) {
	    sprintf(buf, "fork%d: fork", v0);
	    perror(buf);
	    return (1);
	} else if (i == 0) {
	    v0 = v;
	    n = 0;
	    printf("New child: Here's forked %s%d (pid=%d, ppid=%d)\n",
		   fork_name, v0, getpid(), getppid());
	} else {
	    ++n;
	    if (verb >= 1)
		printf("father: fork%d: forked fork has pid %d\n", v0, i);
	}
    } while (v <= rep);
    if (opt_w && n > 0) {
	if (verb >= 2)
	    printf("fork%d: waiting for %d child%s\n",
		   v0, n, (n == 1 ? "" : "ren"));
	while (n > 0) {
	    p = wait(&t);
	    if (verb >= 1)
		printf("wait() call returns: pid %d stat %d\n", i, t);
	    if (p == -1) {
		sprintf(buf, "fork%d: wait", v0);
		perror(buf);
		return (1);
	    } else {
		--n;
		if ((t & 0xff) == 0)
		    printf("fork%d: process %d terminated normally, rc=%d\n",
			   v0, p, t >> 8);
		else if ((t & 0xff) == 127)
		    printf("fork%d: process %d stopped by signal %d\n",
			   v0, p, t >> 8);
		else
		    printf("fork%d: process %d terminated by signal %d\n",
			   v0, p, t & 0xff);
	    }
	}
    }
    if (verb >= 2)
	printf("fork%d: end with ret code %d\n", v0, 10 + getpid());
    return (10 + getpid());
}
