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