xref: /netbsd-src/external/bsd/dhcpcd/dist/src/common.c (revision f3ce8585ec5f9bbdd2f298ace297fe6c547dcb4e)
18bcf1996Sroy /* SPDX-License-Identifier: BSD-2-Clause */
28fd57d42Sroy /*
38fd57d42Sroy  * dhcpcd - DHCP client daemon
4794dfa77Sroy  * Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
58fd57d42Sroy  * All rights reserved
68fd57d42Sroy 
78fd57d42Sroy  * Redistribution and use in source and binary forms, with or without
88fd57d42Sroy  * modification, are permitted provided that the following conditions
98fd57d42Sroy  * are met:
108fd57d42Sroy  * 1. Redistributions of source code must retain the above copyright
118fd57d42Sroy  *    notice, this list of conditions and the following disclaimer.
128fd57d42Sroy  * 2. Redistributions in binary form must reproduce the above copyright
138fd57d42Sroy  *    notice, this list of conditions and the following disclaimer in the
148fd57d42Sroy  *    documentation and/or other materials provided with the distribution.
158fd57d42Sroy  *
168fd57d42Sroy  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
178fd57d42Sroy  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
188fd57d42Sroy  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
198fd57d42Sroy  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
208fd57d42Sroy  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
218fd57d42Sroy  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
228fd57d42Sroy  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
238fd57d42Sroy  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
248fd57d42Sroy  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
258fd57d42Sroy  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
268fd57d42Sroy  * SUCH DAMAGE.
278fd57d42Sroy  */
288fd57d42Sroy 
297c187152Sroy #include <sys/stat.h>
308fc24ed9Sroy #include <sys/statvfs.h>
318fd57d42Sroy 
328fd57d42Sroy #include <ctype.h>
338fd57d42Sroy #include <errno.h>
347c187152Sroy #include <fcntl.h>
358fd57d42Sroy #include <stdio.h>
368fd57d42Sroy #include <stdlib.h>
377c187152Sroy #include <string.h>
388fd57d42Sroy 
398fd57d42Sroy #include "common.h"
408fd57d42Sroy #include "dhcpcd.h"
418fd57d42Sroy #include "if-options.h"
428fd57d42Sroy 
438fd57d42Sroy const char *
hwaddr_ntoa(const void * hwaddr,size_t hwlen,char * buf,size_t buflen)448fd57d42Sroy hwaddr_ntoa(const void *hwaddr, size_t hwlen, char *buf, size_t buflen)
458fd57d42Sroy {
468fd57d42Sroy 	const unsigned char *hp, *ep;
478fd57d42Sroy 	char *p;
488fd57d42Sroy 
49*f3ce8585Sroy 	/* Allow a hwlen of 0 to be an empty string. */
50*f3ce8585Sroy 	if (buf == NULL || buflen == 0) {
51*f3ce8585Sroy 		errno = ENOBUFS;
528fd57d42Sroy 		return NULL;
53*f3ce8585Sroy 	}
548fd57d42Sroy 
558fd57d42Sroy 	if (hwlen * 3 > buflen) {
56*f3ce8585Sroy 		/* We should still terminate the string just in case. */
57*f3ce8585Sroy 		buf[0] = '\0';
588fd57d42Sroy 		errno = ENOBUFS;
598fd57d42Sroy 		return NULL;
608fd57d42Sroy 	}
618fd57d42Sroy 
628fd57d42Sroy 	hp = hwaddr;
638fd57d42Sroy 	ep = hp + hwlen;
648fd57d42Sroy 	p = buf;
658fd57d42Sroy 	while (hp < ep) {
668fd57d42Sroy 		if (hp != hwaddr)
678fd57d42Sroy 			*p ++= ':';
688fd57d42Sroy 		p += snprintf(p, 3, "%.2x", *hp++);
698fd57d42Sroy 	}
708fd57d42Sroy 	*p ++= '\0';
718fd57d42Sroy 	return buf;
728fd57d42Sroy }
738fd57d42Sroy 
748fd57d42Sroy size_t
hwaddr_aton(uint8_t * buffer,const char * addr)758fd57d42Sroy hwaddr_aton(uint8_t *buffer, const char *addr)
768fd57d42Sroy {
778fd57d42Sroy 	char c[3];
788fd57d42Sroy 	const char *p = addr;
798fd57d42Sroy 	uint8_t *bp = buffer;
808fd57d42Sroy 	size_t len = 0;
818fd57d42Sroy 
828fd57d42Sroy 	c[2] = '\0';
838798a270Sroy 	while (*p != '\0') {
848798a270Sroy 		/* Skip separators */
858fd57d42Sroy 		c[0] = *p++;
868798a270Sroy 		switch (c[0]) {
878798a270Sroy 		case '\n':	/* long duid split on lines */
888798a270Sroy 		case ':':	/* typical mac address */
898798a270Sroy 		case '-':	/* uuid */
908fd57d42Sroy 			continue;
918798a270Sroy 		}
928fd57d42Sroy 		c[1] = *p++;
938fd57d42Sroy 		/* Ensure that digits are hex */
948fd57d42Sroy 		if (isxdigit((unsigned char)c[0]) == 0 ||
958fd57d42Sroy 		    isxdigit((unsigned char)c[1]) == 0)
968fd57d42Sroy 		{
978fd57d42Sroy 			errno = EINVAL;
988fd57d42Sroy 			return 0;
998fd57d42Sroy 		}
1008fd57d42Sroy 		/* We should have at least two entries 00:01 */
1018fd57d42Sroy 		if (len == 0 && *p == '\0') {
1028fd57d42Sroy 			errno = EINVAL;
1038fd57d42Sroy 			return 0;
1048fd57d42Sroy 		}
1058fd57d42Sroy 		if (bp)
1068fd57d42Sroy 			*bp++ = (uint8_t)strtol(c, NULL, 16);
1078fd57d42Sroy 		len++;
1088fd57d42Sroy 	}
1098fd57d42Sroy 	return len;
1108fd57d42Sroy }
1118fd57d42Sroy 
1127c187152Sroy ssize_t
readfile(const char * file,void * data,size_t len)1137c187152Sroy readfile(const char *file, void *data, size_t len)
1148fd57d42Sroy {
1157c187152Sroy 	int fd;
1167c187152Sroy 	ssize_t bytes;
1178fd57d42Sroy 
1187c187152Sroy 	fd = open(file, O_RDONLY);
1197c187152Sroy 	if (fd == -1)
1207c187152Sroy 		return -1;
1217c187152Sroy 	bytes = read(fd, data, len);
1227c187152Sroy 	close(fd);
1237c187152Sroy 	if ((size_t)bytes == len) {
1247c187152Sroy 		errno = ENOBUFS;
1257c187152Sroy 		return -1;
1268fd57d42Sroy 	}
1277c187152Sroy 	return bytes;
1287c187152Sroy }
1297c187152Sroy 
1307c187152Sroy ssize_t
writefile(const char * file,mode_t mode,const void * data,size_t len)1317c187152Sroy writefile(const char *file, mode_t mode, const void *data, size_t len)
1327c187152Sroy {
1337c187152Sroy 	int fd;
1347c187152Sroy 	ssize_t bytes;
1357c187152Sroy 
1367c187152Sroy 	fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, mode);
1377c187152Sroy 	if (fd == -1)
1387c187152Sroy 		return -1;
1397c187152Sroy 	bytes = write(fd, data, len);
1407c187152Sroy 	close(fd);
1417c187152Sroy 	return bytes;
1427c187152Sroy }
1437c187152Sroy 
1447c187152Sroy int
filemtime(const char * file,time_t * time)1457c187152Sroy filemtime(const char *file, time_t *time)
1467c187152Sroy {
1477c187152Sroy 	struct stat st;
1487c187152Sroy 
1497c187152Sroy 	if (stat(file, &st) == -1)
1507c187152Sroy 		return -1;
1517c187152Sroy 	*time = st.st_mtime;
1527c187152Sroy 	return 0;
1537c187152Sroy }
1547c187152Sroy 
1557c187152Sroy /* Handy routine to read very long lines in text files.
1567c187152Sroy  * This means we read the whole line and avoid any nasty buffer overflows.
1577c187152Sroy  * We strip leading space and avoid comment lines, making the code that calls
1587c187152Sroy  * us smaller. */
1597c187152Sroy char *
get_line(char ** __restrict buf,ssize_t * __restrict buflen)1607c187152Sroy get_line(char ** __restrict buf, ssize_t * __restrict buflen)
1617c187152Sroy {
1627c187152Sroy 	char *p, *c;
1637c187152Sroy 	bool quoted;
1647c187152Sroy 
1657c187152Sroy 	do {
1667c187152Sroy 		p = *buf;
1677c187152Sroy 		if (*buf == NULL)
1687c187152Sroy 			return NULL;
1697c187152Sroy 		c = memchr(*buf, '\n', (size_t)*buflen);
1707c187152Sroy 		if (c == NULL) {
1717c187152Sroy 			c = memchr(*buf, '\0', (size_t)*buflen);
1727c187152Sroy 			if (c == NULL)
1737c187152Sroy 				return NULL;
1747c187152Sroy 			*buflen = c - *buf;
1757c187152Sroy 			*buf = NULL;
1767c187152Sroy 		} else {
1777c187152Sroy 			*c++ = '\0';
1787c187152Sroy 			*buflen -= c - *buf;
1797c187152Sroy 			*buf = c;
1807c187152Sroy 		}
1817c187152Sroy 		for (; *p == ' ' || *p == '\t'; p++)
1827c187152Sroy 			;
1837c187152Sroy 	} while (*p == '\0' || *p == '\n' || *p == '#' || *p == ';');
1847c187152Sroy 
1857c187152Sroy 	/* Strip embedded comments unless in a quoted string or escaped */
1867c187152Sroy 	quoted = false;
1877c187152Sroy 	for (c = p; *c != '\0'; c++) {
1887c187152Sroy 		if (*c == '\\') {
1897c187152Sroy 			c++; /* escaped */
1907c187152Sroy 			continue;
1917c187152Sroy 		}
1927c187152Sroy 		if (*c == '"')
1937c187152Sroy 			quoted = !quoted;
1947c187152Sroy 		else if (*c == '#' && !quoted) {
1957c187152Sroy 			*c = '\0';
1968fd57d42Sroy 			break;
1978fd57d42Sroy 		}
1988fd57d42Sroy 	}
1997c187152Sroy 	return p;
2008fd57d42Sroy }
2018fc24ed9Sroy 
2027c187152Sroy 
2038fc24ed9Sroy int
is_root_local(void)2048fc24ed9Sroy is_root_local(void)
2058fc24ed9Sroy {
2068fc24ed9Sroy #ifdef ST_LOCAL
2078fc24ed9Sroy 	struct statvfs vfs;
2088fc24ed9Sroy 
2098fc24ed9Sroy 	if (statvfs("/", &vfs) == -1)
2108fc24ed9Sroy 		return -1;
2118fc24ed9Sroy 	return vfs.f_flag & ST_LOCAL ? 1 : 0;
2128fc24ed9Sroy #else
2138fc24ed9Sroy 	errno = ENOTSUP;
2148fc24ed9Sroy 	return -1;
2158fc24ed9Sroy #endif
2168fc24ed9Sroy }
217