1 /* 2 * Copyright (c)2004 The DragonFly Project. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in 13 * the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * Neither the name of the DragonFly Project nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 31 * OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * confed.c 36 * Functions for working with configuration files. 37 * Inspired by (but not derived from) sysinstall's variable.c 38 * $Id: confed.c,v 1.16 2005/02/06 21:05:18 cpressey Exp $ 39 */ 40 41 #include <sys/stat.h> 42 43 #include <ctype.h> 44 #include <stdarg.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <time.h> 49 #include <unistd.h> 50 51 #include "libaura/mem.h" 52 #include "libaura/dict.h" 53 #include "libdfui/system.h" 54 55 #include "confed.h" 56 #include "commands.h" 57 #include "functions.h" 58 59 /* 60 * Create a new, empty set of in-memory config variable settings. 61 */ 62 struct config_vars * 63 config_vars_new(void) 64 { 65 struct config_vars *cvs; 66 67 AURA_MALLOC(cvs, config_vars); 68 69 cvs->d = aura_dict_new(1, AURA_DICT_SORTED_LIST); 70 71 return(cvs); 72 } 73 74 /* 75 * Deallocate the memory used by a set of config variable settings. 76 */ 77 void 78 config_vars_free(struct config_vars *cvs) 79 { 80 if (cvs == NULL) 81 return; 82 83 aura_dict_free(cvs->d); 84 85 AURA_FREE(cvs, config_vars); 86 } 87 88 /* 89 * Get the value of a configuration variable in a set of settings 90 * and return it, or a (constant) 0-length string if not found. 91 */ 92 const char * 93 config_var_get(const struct config_vars *cvs, const char *name) 94 { 95 void *rv; 96 size_t rv_len; 97 98 aura_dict_fetch(cvs->d, name, strlen(name) + 1, &rv, &rv_len); 99 if (rv == NULL) 100 return(""); 101 else 102 return(rv); 103 } 104 105 /* 106 * Set the value of a configuration variable. If the named variable 107 * does not exist within the given set, a new one is created. 108 */ 109 int 110 config_var_set(struct config_vars *cvs, const char *name, const char *value) 111 { 112 aura_dict_store(cvs->d, 113 name, strlen(name) + 1, 114 value, strlen(value) + 1); 115 return(1); 116 } 117 118 /* 119 * Write a set of configuration variable settings to a file. 120 */ 121 int 122 config_vars_write(const struct config_vars *cvs, int config_type, const char *fmt, ...) 123 { 124 FILE *f; 125 va_list args; 126 char *filename; 127 char tstr[256]; 128 int conf_written = 0; 129 time_t t; 130 void *rk, *rv; 131 size_t rk_len, rv_len; 132 133 va_start(args, fmt); 134 vasprintf(&filename, fmt, args); 135 va_end(args); 136 137 if ((f = fopen(filename, "a")) == NULL) 138 return(0); 139 140 time(&t); 141 strlcpy(tstr, ctime(&t), 256); 142 if (strlen(tstr) > 0) 143 tstr[strlen(tstr) - 1] = '\0'; 144 145 switch (config_type) { 146 case CONFIG_TYPE_SH: 147 148 aura_dict_rewind(cvs->d); 149 while (!aura_dict_eof(cvs->d)) { 150 if (! conf_written) { 151 conf_written = 1; 152 fprintf(f, "\n"); 153 fprintf(f, "# -- BEGIN %s " 154 "Installer automatically generated " 155 "configuration -- #\n", 156 OPERATING_SYSTEM_NAME); 157 fprintf(f, "# -- Written on %s -- #\n", tstr); 158 } 159 aura_dict_get_current_key(cvs->d, &rk, &rk_len), 160 aura_dict_fetch(cvs->d, rk, rk_len, &rv, &rv_len); 161 fprintf(f, "%s=\"%s\"\n", (char *)rk, (char *)rv); 162 aura_dict_next(cvs->d); 163 } 164 if (conf_written) { 165 fprintf(f, "# -- END of %s Installer " 166 "automatically generated configuration -- #\n", 167 OPERATING_SYSTEM_NAME); 168 } 169 break; 170 case CONFIG_TYPE_RESOLV: 171 aura_dict_rewind(cvs->d); 172 while (!aura_dict_eof(cvs->d)) { 173 aura_dict_get_current_key(cvs->d, &rk, &rk_len), 174 aura_dict_fetch(cvs->d, rk, rk_len, &rv, &rv_len); 175 fprintf(f, "%s\t\t%s\n", (char *)rk, (char *)rv); 176 aura_dict_next(cvs->d); 177 } 178 break; 179 default: 180 fclose(f); 181 return(0); 182 } 183 184 fclose(f); 185 return(1); 186 } 187 188 /* 189 * Read variables from a file. 190 * Returns 1 if the variables could be read successfully, 0 if not. 191 */ 192 int 193 config_vars_read(struct i_fn_args *a, struct config_vars *cvs, 194 int config_type __unused, const char *fmt, ...) 195 { 196 struct commands *cmds; 197 char *filename, *tmp_filename, line[1024], *value; 198 FILE *f, *script; 199 va_list args; 200 201 va_start(args, fmt); 202 vasprintf(&filename, fmt, args); 203 va_end(args); 204 205 asprintf(&tmp_filename, "%sextract_vars", a->tmp); 206 script = fopen(tmp_filename, "w"); 207 free(tmp_filename); 208 if (script == NULL) 209 return(0); 210 211 fprintf(script, "set | %susr/bin/sort >%senv.before\n", a->os_root, a->tmp); 212 fprintf(script, ". %s%s\n", a->os_root, filename); 213 fprintf(script, "set | %susr/bin/sort >%senv.after\n", a->os_root, a->tmp); 214 fprintf(script, "%susr/bin/comm -1 -3 %senv.before %senv.after | \\\n", 215 a->os_root, a->tmp, a->tmp); 216 fprintf(script, " %susr/bin/awk -F= '{ print $1 }' | \\\n", a->os_root); 217 fprintf(script, " while read __VARNAME; do\n"); 218 fprintf(script, " echo -n ${__VARNAME}=\n"); 219 fprintf(script, " eval echo ' $'${__VARNAME}\n"); 220 fprintf(script, " done\n"); 221 fprintf(script, "%sbin/rm -f %senv.before %senv.after\n", 222 a->os_root, a->tmp, a->tmp); 223 fclose(script); 224 225 cmds = commands_new(); 226 command_add(cmds, "%sbin/sh %sextract_vars >%sextracted_vars.txt", 227 a->os_root, a->tmp, a->tmp); 228 temp_file_add(a, "extracted_vars.txt"); 229 if (!commands_execute(a, cmds)) { 230 commands_free(cmds); 231 return(0); 232 } 233 commands_free(cmds); 234 235 /* 236 * Delete the script immediately. 237 */ 238 asprintf(&tmp_filename, "%sextract_vars", a->tmp); 239 (void)unlink(tmp_filename); /* not much we can do if it fails */ 240 free(tmp_filename); 241 242 asprintf(&tmp_filename, "%sextracted_vars.txt", a->tmp); 243 f = fopen(tmp_filename, "r"); 244 free(tmp_filename); 245 if (f == NULL) 246 return(0); 247 while (fgets(line, 1024, f) != NULL) { 248 if (strlen(line) > 0) 249 line[strlen(line) - 1] = '\0'; 250 /* split line at first = */ 251 for (value = line; *value != '=' && *value != '\0'; value++) 252 ; 253 if (*value == '\0') 254 break; 255 *value = '\0'; 256 value++; 257 config_var_set(cvs, line, value); 258 } 259 fclose(f); 260 261 return(1); 262 } 263