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