source: rtems-libbsd/dhcpcd/dhcpcd.c @ 8bd38d6

5-freebsd-12
Last change on this file since 8bd38d6 was 8bd38d6, checked in by Sebastian Huber <sebastian.huber@…>, on May 2, 2018 at 6:58:48 AM

dhcpcd: Add rtems_dhcpcd_start()

Use it throughout to start the DHCP client (dhcpcd).

  • Property mode set to 100644
File size: 37.5 KB
Line 
1/*
2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2014 Roy Marples <roy@marples.name>
4 * All rights reserved
5
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28const char dhcpcd_copyright[] = "Copyright (c) 2006-2014 Roy Marples";
29
30#include <sys/file.h>
31#include <sys/socket.h>
32#include <sys/stat.h>
33#include <sys/time.h>
34#include <sys/types.h>
35#include <sys/uio.h>
36#include <sys/utsname.h>
37
38#include <ctype.h>
39#include <errno.h>
40#ifdef __rtems__
41#define __need_getopt_newlib
42#endif /* __rtems__ */
43#include <getopt.h>
44#include <limits.h>
45#include <paths.h>
46#include <signal.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50#include <syslog.h>
51#include <unistd.h>
52#include <time.h>
53
54#include "config.h"
55#include "arp.h"
56#include "common.h"
57#include "control.h"
58#include "dev.h"
59#include "dhcpcd.h"
60#include "dhcp6.h"
61#include "duid.h"
62#include "eloop.h"
63#include "if-options.h"
64#include "if-pref.h"
65#include "ipv4.h"
66#include "ipv6.h"
67#include "ipv6nd.h"
68#include "net.h"
69#include "platform.h"
70#include "script.h"
71
72struct if_head *ifaces = NULL;
73char vendor[VENDORCLASSID_MAX_LEN];
74#ifndef MASTER_ONLY
75int pidfd = -1;
76#endif
77struct if_options *if_options = NULL;
78int ifac = 0;
79char **ifav = NULL;
80int ifdc = 0;
81char **ifdv = NULL;
82
83sigset_t dhcpcd_sigset;
84#ifndef MASTER_ONLY
85const int handle_sigs[] = {
86        SIGALRM,
87        SIGHUP,
88        SIGINT,
89        SIGPIPE,
90        SIGTERM,
91        SIGUSR1,
92        0
93};
94#endif
95
96static char *cffile;
97#ifndef MASTER_ONLY
98static char *pidfile;
99#endif
100static int linkfd = -1;
101static char **ifv;
102static int ifc;
103static char **margv;
104static int margc;
105
106#ifndef MASTER_ONLY
107static pid_t
108read_pid(void)
109{
110        FILE *fp;
111        pid_t pid;
112
113        if ((fp = fopen(pidfile, "r")) == NULL) {
114                errno = ENOENT;
115                return 0;
116        }
117        if (fscanf(fp, "%d", &pid) != 1)
118                pid = 0;
119        fclose(fp);
120        return pid;
121}
122#endif
123
124static void
125usage(void)
126{
127
128printf("usage: "PACKAGE"\t[-46ABbDdEGgHJKkLnpqTVw]\n"
129        "\t\t[-C, --nohook hook] [-c, --script script]\n"
130        "\t\t[-e, --env value] [-F, --fqdn FQDN] [-f, --config file]\n"
131        "\t\t[-h, --hostname hostname] [-I, --clientid clientid]\n"
132        "\t\t[-i, --vendorclassid vendorclassid] [-l, --leasetime seconds]\n"
133        "\t\t[-m, --metric metric] [-O, --nooption option]\n"
134        "\t\t[-o, --option option] [-Q, --require option]\n"
135        "\t\t[-r, --request address] [-S, --static value]\n"
136        "\t\t[-s, --inform address[/cidr]] [-t, --timeout seconds]\n"
137        "\t\t[-u, --userclass class] [-v, --vendor code, value]\n"
138        "\t\t[-W, --whitelist address[/cidr]] [-y, --reboot seconds]\n"
139        "\t\t[-X, --blacklist address[/cidr]] [-Z, --denyinterfaces pattern]\n"
140        "\t\t[-z, --allowinterfaces pattern] [interface] [...]\n"
141        "       "PACKAGE"\t-k, --release [interface]\n"
142        "       "PACKAGE"\t-U, --dumplease interface\n"
143        "       "PACKAGE"\t--version\n"
144        "       "PACKAGE"\t-x, --exit [interface]\n");
145}
146
147#ifndef MASTER_ONLY
148static void
149free_globals(void)
150{
151        int i;
152        size_t n;
153        struct dhcp_opt *opt;
154
155        for (i = 0; i < ifac; i++)
156                free(ifav[i]);
157        free(ifav);
158        for (i = 0; i < ifdc; i++)
159                free(ifdv[i]);
160        free(ifdv);
161
162#ifdef INET
163        for (n = 0, opt = dhcp_opts; n < dhcp_opts_len; n++, opt++)
164                free_dhcp_opt_embenc(opt);
165        free(dhcp_opts);
166#endif
167#ifdef INET6
168        for (n = 0, opt = dhcp6_opts; n < dhcp6_opts_len; n++, opt++)
169                free_dhcp_opt_embenc(opt);
170        free(dhcp6_opts);
171#endif
172        for (n = 0, opt = vivso; n < vivso_len; n++, opt++)
173                free_dhcp_opt_embenc(opt);
174        free(vivso);
175}
176
177static void
178cleanup(void)
179{
180#ifdef DEBUG_MEMORY
181        struct interface *ifp;
182
183        free(duid);
184        free_options(if_options);
185
186        if (ifaces) {
187                while ((ifp = TAILQ_FIRST(ifaces))) {
188                        TAILQ_REMOVE(ifaces, ifp, next);
189                        free_interface(ifp);
190                }
191                free(ifaces);
192        }
193
194        free_globals();
195#endif
196
197        if (!(options & DHCPCD_FORKED))
198                dev_stop();
199        if (linkfd != -1)
200                close(linkfd);
201        if (pidfd > -1) {
202                if (options & DHCPCD_MASTER) {
203                        if (control_stop() == -1)
204                                syslog(LOG_ERR, "control_stop: %m");
205                }
206                close(pidfd);
207                unlink(pidfile);
208        }
209#ifdef DEBUG_MEMORY
210        free(pidfile);
211#endif
212
213        if (options & DHCPCD_STARTED && !(options & DHCPCD_FORKED))
214                syslog(LOG_INFO, "exited");
215}
216#endif /* !MASTER_ONLY */
217
218/* ARGSUSED */
219static void
220handle_exit_timeout(__unused void *arg)
221{
222        int timeout;
223
224        syslog(LOG_ERR, "timed out");
225        if (!(options & DHCPCD_IPV4) || !(options & DHCPCD_TIMEOUT_IPV4LL)) {
226                if (options & DHCPCD_MASTER) {
227                        /* We've timed out, so remove the waitip requirements.
228                         * If the user doesn't like this they can always set
229                         * an infinite timeout. */
230                        options &=
231                            ~(DHCPCD_WAITIP | DHCPCD_WAITIP4 | DHCPCD_WAITIP6);
232                        daemonise();
233                        return;
234                } else
235                        exit(EXIT_FAILURE);
236        }
237        options &= ~DHCPCD_TIMEOUT_IPV4LL;
238        timeout = (PROBE_NUM * PROBE_MAX) + (PROBE_WAIT * 2);
239        syslog(LOG_WARNING, "allowing %d seconds for IPv4LL timeout", timeout);
240        eloop_timeout_add_sec(timeout, handle_exit_timeout, NULL);
241}
242
243pid_t
244daemonise(void)
245{
246#ifdef THERE_IS_NO_FORK
247        return -1;
248#else
249        pid_t pid;
250        char buf = '\0';
251        int sidpipe[2], fd;
252
253        if (options & DHCPCD_DAEMONISE && !(options & DHCPCD_DAEMONISED)) {
254                if (options & DHCPCD_WAITIP4 &&
255                    !ipv4_addrexists(NULL))
256                        return -1;
257                if (options & DHCPCD_WAITIP6 &&
258                    !ipv6nd_addrexists(NULL) &&
259                    !dhcp6_addrexists(NULL))
260                        return -1;
261                if ((options &
262                    (DHCPCD_WAITIP | DHCPCD_WAITIP4 | DHCPCD_WAITIP6)) ==
263                    DHCPCD_WAITIP &&
264                    !ipv4_addrexists(NULL) &&
265                    !ipv6nd_addrexists(NULL) &&
266                    !dhcp6_addrexists(NULL))
267                        return -1;
268        }
269
270        eloop_timeout_delete(handle_exit_timeout, NULL);
271        if (options & DHCPCD_DAEMONISED || !(options & DHCPCD_DAEMONISE))
272                return 0;
273        /* Setup a signal pipe so parent knows when to exit. */
274        if (pipe(sidpipe) == -1) {
275                syslog(LOG_ERR, "pipe: %m");
276                return -1;
277        }
278        syslog(LOG_DEBUG, "forking to background");
279        switch (pid = fork()) {
280        case -1:
281                syslog(LOG_ERR, "fork: %m");
282                exit(EXIT_FAILURE);
283                /* NOTREACHED */
284        case 0:
285                setsid();
286                /* Notify parent it's safe to exit as we've detached. */
287                close(sidpipe[0]);
288                if (write(sidpipe[1], &buf, 1) == -1)
289                        syslog(LOG_ERR, "failed to notify parent: %m");
290                close(sidpipe[1]);
291                if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
292                        dup2(fd, STDIN_FILENO);
293                        dup2(fd, STDOUT_FILENO);
294                        dup2(fd, STDERR_FILENO);
295                        close(fd);
296                }
297                break;
298        default:
299                /* Wait for child to detach */
300                close(sidpipe[1]);
301                if (read(sidpipe[0], &buf, 1) == -1)
302                        syslog(LOG_ERR, "failed to read child: %m");
303                close(sidpipe[0]);
304                break;
305        }
306        /* Done with the fd now */
307        if (pid != 0) {
308                syslog(LOG_INFO, "forked to background, child pid %d",pid);
309                writepid(pidfd, pid);
310                close(pidfd);
311                pidfd = -1;
312                options |= DHCPCD_FORKED;
313                exit(EXIT_SUCCESS);
314        }
315        options |= DHCPCD_DAEMONISED;
316        return pid;
317#endif
318}
319
320struct interface *
321find_interface(const char *ifname)
322{
323        struct interface *ifp;
324
325        TAILQ_FOREACH(ifp, ifaces, next) {
326                if (strcmp(ifp->name, ifname) == 0)
327                        return ifp;
328        }
329        return NULL;
330}
331
332static void
333stop_interface(struct interface *ifp)
334{
335
336        syslog(LOG_INFO, "%s: removing interface", ifp->name);
337        ifp->options->options |= DHCPCD_STOPPING;
338
339        // Remove the interface from our list
340        TAILQ_REMOVE(ifaces, ifp, next);
341        dhcp6_drop(ifp, NULL);
342        ipv6nd_drop(ifp);
343        dhcp_drop(ifp, "STOP");
344        dhcp_close(ifp);
345        eloop_timeout_delete(NULL, ifp);
346        if (ifp->options->options & DHCPCD_DEPARTED)
347                script_runreason(ifp, "DEPARTED");
348        free_interface(ifp);
349        if (!(options & (DHCPCD_MASTER | DHCPCD_TEST)))
350                exit(EXIT_FAILURE);
351}
352
353static void
354configure_interface1(struct interface *ifp)
355{
356        struct if_options *ifo = ifp->options;
357        int ra_global, ra_iface;
358
359        /* Do any platform specific configuration */
360        if_conf(ifp);
361
362        /* If we want to release a lease, we can't really persist the
363         * address either. */
364        if (ifo->options & DHCPCD_RELEASE)
365                ifo->options &= ~DHCPCD_PERSISTENT;
366
367        if (ifp->flags & IFF_POINTOPOINT && !(ifo->options & DHCPCD_INFORM))
368                ifo->options |= DHCPCD_STATIC;
369        if (ifp->flags & IFF_NOARP ||
370            ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC))
371                ifo->options &= ~(DHCPCD_ARP | DHCPCD_IPV4LL);
372        if (!(ifp->flags & (IFF_POINTOPOINT | IFF_LOOPBACK | IFF_MULTICAST)))
373                ifo->options &= ~DHCPCD_IPV6RS;
374        if (ifo->options & DHCPCD_LINK && carrier_status(ifp) == LINK_UNKNOWN)
375                ifo->options &= ~DHCPCD_LINK;
376
377        if (ifo->metric != -1)
378                ifp->metric = ifo->metric;
379
380        if (!(ifo->options & DHCPCD_IPV6))
381                ifo->options &= ~DHCPCD_IPV6RS;
382
383        /* We want to disable kernel interface RA as early as possible. */
384        if (ifo->options & DHCPCD_IPV6RS) {
385                ra_global = check_ipv6(NULL, options & DHCPCD_IPV6RA_OWN ? 1:0);
386                ra_iface = check_ipv6(ifp->name,
387                    ifp->options->options & DHCPCD_IPV6RA_OWN ? 1 : 0);
388                if (ra_global == -1 || ra_iface == -1)
389                        ifo->options &= ~DHCPCD_IPV6RS;
390                else if (ra_iface == 0)
391                        ifo->options |= DHCPCD_IPV6RA_OWN;
392        }
393
394        /* If we haven't specified a ClientID and our hardware address
395         * length is greater than DHCP_CHADDR_LEN then we enforce a ClientID
396         * of the hardware address family and the hardware address. */
397        if (ifp->hwlen > DHCP_CHADDR_LEN)
398                ifo->options |= DHCPCD_CLIENTID;
399
400        /* Firewire and InfiniBand interfaces require ClientID and
401         * the broadcast option being set. */
402        switch (ifp->family) {
403        case ARPHRD_IEEE1394:   /* FALLTHROUGH */
404        case ARPHRD_INFINIBAND:
405                ifo->options |= DHCPCD_CLIENTID | DHCPCD_BROADCAST;
406                break;
407        }
408
409        if (!(ifo->options & DHCPCD_IAID)) {
410                /*
411                 * An IAID is for identifying a unqiue interface within
412                 * the client. It is 4 bytes long. Working out a default
413                 * value is problematic.
414                 *
415                 * Interface name and number are not stable
416                 * between different OS's. Some OS's also cannot make
417                 * up their mind what the interface should be called
418                 * (yes, udev, I'm looking at you).
419                 * Also, the name could be longer than 4 bytes.
420                 * Also, with pluggable interfaces the name and index
421                 * could easily get swapped per actual interface.
422                 *
423                 * The MAC address is 6 bytes long, the final 3
424                 * being unique to the manufacturer and the initial 3
425                 * being unique to the organisation which makes it.
426                 * We could use the last 4 bytes of the MAC address
427                 * as the IAID as it's the most stable part given the
428                 * above, but equally it's not guaranteed to be
429                 * unique.
430                 *
431                 * Given the above, and our need to reliably work
432                 * between reboots without persitent storage,
433                 * generating the IAID from the MAC address is the only
434                 * logical default.
435                 *
436                 * dhclient uses the last 4 bytes of the MAC address.
437                 * dibbler uses an increamenting counter.
438                 * wide-dhcpv6 uses 0 or a configured value.
439                 * odhcp6c uses 1.
440                 * Windows 7 uses the first 3 bytes of the MAC address
441                 * and an unknown byte.
442                 * dhcpcd-6.1.0 and earlier used the interface name,
443                 * falling back to interface index if name > 4.
444                 */
445                memcpy(ifo->iaid, ifp->hwaddr + ifp->hwlen - sizeof(ifo->iaid),
446                    sizeof(ifo->iaid));
447#if 0
448                len = strlen(ifp->name);
449                if (len <= sizeof(ifo->iaid)) {
450                        memcpy(ifo->iaid, ifp->name, len);
451                        memset(ifo->iaid + len, 0, sizeof(ifo->iaid) - len);
452                } else {
453                        /* IAID is the same size as a uint32_t */
454                        len = htonl(ifp->index);
455                        memcpy(ifo->iaid, &len, sizeof(len));
456                }
457#endif
458                ifo->options |= DHCPCD_IAID;
459        }
460
461#ifdef INET6
462        if (ifo->ia == NULL && ifo->options & DHCPCD_IPV6) {
463                ifo->ia = malloc(sizeof(*ifo->ia));
464                if (ifo->ia == NULL)
465                        syslog(LOG_ERR, "%s: %m", __func__);
466                else {
467                        if (ifo->ia_type == 0)
468                                ifo->ia_type = D6_OPTION_IA_NA;
469                        memcpy(ifo->ia->iaid, ifo->iaid, sizeof(ifo->iaid));
470                        ifo->ia_len = 1;
471                        ifo->ia->sla = NULL;
472                        ifo->ia->sla_len = 0;
473                }
474        }
475#endif
476
477        /* If we are not sending an authentication option, don't require it */
478        if (!(ifo->auth.options & DHCPCD_AUTH_SEND))
479                ifo->auth.options &= ~DHCPCD_AUTH_REQUIRE;
480
481}
482
483int
484select_profile(struct interface *ifp, const char *profile)
485{
486        struct if_options *ifo;
487        int ret;
488
489        ret = 0;
490        ifo = read_config(cffile, ifp->name, ifp->ssid, profile);
491        if (ifo == NULL) {
492                syslog(LOG_DEBUG, "%s: no profile %s", ifp->name, profile);
493                ret = -1;
494                goto exit;
495        }
496        if (profile != NULL) {
497                strlcpy(ifp->profile, profile, sizeof(ifp->profile));
498                syslog(LOG_INFO, "%s: selected profile %s",
499                    ifp->name, profile);
500        } else
501                *ifp->profile = '\0';
502        free_options(ifp->options);
503        ifp->options = ifo;
504
505exit:
506        if (profile)
507                configure_interface1(ifp);
508        return ret;
509}
510
511static void
512configure_interface(struct interface *ifp, int argc, char **argv)
513{
514
515        select_profile(ifp, NULL);
516        add_options(ifp->name, ifp->options, argc, argv);
517        configure_interface1(ifp);
518}
519
520void
521handle_carrier(int carrier, int flags, const char *ifname)
522{
523        struct interface *ifp;
524
525        ifp = find_interface(ifname);
526        if (ifp == NULL || !(ifp->options->options & DHCPCD_LINK))
527                return;
528
529        if (carrier == LINK_UNKNOWN)
530                carrier = carrier_status(ifp); /* will set ifp->flags */
531        else
532                ifp->flags = flags;
533
534        if (carrier == LINK_UNKNOWN)
535                syslog(LOG_ERR, "%s: carrier_status: %m", ifname);
536        /* IFF_RUNNING is checked, if needed, earlier and is OS dependant */
537        else if (carrier == LINK_DOWN || (ifp->flags & IFF_UP) == 0) {
538                if (ifp->carrier != LINK_DOWN) {
539                        if (ifp->carrier == LINK_UP)
540                                syslog(LOG_INFO, "%s: carrier lost", ifp->name);
541                        ifp->carrier = LINK_DOWN;
542                        dhcp_close(ifp);
543                        dhcp6_drop(ifp, "EXPIRE6");
544                        ipv6nd_drop(ifp);
545                        /* Don't blindly delete our knowledge of LL addresses.
546                         * We need to listen to what the kernel does with
547                         * them as some OS's will remove, mark tentative or
548                         * do nothing. */
549                        ipv6_free_ll_callbacks(ifp);
550                        dhcp_drop(ifp, "NOCARRIER");
551                }
552        } else if (carrier == LINK_UP && ifp->flags & IFF_UP) {
553                if (ifp->carrier != LINK_UP) {
554                        syslog(LOG_INFO, "%s: carrier acquired", ifp->name);
555                        ifp->carrier = LINK_UP;
556#if !defined(__linux__) && !defined(__NetBSD__)
557                        /* BSD does not emit RTM_NEWADDR or RTM_CHGADDR when the
558                         * hardware address changes so we have to go
559                         * through the disovery process to work it out. */
560                        handle_interface(0, ifp->name);
561#endif
562                        if (ifp->wireless)
563                                getifssid(ifp->name, ifp->ssid);
564                        configure_interface(ifp, margc, margv);
565                        script_runreason(ifp, "CARRIER");
566                        start_interface(ifp);
567                }
568        }
569}
570
571static void
572warn_iaid_conflict(struct interface *ifp, uint8_t *iaid)
573{
574        struct interface *ifn;
575        size_t i;
576
577        TAILQ_FOREACH(ifn, ifaces, next) {
578                if (ifn == ifp)
579                        continue;
580                if (memcmp(ifn->options->iaid, iaid,
581                    sizeof(ifn->options->iaid)) == 0)
582                        break;
583                for (i = 0; i < ifn->options->ia_len; i++) {
584                        if (memcmp(&ifn->options->ia[i].iaid, iaid,
585                            sizeof(ifn->options->ia[i].iaid)) == 0)
586                                break;
587                }
588        }
589
590        /* This is only a problem if the interfaces are on the same network. */
591        if (ifn)
592                syslog(LOG_ERR,
593                    "%s: IAID conflicts with one assigned to %s",
594                    ifp->name, ifn->name);
595}
596
597void
598start_interface(void *arg)
599{
600        struct interface *ifp = arg;
601        struct if_options *ifo = ifp->options;
602        int nolease;
603        size_t i;
604
605        handle_carrier(LINK_UNKNOWN, 0, ifp->name);
606        if (ifp->carrier == LINK_DOWN) {
607                syslog(LOG_INFO, "%s: waiting for carrier", ifp->name);
608                return;
609        }
610
611        if (ifo->options & (DHCPCD_DUID | DHCPCD_IPV6)) {
612                /* Report client DUID */
613                if (duid == NULL) {
614                        if (duid_init(ifp) == 0)
615                                return;
616                        syslog(LOG_INFO, "DUID %s",
617                            hwaddr_ntoa(duid, duid_len));
618                }
619
620                /* Report IAIDs */
621                syslog(LOG_INFO, "%s: IAID %s", ifp->name,
622                    hwaddr_ntoa(ifo->iaid, sizeof(ifo->iaid)));
623                warn_iaid_conflict(ifp, ifo->iaid);
624                for (i = 0; i < ifo->ia_len; i++) {
625                        if (memcmp(ifo->iaid, ifo->ia[i].iaid,
626                            sizeof(ifo->iaid)))
627                        {
628                                syslog(LOG_INFO, "%s: IAID %s", ifp->name,
629                                    hwaddr_ntoa(ifo->ia[i].iaid,
630                                    sizeof(ifo->ia[i].iaid)));
631                                warn_iaid_conflict(ifp, ifo->ia[i].iaid);
632                        }
633                }
634        }
635
636        if (ifo->options & DHCPCD_IPV6) {
637                if (ifo->options & DHCPCD_IPV6RS &&
638                    !(ifo->options & DHCPCD_INFORM))
639                        ipv6nd_startrs(ifp);
640
641                if (!(ifo->options & DHCPCD_IPV6RS)) {
642                        if (ifo->options & DHCPCD_IA_FORCED)
643                                nolease = dhcp6_start(ifp, DH6S_INIT);
644                        else {
645                                nolease = dhcp6_find_delegates(ifp);
646                                /* Enabling the below doesn't really make
647                                 * sense as there is currently no standard
648                                 * to push routes via DHCPv6.
649                                 * (There is an expired working draft,
650                                 * maybe abandoned?)
651                                 * You can also get it to work by forcing
652                                 * an IA as shown above. */
653#if 0
654                                /* With no RS or delegates we might
655                                 * as well try and solicit a DHCPv6 address */
656                                if (nolease == 0)
657                                        nolease = dhcp6_start(ifp, DH6S_INIT);
658#endif
659                        }
660                        if (nolease == -1)
661                                syslog(LOG_ERR,
662                                    "%s: dhcp6_start: %m", ifp->name);
663                }
664        }
665
666        if (ifo->options & DHCPCD_IPV4)
667                dhcp_start(ifp);
668}
669
670/* ARGSUSED */
671static void
672handle_link(__unused void *arg)
673{
674
675        if (manage_link(linkfd) == -1 && errno != ENXIO && errno != ENODEV)
676                syslog(LOG_ERR, "manage_link: %m");
677}
678
679static void
680init_state(struct interface *ifp, int argc, char **argv)
681{
682        struct if_options *ifo;
683        const char *reason = NULL;
684
685        configure_interface(ifp, argc, argv);
686        ifo = ifp->options;
687
688        if (ifo->options & DHCPCD_IPV4 && ipv4_init() == -1) {
689                syslog(LOG_ERR, "ipv4_init: %m");
690                ifo->options &= ~DHCPCD_IPV4;
691        }
692        if (ifo->options & DHCPCD_IPV6 && ipv6_init() == -1) {
693                syslog(LOG_ERR, "ipv6_init: %m");
694                ifo->options &= ~DHCPCD_IPV6RS;
695        }
696
697        if (!(options & DHCPCD_TEST))
698                script_runreason(ifp, "PREINIT");
699
700        if (ifo->options & DHCPCD_LINK) {
701                switch (carrier_status(ifp)) {
702                case LINK_DOWN:
703                        ifp->carrier = LINK_DOWN;
704                        reason = "NOCARRIER";
705                        break;
706                case LINK_UP:
707                        ifp->carrier = LINK_UP;
708                        reason = "CARRIER";
709                        break;
710                default:
711                        ifp->carrier = LINK_UNKNOWN;
712                        return;
713                }
714                if (reason && !(options & DHCPCD_TEST))
715                        script_runreason(ifp, reason);
716        } else
717                ifp->carrier = LINK_UNKNOWN;
718}
719
720void
721handle_interface(int action, const char *ifname)
722{
723        struct if_head *ifs;
724        struct interface *ifp, *ifn, *ifl = NULL;
725        const char * const argv[] = { ifname };
726        int i;
727
728        if (action == -1) {
729                ifp = find_interface(ifname);
730                if (ifp != NULL) {
731                        ifp->options->options |= DHCPCD_DEPARTED;
732                        stop_interface(ifp);
733                }
734                return;
735        }
736
737        /* If running off an interface list, check it's in it. */
738        if (ifc) {
739                for (i = 0; i < ifc; i++)
740                        if (strcmp(ifv[i], ifname) == 0)
741                                break;
742                if (i >= ifc)
743                        return;
744        }
745
746        ifs = discover_interfaces(-1, UNCONST(argv));
747        TAILQ_FOREACH_SAFE(ifp, ifs, next, ifn) {
748                if (strcmp(ifp->name, ifname) != 0)
749                        continue;
750                /* Check if we already have the interface */
751                ifl = find_interface(ifp->name);
752                if (ifl) {
753                        /* The flags and hwaddr could have changed */
754                        ifl->flags = ifp->flags;
755                        ifl->hwlen = ifp->hwlen;
756                        if (ifp->hwlen != 0)
757                                memcpy(ifl->hwaddr, ifp->hwaddr, ifl->hwlen);
758                } else {
759                        TAILQ_REMOVE(ifs, ifp, next);
760                        TAILQ_INSERT_TAIL(ifaces, ifp, next);
761                }
762                if (action == 1) {
763                        init_state(ifp, margc, margv);
764                        start_interface(ifp);
765                }
766        }
767
768        /* Free our discovered list */
769        while ((ifp = TAILQ_FIRST(ifs))) {
770                TAILQ_REMOVE(ifs, ifp, next);
771                free_interface(ifp);
772        }
773        free(ifs);
774}
775
776void
777handle_hwaddr(const char *ifname, const uint8_t *hwaddr, size_t hwlen)
778{
779        struct interface *ifp;
780
781        ifp = find_interface(ifname);
782        if (ifp == NULL)
783                return;
784
785        if (hwlen > sizeof(ifp->hwaddr)) {
786                errno = ENOBUFS;
787                syslog(LOG_ERR, "%s: %s: %m", ifp->name, __func__);
788                return;
789        }
790
791        if (ifp->hwlen == hwlen && memcmp(ifp->hwaddr, hwaddr, hwlen) == 0)
792                return;
793
794        syslog(LOG_INFO, "%s: new hardware address: %s", ifp->name,
795            hwaddr_ntoa(hwaddr, hwlen));
796        ifp->hwlen = hwlen;
797        memcpy(ifp->hwaddr, hwaddr, hwlen);
798}
799
800static void
801if_reboot(struct interface *ifp, int argc, char **argv)
802{
803        int oldopts;
804
805        oldopts = ifp->options->options;
806        script_runreason(ifp, "RECONFIGURE");
807        configure_interface(ifp, argc, argv);
808        dhcp_reboot_newopts(ifp, oldopts);
809        dhcp6_reboot(ifp);
810        start_interface(ifp);
811}
812
813static void
814reconf_reboot(int action, int argc, char **argv, int oi)
815{
816        struct if_head *ifs;
817        struct interface *ifn, *ifp;
818
819        ifs = discover_interfaces(argc - oi, argv + oi);
820        if (ifs == NULL)
821                return;
822
823        while ((ifp = TAILQ_FIRST(ifs))) {
824                TAILQ_REMOVE(ifs, ifp, next);
825                ifn = find_interface(ifp->name);
826                if (ifn) {
827                        if (action)
828                                if_reboot(ifn, argc, argv);
829                        else
830                                ipv4_applyaddr(ifn);
831                        free_interface(ifp);
832                } else {
833                        init_state(ifp, argc, argv);
834                        TAILQ_INSERT_TAIL(ifaces, ifp, next);
835                        start_interface(ifp);
836                }
837        }
838        free(ifs);
839
840        sort_interfaces();
841}
842
843#ifndef MASTER_ONLY
844/* ARGSUSED */
845static void
846sig_reboot(void *arg)
847{
848        siginfo_t *siginfo = arg;
849        struct if_options *ifo;
850
851        syslog(LOG_INFO, "received SIGALRM from PID %d, rebinding",
852            (int)siginfo->si_pid);
853
854        free_globals();
855        ifav = NULL;
856        ifac = 0;
857        ifdc = 0;
858        ifdv = NULL;
859
860        ifo = read_config(cffile, NULL, NULL, NULL);
861        add_options(NULL, ifo, margc, margv);
862        /* We need to preserve these two options. */
863        if (options & DHCPCD_MASTER)
864                ifo->options |= DHCPCD_MASTER;
865        if (options & DHCPCD_DAEMONISED)
866                ifo->options |= DHCPCD_DAEMONISED;
867        options = ifo->options;
868        free_options(ifo);
869        reconf_reboot(1, ifc, ifv, 0);
870}
871
872static void
873sig_reconf(void *arg)
874{
875        siginfo_t *siginfo = arg;
876        struct interface *ifp;
877
878        syslog(LOG_INFO, "received SIGUSR from PID %d, reconfiguring",
879            (int)siginfo->si_pid);
880        TAILQ_FOREACH(ifp, ifaces, next) {
881                ipv4_applyaddr(ifp);
882        }
883}
884
885static void
886handle_signal(int sig, siginfo_t *siginfo, __unused void *context)
887{
888        struct interface *ifp;
889        int do_release;
890
891        do_release = 0;
892        switch (sig) {
893        case SIGINT:
894                syslog(LOG_INFO, "received SIGINT from PID %d, stopping",
895                    (int)siginfo->si_pid);
896                break;
897        case SIGTERM:
898                syslog(LOG_INFO, "received SIGTERM from PID %d, stopping",
899                    (int)siginfo->si_pid);
900                break;
901        case SIGALRM:
902                eloop_timeout_add_now(sig_reboot, siginfo);
903                return;
904        case SIGHUP:
905                syslog(LOG_INFO, "received SIGHUP from PID %d, releasing",
906                    (int)siginfo->si_pid);
907                do_release = 1;
908                break;
909        case SIGUSR1:
910                eloop_timeout_add_now(sig_reconf, siginfo);
911                return;
912        case SIGPIPE:
913                syslog(LOG_WARNING, "received SIGPIPE");
914                return;
915        default:
916                syslog(LOG_ERR,
917                    "received signal %d from PID %d, "
918                    "but don't know what to do with it",
919                    sig, (int)siginfo->si_pid);
920                return;
921        }
922
923        if (options & DHCPCD_TEST)
924                exit(EXIT_FAILURE);
925
926        /* As drop_dhcp could re-arrange the order, we do it like this. */
927        for (;;) {
928                /* Be sane and drop the last config first */
929                ifp = TAILQ_LAST(ifaces, if_head);
930                if (ifp == NULL)
931                        break;
932                if (do_release) {
933                        ifp->options->options |= DHCPCD_RELEASE;
934                        ifp->options->options &= ~DHCPCD_PERSISTENT;
935                }
936                ifp->options->options |= DHCPCD_EXITING;
937                stop_interface(ifp);
938        }
939        exit(EXIT_FAILURE);
940}
941#endif /* MASTER_ONLY */
942
943int
944handle_args(struct fd_list *fd, int argc, char **argv)
945{
946        struct interface *ifp;
947        int do_exit = 0, do_release = 0, do_reboot = 0;
948        int opt, oi = 0;
949        ssize_t len;
950        size_t l;
951        struct iovec iov[2];
952        char *tmp, *p;
953
954        if (fd != NULL) {
955                /* Special commands for our control socket */
956                if (strcmp(*argv, "--version") == 0) {
957                        len = strlen(VERSION) + 1;
958                        iov[0].iov_base = &len;
959                        iov[0].iov_len = sizeof(ssize_t);
960                        iov[1].iov_base = UNCONST(VERSION);
961                        iov[1].iov_len = len;
962                        if (writev(fd->fd, iov, 2) == -1) {
963                                syslog(LOG_ERR, "writev: %m");
964                                return -1;
965                        }
966                        return 0;
967                } else if (strcmp(*argv, "--getconfigfile") == 0) {
968                        len = strlen(cffile ? cffile : CONFIG) + 1;
969                        iov[0].iov_base = &len;
970                        iov[0].iov_len = sizeof(ssize_t);
971                        iov[1].iov_base = cffile ? cffile : UNCONST(CONFIG);
972                        iov[1].iov_len = len;
973                        if (writev(fd->fd, iov, 2) == -1) {
974                                syslog(LOG_ERR, "writev: %m");
975                                return -1;
976                        }
977                        return 0;
978                } else if (strcmp(*argv, "--getinterfaces") == 0) {
979                        len = 0;
980                        if (argc == 1) {
981                                TAILQ_FOREACH(ifp, ifaces, next) {
982                                        len++;
983                                        if (D6_STATE_RUNNING(ifp))
984                                                len++;
985                                        if (ipv6nd_has_ra(ifp))
986                                                len++;
987                                }
988                                len = write(fd->fd, &len, sizeof(len));
989                                if (len != sizeof(len))
990                                        return -1;
991                                TAILQ_FOREACH(ifp, ifaces, next) {
992                                        send_interface(fd->fd, ifp);
993                                }
994                                return 0;
995                        }
996                        opt = 0;
997                        while (argv[++opt] != NULL) {
998                                TAILQ_FOREACH(ifp, ifaces, next) {
999                                        if (strcmp(argv[opt], ifp->name) == 0) {
1000                                                len++;
1001                                                if (D6_STATE_RUNNING(ifp))
1002                                                        len++;
1003                                                if (ipv6nd_has_ra(ifp))
1004                                                        len++;
1005                                        }
1006                                }
1007                        }
1008                        len = write(fd->fd, &len, sizeof(len));
1009                        if (len != sizeof(len))
1010                                return -1;
1011                        opt = 0;
1012                        while (argv[++opt] != NULL) {
1013                                TAILQ_FOREACH(ifp, ifaces, next) {
1014                                        if (strcmp(argv[opt], ifp->name) == 0)
1015                                                send_interface(fd->fd, ifp);
1016                                }
1017                        }
1018                        return 0;
1019                } else if (strcmp(*argv, "--listen") == 0) {
1020                        fd->listener = 1;
1021                        return 0;
1022                }
1023        }
1024
1025        /* Log the command */
1026        len = 0;
1027        for (opt = 0; opt < argc; opt++)
1028                len += strlen(argv[opt]) + 1;
1029        tmp = p = malloc(len + 1);
1030        if (tmp == NULL) {
1031                syslog(LOG_ERR, "%s: %m", __func__);
1032                return -1;
1033        }
1034        for (opt = 0; opt < argc; opt++) {
1035                l = strlen(argv[opt]);
1036                strlcpy(p, argv[opt], l + 1);
1037                p += l;
1038                *p++ = ' ';
1039        }
1040        *--p = '\0';
1041        syslog(LOG_INFO, "control command: %s", tmp);
1042        free(tmp);
1043
1044        optind = 0;
1045        while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1)
1046        {
1047                switch (opt) {
1048                case 'g':
1049                        /* Assumed if below not set */
1050                        break;
1051                case 'k':
1052                        do_release = 1;
1053                        break;
1054                case 'n':
1055                        do_reboot = 1;
1056                        break;
1057                case 'x':
1058                        do_exit = 1;
1059                        break;
1060                }
1061        }
1062
1063        /* We need at least one interface */
1064        if (optind == argc) {
1065                syslog(LOG_ERR, "%s: no interface", __func__);
1066                return -1;
1067        }
1068
1069        if (do_release || do_exit) {
1070                for (oi = optind; oi < argc; oi++) {
1071                        if ((ifp = find_interface(argv[oi])) == NULL)
1072                                continue;
1073                        if (do_release) {
1074                                ifp->options->options |= DHCPCD_RELEASE;
1075                                ifp->options->options &= ~DHCPCD_PERSISTENT;
1076                        }
1077                        ifp->options->options |= DHCPCD_EXITING;
1078                        stop_interface(ifp);
1079                }
1080                return 0;
1081        }
1082
1083        reconf_reboot(do_reboot, argc, argv, optind);
1084        return 0;
1085}
1086
1087#ifndef MASTER_ONLY
1088static int
1089signal_init(void (*func)(int, siginfo_t *, void *), sigset_t *oldset)
1090{
1091        unsigned int i;
1092        struct sigaction sa;
1093        sigset_t newset;
1094
1095        sigfillset(&newset);
1096        if (sigprocmask(SIG_SETMASK, &newset, oldset) == -1)
1097                return -1;
1098
1099        memset(&sa, 0, sizeof(sa));
1100        sa.sa_sigaction = func;
1101        sa.sa_flags = SA_SIGINFO;
1102        sigemptyset(&sa.sa_mask);
1103
1104        for (i = 0; handle_sigs[i]; i++) {
1105                if (sigaction(handle_sigs[i], &sa, NULL) == -1)
1106                        return -1;
1107        }
1108        return 0;
1109}
1110#endif
1111
1112#ifdef __rtems__
1113#include <rtems/dhcpcd.h>
1114#include <rtems/libio.h>
1115
1116#include <assert.h>
1117
1118rtems_recursive_mutex dhcpcd_mutex =
1119    RTEMS_RECURSIVE_MUTEX_INITIALIZER("dhcpcd");
1120
1121static bool dhcpcd_initialized;
1122
1123struct getopt_data dhcpcd_getopt_data;
1124
1125static int
1126main(int argc, char **argv);
1127
1128static void
1129dhcpcd_task(rtems_task_argument arg)
1130{
1131        char *default_argv[] = { "dhcpcd", NULL };
1132        const rtems_dhcpcd_config *config;
1133        int argc;
1134        char **argv;
1135        int exit_code;
1136
1137        config = (const rtems_dhcpcd_config *)arg;
1138
1139        if (config != NULL) {
1140                argc = config->argc;
1141                argv = config->argv;
1142        } else {
1143                argc = RTEMS_BSD_ARGC(default_argv);
1144                argv = default_argv;
1145        }
1146
1147        if (config != NULL && config->prepare != NULL) {
1148                (*config->prepare)(config, argc, argv);
1149        }
1150
1151        rtems_mkdir(DBDIR, S_IRWXU | S_IRWXG | S_IRWXO);
1152        exit_code = rtems_bsd_program_call_main("dhcpcd", main, argc, argv);
1153
1154        if (config != NULL && config->destroy != NULL) {
1155                (*config->destroy)(config, exit_code);
1156        }
1157
1158        rtems_task_delete(RTEMS_SELF);
1159}
1160
1161rtems_status_code
1162rtems_dhcpcd_start(const rtems_dhcpcd_config *config)
1163{
1164        rtems_status_code sc;
1165
1166        rtems_recursive_mutex_lock(&dhcpcd_mutex);
1167
1168        if (!dhcpcd_initialized) {
1169                rtems_task_priority priority;
1170                rtems_id id;
1171
1172                if (config != NULL && config->priority != 0) {
1173                        priority = config->priority;
1174                } else {
1175                        priority = RTEMS_MAXIMUM_PRIORITY - 1;
1176                }
1177
1178                sc = rtems_task_create(rtems_build_name('D', 'H', 'C', 'P'), priority,
1179                    2 * RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES,
1180                    RTEMS_FLOATING_POINT, &id);
1181                if (sc == RTEMS_SUCCESSFUL) {
1182                        dhcpcd_initialized = true;
1183
1184                        sc = rtems_task_start(id, dhcpcd_task, 0);
1185                        assert(sc == RTEMS_SUCCESSFUL);
1186                }
1187        } else {
1188                sc = RTEMS_INCORRECT_STATE;
1189        }
1190
1191        rtems_recursive_mutex_unlock(&dhcpcd_mutex);
1192        return sc;
1193}
1194#endif /* __rtems__ */
1195
1196int
1197main(int argc, char **argv)
1198{
1199        struct interface *ifp;
1200        int opt, oi = 0, i;
1201#ifndef MASTER_ONLY
1202        uint16_t family = 0;
1203        int sig = 0, control_fd;
1204        size_t len;
1205        pid_t pid;
1206#endif
1207        struct timespec ts;
1208        struct utsname utn;
1209        const char *platform;
1210
1211        closefrom(3);
1212        openlog(PACKAGE, LOG_PERROR | LOG_PID, LOG_DAEMON);
1213        setlogmask(LOG_UPTO(LOG_INFO));
1214
1215#ifndef MASTER_ONLY
1216        /* Test for --help and --version */
1217        if (argc > 1) {
1218                if (strcmp(argv[1], "--help") == 0) {
1219                        usage();
1220                        exit(EXIT_SUCCESS);
1221                } else if (strcmp(argv[1], "--version") == 0) {
1222                        printf(""PACKAGE" "VERSION"\n%s\n", dhcpcd_copyright);
1223                        exit(EXIT_SUCCESS);
1224                }
1225        }
1226#endif
1227
1228        platform = hardware_platform();
1229        if (uname(&utn) == 0)
1230                snprintf(vendor, VENDORCLASSID_MAX_LEN,
1231                    "%s-%s:%s-%s:%s%s%s", PACKAGE, VERSION,
1232                    utn.sysname, utn.release, utn.machine,
1233                    platform ? ":" : "", platform ? platform : "");
1234        else
1235                snprintf(vendor, VENDORCLASSID_MAX_LEN,
1236                    "%s-%s", PACKAGE, VERSION);
1237
1238#ifndef MASTER_ONLY
1239        i = 0;
1240#endif
1241        while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1)
1242        {
1243                switch (opt) {
1244#ifndef MASTER_ONLY
1245                case '4':
1246                        family = AF_INET;
1247                        break;
1248                case '6':
1249                        family = AF_INET6;
1250                        break;
1251#endif
1252                case 'f':
1253                        cffile = optarg;
1254                        break;
1255#ifndef MASTER_ONLY
1256                case 'g':
1257                        sig = SIGUSR1;
1258                        break;
1259                case 'k':
1260                        sig = SIGHUP;
1261                        break;
1262                case 'n':
1263                        sig = SIGALRM;
1264                        break;
1265                case 'x':
1266                        sig = SIGTERM;
1267                        break;
1268                case 'T':
1269                        i = 1;
1270                        break;
1271                case 'U':
1272                        i = 2;
1273                        break;
1274                case 'V':
1275                        i = 3;
1276                        break;
1277#endif
1278                case '?':
1279                        usage();
1280                        exit(EXIT_FAILURE);
1281                }
1282        }
1283
1284        margv = argv;
1285        margc = argc;
1286        if_options = read_config(cffile, NULL, NULL, NULL);
1287        opt = add_options(NULL, if_options, argc, argv);
1288        if (opt != 1) {
1289                if (opt == 0)
1290                        usage();
1291                exit(EXIT_FAILURE);
1292        }
1293#ifndef MASTER_ONLY
1294        if (i == 3) {
1295                printf("Interface options:\n");
1296                if_printoptions();
1297#ifdef INET
1298                if (family == 0 || family == AF_INET) {
1299                        printf("\nDHCPv4 options:\n");
1300                        dhcp_printoptions();
1301                }
1302#endif
1303#ifdef INET6
1304                if (family == 0 || family == AF_INET6) {
1305                        printf("\nDHCPv6 options:\n");
1306                        dhcp6_printoptions();
1307                }
1308#endif
1309#ifdef DEBUG_MEMORY
1310                cleanup();
1311#endif
1312                exit(EXIT_SUCCESS);
1313        }
1314#endif /* !MASTER_ONLY */
1315        options = if_options->options;
1316#ifndef MASTER_ONLY
1317        if (i != 0) {
1318                if (i == 1)
1319                        options |= DHCPCD_TEST;
1320                else
1321                        options |= DHCPCD_DUMPLEASE;
1322                options |= DHCPCD_PERSISTENT;
1323                options &= ~DHCPCD_DAEMONISE;
1324        }
1325#endif
1326
1327#ifdef THERE_IS_NO_FORK
1328        options &= ~DHCPCD_DAEMONISE;
1329#endif
1330
1331        if (options & DHCPCD_DEBUG)
1332                setlogmask(LOG_UPTO(LOG_DEBUG));
1333#ifndef MASTER_ONLY
1334        if (options & DHCPCD_QUIET) {
1335                i = open(_PATH_DEVNULL, O_RDWR);
1336                if (i == -1)
1337                        syslog(LOG_ERR, "%s: open: %m", __func__);
1338                else {
1339                        dup2(i, STDERR_FILENO);
1340                        close(i);
1341                }
1342        }
1343
1344        if (!(options & (DHCPCD_TEST | DHCPCD_DUMPLEASE))) {
1345                /* If we have any other args, we should run as a single dhcpcd
1346                 *  instance for that interface. */
1347                len = strlen(PIDFILE) + IF_NAMESIZE + 2;
1348                pidfile = malloc(len);
1349                if (pidfile == NULL) {
1350                        syslog(LOG_ERR, "%s: %m", __func__);
1351                        exit(EXIT_FAILURE);
1352                }
1353                if (optind == argc - 1)
1354                        snprintf(pidfile, len, PIDFILE, "-", argv[optind]);
1355                else {
1356                        snprintf(pidfile, len, PIDFILE, "", "");
1357                        options |= DHCPCD_MASTER;
1358                }
1359        }
1360#else
1361        options |= DHCPCD_MASTER;
1362#endif
1363
1364        if (chdir("/") == -1)
1365                syslog(LOG_ERR, "chdir `/': %m");
1366#ifndef MASTER_ONLY
1367        atexit(cleanup);
1368
1369        if (options & DHCPCD_DUMPLEASE) {
1370                if (optind != argc - 1) {
1371                        syslog(LOG_ERR, "dumplease requires an interface");
1372                        exit(EXIT_FAILURE);
1373                }
1374                if (dhcp_dump(argv[optind]) == -1)
1375                        exit(EXIT_FAILURE);
1376                exit(EXIT_SUCCESS);
1377        }
1378
1379        if (!(options & (DHCPCD_MASTER | DHCPCD_TEST))) {
1380                control_fd = control_open();
1381                if (control_fd != -1) {
1382                        syslog(LOG_INFO,
1383                            "sending commands to master dhcpcd process");
1384                        i = control_send(argc, argv);
1385                        if (i > 0) {
1386                                syslog(LOG_DEBUG, "send OK");
1387                                exit(EXIT_SUCCESS);
1388                        } else {
1389                                syslog(LOG_ERR, "failed to send commands");
1390                                exit(EXIT_FAILURE);
1391                        }
1392                } else {
1393                        if (errno != ENOENT)
1394                                syslog(LOG_ERR, "control_open: %m");
1395                }
1396        }
1397
1398        if (geteuid())
1399                syslog(LOG_WARNING,
1400                    PACKAGE " will not work correctly unless run as root");
1401
1402        if (sig != 0) {
1403                pid = read_pid();
1404                if (pid != 0)
1405                        syslog(LOG_INFO, "sending signal %d to pid %d",
1406                            sig, pid);
1407                if (pid == 0 || kill(pid, sig) != 0) {
1408                        if (sig != SIGALRM && errno != EPERM)
1409                                syslog(LOG_ERR, ""PACKAGE" not running");
1410                        if (pid != 0 && errno != ESRCH) {
1411                                syslog(LOG_ERR, "kill: %m");
1412                                exit(EXIT_FAILURE);
1413                        }
1414                        unlink(pidfile);
1415                        if (sig != SIGALRM)
1416                                exit(EXIT_FAILURE);
1417                } else {
1418                        if (sig == SIGALRM || sig == SIGUSR1)
1419                                exit(EXIT_SUCCESS);
1420                        /* Spin until it exits */
1421                        syslog(LOG_INFO, "waiting for pid %d to exit", pid);
1422                        ts.tv_sec = 0;
1423                        ts.tv_nsec = 100000000; /* 10th of a second */
1424                        for(i = 0; i < 100; i++) {
1425                                nanosleep(&ts, NULL);
1426                                if (read_pid() == 0)
1427                                        exit(EXIT_SUCCESS);
1428                        }
1429                        syslog(LOG_ERR, "pid %d failed to exit", pid);
1430                        exit(EXIT_FAILURE);
1431                }
1432        }
1433
1434        if (!(options & DHCPCD_TEST)) {
1435                if ((pid = read_pid()) > 0 &&
1436                    kill(pid, 0) == 0)
1437                {
1438                        syslog(LOG_ERR, ""PACKAGE
1439                            " already running on pid %d (%s)",
1440                            pid, pidfile);
1441                        exit(EXIT_FAILURE);
1442                }
1443
1444                /* Ensure we have the needed directories */
1445                if (mkdir(RUNDIR, 0755) == -1 && errno != EEXIST)
1446                        syslog(LOG_ERR, "mkdir `%s': %m", RUNDIR);
1447                if (mkdir(DBDIR, 0755) == -1 && errno != EEXIST)
1448                        syslog(LOG_ERR, "mkdir `%s': %m", DBDIR);
1449
1450                pidfd = open(pidfile, O_WRONLY | O_CREAT | O_NONBLOCK, 0664);
1451                if (pidfd == -1)
1452                        syslog(LOG_ERR, "open `%s': %m", pidfile);
1453                else {
1454                        /* Lock the file so that only one instance of dhcpcd
1455                         * runs on an interface */
1456                        if (flock(pidfd, LOCK_EX | LOCK_NB) == -1) {
1457                                syslog(LOG_ERR, "flock `%s': %m", pidfile);
1458                                exit(EXIT_FAILURE);
1459                        }
1460                        if (set_cloexec(pidfd) == -1)
1461                                exit(EXIT_FAILURE);
1462                        writepid(pidfd, getpid());
1463                }
1464        }
1465#endif /* !MASTER_ONLY */
1466
1467        syslog(LOG_INFO, "version " VERSION " starting");
1468        options |= DHCPCD_STARTED;
1469
1470#ifdef DEBUG_MEMORY
1471        eloop_init();
1472#endif
1473
1474#ifndef MASTER_ONLY
1475        /* Save signal mask, block and redirect signals to our handler */
1476        if (signal_init(handle_signal, &dhcpcd_sigset) == -1) {
1477                syslog(LOG_ERR, "signal_setup: %m");
1478                exit(EXIT_FAILURE);
1479        }
1480
1481        if (options & DHCPCD_MASTER) {
1482                if (control_start() == -1)
1483                        syslog(LOG_ERR, "control_start: %m");
1484        }
1485#endif
1486
1487        if (open_sockets() == -1) {
1488                syslog(LOG_ERR, "open_sockets: %m");
1489                exit(EXIT_FAILURE);
1490        }
1491
1492#if 0
1493        if (options & DHCPCD_IPV6RS && disable_rtadv() == -1) {
1494                syslog(LOG_ERR, "disable_rtadvd: %m");
1495                options &= ~DHCPCD_IPV6RS;
1496        }
1497#endif
1498
1499        ifc = argc - optind;
1500        ifv = argv + optind;
1501
1502        /* When running dhcpcd against a single interface, we need to retain
1503         * the old behaviour of waiting for an IP address */
1504        if (ifc == 1 && !(options & DHCPCD_BACKGROUND))
1505                options |= DHCPCD_WAITIP;
1506
1507        /* RTM_NEWADDR goes through the link socket as well which we
1508         * need for IPv6 DAD, so we check for DHCPCD_LINK in handle_carrier
1509         * instead.
1510         * We also need to open this before checking for interfaces below
1511         * so that we pickup any new addresses during the discover phase. */
1512        if (linkfd == -1) {
1513                linkfd = open_link_socket();
1514                if (linkfd == -1)
1515                        syslog(LOG_ERR, "open_link_socket: %m");
1516                else
1517                        eloop_event_add(linkfd, handle_link, NULL);
1518        }
1519
1520        /* Start any dev listening plugin which may want to
1521         * change the interface name provided by the kernel */
1522        if ((options & (DHCPCD_MASTER | DHCPCD_DEV)) ==
1523            (DHCPCD_MASTER | DHCPCD_DEV))
1524                dev_start(dev_load);
1525
1526        ifaces = discover_interfaces(ifc, ifv);
1527        for (i = 0; i < ifc; i++) {
1528                if (find_interface(ifv[i]) == NULL)
1529                        syslog(LOG_ERR, "%s: interface not found or invalid",
1530                            ifv[i]);
1531        }
1532        if (ifaces == NULL || TAILQ_FIRST(ifaces) == NULL) {
1533                if (ifc == 0)
1534                        syslog(LOG_ERR, "no valid interfaces found");
1535                else
1536                        exit(EXIT_FAILURE);
1537                if (!(options & DHCPCD_LINK)) {
1538                        syslog(LOG_ERR,
1539                            "aborting as link detection is disabled");
1540                        exit(EXIT_FAILURE);
1541                }
1542        }
1543
1544        if (options & DHCPCD_BACKGROUND)
1545                daemonise();
1546
1547        opt = 0;
1548        TAILQ_FOREACH(ifp, ifaces, next) {
1549                init_state(ifp, argc, argv);
1550                if (ifp->carrier != LINK_DOWN)
1551                        opt = 1;
1552        }
1553
1554        if (!(options & DHCPCD_BACKGROUND)) {
1555                /* If we don't have a carrier, we may have to wait for a second
1556                 * before one becomes available if we brought an interface up */
1557                if (opt == 0 &&
1558                    options & DHCPCD_LINK &&
1559                    options & DHCPCD_WAITUP &&
1560                    !(options & DHCPCD_WAITIP))
1561                {
1562                        ts.tv_sec = 1;
1563                        ts.tv_nsec = 0;
1564                        nanosleep(&ts, NULL);
1565                        TAILQ_FOREACH(ifp, ifaces, next) {
1566                                handle_carrier(LINK_UNKNOWN, 0, ifp->name);
1567                                if (ifp->carrier != LINK_DOWN) {
1568                                        opt = 1;
1569                                        break;
1570                                }
1571                        }
1572                }
1573                if (options & DHCPCD_MASTER)
1574                        i = if_options->timeout;
1575                else if ((ifp = TAILQ_FIRST(ifaces)))
1576                        i = ifp->options->timeout;
1577                else
1578                        i = 0;
1579                if (opt == 0 &&
1580                    options & DHCPCD_LINK &&
1581                    !(options & DHCPCD_WAITIP))
1582                {
1583                        syslog(LOG_WARNING, "no interfaces have a carrier");
1584                        daemonise();
1585                } else if (i > 0) {
1586                        if (options & DHCPCD_IPV4LL)
1587                                options |= DHCPCD_TIMEOUT_IPV4LL;
1588                        eloop_timeout_add_sec(i, handle_exit_timeout, NULL);
1589                }
1590        }
1591        free_options(if_options);
1592        if_options = NULL;
1593
1594        sort_interfaces();
1595        TAILQ_FOREACH(ifp, ifaces, next) {
1596                eloop_timeout_add_sec(0, start_interface, ifp);
1597        }
1598
1599        eloop_start(&dhcpcd_sigset);
1600        exit(EXIT_SUCCESS);
1601}
Note: See TracBrowser for help on using the repository browser.