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.

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