index : pacman | |
Archlinux32 fork of pacman | gitolite user |
summaryrefslogtreecommitdiff |
-rw-r--r-- | lib/libalpm/package.c | 342 |
diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c new file mode 100644 index 00000000..f20b88eb --- /dev/null +++ b/lib/libalpm/package.c @@ -0,0 +1,342 @@ +/* + * package.c + * + * Copyright (c) 2002-2005 by Judd Vinet <jvinet@zeroflux.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#include "config.h" +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <fcntl.h> +#include <string.h> +#include <libtar.h> +#include <zlib.h> +/* pacman */ +#include "log.h" +#include "util.h" +#include "error.h" +#include "list.h" +#include "package.h" + +pmpkg_t *pkg_new() +{ + pmpkg_t* pkg = NULL; + + MALLOC(pkg, sizeof(pmpkg_t)); + + pkg->name[0] = '\0'; + pkg->version[0] = '\0'; + pkg->desc[0] = '\0'; + pkg->url[0] = '\0'; + pkg->license[0] = '\0'; + pkg->builddate[0] = '\0'; + pkg->installdate[0] = '\0'; + pkg->packager[0] = '\0'; + pkg->md5sum[0] = '\0'; + pkg->arch[0] = '\0'; + pkg->size = 0; + pkg->scriptlet = 0; + pkg->force = 0; + pkg->reason = PM_PKG_REASON_EXPLICIT; + pkg->requiredby = NULL; + pkg->conflicts = NULL; + pkg->files = NULL; + pkg->backup = NULL; + pkg->depends = NULL; + pkg->groups = NULL; + pkg->provides = NULL; + pkg->replaces = NULL; + /* internal */ + pkg->origin = 0; + pkg->data = NULL; + pkg->infolevel = 0; + + return(pkg); +} + +void pkg_free(pmpkg_t *pkg) +{ + if(pkg == NULL) { + return; + } + + FREELIST(pkg->files); + FREELIST(pkg->backup); + FREELIST(pkg->depends); + FREELIST(pkg->conflicts); + FREELIST(pkg->requiredby); + FREELIST(pkg->groups); + FREELIST(pkg->provides); + FREELIST(pkg->replaces); + if(pkg->origin == PKG_FROM_FILE) { + FREE(pkg->data); + } + free(pkg); + + return; +} + +/* Parses the package description file for the current package + * + * Returns: 0 on success, 1 on error + * + */ +static int parse_descfile(char *descfile, pmpkg_t *info, int output) +{ + FILE* fp = NULL; + char line[PATH_MAX+1]; + char* ptr = NULL; + char* key = NULL; + int linenum = 0; + + if((fp = fopen(descfile, "r")) == NULL) { + _alpm_log(PM_LOG_ERROR, "could not open file %s", descfile); + return(-1); + } + + while(!feof(fp)) { + fgets(line, PATH_MAX, fp); + linenum++; + _alpm_strtrim(line); + if(strlen(line) == 0 || line[0] == '#') { + continue; + } + if(output) { + printf("%s\n", line); + } + ptr = line; + key = strsep(&ptr, "="); + if(key == NULL || ptr == NULL) { + fprintf(stderr, "%s: syntax error in description file line %d\n", + info->name[0] != '\0' ? info->name : "error", linenum); + } else { + _alpm_strtrim(key); + key = _alpm_strtoupper(key); + _alpm_strtrim(ptr); + if(!strcmp(key, "PKGNAME")) { + strncpy(info->name, ptr, sizeof(info->name)); + } else if(!strcmp(key, "PKGVER")) { + strncpy(info->version, ptr, sizeof(info->version)); + } else if(!strcmp(key, "PKGDESC")) { + strncpy(info->desc, ptr, sizeof(info->desc)); + } else if(!strcmp(key, "GROUP")) { + info->groups = pm_list_add(info->groups, strdup(ptr)); + } else if(!strcmp(key, "URL")) { + strncpy(info->url, ptr, sizeof(info->url)); + } else if(!strcmp(key, "LICENSE")) { + strncpy(info->license, ptr, sizeof(info->license)); + } else if(!strcmp(key, "BUILDDATE")) { + strncpy(info->builddate, ptr, sizeof(info->builddate)); + } else if(!strcmp(key, "INSTALLDATE")) { + strncpy(info->installdate, ptr, sizeof(info->installdate)); + } else if(!strcmp(key, "PACKAGER")) { + strncpy(info->packager, ptr, sizeof(info->packager)); + } else if(!strcmp(key, "ARCH")) { + strncpy(info->arch, ptr, sizeof(info->arch)); + } else if(!strcmp(key, "SIZE")) { + char tmp[32]; + strncpy(tmp, ptr, sizeof(tmp)); + info->size = atol(tmp); + } else if(!strcmp(key, "DEPEND")) { + info->depends = pm_list_add(info->depends, strdup(ptr)); + } else if(!strcmp(key, "CONFLICT")) { + info->conflicts = pm_list_add(info->conflicts, strdup(ptr)); + } else if(!strcmp(key, "REPLACES")) { + info->replaces = pm_list_add(info->replaces, strdup(ptr)); + } else if(!strcmp(key, "PROVIDES")) { + info->provides = pm_list_add(info->provides, strdup(ptr)); + } else if(!strcmp(key, "BACKUP")) { + info->backup = pm_list_add(info->backup, strdup(ptr)); + } else { + fprintf(stderr, "%s: syntax error in description file line %d\n", + info->name[0] != '\0' ? info->name : "error", linenum); + } + } + line[0] = '\0'; + } + fclose(fp); + unlink(descfile); + + return(0); +} + +pmpkg_t *pkg_load(char *pkgfile) +{ + char *expath; + int i; + int config = 0; + int filelist = 0; + int scriptcheck = 0; + TAR *tar; + pmpkg_t *info = NULL; + tartype_t gztype = { + (openfunc_t)_alpm_gzopen_frontend, + (closefunc_t)gzclose, + (readfunc_t)gzread, + (writefunc_t)gzwrite + }; + + if(pkgfile == NULL) { + PM_RET_ERR(PM_ERR_WRONG_ARGS, NULL); + } + + if(tar_open(&tar, pkgfile, &gztype, O_RDONLY, 0, TAR_GNU) == -1) { + PM_RET_ERR(PM_ERR_NOT_A_FILE, NULL); + } + + info = pkg_new(); + if(info == NULL) { + tar_close(tar); + PM_RET_ERR(PM_ERR_MEMORY, NULL); + } + + for(i = 0; !th_read(tar); i++) { + if(config && filelist && scriptcheck) { + /* we have everything we need */ + break; + } + if(!strcmp(th_get_pathname(tar), ".PKGINFO")) { + char *descfile; + + /* extract this file into /tmp. it has info for us */ + descfile = strdup("/tmp/pacman_XXXXXX"); + mkstemp(descfile); + tar_extract_file(tar, descfile); + /* parse the info file */ + if(parse_descfile(descfile, info, 0) == -1) { + goto error; + } + if(!strlen(info->name)) { + _alpm_log(PM_LOG_ERROR, "missing package name in %s", pkgfile); + goto error; + } + if(!strlen(info->version)) { + _alpm_log(PM_LOG_ERROR, "missing package version in %s", pkgfile); + goto error; + } + config = 1; + FREE(descfile); + continue; + } else if(!strcmp(th_get_pathname(tar), "._install") || !strcmp(th_get_pathname(tar), ".INSTALL")) { + info->scriptlet = 1; + scriptcheck = 1; + } else if(!strcmp(th_get_pathname(tar), ".FILELIST")) { + /* Build info->files from the filelist */ + FILE *fp; + char *fn; + char *str; + + MALLOC(str, PATH_MAX); + fn = strdup("/tmp/pacman_XXXXXX"); + mkstemp(fn); + tar_extract_file(tar, fn); + fp = fopen(fn, "r"); + while(!feof(fp)) { + if(fgets(str, PATH_MAX, fp) == NULL) { + continue; + } + _alpm_strtrim(str); + info->files = pm_list_add(info->files, strdup(str)); + } + FREE(str); + fclose(fp); + if(unlink(fn)) { + _alpm_log(PM_LOG_WARNING, "could not remove tempfile %s\n", fn); + } + FREE(fn); + filelist = 1; + continue; + } else { + scriptcheck = 1; + if(!filelist) { + /* no .FILELIST present in this package.. build the filelist the */ + /* old-fashioned way, one at a time */ + expath = strdup(th_get_pathname(tar)); + info->files = pm_list_add(info->files, expath); + } + } + + if(TH_ISREG(tar) && tar_skip_regfile(tar)) { + _alpm_log(PM_LOG_ERROR, "bad package file in %s", pkgfile); + goto error; + } + expath = NULL; + } + tar_close(tar); + + if(!config) { + _alpm_log(PM_LOG_ERROR, "missing package info file in %s", pkgfile); + goto error; + } + + /* internal */ + info->origin = PKG_FROM_FILE; + info->data = strdup(pkgfile); + info->infolevel = 0xFF; + + return(info); + +error: + printf("toto\n"); + + FREEPKG(info); + tar_close(tar); + + return(NULL); +} + +/* Helper function for sorting packages + */ +int pkg_cmp(const void *p1, const void *p2) +{ + pmpkg_t *pkg1 = (pmpkg_t *)p1; + pmpkg_t *pkg2 = (pmpkg_t *)p2; + + return(strcmp(pkg1->name, pkg2->name)); +} + +/* Test for existence of a package in a PMList* + * of pmpkg_t* + * + * returns: 0 for no match + * 1 for identical match + * -1 for name-only match (version mismatch) + */ +int pkg_isin(pmpkg_t *needle, PMList *haystack) +{ + PMList *lp; + + if(needle == NULL || haystack == NULL) { + return(0); + } + + for(lp = haystack; lp; lp = lp->next) { + pmpkg_t *info = lp->data; + + if(info && !strcmp(info->name, needle->name)) { + if(!strcmp(info->version, needle->version)) { + return(1); + } + return(-1); + } + } + return(0); +} + +/* vim: set ts=2 sw=2 noet: */ |