1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 /*
27  * Copyright 2019 Joyent, Inc.
28  * Copyright 2023 Oxide computer Company
29  */
30 
31 #include <strings.h>
32 #include <ctype.h>
33 #include <fm/libtopo.h>
34 #include <fm/topo_mod.h>
35 #include <topo_alloc.h>
36 
37 char *
topo_hdl_strdup(topo_hdl_t * thp,const char * s)38 topo_hdl_strdup(topo_hdl_t *thp, const char *s)
39 {
40 	char *p;
41 
42 	if (s != NULL)
43 		p = topo_hdl_alloc(thp, strlen(s) + 1);
44 	else
45 		p = NULL;
46 
47 	if (p != NULL)
48 		(void) strcpy(p, s);
49 
50 	return (p);
51 }
52 
53 void
topo_hdl_strfree(topo_hdl_t * thp,char * s)54 topo_hdl_strfree(topo_hdl_t *thp, char *s)
55 {
56 	if (s != NULL)
57 		topo_hdl_free(thp, s, strlen(s) + 1);
58 }
59 
60 void
topo_hdl_strfreev(topo_hdl_t * thp,char ** strarr,uint_t nelem)61 topo_hdl_strfreev(topo_hdl_t *thp, char **strarr, uint_t nelem)
62 {
63 	for (uint_t i = 0; i < nelem; i++)
64 		topo_hdl_strfree(thp, strarr[i]);
65 
66 	topo_hdl_free(thp, strarr, (nelem * sizeof (char *)));
67 }
68 
69 char *
topo_mod_strdup(topo_mod_t * mod,const char * s)70 topo_mod_strdup(topo_mod_t *mod, const char *s)
71 {
72 	return (topo_hdl_strdup(mod->tm_hdl, s));
73 }
74 
75 int
topo_hdl_vasprintf(topo_hdl_t * thp,char ** str,const char * fmt,va_list ap)76 topo_hdl_vasprintf(topo_hdl_t *thp, char **str, const char *fmt, va_list ap)
77 {
78 	int len, ret;
79 
80 	*str = NULL;
81 	len = vsnprintf(NULL, 0, fmt, ap);
82 	if (len < 0) {
83 		return (len);
84 	}
85 
86 	if (len == INT_MAX) {
87 		return (-1);
88 	}
89 	len++;
90 
91 	*str = topo_hdl_alloc(thp, len);
92 	if (*str == NULL) {
93 		return (-1);
94 	}
95 
96 	/*
97 	 * If an attempt to format a given string is inconsistent, then that
98 	 * means something is extremely wrong and we're not going to try again
99 	 * and leave that ultimately to the caller to deal with as it suggests
100 	 * they were changing something about the arguments themselves. While
101 	 * asprintf(3C) does loop on this, we are not as forgiving.
102 	 */
103 	ret = vsnprintf(*str, len, fmt, ap);
104 	if (ret < 0 || ret + 1 != len) {
105 		topo_hdl_free(thp, *str, len + 1);
106 		*str = NULL;
107 		return (-1);
108 	}
109 
110 	return (ret);
111 }
112 
113 int
topo_hdl_asprintf(topo_hdl_t * thp,char ** str,const char * fmt,...)114 topo_hdl_asprintf(topo_hdl_t *thp, char **str, const char *fmt, ...)
115 {
116 	int ret;
117 	va_list ap;
118 
119 	va_start(ap, fmt);
120 	ret = topo_hdl_vasprintf(thp, str, fmt, ap);
121 	va_end(ap);
122 	return (ret);
123 }
124 
125 int
topo_mod_vasprintf(topo_mod_t * mod,char ** str,const char * fmt,va_list ap)126 topo_mod_vasprintf(topo_mod_t *mod, char **str, const char *fmt, va_list ap)
127 {
128 	return (topo_hdl_vasprintf(mod->tm_hdl, str, fmt, ap));
129 }
130 
131 int
topo_mod_asprintf(topo_mod_t * mod,char ** str,const char * fmt,...)132 topo_mod_asprintf(topo_mod_t *mod, char **str, const char *fmt, ...)
133 {
134 	int ret;
135 	va_list ap;
136 
137 	va_start(ap, fmt);
138 	ret = topo_hdl_vasprintf(mod->tm_hdl, str, fmt, ap);
139 	va_end(ap);
140 	return (ret);
141 }
142 
143 void
topo_mod_strfree(topo_mod_t * mod,char * s)144 topo_mod_strfree(topo_mod_t *mod, char *s)
145 {
146 	topo_hdl_strfree(mod->tm_hdl, s);
147 }
148 
149 void
topo_mod_strfreev(topo_mod_t * mod,char ** strarr,uint_t nelem)150 topo_mod_strfreev(topo_mod_t *mod, char **strarr, uint_t nelem)
151 {
152 	topo_hdl_strfreev(mod->tm_hdl, strarr, nelem);
153 }
154 
155 const char *
topo_strbasename(const char * s)156 topo_strbasename(const char *s)
157 {
158 	const char *p = strrchr(s, '/');
159 
160 	if (p == NULL)
161 		return (s);
162 
163 	return (++p);
164 }
165 
166 char *
topo_strdirname(char * s)167 topo_strdirname(char *s)
168 {
169 	static char slash[] = "/";
170 	static char dot[] = ".";
171 	char *p;
172 
173 	if (s == NULL || *s == '\0')
174 		return (dot);
175 
176 	for (p = s + strlen(s); p != s && *--p == '/'; )
177 		continue;
178 
179 	if (p == s && *p == '/')
180 		return (slash);
181 
182 	while (p != s) {
183 		if (*--p == '/') {
184 			while (*p == '/' && p != s)
185 				p--;
186 			*++p = '\0';
187 			return (s);
188 		}
189 	}
190 
191 	return (dot);
192 }
193 
194 ulong_t
topo_strhash(const char * key)195 topo_strhash(const char *key)
196 {
197 	ulong_t g, h = 0;
198 	const char *p;
199 
200 	for (p = key; *p != '\0'; p++) {
201 		h = (h << 4) + *p;
202 
203 		if ((g = (h & 0xf0000000)) != 0) {
204 			h ^= (g >> 24);
205 			h ^= g;
206 		}
207 	}
208 
209 	return (h);
210 }
211 
212 /*
213  * Transform string s inline, converting each embedded C escape sequence string
214  * to the corresponding character.  For example, the substring "\n" is replaced
215  * by an inline '\n' character.  The length of the resulting string is returned.
216  */
217 size_t
topo_stresc2chr(char * s)218 topo_stresc2chr(char *s)
219 {
220 	char *p, *q, c;
221 	int esc = 0;
222 	int x;
223 
224 	for (p = q = s; (c = *p) != '\0'; p++) {
225 		if (esc) {
226 			switch (c) {
227 			case '0':
228 			case '1':
229 			case '2':
230 			case '3':
231 			case '4':
232 			case '5':
233 			case '6':
234 			case '7':
235 				c -= '0';
236 				p++;
237 
238 				if (*p >= '0' && *p <= '7') {
239 					c = c * 8 + *p++ - '0';
240 
241 					if (*p >= '0' && *p <= '7')
242 						c = c * 8 + *p - '0';
243 					else
244 						p--;
245 				} else
246 					p--;
247 
248 				*q++ = c;
249 				break;
250 
251 			case 'a':
252 				*q++ = '\a';
253 				break;
254 			case 'b':
255 				*q++ = '\b';
256 				break;
257 			case 'f':
258 				*q++ = '\f';
259 				break;
260 			case 'n':
261 				*q++ = '\n';
262 				break;
263 			case 'r':
264 				*q++ = '\r';
265 				break;
266 			case 't':
267 				*q++ = '\t';
268 				break;
269 			case 'v':
270 				*q++ = '\v';
271 				break;
272 
273 			case 'x':
274 				for (x = 0; (c = *++p) != '\0'; ) {
275 					if (c >= '0' && c <= '9')
276 						x = x * 16 + c - '0';
277 					else if (c >= 'a' && c <= 'f')
278 						x = x * 16 + c - 'a' + 10;
279 					else if (c >= 'A' && c <= 'F')
280 						x = x * 16 + c - 'A' + 10;
281 					else
282 						break;
283 				}
284 				*q++ = (char)x;
285 				p--;
286 				break;
287 
288 			case '"':
289 			case '\\':
290 				*q++ = c;
291 				break;
292 			default:
293 				*q++ = '\\';
294 				*q++ = c;
295 			}
296 
297 			esc = 0;
298 
299 		} else {
300 			if ((esc = c == '\\') == 0)
301 				*q++ = c;
302 		}
303 	}
304 
305 	*q = '\0';
306 	return ((size_t)(q - s));
307 }
308 
309 int
topo_strmatch(const char * s,const char * p)310 topo_strmatch(const char *s, const char *p)
311 {
312 	char c;
313 
314 	if (p == NULL)
315 		return (0);
316 
317 	if (s == NULL)
318 		s = ""; /* treat NULL string as the empty string */
319 
320 	do {
321 		if ((c = *p++) == '\0')
322 			return (*s == '\0');
323 
324 		if (c == '*') {
325 			while (*p == '*')
326 				p++; /* consecutive *'s can be collapsed */
327 
328 			if (*p == '\0')
329 				return (1);
330 
331 			while (*s != '\0') {
332 				if (topo_strmatch(s++, p) != 0)
333 					return (1);
334 			}
335 
336 			return (0);
337 		}
338 	} while (c == *s++);
339 
340 	return (0);
341 }
342