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