121c1c48aSSascha Wildner /* 221c1c48aSSascha Wildner * Copyright (c)2004 The DragonFly Project. All rights reserved. 321c1c48aSSascha Wildner * 421c1c48aSSascha Wildner * Redistribution and use in source and binary forms, with or without 521c1c48aSSascha Wildner * modification, are permitted provided that the following conditions 621c1c48aSSascha Wildner * are met: 721c1c48aSSascha Wildner * 821c1c48aSSascha Wildner * Redistributions of source code must retain the above copyright 921c1c48aSSascha Wildner * notice, this list of conditions and the following disclaimer. 1021c1c48aSSascha Wildner * 1121c1c48aSSascha Wildner * Redistributions in binary form must reproduce the above copyright 1221c1c48aSSascha Wildner * notice, this list of conditions and the following disclaimer in 1321c1c48aSSascha Wildner * the documentation and/or other materials provided with the 1421c1c48aSSascha Wildner * distribution. 1521c1c48aSSascha Wildner * 1621c1c48aSSascha Wildner * Neither the name of the DragonFly Project nor the names of its 1721c1c48aSSascha Wildner * contributors may be used to endorse or promote products derived 1821c1c48aSSascha Wildner * from this software without specific prior written permission. 1921c1c48aSSascha Wildner * 2021c1c48aSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2121c1c48aSSascha Wildner * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2221c1c48aSSascha Wildner * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 2321c1c48aSSascha Wildner * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 2421c1c48aSSascha Wildner * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 2521c1c48aSSascha Wildner * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2621c1c48aSSascha Wildner * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2721c1c48aSSascha Wildner * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2821c1c48aSSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 2921c1c48aSSascha Wildner * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3021c1c48aSSascha Wildner * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 3121c1c48aSSascha Wildner * OF THE POSSIBILITY OF SUCH DAMAGE. 3221c1c48aSSascha Wildner */ 3321c1c48aSSascha Wildner 3421c1c48aSSascha Wildner /* 3521c1c48aSSascha Wildner * functions.c 3621c1c48aSSascha Wildner * Generic functions for installer. 3721c1c48aSSascha Wildner * $Id: functions.c,v 1.22 2005/02/06 21:05:18 cpressey Exp $ 3821c1c48aSSascha Wildner */ 3921c1c48aSSascha Wildner 4021c1c48aSSascha Wildner #include <ctype.h> 4121c1c48aSSascha Wildner #include <stdio.h> 4221c1c48aSSascha Wildner #include <stdarg.h> 4321c1c48aSSascha Wildner #include <stdlib.h> 4421c1c48aSSascha Wildner #include <string.h> 4521c1c48aSSascha Wildner #include <unistd.h> 46*1f2824e8SSascha Wildner #include <libutil.h> 4721c1c48aSSascha Wildner 4821c1c48aSSascha Wildner #include "libaura/mem.h" 4921c1c48aSSascha Wildner #include "libaura/dict.h" 5021c1c48aSSascha Wildner 5121c1c48aSSascha Wildner #include "libdfui/dfui.h" 5221c1c48aSSascha Wildner 5321c1c48aSSascha Wildner #include "functions.h" 5421c1c48aSSascha Wildner #include "diskutil.h" 5521c1c48aSSascha Wildner #include "uiutil.h" 5621c1c48aSSascha Wildner 5721c1c48aSSascha Wildner /*** INSTALLER CONTEXT CONSTRUCTOR ***/ 5821c1c48aSSascha Wildner 5921c1c48aSSascha Wildner struct i_fn_args * 6021c1c48aSSascha Wildner i_fn_args_new(const char *os_root, const char *def_tmp_dir, int transport, const char *rendezvous) 6121c1c48aSSascha Wildner { 6221c1c48aSSascha Wildner struct i_fn_args *a; 6321c1c48aSSascha Wildner char *filename; 6421c1c48aSSascha Wildner 6521c1c48aSSascha Wildner AURA_MALLOC(a, i_fn_args); 6621c1c48aSSascha Wildner 6721c1c48aSSascha Wildner a->c = NULL; 6821c1c48aSSascha Wildner a->os_root = aura_strdup(os_root); 6921c1c48aSSascha Wildner a->cfg_root = ""; 7021c1c48aSSascha Wildner a->name = ""; 7121c1c48aSSascha Wildner a->short_desc = ""; 7221c1c48aSSascha Wildner a->long_desc = ""; 7321c1c48aSSascha Wildner a->result = 0; 7421c1c48aSSascha Wildner a->log = NULL; 7521c1c48aSSascha Wildner a->s = NULL; 7621c1c48aSSascha Wildner a->tmp = NULL; 7721c1c48aSSascha Wildner a->temp_files = NULL; 7821c1c48aSSascha Wildner a->cmd_names = NULL; 7921c1c48aSSascha Wildner 8021c1c48aSSascha Wildner asprintf(&filename, "%sinstall.log", def_tmp_dir); 8121c1c48aSSascha Wildner a->log = fopen(filename, "w"); 8221c1c48aSSascha Wildner free(filename); 8321c1c48aSSascha Wildner if (a->log == NULL) { 8421c1c48aSSascha Wildner i_fn_args_free(a); 8521c1c48aSSascha Wildner return(NULL); 8621c1c48aSSascha Wildner } 8721c1c48aSSascha Wildner 8821c1c48aSSascha Wildner i_log(a, "Installer started"); 8921c1c48aSSascha Wildner i_log(a, "-----------------"); 9021c1c48aSSascha Wildner 9121c1c48aSSascha Wildner i_log(a, "+ Creating DFUI connection on ``%s''\n", rendezvous); 9221c1c48aSSascha Wildner 9321c1c48aSSascha Wildner if ((a->c = dfui_connection_new(transport, rendezvous)) == NULL) { 9421c1c48aSSascha Wildner i_log(a, "! ERROR: Couldn't create connection on ``%s''\n", rendezvous); 9521c1c48aSSascha Wildner i_fn_args_free(a); 9621c1c48aSSascha Wildner return(NULL); 9721c1c48aSSascha Wildner } 9821c1c48aSSascha Wildner 9921c1c48aSSascha Wildner i_log(a, "+ Connecting on ``%s''\n", rendezvous); 10021c1c48aSSascha Wildner 10121c1c48aSSascha Wildner if (!dfui_be_start(a->c)) { 10221c1c48aSSascha Wildner i_log(a, "! ERROR: Couldn't connect to frontend on ``%s''\n", rendezvous); 10321c1c48aSSascha Wildner i_fn_args_free(a); 10421c1c48aSSascha Wildner return(NULL); 10521c1c48aSSascha Wildner } 10621c1c48aSSascha Wildner 10721c1c48aSSascha Wildner if ((a->s = storage_new()) == NULL) { 10821c1c48aSSascha Wildner i_log(a, "! ERROR: Couldn't create storage descriptor"); 10921c1c48aSSascha Wildner i_fn_args_free(a); 11021c1c48aSSascha Wildner return(NULL); 11121c1c48aSSascha Wildner } 11221c1c48aSSascha Wildner 11321c1c48aSSascha Wildner a->tmp = def_tmp_dir; /* XXX temporarily set to this */ 11421c1c48aSSascha Wildner a->temp_files = aura_dict_new(23, AURA_DICT_HASH); 11521c1c48aSSascha Wildner a->cmd_names = config_vars_new(); 11621c1c48aSSascha Wildner if (!config_vars_read(a, a->cmd_names, CONFIG_TYPE_SH, 11721c1c48aSSascha Wildner "usr/share/installer/cmdnames.conf")) { 11821c1c48aSSascha Wildner i_log(a, "! ERROR: Couldn't read cmdnames config file"); 11921c1c48aSSascha Wildner i_fn_args_free(a); 12021c1c48aSSascha Wildner return(NULL); 12121c1c48aSSascha Wildner } 12221c1c48aSSascha Wildner 12321c1c48aSSascha Wildner a->tmp = cmd_name(a, "INSTALLER_TEMP"); 12421c1c48aSSascha Wildner 12521c1c48aSSascha Wildner i_log(a, "+ Starting installer state machine"); 12621c1c48aSSascha Wildner 12721c1c48aSSascha Wildner return(a); 12821c1c48aSSascha Wildner } 12921c1c48aSSascha Wildner 13021c1c48aSSascha Wildner void 13121c1c48aSSascha Wildner i_fn_args_free(struct i_fn_args *a) 13221c1c48aSSascha Wildner { 13321c1c48aSSascha Wildner if (a != NULL) { 13421c1c48aSSascha Wildner if (a->temp_files != NULL) { 13521c1c48aSSascha Wildner temp_files_clean(a); 13621c1c48aSSascha Wildner aura_dict_free(a->temp_files); 13721c1c48aSSascha Wildner } 13821c1c48aSSascha Wildner if (a->cmd_names != NULL) { 13921c1c48aSSascha Wildner config_vars_free(a->cmd_names); 14021c1c48aSSascha Wildner } 14121c1c48aSSascha Wildner if (a->s != NULL) { 14221c1c48aSSascha Wildner storage_free(a->s); 14321c1c48aSSascha Wildner } 14421c1c48aSSascha Wildner if (a->c != NULL) { 14521c1c48aSSascha Wildner dfui_be_stop(a->c); 14621c1c48aSSascha Wildner } 14721c1c48aSSascha Wildner if (a->log != NULL) { 14821c1c48aSSascha Wildner fclose(a->log); 14921c1c48aSSascha Wildner } 15021c1c48aSSascha Wildner AURA_FREE(a, i_fn_args); 15121c1c48aSSascha Wildner } 15221c1c48aSSascha Wildner } 15321c1c48aSSascha Wildner 15421c1c48aSSascha Wildner /*** INSTALLER CONTEXT FUNCTIONS ***/ 15521c1c48aSSascha Wildner 15621c1c48aSSascha Wildner void 15721c1c48aSSascha Wildner i_log(struct i_fn_args *a, const char *fmt, ...) 15821c1c48aSSascha Wildner { 15921c1c48aSSascha Wildner va_list args; 16021c1c48aSSascha Wildner 16121c1c48aSSascha Wildner va_start(args, fmt); 16221c1c48aSSascha Wildner vfprintf(stderr, fmt, args); 16321c1c48aSSascha Wildner fprintf(stderr, "\n"); 164c9ae658bSAntonio Huete va_end(args); 16521c1c48aSSascha Wildner if (a->log != NULL) { 166c9ae658bSAntonio Huete va_start(args, fmt); 16721c1c48aSSascha Wildner vfprintf(a->log, fmt, args); 16821c1c48aSSascha Wildner fprintf(a->log, "\n"); 16921c1c48aSSascha Wildner fflush(a->log); 170c9ae658bSAntonio Huete va_end(args); 17121c1c48aSSascha Wildner } 17221c1c48aSSascha Wildner va_end(args); 17321c1c48aSSascha Wildner } 17421c1c48aSSascha Wildner 17521c1c48aSSascha Wildner /*** UTILITY ***/ 17621c1c48aSSascha Wildner 17721c1c48aSSascha Wildner void 17821c1c48aSSascha Wildner abort_backend(void) 17921c1c48aSSascha Wildner { 18021c1c48aSSascha Wildner exit(1); 18121c1c48aSSascha Wildner } 18221c1c48aSSascha Wildner 18321c1c48aSSascha Wildner int 18421c1c48aSSascha Wildner assert_clean(struct dfui_connection *c, const char *name, const char *field, 18521c1c48aSSascha Wildner const char *not_allowed) 18621c1c48aSSascha Wildner { 18721c1c48aSSascha Wildner if (strpbrk(field, not_allowed) != NULL) { 18821c1c48aSSascha Wildner inform(c, "The %s field may not contain any of the " 18921c1c48aSSascha Wildner "following characters:\n\n%s", 19021c1c48aSSascha Wildner name, not_allowed); 19121c1c48aSSascha Wildner return(0); 19221c1c48aSSascha Wildner } else { 19321c1c48aSSascha Wildner return(1); 19421c1c48aSSascha Wildner } 19521c1c48aSSascha Wildner } 19621c1c48aSSascha Wildner 19721c1c48aSSascha Wildner /* 19821c1c48aSSascha Wildner * Expects a leading 0x. 19921c1c48aSSascha Wildner */ 20021c1c48aSSascha Wildner int 20121c1c48aSSascha Wildner hex_to_int(const char *hex, int *result) 20221c1c48aSSascha Wildner { 20321c1c48aSSascha Wildner int i, a = 0; 20421c1c48aSSascha Wildner char d; 20521c1c48aSSascha Wildner 20621c1c48aSSascha Wildner if (strncmp(hex, "0x", 2) != 0) 20721c1c48aSSascha Wildner return(0); 20821c1c48aSSascha Wildner 20921c1c48aSSascha Wildner for (i = 2; hex[i] != '\0'; i++) { 21021c1c48aSSascha Wildner d = toupper(hex[i]); 21121c1c48aSSascha Wildner if (isspace(d)) 21221c1c48aSSascha Wildner continue; 21321c1c48aSSascha Wildner if (isdigit(d)) 21421c1c48aSSascha Wildner a = a * 16 + (d - '0'); 21521c1c48aSSascha Wildner else if (d >= 'A' && d <= 'F') 21621c1c48aSSascha Wildner a = a * 16 + (d + 10 - 'A'); 21721c1c48aSSascha Wildner else 21821c1c48aSSascha Wildner return(0); 21921c1c48aSSascha Wildner } 22021c1c48aSSascha Wildner 22121c1c48aSSascha Wildner *result = a; 22221c1c48aSSascha Wildner return(1); 22321c1c48aSSascha Wildner } 22421c1c48aSSascha Wildner 22521c1c48aSSascha Wildner int 22621c1c48aSSascha Wildner first_non_space_char_is(const char *line, char x) 22721c1c48aSSascha Wildner { 22821c1c48aSSascha Wildner int i; 22921c1c48aSSascha Wildner 23021c1c48aSSascha Wildner for (i = 0; line[i] != '\0'; i++) { 23121c1c48aSSascha Wildner if (isspace(line[i])) 23221c1c48aSSascha Wildner continue; 23321c1c48aSSascha Wildner if (line[i] == x) 23421c1c48aSSascha Wildner return(1); 23521c1c48aSSascha Wildner return(0); 23621c1c48aSSascha Wildner } 23721c1c48aSSascha Wildner 23821c1c48aSSascha Wildner return(0); 23921c1c48aSSascha Wildner } 24021c1c48aSSascha Wildner 24121c1c48aSSascha Wildner const char * 24221c1c48aSSascha Wildner capacity_to_string(long capacity) 24321c1c48aSSascha Wildner { 244*1f2824e8SSascha Wildner static char string[6]; 24521c1c48aSSascha Wildner 24621c1c48aSSascha Wildner if (capacity < 0) 24721c1c48aSSascha Wildner strlcpy(string, "*", 2); 24821c1c48aSSascha Wildner else 249*1f2824e8SSascha Wildner humanize_number(string, sizeof(string), capacity << 20, "", 250*1f2824e8SSascha Wildner HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 25121c1c48aSSascha Wildner 25221c1c48aSSascha Wildner return(string); 25321c1c48aSSascha Wildner } 25421c1c48aSSascha Wildner 25521c1c48aSSascha Wildner int 25621c1c48aSSascha Wildner string_to_capacity(const char *string, long *capacity) 25721c1c48aSSascha Wildner { 258*1f2824e8SSascha Wildner int error; 259*1f2824e8SSascha Wildner int64_t result; 26021c1c48aSSascha Wildner 26121c1c48aSSascha Wildner if (!strcmp(string, "*")) { 26221c1c48aSSascha Wildner *capacity = -1; 26321c1c48aSSascha Wildner return(1); 26421c1c48aSSascha Wildner } 265*1f2824e8SSascha Wildner error = dehumanize_number(string, &result); 266*1f2824e8SSascha Wildner if (error != 0) 267*1f2824e8SSascha Wildner return(0); 268*1f2824e8SSascha Wildner result >>= 20; 269*1f2824e8SSascha Wildner if (result == 0) 270*1f2824e8SSascha Wildner return(0); 271*1f2824e8SSascha Wildner *capacity = result; 272*1f2824e8SSascha Wildner return(1); 27321c1c48aSSascha Wildner } 27421c1c48aSSascha Wildner 27521c1c48aSSascha Wildner /* 27621c1c48aSSascha Wildner * Round a number up to the nearest power of two. 27721c1c48aSSascha Wildner */ 27821c1c48aSSascha Wildner unsigned long 27921c1c48aSSascha Wildner next_power_of_two(unsigned long n) 28021c1c48aSSascha Wildner { 28121c1c48aSSascha Wildner unsigned long p, op; 28221c1c48aSSascha Wildner 28321c1c48aSSascha Wildner p = 1; 28421c1c48aSSascha Wildner op = 0; 28521c1c48aSSascha Wildner while (p < n && p > op) { 28621c1c48aSSascha Wildner op = p; 28721c1c48aSSascha Wildner p <<= 1; 28821c1c48aSSascha Wildner } 28921c1c48aSSascha Wildner 29021c1c48aSSascha Wildner return(p > op ? p : n); 29121c1c48aSSascha Wildner } 29221c1c48aSSascha Wildner 29321c1c48aSSascha Wildner /* 29421c1c48aSSascha Wildner * Returns file name without extension. 29521c1c48aSSascha Wildner * e.g. 29621c1c48aSSascha Wildner * ru.koi8-r.kbd -> ru.koi8-r 29721c1c48aSSascha Wildner * README -> README 29821c1c48aSSascha Wildner * 29921c1c48aSSascha Wildner * Caller is responsible for freeing the string returned. 30021c1c48aSSascha Wildner */ 30121c1c48aSSascha Wildner char * 30221c1c48aSSascha Wildner filename_noext(const char *filename) 30321c1c48aSSascha Wildner { 30421c1c48aSSascha Wildner int i; 30521c1c48aSSascha Wildner char *buffer, *p; 30621c1c48aSSascha Wildner 30721c1c48aSSascha Wildner buffer = aura_strdup(filename); 30821c1c48aSSascha Wildner 30921c1c48aSSascha Wildner if (strlen(filename) == 0) { 31021c1c48aSSascha Wildner buffer[0] = '\0'; 31121c1c48aSSascha Wildner return(buffer); 31221c1c48aSSascha Wildner } 31321c1c48aSSascha Wildner 31421c1c48aSSascha Wildner p = strrchr(filename, '.'); 31521c1c48aSSascha Wildner 31621c1c48aSSascha Wildner if (p != NULL) { 31721c1c48aSSascha Wildner i = strlen(filename) - strlen(p); 31821c1c48aSSascha Wildner buffer[i] = 0; 31921c1c48aSSascha Wildner } 32021c1c48aSSascha Wildner 32121c1c48aSSascha Wildner return(buffer); 32221c1c48aSSascha Wildner } 32321c1c48aSSascha Wildner 32421c1c48aSSascha Wildner /* 32521c1c48aSSascha Wildner * Temp files 32621c1c48aSSascha Wildner */ 32721c1c48aSSascha Wildner 32821c1c48aSSascha Wildner int 32921c1c48aSSascha Wildner temp_file_add(struct i_fn_args *a, const char *filename) 33021c1c48aSSascha Wildner { 33121c1c48aSSascha Wildner aura_dict_store(a->temp_files, filename, strlen(filename) + 1, "", 1); 33221c1c48aSSascha Wildner return(1); 33321c1c48aSSascha Wildner } 33421c1c48aSSascha Wildner 33521c1c48aSSascha Wildner int 33621c1c48aSSascha Wildner temp_files_clean(struct i_fn_args *a) 33721c1c48aSSascha Wildner { 33821c1c48aSSascha Wildner void *rk; 33921c1c48aSSascha Wildner size_t rk_len; 34021c1c48aSSascha Wildner char *filename; 34121c1c48aSSascha Wildner 34221c1c48aSSascha Wildner aura_dict_rewind(a->temp_files); 34321c1c48aSSascha Wildner while (!aura_dict_eof(a->temp_files)) { 34421c1c48aSSascha Wildner aura_dict_get_current_key(a->temp_files, &rk, &rk_len); 34521c1c48aSSascha Wildner asprintf(&filename, "%s%s", a->tmp, (char *)rk); 34621c1c48aSSascha Wildner (void)unlink(filename); /* not much we can do if it fails */ 34721c1c48aSSascha Wildner free(filename); 34821c1c48aSSascha Wildner aura_dict_next(a->temp_files); 34921c1c48aSSascha Wildner } 35021c1c48aSSascha Wildner return(1); 35121c1c48aSSascha Wildner } 35221c1c48aSSascha Wildner 35321c1c48aSSascha Wildner /* 35421c1c48aSSascha Wildner * Command names 35521c1c48aSSascha Wildner */ 35621c1c48aSSascha Wildner const char * 35721c1c48aSSascha Wildner cmd_name(const struct i_fn_args *a, const char *cmd_key) 35821c1c48aSSascha Wildner { 35921c1c48aSSascha Wildner const char *name; 36021c1c48aSSascha Wildner 36121c1c48aSSascha Wildner name = config_var_get(a->cmd_names, cmd_key); 36221c1c48aSSascha Wildner if (strcmp(name, "") == 0) 36321c1c48aSSascha Wildner return("bin/echo"); /* XXX usr/local/sbin/error? */ 36421c1c48aSSascha Wildner else 36521c1c48aSSascha Wildner return(name); 36621c1c48aSSascha Wildner } 367