
/*
 *      We got a signal (HUP PWR WINCH ALRM INT)
 */
void
signal_handler(int sig)
{
	int cnt, j;
        int map_row, map_col, map_status;
	struct in_addr master_node;
	uint32_t addr;
	int bailed_completely;
	int bailed_pass_ok;
        struct mosixnet map[MAX_MOSNET_ENTS];


	// I bet that a linux signal handler is the worst place to do 
	// networking, outside of Windows NT.

 	if(get_map(map, &cnt) == OPENMOSIX_SUCCESS)
	{

		bailed_completely = 0;
		bailed_pass_ok = 0;
		map_row = 0;
		map_col = 0;
		// room for a while loop here (repeat attempts)

			if(!bailed_completely)
			{
				printf("%s: map found, running delme effort.\n", whoami);


				for(j = 0; (j < 3 && bailed_pass_ok == 0); j++)
				{
					printf("%s: running retry loop for pullmy .. with a map count of [%d]\n", whoami, cnt);
					map_status = pullmyfinger_terrence(map, &cnt, OPT_DELME);
					if(map_status == 0)
					{
						printf("%s: delme worked completely.\n", whoami);
						bailed_pass_ok = 1;
						bailed_completely = 1;
					}
					if(map_status > 0)
					{
						printf("%s: delme worked, but not entirely.\n", whoami);
						bailed_pass_ok = 1;
						bailed_completely = 0;
					}
				}
			}
			else
			{
				printf("%s: FATAL - unable to acquire mosix map. Exiting.\n", whoami);
			}

		// end non existant while
	}

	return;
}



int
yesorno(char *str, int dflt)
{


	// YEP

	if (strcasecmp(str, "yes") == 0) {
		return 1;

	} else if (strcasecmp(str, "yep") == 0) {
		return 1;

	} else if (strcasecmp(str, "yeh") == 0) {
		return 1;

	} else if (strcasecmp(str, "yay") == 0) {
		return 1;

	} else if (strcasecmp(str, "true") == 0) {
		return 1;

	} else if (strcasecmp(str, "on") == 0) {
		return 1;

	} else if (strcasecmp(str, "y") == 0) {
		return 1;

	} else if (strcasecmp(str, "1") == 0) {
		return 1;

	}


	// NUP

	if (strcasecmp(str, "no") == 0) {
		return 0;

	} else if (strcasecmp(str, "nup") == 0) {
		return 0;

	} else if (strcasecmp(str, "nah") == 0) {
		return 0;

	} else if (strcasecmp(str, "nay") == 0) {
		return 0;

	} else if (strcasecmp(str, "false") == 0) {
		return 0;

	} else if (strcasecmp(str, "off") == 0) {
		return 0;

	} else if (strcasecmp(str, "n") == 0) {
		return 0;

	} else if (strcasecmp(str, "0") == 0) {
		return 0;

	}


	// DEFAULT

	return dflt;
}



int
cfg_parseline(char *line)
{
	char *dup = strdup(line);
	char *s = dup;
	char *src, *dst;
	char *w, *a, *c;
	char *ptr;
	int dif = 0;
	int ord = 0;
	int n = -1;


	/*
	 *	Remove the trailing newline.
	 */
	for(w = s; *w; w++)
		;
	while(--w >= s && *w == '\n')
		*w = 0;

	/*
	 *	Get word (w), command (c) and argument (a).
	 */
	while(isspace(*s)) s++;
	w = s;
	while(*s && !isspace(*s)) s++;
	if (*w == 0) {
parseline_error:
		free(dup);
		return -1;
	}
	if (*s) *s++ = 0;
	while(isspace(*s)) s++;
	a = s;

	/*
	 *	Restore pneumonics \r\n etc ..
	 */
	src = s;

	while (*src != '\0') {
		dst = src - dif;
		if(*src == '\\') {
			src++;
			if(*src == 'n') {
				*dst = '\n';
				dif++;
			} else if(*src == 'r') {
				*dst = '\r';
				dif++;
			} else if(*src == '\\') {
				*dst = '\\';
				dif++;
			} else if(*src == 'f') {
				*dst = '\f';
				dif++;
			} else if(*src == 'v') {
				*dst = '\v';
				dif++;
			} else if(*src == 't') {
				*dst = '\t';
				dif++;
			} else if(*src == 'b') {
				*dst = '\b';
				dif++;
			} else if(*src == 'a') {
				*dst = '\a';
				dif++;
			} else {
				src--;
				*dst = *src;
			}
		} else {
			*dst = *src;
		}
		src++;
	}
	dst = src - dif;
	while (dif > 0) {
		*dst = '\0';
		dst++;
		dif--;
	}

	// word vs command separator
	if ((c = strchr(w, ':')) == NULL || c[1] == 0)
		goto parseline_error;
	*c++ = 0;

	// printf("Word [%s], Command [%s], Argument [%s]\n", w, c, a);


	/*
	 *	See what class of command this is.
	 */
	if (strcmp(w, "new") == 0) {

		goto parseline_error;

	} else if (strcmp(w, "set") == 0) {

		// MODULE OPTIONS

		if (strcmp(c, "mod_sbin_dir") == 0) {
			strncpy(cfg_mod_sbindir, a, 127);


		// IPSEC OPTIONS

		} else if (strcmp(c, "ipsec_exec_dir") == 0) {
			strncpy(cfg_ipsec_execdir, a, 127);

		} else if (strcmp(c, "ipsec_lib_dir") == 0) {
			strncpy(cfg_ipsec_libdir, a, 127);

		} else if (strcmp(c, "ipsec_sbin_dir") == 0) {
			strncpy(cfg_ipsec_sbindir, a, 127);

		} else if (strcmp(c, "ipsec_conf_dir") == 0) {
			strncpy(cfg_ipsec_confdir, a, 127);

		} else if (strcmp(c, "ipsec_ctl_base") == 0) {
			strncpy(cfg_ipsec_ctlbase, a, 127);

		} else if (strcmp(c, "ipsec_modprobe") == 0) {
			cfg_ipsec_probeme = yesorno(a, 0);


		// IPTABLES OPTIONS

		} else if (strcmp(c, "iptables_sbin_dir") == 0) {
			strncpy(cfg_iptables_sbindir, a, 127);


		// NET OPTIONS

		} else if (strcmp(c, "net_sbin_dir") == 0) {
			strncpy(cfg_net_sbindir, a, 127);


		// SSH OPTIONS

		} else if (strcmp(c, "rsa_pubkey_file") == 0) {
			strncpy(cfg_ssh_rsa_pubkey_f, a, 127);

		} else if (strcmp(c, "dsa_pubkey_file") == 0) {
			strncpy(cfg_ssh_dsa_pubkey_f, a, 127);

		} else if (strcmp(c, "authorized_file") == 0) {
			strncpy(cfg_ssh_authorized_f, a, 127);

		} else if (strcmp(c, "knownhosts_file") == 0) {
			strncpy(cfg_ssh_knownhosts_f, a, 127);


		// BOMBED ..

		} else {
			goto parseline_error;

		}

	} else if (strlen(w)==0) {
		goto parseline_error;

	} else {
		goto parseline_error;
	}

	return 0;
}



int
fs_get_pubkey(int which, char *buffer)
{
	FILE *fp;

	memset(buffer, 0, KEYSZ);
	if(which == RSAKEY) {
		if ((fp = fopen(cfg_ssh_rsa_pubkey_f, "r")) == NULL) {
			printf("%s: warning, unable to open: %s\n", whoami, cfg_ssh_rsa_pubkey_f);
			return -1;
		}
	} else {
		if ((fp = fopen(cfg_ssh_dsa_pubkey_f, "r")) == NULL) {
			printf("%s: warning, unable to open: %s\n", whoami, cfg_ssh_dsa_pubkey_f);
			return -1;
		}
	}

	if(fgets(buffer, KEYSZ, fp) == NULL) {
		fclose(fp);
		return -1;
	}

	fclose(fp);
	return strlen(buffer);
}


int
fs_set_authorized(void)
{
	FILE *fpa, *fpk;
	struct cluster_node *Cluster_node;
	int counta, countk;



	counta = 0;
	countk = 0;


	if ((fpa = fopen(cfg_ssh_authorized_f, "a")) == NULL) {
		printf("%s: warning, unable to append: %s\n", whoami, cfg_ssh_authorized_f);
		return -1;
	}

	if ((fpk = fopen(cfg_ssh_knownhosts_f, "a")) == NULL) {
		printf("%s: warning, unable to append: %s\n", whoami, cfg_ssh_knownhosts_f);
		return -1;
	}


	Cluster_node = cluster_node_ptr;

	while (Cluster_node->next != NULL) {
		if(Cluster_node->set_ssh_auth == 0) {
			fprintf(fpa, "# chaos-%x\n", ntohl(Cluster_node->addr.s_addr));
			fprintf(fpa, "from=\"%s\",", Cluster_node->ip_string);
			fprintf(fpa, "no-port-forwarding,no-X11-forwarding,no-agent-forwarding %s\n",
 				Cluster_node->ssh_pub_key_rsa);
			fprintf(fpa, "from=\"%s\",", Cluster_node->ip_string);
			fprintf(fpa, "no-port-forwarding,no-X11-forwarding,no-agent-forwarding %s\n",
				Cluster_node->ssh_pub_key_dsa);
			Cluster_node->set_ssh_auth = 1;
			counta++;
		}
		if(Cluster_node->set_ssh_known == 0) {
			fprintf(fpk, "# chaos-%x\n", ntohl(Cluster_node->addr.s_addr));
			fprintf(fpk, "%s %s\n",
				Cluster_node->ip_string, Cluster_node->ssh_pub_key_rsa);
			fprintf(fpk, "%s %s\n",
				Cluster_node->ip_string, Cluster_node->ssh_pub_key_dsa);
			Cluster_node->set_ssh_known = 1;
			countk++;
		}
		Cluster_node = Cluster_node->next;
	}

	fclose(fpa);
	fclose(fpk);


	if(counta > countk)
		return(counta);

	return(countk);
}



// presumption of a valid path for ntpdc and ntpdate
int
fs_set_ntp(void)
{
	struct cluster_node *Cluster_node;
	int count;
	char cmd[128];

	// disable ntp
	return(0);

	count = 0;
	Cluster_node = cluster_node_ptr;

	while (Cluster_node->next != NULL) {
		if(Cluster_node->set_ntp == 0) {
			// virgin? may not be so good on the first
			// cluster node meeting the second .. hmm ..
			if(count == 0) {
				memset(cmd, 0, 128);
				snprintf(cmd, 127, "ntpdate -t 2 %s", Cluster_node->ip_string);
				if (spawn(cmd, 1) <= 0)
					printf("%s: ntpdate failed\n", whoami);
			}
			memset(cmd, 0, 128);
			snprintf(cmd, 127, "ntpdc -c \"addpeer %s\"", Cluster_node->ip_string);
			if (spawn(cmd, 1) <= 0)
				return(-1);
			Cluster_node->set_ntp = 1;
			count++;
		}
		Cluster_node = Cluster_node->next;
	}

	return (count);
}


int
cfg_read(int what)
{
	FILE *fp;
	char buf[2048];
	int lineno = 0;
	char *s, *p;


	if ((fp = fopen(config_cfg_file, "r")) == NULL) {
		if(what != 1)
			printf("%s: warning, unable to open: %s\n", whoami, config_cfg_file);
		return -1;
	}


	// DEFAULTS
	memset(cfg_mod_sbindir,      0, 128);
	memset(cfg_ipsec_execdir,    0, 128);
	memset(cfg_ipsec_libdir,     0, 128);
	memset(cfg_ipsec_sbindir,    0, 128);
	memset(cfg_ipsec_confdir,    0, 128);
	memset(cfg_ipsec_ctlbase,    0, 128);
	memset(cfg_iptables_sbindir, 0, 128);
	memset(cfg_net_sbindir,      0, 128);
	memset(cfg_ssh_rsa_pubkey_f, 0, 128);
	memset(cfg_ssh_dsa_pubkey_f, 0, 128);
	memset(cfg_ssh_authorized_f, 0, 128);
	memset(cfg_ssh_knownhosts_f, 0, 128);

	strcpy(cfg_mod_sbindir,      "/sbin");
	strcpy(cfg_ipsec_execdir,    "/libexec/ipsec");
	strcpy(cfg_ipsec_libdir,     "/lib/ipsec");
	strcpy(cfg_ipsec_sbindir,    "/sbin");
	strcpy(cfg_ipsec_confdir,    "/etc");
	strcpy(cfg_ipsec_ctlbase,    "/var/run/pluto");
	strcpy(cfg_iptables_sbindir, "/sbin");
	strcpy(cfg_net_sbindir,      "/sbin");
	strcpy(cfg_ssh_rsa_pubkey_f, "/etc/ssh/ssh_host_rsa_key.pub");
	strcpy(cfg_ssh_dsa_pubkey_f, "/etc/ssh/ssh_host_dsa_key.pub");
	strcpy(cfg_ssh_authorized_f, "/etc/ssh/authorized_keys");
	strcpy(cfg_ssh_knownhosts_f, "/root/.ssh/known_hosts");

	cfg_ipsec_probeme = 0;


	p = buf;
	while(fgets(p, sizeof(buf) - (p - buf), fp)) {
		if(what == 1) {
			printf("%s", p);
		} else {
			lineno++;
			if (p[0] == '#' || p[0] == '\n') continue;
			s = p + strlen(p);
			if (s > p && *--s == '\n' && *--s == '\\') {
				p = s;
				continue;
			}
			if (buf[0] == '\n' || buf[0] == 0) {
				p = buf;
				continue;
			}
			if (cfg_parseline(buf) < 0) {
				printf("%s[%d]: syntax error\n", config_cfg_file, lineno);
			}
			p = buf;
		}
	}
	return 0;
}


int
usage(int errlvl, char * runbin) {
	// how many printf's must a man print out, before he is truly a man .. 
	printf("\n");

	// errlvl 0 is the nice one where the user really just wanted a chat ..
	if(errlvl == 0) {
		printf("%s: Usage;\n\n", whoami);
		printf("  The first node in the cluster runs the daemon without parameters (as\n");
		printf("  there is no cluster to join);\n\n");
		printf("      [192.168.1.12]# tyd\n");
		printf("\n\n");
		printf("  The second node in the cluster runs the daemon with the IP address of\n");
		printf("  the first node;\n\n");
		printf("      [192.168.1.109]# tyd --master 192.168.1.12\n");
		printf("\n\n");
		printf("  The third node in the cluster runs the daemon as the second did, though\n");
		printf("  it now has the luxury of choice. It can either use the IP of the first\n");
		printf("  node in the cluster, or alternatively, the IP of the second node in\n");
		printf("  the cluster;\n\n");
		printf("      [192.168.1.87]# tyd --master 192.168.1.12\n");
		printf("      [192.168.1.87]# tyd --master 192.168.1.109\n");
		printf("\n\n");
		printf("  And so on.\n");
		printf("\n\n");
	}

	// anything else and he's down to business
	printf("%s: Parameters;\n\n", whoami);
	printf("  Long         Short Args\n");
	printf("  ~~~~         ~~~~~ ~~~~\n");
	printf("  --crypto     -c    off        Disable cryptography\n");
	// printf("                     XOR        Enable XOR layer-4 cryptography\n");
	printf("                     IPSEC      Enable IPSEC layer-3 cryptography (def)\n");
	printf("  --debug      -D               Enable debugging\n");
	printf("  --filter     -f    init       Initialise filtering as-is and exit\n");
	printf("                     off        Disable packet filtering\n");
	printf("                     on         Enable packet filtering (def)\n");
	printf("                     allow-getm Allow 2727-2728/udp in/out\n");
	printf("                     allow-http Allow inbound 80/tcp\n");
	printf("                     allow-seti Allow outbound 80/tcp\n");
	printf("                     allow-sshd Allow inbound 22/tcp\n");
	printf("                     allow-ssh  Allow outbound 22/tcp\n");
	// printf("                     allow-dhcp Allow inbound 67/udp\n");
	printf("  --help       -h               Display this help screen\n");
	printf("  --interface  -i    {if}       Use interface \"if\" (def: eth0)\n");
	printf("  --ipsec-presharedkey\n");
	printf("               -ipsk {\"string\"} Set PSK to \"string\" (def: see below)\n");
	printf("  --master     -m    {ip}       Join cluster at \"ip\"\n");
	printf("                                value of \"any\" or \"multicast\" will use get-m\n");
	printf("                                Note: absent -m makes this node a master\n");
	printf("  --print-cfg  -pc              Print the cfg file contents and exit\n");
	printf("  --pxe-master -pm              This node is a network (PXE) master node\n");
	printf("  --silent     -s               No noisy initialisation\n");
	printf("  --version    -V               Display version and exit\n");
	// printf("  --xor-block-size\n");
	// printf("               -xbs  {num}      Set crypt block size to \"num\" (def: 3)\n");
	// printf("  --xor-key    -xk   {\"string\"} Set crypt key to \"string\" (def: see below)\n");
	printf("\n\n");
	printf("  Default keys are: \"%s\"\n", DEF_KEY);
	printf("  Default config file is: \"%s\"\n", config_cfg_file);
	printf("  Default info file is: \"%s\"\n\n", config_gtm_file);

	printf("  To disable ty-d and run omdiscd perform the following;\n\n");
	printf("      %s --filter off --filter init\n", runbin);
	printf("      omdiscd\n");
	printf("\n\n");

	/*
	if(errlvl == 0) {
		printf("  NB: There is a limit of about 255 nodes that can be supported in any\n");
		printf("  single cluster.\n");
		printf("\n\n");
	}
	*/

	// the answer, my friend, is exit number one ... the answer is exit number one ..
	exit(errlvl);
}



void
parse_args(int argc, char** argv) {
	int argn;

	config_netfilter_enabled = 1;
	// disable ntp
	config_netfilter_ntp = 0;
	config_netfilter_getm = 0;
	config_netfilter_dhcp_in = 0;
	config_netfilter_http_out = 0;
	config_netfilter_http_in = 0;
	config_netfilter_ssh_in = 0;
	config_netfilter_ssh_out = 0;
	config_netfilter_init = 0;
	config_debug = 0;
	config_getm = 0;
	config_master_node = NULL;
	config_print_cfg = 0;
	config_pxe_master = 0;
	config_silent = 0;

	// default interface
	memset(config_interface, 0, 32);
	strncpy(config_interface, "eth0", 32);
	memset(config_ipsec_interface, 0, 32);
	strncpy(config_ipsec_interface, "ipsec0", 32);

	// default crypto settings (love default security params) ..
	config_crypto_enabled = CRYPT_IPSEC;
	config_xor_block_size = 3;
	memset(config_xor_key, 0, 2048);
	strncpy(config_xor_key, DEF_KEY, 2048);
	memset(config_ipsec_psk, 0, 2048);
	strncpy(config_ipsec_psk, DEF_KEY, 2048);

	argn = 1;
	while (argn < argc && argv[argn][0] == '-') {
		// -c, --crypto
		if ((strcmp(argv[argn], "-c") == 0 || strcmp(argv[argn], "--crypto") == 0)
			 && argn + 1 < argc) {
			++argn;
			// off
			if (strcmp(argv[argn], "off") == 0) {
				config_crypto_enabled = 0;
			}
			// XOR
			else if (strcmp(argv[argn], "XOR") == 0) {
				config_crypto_enabled = CRYPT_XOR;
			}
			// XORCONN
			/* else if (strcmp(argv[argn], "XORCONN") == 0) {
				config_crypto_enabled = CRYPT_XORCONN;
			} */
			// IPSEC
			else if (strcmp(argv[argn], "IPSEC") == 0) {
				config_crypto_enabled = CRYPT_IPSEC;
			}
			// doh
			else {
				printf("%s: Unrecognised command parameter [%s], for [%s], exiting.\n",
						 whoami, argv[argn], argv[argn - 1]);
				usage(1, argv[0]);
			}
		}
		// -D, --debug
		else if (strcmp(argv[argn], "-D") == 0 || strcmp(argv[argn], "--debug") == 0) {
			config_debug = 1;
			printf("%s: Note that the [%s] command is only partially implemented.\n", whoami, argv[argn]);
		}
		// -f, --filter
		else if ((strcmp(argv[argn], "-f") == 0 || strcmp(argv[argn], "--filter") == 0)
			 && argn + 1 < argc) {
			++argn;
			// init
			if (strcmp(argv[argn], "init") == 0) {
				config_netfilter_init = 1;
			}
			// off
			else if (strcmp(argv[argn], "off") == 0) {
				config_netfilter_enabled = 0;
			}
			// on
			else if (strcmp(argv[argn], "on") == 0) {
				config_netfilter_enabled = 1;
			}
			// allow-dhcp
			else if (strcmp(argv[argn], "allow-dhcp") == 0) {
				config_netfilter_dhcp_in = 1;
			}
			// allow-getm
			else if (strcmp(argv[argn], "allow-getm") == 0) {
				config_netfilter_getm = 1;
			}
			// allow-http
			else if (strcmp(argv[argn], "allow-http") == 0) {
				config_netfilter_http_in = 1;
			}
			// allow-seti
			else if (strcmp(argv[argn], "allow-seti") == 0) {
				config_netfilter_http_out = 1;
			}
			// allow-sshd
			else if (strcmp(argv[argn], "allow-sshd") == 0) {
				config_netfilter_ssh_in = 1;
			}
			// allow-ssh
			else if (strcmp(argv[argn], "allow-ssh") == 0) {
				config_netfilter_ssh_out = 1;
			}
			// doh
			else {
				printf("%s: Unrecognised command parameter [%s], for [%s], exiting.\n",
						 whoami, argv[argn], argv[argn - 1]);
				usage(1, argv[0]);
			}
		}
		// -h, --help
		else if (strcmp(argv[argn], "-h") == 0 || strcmp(argv[argn], "--help") == 0) {
			usage(0, argv[0]);
		}
	 	// -i, --interface
		else if ((strcmp(argv[argn], "-i") == 0 || strcmp(argv[argn], "--interface") == 0)
			 && argn + 1 < argc) {
			++argn;
			strncpy(config_interface, argv[argn], 32);
		}
		// -ipsk, --ipsec-presharedkey
		else if ((strcmp(argv[argn], "-ipsk") == 0 || strcmp(argv[argn], "--ipsec-presharedkey") == 0)
			 && argn + 1 < argc) {
			++argn;
			strncpy(config_ipsec_psk, argv[argn], 2048);
		}
	 	// -m, --master
		else if ((strcmp(argv[argn], "-m") == 0 || strcmp(argv[argn], "--master") == 0)
			 && argn + 1 < argc) {
			++argn;
			if(strcmp(argv[argn], "any") == 0 || strcmp(argv[argn], "multicast") == 0)
			{
				config_getm = 1;
				config_netfilter_getm = 1;
			} else {
				config_master_node = gethostbyname(argv[argn]);
    				if (config_master_node == NULL)
    				{
        				printf("%s: invalid IP address [%s]!\n", whoami, argv[argn]);
        				exit(1);
    				}
			}
		}
		// -pc, --print-cfg
		else if (strcmp(argv[argn], "-pc") == 0 || strcmp(argv[argn], "--print-cfg") == 0) {
			config_print_cfg = 1;
		}
		// -pm, --pxe-master
		else if (strcmp(argv[argn], "-pm") == 0 || strcmp(argv[argn], "--pxe-master") == 0) {
			config_pxe_master = 1;
			// printf("%s: Note that PXE boot master is not currently implemented.\n", whoami);
		}
		// -s, --silent
		else if (strcmp(argv[argn], "-s") == 0 || strcmp(argv[argn], "--silent") == 0) {
			config_silent = 1;
		}
		// -V, --version
		else if (strcmp(argv[argn], "-V") == 0 || strcmp(argv[argn], "--version") == 0) {
			printf("%s\n", E_VERSION);
			exit(0);
		}
		// -xbs, --xor-block-size
		else if ((strcmp(argv[argn], "-xbs") == 0 || strcmp(argv[argn], "--xor-block-size") == 0)
			 && argn + 1 < argc) {
			++argn;
			config_xor_block_size = atoi(argv[argn]);
		}
		// -xk, --xor-key
		else if ((strcmp(argv[argn], "-xk") == 0 || strcmp(argv[argn], "--xor-key") == 0)
			 && argn + 1 < argc) {
			++argn;
			strncpy(config_xor_key, argv[argn], 2048);
		}
		// doh
		else {
			printf("%s: Unrecognised command parameter [%s], exiting.\n", whoami, argv[argn]);
			usage(1, argv[0]);
		}
		++argn;
	}
	if ( argn != argc )
		usage(1, argv[0]);
}



int
main(int argc, char **argv) {

        int cnt, i, j, k;
	int map_row, map_col, map_status;
	struct in_addr master_node;
        struct mosixnet map[MAX_MOSNET_ENTS];
        net_params_t net_handle;
        int num, val, stripnl;
	int opt_mcast_ttl;
	int have_map, have_valid_map;
	int have_notified_all_nodes;
	char cmd[4096];
	char readbuf[255];
	int  cmd_sz = 4096;
	char cmd_buf[1024];
	char cmd_getgw[128] = "%s/ip route list match 0.0.0.0/0 dev %s";
	char ifs[20];
	char *if_names = NULL;
	uint32_t addr;
	struct sigaction sa;
	char server_ip[64];
	char client_ip[64];
	struct in_addr node;
	FILE *getm_fd;






	val = 1;
	opt_mcast_ttl = 0;


        if (getuid() != 0) {
                printf("%s: Only user id 0 can run this program (you are %d).  Exiting.\n", whoami, getuid());
                exit(1);
        }


	config_ssh_pubkey_share = 1;
	cluster_node_ptr = (struct cluster_node *) malloc(sizeof(struct cluster_node));

	cfg_read(0);
	parse_args(argc, argv);

	/* just dumping config file ? */
	if(config_print_cfg)
	{
		cfg_read(1);
		exit(0);
	}


	/* Initialize the stinky environment variabled .. */	
	snprintf(env_ipsec_execdir, 128, "IPSEC_EXECDIR=\"%s\"", cfg_ipsec_execdir);
	snprintf(env_ipsec_libdir,  128, "IPSEC_LIBDIR=\"%s\"",  cfg_ipsec_libdir);
	snprintf(env_ipsec_sbindir, 128, "IPSEC_SBINDIR=\"%s\"", cfg_ipsec_sbindir);
	snprintf(env_ipsec_confdir, 128, "IPSEC_CONFS=\"%s\"",   cfg_ipsec_confdir);

	// Why - oh why - art'st thou so evil!? //

	// putenv(env_ipsec_execdir);
	// putenv(env_ipsec_libdir);
	// putenv(env_ipsec_sbindir);
	// putenv(env_ipsec_confdir);


        /* Initialize network transport */
	strncpy(ifs, config_interface, 20);
        if (net_initialize(&net_handle, ifs, opt_mcast_ttl) == NET_FAIL)
	{
                printf("%s: Unable to initialise network.  Exiting.\n", whoami);
                exit(1);
        }


	if(config_crypto_enabled == CRYPT_XOR)
	{
		if(!config_silent)
			printf("%s: crypt type XOR will be used.\n", whoami);
	}
	else if(config_crypto_enabled == CRYPT_IPSEC)
	{
		if(!config_silent)
			printf("%s: crypt type IPSEC will be used.\n", whoami);

		// ipsec exists outside the routing structure of the
		// kernel .. .: we need to specify dflt gw ents on the
		// cmd line ... and this was the only way we knew to 
		// get the default gw given an interface
		memset(cmd_buf, 0, 256);
		memset(cmd, 0, cmd_sz);
		snprintf(cmd, cmd_sz, cmd_getgw, cfg_net_sbindir, config_interface);
		fd_gw = popen(cmd, "r");
		fgets(cmd_buf, 256, fd_gw);
		pclose(fd_gw);
		if(strlen(cmd_buf) > 16)
		{
			cmd_buf[strlen(cmd_buf) - 2] = '\0';
			snprintf(our_gw_addr, 64, &cmd_buf[12]);
			if(!config_silent)
				printf("%s: This default gateway will be used [%s]\n", whoami, our_gw_addr);
		}
		else
		{
			printf("%s: Unable to obtain default gateway on interface [%s].\n",
				whoami, config_interface);
			exit(1);
		}
	}
	else
	{
		if(!config_silent)
			printf("%s: no encryption will be used.\n", whoami);
	}



	/*
	 *  the logic in here is a bit screwy .. why do we need a relationship between 
	 *  "--filter init" and all else?  gotta stop writing critical code at 3am ..
	 */

	/* init iptables */
	if(config_netfilter_init) {

		/* disable iptables */
		if(!config_netfilter_enabled) {
			if(do_iptables("", "0.0.0.0/0", "", "0.0.0.0/0", "", DIR_VOID, OPT_ALLOW) != OPENMOSIX_SUCCESS)
			{
				printf("%s: Unable to disable netfilter.  Exiting.\n", whoami);
				exit(1);
			}
			if(!config_silent)
				printf("%s: Successfully disabled netfilter.\n", whoami);
			exit(0);
		} else {
			memset(server_ip, 0, 64);
			snprintf(server_ip, 64, "%s/32", inet_ntoa(*(struct in_addr*)&our_eth0_addr.s_addr));
			if(do_iptables("", "0.0.0.0/0", "", server_ip, "", DIR_VOID, OPT_RESET) != OPENMOSIX_SUCCESS)
			{
				printf("%s: Unable to initialise netfilter.  Exiting.\n", whoami);
				exit(1);
			}
			/*
			 -- must be done after map is added .. see map_to_ ..
			if(config_crypto_enabled == CRYPT_IPSEC) {
				if(do_iptables("", "0.0.0.0/0", "", server_ip, "", DIR_VOID, OPT_GOLOG)
					!= OPENMOSIX_SUCCESS)
				{
					printf("%s: Unable to initialise netfilter.  Exiting.\n", whoami);
					exit(1);
				}
			}
			*/
			if(!config_silent)
				printf("%s: Successfully initialised netfilter.\n", whoami);
		}

		/* init crypto */
		if(config_crypto_enabled) {
			if(config_crypto_enabled == CRYPT_IPSEC)
			{

        			/*
         			 *      Make /etc/ipsec.secrets
         			 */
        			if((fd_hosts = fopen(file_secrets, "w+")) == NULL) {
					printf("%s: Unable to initialise /etc/ipsec.secrets (read only?)\n", whoami);
					exit(1);
				}
				fprintf(fd_hosts, "# ipsec on %s\n", config_interface);
				fprintf(fd_hosts, "%-20.20s %%any: PSK \"%s\"\n",
					inet_ntoa(*(struct in_addr*)&our_eth0_addr.s_addr), config_ipsec_psk);
                		fclose(fd_hosts);
                		sync();
                		sync();

				ipsec(IPSEC_INI, NULL);

			}
			else
			{
				// catch all .. rather than crypt per new node ... should be faster and as effective
                        	// node.s_addr = our_eth0_addr.s_addr;
                        	node.s_addr = 0;
                        	if(node_to_iptables(&node, OPT_CRYPT) == OPENMOSIX_FAIL) {
					printf("%s: Unable to initialise layer-4 cryptography.\n", whoami);
					exit(1);
				}
			}

			if(!config_silent)
				printf("%s: Successfully initialised cryptography.\n", whoami);
		}
		exit(0);
	}



	// there is a presumption here that this daemon will only be run once ..
        net_get_if_addrs(&net_handle, our_if_addrs, &num);
	if (openmosix_initialize(our_if_addrs, num) == OPENMOSIX_FAIL) {
		printf("%s: Unable to initialise openMosix (Try \"setpe -off\").  Exiting.\n", whoami);
		exit(1);
	}



	// daemonize code (flogged from thttpd)
	switch ( fork() ) {
		case 0:
			break;
		case -1:
			// syslog( 1, "fork - %m" );
			exit(1);
		default:
			exit(0);
	}


	// get phillip going .. once we start being added to maps we are able to be polled ..
	init_phillip();


	// more new code!?  Bruce will be beside himself ;-)
	// straight-forward stuff ... use the multicast helper to find a local master
	if(config_getm) {
		for(j = 0; (j < 5 && config_master_node == NULL); j++) {
			memset(readbuf, 0, 255);
			if ((getm_fd = fopen(config_gtm_file, "r")) != NULL) {
				while(fgets(readbuf, 254, getm_fd) != NULL) {
					if(strlen(readbuf) < 2)
						continue;
					// dastardly new line -- *yoink*
					stripnl = strlen(readbuf) - 1;
					readbuf[stripnl] = '\0';
					if(config_debug)
						printf("%s: read entry [%s] from [%s]\n", whoami,
							readbuf, config_gtm_file);
					if((config_master_node = gethostbyname(readbuf)) != NULL) {
						if(!config_silent)
							printf("%s: master node found [%s].\n",
								whoami, config_master_node);
						break;
					}
				}
				fclose(getm_fd);
			}
			if(config_master_node == NULL) {
				if(!config_silent)
					printf("%s: no master node found, sleeping.\n", whoami);
				sleep(5);
			}
		}
	}


	// if we have a master node .. then terrence the heck out of it ..
	if(config_master_node != NULL) {

		map_row = 0;
		map_col = 0;
		have_map = 0;
		have_valid_map = 0;
		have_notified_all_nodes = 0;

		memcpy(&(master_node.s_addr),*(config_master_node->h_addr_list),sizeof(struct in_addr));

		for(i = 0; (i < 5 && have_map == 0 && have_valid_map == 0); i++) {

			if(!have_map || !have_valid_map)
			{
				printf("%s: trying node [%s] for mapme.\n",
					whoami, inet_ntoa(*(struct in_addr*)&master_node.s_addr));
				for(j = 0; (j < 3 && have_map == 0); j++)
				{
					if(init_terrence(&master_node, map, &cnt) == 0)
					{
						if(config_debug)
							printf("%s: success with node [%s] for mapme.\n",
						 		whoami, inet_ntoa(*(struct in_addr*)&master_node.s_addr));
						have_map = 1;
						have_valid_map = 0;
						have_notified_all_nodes = 0;
						// map_row = 0;
						// map_col = 0;
					}
				}
			}

			// t_printmap(map, cnt);
			if(have_map && !have_valid_map)
			{
				// printf("%s: map found, running addme effort.\n", whoami);


				// host for future inquisitions - should start at (0,0)
				addr = next_map_ent(map, &map_row, &map_col, &cnt);

				if(config_debug)
					printf("%s: will attempt to use address [%s] as a future master.\n",
				 		whoami, inet_ntoa(*(struct in_addr*)&addr));

				// not i
				if(addr == our_eth0_addr.s_addr)
				{
					printf("%s: this address [%s] is ours .. skipping.\n",
						whoami, inet_ntoa(*(struct in_addr*)&addr));
					addr = next_map_ent(map, &map_row, &map_col, &cnt);
				}

               			master_node.s_addr = addr;

				for(j = 0; (j < 3 && have_valid_map == 0); j++)
				{
					// printf("%s: running retry loop for pullmy ..\n", whoami);
					map_status = pullmyfinger_terrence(map, &cnt, OPT_ADDME);
					if(map_status == 0)
					{
						printf("%s: addme worked completely.\n", whoami);
						have_valid_map = 1;
						have_notified_all_nodes = 1;
					}
					if(map_status > 0)
					{
						printf("%s: addme worked, but not entirely.\n", whoami);
						have_valid_map = 1;
						have_notified_all_nodes = 0;
					}
				}
			}
			else
			{
				printf("%s: FATAL - unable to acquire mosix map. Exiting.\n", whoami);
				exit(1);
			}
		}
		if(!have_map || !have_valid_map) {
			printf("%s: FATAL - unable to acquire an accurate mosix map. Exiting.\n", whoami);
			exit(1);
		}
		if(!have_notified_all_nodes) {
			printf("%s: WARNING - acquired mosix map but could not contact all nodes.\n", whoami);
		}
	}


	// if we added ok .. then we need to allow for rapid removal ..
	SETSIG(sa, SIGTERM,  signal_handler, 0);

	if(config_crypto_enabled == CRYPT_IPSEC)
		do_iptables("", "0.0.0.0/0", "", server_ip, "", DIR_VOID, OPT_GOLOG);

	if(!config_silent)
		printf("%s: terrence completed, starting phillip.\n", whoami);
	exit(pullmyfinger_phillip());

}

