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