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