Update to dhcpcd-9.4.1 with the following changes:
[dragonfly.git] / contrib / dhcpcd / src / common.c
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3  * dhcpcd - DHCP client daemon
4  * Copyright (c) 2006-2021 Roy Marples <roy@marples.name>
5  * All rights reserved
6
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/stat.h>
30 #include <sys/statvfs.h>
31
32 #include <ctype.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include "common.h"
40 #include "dhcpcd.h"
41 #include "if-options.h"
42
43 const char *
44 hwaddr_ntoa(const void *hwaddr, size_t hwlen, char *buf, size_t buflen)
45 {
46         const unsigned char *hp, *ep;
47         char *p;
48
49         if (buf == NULL || hwlen == 0)
50                 return NULL;
51
52         if (hwlen * 3 > buflen) {
53                 errno = ENOBUFS;
54                 return NULL;
55         }
56
57         hp = hwaddr;
58         ep = hp + hwlen;
59         p = buf;
60
61         while (hp < ep) {
62                 if (hp != hwaddr)
63                         *p ++= ':';
64                 p += snprintf(p, 3, "%.2x", *hp++);
65         }
66         *p ++= '\0';
67         return buf;
68 }
69
70 size_t
71 hwaddr_aton(uint8_t *buffer, const char *addr)
72 {
73         char c[3];
74         const char *p = addr;
75         uint8_t *bp = buffer;
76         size_t len = 0;
77
78         c[2] = '\0';
79         while (*p != '\0') {
80                 /* Skip separators */
81                 c[0] = *p++;
82                 switch (c[0]) {
83                 case '\n':      /* long duid split on lines */
84                 case ':':       /* typical mac address */
85                 case '-':       /* uuid */
86                         continue;
87                 }
88                 c[1] = *p++;
89                 /* Ensure that digits are hex */
90                 if (isxdigit((unsigned char)c[0]) == 0 ||
91                     isxdigit((unsigned char)c[1]) == 0)
92                 {
93                         errno = EINVAL;
94                         return 0;
95                 }
96                 /* We should have at least two entries 00:01 */
97                 if (len == 0 && *p == '\0') {
98                         errno = EINVAL;
99                         return 0;
100                 }
101                 if (bp)
102                         *bp++ = (uint8_t)strtol(c, NULL, 16);
103                 len++;
104         }
105         return len;
106 }
107
108 ssize_t
109 readfile(const char *file, void *data, size_t len)
110 {
111         int fd;
112         ssize_t bytes;
113
114         fd = open(file, O_RDONLY);
115         if (fd == -1)
116                 return -1;
117         bytes = read(fd, data, len);
118         close(fd);
119         if ((size_t)bytes == len) {
120                 errno = ENOBUFS;
121                 return -1;
122         }
123         return bytes;
124 }
125
126 ssize_t
127 writefile(const char *file, mode_t mode, const void *data, size_t len)
128 {
129         int fd;
130         ssize_t bytes;
131
132         fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, mode);
133         if (fd == -1)
134                 return -1;
135         bytes = write(fd, data, len);
136         close(fd);
137         return bytes;
138 }
139
140 int
141 filemtime(const char *file, time_t *time)
142 {
143         struct stat st;
144
145         if (stat(file, &st) == -1)
146                 return -1;
147         *time = st.st_mtime;
148         return 0;
149 }
150
151 /* Handy routine to read very long lines in text files.
152  * This means we read the whole line and avoid any nasty buffer overflows.
153  * We strip leading space and avoid comment lines, making the code that calls
154  * us smaller. */
155 char *
156 get_line(char ** __restrict buf, ssize_t * __restrict buflen)
157 {
158         char *p, *c;
159         bool quoted;
160
161         do {
162                 p = *buf;
163                 if (*buf == NULL)
164                         return NULL;
165                 c = memchr(*buf, '\n', (size_t)*buflen);
166                 if (c == NULL) {
167                         c = memchr(*buf, '\0', (size_t)*buflen);
168                         if (c == NULL)
169                                 return NULL;
170                         *buflen = c - *buf;
171                         *buf = NULL;
172                 } else {
173                         *c++ = '\0';
174                         *buflen -= c - *buf;
175                         *buf = c;
176                 }
177                 for (; *p == ' ' || *p == '\t'; p++)
178                         ;
179         } while (*p == '\0' || *p == '\n' || *p == '#' || *p == ';');
180
181         /* Strip embedded comments unless in a quoted string or escaped */
182         quoted = false;
183         for (c = p; *c != '\0'; c++) {
184                 if (*c == '\\') {
185                         c++; /* escaped */
186                         continue;
187                 }
188                 if (*c == '"')
189                         quoted = !quoted;
190                 else if (*c == '#' && !quoted) {
191                         *c = '\0';
192                         break;
193                 }
194         }
195         return p;
196 }
197
198
199 int
200 is_root_local(void)
201 {
202 #ifdef ST_LOCAL
203         struct statvfs vfs;
204
205         if (statvfs("/", &vfs) == -1)
206                 return -1;
207         return vfs.f_flag & ST_LOCAL ? 1 : 0;
208 #else
209         errno = ENOTSUP;
210         return -1;
211 #endif
212 }