opkg: adding the hash_table_remove API, not using yet.
[project/opkg-lede.git] / libopkg / opkg.c
1 /* opkg.c - the opkg package management system
2
3 Thomas Wood <thomas@openedhand.com>
4
5 Copyright (C) 2008 OpenMoko Inc
6
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.
11
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.
16 */
17
18 #include <config.h>
19 #include <fnmatch.h>
20
21 #include "opkg.h"
22 #include "opkg_conf.h"
23 #include "args.h"
24
25 #include "opkg_install.h"
26 #include "opkg_configure.h"
27 #include "opkg_download.h"
28 #include "opkg_remove.h"
29 #include "opkg_upgrade.h"
30 #include "opkg_error.h"
31
32 #include "sprintf_alloc.h"
33 #include "file_util.h"
34
35 #include <libbb/libbb.h>
36
37 struct errlist* error_list;
38
39 struct _opkg_t
40 {
41 args_t *args;
42 opkg_conf_t *conf;
43 opkg_option_t *options;
44 };
45
46 #define opkg_assert(expr) if (!(expr)) { \
47 printf ("opkg: file %s: line %d (%s): Assertation '%s' failed",\
48 __FILE__, __LINE__, __PRETTY_FUNCTION__, # expr); abort (); }
49
50 #define progress(d, p) d.percentage = p; if (progress_callback) progress_callback (opkg, &d, user_data);
51 #define SSTRCMP(x,y) (x && y) ? strcmp (x, y) : 0
52
53 /** Private Functions ***/
54
55 static opkg_package_t*
56 old_pkg_to_new (pkg_t *old)
57 {
58 opkg_package_t *new;
59
60 new = opkg_package_new ();
61
62 #define sstrdup(x) (x) ? strdup (x) : NULL;
63
64 new->name = sstrdup (old->name);
65 new->version = pkg_version_str_alloc (old);
66 new->architecture = sstrdup (old->architecture);
67 if (old->src)
68 new->repository = sstrdup (old->src->name);
69 new->description = sstrdup (old->description);
70 new->tags = sstrdup (old->tags);
71 new->url = sstrdup (old->url);
72
73 new->size = (old->size) ? atoi (old->size) : 0;
74 new->installed = (old->state_status == SS_INSTALLED);
75
76 return new;
77 }
78
79 static int
80 opkg_configure_packages(opkg_conf_t *conf, char *pkg_name)
81 {
82 pkg_vec_t *all;
83 int i;
84 pkg_t *pkg;
85 int r, err = 0;
86
87 all = pkg_vec_alloc ();
88 pkg_hash_fetch_available (&conf->pkg_hash, all);
89
90 for (i = 0; i < all->len; i++)
91 {
92 pkg = all->pkgs[i];
93
94 if (pkg_name && fnmatch (pkg_name, pkg->name, 0))
95 continue;
96
97 if (pkg->state_status == SS_UNPACKED)
98 {
99 r = opkg_configure (conf, pkg);
100 if (r == 0)
101 {
102 pkg->state_status = SS_INSTALLED;
103 pkg->parent->state_status = SS_INSTALLED;
104 pkg->state_flag &= ~SF_PREFER;
105 }
106 else
107 {
108 if (!err)
109 err = r;
110 }
111 }
112 }
113
114 pkg_vec_free (all);
115 return err;
116 }
117
118 struct _curl_cb_data
119 {
120 opkg_progress_callback_t cb;
121 opkg_progress_data_t *progress_data;
122 opkg_t *opkg;
123 void *user_data;
124 int start_range;
125 int finish_range;
126 };
127
128 int
129 curl_progress_cb (struct _curl_cb_data *cb_data,
130 double t, /* dltotal */
131 double d, /* dlnow */
132 double ultotal,
133 double ulnow)
134 {
135 int p = (t) ? d * 100 / t : 0;
136 static int prev = -1;
137 int progress = 0;
138
139 /* prevent the same value being sent twice (can occur due to rounding) */
140 if (p == prev)
141 return 0;
142 prev = p;
143
144 if (t < 1)
145 return 0;
146
147 progress = cb_data->start_range + (d / t * ((cb_data->finish_range - cb_data->start_range)));
148 cb_data->progress_data->percentage = progress;
149
150 (cb_data->cb)(cb_data->opkg,
151 cb_data->progress_data,
152 cb_data->user_data);
153
154 return 0;
155 }
156
157
158 /*** Public API ***/
159
160 opkg_package_t *
161 opkg_package_new ()
162 {
163
164 opkg_package_t *p;
165
166 p = calloc (1, sizeof (opkg_package_t));
167
168 return p;
169 }
170
171 void
172 opkg_package_free (opkg_package_t *p)
173 {
174 free (p->name);
175 free (p->version);
176 free (p->architecture);
177 free (p->description);
178 free (p->tags);
179 free (p->url);
180 free (p->repository);
181
182 free (p);
183 }
184
185 opkg_t *
186 opkg_new ()
187 {
188 opkg_t *opkg;
189 int err;
190
191 opkg = calloc (1, sizeof (opkg_t));
192
193 opkg->args = calloc (1, sizeof (args_t));
194 err = args_init (opkg->args);
195 if (err)
196 {
197 free (opkg->args);
198 free (opkg);
199 return NULL;
200 }
201
202 opkg->conf = calloc (1, sizeof (opkg_conf_t));
203 err = opkg_conf_init (opkg->conf, opkg->args);
204 if (err)
205 {
206 free (opkg->conf);
207 free (opkg->args);
208 free (opkg);
209 return NULL;
210 }
211
212 opkg_init_options_array (opkg->conf, &opkg->options);
213 return opkg;
214 }
215
216 void
217 opkg_free (opkg_t *opkg)
218 {
219 opkg_assert (opkg != NULL);
220
221 opkg_conf_deinit (opkg->conf);
222 args_deinit (opkg->args);
223 free (opkg->options);
224 free (opkg->args);
225 free (opkg->conf);
226 free (opkg);
227 }
228
229 int
230 opkg_re_read_config_files (opkg_t *opkg)
231 {
232 args_t *a;
233 opkg_conf_t *c;
234
235 opkg_assert (opkg != NULL);
236
237 a = opkg->args;
238 c = opkg->conf;
239
240 /* Unfortunatly, the easiest way to re-read the config files right now is to
241 * throw away opkg->conf and start again */
242
243 /* copy the settings we need to keep */
244 a->autoremove = c->autoremove;
245 a->force_depends = c->force_depends;
246 a->force_defaults = c->force_defaults;
247 a->force_overwrite = c->force_overwrite;
248 a->force_downgrade = c->force_downgrade;
249 a->force_reinstall = c->force_reinstall;
250 a->force_removal_of_dependent_packages = c->force_removal_of_dependent_packages;
251 a->force_removal_of_essential_packages = c->force_removal_of_essential_packages;
252 a->nodeps = c->nodeps;
253 a->noaction = c->noaction;
254 a->query_all = c->query_all;
255 a->verbosity = c->verbosity;
256
257 if (c->offline_root)
258 {
259 if (a->offline_root) free (a->offline_root);
260 a->offline_root = strdup (c->offline_root);
261 }
262
263 if (c->offline_root_pre_script_cmd)
264 {
265 if (a->offline_root_pre_script_cmd) free (a->offline_root_pre_script_cmd);
266 a->offline_root_pre_script_cmd = strdup (c->offline_root_pre_script_cmd);
267 }
268
269 if (c->offline_root_post_script_cmd)
270 {
271 if (a->offline_root_post_script_cmd) free (a->offline_root_post_script_cmd);
272 a->offline_root_post_script_cmd = strdup (c->offline_root_post_script_cmd);
273 }
274
275 if (c->cache) {
276 if (a->cache)
277 free (a->cache);
278 a->cache = strdup(c->cache);
279 }
280
281 /* throw away old opkg_conf and start again */
282 opkg_conf_deinit (opkg->conf);
283 opkg_conf_init (opkg->conf, opkg->args);
284
285 free (opkg->options);
286 opkg_init_options_array (opkg->conf, &opkg->options);
287
288 return 0;
289 }
290
291 void
292 opkg_get_option (opkg_t *opkg, char *option, void **value)
293 {
294 int i = 0;
295 opkg_option_t *options;
296
297 opkg_assert (opkg != NULL);
298 opkg_assert (option != NULL);
299 opkg_assert (value != NULL);
300
301 options = opkg->options;
302
303 /* look up the option
304 * TODO: this would be much better as a hash table
305 */
306 while (options[i].name)
307 {
308 if (strcmp (options[i].name, option) != 0)
309 {
310 i++;
311 continue;
312 }
313 }
314
315 /* get the option */
316 switch (options[i].type)
317 {
318 case OPKG_OPT_TYPE_BOOL:
319 *((int *) value) = *((int *) options[i].value);
320 return;
321
322 case OPKG_OPT_TYPE_INT:
323 *((int *) value) = *((int *) options[i].value);
324 return;
325
326 case OPKG_OPT_TYPE_STRING:
327 *((char **)value) = strdup (options[i].value);
328 return;
329 }
330
331 }
332
333 void
334 opkg_set_option (opkg_t *opkg, char *option, void *value)
335 {
336 int i = 0, found = 0;
337 opkg_option_t *options;
338
339 opkg_assert (opkg != NULL);
340 opkg_assert (option != NULL);
341 opkg_assert (value != NULL);
342
343 options = opkg->options;
344
345 /* look up the option
346 * TODO: this would be much better as a hash table
347 */
348 while (options[i].name)
349 {
350 if (strcmp (options[i].name, option) == 0)
351 {
352 found = 1;
353 break;
354 }
355 i++;
356 }
357
358 if (!found)
359 {
360 /* XXX: Warning: Option not found */
361 return;
362 }
363
364 /* set the option */
365 switch (options[i].type)
366 {
367 case OPKG_OPT_TYPE_BOOL:
368 if (*((int *) value) == 0)
369 *((int *)options[i].value) = 0;
370 else
371 *((int *)options[i].value) = 1;
372 return;
373
374 case OPKG_OPT_TYPE_INT:
375 *((int *) options[i].value) = *((int *) value);
376 return;
377
378 case OPKG_OPT_TYPE_STRING:
379 *((char **)options[i].value) = strdup (value);
380 return;
381 }
382
383 }
384
385 int
386 opkg_install_package (opkg_t *opkg, const char *package_name, opkg_progress_callback_t progress_callback, void *user_data)
387 {
388 int err;
389 char *stripped_filename;
390 opkg_progress_data_t pdata;
391 pkg_t *old, *new;
392 pkg_vec_t *deps, *all;
393 int i, ndepends;
394 char **unresolved = NULL;
395
396 opkg_assert (opkg != NULL);
397 opkg_assert (package_name != NULL);
398
399 /* ... */
400 pkg_info_preinstall_check (opkg->conf);
401
402
403 /* check to ensure package is not already installed */
404 old = pkg_hash_fetch_installed_by_name(&opkg->conf->pkg_hash, package_name);
405 if (old)
406 {
407 /* XXX: Error: Package is already installed. */
408 return OPKG_PACKAGE_ALREADY_INSTALLED;
409 }
410
411 new = pkg_hash_fetch_best_installation_candidate_by_name(opkg->conf, package_name, NULL);
412 if (!new)
413 {
414 /* XXX: Error: Could not find package to install */
415 return OPKG_PACKAGE_NOT_FOUND;
416 }
417
418 new->state_flag |= SF_USER;
419
420 pdata.action = OPKG_INSTALL;
421 pdata.package = old_pkg_to_new (new);
422
423 progress (pdata, 0);
424
425 /* find dependancies and download them */
426 deps = pkg_vec_alloc ();
427 /* this function does not return the original package, so we insert it later */
428 ndepends = pkg_hash_fetch_unsatisfied_dependencies (opkg->conf, new, deps, &unresolved);
429 if (unresolved)
430 {
431 /* XXX: Error: Could not satisfy dependencies */
432 pkg_vec_free (deps);
433 return OPKG_DEPENDENCIES_FAILED;
434 }
435
436 /* insert the package we are installing so that we download it */
437 pkg_vec_insert (deps, new);
438
439 /* download package and dependancies */
440 for (i = 0; i < deps->len; i++)
441 {
442 pkg_t *pkg;
443 struct _curl_cb_data cb_data;
444 char *url;
445
446 pkg = deps->pkgs[i];
447 if (pkg->local_filename)
448 continue;
449
450 opkg_package_free (pdata.package);
451 pdata.package = old_pkg_to_new (pkg);
452 pdata.action = OPKG_DOWNLOAD;
453
454 if (pkg->src == NULL)
455 {
456 /* XXX: Error: Package not available from any configured src */
457 return OPKG_PACKAGE_NOT_AVAILABLE;
458 }
459
460 sprintf_alloc(&url, "%s/%s", pkg->src->value, pkg->filename);
461
462 /* Get the filename part, without any directory */
463 stripped_filename = strrchr(pkg->filename, '/');
464 if ( ! stripped_filename )
465 stripped_filename = pkg->filename;
466
467 sprintf_alloc(&pkg->local_filename, "%s/%s", opkg->conf->tmp_dir, stripped_filename);
468
469 cb_data.cb = progress_callback;
470 cb_data.progress_data = &pdata;
471 cb_data.opkg = opkg;
472 cb_data.user_data = user_data;
473 /* 75% of "install" progress is for downloading */
474 cb_data.start_range = 75 * i / deps->len;
475 cb_data.finish_range = 75 * (i + 1) / deps->len;
476
477 err = opkg_download(opkg->conf, url, pkg->local_filename,
478 (curl_progress_func) curl_progress_cb, &cb_data);
479 free(url);
480
481 if (err)
482 {
483 pkg_vec_free (deps);
484 opkg_package_free (pdata.package);
485 return OPKG_DOWNLOAD_FAILED;
486 }
487
488 }
489 pkg_vec_free (deps);
490
491 /* clear depenacy checked marks, left by pkg_hash_fetch_unsatisfied_dependencies */
492 all = pkg_vec_alloc ();
493 pkg_hash_fetch_available (&opkg->conf->pkg_hash, all);
494 for (i = 0; i < all->len; i++)
495 {
496 all->pkgs[i]->parent->dependencies_checked = 0;
497 }
498 pkg_vec_free (all);
499
500
501 /* 75% of "install" progress is for downloading */
502 opkg_package_free (pdata.package);
503 pdata.package = old_pkg_to_new (new);
504 pdata.action = OPKG_INSTALL;
505 progress (pdata, 75);
506
507 /* unpack the package */
508 err = opkg_install_pkg(opkg->conf, new, 0);
509
510 if (err)
511 {
512 opkg_package_free (pdata.package);
513 switch (err)
514 {
515 case OPKG_INSTALL_ERR_NOT_TRUSTED: return OPKG_GPG_ERROR;
516 case OPKG_INSTALL_ERR_DOWNLOAD: return OPKG_DOWNLOAD_FAILED;
517 case OPKG_INSTALL_ERR_DEPENDENCIES:
518 case OPKG_INSTALL_ERR_CONFLICTS: return OPKG_DEPENDENCIES_FAILED;
519 case OPKG_INSTALL_ERR_ALREADY_INSTALLED: return OPKG_PACKAGE_ALREADY_INSTALLED;
520 case OPKG_INSTALL_ERR_SIGNATURE: return OPKG_GPG_ERROR;
521 case OPKG_INSTALL_ERR_MD5: return OPKG_MD5_ERROR;
522 default: return OPKG_UNKNOWN_ERROR;
523 }
524 }
525
526 progress (pdata, 75);
527
528 /* run configure scripts, etc. */
529 err = opkg_configure_packages (opkg->conf, NULL);
530 if (err)
531 {
532 opkg_package_free (pdata.package);
533 return OPKG_UNKNOWN_ERROR;
534 }
535
536 /* write out status files and file lists */
537 opkg_conf_write_status_files (opkg->conf);
538 pkg_write_changed_filelists (opkg->conf);
539
540 progress (pdata, 100);
541 opkg_package_free (pdata.package);
542 return 0;
543 }
544
545 int
546 opkg_remove_package (opkg_t *opkg, const char *package_name, opkg_progress_callback_t progress_callback, void *user_data)
547 {
548 int err;
549 pkg_t *pkg = NULL;
550 pkg_t *pkg_to_remove;
551 opkg_progress_data_t pdata;
552
553 opkg_assert (opkg != NULL);
554 opkg_assert (package_name != NULL);
555
556 pkg_info_preinstall_check (opkg->conf);
557
558 pkg = pkg_hash_fetch_installed_by_name (&opkg->conf->pkg_hash, package_name);
559
560 if (pkg == NULL)
561 {
562 /* XXX: Error: Package not installed. */
563 return OPKG_PACKAGE_NOT_INSTALLED;
564 }
565
566 pdata.action = OPKG_REMOVE;
567 pdata.package = old_pkg_to_new (pkg);
568 progress (pdata, 0);
569
570
571 if (pkg->state_status == SS_NOT_INSTALLED)
572 {
573 /* XXX: Error: Package seems to be not installed (STATUS = NOT_INSTALLED). */
574 opkg_package_free (pdata.package);
575 return OPKG_PACKAGE_NOT_INSTALLED;
576 }
577 progress (pdata, 25);
578
579 if (opkg->conf->restrict_to_default_dest)
580 {
581 pkg_to_remove = pkg_hash_fetch_installed_by_name_dest (&opkg->conf->pkg_hash,
582 pkg->name,
583 opkg->conf->default_dest);
584 }
585 else
586 {
587 pkg_to_remove = pkg_hash_fetch_installed_by_name (&opkg->conf->pkg_hash, pkg->name );
588 }
589
590
591 progress (pdata, 75);
592
593 err = opkg_remove_pkg (opkg->conf, pkg_to_remove, 0);
594
595 /* write out status files and file lists */
596 opkg_conf_write_status_files (opkg->conf);
597 pkg_write_changed_filelists (opkg->conf);
598
599
600 progress (pdata, 100);
601 opkg_package_free (pdata.package);
602 return (err) ? OPKG_UNKNOWN_ERROR : OPKG_NO_ERROR;
603 }
604
605 int
606 opkg_upgrade_package (opkg_t *opkg, const char *package_name, opkg_progress_callback_t progress_callback, void *user_data)
607 {
608 int err;
609 pkg_t *pkg;
610 opkg_progress_data_t pdata;
611
612
613
614 opkg_assert (opkg != NULL);
615 opkg_assert (package_name != NULL);
616
617 pkg_info_preinstall_check (opkg->conf);
618
619 if (opkg->conf->restrict_to_default_dest)
620 {
621 pkg = pkg_hash_fetch_installed_by_name_dest (&opkg->conf->pkg_hash,
622 package_name,
623 opkg->conf->default_dest);
624 if (pkg == NULL)
625 {
626 /* XXX: Error: Package not installed in default_dest */
627 return OPKG_PACKAGE_NOT_INSTALLED;
628 }
629 }
630 else
631 {
632 pkg = pkg_hash_fetch_installed_by_name (&opkg->conf->pkg_hash,
633 package_name);
634 }
635
636 if (!pkg)
637 {
638 /* XXX: Error: Package not installed */
639 return OPKG_PACKAGE_NOT_INSTALLED;
640 }
641
642 pdata.action = OPKG_INSTALL;
643 pdata.package = old_pkg_to_new (pkg);
644 progress (pdata, 0);
645
646 err = opkg_upgrade_pkg (opkg->conf, pkg);
647 /* opkg_upgrade_pkg returns the error codes of opkg_install_pkg */
648 if (err)
649 {
650
651 opkg_package_free (pdata.package);
652 switch (err)
653 {
654 case OPKG_INSTALL_ERR_NOT_TRUSTED: return OPKG_GPG_ERROR;
655 case OPKG_INSTALL_ERR_DOWNLOAD: return OPKG_DOWNLOAD_FAILED;
656 case OPKG_INSTALL_ERR_DEPENDENCIES:
657 case OPKG_INSTALL_ERR_CONFLICTS: return OPKG_DEPENDENCIES_FAILED;
658 case OPKG_INSTALL_ERR_ALREADY_INSTALLED: return OPKG_PACKAGE_ALREADY_INSTALLED;
659 case OPKG_INSTALL_ERR_SIGNATURE: return OPKG_GPG_ERROR;
660 case OPKG_INSTALL_ERR_MD5: return OPKG_MD5_ERROR;
661 default: return OPKG_UNKNOWN_ERROR;
662 }
663 }
664 progress (pdata, 75);
665
666 err = opkg_configure_packages (opkg->conf, NULL);
667 if (err) {
668 opkg_package_free (pdata.package);
669 return OPKG_UNKNOWN_ERROR;
670 }
671
672 /* write out status files and file lists */
673 opkg_conf_write_status_files (opkg->conf);
674 pkg_write_changed_filelists (opkg->conf);
675
676 progress (pdata, 100);
677 opkg_package_free (pdata.package);
678 return 0;
679 }
680
681 int
682 opkg_upgrade_all (opkg_t *opkg, opkg_progress_callback_t progress_callback, void *user_data)
683 {
684 pkg_vec_t *installed;
685 int err = 0;
686 int i;
687 pkg_t *pkg;
688 opkg_progress_data_t pdata;
689
690 pdata.action = OPKG_INSTALL;
691 pdata.package = NULL;
692
693 opkg_assert (opkg != NULL);
694 progress (pdata, 0);
695
696 installed = pkg_vec_alloc ();
697 pkg_info_preinstall_check (opkg->conf);
698
699 pkg_hash_fetch_all_installed (&opkg->conf->pkg_hash, installed);
700 for (i = 0; i < installed->len; i++)
701 {
702 pkg = installed->pkgs[i];
703
704 pdata.package = old_pkg_to_new (pkg);
705 progress (pdata, 99 * i / installed->len);
706 opkg_package_free (pdata.package);
707
708 err += opkg_upgrade_pkg (opkg->conf, pkg);
709 }
710 pkg_vec_free (installed);
711
712 if (err)
713 return 1;
714
715 err = opkg_configure_packages (opkg->conf, NULL);
716 if (err)
717 return 1;
718
719 pdata.package = NULL;
720 progress (pdata, 100);
721 return 0;
722 }
723
724 int
725 opkg_update_package_lists (opkg_t *opkg, opkg_progress_callback_t progress_callback, void *user_data)
726 {
727 char *tmp;
728 int err, result = 0;
729 char *lists_dir;
730 pkg_src_list_elt_t *iter;
731 pkg_src_t *src;
732 int sources_list_count, sources_done;
733 opkg_progress_data_t pdata;
734
735 opkg_assert (opkg != NULL);
736
737 pdata.action = OPKG_DOWNLOAD;
738 pdata.package = NULL;
739 progress (pdata, 0);
740
741 sprintf_alloc (&lists_dir, "%s",
742 (opkg->conf->restrict_to_default_dest)
743 ? opkg->conf->default_dest->lists_dir
744 : opkg->conf->lists_dir);
745
746 if (!file_is_dir (lists_dir))
747 {
748 if (file_exists (lists_dir))
749 {
750 /* XXX: Error: file exists but is not a directory */
751 free (lists_dir);
752 return 1;
753 }
754
755 err = file_mkdir_hier (lists_dir, 0755);
756 if (err)
757 {
758 /* XXX: Error: failed to create directory */
759 free (lists_dir);
760 return 1;
761 }
762 }
763
764 tmp = strdup ("/tmp/opkg.XXXXXX");
765
766 if (mkdtemp (tmp) == NULL)
767 {
768 /* XXX: Error: could not create temporary file name */
769 free (lists_dir);
770 free (tmp);
771 return 1;
772 }
773
774 /* count the number of sources so we can give some progress updates */
775 sources_list_count = 0;
776 sources_done = 0;
777 iter = opkg->conf->pkg_src_list.head;
778 while (iter)
779 {
780 sources_list_count++;
781 iter = iter->next;
782 }
783
784 for (iter = opkg->conf->pkg_src_list.head; iter; iter = iter->next)
785 {
786 char *url, *list_file_name = NULL;
787
788 src = iter->data;
789
790 if (src->extra_data) /* debian style? */
791 sprintf_alloc (&url, "%s/%s/%s", src->value, src->extra_data,
792 src->gzip ? "Packages.gz" : "Packages");
793 else
794 sprintf_alloc (&url, "%s/%s", src->value, src->gzip ? "Packages.gz" : "Packages");
795
796 sprintf_alloc (&list_file_name, "%s/%s", lists_dir, src->name);
797 if (src->gzip)
798 {
799 FILE *in, *out;
800 struct _curl_cb_data cb_data;
801 char *tmp_file_name = NULL;
802
803 sprintf_alloc (&tmp_file_name, "%s/%s.gz", tmp, src->name);
804
805 /* XXX: Note: downloading url */
806
807 cb_data.cb = progress_callback;
808 cb_data.progress_data = &pdata;
809 cb_data.opkg = opkg;
810 cb_data.user_data = user_data;
811 cb_data.start_range = 100 * sources_done / sources_list_count;
812 cb_data.finish_range = 100 * (sources_done + 1) / sources_list_count;
813
814 err = opkg_download (opkg->conf, url, tmp_file_name, (curl_progress_func) curl_progress_cb, &cb_data);
815
816 if (err == 0)
817 {
818 /* XXX: Note: Inflating downloaded file */
819 in = fopen (tmp_file_name, "r");
820 out = fopen (list_file_name, "w");
821 if (in && out)
822 unzip (in, out);
823 else
824 err = 1;
825 if (in)
826 fclose (in);
827 if (out)
828 fclose (out);
829 unlink (tmp_file_name);
830 }
831 free (tmp_file_name);
832 }
833 else
834 err = opkg_download (opkg->conf, url, list_file_name, NULL, NULL);
835
836 if (err)
837 {
838 /* XXX: Error: download error */
839 result = OPKG_DOWNLOAD_FAILED;
840 }
841 free (url);
842
843 #ifdef HAVE_GPGME
844 char *sig_file_name;
845 /* download detached signitures to verify the package lists */
846 /* get the url for the sig file */
847 if (src->extra_data) /* debian style? */
848 sprintf_alloc (&url, "%s/%s/%s", src->value, src->extra_data,
849 "Packages.sig");
850 else
851 sprintf_alloc (&url, "%s/%s", src->value, "Packages.sig");
852
853 /* create filename for signature */
854 sprintf_alloc (&sig_file_name, "%s/%s.sig", lists_dir, src->name);
855
856 /* make sure there is no existing signature file */
857 unlink (sig_file_name);
858
859 err = opkg_download (opkg->conf, url, sig_file_name, NULL, NULL);
860 if (err)
861 {
862 /* XXX: Warning: Download failed */
863 }
864 else
865 {
866 int err;
867 err = opkg_verify_file (opkg->conf, list_file_name, sig_file_name);
868 if (err == 0)
869 {
870 /* XXX: Notice: Signature check passed */
871 }
872 else
873 {
874 /* XXX: Warning: Signature check failed */
875 }
876 }
877 free (sig_file_name);
878 free (list_file_name);
879 free (url);
880 #else
881 /* XXX: Note: Signature check for %s skipped because GPG support was not
882 * enabled in this build
883 */
884 #endif
885
886 sources_done++;
887 progress (pdata, 100 * sources_done / sources_list_count);
888 }
889
890 rmdir (tmp);
891 free (tmp);
892 free (lists_dir);
893
894 /* Now re-read the package lists to update package hash tables. */
895 opkg_re_read_config_files (opkg);
896
897 return result;
898 }
899
900
901 int
902 opkg_list_packages (opkg_t *opkg, opkg_package_callback_t callback, void *user_data)
903 {
904 pkg_vec_t *all;
905 int i;
906
907 opkg_assert (opkg);
908 opkg_assert (callback);
909
910 all = pkg_vec_alloc ();
911 pkg_hash_fetch_available (&opkg->conf->pkg_hash, all);
912 for (i = 0; i < all->len; i++)
913 {
914 pkg_t *pkg;
915 opkg_package_t *package;
916
917 pkg = all->pkgs[i];
918
919 package = old_pkg_to_new (pkg);
920 callback (opkg, package, user_data);
921 opkg_package_free (package);
922 }
923
924 pkg_vec_free (all);
925
926 return 0;
927 }
928
929 int
930 opkg_list_upgradable_packages (opkg_t *opkg, opkg_package_callback_t callback, void *user_data)
931 {
932 pkg_vec_t *all;
933 int i;
934
935 opkg_assert (opkg);
936 opkg_assert (callback);
937
938 /* ensure all data is valid */
939 pkg_info_preinstall_check (opkg->conf);
940
941 all = pkg_vec_alloc ();
942 pkg_hash_fetch_available (&opkg->conf->pkg_hash, all);
943 for (i = 0; i < all->len; i++)
944 {
945 pkg_t *old, *new;
946 int cmp;
947 opkg_package_t *package;
948
949 old = all->pkgs[i];
950
951 if (old->state_status != SS_INSTALLED)
952 continue;
953
954 new = pkg_hash_fetch_best_installation_candidate_by_name(opkg->conf, old->name, NULL);
955 if (new == NULL) {
956 /* XXX: Notice: Assuming locally install package is up to date */
957 continue;
958 }
959
960 cmp = pkg_compare_versions(old, new);
961
962 if (cmp < 0)
963 {
964 package = old_pkg_to_new (new);
965 callback (opkg, package, user_data);
966 opkg_package_free (package);
967 }
968 }
969
970 pkg_vec_free (all);
971
972 return 0;
973 }
974
975 opkg_package_t*
976 opkg_find_package (opkg_t *opkg, const char *name, const char *ver, const char *arch, const char *repo)
977 {
978 pkg_vec_t *all;
979 opkg_package_t *package = NULL;
980 int i;
981 #define sstrcmp(x,y) (x && y) ? strcmp (x, y) : 0
982
983 opkg_assert (opkg);
984
985 all = pkg_vec_alloc ();
986 pkg_hash_fetch_available (&opkg->conf->pkg_hash, all);
987 for (i = 0; i < all->len; i++)
988 {
989 pkg_t *pkg;
990 char *pkgv;
991
992 pkg = all->pkgs[i];
993
994 /* check name */
995 if (sstrcmp (pkg->name, name))
996 continue;
997
998 /* check version */
999 pkgv = pkg_version_str_alloc (pkg);
1000 if (sstrcmp (pkgv, ver))
1001 {
1002 free (pkgv);
1003 continue;
1004 }
1005 free (pkgv);
1006
1007 /* check architecture */
1008 if (arch)
1009 {
1010 if (sstrcmp (pkg->architecture, arch))
1011 continue;
1012 }
1013
1014 /* check repository */
1015 if (repo)
1016 {
1017 if (sstrcmp (pkg->src->name, repo))
1018 continue;
1019 }
1020
1021 /* match found */
1022 package = old_pkg_to_new (pkg);
1023 break;
1024 }
1025
1026 pkg_vec_free (all);
1027
1028 return package;
1029 }
1030
1031 #include <curl/curl.h>
1032 /**
1033 * @brief Check the accessibility of repositories. It will try to access the repository to check if the respository is accessible throught current network status.
1034 * @param opkg The opkg_t
1035 * @return return how many repositories cannot access. 0 means all okay.
1036 */
1037 int opkg_repository_accessibility_check(opkg_t *opkg)
1038 {
1039 pkg_src_list_elt_t *iter;
1040 str_list_elt_t *iter1;
1041 str_list_t *src;
1042 int repositories=0;
1043 int ret=0;
1044 int err;
1045 char *repo_ptr;
1046 char *stmp;
1047 opkg_assert(opkg != NULL);
1048
1049 src = str_list_alloc();
1050
1051 for (iter = opkg->conf->pkg_src_list.head; iter; iter = iter->next)
1052 {
1053 if (strstr(iter->data->value, "://") &&
1054 index(strstr(iter->data->value, "://") + 3, '/'))
1055 stmp = strndup(iter->data->value,
1056 (index(strstr(iter->data->value, "://") + 3, '/') - iter->data->value)*sizeof(char));
1057
1058 else
1059 stmp = strdup(iter->data->value);
1060
1061 for (iter1 = src->head; iter1; iter1 = iter1->next)
1062 {
1063 if (strstr(iter1->data, stmp))
1064 break;
1065 }
1066 if (iter1)
1067 continue;
1068
1069 sprintf_alloc(&repo_ptr, "%s/index.html",stmp);
1070 free(stmp);
1071
1072 str_list_append(src, repo_ptr);
1073 repositories++;
1074 }
1075 while (repositories > 0)
1076 {
1077 iter1 = str_list_pop(src);
1078 repositories--;
1079
1080 err = opkg_download(opkg->conf, iter1->data, "/dev/null", NULL, NULL);
1081 if (!(err == CURLE_OK ||
1082 err == CURLE_HTTP_RETURNED_ERROR ||
1083 err == CURLE_FILE_COULDNT_READ_FILE ||
1084 err == CURLE_REMOTE_FILE_NOT_FOUND ||
1085 err == CURLE_TFTP_NOTFOUND
1086 )) {
1087 ret++;
1088 }
1089 str_list_elt_deinit(iter1);
1090 free(iter1);
1091 }
1092 free(src);
1093 return ret;
1094 }