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