1*3914ddf8SEdward Tomasz Napierala /*- 2*3914ddf8SEdward Tomasz Napierala * Copyright (c) 2014 The FreeBSD Foundation 3*3914ddf8SEdward Tomasz Napierala * All rights reserved. 4*3914ddf8SEdward Tomasz Napierala * 5*3914ddf8SEdward Tomasz Napierala * This software was developed by Edward Tomasz Napierala under sponsorship 6*3914ddf8SEdward Tomasz Napierala * from the FreeBSD Foundation. 7*3914ddf8SEdward Tomasz Napierala * 8*3914ddf8SEdward Tomasz Napierala * Redistribution and use in source and binary forms, with or without 9*3914ddf8SEdward Tomasz Napierala * modification, are permitted provided that the following conditions 10*3914ddf8SEdward Tomasz Napierala * are met: 11*3914ddf8SEdward Tomasz Napierala * 1. Redistributions of source code must retain the above copyright 12*3914ddf8SEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer. 13*3914ddf8SEdward Tomasz Napierala * 2. Redistributions in binary form must reproduce the above copyright 14*3914ddf8SEdward Tomasz Napierala * notice, this list of conditions and the following disclaimer in the 15*3914ddf8SEdward Tomasz Napierala * documentation and/or other materials provided with the distribution. 16*3914ddf8SEdward Tomasz Napierala * 17*3914ddf8SEdward Tomasz Napierala * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18*3914ddf8SEdward Tomasz Napierala * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*3914ddf8SEdward Tomasz Napierala * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*3914ddf8SEdward Tomasz Napierala * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21*3914ddf8SEdward Tomasz Napierala * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22*3914ddf8SEdward Tomasz Napierala * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23*3914ddf8SEdward Tomasz Napierala * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24*3914ddf8SEdward Tomasz Napierala * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25*3914ddf8SEdward Tomasz Napierala * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26*3914ddf8SEdward Tomasz Napierala * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*3914ddf8SEdward Tomasz Napierala * SUCH DAMAGE. 28*3914ddf8SEdward Tomasz Napierala * 29*3914ddf8SEdward Tomasz Napierala * $FreeBSD$ 30*3914ddf8SEdward Tomasz Napierala */ 31*3914ddf8SEdward Tomasz Napierala 32*3914ddf8SEdward Tomasz Napierala /* 33*3914ddf8SEdward Tomasz Napierala * All the "defined" stuff is for handling variables, 34*3914ddf8SEdward Tomasz Napierala * such as ${OSNAME}, in maps. 35*3914ddf8SEdward Tomasz Napierala */ 36*3914ddf8SEdward Tomasz Napierala 37*3914ddf8SEdward Tomasz Napierala #include <sys/types.h> 38*3914ddf8SEdward Tomasz Napierala #include <sys/time.h> 39*3914ddf8SEdward Tomasz Napierala #include <sys/ioctl.h> 40*3914ddf8SEdward Tomasz Napierala #include <sys/param.h> 41*3914ddf8SEdward Tomasz Napierala #include <sys/linker.h> 42*3914ddf8SEdward Tomasz Napierala #include <sys/mount.h> 43*3914ddf8SEdward Tomasz Napierala #include <sys/socket.h> 44*3914ddf8SEdward Tomasz Napierala #include <sys/stat.h> 45*3914ddf8SEdward Tomasz Napierala #include <sys/wait.h> 46*3914ddf8SEdward Tomasz Napierala #include <sys/utsname.h> 47*3914ddf8SEdward Tomasz Napierala #include <assert.h> 48*3914ddf8SEdward Tomasz Napierala #include <ctype.h> 49*3914ddf8SEdward Tomasz Napierala #include <errno.h> 50*3914ddf8SEdward Tomasz Napierala #include <fcntl.h> 51*3914ddf8SEdward Tomasz Napierala #include <libgen.h> 52*3914ddf8SEdward Tomasz Napierala #include <netdb.h> 53*3914ddf8SEdward Tomasz Napierala #include <signal.h> 54*3914ddf8SEdward Tomasz Napierala #include <stdbool.h> 55*3914ddf8SEdward Tomasz Napierala #include <stdint.h> 56*3914ddf8SEdward Tomasz Napierala #include <stdio.h> 57*3914ddf8SEdward Tomasz Napierala #include <stdlib.h> 58*3914ddf8SEdward Tomasz Napierala #include <string.h> 59*3914ddf8SEdward Tomasz Napierala #include <unistd.h> 60*3914ddf8SEdward Tomasz Napierala 61*3914ddf8SEdward Tomasz Napierala #include <libutil.h> 62*3914ddf8SEdward Tomasz Napierala 63*3914ddf8SEdward Tomasz Napierala #include "common.h" 64*3914ddf8SEdward Tomasz Napierala 65*3914ddf8SEdward Tomasz Napierala static TAILQ_HEAD(, defined_value) defined_values; 66*3914ddf8SEdward Tomasz Napierala 67*3914ddf8SEdward Tomasz Napierala static const char * 68*3914ddf8SEdward Tomasz Napierala defined_find(const char *name) 69*3914ddf8SEdward Tomasz Napierala { 70*3914ddf8SEdward Tomasz Napierala struct defined_value *d; 71*3914ddf8SEdward Tomasz Napierala 72*3914ddf8SEdward Tomasz Napierala TAILQ_FOREACH(d, &defined_values, d_next) { 73*3914ddf8SEdward Tomasz Napierala if (strcmp(d->d_name, name) == 0) 74*3914ddf8SEdward Tomasz Napierala return (d->d_value); 75*3914ddf8SEdward Tomasz Napierala } 76*3914ddf8SEdward Tomasz Napierala 77*3914ddf8SEdward Tomasz Napierala return (NULL); 78*3914ddf8SEdward Tomasz Napierala } 79*3914ddf8SEdward Tomasz Napierala 80*3914ddf8SEdward Tomasz Napierala char * 81*3914ddf8SEdward Tomasz Napierala defined_expand(const char *string) 82*3914ddf8SEdward Tomasz Napierala { 83*3914ddf8SEdward Tomasz Napierala const char *value; 84*3914ddf8SEdward Tomasz Napierala char c, *expanded, *name; 85*3914ddf8SEdward Tomasz Napierala int i, ret, before_len = 0, name_off = 0, name_len = 0, after_off = 0; 86*3914ddf8SEdward Tomasz Napierala bool backslashed = false, bracketed = false; 87*3914ddf8SEdward Tomasz Napierala 88*3914ddf8SEdward Tomasz Napierala expanded = checked_strdup(string); 89*3914ddf8SEdward Tomasz Napierala 90*3914ddf8SEdward Tomasz Napierala for (i = 0; string[i] != '\0'; i++) { 91*3914ddf8SEdward Tomasz Napierala c = string[i]; 92*3914ddf8SEdward Tomasz Napierala if (c == '\\' && backslashed == false) { 93*3914ddf8SEdward Tomasz Napierala backslashed = true; 94*3914ddf8SEdward Tomasz Napierala continue; 95*3914ddf8SEdward Tomasz Napierala } 96*3914ddf8SEdward Tomasz Napierala if (backslashed) { 97*3914ddf8SEdward Tomasz Napierala backslashed = false; 98*3914ddf8SEdward Tomasz Napierala continue; 99*3914ddf8SEdward Tomasz Napierala } 100*3914ddf8SEdward Tomasz Napierala backslashed = false; 101*3914ddf8SEdward Tomasz Napierala if (c != '$') 102*3914ddf8SEdward Tomasz Napierala continue; 103*3914ddf8SEdward Tomasz Napierala 104*3914ddf8SEdward Tomasz Napierala /* 105*3914ddf8SEdward Tomasz Napierala * The 'before_len' variable contains the number 106*3914ddf8SEdward Tomasz Napierala * of characters before the '$'. 107*3914ddf8SEdward Tomasz Napierala */ 108*3914ddf8SEdward Tomasz Napierala before_len = i; 109*3914ddf8SEdward Tomasz Napierala assert(i + 1 < (int)strlen(string)); 110*3914ddf8SEdward Tomasz Napierala if (string[i + 1] == '{') 111*3914ddf8SEdward Tomasz Napierala bracketed = true; 112*3914ddf8SEdward Tomasz Napierala 113*3914ddf8SEdward Tomasz Napierala if (string[i + 1] == '\0') { 114*3914ddf8SEdward Tomasz Napierala log_warnx("truncated variable"); 115*3914ddf8SEdward Tomasz Napierala return (NULL); 116*3914ddf8SEdward Tomasz Napierala } 117*3914ddf8SEdward Tomasz Napierala 118*3914ddf8SEdward Tomasz Napierala /* 119*3914ddf8SEdward Tomasz Napierala * Skip '$'. 120*3914ddf8SEdward Tomasz Napierala */ 121*3914ddf8SEdward Tomasz Napierala i++; 122*3914ddf8SEdward Tomasz Napierala 123*3914ddf8SEdward Tomasz Napierala if (bracketed) { 124*3914ddf8SEdward Tomasz Napierala if (string[i + 1] == '\0') { 125*3914ddf8SEdward Tomasz Napierala log_warnx("truncated variable"); 126*3914ddf8SEdward Tomasz Napierala return (NULL); 127*3914ddf8SEdward Tomasz Napierala } 128*3914ddf8SEdward Tomasz Napierala 129*3914ddf8SEdward Tomasz Napierala /* 130*3914ddf8SEdward Tomasz Napierala * Skip '{'. 131*3914ddf8SEdward Tomasz Napierala */ 132*3914ddf8SEdward Tomasz Napierala i++; 133*3914ddf8SEdward Tomasz Napierala } 134*3914ddf8SEdward Tomasz Napierala 135*3914ddf8SEdward Tomasz Napierala /* 136*3914ddf8SEdward Tomasz Napierala * The 'name_off' variable contains the number 137*3914ddf8SEdward Tomasz Napierala * of characters before the variable name, 138*3914ddf8SEdward Tomasz Napierala * including the "$" or "${". 139*3914ddf8SEdward Tomasz Napierala */ 140*3914ddf8SEdward Tomasz Napierala name_off = i; 141*3914ddf8SEdward Tomasz Napierala 142*3914ddf8SEdward Tomasz Napierala for (; string[i] != '\0'; i++) { 143*3914ddf8SEdward Tomasz Napierala c = string[i]; 144*3914ddf8SEdward Tomasz Napierala /* 145*3914ddf8SEdward Tomasz Napierala * XXX: Decide on the set of characters that can be 146*3914ddf8SEdward Tomasz Napierala * used in a variable name. 147*3914ddf8SEdward Tomasz Napierala */ 148*3914ddf8SEdward Tomasz Napierala if (isalnum(c) || c == '_') 149*3914ddf8SEdward Tomasz Napierala continue; 150*3914ddf8SEdward Tomasz Napierala 151*3914ddf8SEdward Tomasz Napierala /* 152*3914ddf8SEdward Tomasz Napierala * End of variable name. 153*3914ddf8SEdward Tomasz Napierala */ 154*3914ddf8SEdward Tomasz Napierala if (bracketed) { 155*3914ddf8SEdward Tomasz Napierala if (c != '}') 156*3914ddf8SEdward Tomasz Napierala continue; 157*3914ddf8SEdward Tomasz Napierala 158*3914ddf8SEdward Tomasz Napierala /* 159*3914ddf8SEdward Tomasz Napierala * The 'after_off' variable contains the number 160*3914ddf8SEdward Tomasz Napierala * of characters before the rest of the string, 161*3914ddf8SEdward Tomasz Napierala * i.e. after the variable name. 162*3914ddf8SEdward Tomasz Napierala */ 163*3914ddf8SEdward Tomasz Napierala after_off = i + 1; 164*3914ddf8SEdward Tomasz Napierala assert(i > 1); 165*3914ddf8SEdward Tomasz Napierala assert(i - 1 > name_off); 166*3914ddf8SEdward Tomasz Napierala name_len = i - name_off; 167*3914ddf8SEdward Tomasz Napierala break; 168*3914ddf8SEdward Tomasz Napierala } 169*3914ddf8SEdward Tomasz Napierala 170*3914ddf8SEdward Tomasz Napierala after_off = i; 171*3914ddf8SEdward Tomasz Napierala assert(i > 1); 172*3914ddf8SEdward Tomasz Napierala assert(i > name_off); 173*3914ddf8SEdward Tomasz Napierala name_len = i - name_off; 174*3914ddf8SEdward Tomasz Napierala break; 175*3914ddf8SEdward Tomasz Napierala } 176*3914ddf8SEdward Tomasz Napierala 177*3914ddf8SEdward Tomasz Napierala name = strndup(string + name_off, name_len); 178*3914ddf8SEdward Tomasz Napierala if (name == NULL) 179*3914ddf8SEdward Tomasz Napierala log_err(1, "strndup"); 180*3914ddf8SEdward Tomasz Napierala value = defined_find(name); 181*3914ddf8SEdward Tomasz Napierala if (value == NULL) { 182*3914ddf8SEdward Tomasz Napierala log_warnx("undefined variable ${%s}", name); 183*3914ddf8SEdward Tomasz Napierala return (NULL); 184*3914ddf8SEdward Tomasz Napierala } 185*3914ddf8SEdward Tomasz Napierala 186*3914ddf8SEdward Tomasz Napierala /* 187*3914ddf8SEdward Tomasz Napierala * Concatenate it back. 188*3914ddf8SEdward Tomasz Napierala */ 189*3914ddf8SEdward Tomasz Napierala ret = asprintf(&expanded, "%.*s%s%s", 190*3914ddf8SEdward Tomasz Napierala before_len, string, value, string + after_off); 191*3914ddf8SEdward Tomasz Napierala if (ret < 0) 192*3914ddf8SEdward Tomasz Napierala log_err(1, "asprintf"); 193*3914ddf8SEdward Tomasz Napierala 194*3914ddf8SEdward Tomasz Napierala //log_debugx("\"%s\" expanded to \"%s\"", string, expanded); 195*3914ddf8SEdward Tomasz Napierala free(name); 196*3914ddf8SEdward Tomasz Napierala 197*3914ddf8SEdward Tomasz Napierala /* 198*3914ddf8SEdward Tomasz Napierala * Figure out where to start searching for next variable. 199*3914ddf8SEdward Tomasz Napierala */ 200*3914ddf8SEdward Tomasz Napierala string = expanded; 201*3914ddf8SEdward Tomasz Napierala i = before_len + strlen(value); 202*3914ddf8SEdward Tomasz Napierala backslashed = bracketed = false; 203*3914ddf8SEdward Tomasz Napierala before_len = name_off = name_len = after_off = 0; 204*3914ddf8SEdward Tomasz Napierala assert(i <= (int)strlen(string)); 205*3914ddf8SEdward Tomasz Napierala } 206*3914ddf8SEdward Tomasz Napierala 207*3914ddf8SEdward Tomasz Napierala if (before_len != 0 || name_off != 0 || name_len != 0 || after_off != 0) { 208*3914ddf8SEdward Tomasz Napierala log_warnx("truncated variable"); 209*3914ddf8SEdward Tomasz Napierala return (NULL); 210*3914ddf8SEdward Tomasz Napierala } 211*3914ddf8SEdward Tomasz Napierala 212*3914ddf8SEdward Tomasz Napierala return (expanded); 213*3914ddf8SEdward Tomasz Napierala } 214*3914ddf8SEdward Tomasz Napierala 215*3914ddf8SEdward Tomasz Napierala static void 216*3914ddf8SEdward Tomasz Napierala defined_add(const char *name, const char *value) 217*3914ddf8SEdward Tomasz Napierala { 218*3914ddf8SEdward Tomasz Napierala struct defined_value *d; 219*3914ddf8SEdward Tomasz Napierala const char *found; 220*3914ddf8SEdward Tomasz Napierala 221*3914ddf8SEdward Tomasz Napierala found = defined_find(name); 222*3914ddf8SEdward Tomasz Napierala if (found != NULL) 223*3914ddf8SEdward Tomasz Napierala log_errx(1, "variable %s already defined", name); 224*3914ddf8SEdward Tomasz Napierala 225*3914ddf8SEdward Tomasz Napierala log_debugx("defining variable %s=%s", name, value); 226*3914ddf8SEdward Tomasz Napierala 227*3914ddf8SEdward Tomasz Napierala d = calloc(sizeof(*d), 1); 228*3914ddf8SEdward Tomasz Napierala if (d == NULL) 229*3914ddf8SEdward Tomasz Napierala log_err(1, "calloc"); 230*3914ddf8SEdward Tomasz Napierala d->d_name = checked_strdup(name); 231*3914ddf8SEdward Tomasz Napierala d->d_value = checked_strdup(value); 232*3914ddf8SEdward Tomasz Napierala 233*3914ddf8SEdward Tomasz Napierala TAILQ_INSERT_TAIL(&defined_values, d, d_next); 234*3914ddf8SEdward Tomasz Napierala } 235*3914ddf8SEdward Tomasz Napierala 236*3914ddf8SEdward Tomasz Napierala void 237*3914ddf8SEdward Tomasz Napierala defined_parse_and_add(char *def) 238*3914ddf8SEdward Tomasz Napierala { 239*3914ddf8SEdward Tomasz Napierala char *name, *value; 240*3914ddf8SEdward Tomasz Napierala 241*3914ddf8SEdward Tomasz Napierala value = def; 242*3914ddf8SEdward Tomasz Napierala name = strsep(&value, "="); 243*3914ddf8SEdward Tomasz Napierala 244*3914ddf8SEdward Tomasz Napierala if (value == NULL || value[0] == '\0') 245*3914ddf8SEdward Tomasz Napierala log_errx(1, "missing variable value"); 246*3914ddf8SEdward Tomasz Napierala if (name == NULL || name[0] == '\0') 247*3914ddf8SEdward Tomasz Napierala log_errx(1, "missing variable name"); 248*3914ddf8SEdward Tomasz Napierala 249*3914ddf8SEdward Tomasz Napierala defined_add(name, value); 250*3914ddf8SEdward Tomasz Napierala } 251*3914ddf8SEdward Tomasz Napierala 252*3914ddf8SEdward Tomasz Napierala void 253*3914ddf8SEdward Tomasz Napierala defined_init(void) 254*3914ddf8SEdward Tomasz Napierala { 255*3914ddf8SEdward Tomasz Napierala struct utsname name; 256*3914ddf8SEdward Tomasz Napierala int error; 257*3914ddf8SEdward Tomasz Napierala 258*3914ddf8SEdward Tomasz Napierala TAILQ_INIT(&defined_values); 259*3914ddf8SEdward Tomasz Napierala 260*3914ddf8SEdward Tomasz Napierala error = uname(&name); 261*3914ddf8SEdward Tomasz Napierala if (error != 0) 262*3914ddf8SEdward Tomasz Napierala log_err(1, "uname"); 263*3914ddf8SEdward Tomasz Napierala 264*3914ddf8SEdward Tomasz Napierala defined_add("ARCH", name.machine); 265*3914ddf8SEdward Tomasz Napierala defined_add("CPU", name.machine); 266*3914ddf8SEdward Tomasz Napierala defined_add("HOST", name.nodename); 267*3914ddf8SEdward Tomasz Napierala defined_add("OSNAME", name.sysname); 268*3914ddf8SEdward Tomasz Napierala defined_add("OSREL", name.release); 269*3914ddf8SEdward Tomasz Napierala defined_add("OSVERS", name.version); 270*3914ddf8SEdward Tomasz Napierala } 271