|
|
|
/*
|
|
|
|
* Debian Installer main menu program.
|
|
|
|
*
|
|
|
|
* Copyright 2000 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 <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>
|
|
|
|
|
|
|
|
const int RAISE = 1;
|
|
|
|
const int LOWER = 0;
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
static struct debconfclient *debconf;
|
|
|
|
|
|
|
|
static int di_config_package(di_system_package *p,
|
|
|
|
int (*virtfunc)(di_system_package *),
|
|
|
|
int (*walkfunc)(di_system_package *));
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
if (r) return r;
|
|
|
|
return strcmp(p1->p.package, p2->p.package);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isinstallable(di_system_package *p) {
|
|
|
|
int check;
|
|
|
|
|
|
|
|
check = di_system_dpkg_package_control_file_exec(&p->p, "isinstallable", 0, NULL);
|
|
|
|
if (check <= 0)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int provides_installed_virtual_package(di_package *p) {
|
|
|
|
di_slist_node *node1, *node2;
|
|
|
|
|
|
|
|
for (node1 = p->depends.head; node1; node1 = node1->next) {
|
|
|
|
di_package_dependency *d = node1->data;
|
|
|
|
|
|
|
|
if (d->type == di_package_dependency_type_provides)
|
|
|
|
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)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
/* Traverse the list, return the first menu item that isn't installed */
|
|
|
|
for (node = list->head; node != NULL; node = node->next) {
|
|
|
|
p = node->data;
|
|
|
|
if (!p->installer_menu_item ||
|
|
|
|
p->p.status == di_package_status_installed ||
|
|
|
|
!isinstallable(p))
|
|
|
|
continue;
|
|
|
|
/* If menutest says this item should be default, make it so */
|
|
|
|
if (!isdefault(p))
|
|
|
|
continue;
|
|
|
|
/* Do not default to a package that provides a virtual
|
|
|
|
package that is provided by a package that is
|
|
|
|
already installed. */
|
|
|
|
if (!provides_installed_virtual_package(&p->p))
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
/* Severely broken, there are no menu items in the sorted list */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the text of the menu entry for PACKAGE, translated to
|
|
|
|
LANGUAGE if possible. */
|
|
|
|
static size_t menu_entry(struct debconfclient *debconf, char *language, di_system_package *package, char *buf, size_t size)
|
|
|
|
{
|
|
|
|
char question[256];
|
|
|
|
|
|
|
|
snprintf(question, sizeof(question), "debian-installer/%s/title", package->p.package);
|
|
|
|
if (language) {
|
|
|
|
/* 256 + strlen("Description-.UTF-8") */
|
|
|
|
char field[256+18];
|
|
|
|
char *lang, *end, *und;
|
|
|
|
|
|
|
|
strcpy(field, "Description-");
|
|
|
|
lang = language;
|
|
|
|
do {
|
|
|
|
end = strchr(lang, ':');
|
|
|
|
if (end == NULL)
|
|
|
|
end = lang + strlen(lang);
|
|
|
|
strncpy(field+12, lang, end-lang);
|
|
|
|
strcpy(field+12+(end-lang), ".UTF-8");
|
|
|
|
if (!debconf_metaget(debconf, question, field))
|
|
|
|
{
|
|
|
|
strncpy(buf, debconf->value, size);
|
|
|
|
return strlen (buf);
|
|
|
|
}
|
|
|
|
// Was the language of the form xx_YY ?
|
|
|
|
und = strchr(lang, '_');
|
|
|
|
if (und != NULL && (und - lang) < (end - lang)) {
|
|
|
|
strncpy(field+12, lang, und-lang);
|
|
|
|
strcpy(field+12+(und-lang), ".UTF-8");
|
|
|
|
if (!debconf_metaget(debconf, question, field))
|
|
|
|
{
|
|
|
|
strncpy(buf, debconf->value, size);
|
|
|
|
return strlen (buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lang = end+1;
|
|
|
|
} while (*end != '\0');
|
|
|
|
}
|
|
|
|
if (!debconf_metaget(debconf, question, "Description"))
|
|
|
|
{
|
|
|
|
strncpy(buf, debconf->value, size);
|
|
|
|
return strlen (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, size);
|
|
|
|
return strlen (buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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) {
|
|
|
|
char *language = NULL;
|
|
|
|
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 buf[256], *menu, *s;
|
|
|
|
int menu_size, menu_used, size;
|
|
|
|
|
|
|
|
debconf_get(debconf,"debian-installer/language");
|
|
|
|
if (language)
|
|
|
|
free(language);
|
|
|
|
if (debconf->value)
|
|
|
|
language = strdup(debconf->value);
|
|
|
|
|
|
|
|
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_packages_resolve_dependencies_array (packages, (di_package **) package_array, allocator);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Generate list of menu choices for debconf.
|
|
|
|
*/
|
|
|
|
menu = di_malloc(1024);
|
|
|
|
menu[0] = '\0';
|
|
|
|
menu_size = 1024;
|
|
|
|
menu_used = 1;
|
|
|
|
for (node = list->head; node != NULL; node = node->next) {
|
|
|
|
p = node->data;
|
|
|
|
if (!p->installer_menu_item ||
|
|
|
|
!isinstallable(p))
|
|
|
|
continue;
|
|
|
|
size = menu_entry(debconf, language, p, buf, sizeof (buf));
|
|
|
|
if (menu_used + size + 2 > menu_size)
|
|
|
|
{
|
|
|
|
menu_size += 1024;
|
|
|
|
menu = di_realloc(menu, menu_size);
|
|
|
|
}
|
|
|
|
strcat(menu, buf);
|
|
|
|
menu_used += size + 2;
|
|
|
|
if (node->next)
|
|
|
|
strcat(menu, ", ");
|
|
|
|
}
|
|
|
|
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_fset(debconf, MAIN_MENU, "seen", "false");
|
|
|
|
debconf_subst(debconf, MAIN_MENU, "MENU", menu);
|
|
|
|
if (menudefault) {
|
|
|
|
menu_entry(debconf, language, menudefault, buf, sizeof (buf));
|
|
|
|
debconf_set(debconf, MAIN_MENU, buf);
|
|
|
|
}
|
|
|
|
debconf_input(debconf, "medium", 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];
|
|
|
|
menu_entry(debconf, language, p, buf, sizeof (buf));
|
|
|
|
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_INFO, "Internal error! Cannot find \"%s\" in menu.", s);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(language);
|
|
|
|
free(package_array);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int check_special(di_system_package *p);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 *language = NULL;
|
|
|
|
char buf[256], *menu, *s = NULL;
|
|
|
|
size_t menu_size, menu_used, size;
|
|
|
|
int is_menu_item = 0;
|
|
|
|
|
|
|
|
debconf_get(debconf, "debian-installer/language");
|
|
|
|
if (debconf->value)
|
|
|
|
language = strdup(debconf->value);
|
|
|
|
|
|
|
|
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 &&
|
|
|
|
!di_config_package(dep, satisfy_virtual, check_special))
|
|
|
|
return 0;
|
|
|
|
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;
|
|
|
|
|
|
|
|
size = menu_entry(debconf, language, dep, buf, sizeof (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);
|
|
|
|
strcat(menu, ", ");
|
|
|
|
strcat(menu, temp);
|
|
|
|
di_free(temp);
|
|
|
|
} else {
|
|
|
|
strcat(menu, buf);
|
|
|
|
strcat(menu, ", ");
|
|
|
|
}
|
|
|
|
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 */
|
|
|
|
debconf_fset(debconf, MISSING_PROVIDE, "seen", "false");
|
|
|
|
if (defpkg != NULL) {
|
|
|
|
menu_entry(debconf, language, defpkg, buf, sizeof(buf));
|
|
|
|
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)
|
|
|
|
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;
|
|
|
|
menu_entry(debconf, language, dep, buf, sizeof(buf));
|
|
|
|
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 */
|
|
|
|
if (!di_config_package(dep, satisfy_virtual, check_special))
|
|
|
|
return 0;
|
|
|
|
if (is_menu_item)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(menu);
|
|
|
|
free(s);
|
|
|
|
free(language);
|
|
|
|
/* 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 update_language (void) {
|
|
|
|
debconf_get(debconf, "debian-installer/language");
|
|
|
|
if (*debconf->value != 0)
|
|
|
|
setenv("LANGUAGE", debconf->value, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
check_special(di_system_package *p)
|
|
|
|
{
|
|
|
|
di_slist_node *node;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A language selection package must provide the virtual
|
|
|
|
* package 'language-selected'.
|
|
|
|
* The LANGUAGE environment variable must be updated
|
|
|
|
*/
|
|
|
|
for (node = p->p.depends.head; node; node = node->next) {
|
|
|
|
di_package_dependency *d = node->data;
|
|
|
|
if (d->type == di_package_dependency_type_provides && strcmp(d->ptr->package, "language-selected") == 0) {
|
|
|
|
update_language();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void set_package_title(di_system_package *p) {
|
|
|
|
char *title;
|
|
|
|
|
|
|
|
asprintf(&title, "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);
|
|
|
|
}
|
|
|
|
|
|
|
|
int do_menu_item(di_system_package *p) {
|
|
|
|
char *configcommand;
|
|
|
|
const char *showold_template = "debconf/showold";
|
|
|
|
char *showold = NULL;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
di_log(DI_LOG_LEVEL_DEBUG, "Menu item '%s' selected", p->p.package);
|
|
|
|
|
|
|
|
if (p->p.status == di_package_status_installed) {
|
|
|
|
set_package_title(p);
|
|
|
|
|
|
|
|
/* The menu item is already configured, so reconfigure it. */
|
|
|
|
debconf_get(debconf, showold_template);
|
|
|
|
if (debconf->value)
|
|
|
|
showold = strdup(debconf->value);
|
|
|
|
debconf_set(debconf, showold_template, "true");
|
|
|
|
if (asprintf(&configcommand, "exec udpkg --configure --force-configure %s", p->p.package) == -1) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = di_exec_shell_log(configcommand);
|
|
|
|
ret = di_exec_mangle_status(ret);
|
|
|
|
free(configcommand);
|
|
|
|
if (showold) {
|
|
|
|
debconf_set(debconf, showold_template, showold);
|
|
|
|
free(showold);
|
|
|
|
} else {
|
|
|
|
debconf_reset(debconf, showold_template);
|
|
|
|
}
|
|
|
|
check_special(p);
|
|
|
|
if (ret)
|
|
|
|
di_log(DI_LOG_LEVEL_WARNING, "Reconfiguring '%s' failed with error code %d", p->p.package, ret);
|
|
|
|
ret = !ret;
|
|
|
|
}
|
|
|
|
else if (p->p.status == di_package_status_unpacked || p->p.status == di_package_status_half_configured) {
|
|
|
|
ret = di_config_package(p, satisfy_virtual, check_special);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *debconf_priorities[] =
|
|
|
|
{
|
|
|
|
"low",
|
|
|
|
"medium",
|
|
|
|
"high",
|
|
|
|
"critical"
|
|
|
|
};
|
|
|
|
|
|
|
|
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
|
|
|
static void modify_debconf_priority (int raise_or_lower) {
|
|
|
|
int pri, i;
|
|
|
|
const char *template = "debconf/priority";
|
|
|
|
debconf_get(debconf, template);
|
|
|
|
|
|
|
|
pri = 1;
|
|
|
|
if ( debconf->value ) {
|
|
|
|
for (i = 0; (size_t)i < ARRAY_SIZE(debconf_priorities); ++i) {
|
|
|
|
if (0 == strcmp(debconf->value,
|
|
|
|
debconf_priorities[i]) ) {
|
|
|
|
pri = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (raise_or_lower == LOWER)
|
|
|
|
--pri;
|
|
|
|
else if (raise_or_lower == RAISE)
|
|
|
|
++pri;
|
|
|
|
if (0 > pri)
|
|
|
|
pri = 0;
|
|
|
|
if (pri > default_priority)
|
|
|
|
pri = default_priority;
|
|
|
|
if (local_priority != pri) {
|
|
|
|
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, i;
|
|
|
|
const char *template = "debconf/priority";
|
|
|
|
debconf_get(debconf, template);
|
|
|
|
|
|
|
|
pri = 1;
|
|
|
|
if ( debconf->value ) {
|
|
|
|
for (i = 0; (size_t)i < ARRAY_SIZE(debconf_priorities); ++i) {
|
|
|
|
if (0 == strcmp(debconf->value,
|
|
|
|
debconf_priorities[i]) ) {
|
|
|
|
pri = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( pri != local_priority ) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int main (int argc __attribute__ ((unused)), char **argv) {
|
|
|
|
di_system_package *p;
|
|
|
|
di_packages *packages;
|
|
|
|
di_packages_allocator *allocator;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
debconf = debconfclient_new();
|
|
|
|
di_system_init(basename(argv[0]));
|
|
|
|
|
|
|
|
/* Tell udpkg to shut up. */
|
|
|
|
setenv("UDPKG_QUIET", "y", 1);
|
|
|
|
|
|
|
|
allocator = di_system_packages_allocator_alloc ();
|
|
|
|
packages = di_system_packages_status_read_file(DI_SYSTEM_DPKG_STATUSFILE, allocator);
|
|
|
|
while ((p=show_main_menu(packages, allocator))) {
|
|
|
|
ret = do_menu_item(p);
|
|
|
|
adjust_default_priority();
|
|
|
|
if (!ret) {
|
|
|
|
if (ret == 10)
|
|
|
|
di_log(DI_LOG_LEVEL_INFO, "Menu item '%s' succeeded but requested to be left unconfigured.", p->p.package);
|
|
|
|
else
|
|
|
|
di_log(DI_LOG_LEVEL_WARNING, "Menu item '%s' failed.", p->p.package);
|
|
|
|
/* Something went wrong. Lower debconf
|
|
|
|
priority limit to try to give the user more
|
|
|
|
control over the situation. */
|
|
|
|
modify_debconf_priority(LOWER);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
modify_debconf_priority(RAISE);
|
|
|
|
|
|
|
|
di_packages_free (packages);
|
|
|
|
di_packages_allocator_free (allocator);
|
|
|
|
allocator = di_system_packages_allocator_alloc ();
|
|
|
|
packages = di_system_packages_status_read_file(DI_SYSTEM_DPKG_STATUSFILE, allocator);
|
|
|
|
|
|
|
|
/* tell cdebconf to save the database */
|
|
|
|
kill(getppid(), SIGUSR1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Configure all dependencies, special case for virtual packages.
|
|
|
|
* This is done depth-first.
|
|
|
|
*/
|
|
|
|
static int di_config_package(di_system_package *p,
|
|
|
|
int (*virtfunc)(di_system_package *),
|
|
|
|
int (*walkfunc)(di_system_package *)) {
|
|
|
|
char *configcommand;
|
|
|
|
int ret;
|
|
|
|
di_slist_node *node;
|
|
|
|
di_system_package *dep;
|
|
|
|
|
|
|
|
di_log(DI_LOG_LEVEL_DEBUG, "configure %s, status: %d\n", p->p.package, p->p.status);
|
|
|
|
|
|
|
|
if (p->p.type == di_package_type_virtual_package) {
|
|
|
|
di_log(DI_LOG_LEVEL_DEBUG, "virtual package %s\n", p->p.package);
|
|
|
|
if (virtfunc)
|
|
|
|
return virtfunc(p);
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else if (p->p.type == di_package_type_non_existent)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
for (node = p->p.depends.head; node; node = node->next) {
|
|
|
|
di_package_dependency *d = node->data;
|
|
|
|
dep = (di_system_package *)d->ptr;
|
|
|
|
if (dep->p.status == di_package_status_installed)
|
|
|
|
continue;
|
|
|
|
if (d->type != di_package_dependency_type_depends)
|
|
|
|
continue;
|
|
|
|
/* Recursively configure this package */
|
|
|
|
if (!di_config_package(dep, virtfunc, walkfunc))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
set_package_title(p);
|
|
|
|
if (asprintf(&configcommand, "exec udpkg --configure %s", p->p.package) == -1) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = di_exec_shell_log(configcommand);
|
|
|
|
ret = di_exec_mangle_status(ret);
|
|
|
|
free(configcommand);
|
|
|
|
if (ret == 0) {
|
|
|
|
p->p.status = di_package_status_installed;
|
|
|
|
if (walkfunc != NULL)
|
|
|
|
walkfunc(p);
|
|
|
|
} else {
|
|
|
|
di_log(DI_LOG_LEVEL_WARNING, "Configuring '%s' failed with error code %d", p->p.package, ret);
|
|
|
|
p->p.status = di_package_status_half_configured;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return !ret;
|
|
|
|
}
|