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