Add information on how an installed package was validated
[pacman-ng.git] / src / pacman / package.c
blob6e4901d18da7790127ff1d72de97086e74d63532
1 /*
2 * package.c
4 * Copyright (c) 2006-2012 Pacman Development Team <pacman-dev@archlinux.org>
5 * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <limits.h>
26 #include <errno.h>
27 #include <time.h>
29 #include <alpm.h>
30 #include <alpm_list.h>
32 /* pacman */
33 #include "package.h"
34 #include "util.h"
35 #include "conf.h"
37 #define CLBUF_SIZE 4096
39 /** Turn a depends list into a text list.
40 * @param deps a list with items of type alpm_depend_t
42 static void deplist_display(const char *title,
43 alpm_list_t *deps)
45 alpm_list_t *i, *text = NULL;
46 for(i = deps; i; i = alpm_list_next(i)) {
47 alpm_depend_t *dep = i->data;
48 text = alpm_list_add(text, alpm_dep_compute_string(dep));
50 list_display(title, text);
51 FREELIST(text);
54 /** Turn a optdepends list into a text list.
55 * @param optdeps a list with items of type alpm_optdepend_t
57 static void optdeplist_display(const char *title,
58 alpm_list_t *optdeps)
60 alpm_list_t *i, *text = NULL;
61 for(i = optdeps; i; i = alpm_list_next(i)) {
62 alpm_depend_t *optdep = i->data;
63 text = alpm_list_add(text, alpm_dep_compute_string(optdep));
65 list_display_linebreak(title, text);
66 FREELIST(text);
69 /**
70 * Display the details of a package.
71 * Extra information entails 'required by' info for sync packages and backup
72 * files info for local packages.
73 * @param pkg package to display information for
74 * @param from the type of package we are dealing with
75 * @param extra should we show extra information
77 void dump_pkg_full(alpm_pkg_t *pkg, int extra)
79 const char *reason;
80 alpm_list_t *validation = NULL;
81 time_t bdate, idate;
82 char bdatestr[50] = "", idatestr[50] = "";
83 const char *label;
84 double size;
85 alpm_list_t *requiredby = NULL;
86 alpm_pkgfrom_t from;
88 from = alpm_pkg_get_origin(pkg);
90 /* set variables here, do all output below */
91 bdate = (time_t)alpm_pkg_get_builddate(pkg);
92 if(bdate) {
93 strftime(bdatestr, 50, "%c", localtime(&bdate));
95 idate = (time_t)alpm_pkg_get_installdate(pkg);
96 if(idate) {
97 strftime(idatestr, 50, "%c", localtime(&idate));
100 switch(alpm_pkg_get_reason(pkg)) {
101 case ALPM_PKG_REASON_EXPLICIT:
102 reason = _("Explicitly installed");
103 break;
104 case ALPM_PKG_REASON_DEPEND:
105 reason = _("Installed as a dependency for another package");
106 break;
107 default:
108 reason = _("Unknown");
109 break;
112 if(from == PKG_FROM_LOCALDB) {
113 alpm_pkgvalidation_t v = alpm_pkg_get_validation(pkg);
114 if(v) {
115 if(v & ALPM_PKG_VALIDATION_NONE) {
116 validation = alpm_list_add(validation, _("None"));
117 } else {
118 if(v & ALPM_PKG_VALIDATION_MD5SUM) {
119 validation = alpm_list_add(validation, _("MD5 Sum"));
121 if(v & ALPM_PKG_VALIDATION_SHA256SUM) {
122 validation = alpm_list_add(validation, _("SHA256 Sum"));
124 if(v & ALPM_PKG_VALIDATION_SIGNATURE) {
125 validation = alpm_list_add(validation, _("Signature"));
128 } else {
129 validation = alpm_list_add(validation, _("Unknown"));
133 if(extra || from == PKG_FROM_LOCALDB) {
134 /* compute this here so we don't get a pause in the middle of output */
135 requiredby = alpm_pkg_compute_requiredby(pkg);
138 /* actual output */
139 if(from == PKG_FROM_SYNCDB) {
140 string_display(_("Repository :"),
141 alpm_db_get_name(alpm_pkg_get_db(pkg)));
143 string_display(_("Name :"), alpm_pkg_get_name(pkg));
144 string_display(_("Version :"), alpm_pkg_get_version(pkg));
145 string_display(_("URL :"), alpm_pkg_get_url(pkg));
146 list_display(_("Licenses :"), alpm_pkg_get_licenses(pkg));
147 list_display(_("Groups :"), alpm_pkg_get_groups(pkg));
148 deplist_display(_("Provides :"), alpm_pkg_get_provides(pkg));
149 deplist_display(_("Depends On :"), alpm_pkg_get_depends(pkg));
150 optdeplist_display(_("Optional Deps :"), alpm_pkg_get_optdepends(pkg));
151 if(extra || from == PKG_FROM_LOCALDB) {
152 list_display(_("Required By :"), requiredby);
154 deplist_display(_("Conflicts With :"), alpm_pkg_get_conflicts(pkg));
155 deplist_display(_("Replaces :"), alpm_pkg_get_replaces(pkg));
157 size = humanize_size(alpm_pkg_get_size(pkg), 'K', 2, &label);
158 if(from == PKG_FROM_SYNCDB) {
159 printf(_("Download Size : %6.2f %s\n"), size, label);
160 } else if(from == PKG_FROM_FILE) {
161 printf(_("Compressed Size: %6.2f %s\n"), size, label);
164 size = humanize_size(alpm_pkg_get_isize(pkg), 'K', 2, &label);
165 printf(_("Installed Size : %6.2f %s\n"), size, label);
167 string_display(_("Packager :"), alpm_pkg_get_packager(pkg));
168 string_display(_("Architecture :"), alpm_pkg_get_arch(pkg));
169 string_display(_("Build Date :"), bdatestr);
170 if(from == PKG_FROM_LOCALDB) {
171 string_display(_("Install Date :"), idatestr);
172 string_display(_("Install Reason :"), reason);
174 if(from == PKG_FROM_FILE || from == PKG_FROM_LOCALDB) {
175 string_display(_("Install Script :"),
176 alpm_pkg_has_scriptlet(pkg) ? _("Yes") : _("No"));
179 if(from == PKG_FROM_SYNCDB) {
180 string_display(_("MD5 Sum :"), alpm_pkg_get_md5sum(pkg));
181 string_display(_("SHA256 Sum :"), alpm_pkg_get_sha256sum(pkg));
182 string_display(_("Signatures :"),
183 alpm_pkg_get_base64_sig(pkg) ? _("Yes") : _("None"));
185 if(from == PKG_FROM_FILE) {
186 alpm_siglist_t siglist;
187 int err = alpm_pkg_check_pgp_signature(pkg, &siglist);
188 if(err && alpm_errno(config->handle) == ALPM_ERR_SIG_MISSING) {
189 string_display(_("Signatures :"), _("None"));
190 } else if(err) {
191 string_display(_("Signatures :"),
192 alpm_strerror(alpm_errno(config->handle)));
193 } else {
194 signature_display(_("Signatures :"), &siglist);
196 alpm_siglist_cleanup(&siglist);
198 if(from == PKG_FROM_LOCALDB) {
199 list_display(_("Validated By :"), validation);
201 string_display(_("Description :"), alpm_pkg_get_desc(pkg));
203 /* Print additional package info if info flag passed more than once */
204 if(from == PKG_FROM_LOCALDB && extra) {
205 dump_pkg_backups(pkg);
208 /* final newline to separate packages */
209 printf("\n");
211 FREELIST(requiredby);
212 alpm_list_free(validation);
215 static const char *get_backup_file_status(const char *root,
216 const alpm_backup_t *backup)
218 char path[PATH_MAX];
219 const char *ret;
221 snprintf(path, PATH_MAX, "%s%s", root, backup->name);
223 /* if we find the file, calculate checksums, otherwise it is missing */
224 if(access(path, R_OK) == 0) {
225 char *md5sum = alpm_compute_md5sum(path);
227 if(md5sum == NULL) {
228 pm_printf(ALPM_LOG_ERROR,
229 _("could not calculate checksums for %s\n"), path);
230 return NULL;
233 /* if checksums don't match, file has been modified */
234 if(strcmp(md5sum, backup->hash) != 0) {
235 ret = "MODIFIED";
236 } else {
237 ret = "UNMODIFIED";
239 free(md5sum);
240 } else {
241 switch(errno) {
242 case EACCES:
243 ret = "UNREADABLE";
244 break;
245 case ENOENT:
246 ret = "MISSING";
247 break;
248 default:
249 ret = "UNKNOWN";
252 return ret;
255 /* Display list of backup files and their modification states
257 void dump_pkg_backups(alpm_pkg_t *pkg)
259 alpm_list_t *i;
260 const char *root = alpm_option_get_root(config->handle);
261 printf(_("Backup Files:\n"));
262 if(alpm_pkg_get_backup(pkg)) {
263 /* package has backup files, so print them */
264 for(i = alpm_pkg_get_backup(pkg); i; i = alpm_list_next(i)) {
265 const alpm_backup_t *backup = i->data;
266 const char *value;
267 if(!backup->hash) {
268 continue;
270 value = get_backup_file_status(root, backup);
271 printf("%s\t%s%s\n", value, root, backup->name);
273 } else {
274 /* package had no backup files */
275 printf(_("(none)\n"));
279 /* List all files contained in a package
281 void dump_pkg_files(alpm_pkg_t *pkg, int quiet)
283 const char *pkgname, *root;
284 alpm_filelist_t *pkgfiles;
285 size_t i;
287 pkgname = alpm_pkg_get_name(pkg);
288 pkgfiles = alpm_pkg_get_files(pkg);
289 root = alpm_option_get_root(config->handle);
291 for(i = 0; i < pkgfiles->count; i++) {
292 const alpm_file_t *file = pkgfiles->files + i;
293 /* Regular: '<pkgname> <root><filepath>\n'
294 * Quiet : '<root><filepath>\n'
296 if(!quiet) {
297 fputs(pkgname, stdout);
298 putchar(' ');
300 fputs(root, stdout);
301 fputs(file->name, stdout);
302 putchar('\n');
305 fflush(stdout);
308 /* Display the changelog of a package
310 void dump_pkg_changelog(alpm_pkg_t *pkg)
312 void *fp = NULL;
314 if((fp = alpm_pkg_changelog_open(pkg)) == NULL) {
315 pm_printf(ALPM_LOG_ERROR, _("no changelog available for '%s'.\n"),
316 alpm_pkg_get_name(pkg));
317 return;
318 } else {
319 /* allocate a buffer to get the changelog back in chunks */
320 char buf[CLBUF_SIZE];
321 size_t ret = 0;
322 while((ret = alpm_pkg_changelog_read(buf, CLBUF_SIZE, pkg, fp))) {
323 if(ret < CLBUF_SIZE) {
324 /* if we hit the end of the file, we need to add a null terminator */
325 *(buf + ret) = '\0';
327 fputs(buf, stdout);
329 alpm_pkg_changelog_close(pkg, fp);
330 putchar('\n');
334 /* vim: set ts=2 sw=2 noet: */