/* vi: set sw=4 ts=4: */ /* * Mini rpm applet for busybox * * Copyright (C) 2001,2002 by Laurence Anderson * * 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 #include #include #include #include #include /* For ntohl & htonl function */ #include /* For strncmp */ #include /* For mmap */ #include /* For ctime */ #include #include "busybox.h" #include "unarchive.h" #define MAX_BASENAME_LENGTH 64 #define MAX_VERSION_LENGTH 16 #define RPM_HEADER_MAGIC "\216\255\350" #define RPM_CHAR_TYPE 1 #define RPM_INT8_TYPE 2 #define RPM_INT16_TYPE 3 #define RPM_INT32_TYPE 4 /* #define RPM_INT64_TYPE 5 ---- These aren't supported (yet) */ #define RPM_STRING_TYPE 6 #define RPM_BIN_TYPE 7 #define RPM_STRING_ARRAY_TYPE 8 #define RPM_I18NSTRING_TYPE 9 #define RPMTAG_NAME 1000 #define RPMTAG_VERSION 1001 #define RPMTAG_RELEASE 1002 #define RPMTAG_EPOCH 1003 #define RPMTAG_SUMMARY 1004 #define RPMTAG_DESCRIPTION 1005 #define RPMTAG_BUILDTIME 1006 #define RPMTAG_BUILDHOST 1007 #define RPMTAG_SIZE 1009 #define RPMTAG_VENDOR 1011 #define RPMTAG_LICENSE 1014 #define RPMTAG_PACKAGER 1015 #define RPMTAG_GROUP 1016 #define RPMTAG_URL 1020 // pre/post IN are pre- and post-install scripts #define RPMTAG_PREIN 1023 #define RPMTAG_POSTIN 1024 // pre/post UN are pre- and post-uninstall scripts #define RPMTAG_PREUN 1025 #define RPMTAG_POSTUN 1026 #define RPMTAG_FILEMD5S 1035 /* s[] */ #define RPMTAG_FILEFLAGS 1037 #define RPMTAG_FILEUSERNAME 1039 #define RPMTAG_FILEGROUPNAME 1040 #define RPMTAG_SOURCERPM 1044 #define RPMTAG_PROVIDENAME 1047 #define RPMTAG_REQUIREFLAGS 1048 /* i */ #define RPMTAG_REQUIRENAME 1049 /* s[] */ #define RPMTAG_REQUIREVERSION 1050 /* s[] */ #define RPMTAG_CONFLICTFLAGS 1053 /* i */ #define RPMTAG_CONFLICTNAME 1054 /* s[] */ #define RPMTAG_CONFLICTVERSION 1055 /* s[] */ // pre/post PROG strings contain something like /bin/sh #define RPMTAG_PREINPROG 1085 #define RPMTAG_POSTINPROG 1086 #define RPMTAG_PREFIXS 1098 #define RPMTAG_PROVIDEFLAGS 1112 #define RPMTAG_PROVIDEVERSION 1113 #define RPMTAG_DIRINDEXES 1116 #define RPMTAG_BASENAMES 1117 #define RPMTAG_DIRNAMES 1118 #define RPMFILE_CONFIG (1 << 0) #define RPMFILE_DOC (1 << 1) enum { RPMSENSE_ANY = 0, /*@-enummemuse@*/ RPMSENSE_SERIAL = (1 << 0), /*!< @todo Legacy. */ /*@=enummemuse@*/ RPMSENSE_LESS = (1 << 1), RPMSENSE_GREATER = (1 << 2), RPMSENSE_EQUAL = (1 << 3), RPMSENSE_PROVIDES = (1 << 4), /* only used internally by builds */ RPMSENSE_CONFLICTS = (1 << 5), /* only used internally by builds */ /* bit 6 used to be RPMSENSE_PREREQ */ #define RPMSENSE_PREREQ RPMSENSE_ANY RPMSENSE_OBSOLETES = (1 << 7), /* only used internally by builds */ RPMSENSE_INTERP = (1 << 8), /*!< Interpreter used by scriptlet. */ RPMSENSE_SCRIPT_PRE = ((1 << 9)|RPMSENSE_PREREQ), /*!< %pre dependency. */ RPMSENSE_SCRIPT_POST = ((1 << 10)|RPMSENSE_PREREQ), /*!< %post dependency. */ RPMSENSE_SCRIPT_PREUN = ((1 << 11)|RPMSENSE_PREREQ), /*!< %preun dependency. */ RPMSENSE_SCRIPT_POSTUN = ((1 << 12)|RPMSENSE_PREREQ), /*!< %postun dependency. */ RPMSENSE_SCRIPT_VERIFY = (1 << 13), /*!< %verify dependency. */ RPMSENSE_FIND_REQUIRES = (1 << 14), /*!< find-requires generated dependency. */ RPMSENSE_FIND_PROVIDES = (1 << 15), /*!< find-provides generated dependency. */ RPMSENSE_TRIGGERIN = (1 << 16), /*!< %triggerin dependency. */ RPMSENSE_TRIGGERUN = (1 << 17), /*!< %triggerun dependency. */ RPMSENSE_TRIGGERPOSTUN = (1 << 18), /*!< %triggerpostun dependency. */ RPMSENSE_MISSINGOK = (1 << 19), /*!< suggests/enhances hint. */ RPMSENSE_SCRIPT_PREP = (1 << 20), /*!< %prep build dependency. */ RPMSENSE_SCRIPT_BUILD = (1 << 21), /*!< %build build dependency. */ RPMSENSE_SCRIPT_INSTALL = (1 << 22),/*!< %install build dependency. */ RPMSENSE_SCRIPT_CLEAN = (1 << 23), /*!< %clean build dependency. */ RPMSENSE_RPMLIB = ((1 << 24) | RPMSENSE_PREREQ), /*!< rpmlib(feature) dependency. */ /*@-enummemuse@*/ RPMSENSE_TRIGGERPREIN = (1 << 25), /*!< @todo Implement %triggerprein. */ /*@=enummemuse@*/ RPMSENSE_KEYRING = (1 << 26), RPMSENSE_PATCHES = (1 << 27), RPMSENSE_CONFIG = (1 << 28) }; enum rpm_functions_e { rpm_query = 1, rpm_install = 2, rpm_query_info = 4, rpm_package = 8, rpm_query_list = 16, rpm_query_list_doc = 32, rpm_query_list_config = 64, rpm_update = 128, rpm_erase = 256, rpm_oldpackage = 512, rpm_force = 1024, rpm_query_verify = 2048, rpm_query_all = 4096, rpm_skip_uninstalled = 8192, rpm_update = 16384 }; typedef struct { uint32_t tag; /* 4 byte tag */ uint32_t type; /* 4 byte type */ uint32_t offset; /* 4 byte offset */ uint32_t count; /* 4 byte count */ } rpm_index; // one of these is instantiated for each RPM header that we parse // it contains all the parsing state information typedef struct { int m_fd; void * m_map; rpm_index **m_tags; int m_tagcount; int m_offset; int m_nUser; // int available for storing temp states with the object during interation callbacks } rpm_scan_state; void rpm_construct_scan_state(rpm_scan_state * prss) { prss->m_fd=-1; prss->m_tags=NULL; } void rpm_destruct_scan_state(rpm_scan_state * prss) { if(prss->m_fd!=-1) { close(prss->m_fd); prss->m_fd=-1; } if(prss->m_tags!=NULL) { free(prss->m_tags); prss->m_tags=NULL; } } int rpm_open_header(const char * szcFilepath, rpm_scan_state * prss); typedef struct { char m_szPackage[MAX_BASENAME_LENGTH+1]; int m_nFlags; char m_szVersion[MAX_VERSION_LENGTH+1]; } dependency; #define MAX_VERSION_ELEMENTS 6 static char * pszDatabaseDirpath=NULL, **pszArgv; static char szOriginalRootPath[]="/"; // the default root path static char *pszEffectiveRoot=szOriginalRootPath; // by default the effective root path is the original / one static int fdTemp=-1, optind_post_switches, nCopyArgc, nCountErrors=0; static char * szaRelationship[] = { "", "<", ">", "", "=", "<=", ">=", "" }; void extract_cpio_gz(int fd); rpm_index **rpm_gettags(int fd, int *num_tags); int bsearch_rpmtag(const void *key, const void *item); char *rpm_getstring(int tag, int itemindex, rpm_scan_state * pstate); int rpm_getint(int tag, int itemindex, rpm_scan_state * pstate); int rpm_getcount(int tag, rpm_scan_state *pstate); void exec_script(int progtag, int datatag, char *prefix); void fileaction_dobackup(char *filename, int fileref, rpm_scan_state * pstate); void fileaction_setowngrp(char *filename, int fileref, rpm_scan_state * pstate); void fileaction_list(char *filename, int itemno, rpm_scan_state * pstate); void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref, rpm_scan_state *pstate), rpm_scan_state * pstate); void fileaction_nuke(char *filename, int fileref, rpm_scan_state * pstate); void fileaction_nukedir(char *filename, int fileref, rpm_scan_state * pstate); void loop_through_database_files(void (*diraction)(struct dirent * pdirentry)); void diraction_list_packages(struct dirent * pdirentry); void fileaction_verify(char *filename, int fileref, rpm_scan_state * pstate); void diraction_verify_packages(struct dirent * pdirentry); void diraction_append_provides_to_file(struct dirent * pdirentry); void diraction_object_if_installed_file_dep_in_tempfile(struct dirent * pdirentry); #define RPM_STATE_DIR "/var/lib/rpm/" #define RPM_TEMPFILE_REQUIRES "/tmp/_requires" #define RPM_TEMPFILE_PROVIDES "/tmp/_provides" int rpm_compare_versions(const char * sz1, const char * sz2) { const char * psza[2] = { sz1, sz2 }; while(1) { int naElement[2]; unsigned char c; for(c=0;c<2;c++) { naElement[c]=atoi(psza[c]); while((*psza[c]!=':') && (*psza[c]!='.') && (*psza[c]!='-') && (*psza[c]!='\0')) psza[c]++; } if((*psza[0]==':') && (*psza[1]!=':')) return RPMSENSE_GREATER; // first has epoch, must be later if((*psza[0]!=':') && (*psza[1]==':')) return RPMSENSE_LESS; // only second has epoch, must be later if(naElement[0]naElement[1]) return RPMSENSE_GREATER; // equal - go on looking if((*psza[0]=='\0') && (*psza[1]=='\0')) return RPMSENSE_EQUAL; // end of the road on both, must be equal to get this far if((*psza[0]=='\0') && (*psza[1]!='\0')) return RPMSENSE_LESS; // first ran out but second has more if((*psza[0]!='\0') && (*psza[1]=='\0')) return RPMSENSE_GREATER; // second ran out but first has more psza[0]++; psza[1]++; } return 0; } int rpm_open_header(const char * szcFilepath, rpm_scan_state * prss) { prss->m_fd = open(szcFilepath, O_RDONLY); if(prss->m_fd!=-1) { prss->m_tags = rpm_gettags(prss->m_fd, (int *) &prss->m_tagcount); prss->m_offset = lseek(prss->m_fd, 0, SEEK_CUR); if (!prss->m_tags) { printf("Error reading rpm header\n"); exit(-1); } prss->m_map = mmap(0, prss->m_offset > getpagesize() ? (prss->m_offset + prss->m_offset % getpagesize()) : getpagesize(), PROT_READ, MAP_SHARED, prss->m_fd, 0); // Mimimum is one page return 0; } return 1; } void DumpProvides(rpm_scan_state * prss) { int it=0, count = rpm_getcount(RPMTAG_PROVIDENAME, prss); for (; it < count; it++) { dependency dep; strcpy(&dep.m_szPackage[0], rpm_getstring(RPMTAG_PROVIDENAME, it, prss)); dep.m_nFlags=rpm_getint(RPMTAG_PROVIDEFLAGS, it, prss); if(! ( dep.m_nFlags & RPMSENSE_MISSINGOK) ) { strcpy(dep.m_szVersion, rpm_getstring(RPMTAG_PROVIDEVERSION, it, prss)); } write(fdTemp, &dep, sizeof(dep)); // printf("prov %s %s\n", dep.m_szPackage, dep.m_szVersion); } } void PrintDependency(dependency * pdep) { if((pdep->m_nFlags & (RPMSENSE_LESS | RPMSENSE_GREATER | RPMSENSE_EQUAL)) ==0) { printf("%s", pdep->m_szPackage); } else { printf("%s %s %s", pdep->m_szPackage, szaRelationship[(pdep->m_nFlags & (RPMSENSE_LESS | RPMSENSE_GREATER | RPMSENSE_EQUAL))>>1], pdep->m_szVersion); } } int rpm_main(int argc, char **argv) { int opt = 0, func = 0, nPasses=1, nPass=0; char * pszDatabaseFilepath=NULL, * pszProvides=NULL; rpm_scan_state rss_rpm, rss_lib; rpm_construct_scan_state(&rss_rpm); rpm_construct_scan_state(&rss_lib); pszArgv=argv; nCopyArgc=argc; while ((opt = getopt(argc, argv, "iqpldcr:eofvua")) != -1) { switch (opt) { case 'i': // INSTALL package(s), reject if already installed func |= rpm_install | rpm_package; break; case 'u': // UPDATE will allow preinstalled package to be overwritten with newer func |= rpm_update | rpm_package; break; case 'F': // FRESHEN: like Update, but will skip packages not already installed func |= rpm_erase | rpm_install | rpm_package | rpm_skip_uninstalled; break; case 'e': // ERASE package - always querying database func |= rpm_erase; break; case 'q': // Query mode if (!(func & (rpm_erase | rpm_install))) func |= rpm_query; //else bb_show_usage(); break; case 'p': // Query a package (otherwise we query database) func |= rpm_package; break; case 'l': // List files in a package func |= rpm_query_list; break; case 'f': // Force install, overriding requires func |= rpm_force; break; case 'd': // List doc files in a package (implies list) func |= rpm_query_list | rpm_query_list_doc; break; case 'c': // List config files in a package (implies list) func |= rpm_query_list | rpm_query_list_config; break; case 'v': // Verify MD5s against installed header func |= rpm_query_verify | rpm_query; break; case 'a': // Modify queries to apply to all installed packages func |= rpm_query_all; break; case 'r': // Set effective root for file operations pszEffectiveRoot=optarg; // change the effective root to point to the commandline arg in place // printf("Using effective root: %s\n", pszEffectiveRoot); break; case 'o': // oldpackage, allow update of older package over newer already installed func |=rpm_oldpackage; break; default: bb_show_usage(); } } // create database dir (no other init needed) if it is not present already pszDatabaseDirpath=xmalloc(strlen(pszEffectiveRoot) + 4 +1); strcpy(pszDatabaseDirpath, pszEffectiveRoot); strcat(pszDatabaseDirpath, "/tmp"); bb_make_directory(pszDatabaseDirpath, 0744, FILEUTILS_RECUR); // ignore error, we expect it to exist already normally free(pszDatabaseDirpath); pszDatabaseDirpath=xmalloc(strlen(pszEffectiveRoot) + strlen(RPM_STATE_DIR)+1); strcpy(pszDatabaseDirpath, pszEffectiveRoot); strcat(pszDatabaseDirpath, RPM_STATE_DIR); bb_make_directory(pszDatabaseDirpath, 0744, FILEUTILS_RECUR); // ignore error, we expect it to exist already normally if (((func & (rpm_query|rpm_query_verify|rpm_package|rpm_query_list)) == rpm_query) && (optind == argc) ) { loop_through_database_files(diraction_list_packages); } if ((func & (rpm_query|rpm_query_verify|rpm_query_all|rpm_query_list)) == (rpm_query|rpm_query_verify|rpm_query_all)) { loop_through_database_files(diraction_verify_packages); } optind_post_switches=optind; while (nPassm_nUser=0; loop_through_files(RPMTAG_BASENAMES, fileaction_verify, prssActive); } if (func & (rpm_install | rpm_erase | rpm_update)) { unsigned int offsetKeep, nLen=rss_rpm.m_offset; int fdDatabase; nPasses=4; switch (nPass) { case 0: // install: collect provides from given and installed packages; erase: collect provides only from given packages // confirm we don't have this package installed already if (func & rpm_install) { fdDatabase = open(pszDatabaseFilepath, O_RDONLY); if(fdDatabase != -1) { // for install, the package must not already be installed puts(rpm_getstring(RPMTAG_NAME, 0, &rss_lib)); bb_error_msg_and_die("Package already installed"); } } if(fdTemp==-1) { pszProvides=xmalloc(strlen(pszEffectiveRoot) + strlen(RPM_STATE_DIR) + strlen(RPM_TEMPFILE_REQUIRES)+1); strcpy(pszProvides, pszEffectiveRoot); strcat(pszProvides, RPM_TEMPFILE_PROVIDES ); fdTemp=open(pszProvides, O_RDWR|O_CREAT|O_TRUNC); // if install, start the provides list off with provides from all installed packages if(func & rpm_install) loop_through_database_files(diraction_append_provides_to_file); } DumpProvides(prssActive); break; case 1: // look at the provides situation - // install: do all the new packages' requires appear in the temp file? // erase: does any other package require anything listed in the temp file? if (func & (rpm_install|rpm_update)) { // fdTemp file now has all provides, including those supposedly being installed // confirm that all the new guys' *requires* appear in that file somewhere int it=0, count = rpm_getcount(RPMTAG_REQUIRENAME, &rss_rpm); for (; it < count; it++) { char *sz=rpm_getstring(RPMTAG_REQUIRENAME, it, &rss_rpm); int nFlags=rpm_getint(RPMTAG_REQUIREFLAGS, it, &rss_rpm); char *szVersion=rpm_getstring(RPMTAG_REQUIREVERSION, it, &rss_rpm); char fSeen=0; dependency dep; if(sz[0]!='/') { // file deps not supported (can't afford the database) if(!(nFlags & RPMSENSE_RPMLIB)) { // ignore RPM capability requires if(nFlags & (RPMSENSE_LESS | RPMSENSE_GREATER | RPMSENSE_EQUAL)) { // there is a comparison required! lseek(fdTemp, 0, SEEK_SET); // move to start of provides list while((read(fdTemp, &dep, sizeof(dep))!=0) && (!fSeen)) { if(strcmp(dep.m_szPackage, sz)==0) { // match on package name, now check compliance with version needs if(nFlags & rpm_compare_versions(dep.m_szVersion, szVersion)) { // printf("good version seen: %s vs dep %s\n", szVersion, dep.m_szVersion); fSeen=1; } else { // printf("bad version seen: %s vs dep %s\n", szVersion, dep.m_szVersion); } } } if(!fSeen) { // this then is a requirement from a new package not satisfied by any provides printf("Package %s requires %s", argv[optind], sz); if(nFlags & (RPMSENSE_LESS | RPMSENSE_GREATER | RPMSENSE_EQUAL)) { printf("%s %s", szaRelationship[(nFlags & (RPMSENSE_LESS | RPMSENSE_GREATER | RPMSENSE_EQUAL))>>1], szVersion); } printf(" (0x%x)\n", nFlags); nCountErrors++; } } } } else { printf("Warning, %s file dep %s ignored, unsupported\n", argv[optind], sz); } } } else { optind = argc; // just do this step once loop_through_database_files(diraction_object_if_installed_file_dep_in_tempfile); } break; case 2: // install / erase action if((!nCountErrors) || (func&rpm_force)) { // take no action if there were unsatisfied requires if (func & (rpm_erase | rpm_update)) { // kill existing package if in database; update will fall through to install loop_through_files(RPMTAG_BASENAMES, fileaction_nuke, &rss_lib); // Destroy installed fileset, using Effective Root loop_through_files(RPMTAG_BASENAMES, fileaction_nukedir, &rss_lib); // Try to remove all dirs, now they might be empty // remove the database entry for this now deleted package // printf("Package %s is removed\n", rpm_getstring(RPMTAG_NAME, 0, &rss_lib)); close(rss_lib.m_fd); unlink(pszDatabaseFilepath); // remove the header from the database } if(func & (rpm_install | rpm_update)) { unsigned char baBuffer[64]; // perform install/update action loop_through_files(RPMTAG_BASENAMES, fileaction_dobackup, &rss_rpm); // Backup any config files, using Effective Root extract_cpio_gz(rss_rpm.m_fd); // Extact the archive to effective root loop_through_files(RPMTAG_BASENAMES, fileaction_setowngrp, &rss_rpm); /* Set the correct file uid/gid's, using Effective Root */ // copy the RPM header (only) en bloc into a "database" file named after the package name fdDatabase = bb_xopen(pszDatabaseFilepath, O_WRONLY| O_CREAT | O_EXCL); offsetKeep = lseek(rss_rpm.m_fd, 0, SEEK_CUR); lseek(rss_rpm.m_fd, 0, SEEK_SET); // move to start of RPM while (nLen) { // copy the header portion unsigned int nDo=sizeof(baBuffer); if(nLenseek = seek_by_char; //archive_handle->action_header = header_list; archive_handle->action_data = data_extract_all; archive_handle->flags |= ARCHIVE_PRESERVE_DATE | ARCHIVE_CREATE_LEADING_DIRS | ARCHIVE_EXTRACT_UNCONDITIONAL; archive_handle->src_fd = fd; archive_handle->offset = 0; bb_xread_all(archive_handle->src_fd, &magic, 2); if ((magic[0] != 0x1f) || (magic[1] != 0x8b)) { bb_error_msg_and_die("Invalid gzip magic"); } check_header_gzip(archive_handle->src_fd); if(chdir(pszEffectiveRoot)) { // Install RPM's to effective root bb_error_msg_and_die("failed to chdir to effective root"); } archive_handle->src_fd = open_transformer(archive_handle->src_fd, inflate_gunzip); archive_handle->offset = 0; while (get_header_cpio(archive_handle) == EXIT_SUCCESS); } rpm_index **rpm_gettags(int fd, int *num_tags) { rpm_index **tags = calloc(200, sizeof(struct rpmtag *)); /* We should never need mode than 200, and realloc later */ int pass, tagindex = 0; lseek(fd, 96, SEEK_CUR); /* Seek past the unused lead */ for (pass = 0; pass < 2; pass++) { /* 1st pass is the signature headers, 2nd is the main stuff */ struct { char magic[3]; /* 3 byte magic: 0x8e 0xad 0xe8 */ uint8_t version; /* 1 byte version number */ uint32_t reserved; /* 4 bytes reserved */ uint32_t entries; /* Number of entries in header (4 bytes) */ uint32_t size; /* Size of store (4 bytes) */ } header; rpm_index *tmpindex; int storepos; read(fd, &header, sizeof(header)); if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC, 3) != 0) return NULL; /* Invalid magic */ if (header.version != 1) return NULL; /* This program only supports v1 headers */ header.size = ntohl(header.size); header.entries = ntohl(header.entries); storepos = lseek(fd,0,SEEK_CUR) + header.entries * 16; while (header.entries--) { tmpindex = tags[tagindex++] = malloc(sizeof(rpm_index)); read(fd, tmpindex, sizeof(rpm_index)); tmpindex->tag = ntohl(tmpindex->tag); tmpindex->type = ntohl(tmpindex->type); tmpindex->count = ntohl(tmpindex->count); tmpindex->offset = storepos + ntohl(tmpindex->offset); if (pass==0) tmpindex->tag -= 743; } lseek(fd, header.size, SEEK_CUR); /* Seek past store */ if (pass==0) lseek(fd, (8 - (lseek(fd,0,SEEK_CUR) % 8)) % 8, SEEK_CUR); /* Skip padding to 8 byte boundary after reading signature headers */ } tags = realloc(tags, tagindex * sizeof(struct rpmtag *)); /* realloc tags to save space */ *num_tags = tagindex; return tags; /* All done, leave the file at the start of the gzipped cpio archive */ } int bsearch_rpmtag(const void *key, const void *item) { rpm_index **tmp = (rpm_index **) item; return ((int) key - tmp[0]->tag); } // returns how many entries of a particular array tag type are present int rpm_getcount(int tag, rpm_scan_state * pstate) { rpm_index **found; found = bsearch((void *) tag, pstate->m_tags, pstate->m_tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); if (!found) return 0; else return found[0]->count; } char *rpm_getstring(int tag, int itemindex, rpm_scan_state * pstate) { rpm_index **found; found = bsearch((void *) tag, pstate->m_tags, pstate->m_tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); if (!found || itemindex >= found[0]->count) return NULL; if (found[0]->type == RPM_STRING_TYPE || found[0]->type == RPM_I18NSTRING_TYPE || found[0]->type == RPM_STRING_ARRAY_TYPE) { int n; char *tmpstr = (char *) (pstate->m_map + found[0]->offset); for (n=0; n < itemindex; n++) tmpstr = tmpstr + strlen(tmpstr) + 1; return tmpstr; } else return NULL; } int rpm_getint(int tag, int itemindex, rpm_scan_state * pstate) { rpm_index **found; int n, *tmpint; found = bsearch((void *) tag, pstate->m_tags, pstate->m_tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); if (!found || itemindex >= found[0]->count) return -1; tmpint = (int *) (pstate->m_map + found[0]->offset); if (found[0]->type == RPM_INT32_TYPE) { for (n=0; ntype == RPM_INT16_TYPE) { for (n=0; ntype == RPM_INT8_TYPE) { for (n=0; nm_nUser++; break; case 2: case 3: case 4: printf(" DELETED %s\n", filename); pstate->m_nUser++; break; default: break; } } void fileaction_setowngrp(char *filename, int fileref, rpm_scan_state * pstate) { int uid, gid; uid = my_getpwnam(rpm_getstring(RPMTAG_FILEUSERNAME, fileref, pstate)); gid = my_getgrnam(rpm_getstring(RPMTAG_FILEGROUPNAME, fileref, pstate)); chown (filename, uid, gid); } void fileaction_list(char *filename, int fileref, rpm_scan_state * pstate) { printf("%s\n", filename); } void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref, rpm_scan_state * pstate), rpm_scan_state * pstate) { int count = 0; char *filename, *tmp_dirname, *tmp_basename; while (rpm_getstring(filetag, count, pstate)) { tmp_dirname = rpm_getstring(RPMTAG_DIRNAMES, rpm_getint(RPMTAG_DIRINDEXES, count, pstate), pstate); /* 1st put on the directory */ tmp_basename = rpm_getstring(RPMTAG_BASENAMES, count, pstate); filename = xmalloc(strlen(pszEffectiveRoot) + strlen(tmp_basename) + strlen(tmp_dirname) + 1); strcpy(filename, pszEffectiveRoot); // first the effective root dir strcat(filename, tmp_dirname); // then the directory name strcat(filename, tmp_basename); // then the filename fileaction(filename, count++, pstate); free(filename); } } void diraction_list_packages(struct dirent * pdirentry) { rpm_scan_state rss; char * pszFilename; rpm_construct_scan_state(&rss); pszFilename = xmalloc(strlen(pszDatabaseDirpath) + strlen(pdirentry->d_name) + 2); strcpy(pszFilename, pszDatabaseDirpath); // first the effective root dir strcat(pszFilename, pdirentry->d_name); // then the directory name rpm_open_header(pszFilename, &rss); printf("%s-%s-%s\n", pdirentry->d_name, rpm_getstring(RPMTAG_VERSION, 0, &rss), rpm_getstring(RPMTAG_RELEASE, 0, &rss)); free(pszFilename); rpm_destruct_scan_state(&rss); } void diraction_verify_packages(struct dirent * pdirentry) { rpm_scan_state rss; char * pszFilename; rpm_construct_scan_state(&rss); pszFilename = xmalloc(strlen(pszDatabaseDirpath) + strlen(pdirentry->d_name) + 2); strcpy(pszFilename, pszDatabaseDirpath); // first the effective root dir strcat(pszFilename, pdirentry->d_name); // then the directory name rpm_open_header(pszFilename, &rss); rpm_getstring(RPMTAG_RELEASE, 0, &rss); rss.m_nUser=0; loop_through_files(RPMTAG_BASENAMES, fileaction_verify, &rss); free(pszFilename); rpm_destruct_scan_state(&rss); } void diraction_append_provides_to_file(struct dirent * pdirentry) { rpm_scan_state rss; char * pszFilename; rpm_construct_scan_state(&rss); pszFilename = xmalloc(strlen(pszDatabaseDirpath) + strlen(pdirentry->d_name) + 2); strcpy(pszFilename, pszDatabaseDirpath); // first the effective root dir strcat(pszFilename, pdirentry->d_name); // then the directory name rpm_open_header(pszFilename, &rss); DumpProvides(&rss); free(pszFilename); rpm_destruct_scan_state(&rss); } void diraction_object_if_installed_file_dep_in_tempfile(struct dirent * pdirentry) { rpm_scan_state rss; char * pszFilename, *szName; int n; char fSeen=0; rpm_construct_scan_state(&rss); pszFilename = xmalloc(strlen(pszDatabaseDirpath) + strlen(pdirentry->d_name) + 2); strcpy(pszFilename, pszDatabaseDirpath); // first the effective root dir strcat(pszFilename, pdirentry->d_name); // then the directory name rpm_open_header(pszFilename, &rss); szName=rpm_getstring(RPMTAG_NAME, 0, &rss); n=optind_post_switches; while (nd_name[0]!='.') diraction(pdirentry); } } } }