1239302Skib/*- 2239302Skib * SPDX-License-Identifier: BSD-2-Clause 3239302Skib * 4239302Skib * Copyright (c) 2014 The FreeBSD Foundation 5239302Skib * 6239302Skib * This software was developed by Edward Tomasz Napierala under sponsorship 7239302Skib * from the FreeBSD Foundation. 8239302Skib * 9239302Skib * Redistribution and use in source and binary forms, with or without 10239302Skib * modification, are permitted provided that the following conditions 11239302Skib * are met: 12239302Skib * 1. Redistributions of source code must retain the above copyright 13239302Skib * notice, this list of conditions and the following disclaimer. 14239302Skib * 2. Redistributions in binary form must reproduce the above copyright 15239302Skib * notice, this list of conditions and the following disclaimer in the 16239302Skib * documentation and/or other materials provided with the distribution. 17239302Skib * 18239302Skib * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19239302Skib * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20239302Skib * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21239302Skib * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22239302Skib * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23239302Skib * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24239302Skib * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25239302Skib * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26239302Skib * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27239302Skib * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28239302Skib * SUCH DAMAGE. 29239302Skib * 30239302Skib */ 31239302Skib 32239302Skib/* 33239302Skib * All the "defined" stuff is for handling variables, 34239302Skib * such as ${OSNAME}, in maps. 35239302Skib */ 36239302Skib 37239302Skib#include <sys/types.h> 38239305Sjoel#include <sys/time.h> 39239306Skib#include <sys/ioctl.h> 40239305Sjoel#include <sys/param.h> 41239302Skib#include <sys/linker.h> 42239305Sjoel#include <sys/mount.h> 43239305Sjoel#include <sys/socket.h> 44239302Skib#include <sys/stat.h> 45239302Skib#include <sys/wait.h> 46239305Sjoel#include <sys/utsname.h> 47239302Skib#include <assert.h> 48239302Skib#include <ctype.h> 49239302Skib#include <errno.h> 50239302Skib#include <fcntl.h> 51239302Skib#include <libgen.h> 52239302Skib#include <libutil.h> 53239302Skib#include <netdb.h> 54239302Skib#include <signal.h> 55239302Skib#include <stdbool.h> 56239302Skib#include <stdint.h> 57239302Skib#include <stdio.h> 58239302Skib#include <stdlib.h> 59239305Sjoel#include <string.h> 60239305Sjoel#include <unistd.h> 61239305Sjoel 62239302Skib#include "common.h" 63239305Sjoel 64239302Skibstatic TAILQ_HEAD(, defined_value) defined_values; 65239302Skib 66239302Skibstatic const char * 67239305Sjoeldefined_find(const char *name) 68239305Sjoel{ 69239302Skib struct defined_value *d; 70239302Skib 71239302Skib TAILQ_FOREACH(d, &defined_values, d_next) { 72239302Skib if (strcmp(d->d_name, name) == 0) 73239302Skib return (d->d_value); 74239302Skib } 75239302Skib 76239305Sjoel return (NULL); 77239305Sjoel} 78239306Skib 79239306Skibchar * 80239302Skibdefined_expand(const char *string) 81239302Skib{ 82239302Skib const char *value; 83239302Skib char c, *expanded, *name; 84239302Skib int i, ret, before_len = 0, name_off = 0, name_len = 0, after_off = 0; 85239302Skib bool backslashed = false, bracketed = false; 86239302Skib 87239302Skib expanded = checked_strdup(string); 88239305Sjoel 89239302Skib for (i = 0; string[i] != '\0'; i++) { 90239302Skib c = string[i]; 91239305Sjoel if (c == '\\' && backslashed == false) { 92239302Skib backslashed = true; 93239302Skib continue; 94239302Skib } 95239302Skib if (backslashed) { 96239306Skib backslashed = false; 97239302Skib continue; 98239302Skib } 99239302Skib backslashed = false; 100239305Sjoel if (c != '$') 101239302Skib continue; 102239302Skib 103239305Sjoel /* 104239302Skib * The 'before_len' variable contains the number 105239305Sjoel * of characters before the '$'. 106239302Skib */ 107239302Skib before_len = i; 108239302Skib assert(i + 1 < (int)strlen(string)); 109239302Skib if (string[i + 1] == '{') 110239302Skib bracketed = true; 111239302Skib 112239302Skib if (string[i + 1] == '\0') { 113239305Sjoel log_warnx("truncated variable"); 114239302Skib return (NULL); 115239302Skib } 116239302Skib 117239302Skib /* 118239302Skib * Skip '$'. 119239302Skib */ 120239302Skib i++; 121239302Skib 122239302Skib if (bracketed) { 123239302Skib if (string[i + 1] == '\0') { 124239302Skib log_warnx("truncated variable"); 125239302Skib return (NULL); 126239302Skib } 127239302Skib 128239302Skib /* 129239302Skib * Skip '{'. 130239302Skib */ 131239302Skib i++; 132239302Skib } 133239302Skib 134239305Sjoel /* 135239302Skib * The 'name_off' variable contains the number 136239302Skib * of characters before the variable name, 137239302Skib * including the "$" or "${". 138239302Skib */ 139239302Skib name_off = i; 140239302Skib 141239302Skib for (; string[i] != '\0'; i++) { 142239302Skib c = string[i]; 143239302Skib /* 144239302Skib * XXX: Decide on the set of characters that can be 145239305Sjoel * used in a variable name. 146239305Sjoel */ 147 if (isalnum(c) || c == '_') 148 continue; 149 150 /* 151 * End of variable name. 152 */ 153 if (bracketed) { 154 if (c != '}') 155 continue; 156 157 /* 158 * The 'after_off' variable contains the number 159 * of characters before the rest of the string, 160 * i.e. after the variable name. 161 */ 162 after_off = i + 1; 163 assert(i > 1); 164 assert(i - 1 > name_off); 165 name_len = i - name_off; 166 break; 167 } 168 169 after_off = i; 170 assert(i > 1); 171 assert(i > name_off); 172 name_len = i - name_off; 173 break; 174 } 175 176 name = strndup(string + name_off, name_len); 177 if (name == NULL) 178 log_err(1, "strndup"); 179 value = defined_find(name); 180 if (value == NULL) { 181 log_warnx("undefined variable ${%s}", name); 182 return (NULL); 183 } 184 185 /* 186 * Concatenate it back. 187 */ 188 ret = asprintf(&expanded, "%.*s%s%s", 189 before_len, string, value, string + after_off); 190 if (ret < 0) 191 log_err(1, "asprintf"); 192 193 //log_debugx("\"%s\" expanded to \"%s\"", string, expanded); 194 free(name); 195 196 /* 197 * Figure out where to start searching for next variable. 198 */ 199 string = expanded; 200 i = before_len + strlen(value); 201 backslashed = bracketed = false; 202 before_len = name_off = name_len = after_off = 0; 203 assert(i <= (int)strlen(string)); 204 } 205 206 if (before_len != 0 || name_off != 0 || name_len != 0 || after_off != 0) { 207 log_warnx("truncated variable"); 208 return (NULL); 209 } 210 211 return (expanded); 212} 213 214static void 215defined_add(const char *name, const char *value) 216{ 217 struct defined_value *d; 218 const char *found; 219 220 found = defined_find(name); 221 if (found != NULL) 222 log_errx(1, "variable %s already defined", name); 223 224 log_debugx("defining variable %s=%s", name, value); 225 226 d = calloc(1, sizeof(*d)); 227 if (d == NULL) 228 log_err(1, "calloc"); 229 d->d_name = checked_strdup(name); 230 d->d_value = checked_strdup(value); 231 232 TAILQ_INSERT_TAIL(&defined_values, d, d_next); 233} 234 235void 236defined_parse_and_add(char *def) 237{ 238 char *name, *value; 239 240 value = def; 241 name = strsep(&value, "="); 242 243 if (value == NULL || value[0] == '\0') 244 log_errx(1, "missing variable value"); 245 if (name == NULL || name[0] == '\0') 246 log_errx(1, "missing variable name"); 247 248 defined_add(name, value); 249} 250 251void 252defined_init(void) 253{ 254 struct utsname name; 255 int error; 256 257 TAILQ_INIT(&defined_values); 258 259 error = uname(&name); 260 if (error != 0) 261 log_err(1, "uname"); 262 263 defined_add("ARCH", name.machine); 264 defined_add("CPU", name.machine); 265 defined_add("DOLLAR", "$"); 266 defined_add("HOST", name.nodename); 267 defined_add("OSNAME", name.sysname); 268 defined_add("OSREL", name.release); 269 defined_add("OSVERS", name.version); 270} 271