Improve pkghash_remove algorithm
[pacman-ng.git] / src / pacman / package.c
blob77a5ee722c5515059b030e6cbb76dd721f4fc3f2
1 /*
2 * package.c
4 * Copyright (c) 2006-2011 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 "config.h"
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <limits.h>
28 #include <errno.h>
29 #include <wchar.h>
31 #include <alpm.h>
32 #include <alpm_list.h>
34 /* pacman */
35 #include "package.h"
36 #include "util.h"
38 #define CLBUF_SIZE 4096
40 /* Display the content of a package
42 * levels:
43 * <-1 - sync package, extra information (required by) [-Sii]
44 * -1 - sync package, normal level [-Si]
45 * =0 - file query [-Qip]
46 * 1 - localdb query, normal level [-Qi]
47 * >1 - localdb query, extra information (backup files) [-Qii]
49 void dump_pkg_full(pmpkg_t *pkg, int level)
51 const char *reason;
52 time_t bdate, idate;
53 char bdatestr[50] = "", idatestr[50] = "";
54 const alpm_list_t *i;
55 alpm_list_t *requiredby = NULL, *depstrings = NULL;
57 if(pkg == NULL) {
58 return;
61 /* set variables here, do all output below */
62 bdate = alpm_pkg_get_builddate(pkg);
63 if(bdate) {
64 strftime(bdatestr, 50, "%c", localtime(&bdate));
66 idate = alpm_pkg_get_installdate(pkg);
67 if(idate) {
68 strftime(idatestr, 50, "%c", localtime(&idate));
71 switch((long)alpm_pkg_get_reason(pkg)) {
72 case PM_PKG_REASON_EXPLICIT:
73 reason = _("Explicitly installed");
74 break;
75 case PM_PKG_REASON_DEPEND:
76 reason = _("Installed as a dependency for another package");
77 break;
78 default:
79 reason = _("Unknown");
80 break;
83 /* turn depends list into a text list */
84 for(i = alpm_pkg_get_depends(pkg); i; i = alpm_list_next(i)) {
85 pmdepend_t *dep = (pmdepend_t*)alpm_list_getdata(i);
86 depstrings = alpm_list_add(depstrings, alpm_dep_compute_string(dep));
89 if(level > 0 || level < -1) {
90 /* compute this here so we don't get a pause in the middle of output */
91 requiredby = alpm_pkg_compute_requiredby(pkg);
94 /* actual output */
95 string_display(_("Name :"), alpm_pkg_get_name(pkg));
96 string_display(_("Version :"), alpm_pkg_get_version(pkg));
97 string_display(_("URL :"), alpm_pkg_get_url(pkg));
98 list_display(_("Licenses :"), alpm_pkg_get_licenses(pkg));
99 list_display(_("Groups :"), alpm_pkg_get_groups(pkg));
100 list_display(_("Provides :"), alpm_pkg_get_provides(pkg));
101 list_display(_("Depends On :"), depstrings);
102 list_display_linebreak(_("Optional Deps :"), alpm_pkg_get_optdepends(pkg));
103 if(level > 0 || level < -1) {
104 list_display(_("Required By :"), requiredby);
106 list_display(_("Conflicts With :"), alpm_pkg_get_conflicts(pkg));
107 list_display(_("Replaces :"), alpm_pkg_get_replaces(pkg));
108 if(level < 0) {
109 printf(_("Download Size : %6.2f K\n"),
110 (double)alpm_pkg_get_size(pkg) / 1024.0);
112 if(level == 0) {
113 printf(_("Compressed Size: %6.2f K\n"),
114 (double)alpm_pkg_get_size(pkg) / 1024.0);
117 printf(_("Installed Size : %6.2f K\n"),
118 (double)alpm_pkg_get_isize(pkg) / 1024.0);
119 string_display(_("Packager :"), alpm_pkg_get_packager(pkg));
120 string_display(_("Architecture :"), alpm_pkg_get_arch(pkg));
121 string_display(_("Build Date :"), bdatestr);
122 if(level > 0) {
123 string_display(_("Install Date :"), idatestr);
124 string_display(_("Install Reason :"), reason);
126 if(level >= 0) {
127 string_display(_("Install Script :"),
128 alpm_pkg_has_scriptlet(pkg) ? _("Yes") : _("No"));
131 /* MD5 Sum for sync package */
132 if(level < 0) {
133 string_display(_("MD5 Sum :"), alpm_pkg_get_md5sum(pkg));
135 string_display(_("Description :"), alpm_pkg_get_desc(pkg));
137 /* Print additional package info if info flag passed more than once */
138 if(level > 1) {
139 dump_pkg_backups(pkg);
142 /* final newline to separate packages */
143 printf("\n");
145 FREELIST(depstrings);
146 FREELIST(requiredby);
149 /* Display the content of a sync package
151 void dump_pkg_sync(pmpkg_t *pkg, const char *treename, int level)
153 if(pkg == NULL) {
154 return;
156 string_display(_("Repository :"), treename);
157 /* invert the level since we are a sync package */
158 dump_pkg_full(pkg, -level);
161 static const char *get_backup_file_status(const char *root,
162 const char *filename, const char *expected_md5)
164 char path[PATH_MAX];
165 char *ret;
167 snprintf(path, PATH_MAX, "%s%s", root, filename);
169 /* if we find the file, calculate checksums, otherwise it is missing */
170 if(access(path, R_OK) == 0) {
171 char *md5sum = alpm_compute_md5sum(path);
173 if(md5sum == NULL) {
174 pm_fprintf(stderr, PM_LOG_ERROR,
175 _("could not calculate checksums for %s\n"), path);
176 return(NULL);
179 /* if checksums don't match, file has been modified */
180 if (strcmp(md5sum, expected_md5) != 0) {
181 ret = "MODIFIED";
182 } else {
183 ret = "UNMODIFIED";
185 free(md5sum);
186 } else {
187 switch(errno) {
188 case EACCES:
189 ret = "UNREADABLE";
190 break;
191 case ENOENT:
192 ret = "MISSING";
193 break;
194 default:
195 ret = "UNKNOWN";
198 return(ret);
201 /* Display list of backup files and their modification states
203 void dump_pkg_backups(pmpkg_t *pkg)
205 alpm_list_t *i;
206 const char *root = alpm_option_get_root();
207 printf(_("Backup Files:\n"));
208 if(alpm_pkg_get_backup(pkg)) {
209 /* package has backup files, so print them */
210 for(i = alpm_pkg_get_backup(pkg); i; i = alpm_list_next(i)) {
211 const char *value;
212 char *str = strdup(alpm_list_getdata(i));
213 char *ptr = strchr(str, '\t');
214 if(ptr == NULL) {
215 free(str);
216 continue;
218 *ptr = '\0';
219 ptr++;
220 value = get_backup_file_status(root, str, ptr);
221 printf("%s\t%s%s\n", value, root, str);
222 free(str);
224 } else {
225 /* package had no backup files */
226 printf(_("(none)\n"));
230 /* List all files contained in a package
232 void dump_pkg_files(pmpkg_t *pkg, int quiet)
234 const char *pkgname, *root, *filestr;
235 alpm_list_t *i, *pkgfiles;
237 pkgname = alpm_pkg_get_name(pkg);
238 pkgfiles = alpm_pkg_get_files(pkg);
239 root = alpm_option_get_root();
241 for(i = pkgfiles; i; i = alpm_list_next(i)) {
242 filestr = alpm_list_getdata(i);
243 if(!quiet){
244 fprintf(stdout, "%s %s%s\n", pkgname, root, filestr);
245 } else {
246 fprintf(stdout, "%s%s\n", root, filestr);
250 fflush(stdout);
253 /* Display the changelog of a package
255 void dump_pkg_changelog(pmpkg_t *pkg)
257 void *fp = NULL;
259 if((fp = alpm_pkg_changelog_open(pkg)) == NULL) {
260 pm_fprintf(stderr, PM_LOG_ERROR, _("no changelog available for '%s'.\n"),
261 alpm_pkg_get_name(pkg));
262 return;
263 } else {
264 /* allocate a buffer to get the changelog back in chunks */
265 char buf[CLBUF_SIZE];
266 size_t ret = 0;
267 while((ret = alpm_pkg_changelog_read(buf, CLBUF_SIZE, pkg, fp))) {
268 if(ret < CLBUF_SIZE) {
269 /* if we hit the end of the file, we need to add a null terminator */
270 *(buf + ret) = '\0';
272 printf("%s", buf);
274 alpm_pkg_changelog_close(pkg, fp);
275 printf("\n");
279 /* vim: set ts=2 sw=2 noet: */