e33ef68e99072dcf09872cd958809d1cd7e165bb
[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 /* pb_ asked this feature 03292004 */
884 /* Actually I will use only this two, but this is an open for various status */
885           if (( strcmp(flags,"installed")==0)||( strcmp(flags,"unpacked")==0)){
886               pkg->state_status = pkg_state_status_from_str(flags);
887           }
888           opkg_state_changed++;
889           opkg_message(conf, OPKG_NOTICE,
890                        "Setting flags for package %s to %s\n",
891                        pkg->name, flags);
892      }
893
894      write_status_files_if_changed(conf);
895      return 0;
896 }
897
898 static int opkg_files_cmd(opkg_conf_t *conf, int argc, char **argv)
899 {
900      pkg_t *pkg;
901      str_list_t *files;
902      str_list_elt_t *iter;
903      char *pkg_version;
904
905      if (argc < 1) {
906           return EINVAL;
907      }
908
909      pkg = pkg_hash_fetch_installed_by_name(&conf->pkg_hash,
910                                             argv[0]);
911      if (pkg == NULL) {
912           opkg_message(conf, OPKG_ERROR,
913                        "Package %s not installed.\n", argv[0]);
914           return 0;
915      }
916
917      files = pkg_get_installed_files(conf, pkg);
918      pkg_version = pkg_version_str_alloc(pkg);
919
920      printf("Package %s (%s) is installed on %s and has the following files:\n",
921                 pkg->name, pkg_version, pkg->dest->name);
922
923      for (iter=str_list_first(files); iter; iter=str_list_next(files, iter))
924           printf("%s\n", (char *)iter->data);
925
926      free(pkg_version);
927      pkg_free_installed_files(pkg);
928
929      return 0;
930 }
931
932 static int opkg_depends_cmd(opkg_conf_t *conf, int argc, char **argv)
933 {
934
935      if (argc > 0) {
936           pkg_vec_t *available_pkgs = pkg_vec_alloc();
937           const char *rel_str = "depends on";
938           int i;
939      
940           pkg_info_preinstall_check(conf);
941
942           if (conf->query_all)
943                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
944           else
945                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
946           for (i = 0; i < argc; i++) {
947                const char *target = argv[i];
948                int j;
949
950                opkg_message(conf, OPKG_NOTICE, "target=%s\n", target);
951
952                for (j = 0; j < available_pkgs->len; j++) {
953                     pkg_t *pkg = available_pkgs->pkgs[j];
954                     if (fnmatch(target, pkg->name, 0) == 0) {
955                          int k;
956                          int count = pkg->depends_count + pkg->pre_depends_count;
957                          opkg_message(conf, OPKG_NOTICE, "What %s (arch=%s) %s\n",
958                                       target, pkg->architecture, rel_str);
959                          for (k = 0; k < count; k++) {
960                               compound_depend_t *cdepend = &pkg->depends[k];
961                               int l;
962                               for (l = 0; l < cdepend->possibility_count; l++) {
963                                    depend_t *possibility = cdepend->possibilities[l];
964                                    opkg_message(conf, OPKG_NOTICE, "    %s", possibility->pkg->name);
965                                    if (conf->verbosity >= OPKG_NOTICE) {
966                                         if (possibility->version) {
967                                              char *typestr = NULL;
968                                              opkg_message(conf, OPKG_NOTICE, " %s", possibility->version);
969                                              switch (possibility->constraint) {
970                                              case NONE: typestr = "none"; break;
971                                              case EARLIER: typestr = "<"; break;
972                                              case EARLIER_EQUAL: typestr = "<="; break;
973                                              case EQUAL: typestr = "="; break;
974                                              case LATER_EQUAL: typestr = ">="; break;
975                                              case LATER: typestr = ">"; break;
976                                              }
977                                              opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
978                                         }
979                                    }
980                                    opkg_message(conf, OPKG_NOTICE, "\n");
981                               }
982                          }
983                     }
984                }
985           }
986           pkg_vec_free(available_pkgs);
987      }
988      return 0;
989 }
990
991 enum what_field_type {
992   WHATDEPENDS,
993   WHATCONFLICTS,
994   WHATPROVIDES,
995   WHATREPLACES,
996   WHATRECOMMENDS,
997   WHATSUGGESTS
998 };
999
1000 static int opkg_what_depends_conflicts_cmd(opkg_conf_t *conf, enum depend_type what_field_type, int recursive, int argc, char **argv)
1001 {
1002
1003      if (argc > 0) {
1004           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1005           const char *rel_str = NULL;
1006           int i;
1007           int changed;
1008
1009           switch (what_field_type) {
1010           case DEPEND: rel_str = "depends on"; break;
1011           case CONFLICTS: rel_str = "conflicts with"; break;
1012           case SUGGEST: rel_str = "suggests"; break;
1013           case RECOMMEND: rel_str = "recommends"; break;
1014           default: return -1;
1015           }
1016      
1017           if (conf->query_all)
1018                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1019           else
1020                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1021
1022           /* mark the root set */
1023           pkg_vec_clear_marks(available_pkgs);
1024           opkg_message(conf, OPKG_NOTICE, "Root set:\n");
1025           for (i = 0; i < argc; i++) {
1026                const char *dependee_pattern = argv[i];
1027                pkg_vec_mark_if_matches(available_pkgs, dependee_pattern);
1028           }
1029           for (i = 0; i < available_pkgs->len; i++) {
1030                pkg_t *pkg = available_pkgs->pkgs[i];
1031                if (pkg->state_flag & SF_MARKED) {
1032                     /* mark the parent (abstract) package */
1033                     pkg_mark_provides(pkg);
1034                     opkg_message(conf, OPKG_NOTICE, "  %s\n", pkg->name);
1035                }
1036           }
1037
1038           opkg_message(conf, OPKG_NOTICE, "What %s root set\n", rel_str);
1039           do {
1040                int j;
1041                changed = 0;
1042
1043                for (j = 0; j < available_pkgs->len; j++) {
1044                     pkg_t *pkg = available_pkgs->pkgs[j];
1045                     int k;
1046                     int count = ((what_field_type == CONFLICTS)
1047                                  ? pkg->conflicts_count
1048                                  : pkg->pre_depends_count + pkg->depends_count + pkg->recommends_count + pkg->suggests_count);
1049                     /* skip this package if it is already marked */
1050                     if (pkg->parent->state_flag & SF_MARKED) {
1051                          continue;
1052                     }
1053                     for (k = 0; k < count; k++) {
1054                          compound_depend_t *cdepend = 
1055                               (what_field_type == CONFLICTS) ? &pkg->conflicts[k] : &pkg->depends[k];
1056                          int l;
1057                          if (what_field_type != cdepend->type)
1058                                  continue;
1059                          for (l = 0; l < cdepend->possibility_count; l++) {
1060                               depend_t *possibility = cdepend->possibilities[l];
1061                               if (possibility->pkg->state_flag & SF_MARKED) {
1062                                    /* mark the depending package so we won't visit it again */
1063                                    pkg->state_flag |= SF_MARKED;
1064                                    pkg_mark_provides(pkg);
1065                                    changed++;
1066
1067                                    if (conf->verbosity >= OPKG_NOTICE) {
1068                                         char *ver = pkg_version_str_alloc(pkg); 
1069                                         opkg_message(conf, OPKG_NOTICE, "    %s", pkg->name);
1070                                         opkg_message(conf, OPKG_NOTICE, " %s", ver);
1071                                         opkg_message(conf, OPKG_NOTICE, "\t%s %s", rel_str, possibility->pkg->name);
1072                                         if (possibility->version) {
1073                                              char *typestr = NULL;
1074                                              switch (possibility->constraint) {
1075                                              case NONE: typestr = "none"; break;
1076                                              case EARLIER: typestr = "<"; break;
1077                                              case EARLIER_EQUAL: typestr = "<="; break;
1078                                              case EQUAL: typestr = "="; break;
1079                                              case LATER_EQUAL: typestr = ">="; break;
1080                                              case LATER: typestr = ">"; break;
1081                                              }
1082                                              opkg_message(conf, OPKG_NOTICE, " (%s %s)", typestr, possibility->version);
1083                                         }
1084                                         free(ver);
1085                                         if (!pkg_dependence_satisfiable(conf, possibility))
1086                                              opkg_message(conf, OPKG_NOTICE, " unsatisfiable");
1087                                    }
1088                                    opkg_message(conf, OPKG_NOTICE, "\n");
1089                                    goto next_package;
1090                               }
1091                          }
1092                     }
1093                next_package:
1094                     ;
1095                }
1096           } while (changed && recursive);
1097           pkg_vec_free(available_pkgs);
1098      }
1099
1100      return 0;
1101 }
1102
1103 static int pkg_mark_provides(pkg_t *pkg)
1104 {
1105      int provides_count = pkg->provides_count;
1106      abstract_pkg_t **provides = pkg->provides;
1107      int i;
1108      pkg->parent->state_flag |= SF_MARKED;
1109      for (i = 0; i < provides_count; i++) {
1110           provides[i]->state_flag |= SF_MARKED;
1111      }
1112      return 0;
1113 }
1114
1115 static int opkg_whatdepends_recursively_cmd(opkg_conf_t *conf, int argc, char **argv)
1116 {
1117      return opkg_what_depends_conflicts_cmd(conf, DEPEND, 1, argc, argv);
1118 }
1119 static int opkg_whatdepends_cmd(opkg_conf_t *conf, int argc, char **argv)
1120 {
1121      return opkg_what_depends_conflicts_cmd(conf, DEPEND, 0, argc, argv);
1122 }
1123
1124 static int opkg_whatsuggests_cmd(opkg_conf_t *conf, int argc, char **argv)
1125 {
1126      return opkg_what_depends_conflicts_cmd(conf, SUGGEST, 0, argc, argv);
1127 }
1128
1129 static int opkg_whatrecommends_cmd(opkg_conf_t *conf, int argc, char **argv)
1130 {
1131      return opkg_what_depends_conflicts_cmd(conf, RECOMMEND, 0, argc, argv);
1132 }
1133
1134 static int opkg_whatconflicts_cmd(opkg_conf_t *conf, int argc, char **argv)
1135 {
1136      return opkg_what_depends_conflicts_cmd(conf, CONFLICTS, 0, argc, argv);
1137 }
1138
1139 static int opkg_what_provides_replaces_cmd(opkg_conf_t *conf, enum what_field_type what_field_type, int argc, char **argv)
1140 {
1141
1142      if (argc > 0) {
1143           pkg_vec_t *available_pkgs = pkg_vec_alloc();
1144           const char *rel_str = (what_field_type == WHATPROVIDES ? "provides" : "replaces");
1145           int i;
1146      
1147           pkg_info_preinstall_check(conf);
1148
1149           if (conf->query_all)
1150                pkg_hash_fetch_available(&conf->pkg_hash, available_pkgs);
1151           else
1152                pkg_hash_fetch_all_installed(&conf->pkg_hash, available_pkgs);
1153           for (i = 0; i < argc; i++) {
1154                const char *target = argv[i];
1155                int j;
1156
1157                opkg_message(conf, OPKG_ERROR, "What %s %s\n",
1158                             rel_str, target);
1159                for (j = 0; j < available_pkgs->len; j++) {
1160                     pkg_t *pkg = available_pkgs->pkgs[j];
1161                     int k;
1162                     int count = (what_field_type == WHATPROVIDES) ? pkg->provides_count : pkg->replaces_count;
1163                     for (k = 0; k < count; k++) {
1164                          abstract_pkg_t *apkg = 
1165                               ((what_field_type == WHATPROVIDES) 
1166                                ? pkg->provides[k]
1167                                : pkg->replaces[k]);
1168                          if (fnmatch(target, apkg->name, 0) == 0) {
1169                               opkg_message(conf, OPKG_ERROR, "    %s", pkg->name);
1170                               if (strcmp(target, apkg->name) != 0)
1171                                    opkg_message(conf, OPKG_ERROR, "\t%s %s\n", rel_str, apkg->name);
1172                               opkg_message(conf, OPKG_ERROR, "\n");
1173                          }
1174                     }
1175                }
1176           }
1177           pkg_vec_free(available_pkgs);
1178      }
1179      return 0;
1180 }
1181
1182 static int opkg_whatprovides_cmd(opkg_conf_t *conf, int argc, char **argv)
1183 {
1184      return opkg_what_provides_replaces_cmd(conf, WHATPROVIDES, argc, argv);
1185 }
1186
1187 static int opkg_whatreplaces_cmd(opkg_conf_t *conf, int argc, char **argv)
1188 {
1189      return opkg_what_provides_replaces_cmd(conf, WHATREPLACES, argc, argv);
1190 }
1191
1192 static int opkg_search_cmd(opkg_conf_t *conf, int argc, char **argv)
1193 {
1194      int i;
1195
1196      pkg_vec_t *installed;
1197      pkg_t *pkg;
1198      str_list_t *installed_files;
1199      str_list_elt_t *iter;
1200      char *installed_file;
1201
1202      if (argc < 1) {
1203           return EINVAL;
1204      }
1205  
1206      installed = pkg_vec_alloc();
1207      pkg_hash_fetch_all_installed(&conf->pkg_hash, installed);
1208      pkg_vec_sort(installed, pkg_compare_names);
1209
1210      for (i=0; i < installed->len; i++) {
1211           pkg = installed->pkgs[i];
1212
1213           installed_files = pkg_get_installed_files(conf, pkg);
1214
1215           for (iter = str_list_first(installed_files); iter; iter = str_list_next(installed_files, iter)) {
1216                installed_file = (char *)iter->data;
1217                if (fnmatch(argv[0], installed_file, 0)==0)
1218                     print_pkg(pkg);
1219           }
1220
1221           pkg_free_installed_files(pkg);
1222      }
1223
1224      pkg_vec_free(installed);
1225
1226      return 0;
1227 }
1228
1229 static int opkg_compare_versions_cmd(opkg_conf_t *conf, int argc, char **argv)
1230 {
1231      if (argc == 3) {
1232           /* this is a bit gross */
1233           struct pkg p1, p2;
1234           parse_version(&p1, argv[0]); 
1235           parse_version(&p2, argv[2]); 
1236           return pkg_version_satisfied(&p1, &p2, argv[1]);
1237      } else {
1238           opkg_message(conf, OPKG_ERROR,
1239                        "opkg compare_versions <v1> <op> <v2>\n"
1240                        "<op> is one of <= >= << >> =\n");
1241           return -1;
1242      }
1243 }
1244
1245 static int opkg_print_architecture_cmd(opkg_conf_t *conf, int argc, char **argv)
1246 {
1247      nv_pair_list_elt_t *l;
1248
1249      list_for_each_entry(l, &conf->arch_list.head, node) {
1250           nv_pair_t *nv = (nv_pair_t *)l->data;
1251           printf("arch %s %s\n", nv->name, nv->value);
1252      }
1253      return 0;
1254 }