xref: /minix3/external/bsd/dhcpcd/dist/common.c (revision 9f20bfa6c4c442e2e798d91b11c2a5f8d6833a41)
1 #include <sys/cdefs.h>
2  __RCSID("$NetBSD: common.c,v 1.14 2015/07/09 10:15:34 roy Exp $");
3 
4 /*
5  * dhcpcd - DHCP client daemon
6  * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
7  * All rights reserved
8 
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include <sys/param.h>
32 #include <sys/time.h>
33 
34 #include <ctype.h>
35 #include <err.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <limits.h>
39 #ifdef BSD
40 #  include <paths.h>
41 #endif
42 #include <stdarg.h>
43 #include <stdint.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <syslog.h>
48 #include <time.h>
49 #include <unistd.h>
50 
51 #include "common.h"
52 #include "dhcpcd.h"
53 #include "if-options.h"
54 
55 #ifndef _PATH_DEVNULL
56 #  define _PATH_DEVNULL "/dev/null"
57 #endif
58 
59 const char *
get_hostname(char * buf,size_t buflen,int short_hostname)60 get_hostname(char *buf, size_t buflen, int short_hostname)
61 {
62 	char *p;
63 
64 	if (gethostname(buf, buflen) != 0)
65 		return NULL;
66 	buf[buflen - 1] = '\0';
67 	if (strcmp(buf, "(none)") == 0 ||
68 	    strcmp(buf, "localhost") == 0 ||
69 	    strncmp(buf, "localhost.", strlen("localhost.")) == 0 ||
70 	    buf[0] == '.')
71 		return NULL;
72 
73 	if (short_hostname) {
74 		p = strchr(buf, '.');
75 		if (p)
76 			*p = '\0';
77 	}
78 
79 	return buf;
80 }
81 
82 #if USE_LOGFILE
83 void
logger_open(struct dhcpcd_ctx * ctx)84 logger_open(struct dhcpcd_ctx *ctx)
85 {
86 
87 	if (ctx->logfile) {
88 		int f = O_CREAT | O_APPEND | O_TRUNC;
89 
90 #ifdef O_CLOEXEC
91 		f |= O_CLOEXEC;
92 #endif
93 		ctx->log_fd = open(ctx->logfile, O_WRONLY | f, 0644);
94 		if (ctx->log_fd == -1)
95 			warn("open: %s", ctx->logfile);
96 #ifndef O_CLOEXEC
97 		else {
98 			if (fcntl(ctx->log_fd, F_GETFD, &f) == -1 ||
99 			    fcntl(ctx->log_fd, F_SETFD, f | FD_CLOEXEC) == -1)
100 				warn("fcntl: %s", ctx->logfile);
101 		}
102 #endif
103 	} else
104 		openlog(PACKAGE, LOG_PID, LOG_DAEMON);
105 }
106 
107 void
logger_close(struct dhcpcd_ctx * ctx)108 logger_close(struct dhcpcd_ctx *ctx)
109 {
110 
111 	if (ctx->log_fd != -1) {
112 		close(ctx->log_fd);
113 		ctx->log_fd = -1;
114 	}
115 	closelog();
116 }
117 
118 void
logger(struct dhcpcd_ctx * ctx,int pri,const char * fmt,...)119 logger(struct dhcpcd_ctx *ctx, int pri, const char *fmt, ...)
120 {
121 	va_list va;
122 	int serrno;
123 #ifndef HAVE_PRINTF_M
124 	char fmt_cpy[1024];
125 #endif
126 
127 	if (pri >= LOG_DEBUG && ctx && !(ctx->options & DHCPCD_DEBUG))
128 		return;
129 
130 	serrno = errno;
131 	va_start(va, fmt);
132 
133 #ifndef HAVE_PRINTF_M
134 	/* Print strerrno(errno) in place of %m */
135 	if (ctx == NULL || !(ctx->options & DHCPCD_QUIET) || ctx->log_fd != -1)
136 	{
137 		const char *p;
138 		char *fp = fmt_cpy, *serr = NULL;
139 		size_t fmt_left = sizeof(fmt_cpy) - 1, fmt_wrote;
140 
141 		for (p = fmt; *p != '\0'; p++) {
142 			if (p[0] == '%' && p[1] == '%') {
143 				if (fmt_left < 2)
144 					break;
145 				*fp++ = '%';
146 				*fp++ = '%';
147 				fmt_left -= 2;
148 				p++;
149 			} else if (p[0] == '%' && p[1] == 'm') {
150 				if (serr == NULL)
151 					serr = strerror(serrno);
152 				fmt_wrote = strlcpy(fp, serr, fmt_left);
153 				if (fmt_wrote > fmt_left)
154 					break;
155 				fp += fmt_wrote;
156 				fmt_left -= fmt_wrote;
157 				p++;
158 			} else {
159 				*fp++ = *p;
160 				--fmt_left;
161 			}
162 			if (fmt_left == 0)
163 				break;
164 		}
165 		*fp++ = '\0';
166 		fmt = fmt_cpy;
167 	}
168 
169 #endif
170 
171 	if (ctx == NULL || !(ctx->options & DHCPCD_QUIET)) {
172 		va_list vac;
173 
174 		va_copy(vac, va);
175 		vfprintf(pri <= LOG_ERR ? stderr : stdout, fmt, vac);
176 		fputc('\n', pri <= LOG_ERR ? stderr : stdout);
177 		va_end(vac);
178 	}
179 
180 #ifdef HAVE_PRINTF_M
181 	errno = serrno;
182 #endif
183 	if (ctx && ctx->log_fd != -1) {
184 		struct timeval tv;
185 		char buf[32];
186 
187 		/* Write the time, syslog style. month day time - */
188 		if (gettimeofday(&tv, NULL) != -1) {
189 			time_t now;
190 			struct tm tmnow;
191 
192 			tzset();
193 			now = tv.tv_sec;
194 			localtime_r(&now, &tmnow);
195 			strftime(buf, sizeof(buf), "%b %d %T ", &tmnow);
196 			dprintf(ctx->log_fd, "%s", buf);
197 		}
198 
199 		vdprintf(ctx->log_fd, fmt, va);
200 		dprintf(ctx->log_fd, "\n");
201 	} else
202 		vsyslog(pri, fmt, va);
203 	va_end(va);
204 }
205 #endif
206 
207 ssize_t
setvar(struct dhcpcd_ctx * ctx,char ** e,const char * prefix,const char * var,const char * value)208 setvar(struct dhcpcd_ctx *ctx,
209     char **e, const char *prefix, const char *var, const char *value)
210 {
211 	size_t len = strlen(var) + strlen(value) + 3;
212 
213 	if (prefix)
214 		len += strlen(prefix) + 1;
215 	*e = malloc(len);
216 	if (*e == NULL) {
217 		logger(ctx, LOG_ERR, "%s: %m", __func__);
218 		return -1;
219 	}
220 	if (prefix)
221 		snprintf(*e, len, "%s_%s=%s", prefix, var, value);
222 	else
223 		snprintf(*e, len, "%s=%s", var, value);
224 	return (ssize_t)len;
225 }
226 
227 ssize_t
setvard(struct dhcpcd_ctx * ctx,char ** e,const char * prefix,const char * var,size_t value)228 setvard(struct dhcpcd_ctx *ctx,
229     char **e, const char *prefix, const char *var, size_t value)
230 {
231 
232 	char buffer[32];
233 
234 	snprintf(buffer, sizeof(buffer), "%zu", value);
235 	return setvar(ctx, e, prefix, var, buffer);
236 }
237 
238 ssize_t
addvar(struct dhcpcd_ctx * ctx,char *** e,const char * prefix,const char * var,const char * value)239 addvar(struct dhcpcd_ctx *ctx,
240     char ***e, const char *prefix, const char *var, const char *value)
241 {
242 	ssize_t len;
243 
244 	len = setvar(ctx, *e, prefix, var, value);
245 	if (len != -1)
246 		(*e)++;
247 	return (ssize_t)len;
248 }
249 
250 ssize_t
addvard(struct dhcpcd_ctx * ctx,char *** e,const char * prefix,const char * var,size_t value)251 addvard(struct dhcpcd_ctx *ctx,
252     char ***e, const char *prefix, const char *var, size_t value)
253 {
254 	char buffer[32];
255 
256 	snprintf(buffer, sizeof(buffer), "%zu", value);
257 	return addvar(ctx, e, prefix, var, buffer);
258 }
259 
260 char *
hwaddr_ntoa(const unsigned char * hwaddr,size_t hwlen,char * buf,size_t buflen)261 hwaddr_ntoa(const unsigned char *hwaddr, size_t hwlen, char *buf, size_t buflen)
262 {
263 	char *p;
264 	size_t i;
265 
266 	if (buf == NULL) {
267 		return NULL;
268 	}
269 
270 	if (hwlen * 3 > buflen) {
271 		errno = ENOBUFS;
272 		return 0;
273 	}
274 
275 	p = buf;
276 	for (i = 0; i < hwlen; i++) {
277 		if (i > 0)
278 			*p ++= ':';
279 		p += snprintf(p, 3, "%.2x", hwaddr[i]);
280 	}
281 	*p ++= '\0';
282 	return buf;
283 }
284 
285 size_t
hwaddr_aton(unsigned char * buffer,const char * addr)286 hwaddr_aton(unsigned char *buffer, const char *addr)
287 {
288 	char c[3];
289 	const char *p = addr;
290 	unsigned char *bp = buffer;
291 	size_t len = 0;
292 
293 	c[2] = '\0';
294 	while (*p) {
295 		c[0] = *p++;
296 		c[1] = *p++;
297 		/* Ensure that digits are hex */
298 		if (isxdigit((unsigned char)c[0]) == 0 ||
299 		    isxdigit((unsigned char)c[1]) == 0)
300 		{
301 			errno = EINVAL;
302 			return 0;
303 		}
304 		/* We should have at least two entries 00:01 */
305 		if (len == 0 && *p == '\0') {
306 			errno = EINVAL;
307 			return 0;
308 		}
309 		/* Ensure that next data is EOL or a seperator with data */
310 		if (!(*p == '\0' || (*p == ':' && *(p + 1) != '\0'))) {
311 			errno = EINVAL;
312 			return 0;
313 		}
314 		if (*p)
315 			p++;
316 		if (bp)
317 			*bp++ = (unsigned char)strtol(c, NULL, 16);
318 		len++;
319 	}
320 	return len;
321 }
322