/* Check if the mirror carries the architecture that's being installed. */ int check_arch (void) { char *command; FILE *f = NULL; char *hostname, *directory, *suite = NULL; int valid = 0; hostname = add_protocol("hostname"); debconf_get(debconf, hostname); free(hostname); hostname = strdup(debconf->value); directory = add_protocol("directory"); debconf_get(debconf, directory); free(directory); directory = strdup(debconf->value); /* As suite has been determined previously, this should not fail */ debconf_get(debconf, DEBCONF_BASE "suite"); if (strlen(debconf->value) > 0) { suite = strdup(debconf->value); asprintf(&command, "wget -q %s://%s%s/dists/%s/main/binary-%s/Release -O - | grep Architecture", protocol, hostname, directory, suite, ARCH_TEXT); di_log(DI_LOG_LEVEL_DEBUG, "command: %s", command); f = popen(command, "r"); free(command); if (f != NULL) { char buf[SUITE_LENGTH]; if (fgets(buf, SUITE_LENGTH - 1, f)) if (strlen(buf) > 1) valid = 1; } pclose(f); } free(hostname); free(directory); if (suite) free(suite); if (valid) { return 0; } else { di_log(DI_LOG_LEVEL_DEBUG, "Architecture not supported by selected mirror"); debconf_input(debconf, "critical", DEBCONF_BASE "noarch"); if (debconf_go(debconf) == 30) exit(10); /* back up to menu */ else return 1; /* back to beginning of questions */ } }
/* Get the codename for the selected suite. */ int get_codename (void) { char *command; FILE *f = NULL; char *hostname, *directory, *suite = NULL; int ret = 1; hostname = add_protocol("hostname"); debconf_get(debconf, hostname); free(hostname); hostname = strdup(debconf->value); directory = add_protocol("directory"); debconf_get(debconf, directory); free(directory); directory = strdup(debconf->value); /* As suite has been determined previously, this should not fail */ debconf_get(debconf, DEBCONF_BASE "suite"); if (strlen(debconf->value) > 0) { suite = strdup(debconf->value); asprintf(&command, "wget -q %s://%s%s/dists/%s/Release -O - | grep ^Codename: | cut -d' ' -f 2", protocol, hostname, directory, suite); di_log(DI_LOG_LEVEL_DEBUG, "command: %s", command); f = popen(command, "r"); free(command); if (f != NULL) { char buf[SUITE_LENGTH]; if (fgets(buf, SUITE_LENGTH - 1, f)) { if (buf[strlen(buf) - 1] == '\n') buf[strlen(buf) - 1] = '\0'; debconf_set(debconf, DEBCONF_BASE "codename", buf); di_log(DI_LOG_LEVEL_INFO, "codename set to: %s", buf); ret = 0; } } pclose(f); } free(hostname); free(directory); if (suite) free(suite); if (ret != 0) di_log(DI_LOG_LEVEL_ERROR, "Error getting codename"); return ret; }
/* Gets the package list from the retriever and parses it. If a new default * retriever has been set, caches the file (except in low memory mode), will * use the cached file later when asked to install udebs using the default * retriever. */ di_packages *retriever_packages(di_packages_allocator *allocator) { di_packages *packages; char *command; int ret; if (! retriever_usecached) { command = xasprintf("%s packages " DOWNLOAD_PACKAGES, get_retriever()); ret = di_exec_shell_log(command); free(command); if (ret != 0) return NULL; packages = di_system_packages_read_file(DOWNLOAD_PACKAGES, allocator); } else { packages = di_system_packages_read_file(DOWNLOAD_PACKAGES_DEFAULT, allocator); } if (retriever_newdefault && packages) { rename(DOWNLOAD_PACKAGES, DOWNLOAD_PACKAGES_DEFAULT); } else { unlink(DOWNLOAD_PACKAGES); } if (!packages) { di_log(DI_LOG_LEVEL_ERROR, "can't find packages file"); } return packages; }
static int validate_mirror(void) { char *mir; char *host; char *dir; int valid; mir = add_protocol("mirror"); host = add_protocol("hostname"); dir = add_protocol("directory"); if (! manual_entry) { char *mirror; /* * Copy information about the selected * mirror into mirror/{protocol}/{hostname,directory}, * which is the standard location other * tools can look at. */ debconf_get(debconf, mir); mirror = strdup(debconf->value); debconf_set(debconf, host, mirror); debconf_set(debconf, dir, mirror_root(mirror)); free(mirror); if (base_on_cd) { /* We have the base system on the CD, so instead of * trying to contact the mirror (which might take * some time to time out if there's no network * connection), let's just assume that the CD will * be sufficient to get a basic system up, setting * suite to PREFERRED_DISTRIBUTION if unset and * codename = suite. Note that this is an * Ubuntu-specific change since (a) Debian netinst * CDs etc. may not be able to install a complete * system from the network and (b) codename != suite * in Debian. * * We only do this for mirrors in our mirror list, * since we assume that those have a good chance of * not being typoed. For manually-entered mirrors, * we still do full mirror validation. */ di_log(DI_LOG_LEVEL_INFO, "base system installable from CD; skipping mirror check"); debconf_get(debconf, DEBCONF_BASE "suite"); if (!*debconf->value) { di_log(DI_LOG_LEVEL_INFO, "falling back to suite %s", PREFERRED_DISTRIBUTION); debconf_set(debconf, DEBCONF_BASE "suite", PREFERRED_DISTRIBUTION); } debconf_get(debconf, DEBCONF_BASE "suite"); di_log(DI_LOG_LEVEL_INFO, "falling back to codename %s", debconf->value); debconf_set(debconf, DEBCONF_BASE "codename", debconf->value); exit(0); } valid = find_suite(); } else { /* check to see if the entered data is basically ok */ int ok = 1; debconf_get(debconf, host); if (debconf->value == NULL || strcmp(debconf->value, "") == 0 || strchr(debconf->value, '/') != NULL) { ok = 0; } debconf_get(debconf, dir); if (debconf->value == NULL || strcmp(debconf->value, "") == 0) { ok = 0; } if (ok) { valid = find_suite(); } else { valid = 0; } } free(mir); free(host); free(dir); if (valid) { return 0; } else { debconf_input(debconf, "critical", DEBCONF_BASE "bad"); if (debconf_go(debconf) == 30) exit(10); /* back up to menu */ else return 1; /* back to beginning of questions */ } }
/* * Using the current debconf settings for a mirror, figure out which suite * to use from the mirror and set mirror/suite. * * This is accomplished by downloading the Release file from the mirror. * Suite selection tries each suite in turn, and stops at the first one that * seems usable. * * If no Release file is found, returns false. That probably means the * mirror is broken or unreachable. */ int find_suite (void) { char *command; FILE *f = NULL; char *hostname, *directory; int nbr_suites = sizeof(suites)/SUITE_LENGTH; int i; int ret = 0; char buf[SUITE_LENGTH]; if (show_progress) { debconf_progress_start(debconf, 0, 1, DEBCONF_BASE "checking_title"); debconf_progress_info(debconf, DEBCONF_BASE "checking_download"); } hostname = add_protocol("hostname"); debconf_get(debconf, hostname); free(hostname); hostname = strdup(debconf->value); directory = add_protocol("directory"); debconf_get(debconf, directory); free(directory); directory = strdup(debconf->value); /* Try each suite in turn until one is found that works. */ for (i=0; i <= nbr_suites && ! ret; i++) { char *suite; if (i == 0) { /* First check for a preseeded suite. */ debconf_get(debconf, DEBCONF_BASE "suite"); if (strlen(debconf->value) > 0) { suite = strdup(debconf->value); } else { /* Read this file to find the default suite * to use. */ f = fopen("/etc/default-release", "r"); if (f != NULL) { if (fgets(buf, SUITE_LENGTH - 1, f)) { if (buf[strlen(buf) - 1] == '\n') buf[strlen(buf) - 1] = '\0'; suite = strdup(buf); fclose(f); } else { fclose(f); continue; } } else { continue; } } } else { suite = strdup(suites[i - 1]); } asprintf(&command, "wget -q %s://%s%s/dists/%s/Release -O - | grep ^Suite: | cut -d' ' -f 2", protocol, hostname, directory, suite); di_log(DI_LOG_LEVEL_DEBUG, "command: %s", command); f = popen(command, "r"); free(command); if (f != NULL) { if (fgets(buf, SUITE_LENGTH - 1, f)) { if (buf[strlen(buf) - 1] == '\n') buf[strlen(buf) - 1] = '\0'; debconf_set(debconf, DEBCONF_BASE "suite", buf); ret = 1; } } pclose(f); free(suite); } free(hostname); free(directory); if (show_progress) { debconf_progress_step(debconf, 1); debconf_progress_stop(debconf); } return ret; }
bool di_packages_resolve_dependencies_recurse (di_packages_resolve_dependencies_check *r, di_package *package, di_package *dependend_package) { di_slist_node *node; /* did we already check this package? */ if (package->resolver & r->resolver) { #ifdef ENABLE_EXTENSIVE_DEBUG if (package->resolver & (r->resolver << 1)) di_log (DI_LOG_LEVEL_DEBUG, "resolver (%s): already done, okay", package->package); else di_log (DI_LOG_LEVEL_DEBUG, "resolver (%s): already done, not okay", package->package); #endif return package->resolver & (r->resolver << 1); } package->resolver |= r->resolver; package->resolver |= (r->resolver << 1); #ifdef ENABLE_EXTENSIVE_DEBUG di_log (DI_LOG_LEVEL_DEBUG, "resolver (%s): start", package->package); #endif switch (package->type) { case di_package_type_real_package: for (node = package->depends.head; node; node = node->next) { di_package_dependency *d = node->data; if ((d->type == di_package_dependency_type_depends || d->type == di_package_dependency_type_pre_depends) && !r->check_real (r, package, d)) goto error; } #ifdef ENABLE_EXTENSIVE_DEBUG if (dependend_package) di_log (DI_LOG_LEVEL_DEBUG, "resolver (%s): mark, dependency from %s", package->package, dependend_package->package); else di_log (DI_LOG_LEVEL_DEBUG, "resolver (%s): mark", package->package); #endif r->do_real (package, r->do_real_data); break; case di_package_type_virtual_package: #ifdef ENABLE_EXTENSIVE_DEBUG if (dependend_package) di_log (DI_LOG_LEVEL_DEBUG, "resolver (%s): search, dependency from %s", package->package, dependend_package->package); else di_log (DI_LOG_LEVEL_DEBUG, "resolver (%s): search", package->package); #endif for (node = package->depends.head; node; node = node->next) { di_package_dependency *d = node->data; if (d->type == di_package_dependency_type_reverse_provides) package->resolver &= ~(r->resolver << 2); } while (1) { di_package_dependency *best_provide = NULL; for (node = package->depends.head; node; node = node->next) { di_package_dependency *d = node->data; if (d->type == di_package_dependency_type_reverse_provides) { if (!(package->resolver & (r->resolver << 2))) best_provide = r->check_virtual (package, best_provide, d, r->check_virtual_data); } } if (best_provide) { if (r->check_real (r, dependend_package, best_provide)) break; else package->resolver |= (r->resolver << 2); } else if (!r->check_non_existant (r, package, NULL)) goto error; else break; } break; case di_package_type_non_existent: if (!r->check_non_existant (r, package, NULL)) goto error; } return true; error: #ifdef ENABLE_EXTENSIVE_DEBUG di_log (DI_LOG_LEVEL_DEBUG, "resolver (%s): not okay", package->package); #endif package->resolver &= ~(r->resolver << 1); return false; }
int task_chain (struct task_act *tk, struct di_block *di) { struct oper_act * on; struct DSError * err = &(tk->tk_resp.di_error.de_err); struct di_block * di_tmp; char refer_ok = TRUE; #ifdef DEBUG DLOG(log_dsap, LLOG_DEBUG, ("task_chain called with:")); di_list_log(di); #endif /* NB At some point this routine must assign the di_block list to * either the task (if it is intended to geneate a referral) or to * an operation hanging off that task if it is intended to chain the * task. This is fine when there are no deferred di_blocks, but when * there are then the information they will eventually contain is * needed to make a full decision on whether to chain or refer. * This needs a lot of thought to get right, for now the chain/refer * decision is made once and for all on the basis of the information * available now. Any information not available is assumed to force a * referral (the safe option - until network connectivity is considered)! * THis may introduce the unwelcome effect that a first request to a * DSA may produce a referral where subsequent requests do not - so much * for consistency but it won't happen that often if DSA info is cached * sensibly. */ /* * Generate the referral which the DSA will pass back if * chaining is disallowed or oper_chain fails for all * DSAs listed. */ sort_dsa_list (&di); if ((di_tmp = select_refer_dsa (di,tk)) == NULL_DI_BLOCK) { /* The remote END is probably unable to follow the referral - chain if allowed */ refer_ok = FALSE; for(di_tmp=di; di_tmp!=NULL_DI_BLOCK; di_tmp=di_tmp->di_next) { if(di_tmp->di_state == DI_DEFERRED) continue; #ifdef DEBUG DLOG(log_dsap, LLOG_DEBUG, ("About to call di2cref with:")); di_log(di_tmp); #endif if(di2cref(di_tmp, err, tk->tk_conn->cn_ctx) == OK) break; } } else if (di2cref(di_tmp, err, tk->tk_conn->cn_ctx) != OK) di_tmp = NULL_DI_BLOCK; /* waiting... */ if(di_tmp == NULL_DI_BLOCK) { /* * Want to generate a referral - but all di_blocks (if any) * are deferred. Would we be lying too much if we said the * DSA was "busy" at this point??? */ ds_error_free (err); err->dse_type = DSE_SERVICEERROR; err->ERR_SERVICE.DSE_sv_problem = DSE_SV_BUSY; di_desist(di); return(NOTOK); } /* * If it would be inappropriate to chain this operation, then * generate a referral from the di_block list. */ if(chain_ok(tk,refer_ok,di_tmp->di_dn) == FALSE) { DLOG(log_dsap, LLOG_DEBUG, ("Referring!")); di_desist(di); return(NOTOK); } DLOG(log_dsap, LLOG_DEBUG, ("Chaining!")); /* Chain. Generate the new operation to send */ if((on = task2oper(tk)) == NULLOPER) { DLOG(log_dsap, LLOG_DEBUG, ("Why did task2oper fail??")); ds_error_free (err); err->dse_type = DSE_SERVICEERROR; err->ERR_SERVICE.DSE_sv_problem = DSE_SV_UNAVAILABLE; di_desist(di); return(NOTOK); } if(ti_is_elem(tk->tk_dx.dx_arg.dca_charg.cha_trace, tk->tk_dx.dx_arg.dca_charg.cha_trace->ti_next)) { DLOG (log_dsap,LLOG_TRACE,("Loop found in oper_chain()")); ds_error_free (err); err->dse_type = DSE_SERVICEERROR; err->ERR_SERVICE.DSE_sv_problem = DSE_SV_LOOPDETECT; return(NOTOK); } on->on_next_task = tk->tk_operlist; tk->tk_operlist = on; on->on_task = tk; /* Hand control of di_blocks to the operation */ on->on_dsas = di; for(di_tmp = di; di_tmp != NULL_DI_BLOCK; di_tmp=di_tmp->di_next) { di_tmp->di_type = DI_OPERATION; di_tmp->di_oper = on; } if(oper_chain(on) != OK) { oper_task_extract(on); oper_free(on); return(NOTOK); } #ifdef QUIPU_CONSOLE /* SPT trying to insert a chain_analyse here. */ /* The aim is to add this chained command to */ /* the open_call_avs structure */ chaining_analyse(tk, di) ; #endif /* QUIPU_CONSOLE */ return(OK); }
static int find_releases(void) { int nbr_suites = sizeof(suites)/SUITE_LENGTH; int i, r = 0; int bad_mirror = 0, have_default = 0; struct release_t release; char *default_suite; default_suite = get_default_suite(); if (default_suite == NULL) di_log(DI_LOG_LEVEL_ERROR, "no default release specified"); if (show_progress) { debconf_progress_start(debconf, 0, nbr_suites, DEBCONF_BASE "checking_title"); debconf_progress_info(debconf, DEBCONF_BASE "checking_download"); } /* Initialize releases; also ensures NULL termination of the array */ memset(&releases, 0, sizeof(releases)); /* Try to get Release files for all suites. */ if (! base_on_cd) { for (i=0; i < nbr_suites && r < MAXRELEASES; i++) { memset(&release, 0, sizeof(release)); if (get_release(&release, suites[i])) { if (release.status & IS_VALID) { if (strcmp(release.name, default_suite) == 0 || strcmp(release.suite, default_suite) == 0) { release.status |= IS_DEFAULT; have_default = 1; } /* Only list oldstable if it's the default */ if (strcmp(suites[i], "oldstable") != 0 || (release.status & IS_DEFAULT)) releases[r++] = release; } else { bad_mirror = 1; break; } } if (show_progress) debconf_progress_step(debconf, 1); } if (r == MAXRELEASES) di_log(DI_LOG_LEVEL_ERROR, "array overflow: more releases than allowed by MAXRELEASES"); if (! bad_mirror && r == 0) di_log(DI_LOG_LEVEL_INFO, "mirror does not have any suite symlinks"); } /* Try to get Release file using the default "suite". */ if (! bad_mirror && (base_on_cd || ! have_default)) { memset(&release, 0, sizeof(release)); if (get_release(&release, default_suite)) { if (release.status & IS_VALID) { release.status |= IS_DEFAULT; releases[r++] = release; have_default = 1; } else { bad_mirror = 1; } } else { di_log(DI_LOG_LEVEL_WARNING, "mirror does not support the specified release (%s)", default_suite); } if (r == MAXRELEASES) di_log(DI_LOG_LEVEL_ERROR, "array overflow: more releases than allowed by MAXRELEASES"); } if (show_progress) { debconf_progress_set(debconf, nbr_suites); debconf_progress_stop(debconf); } if (r == 0 || bad_mirror) { unset_seen_flags(); free(default_suite); free(release.name); free(release.suite); debconf_input(debconf, "critical", DEBCONF_BASE "bad"); if (debconf_go(debconf) == 30) exit(10); /* back up to menu */ else return 1; /* back to beginning of questions */ } if (! base_on_cd && ! have_default) { unset_seen_flags(); debconf_subst(debconf, DEBCONF_BASE "no-default", "RELEASE", default_suite); free(default_suite); debconf_input(debconf, "critical", DEBCONF_BASE "no-default"); if (debconf_go(debconf) == 30) { exit(10); /* back up to menu */ } else { debconf_get(debconf, DEBCONF_BASE "no-default"); if (strcmp(debconf->value, "false")) return 1; /* back to beginning of questions */ } } else { free(default_suite); } return 0; }
/* * Fetch a Release file, extract its Suite and Codename and check its valitity. */ static int get_release(struct release_t *release, const char *name) { char *command; FILE *f = NULL; char *hostname, *directory; char line[80]; char buf[SUITE_LENGTH]; if (base_on_cd && ! manual_entry) { /* We have the base system on the CD, so instead of trying * to contact the mirror (which might take some time to time * out if there's no network connection), let's just assume * that the CD will be sufficient to get a basic system up, * setting codename = suite. Note that this is an * Ubuntu-specific change since (a) Debian netinst CDs etc. * may not be able to install a complete system from the * network and (b) codename != suite in Debian. * * We only do this for mirrors in our mirror list, since we * assume that those have a good chance of not being typoed. * For manually-entered mirrors, we still do full mirror * validation. */ di_log(DI_LOG_LEVEL_INFO, "base system installable from CD; skipping mirror check"); release->name = strdup(name); release->suite = strdup(name); release->status = IS_VALID | GET_CODENAME; return 1; } hostname = add_protocol("hostname"); debconf_get(debconf, hostname); free(hostname); hostname = strdup(debconf->value); directory = add_protocol("directory"); debconf_get(debconf, directory); free(directory); directory = strdup(debconf->value); asprintf(&command, "wget -q %s://%s%s/dists/%s/Release -O - | grep -E '^(Suite|Codename):'", protocol, hostname, directory, name); di_log(DI_LOG_LEVEL_DEBUG, "command: %s", command); f = popen(command, "r"); free(command); free(hostname); free(directory); if (f != NULL) { while (fgets(line, sizeof(line), f) != NULL) { char *value; if (line[strlen(line) - 1] == '\n') line[strlen(line) - 1] = '\0'; if ((value = strstr(line, ": ")) != NULL) { strncpy(buf, value + 2, SUITE_LENGTH - 1); buf[SUITE_LENGTH - 1] = '\0'; if (strncmp(line, "Codename:", 9) == 0) release->name = strdup(buf); if (strncmp(line, "Suite:", 6) == 0) release->suite = strdup(buf); } } if (release->name != NULL && strcmp(release->name, name) == 0) release->status |= IS_VALID | GET_CODENAME; if (release->suite != NULL && strcmp(release->suite, name) == 0) release->status |= IS_VALID | GET_SUITE; if ((release->name != NULL || release->suite != NULL) && !(release->status & IS_VALID)) log_invalid_release(name, "Suite or Codename"); /* Cross-validate the Release file */ if (release->status & IS_VALID) if (! cross_validate_release(release)) log_invalid_release(name, (release->status & GET_SUITE) ? "Codename" : "Suite"); /* In case there is no Codename field */ if ((release->status & IS_VALID) && release->name == NULL) release->name = strdup(name); // di_log(DI_LOG_LEVEL_DEBUG, "get_release(): %s -> %s:%s (0x%x)", // name, release->suite, release->name, release->status); } pclose(f); if (release->name != NULL) { return 1; } else { free(release->suite); return 0; } }
void log_invalid_release(const char *name, const char *field) { di_log(DI_LOG_LEVEL_WARNING, "broken mirror: invalid %s in Release file for %s", field, name); }