libalpm
Arch Linux Package Manager Library
package.c
Go to the documentation of this file.
00001 /*
00002  *  package.c
00003  *
00004  *  Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
00005  *  Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
00006  *
00007  *  This program is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License as published by
00009  *  the Free Software Foundation; either version 2 of the License, or
00010  *  (at your option) any later version.
00011  *
00012  *  This program is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *  GNU General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU General Public License
00018  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00019  */
00020 
00021 #include <stdlib.h>
00022 #include <stdio.h>
00023 #include <string.h>
00024 #include <unistd.h>
00025 #include <limits.h>
00026 #include <errno.h>
00027 #include <time.h>
00028 
00029 #include <alpm.h>
00030 #include <alpm_list.h>
00031 
00032 /* pacman */
00033 #include "package.h"
00034 #include "util.h"
00035 #include "conf.h"
00036 
00037 #define CLBUF_SIZE 4096
00038 
00039 /** Turn a depends list into a text list.
00040  * @param deps a list with items of type alpm_depend_t
00041  * @return a string list, must be freed
00042  */
00043 static void deplist_display(const char *title,
00044         alpm_list_t *deps)
00045 {
00046     alpm_list_t *i, *text = NULL;
00047     for(i = deps; i; i = alpm_list_next(i)) {
00048         alpm_depend_t *dep = i->data;
00049         text = alpm_list_add(text, alpm_dep_compute_string(dep));
00050     }
00051     list_display(title, text);
00052     FREELIST(text);
00053 }
00054 
00055 /**
00056  * Display the details of a package.
00057  * Extra information entails 'required by' info for sync packages and backup
00058  * files info for local packages.
00059  * @param pkg package to display information for
00060  * @param from the type of package we are dealing with
00061  * @param extra should we show extra information
00062  */
00063 void dump_pkg_full(alpm_pkg_t *pkg, int extra)
00064 {
00065     const char *reason;
00066     time_t bdate, idate;
00067     char bdatestr[50] = "", idatestr[50] = "";
00068     const char *label;
00069     double size;
00070     alpm_list_t *requiredby = NULL;
00071     alpm_pkgfrom_t from;
00072 
00073     from = alpm_pkg_get_origin(pkg);
00074 
00075     /* set variables here, do all output below */
00076     bdate = (time_t)alpm_pkg_get_builddate(pkg);
00077     if(bdate) {
00078         strftime(bdatestr, 50, "%c", localtime(&bdate));
00079     }
00080     idate = (time_t)alpm_pkg_get_installdate(pkg);
00081     if(idate) {
00082         strftime(idatestr, 50, "%c", localtime(&idate));
00083     }
00084 
00085     switch(alpm_pkg_get_reason(pkg)) {
00086         case ALPM_PKG_REASON_EXPLICIT:
00087             reason = _("Explicitly installed");
00088             break;
00089         case ALPM_PKG_REASON_DEPEND:
00090             reason = _("Installed as a dependency for another package");
00091             break;
00092         default:
00093             reason = _("Unknown");
00094             break;
00095     }
00096 
00097     if(extra || from == PKG_FROM_LOCALDB) {
00098         /* compute this here so we don't get a pause in the middle of output */
00099         requiredby = alpm_pkg_compute_requiredby(pkg);
00100     }
00101 
00102     /* actual output */
00103     if(from == PKG_FROM_SYNCDB) {
00104         string_display(_("Repository     :"),
00105                 alpm_db_get_name(alpm_pkg_get_db(pkg)));
00106     }
00107     string_display(_("Name           :"), alpm_pkg_get_name(pkg));
00108     string_display(_("Version        :"), alpm_pkg_get_version(pkg));
00109     string_display(_("URL            :"), alpm_pkg_get_url(pkg));
00110     list_display(_("Licenses       :"), alpm_pkg_get_licenses(pkg));
00111     list_display(_("Groups         :"), alpm_pkg_get_groups(pkg));
00112     deplist_display(_("Provides       :"), alpm_pkg_get_provides(pkg));
00113     deplist_display(_("Depends On     :"), alpm_pkg_get_depends(pkg));
00114     list_display_linebreak(_("Optional Deps  :"), alpm_pkg_get_optdepends(pkg));
00115     if(extra || from == PKG_FROM_LOCALDB) {
00116         list_display(_("Required By    :"), requiredby);
00117     }
00118     deplist_display(_("Conflicts With :"), alpm_pkg_get_conflicts(pkg));
00119     deplist_display(_("Replaces       :"), alpm_pkg_get_replaces(pkg));
00120 
00121     size = humanize_size(alpm_pkg_get_size(pkg), 'K', &label);
00122     if(from == PKG_FROM_SYNCDB) {
00123         printf(_("Download Size  : %6.2f %s\n"), size, label);
00124     } else if(from == PKG_FROM_FILE) {
00125         printf(_("Compressed Size: %6.2f %s\n"), size, label);
00126     }
00127 
00128     size = humanize_size(alpm_pkg_get_isize(pkg), 'K', &label);
00129     printf(_("Installed Size : %6.2f %s\n"), size, label);
00130 
00131     string_display(_("Packager       :"), alpm_pkg_get_packager(pkg));
00132     string_display(_("Architecture   :"), alpm_pkg_get_arch(pkg));
00133     string_display(_("Build Date     :"), bdatestr);
00134     if(from == PKG_FROM_LOCALDB) {
00135         string_display(_("Install Date   :"), idatestr);
00136         string_display(_("Install Reason :"), reason);
00137     }
00138     if(from == PKG_FROM_FILE || from == PKG_FROM_LOCALDB) {
00139         string_display(_("Install Script :"),
00140                 alpm_pkg_has_scriptlet(pkg) ?  _("Yes") : _("No"));
00141     }
00142 
00143     if(from == PKG_FROM_SYNCDB) {
00144         string_display(_("MD5 Sum        :"), alpm_pkg_get_md5sum(pkg));
00145         string_display(_("SHA256 Sum     :"), alpm_pkg_get_sha256sum(pkg));
00146         string_display(_("Signatures     :"),
00147                 alpm_pkg_get_base64_sig(pkg) ? _("Yes") : _("None"));
00148     }
00149     if(from == PKG_FROM_FILE) {
00150         alpm_siglist_t siglist;
00151         int err = alpm_pkg_check_pgp_signature(pkg, &siglist);
00152         if(err && alpm_errno(config->handle) == ALPM_ERR_SIG_MISSING) {
00153             string_display(_("Signatures     :"), _("None"));
00154         } else if(err) {
00155             string_display(_("Signatures     :"),
00156                     alpm_strerror(alpm_errno(config->handle)));
00157         } else {
00158             signature_display(_("Signatures     :"), &siglist);
00159         }
00160         alpm_siglist_cleanup(&siglist);
00161     }
00162     string_display(_("Description    :"), alpm_pkg_get_desc(pkg));
00163 
00164     /* Print additional package info if info flag passed more than once */
00165     if(from == PKG_FROM_LOCALDB && extra) {
00166         dump_pkg_backups(pkg);
00167     }
00168 
00169     /* final newline to separate packages */
00170     printf("\n");
00171 
00172     FREELIST(requiredby);
00173 }
00174 
00175 static const char *get_backup_file_status(const char *root,
00176         const alpm_backup_t *backup)
00177 {
00178     char path[PATH_MAX];
00179     const char *ret;
00180 
00181     snprintf(path, PATH_MAX, "%s%s", root, backup->name);
00182 
00183     /* if we find the file, calculate checksums, otherwise it is missing */
00184     if(access(path, R_OK) == 0) {
00185         char *md5sum = alpm_compute_md5sum(path);
00186 
00187         if(md5sum == NULL) {
00188             pm_printf(ALPM_LOG_ERROR,
00189                     _("could not calculate checksums for %s\n"), path);
00190             return NULL;
00191         }
00192 
00193         /* if checksums don't match, file has been modified */
00194         if(strcmp(md5sum, backup->hash) != 0) {
00195             ret = "MODIFIED";
00196         } else {
00197             ret = "UNMODIFIED";
00198         }
00199         free(md5sum);
00200     } else {
00201         switch(errno) {
00202             case EACCES:
00203                 ret = "UNREADABLE";
00204                 break;
00205             case ENOENT:
00206                 ret = "MISSING";
00207                 break;
00208             default:
00209                 ret = "UNKNOWN";
00210         }
00211     }
00212     return ret;
00213 }
00214 
00215 /* Display list of backup files and their modification states
00216  */
00217 void dump_pkg_backups(alpm_pkg_t *pkg)
00218 {
00219     alpm_list_t *i;
00220     const char *root = alpm_option_get_root(config->handle);
00221     printf(_("Backup Files:\n"));
00222     if(alpm_pkg_get_backup(pkg)) {
00223         /* package has backup files, so print them */
00224         for(i = alpm_pkg_get_backup(pkg); i; i = alpm_list_next(i)) {
00225             const alpm_backup_t *backup = i->data;
00226             const char *value;
00227             if(!backup->hash) {
00228                 continue;
00229             }
00230             value = get_backup_file_status(root, backup);
00231             printf("%s\t%s%s\n", value, root, backup->name);
00232         }
00233     } else {
00234         /* package had no backup files */
00235         printf(_("(none)\n"));
00236     }
00237 }
00238 
00239 /* List all files contained in a package
00240  */
00241 void dump_pkg_files(alpm_pkg_t *pkg, int quiet)
00242 {
00243     const char *pkgname, *root;
00244     alpm_filelist_t *pkgfiles;
00245     size_t i;
00246 
00247     pkgname = alpm_pkg_get_name(pkg);
00248     pkgfiles = alpm_pkg_get_files(pkg);
00249     root = alpm_option_get_root(config->handle);
00250 
00251     for(i = 0; i < pkgfiles->count; i++) {
00252         const alpm_file_t *file = pkgfiles->files + i;
00253         /* Regular: '<pkgname> <root><filepath>\n'
00254          * Quiet  : '<root><filepath>\n'
00255          */
00256         if(!quiet) {
00257             fputs(pkgname, stdout);
00258             putchar(' ');
00259         }
00260         fputs(root, stdout);
00261         fputs(file->name, stdout);
00262         putchar('\n');
00263     }
00264 
00265     fflush(stdout);
00266 }
00267 
00268 /* Display the changelog of a package
00269  */
00270 void dump_pkg_changelog(alpm_pkg_t *pkg)
00271 {
00272     void *fp = NULL;
00273 
00274     if((fp = alpm_pkg_changelog_open(pkg)) == NULL) {
00275         pm_printf(ALPM_LOG_ERROR, _("no changelog available for '%s'.\n"),
00276                 alpm_pkg_get_name(pkg));
00277         return;
00278     } else {
00279         /* allocate a buffer to get the changelog back in chunks */
00280         char buf[CLBUF_SIZE];
00281         size_t ret = 0;
00282         while((ret = alpm_pkg_changelog_read(buf, CLBUF_SIZE, pkg, fp))) {
00283             if(ret < CLBUF_SIZE) {
00284                 /* if we hit the end of the file, we need to add a null terminator */
00285                 *(buf + ret) = '\0';
00286             }
00287             fputs(buf, stdout);
00288         }
00289         alpm_pkg_changelog_close(pkg, fp);
00290         putchar('\n');
00291     }
00292 }
00293 
00294 /* vim: set ts=2 sw=2 noet: */