]>
Commit | Line | Data |
---|---|---|
d04baaba JV |
1 | /* |
2 | * package.c | |
23229097 | 3 | * |
1dd34058 | 4 | * Copyright (c) 2006-2013 Pacman Development Team <pacman-dev@archlinux.org> |
c72b4543 | 5 | * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org> |
23229097 | 6 | * |
d04baaba JV |
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. | |
11 | * | |
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. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
9781d0d6 | 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
d04baaba JV |
19 | */ |
20 | ||
21 | #include <stdlib.h> | |
22 | #include <stdio.h> | |
23 | #include <string.h> | |
29bf6814 | 24 | #include <unistd.h> |
73fa6fb9 | 25 | #include <limits.h> |
cda7d784 | 26 | #include <errno.h> |
5f3629be | 27 | #include <time.h> |
d04baaba JV |
28 | |
29 | #include <alpm.h> | |
eb03fe80 | 30 | #include <alpm_list.h> |
869e81e1 | 31 | |
d04baaba | 32 | /* pacman */ |
869e81e1 | 33 | #include "package.h" |
d04baaba | 34 | #include "util.h" |
17a6ac56 | 35 | #include "conf.h" |
d04baaba | 36 | |
7249c08b DM |
37 | #define CLBUF_SIZE 4096 |
38 | ||
a628feee DM |
39 | /** Turn a depends list into a text list. |
40 | * @param deps a list with items of type alpm_depend_t | |
a628feee DM |
41 | */ |
42 | static void deplist_display(const char *title, | |
8da489ea | 43 | alpm_list_t *deps, unsigned short cols) |
a628feee DM |
44 | { |
45 | alpm_list_t *i, *text = NULL; | |
46 | for(i = deps; i; i = alpm_list_next(i)) { | |
6be492d2 | 47 | alpm_depend_t *dep = i->data; |
a628feee DM |
48 | text = alpm_list_add(text, alpm_dep_compute_string(dep)); |
49 | } | |
8da489ea | 50 | list_display(title, text, cols); |
a628feee DM |
51 | FREELIST(text); |
52 | } | |
53 | ||
e85e77e6 | 54 | /** Turn a optdepends list into a text list. |
7262f4be | 55 | * @param optdeps a list with items of type alpm_depend_t |
e85e77e6 | 56 | */ |
63a2874f | 57 | static void optdeplist_display(alpm_pkg_t *pkg, unsigned short cols) |
e85e77e6 BM |
58 | { |
59 | alpm_list_t *i, *text = NULL; | |
63a2874f | 60 | for(i = alpm_pkg_get_optdepends(pkg); i; i = alpm_list_next(i)) { |
e85e77e6 | 61 | alpm_depend_t *optdep = i->data; |
63a2874f AM |
62 | char *depstring = alpm_dep_compute_string(optdep); |
63 | if(alpm_pkg_get_origin(pkg) == ALPM_PKG_FROM_LOCALDB) { | |
64 | if(alpm_db_get_pkg(alpm_get_localdb(config->handle), optdep->name)) { | |
65 | const char *installed = _(" [installed]"); | |
66 | depstring = realloc(depstring, strlen(depstring) + strlen(installed) + 1); | |
67 | strcpy(depstring + strlen(depstring), installed); | |
68 | } | |
69 | } | |
70 | text = alpm_list_add(text, depstring); | |
e85e77e6 | 71 | } |
63a2874f | 72 | list_display_linebreak(_("Optional Deps :"), text, cols); |
e85e77e6 BM |
73 | FREELIST(text); |
74 | } | |
75 | ||
8b34aa50 DM |
76 | /** |
77 | * Display the details of a package. | |
78 | * Extra information entails 'required by' info for sync packages and backup | |
79 | * files info for local packages. | |
80 | * @param pkg package to display information for | |
81 | * @param from the type of package we are dealing with | |
82 | * @param extra should we show extra information | |
d04baaba | 83 | */ |
040083b9 | 84 | void dump_pkg_full(alpm_pkg_t *pkg, int extra) |
d04baaba | 85 | { |
8da489ea | 86 | unsigned short cols; |
47622eef | 87 | time_t bdate, idate; |
040083b9 | 88 | alpm_pkgfrom_t from; |
8da489ea DM |
89 | double size; |
90 | char bdatestr[50] = "", idatestr[50] = ""; | |
91 | const char *label, *reason; | |
d0e5cd2c | 92 | alpm_list_t *validation = NULL, *requiredby = NULL, *optionalfor = NULL; |
d04baaba | 93 | |
040083b9 | 94 | from = alpm_pkg_get_origin(pkg); |
d04baaba | 95 | |
c6f56aee | 96 | /* set variables here, do all output below */ |
5f3629be | 97 | bdate = (time_t)alpm_pkg_get_builddate(pkg); |
c15f7710 NG |
98 | if(bdate) { |
99 | strftime(bdatestr, 50, "%c", localtime(&bdate)); | |
100 | } | |
5f3629be | 101 | idate = (time_t)alpm_pkg_get_installdate(pkg); |
c15f7710 NG |
102 | if(idate) { |
103 | strftime(idatestr, 50, "%c", localtime(&idate)); | |
104 | } | |
d04baaba | 105 | |
6317db84 | 106 | switch(alpm_pkg_get_reason(pkg)) { |
eb39a948 | 107 | case ALPM_PKG_REASON_EXPLICIT: |
e1bad6ef | 108 | reason = _("Explicitly installed"); |
d04baaba | 109 | break; |
eb39a948 | 110 | case ALPM_PKG_REASON_DEPEND: |
e1bad6ef | 111 | reason = _("Installed as a dependency for another package"); |
d04baaba JV |
112 | break; |
113 | default: | |
e1bad6ef | 114 | reason = _("Unknown"); |
d04baaba JV |
115 | break; |
116 | } | |
117 | ||
f34864cc AM |
118 | alpm_pkgvalidation_t v = alpm_pkg_get_validation(pkg); |
119 | if(v) { | |
120 | if(v & ALPM_PKG_VALIDATION_NONE) { | |
121 | validation = alpm_list_add(validation, _("None")); | |
5c404268 | 122 | } else { |
f34864cc AM |
123 | if(v & ALPM_PKG_VALIDATION_MD5SUM) { |
124 | validation = alpm_list_add(validation, _("MD5 Sum")); | |
125 | } | |
126 | if(v & ALPM_PKG_VALIDATION_SHA256SUM) { | |
127 | validation = alpm_list_add(validation, _("SHA256 Sum")); | |
128 | } | |
129 | if(v & ALPM_PKG_VALIDATION_SIGNATURE) { | |
130 | validation = alpm_list_add(validation, _("Signature")); | |
131 | } | |
5c404268 | 132 | } |
f34864cc AM |
133 | } else { |
134 | validation = alpm_list_add(validation, _("Unknown")); | |
5c404268 AM |
135 | } |
136 | ||
3be02aa2 | 137 | if(extra || from == ALPM_PKG_FROM_LOCALDB) { |
6685822e | 138 | /* compute this here so we don't get a pause in the middle of output */ |
5c21f0f1 | 139 | requiredby = alpm_pkg_compute_requiredby(pkg); |
d0e5cd2c | 140 | optionalfor = alpm_pkg_compute_optionalfor(pkg); |
5c21f0f1 DM |
141 | } |
142 | ||
8da489ea DM |
143 | cols = getcols(fileno(stdout)); |
144 | ||
c6f56aee | 145 | /* actual output */ |
3be02aa2 | 146 | if(from == ALPM_PKG_FROM_SYNCDB) { |
8b34aa50 | 147 | string_display(_("Repository :"), |
8da489ea | 148 | alpm_db_get_name(alpm_pkg_get_db(pkg)), cols); |
8b34aa50 | 149 | } |
8da489ea DM |
150 | string_display(_("Name :"), alpm_pkg_get_name(pkg), cols); |
151 | string_display(_("Version :"), alpm_pkg_get_version(pkg), cols); | |
0fe56201 AM |
152 | string_display(_("Description :"), alpm_pkg_get_desc(pkg), cols); |
153 | string_display(_("Architecture :"), alpm_pkg_get_arch(pkg), cols); | |
8da489ea DM |
154 | string_display(_("URL :"), alpm_pkg_get_url(pkg), cols); |
155 | list_display(_("Licenses :"), alpm_pkg_get_licenses(pkg), cols); | |
156 | list_display(_("Groups :"), alpm_pkg_get_groups(pkg), cols); | |
157 | deplist_display(_("Provides :"), alpm_pkg_get_provides(pkg), cols); | |
158 | deplist_display(_("Depends On :"), alpm_pkg_get_depends(pkg), cols); | |
63a2874f AM |
159 | optdeplist_display(pkg, cols); |
160 | ||
3be02aa2 | 161 | if(extra || from == ALPM_PKG_FROM_LOCALDB) { |
8da489ea | 162 | list_display(_("Required By :"), requiredby, cols); |
d0e5cd2c | 163 | list_display(_("Optional For :"), optionalfor, cols); |
e668b471 | 164 | } |
8da489ea DM |
165 | deplist_display(_("Conflicts With :"), alpm_pkg_get_conflicts(pkg), cols); |
166 | deplist_display(_("Replaces :"), alpm_pkg_get_replaces(pkg), cols); | |
3c8a448a | 167 | |
e8db984c | 168 | size = humanize_size(alpm_pkg_get_size(pkg), 'K', 2, &label); |
3be02aa2 | 169 | if(from == ALPM_PKG_FROM_SYNCDB) { |
46c10c5b SG |
170 | printf("%s%s%s %6.2f %s\n", config->colstr.title, _("Download Size :"), |
171 | config->colstr.nocolor, size, label); | |
3be02aa2 | 172 | } else if(from == ALPM_PKG_FROM_FILE) { |
46c10c5b SG |
173 | printf("%s%s%s %6.2f %s\n", config->colstr.title, _("Compressed Size:"), |
174 | config->colstr.nocolor, size, label); | |
c15f7710 NG |
175 | } |
176 | ||
e8db984c | 177 | size = humanize_size(alpm_pkg_get_isize(pkg), 'K', 2, &label); |
46c10c5b SG |
178 | printf("%s%s%s %6.2f %s\n", config->colstr.title, _("Installed Size :"), |
179 | config->colstr.nocolor, size, label); | |
3c8a448a | 180 | |
8da489ea | 181 | string_display(_("Packager :"), alpm_pkg_get_packager(pkg), cols); |
8da489ea | 182 | string_display(_("Build Date :"), bdatestr, cols); |
3be02aa2 | 183 | if(from == ALPM_PKG_FROM_LOCALDB) { |
8da489ea DM |
184 | string_display(_("Install Date :"), idatestr, cols); |
185 | string_display(_("Install Reason :"), reason, cols); | |
c15f7710 | 186 | } |
3be02aa2 | 187 | if(from == ALPM_PKG_FROM_FILE || from == ALPM_PKG_FROM_LOCALDB) { |
c15f7710 | 188 | string_display(_("Install Script :"), |
8da489ea | 189 | alpm_pkg_has_scriptlet(pkg) ? _("Yes") : _("No"), cols); |
c15f7710 NG |
190 | } |
191 | ||
6d2fb6fd DR |
192 | if(from == ALPM_PKG_FROM_SYNCDB && extra) { |
193 | string_display(_("MD5 Sum :"), alpm_pkg_get_md5sum(pkg), cols); | |
194 | string_display(_("SHA256 Sum :"), alpm_pkg_get_sha256sum(pkg), cols); | |
195 | string_display(_("Signatures :"), | |
196 | alpm_pkg_get_base64_sig(pkg) ? _("Yes") : _("None"), cols); | |
197 | } else { | |
198 | list_display(_("Validated By :"), validation, cols); | |
199 | } | |
f34864cc | 200 | |
3be02aa2 | 201 | if(from == ALPM_PKG_FROM_FILE) { |
de43d00d DM |
202 | alpm_siglist_t siglist; |
203 | int err = alpm_pkg_check_pgp_signature(pkg, &siglist); | |
f37c5016 | 204 | if(err && alpm_errno(config->handle) == ALPM_ERR_SIG_MISSING) { |
8da489ea | 205 | string_display(_("Signatures :"), _("None"), cols); |
f37c5016 | 206 | } else if(err) { |
07502f2d | 207 | string_display(_("Signatures :"), |
8da489ea | 208 | alpm_strerror(alpm_errno(config->handle)), cols); |
07502f2d | 209 | } else { |
8da489ea | 210 | signature_display(_("Signatures :"), &siglist, cols); |
07502f2d | 211 | } |
de43d00d | 212 | alpm_siglist_cleanup(&siglist); |
07502f2d | 213 | } |
f34864cc | 214 | |
c6f56aee | 215 | /* Print additional package info if info flag passed more than once */ |
3be02aa2 | 216 | if(from == ALPM_PKG_FROM_LOCALDB && extra) { |
30691479 | 217 | dump_pkg_backups(pkg); |
73fa6fb9 | 218 | } |
2f55733b | 219 | |
95ea6fb3 XC |
220 | /* final newline to separate packages */ |
221 | printf("\n"); | |
222 | ||
cdbb90ac | 223 | FREELIST(requiredby); |
5c404268 | 224 | alpm_list_free(validation); |
d04baaba JV |
225 | } |
226 | ||
61864e1f | 227 | static const char *get_backup_file_status(const char *root, |
cd1e39ba | 228 | const alpm_backup_t *backup) |
61864e1f DM |
229 | { |
230 | char path[PATH_MAX]; | |
e8a40526 | 231 | const char *ret; |
61864e1f | 232 | |
54ef162a | 233 | snprintf(path, PATH_MAX, "%s%s", root, backup->name); |
61864e1f DM |
234 | |
235 | /* if we find the file, calculate checksums, otherwise it is missing */ | |
236 | if(access(path, R_OK) == 0) { | |
237 | char *md5sum = alpm_compute_md5sum(path); | |
238 | ||
239 | if(md5sum == NULL) { | |
9e9ecf21 | 240 | pm_printf(ALPM_LOG_ERROR, |
61864e1f | 241 | _("could not calculate checksums for %s\n"), path); |
0303b26b | 242 | return NULL; |
61864e1f DM |
243 | } |
244 | ||
245 | /* if checksums don't match, file has been modified */ | |
54ef162a | 246 | if(strcmp(md5sum, backup->hash) != 0) { |
c91bd3dd | 247 | ret = "MODIFIED"; |
61864e1f | 248 | } else { |
c91bd3dd | 249 | ret = "UNMODIFIED"; |
61864e1f DM |
250 | } |
251 | free(md5sum); | |
252 | } else { | |
cda7d784 DM |
253 | switch(errno) { |
254 | case EACCES: | |
255 | ret = "UNREADABLE"; | |
256 | break; | |
257 | case ENOENT: | |
258 | ret = "MISSING"; | |
259 | break; | |
260 | default: | |
261 | ret = "UNKNOWN"; | |
262 | } | |
61864e1f | 263 | } |
0303b26b | 264 | return ret; |
61864e1f DM |
265 | } |
266 | ||
c6f56aee AG |
267 | /* Display list of backup files and their modification states |
268 | */ | |
8a04bc25 | 269 | void dump_pkg_backups(alpm_pkg_t *pkg) |
c6f56aee | 270 | { |
61670172 | 271 | alpm_list_t *i; |
17a6ac56 | 272 | const char *root = alpm_option_get_root(config->handle); |
46c10c5b SG |
273 | printf("%s%s%s", config->colstr.title, _("Backup Files:\n"), |
274 | config->colstr.nocolor); | |
03f034ef DM |
275 | if(alpm_pkg_get_backup(pkg)) { |
276 | /* package has backup files, so print them */ | |
277 | for(i = alpm_pkg_get_backup(pkg); i; i = alpm_list_next(i)) { | |
6be492d2 | 278 | const alpm_backup_t *backup = i->data; |
61864e1f | 279 | const char *value; |
54ef162a | 280 | if(!backup->hash) { |
c6f56aee AG |
281 | continue; |
282 | } | |
54ef162a DM |
283 | value = get_backup_file_status(root, backup); |
284 | printf("%s\t%s%s\n", value, root, backup->name); | |
c6f56aee | 285 | } |
03f034ef DM |
286 | } else { |
287 | /* package had no backup files */ | |
288 | printf(_("(none)\n")); | |
c6f56aee AG |
289 | } |
290 | } | |
23229097 | 291 | |
c6f56aee AG |
292 | /* List all files contained in a package |
293 | */ | |
8a04bc25 | 294 | void dump_pkg_files(alpm_pkg_t *pkg, int quiet) |
d04baaba | 295 | { |
6a6fc310 | 296 | const char *pkgname, *root; |
bb3dada8 DM |
297 | alpm_filelist_t *pkgfiles; |
298 | size_t i; | |
d04baaba | 299 | |
aa1c0ba9 AG |
300 | pkgname = alpm_pkg_get_name(pkg); |
301 | pkgfiles = alpm_pkg_get_files(pkg); | |
17a6ac56 | 302 | root = alpm_option_get_root(config->handle); |
d04baaba | 303 | |
bb3dada8 DM |
304 | for(i = 0; i < pkgfiles->count; i++) { |
305 | const alpm_file_t *file = pkgfiles->files + i; | |
8605284e DM |
306 | /* Regular: '<pkgname> <root><filepath>\n' |
307 | * Quiet : '<root><filepath>\n' | |
308 | */ | |
bb3dada8 | 309 | if(!quiet) { |
7dd1a5a5 | 310 | printf("%s%s%s ", config->colstr.title, pkgname, config->colstr.nocolor); |
a783f3fb | 311 | } |
7dd1a5a5 | 312 | printf("%s%s\n", root, file->name); |
d04baaba JV |
313 | } |
314 | ||
315 | fflush(stdout); | |
316 | } | |
317 | ||
7249c08b | 318 | /* Display the changelog of a package |
3f275421 | 319 | */ |
8a04bc25 | 320 | void dump_pkg_changelog(alpm_pkg_t *pkg) |
3f275421 | 321 | { |
7249c08b | 322 | void *fp = NULL; |
3f275421 | 323 | |
7249c08b | 324 | if((fp = alpm_pkg_changelog_open(pkg)) == NULL) { |
9e9ecf21 | 325 | pm_printf(ALPM_LOG_ERROR, _("no changelog available for '%s'.\n"), |
7249c08b | 326 | alpm_pkg_get_name(pkg)); |
3f275421 | 327 | return; |
7249c08b | 328 | } else { |
95f566d9 | 329 | fprintf(stdout, _("Changelog for %s:\n"), alpm_pkg_get_name(pkg)); |
7249c08b DM |
330 | /* allocate a buffer to get the changelog back in chunks */ |
331 | char buf[CLBUF_SIZE]; | |
62f5da37 | 332 | size_t ret = 0; |
7249c08b DM |
333 | while((ret = alpm_pkg_changelog_read(buf, CLBUF_SIZE, pkg, fp))) { |
334 | if(ret < CLBUF_SIZE) { | |
335 | /* if we hit the end of the file, we need to add a null terminator */ | |
336 | *(buf + ret) = '\0'; | |
337 | } | |
8605284e | 338 | fputs(buf, stdout); |
3f275421 | 339 | } |
7249c08b | 340 | alpm_pkg_changelog_close(pkg, fp); |
8605284e | 341 | putchar('\n'); |
3f275421 AG |
342 | } |
343 | } | |
344 | ||
098cfe51 SG |
345 | void print_installed(alpm_db_t *db_local, alpm_pkg_t *pkg) |
346 | { | |
347 | const char *pkgname = alpm_pkg_get_name(pkg); | |
348 | const char *pkgver = alpm_pkg_get_version(pkg); | |
349 | alpm_pkg_t *lpkg = alpm_db_get_pkg(db_local, pkgname); | |
350 | if(lpkg) { | |
351 | const char *lpkgver = alpm_pkg_get_version(lpkg); | |
326345b3 | 352 | const colstr_t *colstr = &config->colstr; |
098cfe51 | 353 | if(strcmp(lpkgver, pkgver) == 0) { |
326345b3 | 354 | printf(" %s[%s]%s", colstr->meta, _("installed"), colstr->nocolor); |
098cfe51 | 355 | } else { |
326345b3 SG |
356 | printf(" %s[%s: %s]%s", colstr->meta, _("installed"), |
357 | lpkgver, colstr->nocolor); | |
098cfe51 SG |
358 | } |
359 | } | |
360 | } | |
361 | ||
362 | /** | |
58832b0d | 363 | * Display the details of a search. |
098cfe51 SG |
364 | * @param db the database we're searching |
365 | * @param targets the targets we're searching for | |
366 | * @param show_status show if the package is also in the local db | |
367 | */ | |
368 | int dump_pkg_search(alpm_db_t *db, alpm_list_t *targets, int show_status) | |
369 | { | |
370 | int freelist = 0; | |
371 | alpm_db_t *db_local; | |
372 | alpm_list_t *i, *searchlist; | |
373 | unsigned short cols; | |
326345b3 | 374 | const colstr_t *colstr = &config->colstr; |
098cfe51 SG |
375 | |
376 | if(show_status) { | |
377 | db_local = alpm_get_localdb(config->handle); | |
378 | } | |
379 | ||
380 | /* if we have a targets list, search for packages matching it */ | |
381 | if(targets) { | |
382 | searchlist = alpm_db_search(db, targets); | |
383 | freelist = 1; | |
384 | } else { | |
385 | searchlist = alpm_db_get_pkgcache(db); | |
386 | freelist = 0; | |
387 | } | |
388 | if(searchlist == NULL) { | |
389 | return 1; | |
390 | } | |
391 | ||
392 | cols = getcols(fileno(stdout)); | |
393 | for(i = searchlist; i; i = alpm_list_next(i)) { | |
394 | alpm_list_t *grp; | |
395 | alpm_pkg_t *pkg = i->data; | |
396 | ||
397 | if(config->quiet) { | |
398 | fputs(alpm_pkg_get_name(pkg), stdout); | |
399 | } else { | |
326345b3 SG |
400 | printf("%s%s/%s%s %s%s%s", colstr->repo, alpm_db_get_name(db), |
401 | colstr->title, alpm_pkg_get_name(pkg), | |
402 | colstr->version, alpm_pkg_get_version(pkg), colstr->nocolor); | |
098cfe51 SG |
403 | |
404 | if((grp = alpm_pkg_get_groups(pkg)) != NULL) { | |
405 | alpm_list_t *k; | |
326345b3 | 406 | printf(" %s(", colstr->groups); |
098cfe51 SG |
407 | for(k = grp; k; k = alpm_list_next(k)) { |
408 | const char *group = k->data; | |
409 | fputs(group, stdout); | |
410 | if(alpm_list_next(k)) { | |
411 | /* only print a spacer if there are more groups */ | |
412 | putchar(' '); | |
413 | } | |
414 | } | |
326345b3 | 415 | printf(")%s", colstr->nocolor); |
098cfe51 SG |
416 | } |
417 | ||
418 | if(show_status) { | |
419 | print_installed(db_local, pkg); | |
420 | } | |
421 | ||
422 | /* we need a newline and initial indent first */ | |
423 | fputs("\n ", stdout); | |
424 | indentprint(alpm_pkg_get_desc(pkg), 4, cols); | |
425 | } | |
426 | fputc('\n', stdout); | |
427 | } | |
428 | ||
429 | /* we only want to free if the list was a search list */ | |
430 | if(freelist) { | |
431 | alpm_list_free(searchlist); | |
432 | } | |
433 | ||
434 | return 0; | |
435 | } | |
436 | ||
d04baaba | 437 | /* vim: set ts=2 sw=2 noet: */ |