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 * functions.c 36 * Generic functions for installer. 37 * $Id: functions.c,v 1.22 2005/02/06 21:05:18 cpressey Exp $ 38 */ 39 40 #include <ctype.h> 41 #include <stdio.h> 42 #include <stdarg.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <unistd.h> 46 47 #include "libaura/mem.h" 48 #include "libaura/dict.h" 49 50 #include "libdfui/dfui.h" 51 52 #include "functions.h" 53 #include "diskutil.h" 54 #include "uiutil.h" 55 56 /*** INSTALLER CONTEXT CONSTRUCTOR ***/ 57 58 struct i_fn_args * 59 i_fn_args_new(const char *os_root, const char *def_tmp_dir, int transport, const char *rendezvous) 60 { 61 struct i_fn_args *a; 62 char *filename; 63 64 AURA_MALLOC(a, i_fn_args); 65 66 a->c = NULL; 67 a->os_root = aura_strdup(os_root); 68 a->cfg_root = ""; 69 a->name = ""; 70 a->short_desc = ""; 71 a->long_desc = ""; 72 a->result = 0; 73 a->log = NULL; 74 a->s = NULL; 75 a->tmp = NULL; 76 a->temp_files = NULL; 77 a->cmd_names = NULL; 78 79 asprintf(&filename, "%sinstall.log", def_tmp_dir); 80 a->log = fopen(filename, "w"); 81 free(filename); 82 if (a->log == NULL) { 83 i_fn_args_free(a); 84 return(NULL); 85 } 86 87 i_log(a, "Installer started"); 88 i_log(a, "-----------------"); 89 90 i_log(a, "+ Creating DFUI connection on ``%s''\n", rendezvous); 91 92 if ((a->c = dfui_connection_new(transport, rendezvous)) == NULL) { 93 i_log(a, "! ERROR: Couldn't create connection on ``%s''\n", rendezvous); 94 i_fn_args_free(a); 95 return(NULL); 96 } 97 98 i_log(a, "+ Connecting on ``%s''\n", rendezvous); 99 100 if (!dfui_be_start(a->c)) { 101 i_log(a, "! ERROR: Couldn't connect to frontend on ``%s''\n", rendezvous); 102 i_fn_args_free(a); 103 return(NULL); 104 } 105 106 if ((a->s = storage_new()) == NULL) { 107 i_log(a, "! ERROR: Couldn't create storage descriptor"); 108 i_fn_args_free(a); 109 return(NULL); 110 } 111 112 a->tmp = def_tmp_dir; /* XXX temporarily set to this */ 113 a->temp_files = aura_dict_new(23, AURA_DICT_HASH); 114 a->cmd_names = config_vars_new(); 115 if (!config_vars_read(a, a->cmd_names, CONFIG_TYPE_SH, 116 "usr/share/installer/cmdnames.conf")) { 117 i_log(a, "! ERROR: Couldn't read cmdnames config file"); 118 i_fn_args_free(a); 119 return(NULL); 120 } 121 122 a->tmp = cmd_name(a, "INSTALLER_TEMP"); 123 124 i_log(a, "+ Starting installer state machine"); 125 126 return(a); 127 } 128 129 void 130 i_fn_args_free(struct i_fn_args *a) 131 { 132 if (a != NULL) { 133 if (a->temp_files != NULL) { 134 temp_files_clean(a); 135 aura_dict_free(a->temp_files); 136 } 137 if (a->cmd_names != NULL) { 138 config_vars_free(a->cmd_names); 139 } 140 if (a->s != NULL) { 141 storage_free(a->s); 142 } 143 if (a->c != NULL) { 144 dfui_be_stop(a->c); 145 } 146 if (a->log != NULL) { 147 fclose(a->log); 148 } 149 AURA_FREE(a, i_fn_args); 150 } 151 } 152 153 /*** INSTALLER CONTEXT FUNCTIONS ***/ 154 155 void 156 i_log(struct i_fn_args *a, const char *fmt, ...) 157 { 158 va_list args; 159 160 va_start(args, fmt); 161 vfprintf(stderr, fmt, args); 162 fprintf(stderr, "\n"); 163 va_end(args); 164 if (a->log != NULL) { 165 va_start(args, fmt); 166 vfprintf(a->log, fmt, args); 167 fprintf(a->log, "\n"); 168 fflush(a->log); 169 va_end(args); 170 } 171 va_end(args); 172 } 173 174 /*** UTILITY ***/ 175 176 void 177 abort_backend(void) 178 { 179 exit(1); 180 } 181 182 int 183 assert_clean(struct dfui_connection *c, const char *name, const char *field, 184 const char *not_allowed) 185 { 186 if (strpbrk(field, not_allowed) != NULL) { 187 inform(c, "The %s field may not contain any of the " 188 "following characters:\n\n%s", 189 name, not_allowed); 190 return(0); 191 } else { 192 return(1); 193 } 194 } 195 196 /* 197 * Expects a leading 0x. 198 */ 199 int 200 hex_to_int(const char *hex, int *result) 201 { 202 int i, a = 0; 203 char d; 204 205 if (strncmp(hex, "0x", 2) != 0) 206 return(0); 207 208 for (i = 2; hex[i] != '\0'; i++) { 209 d = toupper(hex[i]); 210 if (isspace(d)) 211 continue; 212 if (isdigit(d)) 213 a = a * 16 + (d - '0'); 214 else if (d >= 'A' && d <= 'F') 215 a = a * 16 + (d + 10 - 'A'); 216 else 217 return(0); 218 } 219 220 *result = a; 221 return(1); 222 } 223 224 int 225 first_non_space_char_is(const char *line, char x) 226 { 227 int i; 228 229 for (i = 0; line[i] != '\0'; i++) { 230 if (isspace(line[i])) 231 continue; 232 if (line[i] == x) 233 return(1); 234 return(0); 235 } 236 237 return(0); 238 } 239 240 const char * 241 capacity_to_string(long capacity) 242 { 243 static char string[256]; 244 245 if (capacity < 0) 246 strlcpy(string, "*", 2); 247 else 248 snprintf(string, 255, "%ldM", capacity); 249 250 return(string); 251 } 252 253 int 254 string_to_capacity(const char *string, long *capacity) 255 { 256 char unit; 257 258 unit = string[strlen(string) - 1]; 259 if (!strcmp(string, "*")) { 260 *capacity = -1; 261 return(1); 262 } else if (unit == 'm' || unit == 'M') { 263 *capacity = strtol(string, NULL, 10); 264 return(1); 265 } else if (unit == 'g' || unit == 'G') { 266 *capacity = strtol(string, NULL, 10) * 1024; 267 return(1); 268 } else { 269 return(0); 270 } 271 } 272 273 /* 274 * Round a number up to the nearest power of two. 275 */ 276 unsigned long 277 next_power_of_two(unsigned long n) 278 { 279 unsigned long p, op; 280 281 p = 1; 282 op = 0; 283 while (p < n && p > op) { 284 op = p; 285 p <<= 1; 286 } 287 288 return(p > op ? p : n); 289 } 290 291 /* 292 * Returns file name without extension. 293 * e.g. 294 * ru.koi8-r.kbd -> ru.koi8-r 295 * README -> README 296 * 297 * Caller is responsible for freeing the string returned. 298 */ 299 char * 300 filename_noext(const char *filename) 301 { 302 int i; 303 char *buffer, *p; 304 305 buffer = aura_strdup(filename); 306 307 if (strlen(filename) == 0) { 308 buffer[0] = '\0'; 309 return(buffer); 310 } 311 312 p = strrchr(filename, '.'); 313 314 if (p != NULL) { 315 i = strlen(filename) - strlen(p); 316 buffer[i] = 0; 317 } 318 319 return(buffer); 320 } 321 322 /* 323 * Temp files 324 */ 325 326 int 327 temp_file_add(struct i_fn_args *a, const char *filename) 328 { 329 aura_dict_store(a->temp_files, filename, strlen(filename) + 1, "", 1); 330 return(1); 331 } 332 333 int 334 temp_files_clean(struct i_fn_args *a) 335 { 336 void *rk; 337 size_t rk_len; 338 char *filename; 339 340 aura_dict_rewind(a->temp_files); 341 while (!aura_dict_eof(a->temp_files)) { 342 aura_dict_get_current_key(a->temp_files, &rk, &rk_len); 343 asprintf(&filename, "%s%s", a->tmp, (char *)rk); 344 (void)unlink(filename); /* not much we can do if it fails */ 345 free(filename); 346 aura_dict_next(a->temp_files); 347 } 348 return(1); 349 } 350 351 /* 352 * Command names 353 */ 354 const char * 355 cmd_name(const struct i_fn_args *a, const char *cmd_key) 356 { 357 const char *name; 358 359 name = config_var_get(a->cmd_names, cmd_key); 360 if (strcmp(name, "") == 0) 361 return("bin/echo"); /* XXX usr/local/sbin/error? */ 362 else 363 return(name); 364 } 365