You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

858 lines
24 KiB

  1. /*
  2. * Debian Installer main menu program.
  3. *
  4. * Copyright 2000,2004 Joey Hess <joeyh@debian.org>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. */
  16. #include "main-menu.h"
  17. #include <cdebconf/debconfclient.h>
  18. #include <stdarg.h>
  19. #include <stdlib.h>
  20. #include <search.h>
  21. #include <stdio.h>
  22. #include <sys/stat.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <signal.h>
  26. #include <sys/types.h>
  27. #include <unistd.h>
  28. #include <dirent.h>
  29. #include <errno.h>
  30. const int RAISE = 1;
  31. const int LOWER = 0;
  32. di_hash_table *seen_items;
  33. di_hash_table *notinstallables;
  34. int last_successful_item = -1;
  35. /* Save default priority, to be able to return to it when we have to lower it */
  36. int default_priority = 1;
  37. /* Save priority set by main-menu to detect priority changes from the user */
  38. int local_priority = -1;
  39. /* Force display of the menu at the current priority */
  40. int display_menu = 0;
  41. static struct debconfclient *debconf;
  42. static int di_config_package(di_system_package *p,
  43. int (*virtfunc)(di_system_package *));
  44. static void modify_debconf_priority (int raise_or_lower);
  45. static char *debconf_priorities[] =
  46. {
  47. "low",
  48. "medium",
  49. "high",
  50. "critical"
  51. };
  52. #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
  53. static int debconf_to_pri (char *priority) {
  54. int i;
  55. if (priority)
  56. for (i = 0; (size_t)i < ARRAY_SIZE(debconf_priorities); ++i)
  57. if (0 == strcmp(priority, debconf_priorities[i]))
  58. return i;
  59. return -1;
  60. }
  61. static char *xasprintf (const char *format, ...)
  62. {
  63. va_list args;
  64. char *result;
  65. va_start(args, format);
  66. if (vasprintf(&result, format, args) < 0) {
  67. if (errno == ENOMEM) {
  68. fputs("Out of memory!\n", stderr);
  69. abort();
  70. }
  71. return NULL;
  72. }
  73. return result;
  74. }
  75. /*
  76. * qsort comparison function (sort by menu item values, fall back to
  77. * lexical sort to resolve ties deterministically).
  78. */
  79. int package_array_compare (const void *v1, const void *v2) {
  80. di_system_package *p1, *p2;
  81. p1 = *(di_system_package **)v1;
  82. p2 = *(di_system_package **)v2;
  83. int r = p1->installer_menu_item - p2->installer_menu_item;
  84. //di_log(DI_LOG_LEVEL_DEBUG, "menu compare: %s (%i) vs %s (%i): %i",
  85. // p1->p.package, p1->installer_menu_item,
  86. // p2->p.package, p2->installer_menu_item, r);
  87. if (r) return r;
  88. return strcmp(p1->p.package, p2->p.package);
  89. }
  90. static void seen_items_key_destroy (void *key)
  91. {
  92. di_rstring *s = key;
  93. di_free(s->string);
  94. di_free(s);
  95. }
  96. static void notinstallables_key_destroy (void *key)
  97. {
  98. di_rstring *s = key;
  99. di_free(s->string);
  100. di_free(s);
  101. }
  102. int isdefault(di_system_package *p) {
  103. int check;
  104. check = di_system_dpkg_package_control_file_exec(&p->p, "menutest", 0, NULL);
  105. if (check <= 0 || p->p.status == di_package_status_unpacked || p->p.status == di_package_status_half_configured)
  106. return true;
  107. return false;
  108. }
  109. /*
  110. * Menu items with a number equal to 99999 are intended only to be shown
  111. * during package selection in anna, but not in the main menu, so mark
  112. * them uninstallable.
  113. * For other packages, run the isinstallable maintainer script and check
  114. * its return code.
  115. */
  116. bool isinstallable(di_system_package *p) {
  117. int check;
  118. if (p->installer_menu_item == 99999)
  119. return false;
  120. check = di_system_dpkg_package_control_file_exec(&p->p, "isinstallable", 0, NULL);
  121. if (check <= 0)
  122. return true;
  123. /* Add to table listing not installable packages */
  124. di_rstring *p_name = di_new0(di_rstring, 1);
  125. p_name->string = di_stradup(p->p.key.string, p->p.key.size);
  126. p_name->size = p->p.key.size;
  127. di_hash_table_insert(notinstallables, p_name, p_name);
  128. return false;
  129. }
  130. /* Return nonzero if all of the virtual packages that P provides are
  131. provided by installed packages. */
  132. int provides_installed_virtual_packages(di_package *p) {
  133. di_slist_node *node1, *node2;
  134. int provides = 0;
  135. for (node1 = p->depends.head; node1; node1 = node1->next) {
  136. di_package_dependency *d = node1->data;
  137. if (d->type == di_package_dependency_type_provides) {
  138. int installed = 0;
  139. provides = 1;
  140. for (node2 = d->ptr->depends.head; node2; node2 = node2->next) {
  141. d = node2->data;
  142. if (d->type == di_package_dependency_type_reverse_provides
  143. && d->ptr->status == di_package_status_installed) {
  144. installed = 1;
  145. break;
  146. }
  147. }
  148. if (!installed)
  149. return 0;
  150. }
  151. }
  152. return provides;
  153. }
  154. /* Expects a topologically ordered linked list of packages. */
  155. static di_system_package *
  156. get_default_menu_item(di_slist *list)
  157. {
  158. di_system_package *p;
  159. di_slist_node *node;
  160. /* Create table listing not installable packages from scratch as
  161. * the isinstallable status can change at any time
  162. */
  163. di_hash_table_destroy(notinstallables);
  164. notinstallables = di_hash_table_new_full(di_rstring_hash, di_rstring_equal,
  165. notinstallables_key_destroy, NULL);
  166. /* Traverse the list, return the first menu item that isn't installed */
  167. for (node = list->head; node != NULL; node = node->next) {
  168. p = node->data;
  169. //di_log(DI_LOG_LEVEL_DEBUG, "find default; on: %s", p->p.package);
  170. if (!p->installer_menu_item ||
  171. p->p.status == di_package_status_installed ||
  172. !isinstallable(p)) {
  173. //di_log(DI_LOG_LEVEL_DEBUG, "not a menu item, not installed or not installable");
  174. continue;
  175. }
  176. if (p->installer_menu_item >= NEVERDEFAULT) {
  177. //di_log(DI_LOG_LEVEL_DEBUG, "not in range to be default");
  178. continue;
  179. }
  180. if (p->installer_menu_item < last_successful_item &&
  181. di_hash_table_lookup(seen_items, &p->p.key)) {
  182. //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);
  183. continue;
  184. }
  185. /* If menutest says this item should be default, make it so */
  186. if (!isdefault(p)) {
  187. //di_log(DI_LOG_LEVEL_DEBUG, "isdefault says no");
  188. continue;
  189. }
  190. /* If all of the virtual packages provided by a
  191. package have already been satisfied, do not default
  192. to it. */
  193. if (!provides_installed_virtual_packages(&p->p)) {
  194. //di_log(DI_LOG_LEVEL_DEBUG, "success on this one");
  195. return p;
  196. }
  197. //di_log(DI_LOG_LEVEL_DEBUG, "not default");
  198. }
  199. /* Severely broken, there are no menu items in the sorted list */
  200. return NULL;
  201. }
  202. #define menu_entry_maxlen 256
  203. /* Returns a the text of the menu entry for PACKAGE (in a buffer
  204. * that will persist until the next call of the function) */
  205. const char *menu_entry(struct debconfclient *debconf, di_system_package *package)
  206. {
  207. char question[menu_entry_maxlen];
  208. static char buf[menu_entry_maxlen];
  209. snprintf(question, sizeof(question), "debian-installer/%s/title", package->p.package);
  210. if (!debconf_metaget(debconf, question, "Description")) {
  211. strncpy(buf, debconf->value, menu_entry_maxlen);
  212. return buf;
  213. }
  214. /* The following fallback case can go away once all packages
  215. have transitioned to the new form. */
  216. di_log(DI_LOG_LEVEL_INFO, "Falling back to the package description for %s", package->p.package);
  217. if (package->p.short_description)
  218. strncpy(buf, package->p.short_description, menu_entry_maxlen);
  219. else
  220. buf[0]='\0';
  221. return buf;
  222. }
  223. /* Escapes a string so it can be added to a Choices list. */
  224. const char *choices_escape(const char *string) {
  225. static char buf[menu_entry_maxlen * 2];
  226. const char *s;
  227. char *p;
  228. s = strchr(string, ',');
  229. if (s == NULL)
  230. return string;
  231. /* This is not the cheapest way to do it, but a comma in a
  232. * choice is very rare. */
  233. s=string;
  234. p=buf;
  235. while (s[0] != '\0') {
  236. if (s[0] == ',') {
  237. p[0] = '\\';
  238. p++;
  239. }
  240. p[0]=s[0];
  241. p++;
  242. s++;
  243. }
  244. p[0] = '\0';
  245. return buf;
  246. }
  247. /* Priority at which the menu should be displayed */
  248. static int menu_priority() {
  249. static int default_menu_priority = -1;
  250. int menu_prio = -1;
  251. if (default_menu_priority == -1)
  252. default_menu_priority = debconf_to_pri(MENU_PRIORITY);
  253. if (display_menu)
  254. menu_prio = local_priority;
  255. if (menu_prio < 0 ||
  256. (size_t)menu_prio >= ARRAY_SIZE(debconf_priorities))
  257. menu_prio = default_menu_priority;
  258. //di_log(DI_LOG_LEVEL_INFO, "default: %i; debconf: %i; menu: %i",
  259. // default_menu_priority, local_priority, menu_prio);
  260. return menu_prio;
  261. }
  262. /* Displays the main menu via debconf and returns the selected menu item. */
  263. di_system_package *show_main_menu(di_packages *packages, di_packages_allocator *allocator) {
  264. di_system_package **package_array, *p;
  265. di_slist *list;
  266. di_slist_node *node;
  267. di_system_package *menudefault = NULL, *ret = NULL;
  268. int i = 0, num = 0;
  269. char *menu, *s;
  270. const char *buf;
  271. int menu_prio, menu_size, menu_used, size;
  272. for (node = packages->list.head; node; node = node->next) {
  273. p = node->data;
  274. if (((di_system_package *)p)->installer_menu_item)
  275. num++;
  276. }
  277. package_array = di_new (di_system_package *, num + 1);
  278. package_array[num] = NULL;
  279. for (node = packages->list.head; node; node = node->next) {
  280. p = node->data;
  281. if (p->installer_menu_item)
  282. package_array[i++] = node->data;
  283. }
  284. /* Sort by menu number. */
  285. qsort(package_array, num, sizeof (di_system_package *), package_array_compare);
  286. /* Order menu so depended-upon packages come first. */
  287. /* The menu number is really only used to break ties. */
  288. list = di_system_packages_resolve_dependencies_array_permissive (packages, (di_package **) package_array, allocator);
  289. /*
  290. * Generate list of menu choices for debconf.
  291. */
  292. menu_size = 1024;
  293. menu = di_malloc(menu_size);
  294. menu[0] = '\0';
  295. menu_used = 1;
  296. for (node = list->head; node != NULL; node = node->next) {
  297. p = node->data;
  298. if (!p->installer_menu_item ||
  299. !isinstallable(p))
  300. continue;
  301. buf = choices_escape(menu_entry(debconf, p));
  302. size = strlen(buf);
  303. if (menu_used + size + 2 > menu_size)
  304. {
  305. menu_size += 1024;
  306. menu = di_realloc(menu, menu_size);
  307. }
  308. if (*menu)
  309. strcat(menu, ", ");
  310. strcat(menu, buf);
  311. menu_used += size + 2;
  312. }
  313. menudefault = get_default_menu_item(list);
  314. di_slist_free(list);
  315. /* Make debconf show the menu and get the user's choice. */
  316. debconf_settitle(debconf, "debian-installer/main-menu-title");
  317. debconf_capb(debconf);
  318. debconf_subst(debconf, MAIN_MENU, "MENU", menu);
  319. if (menudefault) {
  320. buf=menu_entry(debconf, menudefault);
  321. debconf_set(debconf, MAIN_MENU, buf);
  322. }
  323. else {
  324. di_log(DI_LOG_LEVEL_INFO, "no default menu item");
  325. modify_debconf_priority(LOWER);
  326. }
  327. menu_prio = menu_priority();
  328. debconf_input(debconf, debconf_priorities[menu_prio], MAIN_MENU);
  329. debconf_go(debconf);
  330. debconf_get(debconf, MAIN_MENU);
  331. s = strdup(debconf->value);
  332. /* Figure out which menu item was selected. */
  333. for (i = 0; i < num; i++) {
  334. p = package_array[i];
  335. buf = menu_entry(debconf, p);
  336. if (strcmp(buf, s) == 0) {
  337. ret = p;
  338. break;
  339. }
  340. }
  341. if (! ret) {
  342. /* This could happen because of a debconf protocol problem
  343. * (for example, leading whitespace in menu items can
  344. * be stripped and confuse the comparisons), or other
  345. * problem. */
  346. di_log(DI_LOG_LEVEL_WARNING, "Internal error! Cannot find \"%s\" in menu.", s);
  347. }
  348. free(s);
  349. free(menu);
  350. free(package_array);
  351. return ret;
  352. }
  353. /*
  354. * Satisfy the dependencies of a virtual package. Its dependencies
  355. * that actually provide the package are presented in a debconf select
  356. * question for the user to pick and choose. Other dependencies are
  357. * just fed recursively through di_config_package.
  358. */
  359. static int satisfy_virtual(di_system_package *p) {
  360. di_slist_node *node;
  361. di_system_package *dep, *defpkg = NULL;
  362. char *menu, *s = NULL;
  363. const char *buf;
  364. size_t menu_size, menu_used, size;
  365. int is_menu_item = 0;
  366. menu = di_malloc(1024);
  367. menu[0] = '\0';
  368. menu_size = 1024;
  369. menu_used = 1;
  370. /* Compile a list of providing package. The default choice will be the
  371. * package with highest priority. If we have ties, menu items are
  372. * preferred. If we still have ties, the default choice is arbitrary */
  373. for (node = p->p.depends.head; node; node = node->next) {
  374. di_package_dependency *d = node->data;
  375. dep = (di_system_package *)d->ptr;
  376. if (d->type == di_package_dependency_type_depends) {
  377. /* Non-providing dependency */
  378. di_log(DI_LOG_LEVEL_DEBUG, "non-providing dependency from %s to %s", p->p.package, dep->p.package);
  379. if (dep->p.status != di_package_status_installed) {
  380. switch (di_config_package(dep, satisfy_virtual)) {
  381. case -1:
  382. di_free(menu);
  383. return -1;
  384. case EXIT_BACKUP:
  385. di_free(menu);
  386. return EXIT_BACKUP;
  387. }
  388. }
  389. continue;
  390. }
  391. if (d->type != di_package_dependency_type_reverse_provides)
  392. continue;
  393. if (dep->p.status == di_package_status_installed) {
  394. /* This means that a providing package is already
  395. * configure. So we short-circuit. */
  396. menu_used = 0;
  397. break;
  398. }
  399. if (defpkg == NULL || dep->p.priority > defpkg->p.priority ||
  400. (dep->p.priority == defpkg->p.priority &&
  401. dep->installer_menu_item < defpkg->installer_menu_item))
  402. defpkg = dep;
  403. /* This only makes sense if one of the dependencies
  404. * is a menu item */
  405. if (dep->installer_menu_item)
  406. is_menu_item = 1;
  407. buf = choices_escape(menu_entry(debconf, dep));
  408. size = strlen(buf);
  409. if (menu_used + size + 2 > menu_size)
  410. {
  411. menu_size += 1024;
  412. menu = di_realloc(menu, menu_size);
  413. }
  414. if (dep == defpkg) {
  415. /* We want the default to be the first item */
  416. char *temp;
  417. temp = di_malloc (menu_size);
  418. strcpy(temp, menu);
  419. strcpy(menu, buf);
  420. if (strlen(temp)) {
  421. strcat(menu, ", ");
  422. strcat(menu, temp);
  423. }
  424. di_free(temp);
  425. } else {
  426. if (strlen(menu)) {
  427. strcat(menu, ", ");
  428. }
  429. strcat(menu, buf);
  430. }
  431. menu_used += size + 2;
  432. }
  433. if (menu_used >= 2)
  434. menu[menu_used-2] = '\0';
  435. if (menu_used > 1) {
  436. if (is_menu_item) {
  437. char *priority = "medium";
  438. /* Only let the user choose if one of them is a menu item */
  439. if (defpkg != NULL) {
  440. buf = menu_entry(debconf, defpkg);
  441. debconf_set(debconf, MISSING_PROVIDE, buf);
  442. } else {
  443. /* TODO: How to figure out a default? */
  444. priority = "critical";
  445. }
  446. debconf_capb(debconf, "backup");
  447. debconf_subst(debconf, MISSING_PROVIDE, "CHOICES", menu);
  448. debconf_input(debconf, priority, MISSING_PROVIDE);
  449. if (debconf_go(debconf) != 0) {
  450. di_free(menu);
  451. return 0;
  452. }
  453. debconf_capb(debconf);
  454. debconf_get(debconf, MISSING_PROVIDE);
  455. s = strdup(debconf->value);
  456. }
  457. /* Go through the dependencies again */
  458. for (node = p->p.depends.head; node; node = node->next) {
  459. di_package_dependency *d = node->data;
  460. dep = (di_system_package *)d->ptr;
  461. buf = menu_entry(debconf, dep);
  462. if (!is_menu_item || strcmp(s, buf) == 0) {
  463. /* Ick. If we have a menu item it has to match the
  464. * debconf choice, otherwise we configure all of
  465. * the providing packages */
  466. switch (di_config_package(dep, satisfy_virtual)) {
  467. case -1:
  468. di_free(menu);
  469. free(s);
  470. return -1;
  471. case EXIT_BACKUP:
  472. di_free(menu);
  473. free(s);
  474. return EXIT_BACKUP;
  475. }
  476. if (is_menu_item)
  477. break;
  478. }
  479. }
  480. }
  481. di_free(menu);
  482. free(s);
  483. /* It doesn't make sense to configure virtual packages,
  484. * since they are, well, virtual. */
  485. p->p.status = di_package_status_installed;
  486. return 1;
  487. }
  488. static void set_package_title(di_system_package *p) {
  489. char *title;
  490. if (!p->installer_menu_item)
  491. return;
  492. title = xasprintf("debian-installer/%s/title", p->p.package);
  493. if (debconf_settitle(debconf, title))
  494. di_log(DI_LOG_LEVEL_WARNING, "Unable to set title for %s.", p->p.package);
  495. free(title);
  496. }
  497. static int do_menu_item(di_system_package *p) {
  498. di_log(DI_LOG_LEVEL_INFO, "Menu item '%s' selected", p->p.package);
  499. return di_config_package(p, satisfy_virtual);
  500. }
  501. static void modify_debconf_priority (int raise_or_lower) {
  502. int pri;
  503. const char *template = "debconf/priority";
  504. debconf_get(debconf, template);
  505. pri = debconf_to_pri(debconf->value);
  506. if ( pri == -1 )
  507. pri = 1;
  508. if (raise_or_lower == LOWER) {
  509. --pri;
  510. /* Make sure the menu is always displayed after an error */
  511. display_menu = 1;
  512. }
  513. else if (raise_or_lower == RAISE)
  514. ++pri;
  515. if (0 > pri)
  516. pri = 0;
  517. if (pri > default_priority)
  518. pri = default_priority;
  519. if (local_priority != pri) {
  520. if (local_priority > -1)
  521. di_log(DI_LOG_LEVEL_INFO, "Modifying debconf priority limit from '%s' to '%s'",
  522. debconf->value ? debconf->value : "(null)",
  523. debconf_priorities[pri] ? debconf_priorities[pri] : "(null)");
  524. local_priority = pri;
  525. debconf_set(debconf, template, debconf_priorities[pri]);
  526. }
  527. }
  528. static void adjust_default_priority (void) {
  529. int pri;
  530. const char *template = "debconf/priority";
  531. debconf_get(debconf, template);
  532. pri = debconf_to_pri(debconf->value);
  533. if (pri > -1 && pri != local_priority) {
  534. if (local_priority > -1)
  535. di_log(DI_LOG_LEVEL_INFO, "Priority changed externally, setting main-menu default to '%s' (%s)",
  536. debconf_priorities[pri] ? debconf_priorities[pri] : "(null)", debconf->value);
  537. local_priority = pri;
  538. default_priority = pri;
  539. }
  540. }
  541. static void restore_default_priority (void) {
  542. const char *template = "debconf/priority";
  543. if (local_priority != default_priority) {
  544. di_log(DI_LOG_LEVEL_INFO, "Restoring default debconf priority '%s'",
  545. debconf_priorities[default_priority] ? debconf_priorities[default_priority] : "(null)");
  546. debconf_set(debconf, template, debconf_priorities[default_priority]);
  547. local_priority = default_priority;
  548. }
  549. }
  550. void notify_user_of_failure (di_system_package *p) {
  551. const char *buf;
  552. set_package_title(p);
  553. debconf_capb(debconf);
  554. buf = menu_entry(debconf, p);
  555. debconf_subst(debconf, ITEM_FAILURE, "ITEM", buf);
  556. debconf_input(debconf, "critical", ITEM_FAILURE);
  557. debconf_go(debconf);
  558. debconf_capb(debconf, "backup");
  559. }
  560. /* Cheap-and-cheerful run-parts-a-like for /lib/main-menu.d. Allows packages
  561. * to register scripts to be run at main-menu startup that need to share
  562. * main-menu's debconf frontend but that don't merit a menu item, such as
  563. * setting an info message.
  564. */
  565. static void menu_startup (void) {
  566. struct dirent **namelist;
  567. int entries, i;
  568. /* scandir() isn't POSIX, but it makes things easy. */
  569. entries = scandir(MAIN_MENU_DIR, &namelist, NULL, alphasort);
  570. if (entries < 0)
  571. return;
  572. for (i = 0; i < entries; ++i) {
  573. size_t len;
  574. char *filename;
  575. struct stat st;
  576. int ret;
  577. if (strcmp(namelist[i]->d_name, ".") == 0 || strcmp(namelist[i]->d_name, "..") == 0)
  578. continue;
  579. /* sizeof(MAIN_MENU_DIR) includes trailing \0 */
  580. len = sizeof(MAIN_MENU_DIR) + 1 + strlen(namelist[i]->d_name);
  581. filename = di_new(char, len);
  582. snprintf(filename, len, "%s/%s", MAIN_MENU_DIR, namelist[i]->d_name);
  583. if (stat(filename, &st) != 0) {
  584. di_log(DI_LOG_LEVEL_WARNING, "Can't stat %s (%s)", filename, strerror(errno));
  585. di_free(filename);
  586. continue;
  587. }
  588. if (!S_ISREG(st.st_mode)) {
  589. di_log(DI_LOG_LEVEL_WARNING, "%s is not a regular file", filename);
  590. di_free(filename);
  591. continue;
  592. }
  593. if (access(filename, X_OK) != 0) {
  594. di_log(DI_LOG_LEVEL_WARNING, "%s is not executable", filename);
  595. di_free(filename);
  596. continue;
  597. }
  598. //di_log(DI_LOG_LEVEL_DEBUG, "Executing %s", filename);
  599. ret = system(filename);
  600. if (ret != 0)
  601. di_log(DI_LOG_LEVEL_WARNING, "%s exited with status %d", filename, ret);
  602. di_free(filename);
  603. }
  604. }
  605. int main (int argc __attribute__ ((unused)), char **argv) {
  606. di_system_package *p;
  607. di_packages *packages;
  608. di_packages_allocator *allocator;
  609. int ret, exit_loop;
  610. debconf = debconfclient_new();
  611. di_system_init(basename(argv[0]));
  612. /* Tell udpkg to shut up. */
  613. setenv("UDPKG_QUIET", "y", 1);
  614. /* Make cdebconf honour currently set language */
  615. const char *template = "debconf/language";
  616. if (debconf_get(debconf, template) == CMD_SUCCESS &&
  617. debconf->value && *debconf->value)
  618. debconf_set(debconf, template, debconf->value);
  619. /* Initialize internal priority variables */
  620. adjust_default_priority();
  621. menu_startup();
  622. seen_items = di_hash_table_new_full(di_rstring_hash, di_rstring_equal,
  623. seen_items_key_destroy, NULL);
  624. notinstallables = di_hash_table_new_full(di_rstring_hash, di_rstring_equal,
  625. notinstallables_key_destroy, NULL);
  626. exit_loop = 0;
  627. allocator = di_system_packages_allocator_alloc ();
  628. packages = di_system_packages_status_read_file(DI_SYSTEM_DPKG_STATUSFILE, allocator);
  629. while (!exit_loop && (p=show_main_menu(packages, allocator))) {
  630. di_slist_node *node;
  631. if (p->installer_menu_item < NEVERDEFAULT && display_menu) {
  632. display_menu = 0;
  633. }
  634. ret = do_menu_item(p);
  635. adjust_default_priority();
  636. switch (ret) {
  637. case EXIT_OK:
  638. /* Success */
  639. if (p->installer_menu_item < NEVERDEFAULT) {
  640. last_successful_item = p->installer_menu_item;
  641. restore_default_priority();
  642. //di_log(DI_LOG_LEVEL_DEBUG, "Installed package '%s', raising last_successful_item to %d", p->p.package, p->installer_menu_item);
  643. }
  644. else {
  645. // di_log(DI_LOG_LEVEL_DEBUG, "Installed package '%s' but no raise since %d >= %i", p->p.package, p->installer_menu_item, NEVERDEFAULT);
  646. }
  647. break;
  648. case EXIT_BACKUP:
  649. di_log(DI_LOG_LEVEL_INFO, "Menu item '%s' succeeded but requested to be left unconfigured.", p->p.package);
  650. display_menu = 1;
  651. break;
  652. case EXIT_INSTALLER:
  653. /* Interrupt the loop and exit properly */
  654. exit_loop = 1;
  655. break;
  656. default:
  657. di_log(DI_LOG_LEVEL_WARNING, "Menu item '%s' failed.", p->p.package);
  658. notify_user_of_failure(p);
  659. modify_debconf_priority(LOWER);
  660. }
  661. /* Remember all the packages we've seen so far */
  662. for (node = packages->list.head; node; node = node->next) {
  663. di_system_package *seen = node->data;
  664. di_rstring *seen_name = di_new0(di_rstring, 1);
  665. seen_name->string = di_stradup(seen->p.key.string,
  666. seen->p.key.size);
  667. seen_name->size = seen->p.key.size;
  668. if (! di_hash_table_lookup(notinstallables, &seen->p.key))
  669. di_hash_table_insert(seen_items, seen_name, seen_name);
  670. }
  671. di_packages_free (packages);
  672. di_packages_allocator_free (allocator);
  673. allocator = di_system_packages_allocator_alloc ();
  674. packages = di_system_packages_status_read_file(DI_SYSTEM_DPKG_STATUSFILE, allocator);
  675. /* tell cdebconf to save the database */
  676. debconf_x_save(debconf);
  677. }
  678. return exit_loop != 0 ? EXIT_OK : EXIT_FAILURE;
  679. }
  680. int di_config_package_depth=0;
  681. /*
  682. * Configure all dependencies, special case for virtual packages.
  683. * This is done depth-first.
  684. */
  685. static int di_config_package(di_system_package *p,
  686. int (*virtfunc)(di_system_package *)) {
  687. char *configcommand;
  688. int ret;
  689. di_slist_node *node;
  690. di_system_package *dep;
  691. //di_log(DI_LOG_LEVEL_DEBUG, "configure %s, status: %d", p->p.package, p->p.status);
  692. if (p->p.type == di_package_type_virtual_package) {
  693. //di_log(DI_LOG_LEVEL_DEBUG, "virtual package %s", p->p.package);
  694. if (virtfunc)
  695. return virtfunc(p);
  696. else
  697. return -1;
  698. }
  699. else if (p->p.type == di_package_type_non_existent)
  700. return 0;
  701. for (node = p->p.depends.head; node; node = node->next) {
  702. di_package_dependency *d = node->data;
  703. dep = (di_system_package *)d->ptr;
  704. if (dep->p.status == di_package_status_installed)
  705. continue;
  706. if (d->type != di_package_dependency_type_depends)
  707. continue;
  708. /* Recursively configure this package */
  709. di_config_package_depth++;
  710. if (di_config_package_depth > 1000) {
  711. di_log(DI_LOG_LEVEL_WARNING, "Deep recursion configuring package %s (dep loop?)", p->p.package);
  712. return -1;
  713. }
  714. ret = di_config_package(dep, virtfunc);
  715. di_config_package_depth--;
  716. switch (ret) {
  717. case -1:
  718. return -1;
  719. case EXIT_BACKUP:
  720. return EXIT_BACKUP;
  721. }
  722. }
  723. set_package_title(p);
  724. if (asprintf(&configcommand, "exec udpkg --configure --force-configure %s", p->p.package) == -1)
  725. return -1;
  726. ret = di_exec_shell_log(configcommand);
  727. ret = di_exec_mangle_status(ret);
  728. free(configcommand);
  729. switch (ret) {
  730. case EXIT_OK:
  731. case EXIT_INSTALLER:
  732. p->p.status = di_package_status_installed;
  733. break;
  734. default:
  735. di_log(DI_LOG_LEVEL_WARNING, "Configuring '%s' failed with error code %d", p->p.package, ret);
  736. ret = -1;
  737. case EXIT_BACKUP:
  738. p->p.status = di_package_status_half_configured;
  739. break;
  740. }
  741. return ret;
  742. }
  743. /* vim: noexpandtab sw=8
  744. */