1d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan/* 2d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * dhcpcd - DHCP client daemon 3d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Copyright (c) 2006-2015 Roy Marples <roy@marples.name> 4d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * All rights reserved 5d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 6d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Redistribution and use in source and binary forms, with or without 7d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * modification, are permitted provided that the following conditions 8d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * are met: 9d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * 1. Redistributions of source code must retain the above copyright 10d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * notice, this list of conditions and the following disclaimer. 11d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * 2. Redistributions in binary form must reproduce the above copyright 12d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * notice, this list of conditions and the following disclaimer in the 13d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * documentation and/or other materials provided with the distribution. 14d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * 15d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * SUCH DAMAGE. 26d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan */ 27d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 28d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/socket.h> 29d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/stat.h> 30d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/uio.h> 31d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <sys/un.h> 32d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 33d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <errno.h> 34d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <fcntl.h> 35d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <stdio.h> 36d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <stdlib.h> 37d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <string.h> 38d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <time.h> 39d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include <unistd.h> 40d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 41d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "config.h" 42d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "common.h" 43d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "dhcpcd.h" 44d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "control.h" 45d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#include "eloop.h" 46d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 47d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifndef SUN_LEN 48d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define SUN_LEN(su) \ 49d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) 50d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 51d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 52d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 53d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_queue_purge(struct dhcpcd_ctx *ctx, char *data) 54d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 55d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int found; 56d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct fd_list *fp; 57d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct fd_data *fpd; 58d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 59d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* If no other fd queue has the same data, free it */ 60d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan found = 0; 61d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_FOREACH(fp, &ctx->control_fds, next) { 62d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_FOREACH(fpd, &fp->queue, next) { 63d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (fpd->data == data) { 64d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan found = 1; 65d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan break; 66d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 67d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 68d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 69d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (!found) 70d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(data); 71d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 72d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 73d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 74d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_queue_free(struct fd_list *fd) 75d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 76d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct fd_data *fdp; 77d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 78d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan while ((fdp = TAILQ_FIRST(&fd->queue))) { 79d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_REMOVE(&fd->queue, fdp, next); 80d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (fdp->freeit) 81d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan control_queue_purge(fd->ctx, fdp->data); 82d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(fdp); 83d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 84d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan while ((fdp = TAILQ_FIRST(&fd->free_queue))) { 85d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_REMOVE(&fd->free_queue, fdp, next); 86d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(fdp); 87d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 88d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 89d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 90d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 91d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_delete(struct fd_list *fd) 92d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 93d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 94d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_REMOVE(&fd->ctx->control_fds, fd, next); 95d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_event_delete(fd->ctx->eloop, fd->fd, 0); 96d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan close(fd->fd); 97d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan control_queue_free(fd); 98d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(fd); 99d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 100d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 101d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 102d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_handle_data(void *arg) 103d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 104d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct fd_list *fd = arg; 105d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan char buffer[1024], *e, *p, *argvp[255], **ap, *a; 106d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ssize_t bytes; 107d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t len; 108d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int argc; 109d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 110d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan bytes = read(fd->fd, buffer, sizeof(buffer) - 1); 111d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (bytes == -1 || bytes == 0) { 112d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Control was closed or there was an error. 113d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Remove it from our list. */ 114d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan control_delete(fd); 115d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 116d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 117d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan buffer[bytes] = '\0'; 118d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p = buffer; 119d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan e = buffer + bytes; 120d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 121d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* Each command is \n terminated 122d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * Each argument is NULL separated */ 123d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan while (p < e) { 124d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan argc = 0; 125d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ap = argvp; 126d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan while (p < e) { 127d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan argc++; 128d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((size_t)argc >= sizeof(argvp) / sizeof(argvp[0])) { 129d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = ENOBUFS; 130d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 131d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 132d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan a = *ap++ = p; 133d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len = strlen(p); 134d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan p += len + 1; 135d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (len && a[len - 1] == '\n') { 136d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan a[len - 1] = '\0'; 137d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan break; 138d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 139d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 140d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan *ap = NULL; 141d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (dhcpcd_handleargs(fd->ctx, fd, argc, argvp) == -1) { 142d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(fd->ctx, LOG_ERR, 143d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: dhcpcd_handleargs: %m", __func__); 144d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (errno != EINTR && errno != EAGAIN) { 145d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan control_delete(fd); 146d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 147d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 148d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 149d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 150d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 151d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 152d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 153d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_handle1(struct dhcpcd_ctx *ctx, int lfd, unsigned int fd_flags) 154d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 155d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct sockaddr_un run; 156d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan socklen_t len; 157d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct fd_list *l; 158d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int fd, flags; 159d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 160d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len = sizeof(run); 161d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((fd = accept(lfd, (struct sockaddr *)&run, &len)) == -1) 162d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 163d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((flags = fcntl(fd, F_GETFD, 0)) == -1 || 164d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) 165d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 166d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan close(fd); 167d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 168d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 169d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((flags = fcntl(fd, F_GETFL, 0)) == -1 || 170d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) 171d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 172d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan close(fd); 173d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 174d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 175d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan l = malloc(sizeof(*l)); 176d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (l) { 177d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan l->ctx = ctx; 178d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan l->fd = fd; 179d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan l->flags = fd_flags; 180d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_INIT(&l->queue); 181d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_INIT(&l->free_queue); 182d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_INSERT_TAIL(&ctx->control_fds, l, next); 183d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_event_add(ctx->eloop, l->fd, 184d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan control_handle_data, l, NULL, NULL); 185d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else 186d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan close(fd); 187d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 188d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 189d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 190d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_handle(void *arg) 191d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 192d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcpcd_ctx *ctx = arg; 193d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 194d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan control_handle1(ctx, ctx->control_fd, 0); 195d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 196d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 197d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 198d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_handle_unpriv(void *arg) 199d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 200d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct dhcpcd_ctx *ctx = arg; 201d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 202d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan control_handle1(ctx, ctx->control_unpriv_fd, FD_UNPRIV); 203d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 204d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 205d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int 206d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanmake_sock(struct sockaddr_un *sa, const char *ifname, int unpriv) 207d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 208d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int fd; 209d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 210d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#ifdef SOCK_CLOEXEC 211d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((fd = socket(AF_UNIX, 212d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) == -1) 213d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 214d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#else 215d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int flags; 216d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 217d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 218d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 219d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((flags = fcntl(fd, F_GETFD, 0)) == -1 || 220d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) 221d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 222d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan close(fd); 223d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 224d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 225d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((flags = fcntl(fd, F_GETFL, 0)) == -1 || 226d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) 227d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 228d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan close(fd); 229d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 230d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 231d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#endif 232d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memset(sa, 0, sizeof(*sa)); 233d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan sa->sun_family = AF_UNIX; 234d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (unpriv) 235d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan strlcpy(sa->sun_path, UNPRIVSOCKET, sizeof(sa->sun_path)); 236d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan else { 237d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan snprintf(sa->sun_path, sizeof(sa->sun_path), CONTROLSOCKET, 238d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ifname ? "-" : "", ifname ? ifname : ""); 239d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 240d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return fd; 241d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 242d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 243d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define S_PRIV (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) 244d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan#define S_UNPRIV (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) 245d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 246d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic int 247d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_start1(struct dhcpcd_ctx *ctx, const char *ifname, mode_t fmode) 248d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 249d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct sockaddr_un sa; 250d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int fd; 251d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan socklen_t len; 252d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 253d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((fd = make_sock(&sa, ifname, (fmode & S_UNPRIV) == S_UNPRIV)) == -1) 254d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 255d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len = (socklen_t)SUN_LEN(&sa); 256d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan unlink(sa.sun_path); 257d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (bind(fd, (struct sockaddr *)&sa, len) == -1 || 258d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan chmod(sa.sun_path, fmode) == -1 || 259d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan (ctx->control_group && 260d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan chown(sa.sun_path, geteuid(), ctx->control_group) == -1) || 261d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan listen(fd, sizeof(ctx->control_fds)) == -1) 262d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan { 263d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan close(fd); 264d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan unlink(sa.sun_path); 265d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 266d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 267d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 268d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((fmode & S_UNPRIV) != S_UNPRIV) 269d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan strlcpy(ctx->control_sock, sa.sun_path, 270d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan sizeof(ctx->control_sock)); 271d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return fd; 272d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 273d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 274d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint 275d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_start(struct dhcpcd_ctx *ctx, const char *ifname) 276d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 277d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int fd; 278d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 279d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((fd = control_start1(ctx, ifname, S_PRIV)) == -1) 280d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 281d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 282d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ctx->control_fd = fd; 283d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_event_add(ctx->eloop, fd, control_handle, ctx, NULL, NULL); 284d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 285d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ifname == NULL && (fd = control_start1(ctx, NULL, S_UNPRIV)) != -1){ 286d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan /* We must be in master mode, so create an unpriviledged socket 287d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan * to allow normal users to learn the status of dhcpcd. */ 288d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ctx->control_unpriv_fd = fd; 289d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_event_add(ctx->eloop, fd, control_handle_unpriv, 290d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ctx, NULL, NULL); 291d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 292d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return ctx->control_fd; 293d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 294d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 295d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint 296d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_stop(struct dhcpcd_ctx *ctx) 297d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 298d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int retval = 0; 299d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct fd_list *l; 300d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 301d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ctx->options & DHCPCD_FORKED) 302d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan goto freeit; 303d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 304d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ctx->control_fd == -1) 305d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 0; 306d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_event_delete(ctx->eloop, ctx->control_fd, 0); 307d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan close(ctx->control_fd); 308d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ctx->control_fd = -1; 309d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (unlink(ctx->control_sock) == -1) 310d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan retval = -1; 311d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 312d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ctx->control_unpriv_fd != -1) { 313d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_event_delete(ctx->eloop, ctx->control_unpriv_fd, 0); 314d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan close(ctx->control_unpriv_fd); 315d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ctx->control_unpriv_fd = -1; 316d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (unlink(UNPRIVSOCKET) == -1) 317d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan retval = -1; 318d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 319d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 320d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanfreeit: 321d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan while ((l = TAILQ_FIRST(&ctx->control_fds))) { 322d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_REMOVE(&ctx->control_fds, l, next); 323d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_event_delete(ctx->eloop, l->fd, 0); 324d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan close(l->fd); 325d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan control_queue_free(l); 326d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan free(l); 327d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 328d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 329d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return retval; 330d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 331d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 332d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint 333d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_open(struct dhcpcd_ctx *ctx, const char *ifname) 334d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 335d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct sockaddr_un sa; 336d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan socklen_t len; 337d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 338d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if ((ctx->control_fd = make_sock(&sa, ifname, 0)) == -1) 339d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 340d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len = (socklen_t)SUN_LEN(&sa); 341d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (connect(ctx->control_fd, (struct sockaddr *)&sa, len) == -1) { 342d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan close(ctx->control_fd); 343d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ctx->control_fd = -1; 344d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 345d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 346d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 0; 347d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 348d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 349d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanssize_t 350d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_send(struct dhcpcd_ctx *ctx, int argc, char * const *argv) 351d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 352d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan char buffer[1024]; 353d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan int i; 354d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t len, l; 355d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 356d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (argc > 255) { 357d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = ENOBUFS; 358d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 359d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 360d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len = 0; 361d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan for (i = 0; i < argc; i++) { 362d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan l = strlen(argv[i]) + 1; 363d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (len + l > sizeof(buffer)) { 364d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = ENOBUFS; 365d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 366d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 367d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan memcpy(buffer + len, argv[i], l); 368d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan len += l; 369d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 370d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return write(ctx->control_fd, buffer, len); 371d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 372d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 373d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanstatic void 374d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_writeone(void *arg) 375d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 376d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct fd_list *fd; 377d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct iovec iov[2]; 378d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct fd_data *data; 379d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 380d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan fd = arg; 381d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan data = TAILQ_FIRST(&fd->queue); 382d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan iov[0].iov_base = &data->data_len; 383d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan iov[0].iov_len = sizeof(size_t); 384d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan iov[1].iov_base = data->data; 385d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan iov[1].iov_len = data->data_len; 386d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (writev(fd->fd, iov, 2) == -1) { 387d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan logger(fd->ctx, LOG_ERR, 388d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan "%s: writev fd %d: %m", __func__, fd->fd); 389d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (errno != EINTR && errno != EAGAIN) 390d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan control_delete(fd); 391d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return; 392d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 393d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 394d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_REMOVE(&fd->queue, data, next); 395d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (data->freeit) 396d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan control_queue_purge(fd->ctx, data->data); 397d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan data->data = NULL; /* safety */ 398d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan data->data_len = 0; 399d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_INSERT_TAIL(&fd->free_queue, data, next); 400d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 401d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (TAILQ_FIRST(&fd->queue) == NULL) 402d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_event_delete(fd->ctx->eloop, fd->fd, 1); 403d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 404d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 405d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanint 406d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_queue(struct fd_list *fd, char *data, size_t data_len, uint8_t fit) 407d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 408d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan struct fd_data *d; 409d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan size_t n; 410d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 411d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan d = TAILQ_FIRST(&fd->free_queue); 412d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (d) { 413d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_REMOVE(&fd->free_queue, d, next); 414d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } else { 415d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan n = 0; 416d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_FOREACH(d, &fd->queue, next) { 417d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (++n == CONTROL_QUEUE_MAX) { 418d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan errno = ENOBUFS; 419d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 420d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 421d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 422d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan d = malloc(sizeof(*d)); 423d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (d == NULL) 424d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return -1; 425d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 426d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan d->data = data; 427d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan d->data_len = data_len; 428d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan d->freeit = fit; 429d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan TAILQ_INSERT_TAIL(&fd->queue, d, next); 430d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan eloop_event_add(fd->ctx->eloop, fd->fd, 431d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan NULL, NULL, control_writeone, fd); 432d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan return 0; 433d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 434d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 435d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tanvoid 436d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tancontrol_close(struct dhcpcd_ctx *ctx) 437d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan{ 438d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan 439d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan if (ctx->control_fd != -1) { 440d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan close(ctx->control_fd); 441d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan ctx->control_fd = -1; 442d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan } 443d7ed851d6fc26c5e7db96971dbe6b44342b97727Samuel Tan} 444