|
|
|
/*
|
|
|
|
* Debian Installer main menu program.
|
|
|
|
*
|
|
|
|
* Copyright 2000,2004 Joey Hess <joeyh@debian.org>
|
|
|
|
*
|
|
|
|
* This program 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 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "main-menu.h"
|
|
|
|
#include <cdebconf/debconfclient.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <search.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
const int RAISE = 1;
|
|
|
|
const int LOWER = 0;
|
|
|
|
|
|
|
|
di_hash_table *seen_items;
|
|
|
|
di_hash_table *notinstallables;
|
|
|
|
int last_successful_item = -1;
|
|
|
|
|
|
|
|
/* Save default priority, to be able to return to it when we have to lower it */
|
|
|
|
int default_priority = 1;
|
|
|
|
|
|
|
|
/* Save priority set by main-menu to detect priority changes from the user */
|
|
|
|
int local_priority = -1;
|
|
|
|
|
|
|
|
/* Force display of the menu at the current priority */
|
|
|
|
int display_menu = 0;
|
|
|
|
|
|
|
|
static struct debconfclient *debconf;
|
|
|
|
|
|
|
|
static int di_config_package(di_system_package *p,
|
|
|
|
int (*virtfunc)(di_system_package *));
|
|
|
|
|
|
|
|
static void modify_debconf_priority (int raise_or_lower);
|
|
|
|
|
|
|
|
static char *debconf_priorities[] =
|
|
|
|
{
|
|
|
|
"low",
|
|
|
|
"medium",
|
|
|
|
"high",
|
|
|
|
"critical"
|
|
|
|
};
|
|
|
|
|
|
|
|
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
|
|
|
static int debconf_to_pri (char *priority) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (priority)
|
|
|
|
for (i = 0; (size_t)i < ARRAY_SIZE(debconf_priorities); ++i)
|
|
|
|
if (0 == strcmp(priority, debconf_priorities[i]))
|
|
|
|
return i;
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *xasprintf (const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
char *result;
|
|
|
|
|
|
|
|
va_start(args, format);
|
|
|
|
if (vasprintf(&result, format, args) < 0) {
|
|
|
|
if (errno == ENOMEM) {
|
|
|
|
fputs("Out of memory!\n", stderr);
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* qsort comparison function (sort by menu item values, fall back to
|
|
|
|
* lexical sort to resolve ties deterministically).
|
|
|
|
*/
|
|
|
|
int package_array_compare (const void *v1, const void *v2) {
|
|
|
|
di_system_package *p1, *p2;
|
|
|
|
|
|
|
|
p1 = *(di_system_package **)v1;
|
|
|
|
p2 = *(di_system_package **)v2;
|
|
|
|
|
|
|
|
int r = p1->installer_menu_item - p2->installer_menu_item;
|
|
|
|
//di_log(DI_LOG_LEVEL_DEBUG, "menu compare: %s (%i) vs %s (%i): %i",
|
|
|
|
// p1->p.package, p1->installer_menu_item,
|
|
|
|
// p2->p.package, p2->installer_menu_item, r);
|
|
|
|
if (r) return r;
|
|
|
|
return strcmp(p1->p.package, p2->p.package);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void seen_items_key_destroy (void *key)
|
|
|
|
{
|
|
|
|
di_rstring *s = key;
|
|
|
|
di_free(s->string);
|
|
|
|
di_free(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void notinstallables_key_destroy (void *key)
|
|
|
|
{
|
|
|
|
di_rstring *s = key;
|
|
|
|
di_free(s->string);
|
|
|
|
di_free(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
int isdefault(di_system_package *p) {
|
|
|
|
int check;
|
|
|
|
|
|
|
|
check = di_system_dpkg_package_control_file_exec(&p->p, "menutest", 0, NULL);
|
|
|
|
if (check <= 0 || p->p.status == di_package_status_unpacked || p->p.status == di_package_status_half_configured)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Menu items with a number equal to 99999 are intended only to be shown
|
|
|
|
* during package selection in anna, but not in the main menu, so mark
|
|
|
|
* them uninstallable.
|
|
|
|
* For other packages, run the isinstallable maintainer script and check
|
|
|
|
* its return code.
|
|
|
|
*/
|
|
|
|
bool isinstallable(di_system_package *p) {
|
|
|
|
int check;
|
|
|
|
|
|
|
|
if (p->installer_menu_item == 99999)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
check = di_system_dpkg_package_control_file_exec(&p->p, "isinstallable", 0, NULL);
|
|
|
|
if (check <= 0)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
/* Add to table listing not installable packages */
|
|
|
|
di_rstring *p_name = di_new0(di_rstring, 1);
|
|
|
|
p_name->string = di_stradup(p->p.key.string, p->p.key.size);
|
|
|
|
p_name->size = p->p.key.size;
|
|
|
|
di_hash_table_insert(notinstallables, p_name, p_name);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return nonzero if all of the virtual packages that P provides are
|
|
|
|
provided by installed packages. */
|
|
|
|
int provides_installed_virtual_packages(di_package *p) {
|
|
|
|
di_slist_node *node1, *node2;
|
|
|
|
int provides = 0;
|
|
|
|
|
|
|
|
for (node1 = p->depends.head; node1; node1 = node1->next) {
|
|
|
|
di_package_dependency *d = node1->data;
|
|
|
|
|
|
|
|
if (d->type == di_package_dependency_type_provides) {
|
|
|
|
int installed = 0;
|
|
|
|
|
|
|
|
provides = 1;
|
|
|
|
|
|
|
|
for (node2 = d->ptr->depends.head; node2; node2 = node2->next) {
|
|
|
|
d = node2->data;
|
|
|
|
|
|
|
|
if (d->type == di_package_dependency_type_reverse_provides
|
|
|
|
&& d->ptr->status == di_package_status_installed) {
|
|
|
|
installed = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!installed)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return provides;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Expects a topologically ordered linked list of packages. */
|
|
|
|
static di_system_package *
|
|
|
|
get_default_menu_item(di_slist *list)
|
|
|
|
{
|
|
|
|
di_system_package *p;
|
|
|
|
di_slist_node *node;
|
|
|
|
|
|
|
|
/* Create table listing not installable packages from scratch as
|
|
|
|
* the isinstallable status can change at any time
|
|
|
|
*/
|
|
|
|
di_hash_table_destroy(notinstallables);
|
|
|
|
notinstallables = di_hash_table_new_full(di_rstring_hash, di_rstring_equal,
|
|
|
|
notinstallables_key_destroy, NULL);
|
|
|
|
|
|
|
|
/* Traverse the list, return the first menu item that isn't installed */
|
|
|
|
for (node = list->head; node != NULL; node = node->next) {
|
|
|
|
p = node->data;
|
|
|
|
//di_log(DI_LOG_LEVEL_DEBUG, "find default; on: %s", p->p.package);
|
|
|
|
if (!p->installer_menu_item ||
|
|
|
|
p->p.status == di_package_status_installed ||
|
|
|
|
!isinstallable(p)) {
|
|
|
|
//di_log(DI_LOG_LEVEL_DEBUG, "not a menu item, not installed or not installable");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (p->installer_menu_item >= NEVERDEFAULT) {
|
|
|
|
//di_log(DI_LOG_LEVEL_DEBUG, "not in range to be default");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (p->installer_menu_item < last_successful_item &&
|
|
|
|
di_hash_table_lookup(seen_items, &p->p.key)) {
|
|
|
|
//di_log(DI_LOG_LEVEL_DEBUG, "menu item (%d) is before last_successful_item (%d), and is not new", p->installer_menu_item, last_successful_item);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* If menutest says this item should be default, make it so */
|
|
|
|
if (!isdefault(p)) {
|
|
|
|
//di_log(DI_LOG_LEVEL_DEBUG, "isdefault says no");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/* If all of the virtual packages provided by a
|
|
|
|
package have already been satisfied, do not default
|
|
|
|
to it. */
|
|
|
|
if (!provides_installed_virtual_packages(&p->p)) {
|
|
|
|
//di_log(DI_LOG_LEVEL_DEBUG, "success on this one");
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
//di_log(DI_LOG_LEVEL_DEBUG, "not default");
|
|
|
|
}
|
|
|
|
/* Severely broken, there are no menu items in the sorted list */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define menu_entry_maxlen 256
|
|
|
|
|
|
|
|
/* Returns a the text of the menu entry for PACKAGE (in a buffer
|
|
|
|
* that will persist until the next call of the function) */
|
|
|
|
const char *menu_entry(struct debconfclient *debconf, di_system_package *package)
|
|
|
|
{
|
|
|
|
char question[menu_entry_maxlen];
|
|
|
|
static char buf[menu_entry_maxlen];
|
|
|
|
|
|
|
|
snprintf(question, sizeof(question), "debian-installer/%s/title", package->p.package);
|
|
|
|
if (!debconf_metaget(debconf, question, "Description")) {
|
|
|
|
strncpy(buf, debconf->value, menu_entry_maxlen);
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The following fallback case can go away once all packages
|
|
|
|
have transitioned to the new form. */
|
|
|
|
di_log(DI_LOG_LEVEL_INFO, "Falling back to the package description for %s", package->p.package);
|
|
|
|
if (package->p.short_description)
|
|
|
|
strncpy(buf, package->p.short_description, menu_entry_maxlen);
|
|
|
|
else
|
|
|
|
buf[0]='\0';
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Escapes a string so it can be added to a Choices list. */
|
|
|
|
const char *choices_escape(const char *string) {
|
|
|
|
static char buf[menu_entry_maxlen * 2];
|
|
|
|
const char *s;
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
s = strchr(string, ',');
|
|
|
|
if (s == NULL)
|
|
|
|
return string;
|
|
|
|
|
|
|
|
/* This is not the cheapest way to do it, but a comma in a
|
|
|
|
* choice is very rare. */
|
|
|
|
s=string;
|
|
|
|
p=buf;
|
|
|
|
while (s[0] != '\0') {
|
|
|
|
if (s[0] == ',') {
|
|
|
|
p[0] = '\\';
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
p[0]=s[0];
|
|
|
|
|
|
|
|
p++;
|
|
|
|
s++;
|
|
|
|
}
|
|
|
|
p[0] = '\0';
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Priority at which the menu should be displayed */
|
|
|
|
static int menu_priority() {
|
|
|
|
static int default_menu_priority = -1;
|
|
|
|
int menu_prio = -1;
|
|
|
|
|
|
|
|
if (default_menu_priority == -1)
|
|
|
|
default_menu_priority = debconf_to_pri(MENU_PRIORITY);
|
|
|
|
|
|
|
|
if (display_menu)
|
|
|
|
menu_prio = local_priority;
|
|
|
|
|
|
|
|
if (menu_prio < 0 ||
|
|
|
|
(size_t)menu_prio >= ARRAY_SIZE(debconf_priorities))
|
|
|
|
menu_prio = default_menu_priority;
|
|
|
|
|
|
|
|
//di_log(DI_LOG_LEVEL_INFO, "default: %i; debconf: %i; menu: %i",
|
|
|
|
// default_menu_priority, local_priority, menu_prio);
|
|
|
|
|
|
|
|
return menu_prio;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Displays the main menu via debconf and returns the selected menu item. */
|
|
|
|
di_system_package *show_main_menu(di_packages *packages, di_packages_allocator *allocator) {
|
|
|
|
di_system_package **package_array, *p;
|
|
|
|
di_slist *list;
|
|
|
|
di_slist_node *node;
|
|
|
|
di_system_package *menudefault = NULL, *ret = NULL;
|
|
|
|
int i = 0, num = 0;
|
|
|
|
char *menu, *s;
|
|
|
|
const char *buf;
|
|
|
|
int menu_prio, menu_size, menu_used, size;
|
|
|
|
|
|
|
|
for (node = packages->list.head; node; node = node->next) {
|
|
|
|
p = node->data;
|
|
|
|
if (((di_system_package *)p)->installer_menu_item)
|
|
|
|
num++;
|
|
|
|
}
|
|
|
|
package_array = di_new (di_system_package *, num + 1);
|
|
|
|
package_array[num] = NULL;
|
|
|
|
for (node = packages->list.head; node; node = node->next) {
|
|
|
|
p = node->data;
|
|
|
|
if (p->installer_menu_item)
|
|
|
|
package_array[i++] = node->data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sort by menu number. */
|
|
|
|
qsort(package_array, num, sizeof (di_system_package *), package_array_compare);
|
|
|
|
|
|
|
|
/* Order menu so depended-upon packages come first. */
|
|
|
|
/* The menu number is really only used to break ties. */
|
|
|
|
list = di_system_packages_resolve_dependencies_array_permissive (packages, (di_package **) package_array, allocator);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Generate list of menu choices for debconf.
|
|
|
|
*/
|
|
|
|
menu_size = 1024;
|
|
|
|
menu = di_malloc(menu_size);
|
|
|
|
menu[0] = '\0';
|
|
|
|
menu_used = 1;
|
|
|
|
for (node = list->head; node != NULL; node = node->next) {
|
|
|
|
p = node->data;
|
|
|
|
if (!p->installer_menu_item ||
|
|
|
|
!isinstallable(p))
|
|
|
|
continue;
|
|
|
|
buf = choices_escape(menu_entry(debconf, p));
|
|
|
|
size = strlen(buf);
|
|
|
|
if (menu_used + size + 2 > menu_size)
|
|
|
|
{
|
|
|
|
menu_size += 1024;
|
|
|
|
menu = di_realloc(menu, menu_size);
|
|
|
|
}
|
|
|
|
if (*menu)
|
|
|
|
strcat(menu, ", ");
|
|
|
|
strcat(menu, buf);
|
|
|
|
menu_used += size + 2;
|
|
|
|
}
|
|
|
|
menudefault = get_default_menu_item(list);
|
|
|
|
di_slist_free(list);
|
|
|
|
|
|
|
|
/* Make debconf show the menu and get the user's choice. */
|
|
|
|
debconf_settitle(debconf, "debian-installer/main-menu-title");
|
|
|
|
debconf_capb(debconf);
|
|
|
|
debconf_subst(debconf, MAIN_MENU, "MENU", menu);
|
|
|
|
if (menudefault) {
|
|
|
|
buf=menu_entry(debconf, menudefault);
|
|
|
|
debconf_set(debconf, MAIN_MENU, buf);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
di_log(DI_LOG_LEVEL_INFO, "no default menu item");
|
|
|
|
modify_debconf_priority(LOWER);
|
|
|
|
}
|
|
|
|
menu_prio = menu_priority();
|
|
|
|
debconf_input(debconf, debconf_priorities[menu_prio], MAIN_MENU);
|
|
|
|
debconf_go(debconf);
|
|
|
|
debconf_get(debconf, MAIN_MENU);
|
|
|
|
s = strdup(debconf->value);
|
|
|
|
|
|
|
|
/* Figure out which menu item was selected. */
|
|
|
|
for (i = 0; i < num; i++) {
|
|
|
|
p = package_array[i];
|
|
|
|
buf = menu_entry(debconf, p);
|
|
|
|
if (strcmp(buf, s) == 0) {
|
|
|
|
ret = p;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! ret) {
|
|
|
|
/* This could happen because of a debconf protocol problem
|
|
|
|
* (for example, leading whitespace in menu items can
|
|
|
|
* be stripped and confuse the comparisons), or other
|
|
|
|
* problem. */
|
|
|
|
di_log(DI_LOG_LEVEL_WARNING, "Internal error! Cannot find \"%s\" in menu.", s);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(s);
|
|
|
|
free(menu);
|
|
|
|
free(package_array);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Satisfy the dependencies of a virtual package. Its dependencies
|
|
|
|
* that actually provide the package are presented in a debconf select
|
|
|
|
* question for the user to pick and choose. Other dependencies are
|
|
|
|
* just fed recursively through di_config_package.
|
|
|
|
*/
|
|
|
|
static int satisfy_virtual(di_system_package *p) {
|
|
|
|
di_slist_node *node;
|
|
|
|
di_system_package *dep, *defpkg = NULL;
|
|
|
|
char *menu, *s = NULL;
|
|
|
|
const char *buf;
|
|
|
|
size_t menu_size, menu_used, size;
|
|
|
|
int is_menu_item = 0;
|
|
|
|
|
|
|
|
menu = di_malloc(1024);
|
|
|
|
menu[0] = '\0';
|
|
|
|
menu_size = 1024;
|
|
|
|
menu_used = 1;
|
|
|
|
/* Compile a list of providing package. The default choice will be the
|
|
|
|
* package with highest priority. If we have ties, menu items are
|
|
|
|
* preferred. If we still have ties, the default choice is arbitrary */
|
|
|
|
for (node = p->p.depends.head; node; node = node->next) {
|
|
|
|
di_package_dependency *d = node->data;
|
|
|
|
dep = (di_system_package *)d->ptr;
|
|
|
|
if (d->type == di_package_dependency_type_depends) {
|
|
|
|
/* Non-providing dependency */
|
|
|
|
di_log(DI_LOG_LEVEL_DEBUG, "non-providing dependency from %s to %s", p->p.package, dep->p.package);
|
|
|
|
if (dep->p.status != di_package_status_installed) {
|
|
|
|
switch (di_config_package(dep, satisfy_virtual)) {
|
|
|
|
case -1:
|
|
|
|
di_free(menu);
|
|
|
|
return -1;
|
|
|
|
case EXIT_BACKUP:
|
|
|
|
di_free(menu);
|
|
|
|
return EXIT_BACKUP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (d->type != di_package_dependency_type_reverse_provides)
|
|
|
|
continue;
|
|
|
|
if (dep->p.status == di_package_status_installed) {
|
|
|
|
/* This means that a providing package is already
|
|
|
|
* configure. So we short-circuit. */
|
|
|
|
menu_used = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (defpkg == NULL || dep->p.priority > defpkg->p.priority ||
|
|
|
|
(dep->p.priority == defpkg->p.priority &&
|
|
|
|
dep->installer_menu_item < defpkg->installer_menu_item))
|
|
|
|
defpkg = dep;
|
|
|
|
/* This only makes sense if one of the dependencies
|
|
|
|
* is a menu item */
|
|
|
|
if (dep->installer_menu_item)
|
|
|
|
is_menu_item = 1;
|
|
|
|
|
|
|
|
buf = choices_escape(menu_entry(debconf, dep));
|
|
|
|
size = strlen(buf);
|
|
|
|
if (menu_used + size + 2 > menu_size)
|
|
|
|
{
|
|
|
|
menu_size += 1024;
|
|
|
|
menu = di_realloc(menu, menu_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dep == defpkg) {
|
|
|
|
/* We want the default to be the first item */
|
|
|
|
char *temp;
|
|
|
|
temp = di_malloc (menu_size);
|
|
|
|
strcpy(temp, menu);
|
|
|
|
strcpy(menu, buf);
|
|
|
|
if (strlen(temp)) {
|
|
|
|
strcat(menu, ", ");
|
|
|
|
strcat(menu, temp);
|
|
|
|
}
|
|
|
|
di_free(temp);
|
|
|
|
} else {
|
|
|
|
if (strlen(menu)) {
|
|
|
|
strcat(menu, ", ");
|
|
|
|
}
|
|
|
|
strcat(menu, buf);
|
|
|
|
}
|
|
|
|
menu_used += size + 2;
|
|
|
|
}
|
|
|
|
if (menu_used >= 2)
|
|
|
|
menu[menu_used-2] = '\0';
|
|
|
|
if (menu_used > 1) {
|
|
|
|
if (is_menu_item) {
|
|
|
|
char *priority = "medium";
|
|
|
|
/* Only let the user choose if one of them is a menu item */
|
|
|
|
if (defpkg != NULL) {
|
|
|
|
buf = menu_entry(debconf, defpkg);
|
|
|
|
debconf_set(debconf, MISSING_PROVIDE, buf);
|
|
|
|
} else {
|
|
|
|
/* TODO: How to figure out a default? */
|
|
|
|
priority = "critical";
|
|
|
|
}
|
|
|
|
debconf_capb(debconf, "backup");
|
|
|
|
debconf_subst(debconf, MISSING_PROVIDE, "CHOICES", menu);
|
|
|
|
debconf_input(debconf, priority, MISSING_PROVIDE);
|
|
|
|
if (debconf_go(debconf) != 0) {
|
|
|
|
di_free(menu);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
debconf_capb(debconf);
|
|
|
|
debconf_get(debconf, MISSING_PROVIDE);
|
|
|
|
s = strdup(debconf->value);
|
|
|
|
}
|
|
|
|
/* Go through the dependencies again */
|
|
|
|
for (node = p->p.depends.head; node; node = node->next) {
|
|
|
|
di_package_dependency *d = node->data;
|
|
|
|
dep = (di_system_package *)d->ptr;
|
|
|
|
buf = menu_entry(debconf, dep);
|
|
|
|
if (!is_menu_item || strcmp(s, buf) == 0) {
|
|
|
|
/* Ick. If we have a menu item it has to match the
|
|
|
|
* debconf choice, otherwise we configure all of
|
|
|
|
* the providing packages */
|
|
|
|
switch (di_config_package(dep, satisfy_virtual)) {
|
|
|
|
case -1:
|
|
|
|
di_free(menu);
|
|
|
|
free(s);
|
|
|
|
return -1;
|
|
|
|
case EXIT_BACKUP:
|
|
|
|
di_free(menu);
|
|
|
|
free(s);
|
|
|
|
return EXIT_BACKUP;
|
|
|
|
}
|
|
|
|
if (is_menu_item)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
di_free(menu);
|
|
|
|
free(s);
|
|
|
|
/* It doesn't make sense to configure virtual packages,
|
|
|
|
* since they are, well, virtual. */
|
|
|
|
p->p.status = di_package_status_installed;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void set_package_title(di_system_package *p) {
|
|
|
|
char *title;
|
|
|
|
|
|
|
|
if (!p->installer_menu_item)
|
|
|
|
return;
|
|
|
|
title = xasprintf("debian-installer/%s/title", p->p.package);
|
|
|
|
if (debconf_settitle(debconf, title))
|
|
|
|
di_log(DI_LOG_LEVEL_WARNING, "Unable to set title for %s.", p->p.package);
|
|
|
|
free(title);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int do_menu_item(di_system_package *p) {
|
|
|
|
di_log(DI_LOG_LEVEL_INFO, "Menu item '%s' selected", p->p.package);
|
|
|
|
|
|
|
|
return di_config_package(p, satisfy_virtual);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void modify_debconf_priority (int raise_or_lower) {
|
|
|
|
int pri;
|
|
|
|
const char *template = "debconf/priority";
|
|
|
|
debconf_get(debconf, template);
|
|
|
|
|
|
|
|
pri = debconf_to_pri(debconf->value);
|
|
|
|
if ( pri == -1 )
|
|
|
|
pri = 1;
|
|
|
|
|
|
|
|
if (raise_or_lower == LOWER) {
|
|
|
|
--pri;
|
|
|
|
/* Make sure the menu is always displayed after an error */
|
|
|
|
display_menu = 1;
|
|
|
|
}
|
|
|
|
else if (raise_or_lower == RAISE)
|
|
|
|
++pri;
|
|
|
|
if (0 > pri)
|
|
|
|
pri = 0;
|
|
|
|
if (pri > default_priority)
|
|
|
|
pri = default_priority;
|
|
|
|
if (local_priority != pri) {
|
|
|
|
if (local_priority > -1)
|
|
|
|
di_log(DI_LOG_LEVEL_INFO, "Modifying debconf priority limit from '%s' to '%s'",
|
|
|
|
debconf->value ? debconf->value : "(null)",
|
|
|
|
debconf_priorities[pri] ? debconf_priorities[pri] : "(null)");
|
|
|
|
local_priority = pri;
|
|
|
|
|
|
|
|
debconf_set(debconf, template, debconf_priorities[pri]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void adjust_default_priority (void) {
|
|
|
|
int pri;
|
|
|
|
const char *template = "debconf/priority";
|
|
|
|
debconf_get(debconf, template);
|
|
|
|
|
|
|
|
pri = debconf_to_pri(debconf->value);
|
|
|
|
|
|
|
|
if (pri > -1 && pri != local_priority) {
|
|
|
|
if (local_priority > -1)
|
|
|
|
di_log(DI_LOG_LEVEL_INFO, "Priority changed externally, setting main-menu default to '%s' (%s)",
|
|
|
|
debconf_priorities[pri] ? debconf_priorities[pri] : "(null)", debconf->value);
|
|
|
|
local_priority = pri;
|
|
|
|
default_priority = pri;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void restore_default_priority (void) {
|
|
|
|
const char *template = "debconf/priority";
|
|
|
|
|
|
|
|
if (local_priority != default_priority) {
|
|
|
|
di_log(DI_LOG_LEVEL_INFO, "Restoring default debconf priority '%s'",
|
|
|
|
debconf_priorities[default_priority] ? debconf_priorities[default_priority] : "(null)");
|
|
|
|
debconf_set(debconf, template, debconf_priorities[default_priority]);
|
|
|
|
local_priority = default_priority;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void notify_user_of_failure (di_system_package *p) {
|
|
|
|
const char *buf;
|
|
|