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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2026 Oxide Computer Company 24 */ 25 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <strings.h> 30 #include <secdb.h> 31 #include <ctype.h> 32 33 /* From libnsl */ 34 extern char *_strdup_null(char *); 35 extern char *_strtok_escape(char *, char *, char **); 36 extern char *_strpbrk_escape(char *, char *); 37 extern char *_unescape(char *, char *); 38 39 char *_do_unescape(char *); 40 41 42 /* 43 * kva_match(): Given a key-value array and a key, return a pointer to the 44 * value that matches the key. 45 */ 46 char * 47 kva_match(kva_t *kva, char *key) 48 { 49 int i; 50 kv_t *data; 51 52 if (kva == NULL || key == NULL) { 53 return (NULL); 54 } 55 data = kva->data; 56 for (i = 0; i < kva->length; i++) { 57 if (strcmp(data[i].key, key) == 0) { 58 return (data[i].value); 59 } 60 } 61 62 return (NULL); 63 } 64 65 /* 66 * _kva_free(): Free up memory. 67 */ 68 void 69 _kva_free(kva_t *kva) 70 { 71 int i; 72 kv_t *data; 73 74 if (kva == NULL) { 75 return; 76 } 77 data = kva->data; 78 for (i = 0; i < kva->length; i++) { 79 if (data[i].key != NULL) { 80 free(data[i].key); 81 data[i].key = NULL; 82 } 83 if (data[i].value != NULL) { 84 free(data[i].value); 85 data[i].value = NULL; 86 } 87 } 88 free(kva->data); 89 free(kva); 90 } 91 92 /* 93 * _kva_free_value(): Free up memory (value) for all the occurrences of 94 * the given key. 95 */ 96 void 97 _kva_free_value(kva_t *kva, char *key) 98 { 99 int ctr; 100 kv_t *data; 101 102 if (kva == NULL) { 103 return; 104 } 105 106 ctr = kva->length; 107 data = kva->data; 108 109 while (ctr--) { 110 if (strcmp(data->key, key) == 0 && data->value != NULL) { 111 free(data->value); 112 data->value = NULL; 113 } 114 data++; 115 } 116 } 117 118 /* 119 * new_kva(): Allocate a key-value array. 120 */ 121 kva_t * 122 _new_kva(int size) 123 { 124 kva_t *new_kva; 125 126 if ((new_kva = (kva_t *)calloc(1, sizeof (kva_t))) == NULL) { 127 return (NULL); 128 } 129 if ((new_kva->data = (kv_t *)calloc(1, (size*sizeof (kv_t)))) == NULL) { 130 free(new_kva); 131 return (NULL); 132 } 133 134 return (new_kva); 135 } 136 137 /* 138 * _str2kva(): Given a string (s) of key-value pairs, separated by delimeter 139 * (del), place the values into the key value array (nkva). 140 */ 141 kva_t * 142 _str2kva(char *s, char *ass, char *del) 143 { 144 int n = 0; 145 int m; 146 int size = KV_ADD_KEYS; 147 char *buf; 148 char *p; 149 char *pair; 150 char *key; 151 char *last_pair; 152 char *last_key; 153 kv_t *data; 154 kva_t *nkva; 155 156 if (s == NULL || 157 ass == NULL || 158 del == NULL || 159 *s == '\0' || 160 *s == '\n' || 161 (strlen(s) <= 1)) { 162 return (NULL); 163 } 164 p = s; 165 while ((p = _strpbrk_escape(p, ass)) != NULL) { 166 n++; 167 p++; 168 } 169 if (n > size) { 170 m = n/size; 171 if (n%size) { 172 ++m; 173 } 174 size = m * KV_ADD_KEYS; 175 } 176 if ((nkva = _new_kva(size)) == NULL) { 177 return (NULL); 178 } 179 data = nkva->data; 180 nkva->length = 0; 181 if ((buf = strdup(s)) == NULL) { 182 return (NULL); 183 } 184 pair = _strtok_escape(buf, del, &last_pair); 185 do { 186 key = _strtok_escape(pair, ass, &last_key); 187 if (key != NULL) { 188 data[nkva->length].key = _do_unescape(key); 189 data[nkva->length].value = _do_unescape(last_key); 190 nkva->length++; 191 } 192 } while ((pair = _strtok_escape(NULL, del, &last_pair)) != NULL); 193 free(buf); 194 return (nkva); 195 } 196 197 /* 198 * _kva2str(): Given an array of key-value pairs, place them into a string 199 * (buf). Use delimeter (del) to separate pairs. Use assignment character 200 * (ass) to separate keys and values. 201 * 202 * Return Values: 0 Success 1 Buffer too small 203 */ 204 int 205 _kva2str(kva_t *kva, char *buf, int buflen, char *ass, char *del) 206 { 207 int i; 208 int len; 209 int off = 0; 210 kv_t *data; 211 212 if (kva == NULL) { 213 return (0); 214 } 215 216 buf[0] = '\0'; 217 data = kva->data; 218 219 for (i = 0; i < kva->length; i++) { 220 if (data[i].value != NULL) { 221 len = snprintf(buf + off, buflen - off, "%s%s%s%s", 222 data[i].key, ass, data[i].value, del); 223 if (len < 0 || len + off >= buflen) { 224 return (1); 225 } 226 off += len; 227 } 228 } 229 230 return (0); 231 } 232 233 int 234 _insert2kva(kva_t *kva, char *key, char *value) 235 { 236 int i; 237 kv_t *data; 238 239 if (kva == NULL) { 240 return (0); 241 } 242 data = kva->data; 243 for (i = 0; i < kva->length; i++) { 244 if (strcmp(data[i].key, key) == 0) { 245 if (data[i].value != NULL) 246 free(data[i].value); 247 data[i].value = _strdup_null(value); 248 return (0); 249 } 250 } 251 return (1); 252 } 253 254 kva_t * 255 _kva_dup(kva_t *old_kva) 256 { 257 int i; 258 int size; 259 kv_t *old_data; 260 kv_t *new_data; 261 kva_t *nkva = NULL; 262 263 if (old_kva == NULL) { 264 return (NULL); 265 } 266 old_data = old_kva->data; 267 size = old_kva->length; 268 if ((nkva = _new_kva(size)) == NULL) { 269 return (NULL); 270 } 271 new_data = nkva->data; 272 nkva->length = old_kva->length; 273 for (i = 0; i < nkva->length; i++) { 274 new_data[i].key = _strdup_null(old_data[i].key); 275 new_data[i].value = _strdup_null(old_data[i].value); 276 } 277 278 return (nkva); 279 } 280 281 static void 282 strip_spaces(char **valuep) 283 { 284 char *p, *start; 285 286 /* Find first non-white space character and return pointer to it */ 287 for (p = *valuep; *p != '\0' && isspace((unsigned char)*p); p++) 288 ; 289 290 *valuep = start = p; 291 292 if (*p == '\0') 293 return; 294 295 p = p + strlen(p) - 1; 296 297 /* Remove trailing spaces */ 298 while (p > start && isspace((unsigned char)*p)) 299 p--; 300 301 p[1] = '\0'; 302 } 303 304 char * 305 _do_unescape(char *src) 306 { 307 char *tmp = NULL; 308 char *dst = NULL; 309 310 if (src == NULL) { 311 dst = _strdup_null(src); 312 } else { 313 strip_spaces(&src); 314 tmp = _unescape(src, "=;:,\\"); 315 dst = (tmp == NULL) ? _strdup_null(src) : tmp; 316 } 317 318 return (dst); 319 } 320 321 322 /* 323 * Some utilities for handling comma-separated lists. 324 */ 325 char * 326 _argv_to_csl(char **strings) 327 { 328 int len = 0; 329 int i = 0; 330 char *newstr = NULL; 331 332 if (strings == NULL) 333 return (NULL); 334 for (i = 0; strings[i] != NULL; i++) { 335 len += strlen(strings[i]) + 1; 336 } 337 if ((len > 0) && ((newstr = (char *)malloc(len + 1)) != NULL)) { 338 (void) memset(newstr, 0, len); 339 for (i = 0; strings[i] != NULL; i++) { 340 (void) strcat(newstr, strings[i]); 341 (void) strcat(newstr, ","); 342 } 343 newstr[len-1] = '\0'; 344 return (newstr); 345 } else 346 return (NULL); 347 } 348 349 350 char ** 351 _csl_to_argv(char *csl) 352 { 353 int len = 0; 354 int ncommas = 0; 355 int i = 0; 356 char **spc = NULL; 357 char *copy = NULL; 358 char *pc; 359 char *lasts = NULL; 360 361 len = strlen(csl); 362 for (i = 0; i < len; i++) { 363 if (csl[i] == ',') 364 ncommas++; 365 } 366 if ((spc = (char **)malloc((ncommas + 2) * sizeof (char *))) == NULL) { 367 return (NULL); 368 } 369 if ((copy = strdup(csl)) == NULL) { 370 free(spc); 371 return (NULL); 372 } 373 for (pc = strtok_r(copy, ",", &lasts), i = 0; pc != NULL; 374 pc = strtok_r(NULL, ",", &lasts), i++) { 375 if ((spc[i] = strdup(pc)) == NULL) { 376 _free_argv(spc); 377 free(copy); 378 return (NULL); 379 } 380 } 381 spc[i] = NULL; 382 free(copy); 383 return (spc); 384 } 385 386 387 void 388 _free_argv(char **p_argv) 389 { 390 char **p_a; 391 392 for (p_a = p_argv; *p_a != NULL; p_a++) 393 free(*p_a); 394 free(p_argv); 395 } 396 397 398 #ifdef DEBUG 399 void 400 print_kva(kva_t *kva) 401 { 402 int i; 403 kv_t *data; 404 405 if (kva == NULL) { 406 (void) printf(" (empty)\n"); 407 return; 408 } 409 data = kva->data; 410 for (i = 0; i < kva->length; i++) { 411 (void) printf(" %s = %s\n", 412 data[i].key != NULL ? data[i].key : "NULL", 413 data[i].value != NULL ? data[i].value : "NULL"); 414 } 415 } 416 #endif /* DEBUG */ 417