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
;