diff options
| author | Roy Marples <roy@marples.name> | 2006-11-27 20:23:22 +0000 |
|---|---|---|
| committer | Roy Marples <roy@marples.name> | 2006-11-27 20:23:22 +0000 |
| commit | cced195e703c548e7375727ea91bbdcd76aae517 (patch) | |
| tree | 6c97679eedd1d687263f7d65742b02bedd93895f /dhcpcd.c | |
| download | dhcpcd-cced195e703c548e7375727ea91bbdcd76aae517.tar.xz | |
Add dhcpcd-3 re-write
Diffstat (limited to 'dhcpcd.c')
| -rw-r--r-- | dhcpcd.c | 362 |
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); +} |
