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