Home | History | Annotate | Download | only in dhcpcd
      1 /*
      2  * dhcpcd - DHCP client daemon
      3  * Copyright (c) 2006-2009 Roy Marples <roy (at) 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 
     28 #include <linux/socket.h>
     29 #include <sys/stat.h>
     30 #include <sys/un.h>
     31 
     32 #include <errno.h>
     33 #include <stdio.h>
     34 #include <stdlib.h>
     35 #include <string.h>
     36 #include <time.h>
     37 #include <unistd.h>
     38 
     39 #include "config.h"
     40 #include "common.h"
     41 #include "dhcpcd.h"
     42 #include "control.h"
     43 #include "eloop.h"
     44 
     45 static int fd = -1;
     46 static char buffer[1024];
     47 static char *argvp[255];
     48 
     49 struct sockaddr_un sun;
     50 struct fd_list *fds = NULL;
     51 
     52 static void
     53 remove_control_data(void *arg)
     54 {
     55 	struct fd_list *l, *last = NULL;
     56 
     57 	for (l = fds; l != NULL; l = l->next) {
     58 		if (l == arg) {
     59 			close(l->fd);
     60 			delete_event(l->fd);
     61 			if (last == NULL)
     62 				fds = l->next;
     63 			else
     64 				last->next = l->next;
     65 			free(l);
     66 			break;
     67 		}
     68 		last = l;
     69 	}
     70 }
     71 
     72 static void
     73 handle_control_data(void *arg)
     74 {
     75 	struct fd_list *l = arg;
     76 	ssize_t bytes;
     77 	int argc;
     78 	char *e, *p;
     79 	char **ap;
     80 
     81 	bytes = read(l->fd, buffer, sizeof(buffer) - 1);
     82 	if (bytes == -1 || bytes == 0) {
     83 		remove_control_data(l);
     84 		return;
     85 	}
     86 	buffer[bytes] = '\0';
     87 	p = buffer;
     88 	e = buffer + bytes;
     89 	argc = 0;
     90 	ap = argvp;
     91 	while (p < e && (size_t)argc < sizeof(argvp)) {
     92 		argc++;
     93 		*ap++ = p;
     94 		p += strlen(p) + 1;
     95 	}
     96 	handle_args(l, argc, argvp);
     97 }
     98 
     99 /* ARGSUSED */
    100 static void
    101 handle_control(_unused void *arg)
    102 {
    103 	struct sockaddr_un run;
    104 	socklen_t len;
    105 	struct fd_list *l;
    106 	int f;
    107 
    108 	len = sizeof(run);
    109 	if ((f = accept(fd, (struct sockaddr *)&run, &len)) == -1)
    110 		return;
    111 	l = xmalloc(sizeof(*l));
    112 	l->fd = f;
    113 	l->listener = 0;
    114 	l->next = fds;
    115 	fds = l;
    116 	add_event(l->fd, handle_control_data, l);
    117 }
    118 
    119 static int
    120 make_sock(void)
    121 {
    122 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
    123 		return -1;
    124 	memset(&sun, 0, sizeof(sun));
    125 	sun.sun_family = AF_UNIX;
    126 	strlcpy(sun.sun_path, CONTROLSOCKET, sizeof(sun.sun_path));
    127 	return sizeof(sun.sun_family) + strlen(sun.sun_path) + 1;
    128 }
    129 
    130 int
    131 start_control(void)
    132 {
    133 	int len;
    134 
    135 	if ((len = make_sock()) == -1)
    136 		return -1;
    137 	unlink(CONTROLSOCKET);
    138 	if (bind(fd, (struct sockaddr *)&sun, len) == -1 ||
    139 	    chmod(CONTROLSOCKET,
    140 		S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) == -1 ||
    141 	    set_cloexec(fd) == -1 ||
    142 	    set_nonblock(fd) == -1 ||
    143 	    listen(fd, sizeof(fds)) == -1)
    144 	{
    145 		close(fd);
    146 		return -1;
    147 	}
    148 	add_event(fd, handle_control, NULL);
    149 	return fd;
    150 }
    151 
    152 int
    153 stop_control(void)
    154 {
    155 	int retval = 0;
    156 	struct fd_list *l, *ll;
    157 
    158 	delete_event(fd);
    159 	if (shutdown(fd, SHUT_RDWR) == -1)
    160 		retval = 1;
    161 	fd = -1;
    162 	if (unlink(CONTROLSOCKET) == -1)
    163 		retval = -1;
    164 
    165 	l = fds;
    166 	while (l != NULL) {
    167 		ll = l->next;
    168 		delete_event(l->fd);
    169 		shutdown(l->fd, SHUT_RDWR);
    170 		free(l);
    171 		l = ll;
    172 	}
    173 
    174 	return retval;
    175 }
    176 
    177 int
    178 open_control(void)
    179 {
    180 	int len;
    181 
    182 	if ((len = make_sock()) == -1)
    183 		return -1;
    184 	return connect(fd, (struct sockaddr *)&sun, len);
    185 }
    186 
    187 int
    188 send_control(int argc, char * const *argv)
    189 {
    190 	char *p = buffer;
    191 	int i;
    192 	size_t len;
    193 
    194 	if (argc > 255) {
    195 		errno = ENOBUFS;
    196 		return -1;
    197 	}
    198 	for (i = 0; i < argc; i++) {
    199 		len = strlen(argv[i]) + 1;
    200 		if ((p - buffer) + len > sizeof(buffer)) {
    201 			errno = ENOBUFS;
    202 			return -1;
    203 		}
    204 		memcpy(p, argv[i], len);
    205 		p += len;
    206 	}
    207 	return write(fd, buffer, p - buffer);
    208 }
    209