Exemplo n.º 1
0
/**
 * DHCP manual mode handler.
 * - Blocking Function
 * - Used only at DHCP manual mode (DHCP mode could be chosen at wizconfig.h file)
 * - DHCP_MANUAL mode does not need a loop structure, but if there is no loop structure, \n
 *    you should handle renew & rebind with your own way, or just ignore renew & rebind action
 *
 * @param action The action you want to do. (@ref dhcp_action)
 * @param renew For returning renew time when DHCP be bound (NULL will be ignored)
 * @param rebind For returning rebind time when DHCP be bound (NULL will be ignored)
 * @return RET_OK: Success
 * @return RET_NOK: Error
 */
int8 dhcp_manual(dhcp_action action, uint32 *renew, uint32 *rebind)	// blocking function
{
	dhcp_state curstt = di.state;

	if(dhcp_alarm == TRUE) return RET_NOK;

	while(curstt != DHCP_STATE_INIT && curstt != DHCP_STATE_BOUND) {
		dhcp_run();
		curstt = di.state;
	}

	if(curstt == DHCP_STATE_INIT) {
		di.action = DHCP_ACT_START;
		memset(&workinfo, 0, sizeof(workinfo));
		workinfo.dhcp = NETINFO_DHCP;
		SetNetInfo(&workinfo);
		
		// ToDo: Set zero IP & SN
		
		do {
			dhcp_run();
			curstt = di.state;
		} while((curstt != DHCP_STATE_INIT || di.action != DHCP_ACT_START) 
			&& curstt != DHCP_STATE_BOUND);
		if(curstt != DHCP_STATE_BOUND) return RET_NOK;
		if(renew) *renew = di.renew_time;
		if(rebind) *rebind = di.rebind_time;
	} else if(curstt == DHCP_STATE_BOUND) {
		if(action == DHCP_ACT_START) {
			if(renew) *renew = 0;
			if(rebind) *rebind = 0;
			return RET_OK;
		} else if(action == DHCP_ACT_RENEW) {	// renew
			SET_STATE(DHCP_STATE_SELECTING);
			di.action = DHCP_ACT_RENEW;
			di.xid++;
		} else if(action == DHCP_ACT_REBIND) {	// rebind
			SET_STATE(DHCP_STATE_SELECTING);
			di.action = DHCP_ACT_REBIND;
			di.xid++;
		} else {
			ERRA("wrong action(%d)", action);
			return RET_NOK;
		}
		curstt = di.state;
		while(curstt != DHCP_STATE_INIT && curstt != DHCP_STATE_BOUND) {
			dhcp_run();
			curstt = di.state;
		}
		if(curstt != DHCP_STATE_BOUND) return RET_NOK;
		if(renew) *renew = di.renew_time;
		if(rebind) *rebind = di.rebind_time;
	}

	return RET_OK;
}
Exemplo n.º 2
0
int8 dhcp_manual(int8 action, uint8 *saved_ip, uint32 *renew, uint32 *rebind)	// blocking function
{
	int8 curstt = dhcp_get_state();

	if(dhcp_alarm == TRUE) return RET_NOK;

	while(curstt != DHCP_STATE_INIT && curstt != DHCP_STATE_BOUND) {
		dhcp_run();
		curstt = dhcp_get_state();
	}

	if(curstt == DHCP_STATE_INIT) {
		di.action = DHCP_ACT_START;
		memset(&workinfo, 0, sizeof(workinfo));
		if(saved_ip) memcpy(workinfo.IP, saved_ip, 4);
		workinfo.DHCP = NETINFO_DHCP_BUSY;
		SetNetInfo(&workinfo);
		do {
			dhcp_run();
			curstt = dhcp_get_state();
		} while((curstt != DHCP_STATE_INIT || workinfo.DHCP == NETINFO_DHCP_BUSY) 
			&& curstt != DHCP_STATE_BOUND);
		if(curstt != DHCP_STATE_BOUND) return RET_NOK;
		if(renew) *renew = di.renew_time;
		if(rebind) *rebind = di.rebind_time;
	} else if(curstt == DHCP_STATE_BOUND) {
		if(action == DHCP_ACT_START) {
			if(renew) *renew = 0;
			if(rebind) *rebind = 0;
			return RET_OK;
		} else if(action == DHCP_ACT_RENEW) {	// renew
			SET_STATE(DHCP_STATE_SELECTING);
			di.action = DHCP_ACT_RENEW;
			di.xid++;
		} else if(action == DHCP_ACT_REBIND) {	// rebind
			SET_STATE(DHCP_STATE_SELECTING);
			di.action = DHCP_ACT_REBIND;
			di.xid++;
		} else {
			ERRA("wrong action(%d)", action);
			return RET_NOK;
		}
		curstt = dhcp_get_state();
		while(curstt != DHCP_STATE_INIT && curstt != DHCP_STATE_BOUND) {
			dhcp_run();
			curstt = dhcp_get_state();
		}
		if(curstt != DHCP_STATE_BOUND) return RET_NOK;
		if(renew) *renew = di.renew_time;
		if(rebind) *rebind = di.rebind_time;
	}

	return RET_OK;
}
Exemplo n.º 3
0
static void dhcp_alarm_cb(int8 arg)	// for DHCP auto mode
{
	if(dhcp_alarm == FALSE) return;
	if(arg == 0) {
		if(di.state == DHCP_STATE_BOUND) {
			alarm_set(wizpf_tick_conv(FALSE, di.renew_time), dhcp_alarm_cb, 1);
			alarm_set(wizpf_tick_conv(FALSE, di.rebind_time), dhcp_alarm_cb, 2);
		}
		if(di.state == DHCP_STATE_FAILED) {
			di.state = DHCP_STATE_INIT;
			di.action = DHCP_ACT_START;
		}
		dhcp_run();
	} else if(arg == 1) {	// renew
		SET_STATE(DHCP_STATE_SELECTING);
		di.action = DHCP_ACT_RENEW;
		di.xid++;
		alarm_set(10, dhcp_alarm_cb, 0);
	} else if(arg == 2) {	// rebind
		SET_STATE(DHCP_STATE_SELECTING);
		di.action = DHCP_ACT_REBIND;
		di.xid++;
		alarm_set(10, dhcp_alarm_cb, 0);
	}
}
Exemplo n.º 4
0
static void dhcp_alarm_cb(int8 arg)	// for alarm mode
{
	if(dhcp_alarm == FALSE) return;
	if(arg == 0) {
		if(workinfo.DHCP == NETINFO_DHCP_FAIL) {
			workinfo.DHCP = NETINFO_DHCP_BUSY;
			di.action = DHCP_ACT_START;
		}
		if(dhcp_get_state() == DHCP_STATE_IP_CHECK) {
			alarm_set(wizpf_tick_conv(FALSE, di.renew_time), dhcp_alarm_cb, 1);
			alarm_set(wizpf_tick_conv(FALSE, di.rebind_time), dhcp_alarm_cb, 2);
		}
		dhcp_run();
	} else if(arg == 1) {	// renew
		SET_STATE(DHCP_STATE_SELECTING);
		di.action = DHCP_ACT_RENEW;
		di.xid++;
		alarm_set(10, dhcp_alarm_cb, 0);
	} else if(arg == 2) {	// rebind
		SET_STATE(DHCP_STATE_SELECTING);
		di.action = DHCP_ACT_REBIND;
		di.xid++;
		alarm_set(10, dhcp_alarm_cb, 0);
	}
}
Exemplo n.º 5
0
int main(void)
{
#define TCP_LISTEN_PORT	5000
#define UDP_LISTEN_PORT	5000

	int8 ret, root;
	uint32 tick = 0;

	ret = platform_init();
	if(ret != RET_OK) {
		goto FAIL_TRAP;
	}

	ret = network_init(SOCK_DHCP, NULL, NULL);
	if(ret != RET_OK) {
		ERRA("network_init fail - ret(%d)", ret);
		goto FAIL_TRAP;
	}

	printf("\r\n-----------------------------------\r\n");
	printf("SMTP Client using W5200\r\n");
	printf("-----------------------------------\r\n\r\n");

	menu_init();
	root = menu_add("Network setting", 0, NULL);
	menu_add("Show", root, mn_show_network);
	menu_add("Static Set", root, mn_set_network);
	menu_add("Loopback", 0, mn_loopback);
	menu_add("LED Test", 0, mn_set_led);
	root = menu_add("App Test", 0, NULL);
	menu_add("DNS", root, mn_dns);
	menu_add("BASE64", root, mn_base64);
	menu_add("eMail", root, mn_email);

	menu_print_tree();

	while(1) {
#if (USE_DHCP == VAL_ENABLE)
		dhcp_run();
#endif
		menu_run();
		if(lb_tcp) loopback_tcps(7, (uint16)TCP_LISTEN_PORT);
		if(lb_udp) loopback_udp(7, (uint16)UDP_LISTEN_PORT);
		if(wizpf_tick_elapse(tick) > 1000) {
			wizpf_led_act(WIZ_LED3, VAL_TOG);
			tick = wizpf_get_systick();
		}
	}

FAIL_TRAP:
	wizpf_led_trap(10);

}
Exemplo n.º 6
0
int main(int argc, char **argv)
{
	options_t options;
	int doversion = 0;
	int dohelp = 0;
	int userclasses = 0;
	int opt;
	int option_index = 0;
	char prefix[IF_NAMESIZE + 3];
	pid_t pid;
	int debug = 0;
	int i;
	int pidfd = -1;
	int sig = 0;

	const struct option longopts[] = {
		{"arp",         no_argument,        NULL, 'a'},
		{"script",      required_argument,  NULL, 'c'},
		{"debug",       no_argument,        NULL, 'd'},
		{"hostname",    optional_argument,  NULL, 'h'},
		{"classid",     optional_argument,  NULL, 'i'},
		{"release",     no_argument,        NULL, 'k'},
		{"leasetime",   required_argument,  NULL, 'l'},
		{"metric",      required_argument,  NULL, 'm'},
		{"renew",       no_argument,        NULL, 'n'},
		{"persistent",  no_argument,        NULL, 'p'},
		{"inform",      optional_argument,  NULL, 's'},
		{"request",     optional_argument,  NULL, 'r'},
		{"timeout",     required_argument,  NULL, 't'},
		{"userclass",   required_argument,  NULL, 'u'},
		{"exit",        no_argument,        NULL, 'x'},
		{"lastlease",   no_argument,        NULL, 'E'},
		{"fqdn",        required_argument,  NULL, 'F'},
		{"nogateway",   no_argument,        NULL, 'G'},
		{"sethostname", no_argument,        NULL, 'H'},
		{"clientid",    optional_argument,  NULL, 'I'},
		{"noipv4ll",	no_argument,		NULL, 'L'},
		{"nomtu",       no_argument,        NULL, 'M'},
		{"nontp",       no_argument,        NULL, 'N'},
		{"nodns",       no_argument,        NULL, 'R'},
		{"test",        no_argument,        NULL, 'T'},
		{"nonis",       no_argument,        NULL, 'Y'},
		{"help",        no_argument,        &dohelp, 1},
		{"version",     no_argument,        &doversion, 1},
		{NULL,          0,                  NULL, 0}
	};

	/* Close any un-needed fd's */
	for (i = getdtablesize() - 1; i >= 3; --i)
		close (i);

	openlog (PACKAGE, LOG_PID, LOG_LOCAL0);

	memset (&options, 0, sizeof (options_t));
	options.script = (char *) DEFAULT_SCRIPT;
	snprintf (options.classid, CLASS_ID_MAX_LEN, "%s %s", PACKAGE, VERSION);
	options.classid_len = strlen (options.classid);

	options.doarp = true;
	options.dodns = true;
	options.domtu = true;
	options.donis = true;
	options.dontp = true;
	options.dogateway = true;
	options.daemonise = true;
	options.doinform = false;
	options.doipv4ll = true;
	options.timeout = DEFAULT_TIMEOUT;

	gethostname (options.hostname, sizeof (options.hostname));
	if (strcmp (options.hostname, "(none)") == 0 ||
		strcmp (options.hostname, "localhost") == 0)
		memset (options.hostname, 0, sizeof (options.hostname));

	/* Don't set any optional arguments here so we retain POSIX
	 * compatibility with getopt */
	while ((opt = getopt_long(argc, argv, "c:dh:i:kl:m:npr:s:t:u:xAEF:GHI:LMNRTY",
							  longopts, &option_index)) != -1)
	{
		switch (opt) {
			case 0:
				if (longopts[option_index].flag)
					break;
				logger (LOG_ERR, "option `%s' should set a flag",
						longopts[option_index].name);
				exit (EXIT_FAILURE);
				break;
			case 'c':
				options.script = optarg;
				break;
			case 'd':
				debug++;
				switch (debug) {
					case 1:
						setloglevel (LOG_DEBUG);
						break;
					case 2:
						options.daemonise = false;
						break;
				}
				break;
			case 'h':
				if (! optarg)
					memset (options.hostname, 0, sizeof (options.hostname));
				else if (strlen (optarg) > MAXHOSTNAMELEN) {
					logger (LOG_ERR, "`%s' too long for HostName string, max is %d",
							optarg, MAXHOSTNAMELEN);
					exit (EXIT_FAILURE);
				} else
					strlcpy (options.hostname, optarg, sizeof (options.hostname));
				break;
			case 'i':
				if (! optarg) {
					memset (options.classid, 0, sizeof (options.classid));
					options.classid_len = 0;
				} else if (strlen (optarg) > CLASS_ID_MAX_LEN) {
					logger (LOG_ERR, "`%s' too long for ClassID string, max is %d",
							optarg, CLASS_ID_MAX_LEN);
					exit (EXIT_FAILURE);
				} else
					options.classid_len = strlcpy (options.classid, optarg,
												   sizeof (options.classid));
				break;
			case 'k':
				sig = SIGHUP;
				break;
			case 'l':
				STRINGINT (optarg, options.leasetime);
				if (options.leasetime <= 0) {
					logger (LOG_ERR, "leasetime must be a positive value");
					exit (EXIT_FAILURE);
				}
				break;
			case 'm':
				STRINGINT (optarg, options.metric);
				break;
			case 'n':
				sig = SIGALRM;
				break;
			case 'p':
				options.persistent = true;
				break;
			case 's':
				options.doinform = true;
				if (! optarg || strlen (optarg) == 0) {
					options.request_address.s_addr = 0;
					break;
				} else {
					char *slash = strchr (optarg, '/');
					if (slash) {
						int cidr;
						/* nullify the slash, so the -r option can read the
						 * address */
						*slash++ = '\0';
						if (sscanf (slash, "%d", &cidr) != 1) {
							logger (LOG_ERR, "`%s' is not a valid CIDR", slash);
							exit (EXIT_FAILURE);
						}
						options.request_netmask = inet_cidrtoaddr (cidr);
					}
					/* fall through */
				}
			case 'r':
				if (! options.doinform)
					options.dorequest = true;
				if (strlen (optarg) > 0 &&
					! inet_aton (optarg, &options.request_address))
				{ 
					logger (LOG_ERR, "`%s' is not a valid IP address", optarg);
					exit (EXIT_FAILURE);
				}
				break;
			case 't':
				STRINGINT (optarg, options.timeout);
				if (options.timeout < 0) {
					logger (LOG_ERR, "timeout must be a positive value");
					exit (EXIT_FAILURE);
				}
				break;
			case 'u':
				{
					int offset = 0;
					for (i = 0; i < userclasses; i++)
						offset += (int) options.userclass[offset] + 1;
					if (offset + 1 + strlen (optarg) > USERCLASS_MAX_LEN) {
						logger (LOG_ERR, "userclass overrun, max is %d",
								USERCLASS_MAX_LEN);
						exit (EXIT_FAILURE);
					}
					userclasses++;
					memcpy (options.userclass + offset + 1 , optarg, strlen (optarg));
					options.userclass[offset] = strlen (optarg);
					options.userclass_len += (strlen (optarg)) + 1;
				}
				break;
			case 'x':
				sig = SIGTERM;
				break;
			case 'A':
#ifndef ENABLE_ARP
				logger (LOG_ERR, "arp support not compiled into dhcpcd");
				exit (EXIT_FAILURE);
#endif
				options.doarp = false;
				break;
			case 'E':
#ifndef ENABLE_INFO
				logger (LOG_ERR, "info support not compiled into dhcpcd");
				exit (EXIT_FAILURE);
#endif
				options.dolastlease = true;
				break;
			case 'F':
				if (strncmp (optarg, "none", strlen (optarg)) == 0)
					options.fqdn = FQDN_NONE;
				else if (strncmp (optarg, "ptr", strlen (optarg)) == 0)
					options.fqdn = FQDN_PTR;
				else if (strncmp (optarg, "both", strlen (optarg)) == 0)
					options.fqdn = FQDN_BOTH;
				else {
					logger (LOG_ERR, "invalid value `%s' for FQDN", optarg);
					exit (EXIT_FAILURE);
				}
				break;
			case 'G':
				options.dogateway = false;
				break;
			case 'H':
				options.dohostname++;
				break;
			case 'I':
				if (optarg) {
					if (strlen (optarg) > CLIENT_ID_MAX_LEN) {
						logger (LOG_ERR, "`%s' is too long for ClientID, max is %d",
								optarg, CLIENT_ID_MAX_LEN);
						exit (EXIT_FAILURE);
					}
					options.clientid_len = strlcpy (options.clientid, optarg,
													sizeof (options.clientid));
					/* empty string disabled duid */
					if (options.clientid_len == 0)
						options.clientid_len = -1;
				} else {
					memset (options.clientid, 0, sizeof (options.clientid));
					options.clientid_len = -1;
				}
				break;
			case 'L':
				options.doipv4ll = false;
				break;
			case 'M':
				options.domtu = false;
				break;
			case 'N':
				options.dontp = false;
				break;
			case 'R':
				options.dodns = false;
				break;
			case 'T':
#ifndef ENABLE_INFO
				logger (LOG_ERR, "info support not compiled into dhcpcd");
				exit (EXIT_FAILURE);
#endif
				options.test = true;
				options.persistent = true;
				break;
			case 'Y':
				options.donis = false;
				break;
			case '?':
				usage ();
				exit (EXIT_FAILURE);
			default:
				usage ();
				exit (EXIT_FAILURE);
		}
	}
	if (doversion)
		printf (""PACKAGE" "VERSION"\n");

	if (dohelp)
		usage ();

	if (optind < argc) {
		if (strlen (argv[optind]) > IF_NAMESIZE) {
			logger (LOG_ERR, "`%s' is too long for an interface name (max=%d)",
					argv[optind], IF_NAMESIZE);
			exit (EXIT_FAILURE);
		}
		strlcpy (options.interface, argv[optind],
				 sizeof (options.interface));
	} else {
		/* If only version was requested then exit now */
		if (doversion || dohelp)
			exit (EXIT_SUCCESS);

		logger (LOG_ERR, "no interface specified");
		exit (EXIT_FAILURE);
	}

	if (strchr (options.hostname, '.')) {
		if (options.fqdn == FQDN_DISABLE)
			options.fqdn = FQDN_BOTH;
	} else
		options.fqdn = FQDN_DISABLE;

	if (options.request_address.s_addr == 0 && options.doinform) {
		if ((options.request_address.s_addr = get_address (options.interface)) != 0)
			options.keep_address = true;
	}

	if (geteuid ()) {
		logger (LOG_ERR, "you need to be root to run "PACKAGE);
		exit (EXIT_FAILURE);
	}

	snprintf (prefix, IF_NAMESIZE, "%s: ", options.interface);
	setlogprefix (prefix);
	snprintf (options.pidfile, sizeof (options.pidfile), PIDFILE,
			  options.interface);

	chdir ("/");
	umask (022);

	if (mkdir (CONFIGDIR, S_IRUSR |S_IWUSR |S_IXUSR | S_IRGRP | S_IXGRP
			   | S_IROTH | S_IXOTH) && errno != EEXIST )
	{
		logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", CONFIGDIR, strerror (errno));
		exit (EXIT_FAILURE);
	}

	if (mkdir (ETCDIR, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP
			   | S_IROTH | S_IXOTH) && errno != EEXIST )
	{
		logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", ETCDIR, strerror (errno));
		exit (EXIT_FAILURE);
	}

	if (options.test) {
		if (options.dorequest || options.doinform) {
			logger (LOG_ERR, "cannot test with --inform or --request");
			exit (EXIT_FAILURE);
		}

		if (options.dolastlease) {
			logger (LOG_ERR, "cannot test with --lastlease");
			exit (EXIT_FAILURE);
		}

		if (sig != 0) {
			logger (LOG_ERR, "cannot test with --release or --renew");
			exit (EXIT_FAILURE);
		}
	}

	if (sig != 0 ) {
		int killed = -1;
		pid = read_pid (options.pidfile);
		if (pid != 0)
			logger (LOG_INFO, "sending signal %d to pid %d", sig, pid);

		if (! pid || (killed = kill (pid, sig)))
			logger (sig == SIGALRM ? LOG_INFO : LOG_ERR, ""PACKAGE" not running");

		if (pid != 0 && (sig != SIGALRM || killed != 0))
			unlink (options.pidfile);

		if (killed == 0)
			exit (EXIT_SUCCESS);

		if (sig != SIGALRM)
			exit (EXIT_FAILURE);
	}

	if (! options.test) {
		if ((pid = read_pid (options.pidfile)) > 0 && kill (pid, 0) == 0) {
			logger (LOG_ERR, ""PACKAGE" already running on pid %d (%s)",
					pid, options.pidfile);
			exit (EXIT_FAILURE);
		}

		pidfd = open (options.pidfile, O_WRONLY | O_CREAT | O_NONBLOCK, 0660);
		if (pidfd == -1) {
			logger (LOG_ERR, "open `%s': %s", options.pidfile, strerror (errno));
			exit (EXIT_FAILURE);
		}

		/* Lock the file so that only one instance of dhcpcd runs on an interface */
		if (flock (pidfd, LOCK_EX | LOCK_NB) == -1) {
			logger (LOG_ERR, "flock `%s': %s", options.pidfile, strerror (errno));
			exit (EXIT_FAILURE);
		}

		/* dhcpcd.sh should not interhit this fd */
		if ((i = fcntl (pidfd, F_GETFD, 0)) == -1 ||
			fcntl (pidfd, F_SETFD, i | FD_CLOEXEC) == -1)
			logger (LOG_ERR, "fcntl: %s", strerror (errno));

		logger (LOG_INFO, PACKAGE " " VERSION " starting");
	}

	/* Seed random */
	srandomdev ();

	if (dhcp_run (&options, &pidfd)) {
		if (pidfd > -1)
			close (pidfd);
		unlink (options.pidfile);
		exit (EXIT_FAILURE);
	}

	exit (EXIT_SUCCESS);
}
Exemplo n.º 7
0
int main(int argc, char **argv)
{
  options_t options;

  /* Sanitize our fd's */
  int zero;
  if ((zero = open (_PATH_DEVNULL, O_RDWR, 0)) >= 0)
    {
      while (zero < 3)
	zero = dup (zero);
      close(zero);
    }

  openlog (PACKAGE, LOG_PID, LOG_LOCAL0);

  memset (&options, 0, sizeof (options_t));
  options.script = DEFAULT_SCRIPT;
  snprintf (options.classid, CLASS_ID_MAX_LEN, "%s %s", PACKAGE, VERSION); 

  options.doarp = false;
  options.dodns = true;
  options.dontp = true;
  options.dogateway = true;
  options.timeout = DEFAULT_TIMEOUT;

  int doversion = 0;
  int dohelp = 0;
  int userclasses = 0;

  const struct option longopts[] =
    {
	{"arp", no_argument, NULL, 'a'},
	{"script",required_argument, NULL, 'c'},
	{"debug", no_argument, NULL, 'd'},
	{"hostname", required_argument, NULL, 'h'},
	{"classid", required_argument, NULL, 'i'},
	{"release", no_argument, NULL, 'k'},
	{"leasetime", required_argument, NULL, 'l'},
	{"metric", required_argument, NULL, 'm'},
	{"renew", no_argument, NULL, 'n'},
	{"persistent", no_argument, NULL, 'p'},
	{"request", required_argument, NULL, 's'},
	{"timeout", required_argument, NULL, 't'},
	{"userclass", required_argument, NULL, 'u'},
	{"fqdn", optional_argument, NULL, 'F'},
	{"nogateway", no_argument, NULL, 'G'},
	{"sethostname", no_argument, NULL, 'H'},
	{"clientid", required_argument, NULL, 'I'},
	{"nontp", no_argument, NULL, 'N'},
	{"nodns", no_argument, NULL, 'R'},
	{"nonis", no_argument, NULL, 'Y'},
	{"help", no_argument, &dohelp, 1},
	{"version", no_argument, &doversion, 1},
	{NULL, 0, NULL, 0}
    };

  int ch;
  int option_index = 0;
  while ((ch = getopt_long(argc, argv, "ac:dh:i:kl:m:nps:t:u:F:GHI:NRY", longopts,
			   &option_index)) != -1)
    switch (ch)
      {
      case 0:
	if (longopts[option_index].flag)
	  break;
	logger (LOG_ERR, "option `%s' should set a flag",
		longopts[option_index].name);
	exit (EXIT_FAILURE);
	break;

      case 'a':
	options.doarp = true;
	break;
      case 'c':
	options.script = optarg;
	break;
      case 'd':
	setloglevel(LOG_DEBUG);
	break;
      case 'h':
	if (strlen (optarg) > HOSTNAME_MAX_LEN)
	  {
	    logger(LOG_ERR, "`%s' too long for HostName string, max is %d",
		   optarg, HOSTNAME_MAX_LEN);
	    exit (EXIT_FAILURE);
	  }
	else
	  options.hostname = optarg;
	break;
      case 'i':
	if (strlen(optarg) > CLASS_ID_MAX_LEN)
	  {
	    logger (LOG_ERR, "`%s' too long for ClassID string, max is %d",
		    optarg, CLASS_ID_MAX_LEN);
	    exit (EXIT_FAILURE);
	  }
	else
	  sprintf(options.classid, "%s", optarg);
	break;
      case 'k':
	options.signal = SIGHUP;
	break;
      case 'l':
	STRINGINT (optarg, options.leasetime);
	if (options.leasetime <= 0)
	  {
	    logger (LOG_ERR, "leasetime must be a positive value");
	    exit (EXIT_FAILURE);
	  }
	break;
      case 'm':
	STRINGINT(optarg, options.metric);
	break;
      case 'n':
	options.signal = SIGALRM;
	break;
      case 'p':
	options.persistent = true;
	break;
      case 's':
	if (! inet_aton (optarg, &options.requestaddress))
	  {
	    logger (LOG_ERR, "`%s' is not a valid IP address", optarg);
	    exit (EXIT_FAILURE);
	  }
	break;
      case 't':
	STRINGINT (optarg, options.timeout);
	if (options.timeout < 0)
	  {
	    logger (LOG_ERR, "timeout must be a positive value");
	    exit (EXIT_FAILURE);
	  }
	break;
      case 'u':
	  {
	    int i;
	    int offset = 0;
	    for (i = 0; i < userclasses; i++)
	      offset += (int) options.userclass[offset] + 1;
	    if (offset + 1 + strlen (optarg) > USERCLASS_MAX_LEN)
	      {
		logger (LOG_ERR, "userclass overrun, max is %d",
			USERCLASS_MAX_LEN);
		exit (EXIT_FAILURE);
	      }
	    userclasses++;
	    memcpy (options.userclass + offset + 1 , optarg, strlen (optarg));
	    options.userclass[offset] = strlen (optarg);
	  }
	break;
      case 'F':
	if (strcmp (optarg, "none") == 0)
	  options.fqdn = FQDN_NONE;
	else if (strcmp (optarg, "ptr") == 0)
	  options.fqdn = FQDN_PTR;
	else if (strcmp (optarg, "both") == 0)
	  options.fqdn = FQDN_BOTH;
	else
	  {
	    logger (LOG_ERR, "invalid value `%s' for FQDN", optarg);
	    exit (EXIT_FAILURE);
	  }
	break;
      case 'G':
	options.dogateway = false;
	break;
      case 'H':
	options.dohostname = true;
	break;
      case 'I':
	if (strlen (optarg) > CLIENT_ID_MAX_LEN)
	  {
	    logger (LOG_ERR, "`%s' is too long for ClientID, max is %d",
		    optarg, CLIENT_ID_MAX_LEN);
	    exit (EXIT_FAILURE);
	  }
	else
	  sprintf(options.clientid, "%s", optarg);
	break;
      case 'N':
	options.dontp = false;
	break;
      case 'R':
	options.dodns = false;
	break;
      case 'Y':
	options.donis = false;
	break;
      case '?':
	usage ();
	exit (EXIT_FAILURE);
      default:
	usage ();
	exit (EXIT_FAILURE);
      }

  if (doversion)
    printf (""PACKAGE" "VERSION"\n");

  if (dohelp)
    usage ();

  if (optind < argc)
    {
      if (strlen (argv[optind]) > IF_NAMESIZE)
	{
	  logger (LOG_ERR, "`%s' is too long for an interface name (max=%d)",
		  argv[optind], IF_NAMESIZE);
	  exit (EXIT_FAILURE);
	}
      options.interface = argv[optind];
    }
  else
    {
      /* If only version was requested then exit now */
      if (doversion || dohelp)
	exit (EXIT_SUCCESS);

      logger (LOG_ERR, "no interface specified", options.interface);
      exit (EXIT_FAILURE);
    }

  if (geteuid ())
    {
      logger (LOG_ERR, "you need to be root to run "PACKAGE);
      exit (EXIT_FAILURE);
    }

  char prefix[IF_NAMESIZE + 3];
  snprintf (prefix, IF_NAMESIZE, "%s: ", options.interface);
  setlogprefix (prefix);
  snprintf (options.pidfile, sizeof (options.pidfile), PIDFILE,
	    options.interface);

  if (options.signal != 0)
    exit (kill_pid (options.pidfile, options.signal));

  umask (022);

  if (readpid (options.pidfile))
    {
      logger (LOG_ERR, ""PACKAGE" already running (%s)", options.pidfile);
      exit (EXIT_FAILURE);
    }

  if (mkdir (CONFIGDIR, S_IRUSR |S_IWUSR |S_IXUSR | S_IRGRP | S_IXGRP
	     | S_IROTH | S_IXOTH) && errno != EEXIST )
    {
      logger( LOG_ERR, "mkdir(\"%s\",0): %m\n", CONFIGDIR);
      exit (EXIT_FAILURE);
    }

  if (mkdir (ETCDIR, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP
	     | S_IROTH | S_IXOTH) && errno != EEXIST )
    {
      logger (LOG_ERR, "mkdir(\"%s\",0): %m\n", ETCDIR);
      exit (EXIT_FAILURE);
    }

  logger (LOG_INFO, PACKAGE " " VERSION " starting");
  if (dhcp_run (&options))
    exit (EXIT_FAILURE);

  exit (EXIT_SUCCESS);
}
Exemplo n.º 8
0
int main(int argc, char **argv)
{
	options_t *options;
	int userclasses = 0;
	int opt;
	int option_index = 0;
	char *prefix;
	pid_t pid;
	int debug = 0;
	int i;
	int pidfd = -1;
	int sig = 0;

	/* Close any un-needed fd's */
	for (i = getdtablesize() - 1; i >= 3; --i)
		close (i);

	openlog (PACKAGE, LOG_PID, LOG_LOCAL0);

	options = xmalloc (sizeof (options_t));
	memset (options, 0, sizeof (options_t));
	options->script = (char *) DEFAULT_SCRIPT;
	snprintf (options->classid, CLASS_ID_MAX_LEN, "%s %s", PACKAGE, VERSION);
	options->classid_len = strlen (options->classid);

	options->doarp = true;
	options->dodns = true;
	options->domtu = true;
	options->donis = true;
	options->dontp = true;
	options->dogateway = true;
	options->daemonise = true;
	options->doinform = false;
	options->doipv4ll = true;
	options->timeout = DEFAULT_TIMEOUT;

	gethostname (options->hostname, sizeof (options->hostname));
	if (strcmp (options->hostname, "(none)") == 0 ||
		strcmp (options->hostname, "localhost") == 0)
		memset (options->hostname, 0, sizeof (options->hostname));

	/* Don't set any optional arguments here so we retain POSIX
	 * compatibility with getopt */
	while ((opt = getopt_long(argc, argv, EXTRA_OPTS
							  "c:dh:i:kl:m:npr:s:t:u:xAEF:GHI:LMNRTY",
							  longopts, &option_index)) != -1)
	{
		switch (opt) {
			case 0:
				if (longopts[option_index].flag)
					break;
				logger (LOG_ERR, "option `%s' should set a flag",
						longopts[option_index].name);
				exit (EXIT_FAILURE);
				break;
			case 'c':
				options->script = optarg;
				break;
			case 'd':
				debug++;
				switch (debug) {
					case 1:
						setloglevel (LOG_DEBUG);
						break;
					case 2:
						options->daemonise = false;
						break;
				}
				break;
#ifdef THERE_IS_NO_FORK
			case 'f':
				options->daemonised = true;
				close_fds ();
				break;
			case 'g':
				dhcpcd_skiproutes = xstrdup (optarg);
				break;
#endif
			case 'h':
				if (! optarg)
					memset (options->hostname, 0, sizeof (options->hostname));
				else if (strlen (optarg) > MAXHOSTNAMELEN) {
					logger (LOG_ERR, "`%s' too long for HostName string, max is %d",
							optarg, MAXHOSTNAMELEN);
					exit (EXIT_FAILURE);
				} else
					strlcpy (options->hostname, optarg, sizeof (options->hostname));
				break;
			case 'i':
				if (! optarg) {
					memset (options->classid, 0, sizeof (options->classid));
					options->classid_len = 0;
				} else if (strlen (optarg) > CLASS_ID_MAX_LEN) {
					logger (LOG_ERR, "`%s' too long for ClassID string, max is %d",
							optarg, CLASS_ID_MAX_LEN);
					exit (EXIT_FAILURE);
				} else
					options->classid_len = strlcpy (options->classid, optarg,
												   sizeof (options->classid));
				break;
			case 'k':
				sig = SIGHUP;
				break;
			case 'l':
				STRINGINT (optarg, options->leasetime);
				if (options->leasetime <= 0) {
					logger (LOG_ERR, "leasetime must be a positive value");
					exit (EXIT_FAILURE);
				}
				break;
			case 'm':
				STRINGINT (optarg, options->metric);
				break;
			case 'n':
				sig = SIGALRM;
				break;
			case 'p':
				options->persistent = true;
				break;
			case 's':
				options->doinform = true;
				options->doarp = false;
				if (! optarg || strlen (optarg) == 0) {
					options->request_address.s_addr = 0;
					break;
				} else {
					char *slash = strchr (optarg, '/');
					if (slash) {
						int cidr;
						/* nullify the slash, so the -r option can read the
						 * address */
						*slash++ = '\0';
						if (sscanf (slash, "%d", &cidr) != 1 ||
							inet_cidrtoaddr (cidr, &options->request_netmask) != 0) {
							logger (LOG_ERR, "`%s' is not a valid CIDR", slash);
							exit (EXIT_FAILURE);
						}
					}
					/* fall through */
				}
			case 'r':
				if (! options->doinform)
					options->dorequest = true;
				if (strlen (optarg) > 0 &&
					! inet_aton (optarg, &options->request_address))
				{ 
					logger (LOG_ERR, "`%s' is not a valid IP address", optarg);
					exit (EXIT_FAILURE);
				}
				break;
			case 't':
				STRINGINT (optarg, options->timeout);
				if (options->timeout < 0) {
					logger (LOG_ERR, "timeout must be a positive value");
					exit (EXIT_FAILURE);
				}
				break;
			case 'u':
				{
					int offset = 0;
					for (i = 0; i < userclasses; i++)
						offset += (int) options->userclass[offset] + 1;
					if (offset + 1 + strlen (optarg) > USERCLASS_MAX_LEN) {
						logger (LOG_ERR, "userclass overrun, max is %d",
								USERCLASS_MAX_LEN);
						exit (EXIT_FAILURE);
					}
					userclasses++;
					memcpy (options->userclass + offset + 1 , optarg, strlen (optarg));
					options->userclass[offset] = strlen (optarg);
					options->userclass_len += (strlen (optarg)) + 1;
				}
				break;
			case 'x':
				sig = SIGTERM;
				break;
			case 'A':
#ifndef ENABLE_ARP
				logger (LOG_ERR, "arp support not compiled into dhcpcd");
				exit (EXIT_FAILURE);
#endif
				options->doarp = false;
				break;
			case 'E':
#ifndef ENABLE_INFO
				logger (LOG_ERR, "info support not compiled into dhcpcd");
				exit (EXIT_FAILURE);
#endif
				options->dolastlease = true;
				break;
			case 'F':
				if (strncmp (optarg, "none", strlen (optarg)) == 0)
					options->fqdn = FQDN_NONE;
				else if (strncmp (optarg, "ptr", strlen (optarg)) == 0)
					options->fqdn = FQDN_PTR;
				else if (strncmp (optarg, "both", strlen (optarg)) == 0)
					options->fqdn = FQDN_BOTH;
				else {
					logger (LOG_ERR, "invalid value `%s' for FQDN", optarg);
					exit (EXIT_FAILURE);
				}
				break;
			case 'G':
				options->dogateway = false;
				break;
			case 'H':
				options->dohostname++;
				break;
			case 'I':
				if (optarg) {
					if (strlen (optarg) > CLIENT_ID_MAX_LEN) {
						logger (LOG_ERR, "`%s' is too long for ClientID, max is %d",
								optarg, CLIENT_ID_MAX_LEN);
						exit (EXIT_FAILURE);
					}
					options->clientid_len = strlcpy (options->clientid, optarg,
													sizeof (options->clientid));
					/* empty string disabled duid */
					if (options->clientid_len == 0)
						options->clientid_len = -1;
				} else {
					memset (options->clientid, 0, sizeof (options->clientid));
					options->clientid_len = -1;
				}
				break;
			case 'L':
				options->doipv4ll = false;
				break;
			case 'M':
				options->domtu = false;
				break;
			case 'N':
				options->dontp = false;
				break;
			case 'R':
				options->dodns = false;
				break;
			case 'T':
#ifndef ENABLE_INFO
				logger (LOG_ERR, "info support not compiled into dhcpcd");
				exit (EXIT_FAILURE);
#endif
				options->test = true;
				options->persistent = true;
				break;
			case 'Y':
				options->donis = false;
				break;
			case '?':
				usage ();
				exit (EXIT_FAILURE);
			default:
				usage ();
				exit (EXIT_FAILURE);
		}
	}
	if (doversion) {
		printf (""PACKAGE" "VERSION"\n");
		printf ("Compile time options:"
#ifdef ENABLE_ARP
				" ARP"
#endif
#ifdef ENABLE_DUID
				" DUID"
#endif
#ifdef ENABLE_INFO
				" INFO"
#endif
#ifdef ENABLE_INFO_COMPAT
				" INFO_COMPAT"
#endif
#ifdef ENABLE_IPV4LL
				" IPV4LL"
#endif
#ifdef ENABLE_NIS
				" NIS"
#endif
#ifdef ENABLE_NTP
				" NTP"
#endif
#ifdef THERE_IS_NO_FORK
				" THERE_IS_NO_FORK"
#endif
				"\n");
	}

	if (dohelp)
		usage ();

#ifdef THERE_IS_NO_FORK
	dhcpcd_argv = argv;
	dhcpcd_argc = argc;

	/* We need the full path to the dhcpcd */
	if (*argv[0] == '/')
		strlcpy (dhcpcd, argv[0], sizeof (dhcpcd));
	else {
		char pwd[PATH_MAX];
		if (! getcwd (pwd, PATH_MAX)) {
			logger (LOG_ERR, "getcwd: %s", strerror (errno));
			exit (EXIT_FAILURE);
		}
		snprintf (dhcpcd, sizeof (dhcpcd), "%s/%s", pwd, argv[0]);
	}

#endif

	if (optind < argc) {
		if (strlen (argv[optind]) > IF_NAMESIZE) {
			logger (LOG_ERR, "`%s' is too long for an interface name (max=%d)",
					argv[optind], IF_NAMESIZE);
			exit (EXIT_FAILURE);
		}
		strlcpy (options->interface, argv[optind],
				 sizeof (options->interface));
	} else {
		/* If only version was requested then exit now */
		if (doversion || dohelp)
			exit (EXIT_SUCCESS);

		logger (LOG_ERR, "no interface specified");
		exit (EXIT_FAILURE);
	}

	if (strchr (options->hostname, '.')) {
		if (options->fqdn == FQDN_DISABLE)
			options->fqdn = FQDN_BOTH;
	} else
		options->fqdn = FQDN_DISABLE;

	if (options->request_address.s_addr == 0 && options->doinform) {
		if ((options->request_address.s_addr = get_address (options->interface)) != 0)
			options->keep_address = true;
	}

	if (IN_LINKLOCAL (options->request_address.s_addr)) {
		logger (LOG_ERR, "you are not allowed to request a link local address");
		exit (EXIT_FAILURE);
	}

	if (geteuid ()) {
		logger (LOG_ERR, "you need to be root to run "PACKAGE);
		exit (EXIT_FAILURE);
	}

	prefix = xmalloc (sizeof (char) * (IF_NAMESIZE + 3));
	snprintf (prefix, IF_NAMESIZE, "%s: ", options->interface);
	setlogprefix (prefix);
	snprintf (options->pidfile, sizeof (options->pidfile), PIDFILE,
			  options->interface);
	free (prefix);

	chdir ("/");
	umask (022);
	
	if (mkdir (CONFIGDIR, S_IRUSR |S_IWUSR |S_IXUSR | S_IRGRP | S_IXGRP
			   | S_IROTH | S_IXOTH) && errno != EEXIST )
	{
		logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", CONFIGDIR, strerror (errno));
		exit (EXIT_FAILURE);
	}

	if (mkdir (ETCDIR, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP
			   | S_IROTH | S_IXOTH) && errno != EEXIST )
	{
		logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", ETCDIR, strerror (errno));
		exit (EXIT_FAILURE);
	}

	if (options->test) {
		if (options->dorequest || options->doinform) {
			logger (LOG_ERR, "cannot test with --inform or --request");
			exit (EXIT_FAILURE);
		}

		if (options->dolastlease) {
			logger (LOG_ERR, "cannot test with --lastlease");
			exit (EXIT_FAILURE);
		}

		if (sig != 0) {
			logger (LOG_ERR, "cannot test with --release or --renew");
			exit (EXIT_FAILURE);
		}
	}

	if (sig != 0) {
		int killed = -1;
		pid = read_pid (options->pidfile);
		if (pid != 0)
			logger (LOG_INFO, "sending signal %d to pid %d", sig, pid);

		if (! pid || (killed = kill (pid, sig)))
			logger (sig == SIGALRM ? LOG_INFO : LOG_ERR, ""PACKAGE" not running");

		if (pid != 0 && (sig != SIGALRM || killed != 0))
			unlink (options->pidfile);

		if (killed == 0)
			exit (EXIT_SUCCESS);

		if (sig != SIGALRM)
			exit (EXIT_FAILURE);
	}

	if (! options->test && ! options->daemonised) {
		if ((pid = read_pid (options->pidfile)) > 0 && kill (pid, 0) == 0) {
			logger (LOG_ERR, ""PACKAGE" already running on pid %d (%s)",
					pid, options->pidfile);
			exit (EXIT_FAILURE);
		}

		pidfd = open (options->pidfile, O_WRONLY | O_CREAT | O_NONBLOCK, 0660);
		if (pidfd == -1) {
			logger (LOG_ERR, "open `%s': %s", options->pidfile, strerror (errno));
			exit (EXIT_FAILURE);
		}

		/* Lock the file so that only one instance of dhcpcd runs on an interface */
		if (flock (pidfd, LOCK_EX | LOCK_NB) == -1) {
			logger (LOG_ERR, "flock `%s': %s", options->pidfile, strerror (errno));
			exit (EXIT_FAILURE);
		}

		/* dhcpcd.sh should not interhit this fd */
		if ((i = fcntl (pidfd, F_GETFD, 0)) == -1 ||
			fcntl (pidfd, F_SETFD, i | FD_CLOEXEC) == -1)
			logger (LOG_ERR, "fcntl: %s", strerror (errno));

		writepid (pidfd, getpid ());
		logger (LOG_INFO, PACKAGE " " VERSION " starting");
	}

	/* Seed random */
	srandomdev ();

	i = EXIT_FAILURE;
	if (dhcp_run (options, &pidfd) == 0)
		i = EXIT_SUCCESS;

	/* If we didn't daemonise then we need to punt the pidfile now */
	if (pidfd > -1) {
		close (pidfd);
		unlink (options->pidfile);
	}

	free (options);

#ifdef THERE_IS_NO_FORK
	/* There may have been an error before the dhcp_run function
	 * clears this, so just do it here to be safe */
	free (dhcpcd_skiproutes);
#endif

	logger (LOG_INFO, "exiting");
	
	exit (i);
}
Exemplo n.º 9
0
int main(void)
{
  dhcp dhcp_session;
  int  dhcp_state;
  http_server http;
  http_socket httpsock[4];
  http_content httpcontent[4];
  char oled_msg[17];
  char *pnt;
  int   step;

  api_init();
  uart_puts(" * eCowLogic firmware \r\n");

  hw_systick( hw_getfreq() / 1000 );

  dhcp_session.socket = 2;
  dhcp_session.buffer = (u8 *)buffer_dhcp;
  dhcp_init(&dhcp_session);
  
  oled_pos(1, 0);
  oled_puts("Reseau (DHCP)   ");
  step = 0;
  while(1)
  {
    dhcp_state = dhcp_run(&dhcp_session);
    if (dhcp_state == DHCP_IP_LEASED)
      break;
    step++;
    oled_pos(1, 13);
    if (step == 1) oled_puts(".  ");
    if (step == 2) oled_puts(".. ");
    if (step == 3) oled_puts("...");
    if (step == 4)
    {
      step = 0;
      dhcp_session.tick_1s++;
      uart_putc('.');
      oled_puts("   ");
    }
    delay(250);
  }
  pnt = oled_msg;
  pnt += b2ds(pnt, dhcp_session.dhcp_my_ip[0]); *pnt++ = '.';
  pnt += b2ds(pnt, dhcp_session.dhcp_my_ip[1]); *pnt++ = '.';
  pnt += b2ds(pnt, dhcp_session.dhcp_my_ip[2]); *pnt++ = '.';
  pnt += b2ds(pnt, dhcp_session.dhcp_my_ip[3]);
  for ( ; pnt < (oled_msg + 16); pnt++)
    *pnt = ' ';
  oled_msg[16] = 0;
  uart_puts("DHCP: LEASED ! ");
  uart_puts(oled_msg); uart_puts("\r\n");
  oled_pos(1, 0);
  oled_puts(oled_msg);
  
  spi_init();
  pld_init();

  //net_init();
  
  /* Init HTTP content */
  strcpy(httpcontent[0].name, "/pld");
  httpcontent[0].wildcard = 0;
  httpcontent[0].cgi = cgi_ng_pld;
  httpcontent[0].next = &httpcontent[1];
  /* Init HTTP content */
  strcpy(httpcontent[1].name, "/spi");
  httpcontent[1].wildcard = 0;
  httpcontent[1].cgi = cgi_spi;
  httpcontent[1].next = &httpcontent[2];
  /* Init HTTP content */
  strcpy(httpcontent[2].name, "/infos");
  httpcontent[2].wildcard = 0;
  httpcontent[2].cgi = cgi_info;
  httpcontent[2].next = &httpcontent[3];
  /* Init HTTP content */
  strcpy(httpcontent[3].name, "/");
  httpcontent[3].wildcard = 1;
  httpcontent[3].cgi = cgi_ng_page;
  httpcontent[3].next = 0;
  /* Init HTTP socket */
  httpsock[0].id = 4;
  httpsock[0].state = 0;
  httpsock[0].server = &http;
  httpsock[0].next = &httpsock[1];
  /* Init HTTP socket */
  httpsock[1].id = 5;
  httpsock[1].state = 0;
  httpsock[1].server = &http;
  httpsock[1].next = &httpsock[2];
  /* Init HTTP socket */
  httpsock[2].id = 6;
  httpsock[2].state = 0;
  httpsock[2].server = &http;
  httpsock[2].next = &httpsock[3];
  /* Init HTTP socket */
  httpsock[3].id = 7;
  httpsock[3].state = 0;
  httpsock[3].server = &http;
  httpsock[3].next = 0;
  /* Init the new HTTP layer */
  http.port   = 80;
  http.err404 = 0;
  http.err403 = 0;
  http.keepalive = 10;
  http.socks  = &httpsock[0];
  http.contents = &httpcontent[0];
  http_init(&http);
  
  while(1)
  {
    http_run(&http);
  }
}
Exemplo n.º 10
0
int main(int argc, char **argv)
{
	options_t options;
	int doversion = 0;
	int dohelp = 0;
	int userclasses = 0;
	int ch;
	int option_index = 0;
	char prefix[IF_NAMESIZE + 3];
	pid_t pid;
	int debug = 0;
	int i;

	const struct option longopts[] = {
        {"arp",         no_argument,        NULL, 'a'},
        {"script",      required_argument,  NULL, 'c'},
        {"debug",       no_argument,        NULL, 'd'},
        {"hostname",    required_argument,  NULL, 'h'},
        {"classid",     required_argument,  NULL, 'i'},
        {"release",     no_argument,        NULL, 'k'},
        {"leasetime",   required_argument,  NULL, 'l'},
        {"metric",      required_argument,  NULL, 'm'},
        {"renew",       no_argument,        NULL, 'n'},
        {"persistent",  no_argument,        NULL, 'p'},
        {"request",     required_argument,  NULL, 's'},
        {"timeout",     required_argument,  NULL, 't'},
        {"userclass",   required_argument,  NULL, 'u'},
        {"fqdn",        optional_argument,  NULL, 'F'},
        {"nogateway",   no_argument,        NULL, 'G'},
        {"sethostname", no_argument,        NULL, 'H'},
        {"clientid",    required_argument,  NULL, 'I'},
        {"nomtu",       no_argument,        NULL, 'M'},
        {"nontp",       no_argument,        NULL, 'N'},
        {"nodns",       no_argument,        NULL, 'R'},
        {"nonis",       no_argument,        NULL, 'Y'},
        {"help",        no_argument,        &dohelp, 1},
        {"version",     no_argument,        &doversion, 1},
        {NULL,          0,                  NULL, 0}
	};

	/* Close any un-needed fd's */
	for (i = getdtablesize() - 1; i >= 3; --i)
		close (i);

	openlog (PACKAGE, LOG_PID, LOG_LOCAL0);

	memset (&options, 0, sizeof (options_t));
	options.script = (char *) DEFAULT_SCRIPT;
	snprintf (options.classid, CLASS_ID_MAX_LEN, "%s %s", PACKAGE, VERSION); 

	options.doarp = false;
	options.dodns = true;
	options.domtu = true;
	options.donis = true;
	options.dontp = true;
	options.dogateway = true;
	options.daemonise = true;
	options.timeout = DEFAULT_TIMEOUT;

	while ((ch = getopt_long(argc, argv, "ac:dh:i:kl:m:nps:t:u:F:GHI:MNRY", longopts,
							 &option_index)) != -1)
		switch (ch) {
			case 0:
				if (longopts[option_index].flag)
					break;
				logger (LOG_ERR, "option `%s' should set a flag",
						longopts[option_index].name);
				exit (EXIT_FAILURE);
				break;

			case 'a':
				options.doarp = true;
				break;
			case 'c':
				options.script = optarg;
				break;
			case 'd':
				debug++;
				switch (debug) {
					case 1:
						setloglevel (LOG_DEBUG);
						break;
					case 2:
						options.daemonise = false;
						break;
				}
				break;
			case 'h':
				if (strlen (optarg) > sizeof (options.hostname)) {
					logger (LOG_ERR, "`%s' too long for HostName string, max is %d",
							optarg, sizeof (options.hostname));
					exit (EXIT_FAILURE);
				} else
					strlcpy (options.hostname, optarg, sizeof (options.hostname));
				break;
			case 'i':
				if (strlen (optarg) > CLASS_ID_MAX_LEN) {
					logger (LOG_ERR, "`%s' too long for ClassID string, max is %d",
							optarg, CLASS_ID_MAX_LEN);
					exit (EXIT_FAILURE);
				} else
					strlcpy (options.classid, optarg, sizeof (options.classid));
				break;
			case 'k':
				options.signal = SIGHUP;
				break;
			case 'l':
				STRINGINT (optarg, options.leasetime);
				if (options.leasetime <= 0) {
					logger (LOG_ERR, "leasetime must be a positive value");
					exit (EXIT_FAILURE);
				}
				break;
			case 'm':
				STRINGINT (optarg, options.metric);
				break;
			case 'n':
				options.signal = SIGALRM;
				break;
			case 'p':
				options.persistent = true;
				break;
			case 's':
				if (! inet_aton (optarg, &options.requestaddress)) {
					logger (LOG_ERR, "`%s' is not a valid IP address", optarg);
					exit (EXIT_FAILURE);
				}
				break;
			case 't':
				STRINGINT (optarg, options.timeout);
				if (options.timeout < 0) {
					logger (LOG_ERR, "timeout must be a positive value");
					exit (EXIT_FAILURE);
				}
				break;
			case 'u':
				{
					int offset = 0;
					for (i = 0; i < userclasses; i++)
						offset += (int) options.userclass[offset] + 1;
					if (offset + 1 + strlen (optarg) > USERCLASS_MAX_LEN) {
						logger (LOG_ERR, "userclass overrun, max is %d",
								USERCLASS_MAX_LEN);
						exit (EXIT_FAILURE);
					}
					userclasses++;
					memcpy (options.userclass + offset + 1 , optarg, strlen (optarg));
					options.userclass[offset] = strlen (optarg);
					options.userclass_len += (strlen (optarg)) + 1;
				}
				break;
			case 'F':
				if (strncmp (optarg, "none", strlen (optarg)) == 0)
					options.fqdn = FQDN_NONE;
				else if (strncmp (optarg, "ptr", strlen (optarg)) == 0)
					options.fqdn = FQDN_PTR;
				else if (strncmp (optarg, "both", strlen (optarg)) == 0)
					options.fqdn = FQDN_BOTH;
				else {
					logger (LOG_ERR, "invalid value `%s' for FQDN", optarg);
					exit (EXIT_FAILURE);
				}
				break;
			case 'G':
				options.dogateway = false;
				break;
			case 'H':
				options.dohostname = true;
				break;
			case 'I':
				if (strlen (optarg) > CLIENT_ID_MAX_LEN) {
					logger (LOG_ERR, "`%s' is too long for ClientID, max is %d",
							optarg, CLIENT_ID_MAX_LEN);
					exit (EXIT_FAILURE);
				} else
					strlcpy (options.clientid, optarg, sizeof (options.clientid));
				break;
			case 'M':
				options.domtu = false;
				break;
			case 'N':
				options.dontp = false;
				break;
			case 'R':
				options.dodns = false;
				break;
			case 'Y':
				options.donis = false;
				break;
			case '?':
				usage ();
				exit (EXIT_FAILURE);
			default:
				usage ();
				exit (EXIT_FAILURE);
		}

	if (doversion)
		printf (""PACKAGE" "VERSION"\n");

	if (dohelp)
		usage ();

	if (optind < argc) {
		if (strlen (argv[optind]) > IF_NAMESIZE) {
			logger (LOG_ERR, "`%s' is too long for an interface name (max=%d)",
					argv[optind], IF_NAMESIZE);
			exit (EXIT_FAILURE);
		}
		strlcpy (options.interface, argv[optind],
				 sizeof (options.interface));
	} else {
		/* If only version was requested then exit now */
		if (doversion || dohelp)
			exit (EXIT_SUCCESS);

		logger (LOG_ERR, "no interface specified");
		exit (EXIT_FAILURE);
	}

	/* If we are given a hostname use it and set FQDN if it contains a . */
	if (! options.hostname[0]) {
		gethostname (options.hostname, sizeof (options.hostname));
		if (strcmp (options.hostname, "(none)") == 0 ||
			strcmp (options.hostname, "localhost") == 0)
			memset (options.hostname, 0, sizeof (options.hostname));
	}
	if (strchr (options.hostname, '.')) {
		if (options.fqdn == FQDN_DISABLE)
			options.fqdn = FQDN_BOTH;
	} else
		options.fqdn = FQDN_DISABLE;
	
	if (geteuid ()) {
		logger (LOG_ERR, "you need to be root to run "PACKAGE);
		exit (EXIT_FAILURE);
	}

	snprintf (prefix, IF_NAMESIZE, "%s: ", options.interface);
	setlogprefix (prefix);
	snprintf (options.pidfile, sizeof (options.pidfile), PIDFILE,
			  options.interface);

	if (options.signal != 0) {
		int killed = -1;
		pid = read_pid (options.pidfile);
		if (pid != 0)
			logger (LOG_INFO, "sending signal %d to pid %d", options.signal, pid);

		if (! pid || (killed = kill (pid, options.signal)))
			logger (options.signal == SIGALRM ? LOG_INFO : LOG_ERR, ""PACKAGE" not running");

		if (pid != 0 && (options.signal != SIGALRM || killed != 0))
			unlink (options.pidfile);

		if (killed == 0)
			exit (EXIT_SUCCESS);

		if (options.signal != SIGALRM)
			exit (EXIT_FAILURE);
	}

	chdir ("/");
	umask (022);

	if (mkdir (CONFIGDIR, S_IRUSR |S_IWUSR |S_IXUSR | S_IRGRP | S_IXGRP
			   | S_IROTH | S_IXOTH) && errno != EEXIST )
	{
		logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", CONFIGDIR, strerror (errno));
		exit (EXIT_FAILURE);
	}

	if (mkdir (ETCDIR, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP
			   | S_IROTH | S_IXOTH) && errno != EEXIST )
	{
		logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", ETCDIR, strerror (errno));
		exit (EXIT_FAILURE);
	}

	if ((pid = read_pid (options.pidfile)) > 0 && kill (pid, 0) == 0) {
		logger (LOG_ERR, ""PACKAGE" already running (%s)", options.pidfile);
		exit (EXIT_FAILURE);
	}

	make_pid (options.pidfile);

	logger (LOG_INFO, PACKAGE " " VERSION " starting");
	if (dhcp_run (&options)) {
		unlink (options.pidfile);
		exit (EXIT_FAILURE);
	}

	exit (EXIT_SUCCESS);
}