1 /* opkg_hash.c - the opkg package management system
5 Copyright (C) 2002 Compaq Computer Corporation
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2, or (at
10 your option) any later version.
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
24 #include "hash_table.h"
26 #include "opkg_message.h"
29 #include "pkg_parse.h"
30 #include "opkg_utils.h"
31 #include "libbb/libbb.h"
36 hash_table_init("pkg-hash", &conf->pkg_hash,
37 OPKG_CONF_DEFAULT_HASH_LEN);
41 free_pkgs(const char *key, void *entry, void *data)
44 abstract_pkg_t *ab_pkg;
46 /* Each entry in the hash table is an abstract package, which contains
47 * a list of packages that provide the abstract package.
50 ab_pkg = (abstract_pkg_t*) entry;
53 for (i = 0; i < ab_pkg->pkgs->len; i++) {
54 pkg_deinit (ab_pkg->pkgs->pkgs[i]);
55 free (ab_pkg->pkgs->pkgs[i]);
59 abstract_pkg_vec_free (ab_pkg->provided_by);
60 abstract_pkg_vec_free (ab_pkg->replaced_by);
61 pkg_vec_free (ab_pkg->pkgs);
62 free (ab_pkg->depended_upon_by);
70 hash_table_foreach(&conf->pkg_hash, free_pkgs, NULL);
71 hash_table_deinit(&conf->pkg_hash);
75 pkg_hash_add_from_file(const char *file_name,
76 pkg_src_t *src, pkg_dest_t *dest, int is_status_file)
81 const size_t len = 4096;
84 fp = fopen(file_name, "r");
86 opkg_perror(ERROR, "Failed to open %s", file_name);
97 ret = pkg_parse_from_stream_nomalloc(pkg, fp, 0,
105 /* Probably a blank line, continue parsing. */
110 if (!pkg->architecture) {
111 char *version_str = pkg_version_str_alloc(pkg);
112 opkg_msg(ERROR, "Package %s version %s has no "
113 "architecture specified, ignoring.\n",
114 pkg->name, version_str);
119 hash_insert_pkg(pkg, is_status_file);
129 static abstract_pkg_t *
130 abstract_pkg_fetch_by_name(const char * pkg_name)
132 return (abstract_pkg_t *)hash_table_get(&conf->pkg_hash, pkg_name);
136 pkg_hash_fetch_best_installation_candidate(abstract_pkg_t *apkg,
137 int (*constraint_fcn)(pkg_t *pkg, void *cdata),
138 void *cdata, int quiet)
143 int wrong_arch_found = 0;
144 pkg_vec_t *matching_pkgs;
145 abstract_pkg_vec_t *matching_apkgs;
146 abstract_pkg_vec_t *provided_apkg_vec;
147 abstract_pkg_t **provided_apkgs;
148 abstract_pkg_vec_t *providers;
149 pkg_t *latest_installed_parent = NULL;
150 pkg_t *latest_matching = NULL;
151 pkg_t *priorized_matching = NULL;
152 pkg_t *held_pkg = NULL;
153 pkg_t *good_pkg_by_name = NULL;
155 if (apkg == NULL || apkg->provided_by == NULL || (apkg->provided_by->len == 0))
158 matching_pkgs = pkg_vec_alloc();
159 matching_apkgs = abstract_pkg_vec_alloc();
160 providers = abstract_pkg_vec_alloc();
162 opkg_msg(DEBUG, "Best installation candidate for %s:\n", apkg->name);
164 provided_apkg_vec = apkg->provided_by;
165 nprovides = provided_apkg_vec->len;
166 provided_apkgs = provided_apkg_vec->pkgs;
168 opkg_msg(DEBUG, "apkg=%s nprovides=%d.\n", apkg->name, nprovides);
170 /* accumulate all the providers */
171 for (i = 0; i < nprovides; i++) {
172 abstract_pkg_t *provider_apkg = provided_apkgs[i];
173 opkg_msg(DEBUG, "Adding %s to providers.\n", provider_apkg->name);
174 abstract_pkg_vec_insert(providers, provider_apkg);
176 nprovides = providers->len;
178 for (i = 0; i < nprovides; i++) {
179 abstract_pkg_t *provider_apkg = abstract_pkg_vec_get(providers, i);
180 abstract_pkg_t *replacement_apkg = NULL;
183 if (provider_apkg->replaced_by && provider_apkg->replaced_by->len) {
184 replacement_apkg = provider_apkg->replaced_by->pkgs[0];
185 if (provider_apkg->replaced_by->len > 1) {
186 opkg_msg(NOTICE, "Multiple replacers for %s, "
187 "using first one (%s).\n",
188 provider_apkg->name, replacement_apkg->name);
192 if (replacement_apkg)
193 opkg_msg(DEBUG, "replacement_apkg=%s for provider_apkg=%s.\n",
194 replacement_apkg->name, provider_apkg->name);
196 if (replacement_apkg && (replacement_apkg != provider_apkg)) {
197 if (abstract_pkg_vec_contains(providers, replacement_apkg))
200 provider_apkg = replacement_apkg;
203 if (!(vec = provider_apkg->pkgs)) {
204 opkg_msg(DEBUG, "No pkgs for provider_apkg %s.\n",
205 provider_apkg->name);
210 /* now check for supported architecture */
214 /* count packages matching max arch priority and keep track of last one */
215 for (i = 0; i < vec->len; i++) {
216 pkg_t *maybe = vec->pkgs[i];
217 opkg_msg(DEBUG, "%s arch=%s arch_priority=%d version=%s.\n",
218 maybe->name, maybe->architecture,
219 maybe->arch_priority, maybe->version);
220 /* We make sure not to add the same package twice. Need to search for the reason why
221 they show up twice sometimes. */
222 if ((maybe->arch_priority > 0) && (! pkg_vec_contains(matching_pkgs, maybe))) {
224 abstract_pkg_vec_insert(matching_apkgs, maybe->parent);
225 pkg_vec_insert(matching_pkgs, maybe);
229 if (vec->len > 0 && matching_pkgs->len < 1)
230 wrong_arch_found = 1;
234 if (matching_pkgs->len < 1) {
235 if (wrong_arch_found)
236 opkg_msg(ERROR, "Packages for %s found, but"
237 " incompatible with the architectures configured\n",
239 pkg_vec_free(matching_pkgs);
240 abstract_pkg_vec_free(matching_apkgs);
241 abstract_pkg_vec_free(providers);
246 if (matching_pkgs->len > 1)
247 pkg_vec_sort(matching_pkgs, pkg_name_version_and_architecture_compare);
248 if (matching_apkgs->len > 1)
249 abstract_pkg_vec_sort(matching_pkgs, abstract_pkg_name_compare);
251 for (i = 0; i < matching_pkgs->len; i++) {
252 pkg_t *matching = matching_pkgs->pkgs[i];
253 if (constraint_fcn(matching, cdata)) {
254 opkg_msg(DEBUG, "Candidate: %s %s.\n",
255 matching->name, matching->version) ;
256 good_pkg_by_name = matching;
257 /* It has been provided by hand, so it is what user want */
258 if (matching->provided_by_hand == 1)
264 for (i = 0; i < matching_pkgs->len; i++) {
265 pkg_t *matching = matching_pkgs->pkgs[i];
266 latest_matching = matching;
267 if (matching->parent->state_status == SS_INSTALLED || matching->parent->state_status == SS_UNPACKED)
268 latest_installed_parent = matching;
269 if (matching->state_flag & (SF_HOLD|SF_PREFER)) {
271 opkg_msg(NOTICE, "Multiple packages (%s and %s) providing"
272 " same name marked HOLD or PREFER. "
274 held_pkg->name, matching->name);
279 if (!good_pkg_by_name && !held_pkg && !latest_installed_parent && matching_apkgs->len > 1 && !quiet) {
281 for (i = 0; i < matching_pkgs->len; i++) {
282 pkg_t *matching = matching_pkgs->pkgs[i];
283 if (matching->arch_priority > prio) {
284 priorized_matching = matching;
285 prio = matching->arch_priority;
286 opkg_msg(DEBUG, "Match %s with priority %i.\n",
287 matching->name, prio);
293 if (conf->verbosity >= INFO && matching_apkgs->len > 1) {
294 opkg_msg(INFO, "%d matching pkgs for apkg=%s:\n",
295 matching_pkgs->len, apkg->name);
296 for (i = 0; i < matching_pkgs->len; i++) {
297 pkg_t *matching = matching_pkgs->pkgs[i];
298 opkg_msg(INFO, "%s %s %s\n",
299 matching->name, matching->version,
300 matching->architecture);
304 nmatching = matching_apkgs->len;
306 pkg_vec_free(matching_pkgs);
307 abstract_pkg_vec_free(matching_apkgs);
308 abstract_pkg_vec_free(providers);
310 if (good_pkg_by_name) { /* We found a good candidate, we will install it */
311 return good_pkg_by_name;
314 opkg_msg(INFO, "Using held package %s.\n", held_pkg->name);
317 if (latest_installed_parent) {
318 opkg_msg(INFO, "Using latest version of installed package %s.\n",
319 latest_installed_parent->name);
320 return latest_installed_parent;
322 if (priorized_matching) {
323 opkg_msg(INFO, "Using priorized matching %s %s %s.\n",
324 priorized_matching->name, priorized_matching->version,
325 priorized_matching->architecture);
326 return priorized_matching;
329 opkg_msg(INFO, "No matching pkg out of %d matching_apkgs.\n",
333 if (latest_matching) {
334 opkg_msg(INFO, "Using latest matching %s %s %s.\n",
335 latest_matching->name, latest_matching->version,
336 latest_matching->architecture);
337 return latest_matching;
343 pkg_name_constraint_fcn(pkg_t *pkg, void *cdata)
345 const char *name = (const char *)cdata;
347 if (strcmp(pkg->name, name) == 0)
354 pkg_vec_fetch_by_name(const char *pkg_name)
356 abstract_pkg_t * ab_pkg;
358 if(!(ab_pkg = abstract_pkg_fetch_by_name(pkg_name)))
364 if (ab_pkg->provided_by) {
365 abstract_pkg_t *abpkg = abstract_pkg_vec_get(ab_pkg->provided_by, 0);
377 pkg_hash_fetch_best_installation_candidate_by_name(const char *name)
379 abstract_pkg_t *apkg = NULL;
381 if (!(apkg = abstract_pkg_fetch_by_name(name)))
384 return pkg_hash_fetch_best_installation_candidate(apkg,
385 pkg_name_constraint_fcn, apkg->name, 0);
390 pkg_hash_fetch_by_name_version(const char *pkg_name, const char * version)
394 char *version_str = NULL;
396 if(!(vec = pkg_vec_fetch_by_name(pkg_name)))
399 for(i = 0; i < vec->len; i++) {
400 version_str = pkg_version_str_alloc(vec->pkgs[i]);
401 if(!strcmp(version_str, version)) {
415 pkg_hash_fetch_installed_by_name_dest(const char *pkg_name, pkg_dest_t *dest)
420 if (!(vec = pkg_vec_fetch_by_name(pkg_name))) {
424 for (i = 0; i < vec->len; i++)
425 if((vec->pkgs[i]->state_status == SS_INSTALLED
426 || vec->pkgs[i]->state_status == SS_UNPACKED)
427 && vec->pkgs[i]->dest == dest) {
435 pkg_hash_fetch_installed_by_name(const char *pkg_name)
440 if (!(vec = pkg_vec_fetch_by_name(pkg_name))) {
444 for (i = 0; i < vec->len; i++) {
445 if (vec->pkgs[i]->state_status == SS_INSTALLED
446 || vec->pkgs[i]->state_status == SS_UNPACKED) {
456 pkg_hash_fetch_available_helper(const char *pkg_name, void *entry, void *data)
459 abstract_pkg_t *ab_pkg = (abstract_pkg_t *)entry;
460 pkg_vec_t *all = (pkg_vec_t *)data;
461 pkg_vec_t *pkg_vec = ab_pkg->pkgs;
466 for (j = 0; j < pkg_vec->len; j++) {
467 pkg_t *pkg = pkg_vec->pkgs[j];
468 pkg_vec_insert(all, pkg);
473 pkg_hash_fetch_available(pkg_vec_t *all)
475 hash_table_foreach(&conf->pkg_hash, pkg_hash_fetch_available_helper,
480 pkg_hash_fetch_all_installed_helper(const char *pkg_name, void *entry, void *data)
482 abstract_pkg_t *ab_pkg = (abstract_pkg_t *)entry;
483 pkg_vec_t *all = (pkg_vec_t *)data;
484 pkg_vec_t *pkg_vec = ab_pkg->pkgs;
490 for (j = 0; j < pkg_vec->len; j++) {
491 pkg_t *pkg = pkg_vec->pkgs[j];
492 if (pkg->state_status == SS_INSTALLED
493 || pkg->state_status == SS_UNPACKED)
494 pkg_vec_insert(all, pkg);
499 pkg_hash_fetch_all_installed(pkg_vec_t *all)
501 hash_table_foreach(&conf->pkg_hash, pkg_hash_fetch_all_installed_helper,
506 * This assumes that the abstract pkg doesn't exist.
508 static abstract_pkg_t *
509 add_new_abstract_pkg_by_name(const char *pkg_name)
511 abstract_pkg_t *ab_pkg;
513 ab_pkg = abstract_pkg_new();
515 ab_pkg->name = xstrdup(pkg_name);
516 hash_table_insert(&conf->pkg_hash, pkg_name, ab_pkg);
523 ensure_abstract_pkg_by_name(const char *pkg_name)
525 abstract_pkg_t * ab_pkg;
527 if (!(ab_pkg = abstract_pkg_fetch_by_name(pkg_name)))
528 ab_pkg = add_new_abstract_pkg_by_name(pkg_name);
534 hash_insert_pkg(pkg_t *pkg, int set_status)
536 abstract_pkg_t * ab_pkg;
538 ab_pkg = ensure_abstract_pkg_by_name(pkg->name);
540 ab_pkg->pkgs = pkg_vec_alloc();
542 if (pkg->state_status == SS_INSTALLED) {
543 ab_pkg->state_status = SS_INSTALLED;
544 } else if (pkg->state_status == SS_UNPACKED) {
545 ab_pkg->state_status = SS_UNPACKED;
550 buildProvides(ab_pkg, pkg);
552 /* Need to build the conflicts graph before replaces for correct
553 * calculation of replaced_by relation.
557 buildReplaces(ab_pkg, pkg);
559 buildDependedUponBy(pkg, ab_pkg);
561 pkg_vec_insert_merge(ab_pkg->pkgs, pkg, set_status);
562 pkg->parent = ab_pkg;
567 file_hash_get_file_owner(const char *file_name)
569 return hash_table_get(&conf->file_hash, file_name);
573 file_hash_set_file_owner(const char *file_name, pkg_t *owning_pkg)
575 pkg_t *old_owning_pkg = hash_table_get(&conf->file_hash, file_name);
576 int file_name_len = strlen(file_name);
578 if (file_name[file_name_len -1] == '/')
581 if (conf->offline_root) {
582 unsigned int len = strlen(conf->offline_root);
583 if (strncmp(file_name, conf->offline_root, len) == 0) {
588 hash_table_insert(&conf->file_hash, file_name, owning_pkg);
590 if (old_owning_pkg) {
591 pkg_get_installed_files(old_owning_pkg);
592 str_list_remove_elt(old_owning_pkg->installed_files, file_name);
593 pkg_free_installed_files(old_owning_pkg);
595 /* mark this package to have its filelist written */
596 old_owning_pkg->state_flag |= SF_FILELIST_CHANGED;
597 owning_pkg->state_flag |= SF_FILELIST_CHANGED;