summaryrefslogtreecommitdiffstats
path: root/dhcpcd.c
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2006-11-27 20:23:22 +0000
committerRoy Marples <roy@marples.name>2006-11-27 20:23:22 +0000
commitcced195e703c548e7375727ea91bbdcd76aae517 (patch)
tree6c97679eedd1d687263f7d65742b02bedd93895f /dhcpcd.c
downloaddhcpcd-cced195e703c548e7375727ea91bbdcd76aae517.tar.xz
Add dhcpcd-3 re-write
Diffstat (limited to 'dhcpcd.c')
-rw-r--r--dhcpcd.c362
1 files changed, 362 insertions, 0 deletions
diff --git a/dhcpcd.c b/dhcpcd.c
new file mode 100644
index 00000000..9b03fb03
--- /dev/null
+++ b/dhcpcd.c
@@ -0,0 +1,362 @@
+/*
+ * dhcpcd - DHCP client daemon -
+ * Copyright (C) 2005 - 2006 Roy Marples <uberlord@gentoo.org>
+ *
+ * dhcpcd is an RFC2131 compliant DHCP client daemon.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/stat.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "client.h"
+#include "dhcpcd.h"
+#include "dhcp.h"
+#include "interface.h"
+#include "logger.h"
+#include "pathnames.h"
+#include "version.h"
+
+#define PACKAGE "dhcpcd"
+
+#define STRINGINT(_string, _int) { \
+ char *_tmp; \
+ errno = 0; \
+ long _number = strtol (_string, &_tmp, 0); \
+ if ((errno != 0 && _number == 0) || _string == _tmp || \
+ (errno == ERANGE && (_number == LONG_MAX || _number == LONG_MIN))) \
+ { \
+ logger (LOG_ERR, "`%s' out of range", _string);; \
+ exit (EXIT_FAILURE); \
+ } \
+ else \
+ _int = (int) _number; \
+}
+
+static pid_t readpid(char *pidfile)
+{
+ FILE *fp;
+ pid_t pid;
+
+ if ((fp = fopen (pidfile, "r")) == NULL)
+ {
+ errno = ENOENT;
+ return 0;
+ }
+
+ fscanf (fp, "%d", &pid);
+ fclose (fp);
+
+ return pid;
+}
+
+static int kill_pid (char *pidfile, int sig)
+{
+ pid_t pid = readpid (pidfile);
+ int r = 0;
+
+ if (!pid || (r = kill (pid, sig)))
+ {
+ logger (LOG_ERR, ""PACKAGE" not running");
+ unlink (pidfile);
+ }
+
+ return r;
+}
+
+static void usage ()
+{
+ printf ("usage: "PACKAGE" [-adknpGHNRY] [-c script] [-h hostame] [-i classID]\n"
+ " [-l leasetime] [-m metric] [-s ipaddress] [-t timeout]\n"
+ " [-u userclass] [-F [none | ptr | both]] [-I clientID]\n");
+}
+
+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);
+}