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