rpm applet by Laurence Anderson
authorGlenn L McGrath <bug1@ihug.co.nz>
Tue, 10 Dec 2002 00:17:22 +0000 (00:17 -0000)
committerGlenn L McGrath <bug1@ihug.co.nz>
Tue, 10 Dec 2002 00:17:22 +0000 (00:17 -0000)
AUTHORS
archival/Config.in
archival/Makefile.in
archival/cpio.c
archival/libunarchive/Makefile.in
archival/libunarchive/data_extract_all.c
archival/libunarchive/get_header_cpio.c [new file with mode: 0644]
archival/rpm.c [new file with mode: 0644]
include/applets.h
include/unarchive.h
include/usage.h

diff --git a/AUTHORS b/AUTHORS
index 7ec7d49..812807a 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -16,7 +16,7 @@ Erik Andersen <andersen@codepoet.org>, <andersee@debian.org>
     core apps, tons of new apps as noted in header files.
 
 Laurence Anderson <l.d.anderson@warwick.ac.uk>
-    rpm2cpio, unzip, get_header_cpio, read_gz interface
+    rpm2cpio, unzip, get_header_cpio, read_gz interface, rpm
 
 Edward Betts <edward@debian.org>
     expr, hostid, logname, tty, wc, whoami, yes
index bbd3fa0..affde32 100644 (file)
@@ -139,7 +139,13 @@ config CONFIG_RPM2CPIO
        bool "rpm2cpio"
        default n
        help
-         Please submit a patch to add help text for this item.
+         Converts an RPM file into a CPIO archive.
+
+config CONFIG_RPM
+       bool "rpm"
+       default n
+       help
+         Mini RPM applet - querys and extracts
 
 config CONFIG_TAR
        bool "tar"
index 226cde6..38f5e62 100644 (file)
@@ -32,6 +32,7 @@ ARCHIVAL-$(CONFIG_DPKG_DEB)   += dpkg_deb.o
 ARCHIVAL-$(CONFIG_GUNZIP)      += gunzip.o
 ARCHIVAL-$(CONFIG_GZIP)                += gzip.o
 ARCHIVAL-$(CONFIG_RPM2CPIO)    += rpm2cpio.o
+ARCHIVAL-$(CONFIG_RPM)         += rpm.o
 ARCHIVAL-$(CONFIG_TAR)         += tar.o
 ARCHIVAL-$(CONFIG_UNCOMPRESS)  += uncompress.o
 ARCHIVAL-$(CONFIG_UNZIP)       += unzip.o
index 8b4cc2d..49f3f88 100644 (file)
 #include "unarchive.h"
 #include "busybox.h"
 
-typedef struct hardlinks_s {
-       file_header_t *entry;
-       int inode;
-       struct hardlinks_s *next;
-} hardlinks_t;
-
 extern int cpio_main(int argc, char **argv)
 {
        archive_handle_t *archive_handle;
@@ -83,159 +77,7 @@ extern int cpio_main(int argc, char **argv)
                optind++;
        }
 
-       while (1) {
-               static hardlinks_t *saved_hardlinks = NULL;
-               static unsigned short pending_hardlinks = 0;
-               file_header_t *file_header = archive_handle->file_header;
-               char cpio_header[110];
-               int namesize;
-               char dummy[16];
-               int major, minor, nlink, inode;
-               char extract_flag;
-
-               if (pending_hardlinks) { /* Deal with any pending hardlinks */
-                       hardlinks_t *tmp;
-                       hardlinks_t *oldtmp;
-
-                       tmp = saved_hardlinks;
-                       oldtmp = NULL;
-
-                       while (tmp) {
-                               error_msg_and_die("need to fix this\n");
-                               if (tmp->entry->link_name) { /* Found a hardlink ready to be extracted */
-                                       file_header = tmp->entry;
-                                       if (oldtmp) {
-                                               oldtmp->next = tmp->next; /* Remove item from linked list */
-                                       } else {
-                                               saved_hardlinks = tmp->next;
-                                       }
-                                       free(tmp);
-                                       continue;
-                               }
-                               oldtmp = tmp;
-                               tmp = tmp->next;
-                       }
-                       pending_hardlinks = 0; /* No more pending hardlinks, read next file entry */
-               }
-
-               /* There can be padding before archive header */
-               data_align(archive_handle, 4);
-
-               if (archive_xread_all_eof(archive_handle, cpio_header, 110) == 0) {
-                       return(EXIT_FAILURE);
-               }
-               archive_handle->offset += 110;
-
-               if (strncmp(&cpio_header[0], "07070", 5) != 0) {
-                       printf("cpio header is %x-%x-%x-%x-%x\n",
-                               cpio_header[0],
-                               cpio_header[1],
-                               cpio_header[2],
-                               cpio_header[3],
-                               cpio_header[4]);
-                       error_msg_and_die("Unsupported cpio format");
-               }
-               
-               if ((cpio_header[5] != '1') && (cpio_header[5] != '2')) {
-                       error_msg_and_die("Unsupported cpio format, use newc or crc");
-               }
-
-               sscanf(cpio_header, "%6c%8x%8x%8x%8x%8x%8lx%8lx%16c%8x%8x%8x%8c",
-                       dummy, &inode, (unsigned int*)&file_header->mode, 
-                       (unsigned int*)&file_header->uid, (unsigned int*)&file_header->gid,
-                       &nlink, &file_header->mtime, &file_header->size,
-                       dummy, &major, &minor, &namesize, dummy);
-
-               file_header->name = (char *) xmalloc(namesize + 1);
-               archive_xread_all(archive_handle, file_header->name, namesize); /* Read in filename */
-               file_header->name[namesize] = '\0';
-               archive_handle->offset += namesize;
-
-               /* Update offset amount and skip padding before file contents */
-               data_align(archive_handle, 4);
-
-               if (strcmp(file_header->name, "TRAILER!!!") == 0) {
-                       printf("%d blocks\n", (int) (archive_handle->offset % 512 ? (archive_handle->offset / 512) + 1 : archive_handle->offset / 512)); /* Always round up */
-                       if (saved_hardlinks) { /* Bummer - we still have unresolved hardlinks */
-                               hardlinks_t *tmp = saved_hardlinks;
-                               hardlinks_t *oldtmp = NULL;
-                               while (tmp) {
-                                       error_msg("%s not created: cannot resolve hardlink", tmp->entry->name);
-                                       oldtmp = tmp;
-                                       tmp = tmp->next;
-                                       free (oldtmp->entry->name);
-                                       free (oldtmp->entry);
-                                       free (oldtmp);
-                               }
-                               saved_hardlinks = NULL;
-                               pending_hardlinks = 0;
-       }
-                       return(EXIT_FAILURE);
-               }
-
-               if (S_ISLNK(file_header->mode)) {
-                       file_header->link_name = (char *) xmalloc(file_header->size + 1);
-                       archive_xread_all(archive_handle, file_header->link_name, file_header->size);
-                       file_header->link_name[file_header->size] = '\0';
-                       archive_handle->offset += file_header->size;
-                       file_header->size = 0; /* Stop possible seeks in future */
-               }
-               if (nlink > 1 && !S_ISDIR(file_header->mode)) {
-                       if (file_header->size == 0) { /* Put file on a linked list for later */
-                               hardlinks_t *new = xmalloc(sizeof(hardlinks_t));
-                               new->next = saved_hardlinks;
-                               new->inode = inode;
-                               new->entry = file_header;
-                               saved_hardlinks = new;
-                               continue;
-                       } else { /* Found the file with data in */
-                               hardlinks_t *tmp = saved_hardlinks;
-                               pending_hardlinks = 1;
-                               while (tmp) {
-                                       if (tmp->inode == inode) {
-                                               tmp->entry->link_name = xstrdup(file_header->name);
-                                               nlink--;
-                                       }
-                                       tmp = tmp->next;
-                               }
-                               if (nlink > 1) {
-                                       error_msg("error resolving hardlink: did you create the archive with GNU cpio 2.0-2.2?");
-                               }
-                       }
-               }
-               file_header->device = (major << 8) | minor;
-
-               extract_flag = FALSE;
-               if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
-                       struct stat statbuf;
-
-                       extract_flag = TRUE;
-
-                       /* Check if the file already exists */
-                       if (lstat (file_header->name, &statbuf) == 0) {
-                               if ((archive_handle->flags & ARCHIVE_EXTRACT_UNCONDITIONAL) || (statbuf.st_mtime < file_header->mtime)) {
-                                       /* Remove file if flag set or its older than the file to be extracted */
-                                       if (unlink(file_header->name) == -1) {
-                                               perror_msg_and_die("Couldnt remove old file");
-                                       }
-                               } else {
-                                       if (! archive_handle->flags & ARCHIVE_EXTRACT_QUIET) {
-                                               error_msg("%s not created: newer or same age file exists", file_header->name);
-                                       }
-                                       extract_flag = FALSE;
-                               }
-                       }
-                       archive_handle->action_header(file_header);
-               }
-
-               archive_handle->action_header(file_header);
-               if (extract_flag) {
-                       archive_handle->action_data(archive_handle);
-               } else {
-                       data_skip(archive_handle);
-               }
-               archive_handle->offset += file_header->size;
-       }
+       while (get_header_cpio(archive_handle) == EXIT_SUCCESS);
 
        return(EXIT_SUCCESS);
 }
index 28e2955..b590486 100644 (file)
@@ -35,6 +35,7 @@ LIBUNARCHIVE-y:= \
        filter_accept_reject_list.o \
 \
        get_header_ar.o \
+       get_header_cpio.o \
        get_header_tar.o \
        get_header_tar_bz2.o \
        get_header_tar_gz.o \
index 7ab87e7..9c4510e 100644 (file)
@@ -43,7 +43,7 @@ extern void data_extract_all(archive_handle_t *archive_handle)
        switch(file_header->mode & S_IFMT) {
                case S_IFREG: {
 #ifdef CONFIG_CPIO
-                       if (file_header->link_name) {
+                       if (file_header->link_name && file_header->size == 0) {
                                /* hard link */
                                res = link(file_header->link_name, file_header->name);
                                if ((res == -1) && !(archive_handle->flags & ARCHIVE_EXTRACT_QUIET)) {
diff --git a/archival/libunarchive/get_header_cpio.c b/archival/libunarchive/get_header_cpio.c
new file mode 100644 (file)
index 0000000..87e9715
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ *  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 Library 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "unarchive.h"
+#include "libbb.h"
+
+typedef struct hardlinks_s {
+       file_header_t *entry;
+       int inode;
+       struct hardlinks_s *next;
+} hardlinks_t;
+
+extern char get_header_cpio(archive_handle_t *archive_handle)
+{
+       static hardlinks_t *saved_hardlinks = NULL;
+       static unsigned short pending_hardlinks = 0;
+       file_header_t *file_header = archive_handle->file_header;
+       char cpio_header[110];
+       int namesize;
+       char dummy[16];
+       int major, minor, nlink, inode;
+       char extract_flag;
+       
+       if (pending_hardlinks) { /* Deal with any pending hardlinks */
+               hardlinks_t *tmp;
+               hardlinks_t *oldtmp;
+
+               tmp = saved_hardlinks;
+               oldtmp = NULL;
+
+               while (tmp) {
+                       error_msg_and_die("need to fix this\n");
+                       if (tmp->entry->link_name) { /* Found a hardlink ready to be extracted */
+                               file_header = tmp->entry;
+                               if (oldtmp) {
+                                       oldtmp->next = tmp->next; /* Remove item from linked list */
+                               } else {
+                                       saved_hardlinks = tmp->next;
+                               }
+                               free(tmp);
+                               continue;
+                       }
+                       oldtmp = tmp;
+                       tmp = tmp->next;
+               }
+               pending_hardlinks = 0; /* No more pending hardlinks, read next file entry */
+       }
+
+       /* There can be padding before archive header */
+       data_align(archive_handle, 4);
+
+       if (archive_xread_all_eof(archive_handle, cpio_header, 110) == 0) {
+               return(EXIT_FAILURE);
+       }
+       archive_handle->offset += 110;
+
+       if (strncmp(&cpio_header[0], "07070", 5) != 0) {
+               printf("cpio header is %x-%x-%x-%x-%x\n",
+                       cpio_header[0],
+                       cpio_header[1],
+                       cpio_header[2],
+                       cpio_header[3],
+                       cpio_header[4]);
+               error_msg_and_die("Unsupported cpio format");
+       }
+               
+       if ((cpio_header[5] != '1') && (cpio_header[5] != '2')) {
+               error_msg_and_die("Unsupported cpio format, use newc or crc");
+       }
+
+       sscanf(cpio_header, "%6c%8x%8x%8x%8x%8x%8lx%8lx%16c%8x%8x%8x%8c",
+               dummy, &inode, (unsigned int*)&file_header->mode, 
+               (unsigned int*)&file_header->uid, (unsigned int*)&file_header->gid,
+               &nlink, &file_header->mtime, &file_header->size,
+               dummy, &major, &minor, &namesize, dummy);
+
+       file_header->name = (char *) xmalloc(namesize + 1);
+       archive_xread_all(archive_handle, file_header->name, namesize); /* Read in filename */
+       file_header->name[namesize] = '\0';
+       archive_handle->offset += namesize;
+
+       /* Update offset amount and skip padding before file contents */
+       data_align(archive_handle, 4);
+
+       if (strcmp(file_header->name, "TRAILER!!!") == 0) {
+               printf("%d blocks\n", (int) (archive_handle->offset % 512 ? (archive_handle->offset / 512) + 1 : archive_handle->offset / 512)); /* Always round up */
+               if (saved_hardlinks) { /* Bummer - we still have unresolved hardlinks */
+                       hardlinks_t *tmp = saved_hardlinks;
+                       hardlinks_t *oldtmp = NULL;
+                       while (tmp) {
+                               error_msg("%s not created: cannot resolve hardlink", tmp->entry->name);
+                               oldtmp = tmp;
+                               tmp = tmp->next;
+                               free (oldtmp->entry->name);
+                               free (oldtmp->entry);
+                               free (oldtmp);
+                       }
+                       saved_hardlinks = NULL;
+                       pending_hardlinks = 0;
+               }
+               return(EXIT_FAILURE);
+       }
+
+       if (S_ISLNK(file_header->mode)) {
+               file_header->link_name = (char *) xmalloc(file_header->size + 1);
+               archive_xread_all(archive_handle, file_header->link_name, file_header->size);
+               file_header->link_name[file_header->size] = '\0';
+               archive_handle->offset += file_header->size;
+               file_header->size = 0; /* Stop possible seeks in future */
+       }
+       if (nlink > 1 && !S_ISDIR(file_header->mode)) {
+               if (file_header->size == 0) { /* Put file on a linked list for later */
+                       hardlinks_t *new = xmalloc(sizeof(hardlinks_t));
+                       new->next = saved_hardlinks;
+                       new->inode = inode;
+                       new->entry = file_header;
+                       saved_hardlinks = new;
+                       return(EXIT_SUCCESS); // Skip this one
+               } else { /* Found the file with data in */
+                       hardlinks_t *tmp = saved_hardlinks;
+                       pending_hardlinks = 1;
+                       while (tmp) {
+                               if (tmp->inode == inode) {
+                                       tmp->entry->link_name = xstrdup(file_header->name);
+                                       nlink--;
+                               }
+                               tmp = tmp->next;
+                       }
+                       if (nlink > 1) {
+                               error_msg("error resolving hardlink: did you create the archive with GNU cpio 2.0-2.2?");
+                       }
+               }
+       }
+       file_header->device = (major << 8) | minor;
+
+       extract_flag = FALSE;
+       if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
+               struct stat statbuf;
+
+               extract_flag = TRUE;
+
+               /* Check if the file already exists */
+               if (lstat (file_header->name, &statbuf) == 0) {
+                       if ((archive_handle->flags & ARCHIVE_EXTRACT_UNCONDITIONAL) || (statbuf.st_mtime < file_header->mtime)) {
+                               /* Remove file if flag set or its older than the file to be extracted */
+                               if (unlink(file_header->name) == -1) {
+                                       perror_msg_and_die("Couldnt remove old file");
+                               }
+                       } else {
+                               if (! archive_handle->flags & ARCHIVE_EXTRACT_QUIET) {
+                                       error_msg("%s not created: newer or same age file exists", file_header->name);
+                               }
+                               extract_flag = FALSE;
+                       }
+               }
+               archive_handle->action_header(file_header);
+       }
+
+       archive_handle->action_header(file_header);
+       if (extract_flag) {
+               archive_handle->action_data(archive_handle);
+       } else {
+               data_skip(archive_handle);
+       }
+       archive_handle->offset += file_header->size;
+       return (EXIT_SUCCESS);
+}
+
diff --git a/archival/rpm.c b/archival/rpm.c
new file mode 100644 (file)
index 0000000..ee5087f
--- /dev/null
@@ -0,0 +1,351 @@
+/* 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 "busybox.h"
+#include "unarchive.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <netinet/in.h> /* For ntohl & htonl function */
+#include <string.h> /* For strncmp */
+#include <sys/mman.h> /* For mmap */
+#include <time.h> /* For ctime */
+
+#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_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
+#define        RPMTAG_PREIN                    1023
+#define        RPMTAG_POSTIN                   1024
+#define        RPMTAG_FILEFLAGS                1037
+#define        RPMTAG_FILEUSERNAME             1039
+#define        RPMTAG_FILEGROUPNAME            1040
+#define        RPMTAG_SOURCERPM                1044
+#define        RPMTAG_PREINPROG                1085
+#define        RPMTAG_POSTINPROG               1086
+#define        RPMTAG_PREFIXS                  1098
+#define        RPMTAG_DIRINDEXES               1116
+#define        RPMTAG_BASENAMES                1117
+#define        RPMTAG_DIRNAMES                 1118
+#define        RPMFILE_CONFIG                  (1 << 0)
+#define        RPMFILE_DOC                     (1 << 1)
+
+enum rpm_functions_e {
+       rpm_query = 1,
+       rpm_install = 2,
+       rpm_query_info = 4,
+       rpm_query_package = 8,
+       rpm_query_list = 16,
+       rpm_query_list_doc = 32,
+       rpm_query_list_config = 64
+};
+
+typedef struct {
+       u_int32_t tag; /* 4 byte tag */
+       u_int32_t type; /* 4 byte type */
+       u_int32_t offset; /* 4 byte offset */
+       u_int32_t count; /* 4 byte count */
+} rpm_index;
+
+static void *map;
+static rpm_index **mytags;
+static int tagcount;
+
+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);
+int rpm_getint(int tag, int itemindex);
+int rpm_getcount(int tag);
+void exec_script(int progtag, int datatag, char *prefix);
+void fileaction_dobackup(char *filename, int fileref);
+void fileaction_setowngrp(char *filename, int fileref);
+void fileaction_list(char *filename, int itemno);
+void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref));
+
+int rpm_main(int argc, char **argv)
+{
+       int opt = 0, func = 0, rpm_fd, offset;
+
+       while ((opt = getopt(argc, argv, "iqpldc")) != -1) {
+               switch (opt) {
+               case 'i': // First arg: Install mode, with q: Information
+                       if (!func) func |= rpm_install;
+                       else func |= rpm_query_info;
+                       break;
+               case 'q': // First arg: Query mode
+                       if (!func) func |= rpm_query;
+                       else show_usage();
+                       break;
+               case 'p': // Query a package
+                       func |= rpm_query_package;
+                       break;
+               case 'l': // List files in a package
+                       func |= rpm_query_list;
+                       break;
+               case 'd': // List doc files in a package (implies list)
+                       func |= rpm_query_list;
+                       func |= rpm_query_list_doc;
+                       break;
+               case 'c': // List config files in a package (implies list)
+                       func |= rpm_query_list;
+                       func |= rpm_query_list_config;
+                       break;
+               default:
+                       show_usage();
+               }
+       }
+
+       if (optind == argc) show_usage();
+       while (optind < argc) {
+               rpm_fd = xopen(argv[optind], O_RDONLY);
+               mytags = rpm_gettags(rpm_fd, (int *) &tagcount);
+               offset = lseek(rpm_fd, 0, SEEK_CUR);
+               if (!mytags) { printf("Error reading rpm header\n"); exit(-1); }
+               map = mmap(0, offset > getpagesize() ? (offset + offset % getpagesize()) : getpagesize(), PROT_READ, MAP_SHARED, rpm_fd, 0); // Mimimum is one page
+               if (func & rpm_install) {
+                       loop_through_files(RPMTAG_BASENAMES, fileaction_dobackup); /* Backup any config files */
+                       extract_cpio_gz(rpm_fd); // Extact the archive
+                       loop_through_files(RPMTAG_BASENAMES, fileaction_setowngrp); /* Set the correct file uid/gid's */
+               } else if (func & rpm_query && func & rpm_query_package) {
+                       if (!((func & rpm_query_info) || (func & rpm_query_list))) { // If just a straight query, just give package name
+                               printf("%s-%s-%s\n", rpm_getstring(RPMTAG_NAME, 0), rpm_getstring(RPMTAG_VERSION, 0), rpm_getstring(RPMTAG_RELEASE, 0));
+                       }
+                       if (func & rpm_query_info) {
+                               /* Do the nice printout */
+                               time_t bdate_time;
+                               struct tm *bdate;
+                               char bdatestring[50];
+                               printf("Name        : %-29sRelocations: %s\n", rpm_getstring(RPMTAG_NAME, 0), rpm_getstring(RPMTAG_PREFIXS, 0) ? rpm_getstring(RPMTAG_PREFIXS, 0) : "(not relocateable)");
+                               printf("Version     : %-34sVendor: %s\n", rpm_getstring(RPMTAG_VERSION, 0), rpm_getstring(RPMTAG_VENDOR, 0) ? rpm_getstring(RPMTAG_VENDOR, 0) : "(none)");
+                               bdate_time = rpm_getint(RPMTAG_BUILDTIME, 0);
+                               bdate = localtime((time_t *) &bdate_time);
+                               strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate);
+                               printf("Release     : %-30sBuild Date: %s\n", rpm_getstring(RPMTAG_RELEASE, 0), bdatestring);
+                               printf("Install date: %-30sBuild Host: %s\n", "(not installed)", rpm_getstring(RPMTAG_BUILDHOST, 0));
+                               printf("Group       : %-30sSource RPM: %s\n", rpm_getstring(RPMTAG_GROUP, 0), rpm_getstring(RPMTAG_SOURCERPM, 0));
+                               printf("Size        : %-33dLicense: %s\n", rpm_getint(RPMTAG_SIZE, 0), rpm_getstring(RPMTAG_LICENSE, 0));
+                               printf("URL         : %s\n", rpm_getstring(RPMTAG_URL, 0));
+                               printf("Summary     : %s\n", rpm_getstring(RPMTAG_SUMMARY, 0));
+                               printf("Description :\n%s\n", rpm_getstring(RPMTAG_DESCRIPTION, 0));
+                       }
+                       if (func & rpm_query_list) {
+                               int count, it, flags;
+                               count = rpm_getcount(RPMTAG_BASENAMES);
+                               for (it = 0; it < count; it++) {
+                                       flags = rpm_getint(RPMTAG_FILEFLAGS, it);
+                                       switch ((func & rpm_query_list_doc) + (func & rpm_query_list_config))
+                                       {
+                                               case rpm_query_list_doc: if (!(flags & RPMFILE_DOC)) continue; break;
+                                               case rpm_query_list_config: if (!(flags & RPMFILE_CONFIG)) continue; break;
+                                               case rpm_query_list_doc + rpm_query_list_config: if (!((flags & RPMFILE_CONFIG) || (flags & RPMFILE_DOC))) continue; break;
+                                       }
+                                       printf("%s%s\n", rpm_getstring(RPMTAG_DIRNAMES, rpm_getint(RPMTAG_DIRINDEXES, it)), rpm_getstring(RPMTAG_BASENAMES, it));
+                               }
+                       }
+               }
+               optind++;
+               free (mytags);
+       }
+       return 0;
+}
+
+void extract_cpio_gz(int fd) {
+       archive_handle_t *archive_handle;
+       unsigned char magic[2];
+
+       /* Initialise */
+       archive_handle = init_handle();
+       archive_handle->read = read_gz;
+       archive_handle->seek = seek_by_char;
+       //archive_handle->action_header = header_list;
+       archive_handle->action_data = data_extract_all;
+       archive_handle->flags |= ARCHIVE_PRESERVE_DATE;
+       archive_handle->flags |= ARCHIVE_CREATE_LEADING_DIRS;
+       archive_handle->src_fd = fd;
+       archive_handle->offset = 0;
+       
+       xread_all(archive_handle->src_fd, &magic, 2);
+       if ((magic[0] != 0x1f) || (magic[1] != 0x8b)) {
+               error_msg_and_die("Invalid gzip magic");
+       }
+       check_header_gzip(archive_handle->src_fd);      
+       chdir("/"); // Install RPM's to root
+
+       GZ_gzReadOpen(archive_handle->src_fd, 0, 0);
+       while (get_header_cpio(archive_handle) == EXIT_SUCCESS);
+       GZ_gzReadClose();
+       
+       check_trailer_gzip(archive_handle->src_fd);
+}
+
+
+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 */
+                       u_int8_t version; /* 1 byte version number */
+                       u_int32_t reserved; /* 4 bytes reserved */
+                       u_int32_t entries; /* Number of entries in header (4 bytes) */
+                       u_int32_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);
+}
+
+int rpm_getcount(int tag)
+{
+       rpm_index **found;
+       found = bsearch((void *) tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
+       if (!found) return 0;
+       else return found[0]->count;
+}
+
+char *rpm_getstring(int tag, int itemindex)
+{
+       rpm_index **found;
+       found = bsearch((void *) tag, mytags, 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 *) (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_index **found;
+       int n, *tmpint;
+       found = bsearch((void *) tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag);
+       if (!found || itemindex >= found[0]->count) return -1;
+       tmpint = (int *) (map + found[0]->offset);
+       if (found[0]->type == RPM_INT32_TYPE) {
+               for (n=0; n<itemindex; n++) tmpint = (int *) ((void *) tmpint + 4);
+               return ntohl(*tmpint);
+       } else if (found[0]->type == RPM_INT16_TYPE) {
+               for (n=0; n<itemindex; n++) tmpint = (int *) ((void *) tmpint + 2);
+               return ntohs(*tmpint);
+       } else if (found[0]->type == RPM_INT8_TYPE) {
+               for (n=0; n<itemindex; n++) tmpint = (int *) ((void *) tmpint + 1);
+               return ntohs(*tmpint);
+       } else return -1;
+}
+
+void fileaction_dobackup(char *filename, int fileref)
+{
+       struct stat oldfile;
+       int stat_res;
+       char *newname;
+       if (rpm_getint(RPMTAG_FILEFLAGS, fileref) & RPMFILE_CONFIG) { /* Only need to backup config files */
+               stat_res = lstat (filename, &oldfile);
+               if (stat_res == 0 && S_ISREG(oldfile.st_mode)) { /* File already exists  - really should check MD5's etc to see if different */
+                       newname = xstrdup(filename);
+                       newname = strcat(newname, ".rpmorig");
+                       copy_file(filename, newname, FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS);
+                       remove_file(filename, FILEUTILS_RECUR | FILEUTILS_FORCE);
+                       free(newname);
+               }
+       }
+}
+
+void fileaction_setowngrp(char *filename, int fileref)
+{
+       int uid, gid;
+       uid = my_getpwnam(rpm_getstring(RPMTAG_FILEUSERNAME, fileref));
+       gid = my_getgrnam(rpm_getstring(RPMTAG_FILEGROUPNAME, fileref));
+       chown (filename, uid, gid);
+}
+
+void fileaction_list(char *filename, int fileref)
+{
+       printf("%s\n", filename);
+}
+
+void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref))
+{
+       int count = 0;
+       char *filename, *tmp_dirname, *tmp_basename;
+       while (rpm_getstring(filetag, count)) {
+               tmp_dirname = rpm_getstring(RPMTAG_DIRNAMES, rpm_getint(RPMTAG_DIRINDEXES, count)); /* 1st put on the directory */
+               tmp_basename = rpm_getstring(RPMTAG_BASENAMES, count);
+               filename = xmalloc(strlen(tmp_basename) + strlen(tmp_dirname) + 1);
+               strcpy(filename, tmp_dirname); /* First the directory name */
+               strcat(filename, tmp_basename); /* then the filename */
+               fileaction(filename, count++);
+               free(filename);
+       }
+}
index b7171f7..9257fc9 100644 (file)
 #ifdef CONFIG_ROUTE
        APPLET(route, route_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
 #endif
+#ifdef CONFIG_RPM
+       APPLET(rpm, rpm_main, _BB_DIR_BIN, _BB_SUID_NEVER)
+#endif
 #ifdef CONFIG_RPM2CPIO
        APPLET(rpm2cpio, rpm2cpio_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
 #endif
index aca6859..8396f87 100644 (file)
@@ -85,6 +85,7 @@ extern void check_header_gzip(int src_fd);
 extern void check_trailer_gzip(int src_fd);
 
 extern char get_header_ar(archive_handle_t *archive_handle);
+extern char get_header_cpio(archive_handle_t *archive_handle);
 extern char get_header_tar(archive_handle_t *archive_handle);
 extern char get_header_tar_bz2(archive_handle_t *archive_handle);
 extern char get_header_tar_gz(archive_handle_t *archive_handle);
index 17fd407..5b357a2 100644 (file)
        "\t-n\tDont resolve names.\n" \
        "\t-e\tDisplay other/more information"
 
+#define rpm_trivial_usage \
+       "-i -q[ildc]p package.rpm"
+#define rpm_full_usage \
+       "Manipulates RPM packages" \
+       "Options:" \
+       "\t-i Install package" \
+       "\t-q Query package" \
+       "\t\t-p Query uninstalled package" \
+       "\t\t-i Show information" \
+       "\t\t-l List contents" \
+       "\t\t-d List documents" \
+       "\t\t-c List config files"
+
 #define rpm2cpio_trivial_usage \
        "package.rpm"
 #define rpm2cpio_full_usage \