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