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.

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