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.
 
 
 
 

992 lines
24 KiB

  1. #include <debian-installer.h>
  2. #include <cdebconf/debconfclient.h>
  3. #include <errno.h>
  4. #include <stdarg.h>
  5. #include <string.h>
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include <assert.h>
  9. #include "mirrors.h"
  10. #ifdef WITH_HTTP
  11. #include "mirrors_http.h"
  12. #endif
  13. #ifdef WITH_HTTPS
  14. #include "mirrors_https.h"
  15. #endif
  16. #ifdef WITH_FTP
  17. #include "mirrors_ftp.h"
  18. #endif
  19. #if ! defined (WITH_HTTP) && ! defined (WITH_FTP)
  20. #error Must compile with at least one of FTP or HTTP
  21. #endif
  22. #if defined (WITH_FTP) && defined (WITH_FTP_MANUAL)
  23. #error Only one of WITH_FTP and WITH_FTP_MANUAL can be defined
  24. #endif
  25. #define MAX_PROTOCOLS 3
  26. static struct debconfclient *debconf;
  27. static char *protocol = NULL;
  28. static char *country = NULL;
  29. int show_progress = 1;
  30. /* Are we installing from a CD that includes base system packages? */
  31. static int base_on_cd = 0;
  32. /* Available releases (suite/codename) on the mirror. */
  33. static struct release_t releases[MAXRELEASES];
  34. static char *xasprintf(const char *format, ...)
  35. {
  36. va_list args;
  37. char *result;
  38. va_start(args, format);
  39. if (vasprintf(&result, format, args) < 0) {
  40. if (errno == ENOMEM) {
  41. fputs("Out of memory!\n", stderr);
  42. abort();
  43. }
  44. return NULL;
  45. }
  46. return result;
  47. }
  48. /*
  49. * Returns a string on the form "DEBCONF_BASE/protocol/supplied". The
  50. * calling function is responsible for freeing the string afterwards.
  51. */
  52. static char *add_protocol(char *string) {
  53. char *ret;
  54. assert(protocol != NULL); /* Fetched by choose_protocol */
  55. ret = xasprintf(DEBCONF_BASE "%s/%s", protocol, string);
  56. return ret;
  57. }
  58. /*
  59. * Generates a list, suitable to be passed into debconf, from a
  60. * NULL-terminated string array.
  61. */
  62. static char *debconf_list(char *list[]) {
  63. int len, i, size = 1;
  64. char *ret = 0;
  65. for (i = 0; list[i] != NULL; i++) {
  66. len = strlen(list[i]);
  67. size += len;
  68. ret = realloc(ret, size + 2);
  69. memcpy(ret + size - len - 1, list[i], len);
  70. if (list[i+1] != NULL) {
  71. ret[size++ - 1] = ',';
  72. ret[size++ - 1] = ' ';
  73. }
  74. ret[size -1] = '\0';
  75. }
  76. return ret;
  77. }
  78. /*
  79. * Returns the correct mirror list, depending on the value of "protocol".
  80. * Do NOT free the structure - it is a pointer to the static list in
  81. * mirrors_protocol.h.
  82. */
  83. static struct mirror_t *mirror_list(void) {
  84. assert(protocol != NULL);
  85. #ifdef WITH_HTTP
  86. if (strcasecmp(protocol, "http") == 0)
  87. return mirrors_http;
  88. #endif
  89. #ifdef WITH_HTTPS
  90. if (strcasecmp(protocol, "https") == 0)
  91. return mirrors_https;
  92. #endif
  93. #ifdef WITH_FTP
  94. if (strcasecmp(protocol, "ftp") == 0)
  95. return mirrors_ftp;
  96. #endif
  97. return 0; // should never happen
  98. }
  99. /* Returns an array of hostnames of mirrors in the specified country
  100. * or using GeoDNS. */
  101. static char **mirrors_in(char *country) {
  102. static char **ret;
  103. int i, j, num = 1;
  104. struct mirror_t *mirrors = mirror_list();
  105. ret = malloc(num * sizeof(char *));
  106. for (i = j = 0; mirrors[i].site != NULL; i++) {
  107. if (j == num - 1) {
  108. num *= 2;
  109. ret = realloc(ret, num * sizeof(char*));
  110. }
  111. if (! mirrors[i].country ||
  112. strcmp(mirrors[i].country, country) == 0)
  113. ret[j++] = mirrors[i].site;
  114. }
  115. ret[j] = NULL;
  116. return ret;
  117. }
  118. /* returns true if there is a mirror in the specified country */
  119. static inline int has_mirror(char *country) {
  120. char **mirrors;
  121. if (strcmp(country, MANUAL_ENTRY) == 0)
  122. return 1;
  123. mirrors = mirrors_in(country);
  124. return (mirrors[0] == NULL) ? 0 : 1;
  125. }
  126. /* Returns the root of the mirror, given the hostname. */
  127. static char *mirror_root(char *mirror) {
  128. int i;
  129. struct mirror_t *mirrors = mirror_list();
  130. for (i = 0; mirrors[i].site != NULL; i++)
  131. if (strcmp(mirrors[i].site, mirror) == 0)
  132. return mirrors[i].root;
  133. return NULL;
  134. }
  135. /*
  136. * Get the default suite (can be a codename) to use; this is either a
  137. * preseeded value or a value set at build time.
  138. */
  139. static char *get_default_suite(void) {
  140. char *suite = NULL;
  141. FILE *f = NULL;
  142. char buf[SUITE_LENGTH];
  143. debconf_get(debconf, DEBCONF_BASE "suite");
  144. if (strlen(debconf->value) > 0) {
  145. /* Use preseeded or previously selected value. */
  146. suite = strdup(debconf->value);
  147. } else {
  148. /* Check for default suite/codename set at build time. */
  149. f = fopen("/etc/default-release", "r");
  150. if (f != NULL) {
  151. if (fgets(buf, SUITE_LENGTH - 1, f)) {
  152. if (buf[strlen(buf) - 1] == '\n')
  153. buf[strlen(buf) - 1] = '\0';
  154. suite = strdup(buf);
  155. }
  156. fclose(f);
  157. }
  158. }
  159. return suite;
  160. }
  161. /*
  162. * Unset most relevant seen flags to allow to correct preseeded values
  163. * when mirror is bad.
  164. */
  165. void unset_seen_flags(void) {
  166. char *hostname, *directory;
  167. hostname = add_protocol("hostname");
  168. debconf_fset(debconf, hostname, "seen", "false");
  169. free(hostname);
  170. directory = add_protocol("directory");
  171. debconf_fset(debconf, directory, "seen", "false");
  172. free(directory);
  173. debconf_fset(debconf, DEBCONF_BASE "country", "seen", "false");
  174. debconf_fset(debconf, DEBCONF_BASE "suite", "seen", "false");
  175. }
  176. void log_invalid_release(const char *name, const char *field) {
  177. di_log(DI_LOG_LEVEL_WARNING,
  178. "broken mirror: invalid %s in Release file for %s", field, name);
  179. }
  180. static int get_release(struct release_t *release, const char *name);
  181. /*
  182. * Cross-validate Release file by checking if it can also be accessed using
  183. * its codename if we got it using a suite and vice versa; if successful,
  184. * check that it really matches the earlier Release file.
  185. * Returns false only if an invalid Release file was found.
  186. */
  187. static int cross_validate_release(struct release_t *release) {
  188. struct release_t t_release;
  189. int ret = 1;
  190. memset(&t_release, 0, sizeof(t_release));
  191. /* Preset status field to prevent endless recursion. */
  192. t_release.status = (release->status & (GET_SUITE | GET_CODENAME));
  193. /* Only one of the two following conditions can trigger. */
  194. if (release->suite != NULL && !(release->status & GET_SUITE)) {
  195. /* Cross-validate the suite */
  196. if (get_release(&t_release, release->suite)) {
  197. if ((t_release.status & IS_VALID) &&
  198. strcmp(t_release.name, release->name) == 0) {
  199. release->status |= (t_release.status & GET_SUITE);
  200. } else {
  201. release->status &= ~IS_VALID;
  202. ret = 0;
  203. }
  204. }
  205. }
  206. if (release->name != NULL && !(release->status & GET_CODENAME)) {
  207. /* Cross-validate the codename (release->name) */
  208. if (get_release(&t_release, release->name)) {
  209. if ((t_release.status & IS_VALID) &&
  210. strcmp(t_release.suite, release->suite) == 0) {
  211. release->status |= (t_release.status & GET_CODENAME);
  212. } else {
  213. release->status &= ~IS_VALID;
  214. ret = 0;
  215. }
  216. }
  217. }
  218. free(t_release.name);
  219. free(t_release.suite);
  220. free(t_release.archs);
  221. return ret;
  222. }
  223. int cached_wget_is_gnu = -1;
  224. static int wget_is_gnu(void) {
  225. if (cached_wget_is_gnu == -1)
  226. cached_wget_is_gnu = (system("wget --version 2>/dev/null | grep -q 'GNU Wget'") == 0) ? 1 : 0;
  227. return cached_wget_is_gnu;
  228. }
  229. char *append(char *str, const char *suffix) {
  230. size_t len, newlen;
  231. len = strlen (str);
  232. newlen = len + strlen(suffix);
  233. str = di_realloc(str, newlen + 1);
  234. strcpy(str + len, suffix);
  235. return str;
  236. }
  237. char *get_wget_options(void) {
  238. char *options;
  239. if (wget_is_gnu()) {
  240. options = strdup("--no-verbose");
  241. if (strcasecmp(protocol, "https") == 0) {
  242. debconf_get(debconf, "debian-installer/allow_unauthenticated_ssl");
  243. if (strcmp(debconf->value, "true") == 0)
  244. options = append(options, " --no-check-certificate");
  245. }
  246. } else {
  247. if (strcasecmp(protocol, "https") == 0)
  248. /* We shouldn't normally get here, but let's make it
  249. * easier to debug in case somebody has hit us over
  250. * the head with preseeding.
  251. */
  252. fputs("busybox wget does not support https\n", stderr);
  253. options = strdup("-q");
  254. }
  255. return options;
  256. }
  257. /*
  258. * Fetch a Release file, extract its Suite and Codename and check its valitity.
  259. */
  260. static int get_release(struct release_t *release, const char *name) {
  261. char *command;
  262. FILE *f = NULL;
  263. char *wget_options, *hostname, *directory;
  264. char line[BUFFER_LENGTH];
  265. char *p;
  266. char buf[BUFFER_LENGTH];
  267. hostname = add_protocol("hostname");
  268. debconf_get(debconf, hostname);
  269. free(hostname);
  270. hostname = strdup(debconf->value);
  271. directory = add_protocol("directory");
  272. debconf_get(debconf, directory);
  273. free(directory);
  274. directory = strdup(debconf->value);
  275. /* remove trailing slashes */
  276. for (p = directory + strlen(directory) - 1;
  277. p >= directory && p[0] == '/';
  278. p--) {
  279. p[0] = '\0';
  280. }
  281. wget_options = get_wget_options();
  282. command = xasprintf("wget %s %s://%s%s/dists/%s/Release -O - | grep -E '^(Suite|Codename|Architectures):'",
  283. wget_options, protocol, hostname, directory, name);
  284. di_log(DI_LOG_LEVEL_DEBUG, "command: %s", command);
  285. f = popen(command, "r");
  286. free(command);
  287. free(wget_options);
  288. free(hostname);
  289. free(directory);
  290. if (f != NULL) {
  291. while (fgets(line, sizeof(line), f) != NULL) {
  292. char *value;
  293. if (line[strlen(line) - 1] == '\n')
  294. line[strlen(line) - 1] = '\0';
  295. if ((value = strstr(line, ": ")) != NULL) {
  296. strncpy(buf, value + 2, BUFFER_LENGTH - 1);
  297. buf[BUFFER_LENGTH - 1] = '\0';
  298. if (strncmp(line, "Codename:", 9) == 0)
  299. release->name = strdup(buf);
  300. if (strncmp(line, "Suite:", 6) == 0)
  301. release->suite = strdup(buf);
  302. if (strncmp(line, "Architectures:", 14) == 0)
  303. release->archs = strdup(buf);
  304. }
  305. }
  306. if (release->name != NULL && strcmp(release->name, name) == 0)
  307. release->status |= IS_VALID | GET_CODENAME;
  308. if (release->suite != NULL && strcmp(release->suite, name) == 0)
  309. release->status |= IS_VALID | GET_SUITE;
  310. if ((release->name != NULL || release->suite != NULL) &&
  311. !(release->status & IS_VALID))
  312. log_invalid_release(name, "Suite or Codename");
  313. /* Does the release include this arch? */
  314. if (release->archs != NULL && strstr(release->archs, ARCH_TEXT) == NULL) {
  315. /* No: disregard this release */
  316. log_invalid_release(name, "Architectures");
  317. release->status &= ~IS_VALID;
  318. free(release->archs);
  319. free(release->name);
  320. release->name = NULL;
  321. }
  322. /* Cross-validate the Release file */
  323. if (release->status & IS_VALID)
  324. if (! cross_validate_release(release))
  325. log_invalid_release(name, (release->status & GET_SUITE) ? "Codename" : "Suite");
  326. /* In case there is no Codename field */
  327. if ((release->status & IS_VALID) && release->name == NULL)
  328. release->name = strdup(name);
  329. // di_log(DI_LOG_LEVEL_DEBUG, "get_release(): %s -> %s:%s (0x%x)",
  330. // name, release->suite, release->name, release->status);
  331. }
  332. pclose(f);
  333. if (release->name != NULL) {
  334. return 1;
  335. } else {
  336. free(release->suite);
  337. return 0;
  338. }
  339. }
  340. static int find_releases(void) {
  341. int nbr_suites = sizeof(suites)/SUITE_LENGTH;
  342. int i, r = 0;
  343. int bad_mirror = 0, have_default = 0;
  344. struct release_t release;
  345. char *default_suite;
  346. default_suite = get_default_suite();
  347. if (default_suite == NULL)
  348. di_log(DI_LOG_LEVEL_ERROR, "no default release specified");
  349. if (show_progress) {
  350. debconf_progress_start(debconf, 0, nbr_suites,
  351. DEBCONF_BASE "checking_title");
  352. debconf_progress_info(debconf,
  353. DEBCONF_BASE "checking_download");
  354. }
  355. /* Initialize releases; also ensures NULL termination of the array */
  356. memset(&releases, 0, sizeof(releases));
  357. /* Try to get Release files for all suites. */
  358. if (! base_on_cd) {
  359. for (i=0; i < nbr_suites && r < MAXRELEASES; i++) {
  360. memset(&release, 0, sizeof(release));
  361. if (get_release(&release, suites[i])) {
  362. if (release.status & IS_VALID) {
  363. if (strcmp(release.name, default_suite) == 0 ||
  364. strcmp(release.suite, default_suite) == 0) {
  365. release.status |= IS_DEFAULT;
  366. have_default = 1;
  367. }
  368. /* Only list oldstable if it's the default */
  369. if (strcmp(suites[i], "oldstable") != 0 ||
  370. (release.status & IS_DEFAULT))
  371. releases[r++] = release;
  372. } else {
  373. bad_mirror = 1;
  374. break;
  375. }
  376. }
  377. if (show_progress)
  378. debconf_progress_step(debconf, 1);
  379. }
  380. if (r == MAXRELEASES)
  381. di_log(DI_LOG_LEVEL_ERROR, "array overflow: more releases than allowed by MAXRELEASES");
  382. if (! bad_mirror && r == 0)
  383. di_log(DI_LOG_LEVEL_INFO, "mirror does not have any suite symlinks");
  384. }
  385. /* Try to get Release file using the default "suite". */
  386. if (! bad_mirror && (base_on_cd || ! have_default)) {
  387. memset(&release, 0, sizeof(release));
  388. if (get_release(&release, default_suite)) {
  389. if (release.status & IS_VALID) {
  390. release.status |= IS_DEFAULT;
  391. releases[r++] = release;
  392. have_default = 1;
  393. } else {
  394. bad_mirror = 1;
  395. }
  396. } else {
  397. di_log(DI_LOG_LEVEL_WARNING,
  398. "mirror does not support the specified release (%s)",
  399. default_suite);
  400. }
  401. if (r == MAXRELEASES)
  402. di_log(DI_LOG_LEVEL_ERROR, "array overflow: more releases than allowed by MAXRELEASES");
  403. }
  404. if (show_progress) {
  405. debconf_progress_set(debconf, nbr_suites);
  406. debconf_progress_stop(debconf);
  407. }
  408. if (r == 0 || bad_mirror) {
  409. unset_seen_flags();
  410. free(default_suite);
  411. free(release.name);
  412. free(release.suite);
  413. free(release.archs);
  414. debconf_input(debconf, "critical", DEBCONF_BASE "bad");
  415. if (debconf_go(debconf) == 30)
  416. exit(10); /* back up to menu */
  417. else
  418. return 1; /* back to beginning of questions */
  419. }
  420. if (! base_on_cd && ! have_default) {
  421. unset_seen_flags();
  422. debconf_subst(debconf, DEBCONF_BASE "no-default",
  423. "RELEASE", default_suite);
  424. free(default_suite);
  425. debconf_input(debconf, "critical", DEBCONF_BASE "no-default");
  426. if (debconf_go(debconf) == 30) {
  427. exit(10); /* back up to menu */
  428. } else {
  429. debconf_get(debconf, DEBCONF_BASE "no-default");
  430. if (strcmp(debconf->value, "false"))
  431. return 1; /* back to beginning of questions */
  432. }
  433. } else {
  434. free(default_suite);
  435. }
  436. return 0;
  437. }
  438. /* Try to get translation for suite names */
  439. static char *l10n_suite(const char *name) {
  440. char *template, *l10n_name;
  441. template = xasprintf("%ssuites/%s", DEBCONF_BASE, name);
  442. if (! debconf_metaget(debconf, template, "description") &&
  443. strlen(debconf->value))
  444. l10n_name = strdup(debconf->value);
  445. else
  446. l10n_name = strdup(name);
  447. free(template);
  448. return l10n_name;
  449. }
  450. static int check_base_on_cd(void) {
  451. FILE *fp;
  452. if ((fp = fopen("/cdrom/.disk/base_installable", "r"))) {
  453. base_on_cd = 1;
  454. fclose(fp);
  455. }
  456. return 0;
  457. }
  458. static int fill_protocols(const char **protocols) {
  459. int i = 0;
  460. #ifdef WITH_HTTP
  461. protocols[i++] = "http";
  462. #endif
  463. #ifdef WITH_HTTPS
  464. if (wget_is_gnu())
  465. protocols[i++] = "https";
  466. #endif
  467. #if defined (WITH_FTP) || defined (WITH_FTP_MANUAL)
  468. protocols[i++] = "ftp";
  469. #endif
  470. protocols[i] = NULL;
  471. return i;
  472. }
  473. static int choose_protocol(void) {
  474. const char *protocols[MAX_PROTOCOLS + 1];
  475. int i;
  476. size_t len;
  477. char *choices;
  478. if (fill_protocols(protocols) <= 1)
  479. return 0;
  480. /* More than one protocol is supported, so ask. */
  481. len = strlen(protocols[0]);
  482. for (i = 1; protocols[i]; i++)
  483. len += 2 + strlen(protocols[i]);
  484. choices = di_malloc(len + 1);
  485. strcpy(choices, protocols[0]);
  486. for (i = 1; protocols[i]; i++) {
  487. strcat(choices, ", ");
  488. strcat(choices, protocols[i]);
  489. }
  490. debconf_subst(debconf, DEBCONF_BASE "protocol", "protocols", choices);
  491. di_free(choices);
  492. debconf_input(debconf, "medium", DEBCONF_BASE "protocol");
  493. return 0;
  494. }
  495. static int get_protocol(void) {
  496. const char *protocols[MAX_PROTOCOLS + 1];
  497. if (fill_protocols(protocols) > 1) {
  498. debconf_get(debconf, DEBCONF_BASE "protocol");
  499. protocol = strdup(debconf->value);
  500. } else {
  501. debconf_set(debconf, DEBCONF_BASE "protocol", protocols[0]);
  502. protocol = strdup(protocols[0]);
  503. }
  504. return 0;
  505. }
  506. static int choose_country(void) {
  507. if (country)
  508. free(country);
  509. country = NULL;
  510. #if defined (WITH_FTP_MANUAL)
  511. assert(protocol != NULL);
  512. if (strcasecmp(protocol, "ftp") == 0)
  513. return 0;
  514. #endif
  515. debconf_get(debconf, DEBCONF_BASE "country");
  516. if (! strlen(debconf->value)) {
  517. /* Not set yet. Seed with a default value. */
  518. if ((debconf_get(debconf, "debian-installer/country") == 0) &&
  519. (debconf->value != NULL) ) {
  520. country = strdup (debconf->value);
  521. debconf_set(debconf, DEBCONF_BASE "country", country);
  522. }
  523. } else {
  524. country = strdup(debconf->value);
  525. }
  526. /* Ensure 'country' is set to something. */
  527. if (country == NULL || *country == 0) {
  528. free(country);
  529. country = strdup("US");
  530. }
  531. char *countries;
  532. countries = add_protocol("countries");
  533. if (has_mirror(country)) {
  534. debconf_set(debconf, countries, country);
  535. debconf_fget(debconf, DEBCONF_BASE "country", "seen");
  536. debconf_fset(debconf, countries, "seen", debconf->value);
  537. }
  538. debconf_input(debconf, "high", countries);
  539. free (countries);
  540. return 0;
  541. }
  542. static int set_country(void) {
  543. char *countries;
  544. #if defined (WITH_FTP_MANUAL)
  545. assert(protocol != NULL);
  546. if (strcasecmp(protocol, "ftp") == 0)
  547. return 0;
  548. #endif
  549. countries = add_protocol("countries");
  550. debconf_get(debconf, countries);
  551. country = strdup(debconf->value);
  552. debconf_set(debconf, DEBCONF_BASE "country", country);
  553. free (countries);
  554. return 0;
  555. }
  556. static int manual_entry;
  557. static int choose_mirror(void) {
  558. char *list;
  559. debconf_get(debconf, DEBCONF_BASE "country");
  560. #ifndef WITH_FTP_MANUAL
  561. manual_entry = ! strcmp(debconf->value, MANUAL_ENTRY);
  562. #else
  563. if (! strcasecmp(protocol, "ftp") == 0)
  564. manual_entry = ! strcmp(debconf->value, MANUAL_ENTRY);
  565. else
  566. manual_entry = 1;
  567. #endif
  568. if (! manual_entry) {
  569. char *mir = add_protocol("mirror");
  570. /* Prompt for mirror in selected country. */
  571. list = debconf_list(mirrors_in(country));
  572. debconf_subst(debconf, mir, "mirrors", list);
  573. free(list);
  574. debconf_input(debconf, "high", mir);
  575. free(mir);
  576. } else {
  577. char *host = add_protocol("hostname");
  578. char *dir = add_protocol("directory");
  579. /* Manual entry. */
  580. debconf_input(debconf, "critical", host);
  581. debconf_input(debconf, "critical", dir);
  582. free(host);
  583. free(dir);
  584. }
  585. return 0;
  586. }
  587. /* Check basic validity of the selected/entered mirror. */
  588. static int validate_mirror(void) {
  589. char *mir;
  590. char *host;
  591. char *dir;
  592. int valid = 1;
  593. mir = add_protocol("mirror");
  594. host = add_protocol("hostname");
  595. dir = add_protocol("directory");
  596. if (! manual_entry) {
  597. char *mirror;
  598. char *root;
  599. /*
  600. * Copy information about the selected
  601. * mirror into mirror/{protocol}/{hostname,directory},
  602. * which is the standard location other
  603. * tools can look at.
  604. */
  605. debconf_get(debconf, mir);
  606. mirror = strdup(debconf->value);
  607. debconf_set(debconf, host, mirror);
  608. root = mirror_root(mirror);
  609. free(mirror);
  610. if (root == NULL)
  611. valid = 0;
  612. else
  613. debconf_set(debconf, dir, root);
  614. } else {
  615. /* check if manually entered mirror is basically ok */
  616. debconf_get(debconf, host);
  617. if (debconf->value == NULL || strcmp(debconf->value, "") == 0)
  618. valid = 0;
  619. else {
  620. const char *host_value = debconf->value;
  621. char *scheme_end = strstr(host_value, "://");
  622. if (scheme_end != NULL) {
  623. host_value = scheme_end + sizeof("://") - 1;
  624. debconf_set(debconf, host, host_value);
  625. }
  626. if (strchr(host_value, '/') != NULL)
  627. valid = 0;
  628. }
  629. debconf_get(debconf, dir);
  630. if (debconf->value == NULL || strcmp(debconf->value, "") == 0)
  631. valid = 0;
  632. }
  633. free(mir);
  634. free(host);
  635. free(dir);
  636. if (valid) {
  637. return 0;
  638. } else {
  639. unset_seen_flags();
  640. debconf_input(debconf, "critical", DEBCONF_BASE "bad");
  641. if (debconf_go(debconf) == 30)
  642. exit(10); /* back up to menu */
  643. else
  644. return 9; /* back up to choose_mirror */
  645. }
  646. }
  647. static int choose_proxy(void) {
  648. char *px = add_protocol("proxy");
  649. /* Always ask about a proxy. */
  650. debconf_input(debconf, "high", px);
  651. free(px);
  652. return 0;
  653. }
  654. static int set_proxy(void) {
  655. char *px = add_protocol("proxy");
  656. char *proxy_var;
  657. proxy_var = xasprintf("%s_proxy", protocol);
  658. debconf_get(debconf, px);
  659. if (debconf->value != NULL && strlen(debconf->value)) {
  660. if (strstr(debconf->value, "://")) {
  661. setenv(proxy_var, debconf->value, 1);
  662. } else {
  663. char *proxy_value;
  664. proxy_value = xasprintf("http://%s", debconf->value);
  665. setenv(proxy_var, proxy_value, 1);
  666. free(proxy_value);
  667. }
  668. } else {
  669. unsetenv(proxy_var);
  670. }
  671. free(proxy_var);
  672. free(px);
  673. return 0;
  674. }
  675. static int choose_suite(void) {
  676. char *choices_c[MAXRELEASES], *choices[MAXRELEASES], *list;
  677. int i, ret;
  678. int have_default = 0;
  679. ret = find_releases();
  680. if (ret)
  681. return ret;
  682. /* Also ensures NULL termination */
  683. memset(choices, 0, sizeof(choices));
  684. memset(choices_c, 0, sizeof(choices_c));
  685. /* Arrays can never overflow as we've already checked releases */
  686. for (i=0; releases[i].name != NULL; i++) {
  687. char *name;
  688. if (releases[i].status & GET_SUITE)
  689. name = releases[i].suite;
  690. else
  691. name = releases[i].name;
  692. choices_c[i] = name;
  693. if (strcmp(name, releases[i].name) != 0)
  694. choices[i] = xasprintf("%s${!TAB}-${!TAB}%s", releases[i].name,
  695. l10n_suite(name));
  696. else
  697. choices[i] = l10n_suite(name);
  698. if (releases[i].status & IS_DEFAULT) {
  699. debconf_set(debconf, DEBCONF_BASE "suite", name);
  700. have_default = 1;
  701. }
  702. }
  703. list = debconf_list(choices_c);
  704. debconf_subst(debconf, DEBCONF_BASE "suite", "CHOICES-C", list);
  705. free(list);
  706. list = debconf_list(choices);
  707. debconf_subst(debconf, DEBCONF_BASE "suite", "CHOICES", list);
  708. free(list);
  709. /* If the base system can be installed from CD, don't allow to
  710. * select a different suite
  711. */
  712. if (! have_default)
  713. debconf_fset(debconf, DEBCONF_BASE "suite", "seen", "false");
  714. if (! base_on_cd)
  715. debconf_input(debconf, have_default ? "medium" : "critical",
  716. DEBCONF_BASE "suite");
  717. return 0;
  718. }
  719. /* Set the codename for the selected suite. */
  720. int set_codename (void) {
  721. char *suite;
  722. int i;
  723. /* If preseed specifies codename, omit the codename check */
  724. debconf_get(debconf, DEBCONF_BASE "codename");
  725. if (! strlen(debconf->value)) {
  726. /* As suite has been determined previously, this should not fail */
  727. debconf_get(debconf, DEBCONF_BASE "suite");
  728. if (strlen(debconf->value) > 0) {
  729. suite = strdup(debconf->value);
  730. for (i=0; releases[i].name != NULL; i++) {
  731. if (strcmp(releases[i].name, suite) == 0 ||
  732. strcmp(releases[i].suite, suite) == 0) {
  733. char *codename;
  734. if (releases[i].status & GET_CODENAME)
  735. codename = releases[i].name;
  736. else
  737. codename = releases[i].suite;
  738. debconf_set(debconf, DEBCONF_BASE "codename", codename);
  739. di_log(DI_LOG_LEVEL_INFO,
  740. "suite/codename set to: %s/%s",
  741. suite, codename);
  742. break;
  743. }
  744. }
  745. free(suite);
  746. }
  747. }
  748. return 0;
  749. }
  750. /* Check if the mirror carries the architecture that's being installed. */
  751. int check_arch (void) {
  752. char *command;
  753. FILE *f = NULL;
  754. char *wget_options, *hostname, *directory, *codename = NULL;
  755. int valid = 0;
  756. hostname = add_protocol("hostname");
  757. debconf_get(debconf, hostname);
  758. free(hostname);
  759. hostname = strdup(debconf->value);
  760. directory = add_protocol("directory");
  761. debconf_get(debconf, directory);
  762. free(directory);
  763. directory = strdup(debconf->value);
  764. /* As codename has been determined previously, this should not fail */
  765. debconf_get(debconf, DEBCONF_BASE "codename");
  766. if (strlen(debconf->value) > 0) {
  767. codename = strdup(debconf->value);
  768. wget_options = get_wget_options();
  769. command = xasprintf("wget %s %s://%s%s/dists/%s/main/binary-%s/Release -O - | grep ^Architecture:",
  770. wget_options, protocol, hostname, directory, codename, ARCH_TEXT);
  771. di_log(DI_LOG_LEVEL_DEBUG, "command: %s", command);
  772. f = popen(command, "r");
  773. free(command);
  774. free(wget_options);
  775. if (f != NULL) {
  776. char buf[SUITE_LENGTH];
  777. if (fgets(buf, SUITE_LENGTH - 1, f))
  778. if (strlen(buf) > 1)
  779. valid = 1;
  780. }
  781. pclose(f);
  782. }
  783. free(hostname);
  784. free(directory);
  785. free(codename);
  786. if (valid) {
  787. return 0;
  788. } else {
  789. unset_seen_flags();
  790. di_log(DI_LOG_LEVEL_DEBUG, "architecture not supported by selected mirror");
  791. debconf_input(debconf, "critical", DEBCONF_BASE "noarch");
  792. if (debconf_go(debconf) == 30)
  793. exit(10); /* back up to menu */
  794. else
  795. return 1; /* back to beginning of questions */
  796. }
  797. }
  798. int main (int argc, char **argv) {
  799. int i;
  800. /* Use a state machine with a function to run in each state */
  801. int state = 0;
  802. int (*states[])() = {
  803. check_base_on_cd,
  804. choose_protocol,
  805. get_protocol,
  806. choose_country,
  807. set_country,
  808. choose_mirror,
  809. validate_mirror,
  810. choose_proxy,
  811. set_proxy,
  812. choose_suite,
  813. set_codename,
  814. check_arch,
  815. NULL,
  816. };
  817. if (argc > 1 && strcmp(argv[1], "-n") == 0)
  818. show_progress = 0;
  819. debconf = debconfclient_new();
  820. debconf_capb(debconf, "backup align");
  821. debconf_version(debconf, 2);
  822. di_system_init("choose-mirror");
  823. #ifdef WITH_HTTPS
  824. debconf_register(debconf, "mirror/http/mirror", "mirror/https/mirror");
  825. debconf_register(debconf,
  826. "mirror/http/hostname", "mirror/https/hostname");
  827. debconf_register(debconf,
  828. "mirror/http/directory", "mirror/https/directory");
  829. debconf_register(debconf, "mirror/http/proxy", "mirror/https/proxy");
  830. #endif
  831. while (state >= 0 && states[state]) {
  832. int res;
  833. res = states[state]();
  834. if (res == 9) /* back up */
  835. state--;
  836. else if (res) /* back up to start */
  837. state = 0;
  838. else if (debconf_go(debconf)) /* back up */
  839. state--;
  840. else
  841. state++;
  842. }
  843. for (i=0; releases[i].name != NULL; i++) {
  844. free(releases[i].name);
  845. free(releases[i].suite);
  846. free(releases[i].archs);
  847. }
  848. return (state >= 0) ? 0 : 10; /* backed all the way out */
  849. }