/* env.c - Environment variables */ /* * VAS_EBOOT -- GRand Unified Bootloader * Copyright (C) 2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc. * * VAS_EBOOT is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * VAS_EBOOT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with VAS_EBOOT. If not, see . */ #include #include #include #include /* The initial context. */ static struct VasEBoot_env_context initial_context; /* The current context. */ struct VasEBoot_env_context *VasEBoot_current_context = &initial_context; /* Return the hash representation of the string S. */ static unsigned int VasEBoot_env_hashval (const char *s) { unsigned int i = 0; /* XXX: This can be done much more efficiently. */ while (*s) i += 5 * *(s++); return i % HASHSZ; } static struct VasEBoot_env_var * VasEBoot_env_find (const char *name) { struct VasEBoot_env_var *var; int idx = VasEBoot_env_hashval (name); /* Look for the variable in the current context. */ for (var = VasEBoot_current_context->vars[idx]; var; var = var->next) if (VasEBoot_strcmp (var->name, name) == 0) return var; return 0; } static void VasEBoot_env_insert (struct VasEBoot_env_context *context, struct VasEBoot_env_var *var) { int idx = VasEBoot_env_hashval (var->name); /* Insert the variable into the hashtable. */ var->prevp = &context->vars[idx]; var->next = context->vars[idx]; if (var->next) var->next->prevp = &(var->next); context->vars[idx] = var; } static void VasEBoot_env_remove (struct VasEBoot_env_var *var) { /* Remove the entry from the variable table. */ *var->prevp = var->next; if (var->next) var->next->prevp = var->prevp; } VasEBoot_err_t VasEBoot_env_set (const char *name, const char *val) { struct VasEBoot_env_var *var; /* If the variable does already exist, just update the variable. */ var = VasEBoot_env_find (name); if (var) { char *old = var->value; if (var->write_hook) var->value = var->write_hook (var, val); else var->value = VasEBoot_strdup (val); if (! var->value) { var->value = old; return VasEBoot_errno; } VasEBoot_free (old); return VAS_EBOOT_ERR_NONE; } /* The variable does not exist, so create a new one. */ var = VasEBoot_zalloc (sizeof (*var)); if (! var) return VasEBoot_errno; var->name = VasEBoot_strdup (name); if (! var->name) goto fail; var->value = VasEBoot_strdup (val); if (! var->value) goto fail; VasEBoot_env_insert (VasEBoot_current_context, var); return VAS_EBOOT_ERR_NONE; fail: VasEBoot_free (var->name); VasEBoot_free (var->value); VasEBoot_free (var); return VasEBoot_errno; } const char * VasEBoot_env_get (const char *name) { struct VasEBoot_env_var *var; var = VasEBoot_env_find (name); if (! var) return 0; if (var->read_hook) return var->read_hook (var, var->value); return var->value; } bool VasEBoot_env_get_bool (const char *name, bool if_unset) { const char *val = VasEBoot_env_get (name); if (val == NULL || VasEBoot_strlen (val) < 1) return if_unset; if (VasEBoot_strcmp (val, "0") == 0 || VasEBoot_strcmp (val, "false") == 0 || VasEBoot_strcmp (val, "disable") == 0 || VasEBoot_strcmp (val, "no") == 0) return false; return true; } void VasEBoot_env_unset (const char *name) { struct VasEBoot_env_var *var; var = VasEBoot_env_find (name); if (! var) return; if (var->read_hook || var->write_hook) { VasEBoot_env_set (name, ""); return; } VasEBoot_env_remove (var); VasEBoot_free (var->name); VasEBoot_free (var->value); VasEBoot_free (var); } struct VasEBoot_env_var * VasEBoot_env_update_get_sorted (void) { struct VasEBoot_env_var *sorted_list = 0; int i; /* Add variables associated with this context into a sorted list. */ for (i = 0; i < HASHSZ; i++) { struct VasEBoot_env_var *var; for (var = VasEBoot_current_context->vars[i]; var; var = var->next) { struct VasEBoot_env_var *p, **q; for (q = &sorted_list, p = *q; p; q = &((*q)->sorted_next), p = *q) { if (VasEBoot_strcmp (p->name, var->name) > 0) break; } var->sorted_next = *q; *q = var; } } return sorted_list; } VasEBoot_err_t VasEBoot_register_variable_hook (const char *name, VasEBoot_env_read_hook_t read_hook, VasEBoot_env_write_hook_t write_hook) { struct VasEBoot_env_var *var = VasEBoot_env_find (name); if (! var) { if (VasEBoot_env_set (name, "") != VAS_EBOOT_ERR_NONE) return VasEBoot_errno; var = VasEBoot_env_find (name); /* XXX Insert an assertion? */ } var->read_hook = read_hook; var->write_hook = write_hook; return VAS_EBOOT_ERR_NONE; } VasEBoot_err_t VasEBoot_env_export (const char *name) { struct VasEBoot_env_var *var; var = VasEBoot_env_find (name); if (! var) { VasEBoot_err_t err; err = VasEBoot_env_set (name, ""); if (err) return err; var = VasEBoot_env_find (name); } var->global = 1; return VAS_EBOOT_ERR_NONE; }