defined.c revision 270897
1270096Strasz/*- 2270096Strasz * Copyright (c) 2014 The FreeBSD Foundation 3270096Strasz * All rights reserved. 4270096Strasz * 5270096Strasz * This software was developed by Edward Tomasz Napierala under sponsorship 6270096Strasz * from the FreeBSD Foundation. 7270096Strasz * 8270096Strasz * Redistribution and use in source and binary forms, with or without 9270096Strasz * modification, are permitted provided that the following conditions 10270096Strasz * are met: 11270096Strasz * 1. Redistributions of source code must retain the above copyright 12270096Strasz * notice, this list of conditions and the following disclaimer. 13270096Strasz * 2. Redistributions in binary form must reproduce the above copyright 14270096Strasz * notice, this list of conditions and the following disclaimer in the 15270096Strasz * documentation and/or other materials provided with the distribution. 16270096Strasz * 17270096Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18270096Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19270096Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20270096Strasz * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21270096Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22270096Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23270096Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24270096Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25270096Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26270096Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27270096Strasz * SUCH DAMAGE. 28270096Strasz * 29270096Strasz */ 30270096Strasz 31270096Strasz/* 32270096Strasz * All the "defined" stuff is for handling variables, 33270096Strasz * such as ${OSNAME}, in maps. 34270096Strasz */ 35270096Strasz 36270897Strasz#include <sys/cdefs.h> 37270897Strasz__FBSDID("$FreeBSD: stable/10/usr.sbin/autofs/defined.c 270897 2014-08-31 21:48:12Z trasz $"); 38270897Strasz 39270096Strasz#include <sys/types.h> 40270096Strasz#include <sys/time.h> 41270096Strasz#include <sys/ioctl.h> 42270096Strasz#include <sys/param.h> 43270096Strasz#include <sys/linker.h> 44270096Strasz#include <sys/mount.h> 45270096Strasz#include <sys/socket.h> 46270096Strasz#include <sys/stat.h> 47270096Strasz#include <sys/wait.h> 48270096Strasz#include <sys/utsname.h> 49270096Strasz#include <assert.h> 50270096Strasz#include <ctype.h> 51270096Strasz#include <errno.h> 52270096Strasz#include <fcntl.h> 53270096Strasz#include <libgen.h> 54270096Strasz#include <netdb.h> 55270096Strasz#include <signal.h> 56270096Strasz#include <stdbool.h> 57270096Strasz#include <stdint.h> 58270096Strasz#include <stdio.h> 59270096Strasz#include <stdlib.h> 60270096Strasz#include <string.h> 61270096Strasz#include <unistd.h> 62270096Strasz 63270096Strasz#include <libutil.h> 64270096Strasz 65270096Strasz#include "common.h" 66270096Strasz 67270096Straszstatic TAILQ_HEAD(, defined_value) defined_values; 68270096Strasz 69270096Straszstatic const char * 70270096Straszdefined_find(const char *name) 71270096Strasz{ 72270096Strasz struct defined_value *d; 73270096Strasz 74270096Strasz TAILQ_FOREACH(d, &defined_values, d_next) { 75270096Strasz if (strcmp(d->d_name, name) == 0) 76270096Strasz return (d->d_value); 77270096Strasz } 78270096Strasz 79270096Strasz return (NULL); 80270096Strasz} 81270096Strasz 82270096Straszchar * 83270096Straszdefined_expand(const char *string) 84270096Strasz{ 85270096Strasz const char *value; 86270096Strasz char c, *expanded, *name; 87270096Strasz int i, ret, before_len = 0, name_off = 0, name_len = 0, after_off = 0; 88270096Strasz bool backslashed = false, bracketed = false; 89270096Strasz 90270096Strasz expanded = checked_strdup(string); 91270096Strasz 92270096Strasz for (i = 0; string[i] != '\0'; i++) { 93270096Strasz c = string[i]; 94270096Strasz if (c == '\\' && backslashed == false) { 95270096Strasz backslashed = true; 96270096Strasz continue; 97270096Strasz } 98270096Strasz if (backslashed) { 99270096Strasz backslashed = false; 100270096Strasz continue; 101270096Strasz } 102270096Strasz backslashed = false; 103270096Strasz if (c != '$') 104270096Strasz continue; 105270096Strasz 106270096Strasz /* 107270096Strasz * The 'before_len' variable contains the number 108270096Strasz * of characters before the '$'. 109270096Strasz */ 110270096Strasz before_len = i; 111270096Strasz assert(i + 1 < (int)strlen(string)); 112270096Strasz if (string[i + 1] == '{') 113270096Strasz bracketed = true; 114270096Strasz 115270096Strasz if (string[i + 1] == '\0') { 116270096Strasz log_warnx("truncated variable"); 117270096Strasz return (NULL); 118270096Strasz } 119270096Strasz 120270096Strasz /* 121270096Strasz * Skip '$'. 122270096Strasz */ 123270096Strasz i++; 124270096Strasz 125270096Strasz if (bracketed) { 126270096Strasz if (string[i + 1] == '\0') { 127270096Strasz log_warnx("truncated variable"); 128270096Strasz return (NULL); 129270096Strasz } 130270096Strasz 131270096Strasz /* 132270096Strasz * Skip '{'. 133270096Strasz */ 134270096Strasz i++; 135270096Strasz } 136270096Strasz 137270096Strasz /* 138270096Strasz * The 'name_off' variable contains the number 139270096Strasz * of characters before the variable name, 140270096Strasz * including the "$" or "${". 141270096Strasz */ 142270096Strasz name_off = i; 143270096Strasz 144270096Strasz for (; string[i] != '\0'; i++) { 145270096Strasz c = string[i]; 146270096Strasz /* 147270096Strasz * XXX: Decide on the set of characters that can be 148270096Strasz * used in a variable name. 149270096Strasz */ 150270096Strasz if (isalnum(c) || c == '_') 151270096Strasz continue; 152270096Strasz 153270096Strasz /* 154270096Strasz * End of variable name. 155270096Strasz */ 156270096Strasz if (bracketed) { 157270096Strasz if (c != '}') 158270096Strasz continue; 159270096Strasz 160270096Strasz /* 161270096Strasz * The 'after_off' variable contains the number 162270096Strasz * of characters before the rest of the string, 163270096Strasz * i.e. after the variable name. 164270096Strasz */ 165270096Strasz after_off = i + 1; 166270096Strasz assert(i > 1); 167270096Strasz assert(i - 1 > name_off); 168270096Strasz name_len = i - name_off; 169270096Strasz break; 170270096Strasz } 171270096Strasz 172270096Strasz after_off = i; 173270096Strasz assert(i > 1); 174270096Strasz assert(i > name_off); 175270096Strasz name_len = i - name_off; 176270096Strasz break; 177270096Strasz } 178270096Strasz 179270096Strasz name = strndup(string + name_off, name_len); 180270096Strasz if (name == NULL) 181270096Strasz log_err(1, "strndup"); 182270096Strasz value = defined_find(name); 183270096Strasz if (value == NULL) { 184270096Strasz log_warnx("undefined variable ${%s}", name); 185270096Strasz return (NULL); 186270096Strasz } 187270096Strasz 188270096Strasz /* 189270096Strasz * Concatenate it back. 190270096Strasz */ 191270096Strasz ret = asprintf(&expanded, "%.*s%s%s", 192270096Strasz before_len, string, value, string + after_off); 193270096Strasz if (ret < 0) 194270096Strasz log_err(1, "asprintf"); 195270096Strasz 196270096Strasz //log_debugx("\"%s\" expanded to \"%s\"", string, expanded); 197270096Strasz free(name); 198270096Strasz 199270096Strasz /* 200270096Strasz * Figure out where to start searching for next variable. 201270096Strasz */ 202270096Strasz string = expanded; 203270096Strasz i = before_len + strlen(value); 204270096Strasz backslashed = bracketed = false; 205270096Strasz before_len = name_off = name_len = after_off = 0; 206270096Strasz assert(i <= (int)strlen(string)); 207270096Strasz } 208270096Strasz 209270096Strasz if (before_len != 0 || name_off != 0 || name_len != 0 || after_off != 0) { 210270096Strasz log_warnx("truncated variable"); 211270096Strasz return (NULL); 212270096Strasz } 213270096Strasz 214270096Strasz return (expanded); 215270096Strasz} 216270096Strasz 217270096Straszstatic void 218270096Straszdefined_add(const char *name, const char *value) 219270096Strasz{ 220270096Strasz struct defined_value *d; 221270096Strasz const char *found; 222270096Strasz 223270096Strasz found = defined_find(name); 224270096Strasz if (found != NULL) 225270096Strasz log_errx(1, "variable %s already defined", name); 226270096Strasz 227270096Strasz log_debugx("defining variable %s=%s", name, value); 228270096Strasz 229270096Strasz d = calloc(sizeof(*d), 1); 230270096Strasz if (d == NULL) 231270096Strasz log_err(1, "calloc"); 232270096Strasz d->d_name = checked_strdup(name); 233270096Strasz d->d_value = checked_strdup(value); 234270096Strasz 235270096Strasz TAILQ_INSERT_TAIL(&defined_values, d, d_next); 236270096Strasz} 237270096Strasz 238270096Straszvoid 239270096Straszdefined_parse_and_add(char *def) 240270096Strasz{ 241270096Strasz char *name, *value; 242270096Strasz 243270096Strasz value = def; 244270096Strasz name = strsep(&value, "="); 245270096Strasz 246270096Strasz if (value == NULL || value[0] == '\0') 247270096Strasz log_errx(1, "missing variable value"); 248270096Strasz if (name == NULL || name[0] == '\0') 249270096Strasz log_errx(1, "missing variable name"); 250270096Strasz 251270096Strasz defined_add(name, value); 252270096Strasz} 253270096Strasz 254270096Straszvoid 255270096Straszdefined_init(void) 256270096Strasz{ 257270096Strasz struct utsname name; 258270096Strasz int error; 259270096Strasz 260270096Strasz TAILQ_INIT(&defined_values); 261270096Strasz 262270096Strasz error = uname(&name); 263270096Strasz if (error != 0) 264270096Strasz log_err(1, "uname"); 265270096Strasz 266270096Strasz defined_add("ARCH", name.machine); 267270096Strasz defined_add("CPU", name.machine); 268270096Strasz defined_add("HOST", name.nodename); 269270096Strasz defined_add("OSNAME", name.sysname); 270270096Strasz defined_add("OSREL", name.release); 271270096Strasz defined_add("OSVERS", name.version); 272270096Strasz} 273