xref: /dflybsd-src/contrib/dhcpcd/src/common.c (revision 5422d4140b73a6e65966a6f40831066aa79c4714)
18d36e1dfSRoy Marples /* SPDX-License-Identifier: BSD-2-Clause */
27827cba2SAaron LI /*
37827cba2SAaron LI  * dhcpcd - DHCP client daemon
480aa9461SRoy Marples  * Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
57827cba2SAaron LI  * All rights reserved
67827cba2SAaron LI 
77827cba2SAaron LI  * Redistribution and use in source and binary forms, with or without
87827cba2SAaron LI  * modification, are permitted provided that the following conditions
97827cba2SAaron LI  * are met:
107827cba2SAaron LI  * 1. Redistributions of source code must retain the above copyright
117827cba2SAaron LI  *    notice, this list of conditions and the following disclaimer.
127827cba2SAaron LI  * 2. Redistributions in binary form must reproduce the above copyright
137827cba2SAaron LI  *    notice, this list of conditions and the following disclaimer in the
147827cba2SAaron LI  *    documentation and/or other materials provided with the distribution.
157827cba2SAaron LI  *
167827cba2SAaron LI  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
177827cba2SAaron LI  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
187827cba2SAaron LI  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
197827cba2SAaron LI  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
207827cba2SAaron LI  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
217827cba2SAaron LI  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
227827cba2SAaron LI  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
237827cba2SAaron LI  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
247827cba2SAaron LI  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
257827cba2SAaron LI  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
267827cba2SAaron LI  * SUCH DAMAGE.
277827cba2SAaron LI  */
287827cba2SAaron LI 
29d4fb1e02SRoy Marples #include <sys/stat.h>
3012af092aSRoy Marples #include <sys/statvfs.h>
317827cba2SAaron LI 
327827cba2SAaron LI #include <ctype.h>
337827cba2SAaron LI #include <errno.h>
34d4fb1e02SRoy Marples #include <fcntl.h>
357827cba2SAaron LI #include <stdio.h>
367827cba2SAaron LI #include <stdlib.h>
37d4fb1e02SRoy Marples #include <string.h>
387827cba2SAaron LI 
397827cba2SAaron LI #include "common.h"
407827cba2SAaron LI #include "dhcpcd.h"
417827cba2SAaron LI #include "if-options.h"
427827cba2SAaron LI 
437827cba2SAaron LI const char *
hwaddr_ntoa(const void * hwaddr,size_t hwlen,char * buf,size_t buflen)447827cba2SAaron LI hwaddr_ntoa(const void *hwaddr, size_t hwlen, char *buf, size_t buflen)
457827cba2SAaron LI {
467827cba2SAaron LI 	const unsigned char *hp, *ep;
477827cba2SAaron LI 	char *p;
487827cba2SAaron LI 
49*f3744ac9SRoy Marples 	/* Allow a hwlen of 0 to be an empty string. */
50*f3744ac9SRoy Marples 	if (buf == NULL || buflen == 0) {
51*f3744ac9SRoy Marples 		errno = ENOBUFS;
527827cba2SAaron LI 		return NULL;
53*f3744ac9SRoy Marples 	}
547827cba2SAaron LI 
557827cba2SAaron LI 	if (hwlen * 3 > buflen) {
56*f3744ac9SRoy Marples 		/* We should still terminate the string just in case. */
57*f3744ac9SRoy Marples 		buf[0] = '\0';
587827cba2SAaron LI 		errno = ENOBUFS;
597827cba2SAaron LI 		return NULL;
607827cba2SAaron LI 	}
617827cba2SAaron LI 
627827cba2SAaron LI 	hp = hwaddr;
637827cba2SAaron LI 	ep = hp + hwlen;
647827cba2SAaron LI 	p = buf;
657827cba2SAaron LI 	while (hp < ep) {
667827cba2SAaron LI 		if (hp != hwaddr)
677827cba2SAaron LI 			*p ++= ':';
687827cba2SAaron LI 		p += snprintf(p, 3, "%.2x", *hp++);
697827cba2SAaron LI 	}
707827cba2SAaron LI 	*p ++= '\0';
717827cba2SAaron LI 	return buf;
727827cba2SAaron LI }
737827cba2SAaron LI 
747827cba2SAaron LI size_t
hwaddr_aton(uint8_t * buffer,const char * addr)757827cba2SAaron LI hwaddr_aton(uint8_t *buffer, const char *addr)
767827cba2SAaron LI {
777827cba2SAaron LI 	char c[3];
787827cba2SAaron LI 	const char *p = addr;
797827cba2SAaron LI 	uint8_t *bp = buffer;
807827cba2SAaron LI 	size_t len = 0;
817827cba2SAaron LI 
827827cba2SAaron LI 	c[2] = '\0';
837827cba2SAaron LI 	while (*p != '\0') {
847827cba2SAaron LI 		/* Skip separators */
857827cba2SAaron LI 		c[0] = *p++;
867827cba2SAaron LI 		switch (c[0]) {
877827cba2SAaron LI 		case '\n':	/* long duid split on lines */
887827cba2SAaron LI 		case ':':	/* typical mac address */
897827cba2SAaron LI 		case '-':	/* uuid */
907827cba2SAaron LI 			continue;
917827cba2SAaron LI 		}
927827cba2SAaron LI 		c[1] = *p++;
937827cba2SAaron LI 		/* Ensure that digits are hex */
947827cba2SAaron LI 		if (isxdigit((unsigned char)c[0]) == 0 ||
957827cba2SAaron LI 		    isxdigit((unsigned char)c[1]) == 0)
967827cba2SAaron LI 		{
977827cba2SAaron LI 			errno = EINVAL;
987827cba2SAaron LI 			return 0;
997827cba2SAaron LI 		}
1007827cba2SAaron LI 		/* We should have at least two entries 00:01 */
1017827cba2SAaron LI 		if (len == 0 && *p == '\0') {
1027827cba2SAaron LI 			errno = EINVAL;
1037827cba2SAaron LI 			return 0;
1047827cba2SAaron LI 		}
1057827cba2SAaron LI 		if (bp)
1067827cba2SAaron LI 			*bp++ = (uint8_t)strtol(c, NULL, 16);
1077827cba2SAaron LI 		len++;
1087827cba2SAaron LI 	}
1097827cba2SAaron LI 	return len;
1107827cba2SAaron LI }
1117827cba2SAaron LI 
112d4fb1e02SRoy Marples ssize_t
readfile(const char * file,void * data,size_t len)113d4fb1e02SRoy Marples readfile(const char *file, void *data, size_t len)
1147827cba2SAaron LI {
115d4fb1e02SRoy Marples 	int fd;
116d4fb1e02SRoy Marples 	ssize_t bytes;
1177827cba2SAaron LI 
118d4fb1e02SRoy Marples 	fd = open(file, O_RDONLY);
119d4fb1e02SRoy Marples 	if (fd == -1)
120d4fb1e02SRoy Marples 		return -1;
121d4fb1e02SRoy Marples 	bytes = read(fd, data, len);
122d4fb1e02SRoy Marples 	close(fd);
123d4fb1e02SRoy Marples 	if ((size_t)bytes == len) {
124d4fb1e02SRoy Marples 		errno = ENOBUFS;
125d4fb1e02SRoy Marples 		return -1;
1267827cba2SAaron LI 	}
127d4fb1e02SRoy Marples 	return bytes;
128d4fb1e02SRoy Marples }
129d4fb1e02SRoy Marples 
130d4fb1e02SRoy Marples ssize_t
writefile(const char * file,mode_t mode,const void * data,size_t len)131d4fb1e02SRoy Marples writefile(const char *file, mode_t mode, const void *data, size_t len)
132d4fb1e02SRoy Marples {
133d4fb1e02SRoy Marples 	int fd;
134d4fb1e02SRoy Marples 	ssize_t bytes;
135d4fb1e02SRoy Marples 
136d4fb1e02SRoy Marples 	fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, mode);
137d4fb1e02SRoy Marples 	if (fd == -1)
138d4fb1e02SRoy Marples 		return -1;
139d4fb1e02SRoy Marples 	bytes = write(fd, data, len);
140d4fb1e02SRoy Marples 	close(fd);
141d4fb1e02SRoy Marples 	return bytes;
142d4fb1e02SRoy Marples }
143d4fb1e02SRoy Marples 
144d4fb1e02SRoy Marples int
filemtime(const char * file,time_t * time)145d4fb1e02SRoy Marples filemtime(const char *file, time_t *time)
146d4fb1e02SRoy Marples {
147d4fb1e02SRoy Marples 	struct stat st;
148d4fb1e02SRoy Marples 
149d4fb1e02SRoy Marples 	if (stat(file, &st) == -1)
150d4fb1e02SRoy Marples 		return -1;
151d4fb1e02SRoy Marples 	*time = st.st_mtime;
152d4fb1e02SRoy Marples 	return 0;
153d4fb1e02SRoy Marples }
154d4fb1e02SRoy Marples 
155d4fb1e02SRoy Marples /* Handy routine to read very long lines in text files.
156d4fb1e02SRoy Marples  * This means we read the whole line and avoid any nasty buffer overflows.
157d4fb1e02SRoy Marples  * We strip leading space and avoid comment lines, making the code that calls
158d4fb1e02SRoy Marples  * us smaller. */
159d4fb1e02SRoy Marples char *
get_line(char ** __restrict buf,ssize_t * __restrict buflen)160d4fb1e02SRoy Marples get_line(char ** __restrict buf, ssize_t * __restrict buflen)
161d4fb1e02SRoy Marples {
162d4fb1e02SRoy Marples 	char *p, *c;
163d4fb1e02SRoy Marples 	bool quoted;
164d4fb1e02SRoy Marples 
165d4fb1e02SRoy Marples 	do {
166d4fb1e02SRoy Marples 		p = *buf;
167d4fb1e02SRoy Marples 		if (*buf == NULL)
168d4fb1e02SRoy Marples 			return NULL;
169d4fb1e02SRoy Marples 		c = memchr(*buf, '\n', (size_t)*buflen);
170d4fb1e02SRoy Marples 		if (c == NULL) {
171d4fb1e02SRoy Marples 			c = memchr(*buf, '\0', (size_t)*buflen);
172d4fb1e02SRoy Marples 			if (c == NULL)
173d4fb1e02SRoy Marples 				return NULL;
174d4fb1e02SRoy Marples 			*buflen = c - *buf;
175d4fb1e02SRoy Marples 			*buf = NULL;
176d4fb1e02SRoy Marples 		} else {
177d4fb1e02SRoy Marples 			*c++ = '\0';
178d4fb1e02SRoy Marples 			*buflen -= c - *buf;
179d4fb1e02SRoy Marples 			*buf = c;
180d4fb1e02SRoy Marples 		}
181d4fb1e02SRoy Marples 		for (; *p == ' ' || *p == '\t'; p++)
182d4fb1e02SRoy Marples 			;
183d4fb1e02SRoy Marples 	} while (*p == '\0' || *p == '\n' || *p == '#' || *p == ';');
184d4fb1e02SRoy Marples 
185d4fb1e02SRoy Marples 	/* Strip embedded comments unless in a quoted string or escaped */
186d4fb1e02SRoy Marples 	quoted = false;
187d4fb1e02SRoy Marples 	for (c = p; *c != '\0'; c++) {
188d4fb1e02SRoy Marples 		if (*c == '\\') {
189d4fb1e02SRoy Marples 			c++; /* escaped */
190d4fb1e02SRoy Marples 			continue;
191d4fb1e02SRoy Marples 		}
192d4fb1e02SRoy Marples 		if (*c == '"')
193d4fb1e02SRoy Marples 			quoted = !quoted;
194d4fb1e02SRoy Marples 		else if (*c == '#' && !quoted) {
195d4fb1e02SRoy Marples 			*c = '\0';
1967827cba2SAaron LI 			break;
1977827cba2SAaron LI 		}
1987827cba2SAaron LI 	}
199d4fb1e02SRoy Marples 	return p;
2007827cba2SAaron LI }
20112af092aSRoy Marples 
202d4fb1e02SRoy Marples 
20312af092aSRoy Marples int
is_root_local(void)20412af092aSRoy Marples is_root_local(void)
20512af092aSRoy Marples {
20612af092aSRoy Marples #ifdef ST_LOCAL
20712af092aSRoy Marples 	struct statvfs vfs;
20812af092aSRoy Marples 
20912af092aSRoy Marples 	if (statvfs("/", &vfs) == -1)
21012af092aSRoy Marples 		return -1;
21112af092aSRoy Marples 	return vfs.f_flag & ST_LOCAL ? 1 : 0;
21212af092aSRoy Marples #else
21312af092aSRoy Marples 	errno = ENOTSUP;
21412af092aSRoy Marples 	return -1;
21512af092aSRoy Marples #endif
21612af092aSRoy Marples }
217