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 if (a->log != NULL) { 164 vfprintf(a->log, fmt, args); 165 fprintf(a->log, "\n"); 166 fflush(a->log); 167 } 168 va_end(args); 169 } 170 171 /*** UTILITY ***/ 172 173 void 174 abort_backend(void) 175 { 176 exit(1); 177 } 178 179 int 180 assert_clean(struct dfui_connection *c, const char *name, const char *field, 181 const char *not_allowed) 182 { 183 if (strpbrk(field, not_allowed) != NULL) { 184 inform(c, "The %s field may not contain any of the " 185 "following characters:\n\n%s", 186 name, not_allowed); 187 return(0); 188 } else { 189 return(1); 190 } 191 } 192 193 /* 194 * Expects a leading 0x. 195 */ 196 int 197 hex_to_int(const char *hex, int *result) 198 { 199 int i, a = 0; 200 char d; 201 202 if (strncmp(hex, "0x", 2) != 0) 203 return(0); 204 205 for (i = 2; hex[i] != '\0'; i++) { 206 d = toupper(hex[i]); 207 if (isspace(d)) 208 continue; 209 if (isdigit(d)) 210 a = a * 16 + (d - '0'); 211 else if (d >= 'A' && d <= 'F') 212 a = a * 16 + (d + 10 - 'A'); 213 else 214 return(0); 215 } 216 217 *result = a; 218 return(1); 219 } 220 221 int 222 first_non_space_char_is(const char *line, char x) 223 { 224 int i; 225 226 for (i = 0; line[i] != '\0'; i++) { 227 if (isspace(line[i])) 228 continue; 229 if (line[i] == x) 230 return(1); 231 return(0); 232 } 233 234 return(0); 235 } 236 237 const char * 238 capacity_to_string(long capacity) 239 { 240 static char string[256]; 241 242 if (capacity < 0) 243 strlcpy(string, "*", 2); 244 else 245 snprintf(string, 255, "%ldM", capacity); 246 247 return(string); 248 } 249 250 int 251 string_to_capacity(const char *string, long *capacity) 252 { 253 char unit; 254 255 unit = string[strlen(string) - 1]; 256 if (!strcmp(string, "*")) { 257 *capacity = -1; 258 return(1); 259 } else if (unit == 'm' || unit == 'M') { 260 *capacity = strtol(string, NULL, 10); 261 return(1); 262 } else if (unit == 'g' || unit == 'G') { 263 *capacity = strtol(string, NULL, 10) * 1024; 264 return(1); 265 } else { 266 return(0); 267 } 268 } 269 270 /* 271 * Round a number up to the nearest power of two. 272 */ 273 unsigned long 274 next_power_of_two(unsigned long n) 275 { 276 unsigned long p, op; 277 278 p = 1; 279 op = 0; 280 while (p < n && p > op) { 281 op = p; 282 p <<= 1; 283 } 284 285 return(p > op ? p : n); 286 } 287 288 /* 289 * Returns file name without extension. 290 * e.g. 291 * ru.koi8-r.kbd -> ru.koi8-r 292 * README -> README 293 * 294 * Caller is responsible for freeing the string returned. 295 */ 296 char * 297 filename_noext(const char *filename) 298 { 299 int i; 300 char *buffer, *p; 301 302 buffer = aura_strdup(filename); 303 304 if (strlen(filename) == 0) { 305 buffer[0] = '\0'; 306 return(buffer); 307 } 308 309 p = strrchr(filename, '.'); 310 311 if (p != NULL) { 312 i = strlen(filename) - strlen(p); 313 buffer[i] = 0; 314 } 315 316 return(buffer); 317 } 318 319 /* 320 * Temp files 321 */ 322 323 int 324 temp_file_add(struct i_fn_args *a, const char *filename) 325 { 326 aura_dict_store(a->temp_files, filename, strlen(filename) + 1, "", 1); 327 return(1); 328 } 329 330 int 331 temp_files_clean(struct i_fn_args *a) 332 { 333 void *rk; 334 size_t rk_len; 335 char *filename; 336 337 aura_dict_rewind(a->temp_files); 338 while (!aura_dict_eof(a->temp_files)) { 339 aura_dict_get_current_key(a->temp_files, &rk, &rk_len); 340 asprintf(&filename, "%s%s", a->tmp, (char *)rk); 341 (void)unlink(filename); /* not much we can do if it fails */ 342 free(filename); 343 aura_dict_next(a->temp_files); 344 } 345 return(1); 346 } 347 348 /* 349 * Command names 350 */ 351 const char * 352 cmd_name(const struct i_fn_args *a, const char *cmd_key) 353 { 354 const char *name; 355 356 name = config_var_get(a->cmd_names, cmd_key); 357 if (strcmp(name, "") == 0) 358 return("bin/echo"); /* XXX usr/local/sbin/error? */ 359 else 360 return(name); 361 } 362