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