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