13914ddf8SEdward Tomasz Napierala /*- 2*abdd3945SEdward Tomasz Napierala * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*abdd3945SEdward Tomasz Napierala * 43914ddf8SEdward Tomasz Napierala * Copyright (c) 2014 The FreeBSD Foundation 53914ddf8SEdward Tomasz Napierala * All rights reserved. 63914ddf8SEdward Tomasz Napierala * 73914ddf8SEdward Tomasz Napierala * This software was developed by Edward Tomasz Napierala under sponsorship 83914ddf8SEdward Tomasz Napierala * from the FreeBSD Foundation. 93914ddf8SEdward Tomasz Napierala * 103914ddf8SEdward Tomasz Napierala * Redistribution and use in source and binary forms, with or without 113914ddf8SEdward Tomasz Napierala * modification, are permitted provided that the following conditions 123914ddf8SEdward Tomasz Napierala * are met: 133914ddf8SEdward Tomasz Napierala * 1. Redistributions of source code must retain the above copyright 143914ddf8SEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer. 153914ddf8SEdward Tomasz Napierala * 2. Redistributions in binary form must reproduce the above copyright 163914ddf8SEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer in the 173914ddf8SEdward Tomasz Napierala * documentation and/or other materials provided with the distribution. 183914ddf8SEdward Tomasz Napierala * 193914ddf8SEdward Tomasz Napierala * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 203914ddf8SEdward Tomasz Napierala * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 213914ddf8SEdward Tomasz Napierala * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 223914ddf8SEdward Tomasz Napierala * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 233914ddf8SEdward Tomasz Napierala * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 243914ddf8SEdward Tomasz Napierala * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 253914ddf8SEdward Tomasz Napierala * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 263914ddf8SEdward Tomasz Napierala * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 273914ddf8SEdward Tomasz Napierala * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 283914ddf8SEdward Tomasz Napierala * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 293914ddf8SEdward Tomasz Napierala * SUCH DAMAGE. 303914ddf8SEdward Tomasz Napierala * 313914ddf8SEdward Tomasz Napierala */ 323914ddf8SEdward Tomasz Napierala 333914ddf8SEdward Tomasz Napierala /* 343914ddf8SEdward Tomasz Napierala * All the "defined" stuff is for handling variables, 353914ddf8SEdward Tomasz Napierala * such as ${OSNAME}, in maps. 363914ddf8SEdward Tomasz Napierala */ 373914ddf8SEdward Tomasz Napierala 38925fd945SEdward Tomasz Napierala #include <sys/cdefs.h> 39925fd945SEdward Tomasz Napierala __FBSDID("$FreeBSD$"); 40925fd945SEdward Tomasz Napierala 413914ddf8SEdward Tomasz Napierala #include <sys/types.h> 423914ddf8SEdward Tomasz Napierala #include <sys/time.h> 433914ddf8SEdward Tomasz Napierala #include <sys/ioctl.h> 443914ddf8SEdward Tomasz Napierala #include <sys/param.h> 453914ddf8SEdward Tomasz Napierala #include <sys/linker.h> 463914ddf8SEdward Tomasz Napierala #include <sys/mount.h> 473914ddf8SEdward Tomasz Napierala #include <sys/socket.h> 483914ddf8SEdward Tomasz Napierala #include <sys/stat.h> 493914ddf8SEdward Tomasz Napierala #include <sys/wait.h> 503914ddf8SEdward Tomasz Napierala #include <sys/utsname.h> 513914ddf8SEdward Tomasz Napierala #include <assert.h> 523914ddf8SEdward Tomasz Napierala #include <ctype.h> 533914ddf8SEdward Tomasz Napierala #include <errno.h> 543914ddf8SEdward Tomasz Napierala #include <fcntl.h> 553914ddf8SEdward Tomasz Napierala #include <libgen.h> 56592d6e85SEdward Tomasz Napierala #include <libutil.h> 573914ddf8SEdward Tomasz Napierala #include <netdb.h> 583914ddf8SEdward Tomasz Napierala #include <signal.h> 593914ddf8SEdward Tomasz Napierala #include <stdbool.h> 603914ddf8SEdward Tomasz Napierala #include <stdint.h> 613914ddf8SEdward Tomasz Napierala #include <stdio.h> 623914ddf8SEdward Tomasz Napierala #include <stdlib.h> 633914ddf8SEdward Tomasz Napierala #include <string.h> 643914ddf8SEdward Tomasz Napierala #include <unistd.h> 653914ddf8SEdward Tomasz Napierala 663914ddf8SEdward Tomasz Napierala #include "common.h" 673914ddf8SEdward Tomasz Napierala 683914ddf8SEdward Tomasz Napierala static TAILQ_HEAD(, defined_value) defined_values; 693914ddf8SEdward Tomasz Napierala 703914ddf8SEdward Tomasz Napierala static const char * 713914ddf8SEdward Tomasz Napierala defined_find(const char *name) 723914ddf8SEdward Tomasz Napierala { 733914ddf8SEdward Tomasz Napierala struct defined_value *d; 743914ddf8SEdward Tomasz Napierala 753914ddf8SEdward Tomasz Napierala TAILQ_FOREACH(d, &defined_values, d_next) { 763914ddf8SEdward Tomasz Napierala if (strcmp(d->d_name, name) == 0) 773914ddf8SEdward Tomasz Napierala return (d->d_value); 783914ddf8SEdward Tomasz Napierala } 793914ddf8SEdward Tomasz Napierala 803914ddf8SEdward Tomasz Napierala return (NULL); 813914ddf8SEdward Tomasz Napierala } 823914ddf8SEdward Tomasz Napierala 833914ddf8SEdward Tomasz Napierala char * 843914ddf8SEdward Tomasz Napierala defined_expand(const char *string) 853914ddf8SEdward Tomasz Napierala { 863914ddf8SEdward Tomasz Napierala const char *value; 873914ddf8SEdward Tomasz Napierala char c, *expanded, *name; 883914ddf8SEdward Tomasz Napierala int i, ret, before_len = 0, name_off = 0, name_len = 0, after_off = 0; 893914ddf8SEdward Tomasz Napierala bool backslashed = false, bracketed = false; 903914ddf8SEdward Tomasz Napierala 913914ddf8SEdward Tomasz Napierala expanded = checked_strdup(string); 923914ddf8SEdward Tomasz Napierala 933914ddf8SEdward Tomasz Napierala for (i = 0; string[i] != '\0'; i++) { 943914ddf8SEdward Tomasz Napierala c = string[i]; 953914ddf8SEdward Tomasz Napierala if (c == '\\' && backslashed == false) { 963914ddf8SEdward Tomasz Napierala backslashed = true; 973914ddf8SEdward Tomasz Napierala continue; 983914ddf8SEdward Tomasz Napierala } 993914ddf8SEdward Tomasz Napierala if (backslashed) { 1003914ddf8SEdward Tomasz Napierala backslashed = false; 1013914ddf8SEdward Tomasz Napierala continue; 1023914ddf8SEdward Tomasz Napierala } 1033914ddf8SEdward Tomasz Napierala backslashed = false; 1043914ddf8SEdward Tomasz Napierala if (c != '$') 1053914ddf8SEdward Tomasz Napierala continue; 1063914ddf8SEdward Tomasz Napierala 1073914ddf8SEdward Tomasz Napierala /* 1083914ddf8SEdward Tomasz Napierala * The 'before_len' variable contains the number 1093914ddf8SEdward Tomasz Napierala * of characters before the '$'. 1103914ddf8SEdward Tomasz Napierala */ 1113914ddf8SEdward Tomasz Napierala before_len = i; 1123914ddf8SEdward Tomasz Napierala assert(i + 1 < (int)strlen(string)); 1133914ddf8SEdward Tomasz Napierala if (string[i + 1] == '{') 1143914ddf8SEdward Tomasz Napierala bracketed = true; 1153914ddf8SEdward Tomasz Napierala 1163914ddf8SEdward Tomasz Napierala if (string[i + 1] == '\0') { 1173914ddf8SEdward Tomasz Napierala log_warnx("truncated variable"); 1183914ddf8SEdward Tomasz Napierala return (NULL); 1193914ddf8SEdward Tomasz Napierala } 1203914ddf8SEdward Tomasz Napierala 1213914ddf8SEdward Tomasz Napierala /* 1223914ddf8SEdward Tomasz Napierala * Skip '$'. 1233914ddf8SEdward Tomasz Napierala */ 1243914ddf8SEdward Tomasz Napierala i++; 1253914ddf8SEdward Tomasz Napierala 1263914ddf8SEdward Tomasz Napierala if (bracketed) { 1273914ddf8SEdward Tomasz Napierala if (string[i + 1] == '\0') { 1283914ddf8SEdward Tomasz Napierala log_warnx("truncated variable"); 1293914ddf8SEdward Tomasz Napierala return (NULL); 1303914ddf8SEdward Tomasz Napierala } 1313914ddf8SEdward Tomasz Napierala 1323914ddf8SEdward Tomasz Napierala /* 1333914ddf8SEdward Tomasz Napierala * Skip '{'. 1343914ddf8SEdward Tomasz Napierala */ 1353914ddf8SEdward Tomasz Napierala i++; 1363914ddf8SEdward Tomasz Napierala } 1373914ddf8SEdward Tomasz Napierala 1383914ddf8SEdward Tomasz Napierala /* 1393914ddf8SEdward Tomasz Napierala * The 'name_off' variable contains the number 1403914ddf8SEdward Tomasz Napierala * of characters before the variable name, 1413914ddf8SEdward Tomasz Napierala * including the "$" or "${". 1423914ddf8SEdward Tomasz Napierala */ 1433914ddf8SEdward Tomasz Napierala name_off = i; 1443914ddf8SEdward Tomasz Napierala 1453914ddf8SEdward Tomasz Napierala for (; string[i] != '\0'; i++) { 1463914ddf8SEdward Tomasz Napierala c = string[i]; 1473914ddf8SEdward Tomasz Napierala /* 1483914ddf8SEdward Tomasz Napierala * XXX: Decide on the set of characters that can be 1493914ddf8SEdward Tomasz Napierala * used in a variable name. 1503914ddf8SEdward Tomasz Napierala */ 1513914ddf8SEdward Tomasz Napierala if (isalnum(c) || c == '_') 1523914ddf8SEdward Tomasz Napierala continue; 1533914ddf8SEdward Tomasz Napierala 1543914ddf8SEdward Tomasz Napierala /* 1553914ddf8SEdward Tomasz Napierala * End of variable name. 1563914ddf8SEdward Tomasz Napierala */ 1573914ddf8SEdward Tomasz Napierala if (bracketed) { 1583914ddf8SEdward Tomasz Napierala if (c != '}') 1593914ddf8SEdward Tomasz Napierala continue; 1603914ddf8SEdward Tomasz Napierala 1613914ddf8SEdward Tomasz Napierala /* 1623914ddf8SEdward Tomasz Napierala * The 'after_off' variable contains the number 1633914ddf8SEdward Tomasz Napierala * of characters before the rest of the string, 1643914ddf8SEdward Tomasz Napierala * i.e. after the variable name. 1653914ddf8SEdward Tomasz Napierala */ 1663914ddf8SEdward Tomasz Napierala after_off = i + 1; 1673914ddf8SEdward Tomasz Napierala assert(i > 1); 1683914ddf8SEdward Tomasz Napierala assert(i - 1 > name_off); 1693914ddf8SEdward Tomasz Napierala name_len = i - name_off; 1703914ddf8SEdward Tomasz Napierala break; 1713914ddf8SEdward Tomasz Napierala } 1723914ddf8SEdward Tomasz Napierala 1733914ddf8SEdward Tomasz Napierala after_off = i; 1743914ddf8SEdward Tomasz Napierala assert(i > 1); 1753914ddf8SEdward Tomasz Napierala assert(i > name_off); 1763914ddf8SEdward Tomasz Napierala name_len = i - name_off; 1773914ddf8SEdward Tomasz Napierala break; 1783914ddf8SEdward Tomasz Napierala } 1793914ddf8SEdward Tomasz Napierala 1803914ddf8SEdward Tomasz Napierala name = strndup(string + name_off, name_len); 1813914ddf8SEdward Tomasz Napierala if (name == NULL) 1823914ddf8SEdward Tomasz Napierala log_err(1, "strndup"); 1833914ddf8SEdward Tomasz Napierala value = defined_find(name); 1843914ddf8SEdward Tomasz Napierala if (value == NULL) { 1853914ddf8SEdward Tomasz Napierala log_warnx("undefined variable ${%s}", name); 1863914ddf8SEdward Tomasz Napierala return (NULL); 1873914ddf8SEdward Tomasz Napierala } 1883914ddf8SEdward Tomasz Napierala 1893914ddf8SEdward Tomasz Napierala /* 1903914ddf8SEdward Tomasz Napierala * Concatenate it back. 1913914ddf8SEdward Tomasz Napierala */ 1923914ddf8SEdward Tomasz Napierala ret = asprintf(&expanded, "%.*s%s%s", 1933914ddf8SEdward Tomasz Napierala before_len, string, value, string + after_off); 1943914ddf8SEdward Tomasz Napierala if (ret < 0) 1953914ddf8SEdward Tomasz Napierala log_err(1, "asprintf"); 1963914ddf8SEdward Tomasz Napierala 1973914ddf8SEdward Tomasz Napierala //log_debugx("\"%s\" expanded to \"%s\"", string, expanded); 1983914ddf8SEdward Tomasz Napierala free(name); 1993914ddf8SEdward Tomasz Napierala 2003914ddf8SEdward Tomasz Napierala /* 2013914ddf8SEdward Tomasz Napierala * Figure out where to start searching for next variable. 2023914ddf8SEdward Tomasz Napierala */ 2033914ddf8SEdward Tomasz Napierala string = expanded; 2043914ddf8SEdward Tomasz Napierala i = before_len + strlen(value); 2053914ddf8SEdward Tomasz Napierala backslashed = bracketed = false; 2063914ddf8SEdward Tomasz Napierala before_len = name_off = name_len = after_off = 0; 2073914ddf8SEdward Tomasz Napierala assert(i <= (int)strlen(string)); 2083914ddf8SEdward Tomasz Napierala } 2093914ddf8SEdward Tomasz Napierala 2103914ddf8SEdward Tomasz Napierala if (before_len != 0 || name_off != 0 || name_len != 0 || after_off != 0) { 2113914ddf8SEdward Tomasz Napierala log_warnx("truncated variable"); 2123914ddf8SEdward Tomasz Napierala return (NULL); 2133914ddf8SEdward Tomasz Napierala } 2143914ddf8SEdward Tomasz Napierala 2153914ddf8SEdward Tomasz Napierala return (expanded); 2163914ddf8SEdward Tomasz Napierala } 2173914ddf8SEdward Tomasz Napierala 2183914ddf8SEdward Tomasz Napierala static void 2193914ddf8SEdward Tomasz Napierala defined_add(const char *name, const char *value) 2203914ddf8SEdward Tomasz Napierala { 2213914ddf8SEdward Tomasz Napierala struct defined_value *d; 2223914ddf8SEdward Tomasz Napierala const char *found; 2233914ddf8SEdward Tomasz Napierala 2243914ddf8SEdward Tomasz Napierala found = defined_find(name); 2253914ddf8SEdward Tomasz Napierala if (found != NULL) 2263914ddf8SEdward Tomasz Napierala log_errx(1, "variable %s already defined", name); 2273914ddf8SEdward Tomasz Napierala 2283914ddf8SEdward Tomasz Napierala log_debugx("defining variable %s=%s", name, value); 2293914ddf8SEdward Tomasz Napierala 23027525377SEdward Tomasz Napierala d = calloc(1, sizeof(*d)); 2313914ddf8SEdward Tomasz Napierala if (d == NULL) 2323914ddf8SEdward Tomasz Napierala log_err(1, "calloc"); 2333914ddf8SEdward Tomasz Napierala d->d_name = checked_strdup(name); 2343914ddf8SEdward Tomasz Napierala d->d_value = checked_strdup(value); 2353914ddf8SEdward Tomasz Napierala 2363914ddf8SEdward Tomasz Napierala TAILQ_INSERT_TAIL(&defined_values, d, d_next); 2373914ddf8SEdward Tomasz Napierala } 2383914ddf8SEdward Tomasz Napierala 2393914ddf8SEdward Tomasz Napierala void 2403914ddf8SEdward Tomasz Napierala defined_parse_and_add(char *def) 2413914ddf8SEdward Tomasz Napierala { 2423914ddf8SEdward Tomasz Napierala char *name, *value; 2433914ddf8SEdward Tomasz Napierala 2443914ddf8SEdward Tomasz Napierala value = def; 2453914ddf8SEdward Tomasz Napierala name = strsep(&value, "="); 2463914ddf8SEdward Tomasz Napierala 2473914ddf8SEdward Tomasz Napierala if (value == NULL || value[0] == '\0') 2483914ddf8SEdward Tomasz Napierala log_errx(1, "missing variable value"); 2493914ddf8SEdward Tomasz Napierala if (name == NULL || name[0] == '\0') 2503914ddf8SEdward Tomasz Napierala log_errx(1, "missing variable name"); 2513914ddf8SEdward Tomasz Napierala 2523914ddf8SEdward Tomasz Napierala defined_add(name, value); 2533914ddf8SEdward Tomasz Napierala } 2543914ddf8SEdward Tomasz Napierala 2553914ddf8SEdward Tomasz Napierala void 2563914ddf8SEdward Tomasz Napierala defined_init(void) 2573914ddf8SEdward Tomasz Napierala { 2583914ddf8SEdward Tomasz Napierala struct utsname name; 2593914ddf8SEdward Tomasz Napierala int error; 2603914ddf8SEdward Tomasz Napierala 2613914ddf8SEdward Tomasz Napierala TAILQ_INIT(&defined_values); 2623914ddf8SEdward Tomasz Napierala 2633914ddf8SEdward Tomasz Napierala error = uname(&name); 2643914ddf8SEdward Tomasz Napierala if (error != 0) 2653914ddf8SEdward Tomasz Napierala log_err(1, "uname"); 2663914ddf8SEdward Tomasz Napierala 2673914ddf8SEdward Tomasz Napierala defined_add("ARCH", name.machine); 2683914ddf8SEdward Tomasz Napierala defined_add("CPU", name.machine); 2693914ddf8SEdward Tomasz Napierala defined_add("HOST", name.nodename); 2703914ddf8SEdward Tomasz Napierala defined_add("OSNAME", name.sysname); 2713914ddf8SEdward Tomasz Napierala defined_add("OSREL", name.release); 2723914ddf8SEdward Tomasz Napierala defined_add("OSVERS", name.version); 2733914ddf8SEdward Tomasz Napierala } 274