info.c 6.58 KB
Newer Older
Natanael Copa's avatar
Natanael Copa committed
1 2 3 4 5 6 7 8 9 10 11 12
/* info.c - Alpine Package Keeper (APK)
 *
 * Copyright (C) 2005-2009 Natanael Copa <n@tanael.org>
 * Copyright (C) 2009 Timo Teräs <timo.teras@iki.fi>
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation. See http://www.gnu.org/ for details.
 */

#include <stdio.h>
13
#include <unistd.h>
Natanael Copa's avatar
Natanael Copa committed
14 15
#include "apk_defines.h"
#include "apk_applet.h"
Timo Teräs's avatar
Timo Teräs committed
16
#include "apk_package.h"
Natanael Copa's avatar
Natanael Copa committed
17
#include "apk_database.h"
Timo Teräs's avatar
Timo Teräs committed
18
#include "apk_state.h"
Natanael Copa's avatar
Natanael Copa committed
19

Timo Teräs's avatar
Timo Teräs committed
20
struct info_ctx {
21 22 23
	int (*action)(struct info_ctx *ctx, struct apk_database *db,
		      int argc, char **argv);
	void (*subaction)(struct apk_package *pkg);
Timo Teräs's avatar
Timo Teräs committed
24 25
};

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
static void verbose_print_pkg(struct apk_package *pkg, int minimal_verbosity)
{
	int verbosity = apk_verbosity;
	if (verbosity < minimal_verbosity)
		verbosity = minimal_verbosity;

	if (pkg == NULL || verbosity < 1)
		return;

	printf("%s", pkg->name->name);
	if (apk_verbosity > 1)
		printf("-%s", pkg->version);
	if (apk_verbosity > 2)
		printf(" - %s", pkg->description);
	printf("\n");
}


44 45
static int info_list(struct info_ctx *ctx, struct apk_database *db,
		     int argc, char **argv)
Natanael Copa's avatar
Natanael Copa committed
46 47 48
{
	struct apk_package *pkg;

49 50
	list_for_each_entry(pkg, &db->installed.packages, installed_pkgs_list)
		verbose_print_pkg(pkg, 1);
Timo Teräs's avatar
Timo Teräs committed
51 52 53
	return 0;
}

54 55
static int info_exists(struct info_ctx *ctx, struct apk_database *db,
		       int argc, char **argv)
Timo Teräs's avatar
Timo Teräs committed
56 57
{
	struct apk_name *name;
58
	int i, j, ret = 0;
Timo Teräs's avatar
Timo Teräs committed
59 60 61

	for (i = 0; i < argc; i++) {
		name = apk_db_query_name(db, APK_BLOB_STR(argv[i]));
62 63 64 65
		if (name == NULL) { 
			ret++;
			continue;
		}
Timo Teräs's avatar
Timo Teräs committed
66 67

		for (j = 0; j < name->pkgs->num; j++) {
68
			if (apk_pkg_get_state(name->pkgs->item[j]) == APK_PKG_INSTALLED)
Timo Teräs's avatar
Timo Teräs committed
69 70
				break;
		}
71 72 73 74
		if (j >= name->pkgs->num) {
			ret++;
		} else
			verbose_print_pkg(name->pkgs->item[j], 0);
Timo Teräs's avatar
Timo Teräs committed
75
	}
Natanael Copa's avatar
Natanael Copa committed
76

77
	return ret;
Natanael Copa's avatar
Natanael Copa committed
78 79
}

80 81
static int info_who_owns(struct info_ctx *ctx, struct apk_database *db,
			 int argc, char **argv)
82 83 84 85 86 87 88 89 90 91 92
{
	struct apk_package *pkg;
	struct apk_dependency_array *deps = NULL;
	struct apk_dependency dep;
	int i;

	for (i = 0; i < argc; i++) {
		pkg = apk_db_get_file_owner(db, APK_BLOB_STR(argv[i]));
		if (pkg == NULL)
			continue;

93
		if (apk_verbosity < 1) {
94 95
			dep = (struct apk_dependency) {
				.name = pkg->name,
96
				.result_mask = APK_DEPMASK_REQUIRE,
97 98 99 100 101 102 103
			};
			apk_deps_add(&deps, &dep);
		} else {
			printf("%s is owned by %s-%s\n", argv[i],
			       pkg->name->name, pkg->version);
		}
	}
104
	if (apk_verbosity < 1 && deps != NULL) {
105 106 107 108 109 110 111
		struct apk_ostream *os;

		os = apk_ostream_to_fd(STDOUT_FILENO);
		apk_deps_write(deps, os);
		os->write(os, "\n", 1);
		os->close(os);

112 113 114 115 116 117
		free(deps);
	}

	return 0;
}

118 119 120 121 122 123 124 125 126 127 128 129 130 131
static int info_package(struct info_ctx *ctx, struct apk_database *db,
			int argc, char **argv)
{
	struct apk_name *name;
	int i, j;

	for (i = 0; i < argc; i++) {
		name = apk_db_query_name(db, APK_BLOB_STR(argv[i]));
		if (name == NULL) {
			apk_error("Not found: %s", name);
			return 1;
		}
		for (j = 0; j < name->pkgs->num; j++) {
			struct apk_package *pkg = name->pkgs->item[j];
132
			if (apk_pkg_get_state(pkg) == APK_PKG_INSTALLED)
133 134 135 136 137 138
				ctx->subaction(pkg);
		}
	}
	return 0;
}

Natanael Copa's avatar
Natanael Copa committed
139 140 141 142 143 144
static void info_print_contents(struct apk_package *pkg)
{
	struct apk_db_dir_instance *diri;
	struct apk_db_file *file;
	struct hlist_node *dc, *dn, *fc, *fn;

145 146 147
	if (apk_verbosity == 1)
		printf("%s-%s contains:\n", pkg->name->name, pkg->version);

Natanael Copa's avatar
Natanael Copa committed
148 149 150 151 152
	hlist_for_each_entry_safe(diri, dc, dn, &pkg->owned_dirs,
				  pkg_dirs_list) {
		hlist_for_each_entry_safe(file, fc, fn, &diri->owned_files,
					  diri_files_list) {
			if (apk_verbosity > 1)
153
				printf("%s: ", pkg->name->name);
Natanael Copa's avatar
Natanael Copa committed
154 155 156
			printf("%s/%s\n", diri->dir->dirname, file->filename);
		}
	}
157
	puts("");
Natanael Copa's avatar
Natanael Copa committed
158 159
}

160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
static void info_print_depends(struct apk_package *pkg)
{
	int i;
	char *separator = apk_verbosity > 1 ? " " : "\n";
	if (apk_verbosity == 1) 
		printf("%s-%s depends on:\n", pkg->name->name, pkg->version);
	if (pkg->depends == NULL)
		return;
	if (apk_verbosity > 1)
		printf("%s: ", pkg->name->name);
	for (i = 0; i < pkg->depends->num; i++) {
		printf("%s%s", pkg->depends->item[i].name->name, separator);
	}
	puts("");
}

176
static void info_print_required_by(struct apk_package *pkg)
177
{
178 179
	int i, j, k;
	char *separator = apk_verbosity > 1 ? " " : "\n";
180

181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
	if (apk_verbosity == 1)
		printf("%s-%s is required by:\n", pkg->name->name, pkg->version);
	if (pkg->name->rdepends == NULL)
		return;
	if (apk_verbosity > 1)
		printf("%s: ", pkg->name->name);
	for (i = 0; i < pkg->name->rdepends->num; i++) {
		struct apk_name *name0 = pkg->name->rdepends->item[i];

		/* Check only the package that is installed, and that
		 * it actually has this package as dependency. */
		if (name0->pkgs == NULL)
			continue;
		for (j = 0; j < name0->pkgs->num; j++) {
			struct apk_package *pkg0 = name0->pkgs->item[j];

197
			if (apk_pkg_get_state(pkg0) != APK_PKG_INSTALLED ||
198 199 200 201 202 203 204 205 206
			    pkg0->depends == NULL)
				continue;
			for (k = 0; k < pkg0->depends->num; k++) {
				if (pkg0->depends->item[k].name != pkg->name)
					continue;
				printf("%s-%s%s", pkg0->name->name,
				       pkg0->version, separator);
				break;
			}
207 208
		}
	}
209
	puts("");
210 211
}

Timo Teräs's avatar
Timo Teräs committed
212 213 214 215 216 217 218 219
static int info_parse(void *ctx, int optch, int optindex, const char *optarg)
{
	struct info_ctx *ictx = (struct info_ctx *) ctx;

	switch (optch) {
	case 'e':
		ictx->action = info_exists;
		break;
220 221 222
	case 'W':
		ictx->action = info_who_owns;
		break;
Natanael Copa's avatar
Natanael Copa committed
223
	case 'L':
224 225
		ictx->action = info_package;
		ictx->subaction = info_print_contents;
Natanael Copa's avatar
Natanael Copa committed
226
		break;
227
	case 'R':
228 229 230 231 232 233
		ictx->action = info_package;
		ictx->subaction = info_print_depends;
		break;
	case 'r':
		ictx->action = info_package;
		ictx->subaction = info_print_required_by;
234
		break;
Timo Teräs's avatar
Timo Teräs committed
235 236 237 238 239 240 241 242 243 244 245 246
	default:
		return -1;
	}
	return 0;
}

static int info_main(void *ctx, int argc, char **argv)
{
	struct info_ctx *ictx = (struct info_ctx *) ctx;
	struct apk_database db;
	int r;

247
	if (apk_db_open(&db, apk_root, APK_OPENF_READ + APK_OPENF_EMPTY_REPOS) < 0)
Timo Teräs's avatar
Timo Teräs committed
248 249 250
		return -1;

	if (ictx->action != NULL)
251
		r = ictx->action(ictx, &db, argc, argv);
Timo Teräs's avatar
Timo Teräs committed
252
	else
253
		r = info_list(ictx, &db, argc, argv);
Timo Teräs's avatar
Timo Teräs committed
254 255 256 257 258 259

	apk_db_close(&db);
	return r;
}

static struct option info_options[] = {
Natanael Copa's avatar
Natanael Copa committed
260
	{ "contents",	no_argument,		NULL, 'L' },
Timo Teräs's avatar
Timo Teräs committed
261
	{ "installed",	no_argument,		NULL, 'e' },
262
	{ "who-owns",	no_argument,		NULL, 'W' },
263
	{ "depends",	no_argument,		NULL, 'R' },
264
	{ "rdepends",	no_argument,		NULL, 'r' },
Timo Teräs's avatar
Timo Teräs committed
265 266
};

Natanael Copa's avatar
Natanael Copa committed
267 268
static struct apk_applet apk_info = {
	.name = "info",
Natanael Copa's avatar
Natanael Copa committed
269 270
	.usage = "[-L|--contents] [-e|--installed] [-W|--who-owns] [-R|--depends]\n"
		 "\t\t[-r|--rdepends] PACKAGE...",
Timo Teräs's avatar
Timo Teräs committed
271 272 273 274
	.context_size = sizeof(struct info_ctx),
	.num_options = ARRAY_SIZE(info_options),
	.options = info_options,
	.parse = info_parse,
Natanael Copa's avatar
Natanael Copa committed
275 276 277 278 279
	.main = info_main,
};

APK_DEFINE_APPLET(apk_info);