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.

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