Remove dead code in opkg_remove_cmd().
[oweals/opkg-lede.git] / libopkg / opkg_cmd.c
1 /* opkg_cmd.c - the opkg package management system
2
3    Carl D. Worth
4
5    Copyright (C) 2001 University of Southern California
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
19 #include "includes.h"
20 #include <dirent.h>
21 #include <glob.h>
22 #include <fnmatch.h>
23
24 #include "opkg_conf.h"
25 #include "opkg_cmd.h"
26 #include "opkg_message.h"
27 #include "pkg.h"
28 #include "pkg_dest.h"
29 #include "pkg_parse.h"
30 #include "sprintf_alloc.h"
31 #include "pkg.h"
32 #include "file_util.h"
33 #include "str_util.h"
34 #include "libbb/libbb.h"
35 #include "opkg_utils.h"
36 #include "opkg_defines.h"
37 #include "opkg_download.h"
38 #include "opkg_install.h"
39 #include "opkg_upgrade.h"
40 #include "opkg_remove.h"
41 #include "opkg_configure.h"
42 #include "opkg_message.h"
43 #include "libopkg.h"
44 #include "xsystem.h"
45
46 static int opkg_update_cmd(opkg_conf_t *conf, int argc, char **argv);
47 static int opkg_upgrade_cmd(opkg_conf_t *conf, int argc, char **argv);
48 static int opkg_list_cmd(opkg_conf_t *conf, int argc, char **argv);
49 static int opkg_info_cmd(opkg_conf_t *conf, int argc, char **argv);
50 static int opkg_status_cmd(opkg_conf_t *conf, int argc, char **argv);
51 static int opkg_install_pending_cmd(opkg_conf_t *conf, int argc, char **argv);
52 static int opkg_install_cmd(opkg_conf_t *conf, int argc, char **argv);
53 static int opkg_list_installed_cmd(opkg_conf_t *conf, int argc, char **argv);
54 static int opkg_list_upgradable_cmd(opkg_conf_t *conf, int argc, char **argv);
55 static int opkg_remove_cmd(opkg_conf_t *conf, int argc, char **argv);
56 static int opkg_purge_cmd(opkg_conf_t *conf, int argc, char **argv);
57 static int opkg_flag_cmd(opkg_conf_t *conf, int argc, char **argv);
58 static int opkg_files_cmd(opkg_conf_t *conf, int argc, char **argv);
59 static int opkg_search_cmd(opkg_conf_t *conf, int argc, char **argv);
60 static int opkg_download_cmd(opkg_conf_t *conf, int argc, char **argv);
61 static int opkg_depends_cmd(opkg_conf_t *conf, int argc, char **argv);
62 static int opkg_whatdepends_cmd(opkg_conf_t *conf, int argc, char **argv);
63 static int opkg_whatdepends_recursively_cmd(opkg_conf_t *conf, int argc, char **argv);
64 static int opkg_whatsuggests_cmd(opkg_conf_t *conf, int argc, char **argv);
65 static int opkg_whatrecommends_cmd(opkg_conf_t *conf, int argc, char **argv);
66 static int opkg_whatprovides_cmd(opkg_conf_t *conf, int argc, char **argv);
67 static int opkg_whatconflicts_cmd(opkg_conf_t *conf, int argc, char **argv);
68 static int opkg_whatreplaces_cmd(opkg_conf_t *conf, int argc, char **argv);
69 static int opkg_compare_versions_cmd(opkg_conf_t *conf, int argc, char **argv);
70 static int opkg_print_architecture_cmd(opkg_conf_t *conf, int argc, char **argv);
71 static int opkg_configure_cmd(opkg_conf_t *conf, int argc, char **argv);
72 static int pkg_mark_provides(pkg_t *pkg);
73
74 /* XXX: CLEANUP: The usage strings should be incorporated into this
75    array for easier maintenance */
76 static opkg_cmd_t cmds[] = {
77      {"update", 0, (opkg_cmd_fun_t)opkg_update_cmd}, 
78      {"upgrade", 0, (opkg_cmd_fun_t)opkg_upgrade_cmd},
79      {"list", 0, (opkg_cmd_fun_t)opkg_list_cmd},
80      {"list_installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd},
81      {"list-installed", 0, (opkg_cmd_fun_t)opkg_list_installed_cmd},
82      {"list_upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd},
83      {"list-upgradable", 0, (opkg_cmd_fun_t)opkg_list_upgradable_cmd},
84      {"info", 0, (opkg_cmd_fun_t)opkg_info_cmd},
85      {"flag", 1, (opkg_cmd_fun_t)opkg_flag_cmd},
86      {"status", 0, (opkg_cmd_fun_t)opkg_status_cmd},
87      {"install_pending", 0, (opkg_cmd_fun_t)opkg_install_pending_cmd},
88      {"install-pending", 0, (opkg_cmd_fun_t)opkg_install_pending_cmd},
89      {"install", 1, (opkg_cmd_fun_t)opkg_install_cmd},
90      {"remove", 1, (opkg_cmd_fun_t)opkg_remove_cmd},
91      {"purge", 1, (opkg_cmd_fun_t)opkg_purge_cmd},
92      {"configure", 0, (opkg_cmd_fun_t)opkg_configure_cmd},
93      {"files", 1, (opkg_cmd_fun_t)opkg_files_cmd},
94      {"search", 1, (opkg_cmd_fun_t)opkg_search_cmd},
95      {"download", 1, (opkg_cmd_fun_t)opkg_download_cmd},
96      {"compare_versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd},
97      {"compare-versions", 1, (opkg_cmd_fun_t)opkg_compare_versions_cmd},
98      {"print-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
99      {"print_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
100      {"print-installation-architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
101      {"print_installation_architecture", 0, (opkg_cmd_fun_t)opkg_print_architecture_cmd},
102      {"depends", 1, (opkg_cmd_fun_t)opkg_depends_cmd},
103      {"whatdepends", 1, (opkg_cmd_fun_t)opkg_whatdepends_cmd},
104      {"whatdependsrec", 1, (opkg_cmd_fun_t)opkg_whatdepends_recursively_cmd},
105      {"whatrecommends", 1, (opkg_cmd_fun_t)opkg_whatrecommends_cmd},
106      {"whatsuggests", 1, (opkg_cmd_fun_t)opkg_whatsuggests_cmd},
107      {"whatprovides", 1, (opkg_cmd_fun_t)opkg_whatprovides_cmd},
108      {"whatreplaces", 1, (opkg_cmd_fun_t)opkg_whatreplaces_cmd},
109      {"whatconflicts", 1, (opkg_cmd_fun_t)opkg_whatconflicts_cmd},
110 };
111
112 static void print_pkg(pkg_t *pkg)
113 {
114         char *version = pkg_version_str_alloc(pkg);
115         if (pkg->description)
116                 printf("%s - %s - %s\n", pkg->name, version, pkg->description);
117         else
118                 printf("%s - %s\n", pkg->name, version);
119         free(version);
120 }
121
122 int opkg_state_changed;
123 static void write_status_files_if_changed(opkg_conf_t *conf)
124 {
125      if (opkg_state_changed && !conf->noaction) {
126           opkg_message(conf, OPKG_INFO,
127                        "  writing status file\n");
128           opkg_conf_write_status_files(conf);
129           pkg_write_changed_filelists(conf);
130      } else { 
131           opkg_message(conf, OPKG_DEBUG, "Nothing to be done\n");
132      }
133 }
134
135
136 static int num_cmds = sizeof(cmds) / sizeof(opkg_cmd_t);
137
138 opkg_cmd_t *opkg_cmd_find(const char *name)
139 {
140      int i;
141      opkg_cmd_t *cmd;
142
143      for (i=0; i < num_cmds; i++) {
144           cmd = &cmds[i];
145           if (strcmp(name, cmd->name) == 0) {
146                return cmd;
147           }
148      }
149
150      return NULL;
151 }
152
153 int opkg_cmd_exec(opkg_cmd_t *cmd, opkg_conf_t *conf, int argc, const char **argv, void *userdata)
154 {
155         int result;
156
157         result = (cmd->fun)(conf, argc, argv);
158
159         print_error_list();
160         free_error_list();
161
162         return result;
163 }
164
165 static int opkg_update_cmd(opkg_conf_t *conf, int argc, char **argv)
166 {
167      char *tmp;
168      int err;
169      int failures;
170      char *lists_dir;
171      pkg_src_list_elt_t *iter;
172      pkg_src_t *src;
173
174  
175     sprintf_alloc(&lists_dir, "%s", conf->restrict_to_default_dest ? conf->default_dest->lists_dir : conf->lists_dir);
176  
177     if (! file_is_dir(lists_dir)) {
178           if (file_exists(lists_dir)) {
179                opkg_message(conf, OPKG_ERROR,
180                             "%s: ERROR: %s exists, but is not a directory\n",
181                             __FUNCTION__, lists_dir);
182                free(lists_dir);
183                return -1;
184           }
185           err = file_mkdir_hier(lists_dir, 0755);
186           if (err) {
187                opkg_message(conf, OPKG_ERROR,
188                             "%s: ERROR: failed to make directory %s: %s\n",
189                             __FUNCTION__, lists_dir, strerror(errno));
190                free(lists_dir);
191                return -1;
192           }     
193      } 
194
195      failures = 0;
196
197      sprintf_alloc(&tmp, "%s/update-XXXXXX", conf->tmp_dir);
198      if (mkdtemp (tmp) == NULL) {
199          perror ("mkdtemp");
200          return -1;
201      }
202
203
204      for (iter = void_list_first(&conf->pkg_src_list); iter; iter = void_list_next(&conf->pkg_src_list, iter)) {
205           char *url, *list_file_name;
206
207           src = (pkg_src_t *)iter->data;
208
209           if (src->extra_data)  /* debian style? */
210               sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data, 
211                             src->gzip ? "Packages.gz" : "Packages");
212           else
213               sprintf_alloc(&url, "%s/%s", src->value, src->gzip ? "Packages.gz" : "Packages");
214
215           sprintf_alloc(&list_file_name, "%s/%s", lists_dir, src->name);
216           if (src->gzip) {
217               char *tmp_file_name;
218               FILE *in, *out;
219               
220               sprintf_alloc (&tmp_file_name, "%s/%s.gz", tmp, src->name);
221               err = opkg_download(conf, url, tmp_file_name, NULL, NULL);
222               if (err == 0) {
223                    opkg_message (conf, OPKG_NOTICE, "Inflating %s\n", url);
224                    in = fopen (tmp_file_name, "r");
225                    out = fopen (list_file_name, "w");
226                    if (in && out)
227                         unzip (in, out);
228                    else
229                         err = 1;
230                    if (in)
231                         fclose (in);
232                    if (out)
233                         fclose (out);
234                    unlink (tmp_file_name);
235               }
236               free(tmp_file_name);
237           } else
238               err = opkg_download(conf, url, list_file_name, NULL, NULL);
239           if (err) {
240                failures++;
241           } else {
242                opkg_message(conf, OPKG_NOTICE,
243                             "Updated list of available packages in %s\n",
244                             list_file_name);
245           }
246           free(url);
247 #if defined(HAVE_GPGME) || defined(HAVE_OPENSSL)
248           if (conf->check_signature) {
249               /* download detached signitures to verify the package lists */
250               /* get the url for the sig file */
251               if (src->extra_data)      /* debian style? */
252                   sprintf_alloc(&url, "%s/%s/%s", src->value, src->extra_data,
253                           "Packages.sig");
254               else
255                   sprintf_alloc(&url, "%s/%s", src->value, "Packages.sig");
256
257               /* create temporary file for it */
258               char *tmp_file_name;
259
260               /* Put the signature in the right place */
261               sprintf_alloc (&tmp_file_name, "%s/%s.sig", lists_dir, src->name);
262
263               err = opkg_download(conf, url, tmp_file_name, NULL, NULL);
264               if (err) {
265                   failures++;
266                   opkg_message (conf, OPKG_NOTICE, "Signature check failed\n");
267               } else {
268                   int err;
269                   err = opkg_verify_file (conf, list_file_name, tmp_file_name);
270                   if (err == 0)
271                       opkg_message (conf, OPKG_NOTICE, "Signature check passed\n");
272                   else
273                       opkg_message (conf, OPKG_NOTICE, "Signature check failed\n");
274               }
275               /* We shouldn't unlink the signature ! */
276               // unlink (tmp_file_name);
277               free (tmp_file_name);
278               free (url);
279           }
280 #else
281           // Do nothing
282 #endif
283           free(list_file_name);
284      }
285      rmdir (tmp);
286      free (tmp);
287      free(lists_dir);
288
289      return failures;
290 }
291
292
293 struct opkg_intercept
294 {
295     char *oldpath;
296     char *statedir;
297 };
298
299 typedef struct opkg_intercept *opkg_intercept_t;
300
301 static opkg_intercept_t opkg_prep_intercepts(opkg_conf_t *conf)
302 {
303     opkg_intercept_t ctx;
304     char *newpath;
305
306     ctx = xcalloc(1, sizeof (*ctx));
307     ctx->oldpath = xstrdup(getenv("PATH"));
308     sprintf_alloc(&newpath, "%s/opkg/intercept:%s", DATADIR, ctx->oldpath);
309     sprintf_alloc(&ctx->statedir, "%s/opkg-intercept-XXXXXX", conf->tmp_dir);
310
311     if (mkdtemp(ctx->statedir) == NULL) {
312         fprintf(stderr, "%s: mkdtemp: %s\n", __FUNCTION__, strerror(errno));
313         free(ctx->oldpath);
314         free(ctx->statedir);
315         free(newpath);
316         free(ctx);
317         return NULL;
318     }
319
320     setenv("OPKG_INTERCEPT_DIR", ctx->statedir, 1);
321     setenv("PATH", newpath, 1);
322     free(newpath);
323
324     return ctx;
325 }
326
327 static int opkg_finalize_intercepts(opkg_intercept_t ctx)
328 {
329     DIR *dir;
330     int err = 0;
331
332     setenv ("PATH", ctx->oldpath, 1);
333     free (ctx->oldpath);
334
335     dir = opendir (ctx->statedir);
336     if (dir) {
337         struct dirent *de;
338         while (de = readdir (dir), de != NULL) {
339             char *path;
340
341             if (de->d_name[0] == '.')
342                 continue;
343             
344             sprintf_alloc (&path, "%s/%s", ctx->statedir, de->d_name);
345             if (access (path, X_OK) == 0) {
346                 const char *argv[] = {"sh", "-c", path, NULL};
347                 xsystem (argv);
348             }
349             free (path);
350         }
351         closedir(dir);
352     } else
353         perror (ctx->statedir);
354         
355     rm_r(ctx->statedir);
356     free (ctx->statedir);
357     free (ctx);
358
359     return err;
360 }
361
362 /* For package pkg do the following: If it is already visited, return. If not,
363    add it in visited list and recurse to its deps. Finally, add it to ordered 
364    list.
365    pkg_vec all contains all available packages in repos.
366    pkg_vec visited contains packages already visited by this function, and is 
367    used to end recursion and avoid an infinite loop on graph cycles.
368    pkg_vec ordered will finally contain the ordered set of packages.
369 */
370 static int opkg_recurse_pkgs_in_order(opkg_conf_t *conf, pkg_t *pkg, pkg_vec_t *all,
371                                pkg_vec_t *visited, pkg_vec_t *ordered)
372 {
373     int j,k,l,m;
374     int count;
375     pkg_t *dep;
376     compound_depend_t * compound_depend;
377     depend_t ** possible_satisfiers;
378     abstract_pkg_t *abpkg;
379     abstract_pkg_t **dependents;
380
381     /* If it's just an available package, that is, not installed and not even
382        unpacked, skip it */
383     /* XXX: This is probably an overkill, since a state_status != SS_UNPACKED 
384        would do here. However, if there is an intermediate node (pkg) that is 
385        configured and installed between two unpacked packages, the latter 
386        won't be properly reordered, unless all installed/unpacked pkgs are
387        checked */
388     if (pkg->state_status == SS_NOT_INSTALLED) 
389         return 0;
390
391     /* If the  package has already been visited (by this function), skip it */
392     for(j = 0; j < visited->len; j++) 
393         if ( ! strcmp(visited->pkgs[j]->name, pkg->name)) {
394             opkg_message(conf, OPKG_INFO,
395                          "  pkg: %s already visited\n", pkg->name);
396             return 0;
397         }
398     
399     pkg_vec_insert(visited, pkg);
400
401     count = pkg->pre_depends_count + pkg->depends_count + \
402         pkg->recommends_count + pkg->suggests_count;
403
404     opkg_message(conf, OPKG_INFO,
405                  "  pkg: %s\n", pkg->name);
406
407     /* Iterate over all the dependencies of pkg. For each one, find a package 
408        that is either installed or unpacked and satisfies this dependency.
409        (there should only be one such package per dependency installed or 
410        unpacked). Then recurse to the dependency package */
411     for (j=0; j < count ; j++) {
412         compound_depend = &pkg->depends[j];
413         possible_satisfiers = compound_depend->possibilities;
414         for (k=0; k < compound_depend->possibility_count ; k++) {
415             abpkg = possible_satisfiers[k]->pkg;
416             dependents = abpkg->provided_by->pkgs;
417             l = 0;
418             if (dependents != NULL)
419                 while (l < abpkg->provided_by->len && dependents[l] != NULL) {
420                     opkg_message(conf, OPKG_INFO,
421                                  "  Descending on pkg: %s\n", 
422                                  dependents [l]->name);
423     
424                     /* find whether dependent l is installed or unpacked,
425                      * and then find which package in the list satisfies it */
426                     for(m = 0; m < all->len; m++) {
427                         dep = all->pkgs[m];
428                         if ( dep->state_status != SS_NOT_INSTALLED)
429                             if ( ! strcmp(dep->name, dependents[l]->name)) {
430                                 opkg_recurse_pkgs_in_order(conf, dep, all, 
431                                                            visited, ordered);
432                                 /* Stop the outer loop */
433                                 l = abpkg->provided_by->len;
434                                 /* break from the inner loop */
435                                 break;
436                             }
437                     }
438                     l++;
439                 }
440         }
441     }
442
443     /* When all recursions from this node down, are over, and all 
444        dependencies have been added in proper order in the ordered array, add
445        also the package pkg to ordered array */
446     pkg_vec_insert(ordered, pkg);
447
448     return 0;
449
450 }
451
452 static int opkg_configure_packages(opkg_conf_t *conf, char *pkg_name)
453 {
454      pkg_vec_t *all, *ordered, *visited;
455      int i;
456      pkg_t *pkg;
457      opkg_intercept_t ic;
458      int r, err = 0;
459
460      opkg_message(conf, OPKG_INFO,
461                   "Configuring unpacked packages\n");
462      fflush( stdout );
463
464      all = pkg_vec_alloc();
465
466      pkg_hash_fetch_available(&conf->pkg_hash, all);
467
468      /* Reorder pkgs in order to be configured according to the Depends: tag
469         order */
470      opkg_message(conf, OPKG_INFO,
471                   "Reordering packages before configuring them...\n");
472      ordered = pkg_vec_alloc();
473      visited = pkg_vec_alloc();
474      for(i = 0; i < all->len; i++) {
475          pkg = all->pkgs[i];
476          opkg_recurse_pkgs_in_order(conf, pkg, all, visited, ordered);
477      }
478
479      ic = opkg_prep_intercepts (conf);
480      if (ic == NULL) {
481              err = -1;
482              goto error;
483      }
484     
485      for(i = 0; i < all->len; i++) {
486           pkg = all->pkgs[i];
487
488           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 
489                continue;
490
491           if (pkg->state_status == SS_UNPACKED) {
492                opkg_message(conf, OPKG_NOTICE,
493                             "Configuring %s\n", pkg->name);
494                fflush( stdout );
495                r = opkg_configure(conf, pkg);
496                if (r == 0) {
497                     pkg->state_status = SS_INSTALLED;
498                     pkg->parent->state_status = SS_INSTALLED;
499                     pkg->state_flag &= ~SF_PREFER;
500                } else {
501                     if (!err)
502                         err = r;
503                }
504           }
505      }
506
507      r = opkg_finalize_intercepts (ic);
508      if (r && !err)
509          err = r;
510
511 error:
512      pkg_vec_free(all);
513      pkg_vec_free(ordered);
514      pkg_vec_free(visited);
515
516      return err;
517 }
518
519 static opkg_conf_t *global_conf;
520
521 static void sigint_handler(int sig)
522 {
523      signal(sig, SIG_DFL);
524      opkg_message(NULL, OPKG_NOTICE,
525                   "opkg: interrupted. writing out status database\n");
526      write_status_files_if_changed(global_conf);
527      exit(128 + sig);
528 }
529
530 static int opkg_install_cmd(opkg_conf_t *conf, int argc, char **argv)
531 {
532      int i;
533      char *arg;
534      int err=0;
535
536      global_conf = conf;
537      signal(SIGINT, sigint_handler);
538
539      /*
540       * Now scan through package names and install
541       */
542      for (i=0; i < argc; i++) {
543           arg = argv[i];
544
545           opkg_message(conf, OPKG_DEBUG2, "Debug install_cmd: %s  \n",arg );
546           err = opkg_prepare_url_for_install(conf, arg, &argv[i]);
547           if (err != EINVAL && err != 0)
548               return err;
549      }
550      pkg_info_preinstall_check(conf);
551
552      for (i=0; i < argc; i++) {
553           arg = argv[i];
554           err = opkg_install_by_name(conf, arg);
555           if (err == OPKG_PKG_HAS_NO_CANDIDATE) {
556                opkg_message(conf, OPKG_ERROR,
557                             "Cannot find package %s.\n",
558                             arg);
559           }
560      }
561
562      opkg_configure_packages(conf, NULL);
563
564      write_status_files_if_changed(conf);
565
566      return err;
567 }
568
569 static int opkg_upgrade_cmd(opkg_conf_t *conf, int argc, char **argv)
570 {
571      int i;
572      pkg_t *pkg;
573      int err;
574
575      global_conf = conf;
576      signal(SIGINT, sigint_handler);
577
578      if (argc) {
579           for (i=0; i < argc; i++) {
580                char *arg = argv[i];
581
582                err = opkg_prepare_url_for_install(conf, arg, &arg);
583                if (err != EINVAL && err != 0)
584                    return err;
585           }
586           pkg_info_preinstall_check(conf);
587
588           for (i=0; i < argc; i++) {
589                char *arg = argv[i];
590                if (conf->restrict_to_default_dest) {
591                     pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
592                                                                 argv[i],
593                                                                 conf->default_dest);
594                     if (pkg == NULL) {
595                          opkg_message(conf, OPKG_NOTICE,
596                                       "Package %s not installed in %s\n",
597                                       argv[i], conf->default_dest->name);
598                          continue;
599                     }
600                } else {
601                     pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
602                                                            argv[i]);
603                }
604                if (pkg)
605                     opkg_upgrade_pkg(conf, pkg);
606                else {
607                     opkg_install_by_name(conf, arg);
608                }
609           }
610      } else {
611           pkg_vec_t *installed = pkg_vec_alloc();
612
613           pkg_info_preinstall_check(conf);
614
615           pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
616           for (i = 0; i < installed->len; i++) {
617                pkg = installed->pkgs[i];
618                opkg_upgrade_pkg(conf, pkg);
619           }
620           pkg_vec_free(installed);
621      }
622
623      opkg_configure_packages(conf, NULL);
624
625      write_status_files_if_changed(conf);
626
627      return 0;
628 }
629
630 static int opkg_download_cmd(opkg_conf_t *conf, int argc, char **argv)
631 {
632      int i, err;
633      char *arg;
634      pkg_t *pkg;
635
636      pkg_info_preinstall_check(conf);
637      for (i = 0; i < argc; i++) {
638           arg = argv[i];
639
640           pkg = pkg_hash_fetch_best_installation_candidate_by_name(conf, arg, &err);
641           if (pkg == NULL) {
642                opkg_message(conf, OPKG_ERROR,
643                             "Cannot find package %s.\n"
644                             "Check the spelling or perhaps run 'opkg update'\n",
645                             arg);
646                continue;
647           }
648
649           err = opkg_download_pkg(conf, pkg, ".");
650
651           if (err) {
652                opkg_message(conf, OPKG_ERROR,
653                             "Failed to download %s\n", pkg->name);
654           } else {
655                opkg_message(conf, OPKG_NOTICE,
656                             "Downloaded %s as %s\n",
657                             pkg->name, pkg->local_filename);
658           }
659      }
660
661      return 0;
662 }
663
664
665 static int opkg_list_cmd(opkg_conf_t *conf, int argc, char **argv)
666 {
667      int i;
668      pkg_vec_t *available;
669      pkg_t *pkg;
670      char *pkg_name = NULL;
671
672      if (argc > 0) {
673           pkg_name = argv[0];
674      }
675      available = pkg_vec_alloc();
676      pkg_hash_fetch_available(&conf->pkg_hash, available);
677      pkg_vec_sort(available, pkg_compare_names);
678      for (i=0; i < available->len; i++) {
679           pkg = available->pkgs[i];
680           /* if we have package name or pattern and pkg does not match, then skip it */
681           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 
682                continue;
683           print_pkg(pkg);
684      }
685      pkg_vec_free(available);
686
687      return 0;
688 }
689
690
691 static int opkg_list_installed_cmd(opkg_conf_t *conf, int argc, char **argv)
692 {
693      int i ;
694      pkg_vec_t *available;
695      pkg_t *pkg;
696      char *pkg_name = NULL;
697
698      if (argc > 0) {
699           pkg_name = argv[0];
700      }
701      available = pkg_vec_alloc();
702      pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
703      pkg_vec_sort(available, pkg_compare_names);
704      for (i=0; i < available->len; i++) {
705           pkg = available->pkgs[i];
706           /* if we have package name or pattern and pkg does not match, then skip it */
707           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) 
708                continue;
709           print_pkg(pkg);
710      }
711
712      pkg_vec_free(available);
713
714      return 0;
715 }
716
717 static int opkg_list_upgradable_cmd(opkg_conf_t *conf, int argc, char **argv) 
718 {
719     struct active_list *head = prepare_upgrade_list(conf);
720     struct active_list *node=NULL;
721     pkg_t *_old_pkg, *_new_pkg;
722     char *old_v, *new_v;
723     for (node = active_list_next(head, head); node;node = active_list_next(head,node)) {
724         _old_pkg = list_entry(node, pkg_t, list);
725         _new_pkg = pkg_hash_fetch_best_installation_candidate_by_name(conf, _old_pkg->name, NULL);
726         old_v = pkg_version_str_alloc(_old_pkg);
727         new_v = pkg_version_str_alloc(_new_pkg);
728         printf("%s - %s - %s\n", _old_pkg->name, old_v, new_v);
729         free(old_v);
730         free(new_v);
731     }
732     active_list_head_delete(head);
733     return 0;
734 }
735
736 static int opkg_info_status_cmd(opkg_conf_t *conf, int argc, char **argv, int installed_only)
737 {
738      int i;
739      pkg_vec_t *available;
740      pkg_t *pkg;
741      char *pkg_name = NULL;
742
743      if (argc > 0) {
744           pkg_name = argv[0];
745      }
746
747      available = pkg_vec_alloc();
748      if (installed_only)
749           pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
750      else
751           pkg_hash_fetch_available(&conf->pkg_hash, available);
752
753      for (i=0; i < available->len; i++) {
754           pkg = available->pkgs[i];
755           if (pkg_name && fnmatch(pkg_name, pkg->name, 0)) {
756                continue;
757           }
758
759           pkg_formatted_info(stdout, pkg);
760
761           if (conf->verbosity >= OPKG_NOTICE) {
762                conffile_list_elt_t *iter;
763                for (iter = nv_pair_list_first(&pkg->conffiles); iter; iter = nv_pair_list_next(&pkg->conffiles, iter)) {
764                     conffile_t *cf = (conffile_t *)iter->data;
765                     int modified = conffile_has_been_modified(conf, cf);
766                     if (cf->value)
767                         opkg_message(conf, OPKG_NOTICE,
768                                 "conffile=%s md5sum=%s modified=%d\n",
769                                  cf->name, cf->value, modified);
770                }
771           }
772      }
773      pkg_vec_free(available);
774
775      return 0;
776 }
777
778 static int opkg_info_cmd(opkg_conf_t *conf, int argc, char **argv)
779 {
780      return opkg_info_status_cmd(conf, argc, argv, 0);
781 }
782
783 static int opkg_status_cmd(opkg_conf_t *conf, int argc, char **argv)
784 {
785      return opkg_info_status_cmd(conf, argc, argv, 1);
786 }
787
788 static int opkg_configure_cmd(opkg_conf_t *conf, int argc, char **argv)
789 {
790      
791      int err;
792      if (argc > 0) {
793           char *pkg_name = NULL;
794
795           pkg_name = argv[0];
796
797           err = opkg_configure_packages (conf, pkg_name);
798      
799      } else {
800           err = opkg_configure_packages (conf, NULL);
801      }
802
803      write_status_files_if_changed(conf);
804
805      return err;
806 }
807
808 static int opkg_install_pending_cmd(opkg_conf_t *conf, int argc, char **argv)
809 {
810      int i, err;
811      char *globpattern;
812      glob_t globbuf;
813     
814      sprintf_alloc(&globpattern, "%s/*" OPKG_PKG_EXTENSION, conf->pending_dir);
815      err = glob(globpattern, 0, NULL, &globbuf);
816      free(globpattern);
817      if (err) {
818           return 0;
819      }
820
821      opkg_message(conf, OPKG_NOTICE,
822                   "The following packages in %s will now be installed.\n",
823                   conf->pending_dir);
824      for (i = 0; i < globbuf.gl_pathc; i++) {
825           opkg_message(conf, OPKG_NOTICE,
826                        "%s%s", i == 0 ? "" : " ", globbuf.gl_pathv[i]);
827      }
828      opkg_message(conf, OPKG_NOTICE, "\n");
829      for (i = 0; i < globbuf.gl_pathc; i++) {
830           err = opkg_install_from_file(conf, globbuf.gl_pathv[i]);
831           if (err == 0) {
832                err = unlink(globbuf.gl_pathv[i]);
833                if (err) {
834                     opkg_message(conf, OPKG_ERROR,
835                                  "%s: ERROR: failed to unlink %s: %s\n",
836                                  __FUNCTION__, globbuf.gl_pathv[i], strerror(err));
837                     return err;
838                }
839           }
840      }
841      globfree(&globbuf);
842
843      return err;
844 }
845
846 static int opkg_remove_cmd(opkg_conf_t *conf, int argc, char **argv)
847 {
848      int i, a, done;
849      pkg_t *pkg;
850      pkg_t *pkg_to_remove;
851      pkg_vec_t *available;
852
853      global_conf = conf;
854      done = 0;
855
856      signal(SIGINT, sigint_handler);
857
858      pkg_info_preinstall_check(conf);
859
860      available = pkg_vec_alloc();
861      pkg_hash_fetch_all_installed(&conf->pkg_hash, available);
862
863      for (i=0; i<argc; i++) {
864         for (a=0; a<available->len; a++) {
865             pkg = available->pkgs[a];
866             if (fnmatch(argv[i], pkg->name, 0)) {
867                continue;
868             }
869             if (conf->restrict_to_default_dest) {
870                  pkg_to_remove = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
871                                         pkg->name,
872                                         conf->default_dest);
873             } else {
874                  pkg_to_remove = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, pkg->name );
875             }
876         
877             if (pkg_to_remove == NULL) {
878                  opkg_message(conf, OPKG_ERROR, "Package %s is not installed.\n", pkg->name);
879                  continue;
880             }
881             if (pkg->state_status == SS_NOT_INSTALLED) {    // Added the control, so every already removed package could be skipped
882                  opkg_message(conf, OPKG_ERROR, "Package seems to be %s not installed (STATUS = NOT_INSTALLED).\n", pkg->name);
883                  continue;
884             }
885             opkg_remove_pkg(conf, pkg_to_remove, 0);
886             done = 1;
887         }
888      }
889
890      pkg_vec_free(available);
891
892      if (done == 0)
893         opkg_message(conf, OPKG_NOTICE, "No packages removed.\n");
894
895      write_status_files_if_changed(conf);
896      return 0;
897 }
898
899 static int opkg_purge_cmd(opkg_conf_t *conf, int argc, char **argv)
900 {
901      int i;
902      pkg_t *pkg;
903
904      global_conf = conf;
905      signal(SIGINT, sigint_handler);
906
907      pkg_info_preinstall_check(conf);
908
909      for (i=0; i < argc; i++) {
910           if (conf->restrict_to_default_dest) {
911                pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
912                                                            argv[i],
913                                                            conf->default_dest);
914           } else {
915                pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
916           }
917
918           if (pkg == NULL) {
919                opkg_message(conf, OPKG_ERROR,
920                             "Package %s is not installed.\n", argv[i]);
921                continue;
922           }
923           opkg_purge_pkg(conf, pkg);
924      }
925
926      write_status_files_if_changed(conf);
927      return 0;
928 }
929
930 static int opkg_flag_cmd(opkg_conf_t *conf, int argc, char **argv)
931 {
932      int i;
933      pkg_t *pkg;
934      const char *flags = argv[0];
935     
936      global_conf = conf;
937      signal(SIGINT, sigint_handler);
938
939      for (i=1; i < argc; i++) {
940           if (conf->restrict_to_default_dest) {
941                pkg = pkg_hash_fetch_installed_by_name_dest(&conf->pkg_hash,
942                                                            argv[i],
943                                                            conf->default_dest);
944           } else {
945                pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash, argv[i]);
946           }
947
948           if (pkg == NULL) {
949                opkg_message(conf, OPKG_ERROR,
950                             "Package %s is not installed.\n", argv[i]);
951                continue;
952           }
953           if (( strcmp(flags,"hold")==0)||( strcmp(flags,"noprune")==0)||
954               ( strcmp(flags,"user")==0)||( strcmp(flags,"ok")==0)) {
955               pkg->state_flag = pkg_state_flag_from_str(flags);
956           }
957 /* pb_ asked this feature 03292004 */
958 /* Actually I will use only this two, but this is an open for various status */
959           if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){
960               pkg->state_status = pkg_state_status_from_str(flags);
961           }
962           opkg_state_changed++;
963           opkg_message(conf, OPKG_NOTICE,
964                        "Setting flags for package %s to %s\n",
965                        pkg->name, flags);
966      }
967
968      write_status_files_if_changed(conf);
969      return 0;
970 }
971
972 static int opkg_files_cmd(opkg_conf_t *conf, int argc, char **argv)
973 {
974      pkg_t *pkg;
975      str_list_t *files;
976      str_list_elt_t *iter;
977      char *pkg_version;
978
979      if (argc < 1) {
980           return EINVAL;
981      }
982
983      pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
984                                             argv[0]);
985      if (pkg == NULL) {
986           opkg_message(conf, OPKG_ERROR,
987                        "Package %s not installed.\n", argv[0]);
988           return 0;
989      }
990
991      files = pkg_get_installed_files(conf, pkg);
992      pkg_version = pkg_version_str_alloc(pkg);
993
994      printf("Package %s (%s) is installed on %s and has the following files:\n",
995                 pkg->name, pkg_version, pkg->dest->name);
996
997      for (iter=str_list_first(files); iter; iter=str_list_next(files, iter))
998           printf("%s\n", (char *)iter->data);
999
1000      free(pkg_version);
1001      pkg_free_installed_files(pkg);
1002
1003      return 0;
1004 }
1005
1006 static int opkg_depends_cmd(opkg_conf_t *conf, int argc, char **argv)
1007 {
1008
1009      if (argc > 0) {
1010           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1011           const char *rel_str = "depends on";
1012           int i;
1013      
1014           pkg_info_preinstall_check(conf);
1015
1016           if (conf->query_all)
1017                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1018           else
1019                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1020           for (i = 0; i < argc; i++) {
1021                const char *target = argv[i];
1022                int j;
1023
1024                opkg_message(conf, OPKG_NOTICE, "target=%s\n", target);
1025
1026                for (j = 0; j < available_pkgs->len; j++) {
1027                     pkg_t *pkg = available_pkgs->pkgs[j];
1028                     if (fnmatch(target, pkg->name, 0) == 0) {
1029                          int k;
1030                          int count = pkg->depends_count + pkg->pre_depends_count;
1031                          opkg_message(conf, OPKG_NOTICE, "What %s (arch=%s) %s\n",
1032                                       target, pkg->architecture, rel_str);
1033                          for (k = 0; k < count; k++) {
1034                               compound_depend_t *cdepend = &pkg->depends[k];
1035                               int l;
1036                               for (l = 0; l < cdepend->possibility_count; l++) {
1037                                    depend_t *possibility = cdepend->possibilities[l];
1038                                    opkg_message(conf, OPKG_NOTICE, "    %s", possibility->pkg->name);
1039                                    if (conf->verbosity >= OPKG_NOTICE) {
1040                                         if (possibility->version) {
1041                                              char *typestr = NULL;
1042                                              opkg_message(conf, OPKG_NOTICE, " %s", possibility->version);
1043                                              switch (possibility->constraint) {
1044                                              case NONE: typestr = "none"; break;
1045                                              case EARLIER: typestr = "<"; break;
1046                                              case EARLIER_EQUAL: typestr = "<="; break;
1047                                              case EQUAL: typestr = "="; break;
1048                                              case LATER_EQUAL: typestr = ">="; break;
1049                                              case LATER: typestr = ">"; break;
1050                                              }
1051                                              opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1052                                         }
1053                                    }
1054                                    opkg_message(conf, OPKG_NOTICE, "\n");
1055                               }
1056                          }
1057                     }
1058                }
1059           }
1060           pkg_vec_free(available_pkgs);
1061      }
1062      return 0;
1063 }
1064
1065 enum what_field_type {
1066   WHATDEPENDS,
1067   WHATCONFLICTS,
1068   WHATPROVIDES,
1069   WHATREPLACES,
1070   WHATRECOMMENDS,
1071   WHATSUGGESTS
1072 };
1073
1074 static int opkg_what_depends_conflicts_cmd(opkg_conf_t *conf, enum depend_type what_field_type, int recursive, int argc, char **argv)
1075 {
1076
1077      if (argc > 0) {
1078           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1079           const char *rel_str = NULL;
1080           int i;
1081           int changed;
1082
1083           switch (what_field_type) {
1084           case DEPEND: rel_str = "depends on"; break;
1085           case CONFLICTS: rel_str = "conflicts with"; break;
1086           case SUGGEST: rel_str = "suggests"; break;
1087           case RECOMMEND: rel_str = "recommends"; break;
1088           default: return -1;
1089           }
1090      
1091           if (conf->query_all)
1092                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1093           else
1094                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1095
1096           /* mark the root set */
1097           pkg_vec_clear_marks(available_pkgs);
1098           opkg_message(conf, OPKG_NOTICE, "Root set:\n");
1099           for (i = 0; i < argc; i++) {
1100                const char *dependee_pattern = argv[i];
1101                pkg_vec_mark_if_matches(available_pkgs, dependee_pattern);
1102           }
1103           for (i = 0; i < available_pkgs->len; i++) {
1104                pkg_t *pkg = available_pkgs->pkgs[i];
1105                if (pkg->state_flag & SF_MARKED) {
1106                     /* mark the parent (abstract) package */
1107                     pkg_mark_provides(pkg);
1108                     opkg_message(conf, OPKG_NOTICE, "  %s\n", pkg->name);
1109                }
1110           }
1111
1112           opkg_message(conf, OPKG_NOTICE, "What %s root set\n", rel_str);
1113           do {
1114                int j;
1115                changed = 0;
1116
1117                for (j = 0; j < available_pkgs->len; j++) {
1118                     pkg_t *pkg = available_pkgs->pkgs[j];
1119                     int k;
1120                     int count = ((what_field_type == CONFLICTS)
1121                                  ? pkg->conflicts_count
1122                                  : pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count);
1123                     /* skip this package if it is already marked */
1124                     if (pkg->parent->state_flag & SF_MARKED) {
1125                          continue;
1126                     }
1127                     for (k = 0; k < count; k++) {
1128                          compound_depend_t *cdepend = 
1129                               (what_field_type == CONFLICTS) ? &pkg->conflicts[k] : &pkg->depends[k];
1130                          int l;
1131                          if (what_field_type != cdepend->type)
1132                                  continue;
1133                          for (l = 0; l < cdepend->possibility_count; l++) {
1134                               depend_t *possibility = cdepend->possibilities[l];
1135                               if (possibility->pkg->state_flag & SF_MARKED) {
1136                                    /* mark the depending package so we won't visit it again */
1137                                    pkg->state_flag |= SF_MARKED;
1138                                    pkg_mark_provides(pkg);
1139                                    changed++;
1140
1141                                    if (conf->verbosity >= OPKG_NOTICE) {
1142                                         char *ver = pkg_version_str_alloc(pkg); 
1143                                         opkg_message(conf, OPKG_NOTICE, "    %s", pkg->name);
1144                                         opkg_message(conf, OPKG_NOTICE, " %s", ver);
1145                                         opkg_message(conf, OPKG_NOTICE, "\t%s %s", rel_str, possibility->pkg->name);
1146                                         if (possibility->version) {
1147                                              char *typestr = NULL;
1148                                              switch (possibility->constraint) {
1149                                              case NONE: typestr = "none"; break;
1150                                              case EARLIER: typestr = "<"; break;
1151                                              case EARLIER_EQUAL: typestr = "<="; break;
1152                                              case EQUAL: typestr = "="; break;
1153                                              case LATER_EQUAL: typestr = ">="; break;
1154                                              case LATER: typestr = ">"; break;
1155                                              }
1156                                              opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1157                                         }
1158                                         free(ver);
1159                                         if (!pkg_dependence_satisfiable(conf, possibility))
1160                                              opkg_message(conf, OPKG_NOTICE, " unsatisfiable");
1161                                    }
1162                                    opkg_message(conf, OPKG_NOTICE, "\n");
1163                                    goto next_package;
1164                               }
1165                          }
1166                     }
1167                next_package:
1168                     ;
1169                }
1170           } while (changed && recursive);
1171           pkg_vec_free(available_pkgs);
1172      }
1173
1174      return 0;
1175 }
1176
1177 static int pkg_mark_provides(pkg_t *pkg)
1178 {
1179      int provides_count = pkg->provides_count;
1180      abstract_pkg_t **provides = pkg->provides;
1181      int i;
1182      pkg->parent->state_flag |= SF_MARKED;
1183      for (i = 0; i < provides_count; i++) {
1184           provides[i]->state_flag |= SF_MARKED;
1185      }
1186      return 0;
1187 }
1188
1189 static int opkg_whatdepends_recursively_cmd(opkg_conf_t *conf, int argc, char **argv)
1190 {
1191      return opkg_what_depends_conflicts_cmd(conf, DEPEND, 1, argc, argv);
1192 }
1193 static int opkg_whatdepends_cmd(opkg_conf_t *conf, int argc, char **argv)
1194 {
1195      return opkg_what_depends_conflicts_cmd(conf, DEPEND, 0, argc, argv);
1196 }
1197
1198 static int opkg_whatsuggests_cmd(opkg_conf_t *conf, int argc, char **argv)
1199 {
1200      return opkg_what_depends_conflicts_cmd(conf, SUGGEST, 0, argc, argv);
1201 }
1202
1203 static int opkg_whatrecommends_cmd(opkg_conf_t *conf, int argc, char **argv)
1204 {
1205      return opkg_what_depends_conflicts_cmd(conf, RECOMMEND, 0, argc, argv);
1206 }
1207
1208 static int opkg_whatconflicts_cmd(opkg_conf_t *conf, int argc, char **argv)
1209 {
1210      return opkg_what_depends_conflicts_cmd(conf, CONFLICTS, 0, argc, argv);
1211 }
1212
1213 static int opkg_what_provides_replaces_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int argc, char **argv)
1214 {
1215
1216      if (argc > 0) {
1217           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1218           const char *rel_str = (what_field_type == WHATPROVIDES ? "provides" : "replaces");
1219           int i;
1220      
1221           pkg_info_preinstall_check(conf);
1222
1223           if (conf->query_all)
1224                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1225           else
1226                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1227           for (i = 0; i < argc; i++) {
1228                const char *target = argv[i];
1229                int j;
1230
1231                opkg_message(conf, OPKG_ERROR, "What %s %s\n",
1232                             rel_str, target);
1233                for (j = 0; j < available_pkgs->len; j++) {
1234                     pkg_t *pkg = available_pkgs->pkgs[j];
1235                     int k;
1236                     int count = (what_field_type == WHATPROVIDES) ? pkg->provides_count : pkg->replaces_count;
1237                     for (k = 0; k < count; k++) {
1238                          abstract_pkg_t *apkg = 
1239                               ((what_field_type == WHATPROVIDES) 
1240                                ? pkg->provides[k]
1241                                : pkg->replaces[k]);
1242                          if (fnmatch(target, apkg->name, 0) == 0) {
1243                               opkg_message(conf, OPKG_ERROR, "    %s", pkg->name);
1244                               if (strcmp(target, apkg->name) != 0)
1245                                    opkg_message(conf, OPKG_ERROR, "\t%s %s\n", rel_str, apkg->name);
1246                               opkg_message(conf, OPKG_ERROR, "\n");
1247                          }
1248                     }
1249                }
1250           }
1251           pkg_vec_free(available_pkgs);
1252      }
1253      return 0;
1254 }
1255
1256 static int opkg_whatprovides_cmd(opkg_conf_t *conf, int argc, char **argv)
1257 {
1258      return opkg_what_provides_replaces_cmd(conf, WHATPROVIDES, argc, argv);
1259 }
1260
1261 static int opkg_whatreplaces_cmd(opkg_conf_t *conf, int argc, char **argv)
1262 {
1263      return opkg_what_provides_replaces_cmd(conf, WHATREPLACES, argc, argv);
1264 }
1265
1266 static int opkg_search_cmd(opkg_conf_t *conf, int argc, char **argv)
1267 {
1268      int i;
1269
1270      pkg_vec_t *installed;
1271      pkg_t *pkg;
1272      str_list_t *installed_files;
1273      str_list_elt_t *iter;
1274      char *installed_file;
1275
1276      if (argc < 1) {
1277           return EINVAL;
1278      }
1279  
1280      installed = pkg_vec_alloc();
1281      pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
1282      pkg_vec_sort(installed, pkg_compare_names);
1283
1284      for (i=0; i < installed->len; i++) {
1285           pkg = installed->pkgs[i];
1286
1287           installed_files = pkg_get_installed_files(conf, pkg);
1288
1289           for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) {
1290                installed_file = (char *)iter->data;
1291                if (fnmatch(argv[0], installed_file, 0)==0)
1292                     print_pkg(pkg);
1293           }
1294
1295           pkg_free_installed_files(pkg);
1296      }
1297
1298      pkg_vec_free(installed);
1299
1300      return 0;
1301 }
1302
1303 static int opkg_compare_versions_cmd(opkg_conf_t *conf, int argc, char **argv)
1304 {
1305      if (argc == 3) {
1306           /* this is a bit gross */
1307           struct pkg p1, p2;
1308           parse_version(&p1, argv[0]); 
1309           parse_version(&p2, argv[2]); 
1310           return pkg_version_satisfied(&p1, &p2, argv[1]);
1311      } else {
1312           opkg_message(conf, OPKG_ERROR,
1313                        "opkg compare_versions <v1> <op> <v2>\n"
1314                        "<op> is one of <= >= << >> =\n");
1315           return -1;
1316      }
1317 }
1318
1319 static int opkg_print_architecture_cmd(opkg_conf_t *conf, int argc, char **argv)
1320 {
1321      nv_pair_list_elt_t *l;
1322
1323      list_for_each_entry(l, &conf->arch_list.head, node) {
1324           nv_pair_t *nv = (nv_pair_t *)l->data;
1325           printf("arch %s %s\n", nv->name, nv->value);
1326      }
1327      return 0;
1328 }