From 6748c9f084926d640133c27eea34c34bb07c1191 Mon Sep 17 00:00:00 2001 From: Daniel Hokka Zakrisson Date: Tue, 10 Jul 2007 20:34:48 +0000 Subject: [PATCH] Replace file with h2ext for the template build method. git-svn-id: http://svn.linux-vserver.org/svn/util-vserver/trunk@2558 94cd875c-1c1d-0410-91d2-eb244daf1a30 --- contrib/manifest.dat.pathsubst | 4 +- distrib/Makefile.am | 3 +- distrib/misc/h2ext.desc | 19 ++ pathconfig.h.pathsubst | 1 + scripts/Makefile-files | 4 +- scripts/h2ext-worker | 29 +++ scripts/magic.mime | 19 -- scripts/util-vserver-vars.pathsubst | 1 + scripts/vserver-build.template | 29 +-- src/Makefile-files | 8 +- src/h2ext.c | 439 ++++++++++++++++++++++++++++++++++++ 11 files changed, 510 insertions(+), 46 deletions(-) create mode 100644 distrib/misc/h2ext.desc create mode 100644 scripts/h2ext-worker delete mode 100644 scripts/magic.mime create mode 100644 src/h2ext.c diff --git a/contrib/manifest.dat.pathsubst b/contrib/manifest.dat.pathsubst index ccf9291..08eca55 100644 --- a/contrib/manifest.dat.pathsubst +++ b/contrib/manifest.dat.pathsubst @@ -17,7 +17,6 @@ build @PKGLIBDIR@/vserver-build.functions.rpm build @PKGLIBDIR@/vserver-build.functions.yum build @PKGLIBDIR@/vserver-build.functions.pkgmgmt build @PKGLIBDIR@/vserver-setup.functions -build @PKGLIBDIR@/magic.mime base @PKGLIBDIR@/vserver.functions base @PKGLIBDIR@/vserver.start @ENSC_HAVE_C99_COMPILER_TRUE@base @PKGLIBDIR@/vserver.start.bin @@ -48,6 +47,7 @@ build @PKGLIBDIR@/defaults/debootstrap.uri build @PKGLIBDIR@/defaults/context.start build @PKGLIBDIR@/defaults/debootstrap.mirror @ENSC_HAVE_C99_COMPILER_TRUE@build @PKGLIBDIR@/defaults/vunify-exclude +build @PKGLIBDIR@/defaults/h2ext.desc base @PKGLIBDIR@/capchroot base @PKGLIBDIR@/chain-echo core @PKGLIBDIR@/chcontext-compat @@ -57,6 +57,8 @@ base @PKGLIBDIR@/chroot-sh base @PKGLIBDIR@/exec-ulimit base @PKGLIBDIR@/fakerunlevel base @PKGLIBDIR@/filetime +build @PKGLIBDIR@/h2ext +build @PKGLIBDIR@/h2ext-worker base @PKGLIBDIR@/lockfile base @PKGLIBDIR@/keep-ctx-alive base @PKGLIBDIR@/mask2prefix diff --git a/distrib/Makefile.am b/distrib/Makefile.am index 487116b..1b254da 100644 --- a/distrib/Makefile.am +++ b/distrib/Makefile.am @@ -28,7 +28,8 @@ defaults_DATA = misc/debootstrap.mirror \ misc/vprocunhide-files \ misc/vunify-exclude \ misc/environment \ - misc/context.start + misc/context.start \ + misc/h2ext.desc nobase_distrib_SCRIPTS = redhat/initpost \ redhat/initpre \ diff --git a/distrib/misc/h2ext.desc b/distrib/misc/h2ext.desc new file mode 100644 index 0000000..01afd3a --- /dev/null +++ b/distrib/misc/h2ext.desc @@ -0,0 +1,19 @@ +# Borrowed from file(1) +# gzip (GNU zip, not to be confused with [Info-ZIP/PKWARE] zip archiver) +0 string \037\213 gzip -d -c 1 +# tar posix +257 string ustar\0 tar -x 0 +# tar gnu +257 string ustar\040\040\0 tar -x 0 +# cpio +0 short 070707 cpio -i 0 +# cpio swapped +0 short 0143561 cpio -i 0 +# bzip2 +0 string BZh bzip2 -d -c 1 +# dump/restore new-fs big and little endian +24 belong 60012 restore -rf - 0 +24 lelong 60012 restore -rf - 0 +# dump/restore old-fs big and little endian +24 belong 60011 restore -rf - 0 +24 lelong 60011 restore -rf - 0 diff --git a/pathconfig.h.pathsubst b/pathconfig.h.pathsubst index 941af01..4679e02 100644 --- a/pathconfig.h.pathsubst +++ b/pathconfig.h.pathsubst @@ -44,6 +44,7 @@ #define PROG_VCONFIG "@VCONFIG@" #define PROG_SECURE_MOUNT PKGLIBDIR "/secure-mount" +#define PROG_H2EXT_WORKER PKGLIBDIR "/h2ext-worker" #define PATH_VSERVER_START PKGLIBDIR "/vserver.start" #define PATH_FUNCTIONS PKGLIBDIR "/functions" diff --git a/scripts/Makefile-files b/scripts/Makefile-files index 128c5a4..c59390a 100644 --- a/scripts/Makefile-files +++ b/scripts/Makefile-files @@ -38,7 +38,6 @@ AM_INSTALLCHECK_STD_OPTIONS_EXEMPT += \ scripts_pkglib_src_DTA = scripts/functions \ - scripts/magic.mime \ scripts/vserver-build.apt-rpm \ scripts/vserver-build.skeleton \ scripts/vserver-build.debootstrap \ @@ -75,7 +74,8 @@ scripts_pkglib_src_SCRPTS = scripts/pkgmgmt \ scripts/vservers.grabinfo.sh \ scripts/vshelper \ scripts/vsysvwrapper \ - scripts/vyum-worker + scripts/vyum-worker \ + scripts/h2ext-worker scripts_legacy_src_SCRPTS = scripts/legacy/save_s_context \ scripts/legacy/vserver \ diff --git a/scripts/h2ext-worker b/scripts/h2ext-worker new file mode 100644 index 0000000..9f55675 --- /dev/null +++ b/scripts/h2ext-worker @@ -0,0 +1,29 @@ +#! /bin/bash +# $Id$ + +# Copyright (C) 2007 Daniel Hokka Zakrisson +# +# 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; version 2 of the License. +# +# 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. + +# set -e + +: ${UTIL_VSERVER_VARS:=/usr/lib/util-vserver/util-vserver-vars} +test -e "$UTIL_VSERVER_VARS" || { + echo $"Can not find util-vserver installation (the file '$UTIL_VSERVER_VARS' would be expected); aborting..." >&2 + exit 1 +} +. "$UTIL_VSERVER_VARS" + +eval command=( $1 ) +exec "${command[@]}" diff --git a/scripts/magic.mime b/scripts/magic.mime deleted file mode 100644 index 0e10d84..0000000 --- a/scripts/magic.mime +++ /dev/null @@ -1,19 +0,0 @@ -# Borrowed from file(1) -# gzip (GNU zip, not to be confused with [Info-ZIP/PKWARE] zip archiver) -0 string \037\213 application/x-gzip -# tar posix -257 string ustar\0 application/x-tar -# tar gnu -257 string ustar\040\040\0 application/x-tar -# cpio -0 short 070707 application/x-cpio -# cpio swapped -0 short 0143561 application/x-cpio -# bzip2 -0 string BZh application/x-bzip2 -# dump/restore new-fs big and little endian -24 belong 60012 application/x-dump -24 lelong 60012 application/x-dump -# dump/restore old-fs big and little endian -24 belong 60011 application/x-dump -24 lelong 60011 application/x-dump diff --git a/scripts/util-vserver-vars.pathsubst b/scripts/util-vserver-vars.pathsubst index 7b4b450..4a87f34 100644 --- a/scripts/util-vserver-vars.pathsubst +++ b/scripts/util-vserver-vars.pathsubst @@ -40,6 +40,7 @@ _EXEC_CD="$__SBINDIR/exec-cd" _EXEC_ULIMIT="$__PKGLIBDIR/exec-ulimit" _FAKE_RUNLEVEL="$__PKGLIBDIR/fakerunlevel" _FILETIME="$__PKGLIBDIR/filetime" +_H2EXT="$__PKGLIBDIR/h2ext" _IFSPEC="$__LEGACYDIR/ifspec" _INITSYNC_MINIT_START=: _KEEP_CTX_ALIVE="$__PKGLIBDIR/keep-ctx-alive" diff --git a/scripts/vserver-build.template b/scripts/vserver-build.template index 27616cb..77b7326 100644 --- a/scripts/vserver-build.template +++ b/scripts/vserver-build.template @@ -69,30 +69,15 @@ test -z "$BUILD_INITPRE" || "$BUILD_INITPRE" "$SETUP_CONFDIR" "$UTIL_VSERVER_V pushd "$SETUP_CONFDIR/vdir" &> /dev/null for t in "${TEMPLATE[@]}"; do - mime=$($_FILE -Nbiz -m "$_LIB_MAGIC" "$t") - compression=$(echo "$mime" | $_GREP '(' | $_SED 's!.*(\(.*\))$!\1!') - - case "$compression" in - application/x-bzip2) DECOMPRESS="$_BZIP2 -d -c";; - application/x-gzip) DECOMPRESS="$_GZIP -d -c";; - "") DECOMPRESS=$_CAT;; - *) - echo "Unsupported compression method: $compression" - exit 1 - ;; - esac + findFile DESC "$__CONFDIR/.defaults/apps/h2ext/desc" "$__PKGLIBDEFAULTDIR/h2ext.desc" + pipe=$($_H2EXT -d "$DESC" -q "$t") - case "$mime" in - application/x-tar*) EXTRACT="$_TAR -x";; - application/x-cpio*) EXTRACT="$_CPIO -i";; - application/x-dump*) EXTRACT="$_RESTORE -rf -";; - *) - echo "Unsupported packaging method: $mime" - exit 1 - ;; - esac + if echo "$pipe" | grep -q "unknown format"; then + echo "vserver-build.template: $t: Unknown format" >&2 + exit 1 + fi - $DECOMPRESS "$t" | $EXTRACT + eval `echo $_CAT "\$t" '|' $pipe` done test -z "$no_dev_sanity" && { diff --git a/src/Makefile-files b/src/Makefile-files index 370d569..dad36c1 100644 --- a/src/Makefile-files +++ b/src/Makefile-files @@ -80,7 +80,8 @@ DIETPROGS += src/chcontext-compat \ src/naddress \ src/vdevmap \ src/vsysctl \ - src/vclone + src/vclone \ + src/h2ext if ENSC_CAN_BEECRYPT_WITH_DIETLIBC DIETPROGS += src/vhashify @@ -118,6 +119,7 @@ pkglib_PROGRAMS += src/capchroot \ src/sigexec \ src/chbind-compat \ src/vsysctl \ + src/h2ext \ $(src_pkglib_C99_X_PROGS) \ $(src_pkglib_CXX_X_PROGS) @@ -336,6 +338,10 @@ src_vclone_SOURCES = src/vclone.c src_vclone_LDADD = $(LIBINTERNAL) $(VSERVER_LDADDS) src_vclone_LDFLAGS = $(VSERVER_LDLFGS) +src_h2ext_SOURCES = src/h2ext.c +src_h2ext_LDADD = $(LIBINTERNAL) $(VSERVER_LDADDS) +src_h2ext_LDFLAGS = $(VSERVER_LDFLGS) + EXTRA_PROGRAMS += $(src_sbin_CXX_PROGS) $(src_pkglib_CXX_PROGS) TESTS_ENVIRONMENT += srctestsuitedir=$(top_builddir)/src/testsuite diff --git a/src/h2ext.c b/src/h2ext.c new file mode 100644 index 0000000..d1050c8 --- /dev/null +++ b/src/h2ext.c @@ -0,0 +1,439 @@ +// $Id$ + +// Copyright (C) 2007 Daniel Hokka Zakrisson +// +// 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, 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. + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "lib/internal.h" +#include "pathconfig.h" + +#define ENSC_WRAPPERS_PREFIX "h2ext: " +#define ENSC_WRAPPERS_UNISTD 1 +#define ENSC_WRAPPERS_FCNTL 1 +#define ENSC_WRAPPERS_STAT 1 +#include + +#define MAX_PEEK_SIZE 4096 +#define MIN(a,b) (((a) > (b)) ? (b) : (a)) + +struct file_format { + /* where the value would be in the file */ + long offset; + /* type of match */ + enum { + FFT_STRING = 1, + FFT_SHORT, + FFT_LONG, + FFT_LE = 0x4000, + FFT_BE = 0x8000, + } type; + /* the value */ + union { + char * st; + uint16_t sh; + uint32_t lo; + } value; + /* length of the value */ + size_t len; + /* program to use for extraction */ + char * extractor; + /* should we try to process the contents as well? */ + int peek_inside; + + struct file_format *next; +}; +typedef struct file_format file_format_t; + +int wrapper_exit_code = 255; + +#define CMD_HELP 0x4001 +#define CMD_VERSION 0x4002 + +struct option const +CMDLINE_OPTIONS[] = { + { "help", no_argument, 0, CMD_HELP }, + { "version", no_argument, 0, CMD_VERSION }, + { "desc", required_argument, 0, 'd' }, + { "silent", no_argument, 0, 'q' }, + { 0,0,0,0 }, +}; + +static void +showHelp(int fd, char const *cmd, int res) +{ + WRITE_MSG(fd, "Usage:\n "); + WRITE_STR(fd, cmd); + WRITE_MSG(fd, + " -d [...]\n\n" + "Please report bugs to " PACKAGE_BUGREPORT "\n"); + + exit(res); +} + +static void +showVersion() +{ + WRITE_MSG(1, + "h2ext " VERSION " -- determines how to extract a file\n" + "This program is part of " PACKAGE_STRING "\n\n" + "Copyright (C) 2007 Daniel Hokka Zakrisson\n" + VERSION_COPYRIGHT_DISCLAIMER); + exit(0); +} + +static file_format_t * +find_format(file_format_t *head, char *data) +{ + file_format_t *i; + + for (i = head; i; i = i->next) { + switch (i->type & ~(FFT_LE|FFT_BE)) { + case FFT_STRING: + if (memcmp(i->value.st, data + i->offset, i->len) == 0) + goto found; + break; + case FFT_SHORT: + if (i->value.sh == *((__typeof__(i->value.sh) *)data + i->offset)) + goto found; + break; + case FFT_LONG: + if (i->value.lo == *((__typeof__(i->value.lo) *)data + i->offset)) + goto found; + break; + } + } +found: + return i; +} + +static int +process_file(file_format_t *head, const char *file, file_format_t *ret[2]) +{ + int fd; + void *mapping; + struct stat st; + + fd = EopenD(file, O_RDONLY, 0); + Efstat(fd, &st); + mapping = mmap(NULL, MIN(st.st_size, MAX_PEEK_SIZE), PROT_READ, MAP_SHARED, fd, 0); + if (!mapping) { + perror("mmap()"); + Eclose(fd); + return -1; + } + + ret[0] = find_format(head, mapping); + + munmap(mapping, MIN(st.st_size, MAX_PEEK_SIZE)); + + if (ret[0] && ret[0]->peek_inside) { + pid_t child; + int fds[2]; + + Elseek(fd, 0, SEEK_SET); + + Epipe(fds); + child = Efork(); + if (child == 0) { + char *argv[3] = { PROG_H2EXT_WORKER, ret[0]->extractor, NULL }; + dup2(fd, 0); + dup2(fds[1], 1); + EexecvpD(PROG_H2EXT_WORKER, argv); + } + else { + char *buf = calloc(MAX_PEEK_SIZE, sizeof(char)), *cur, *end; + ssize_t bytes_read; + + /* read MAX_PEEK_SIZE bytes from the decompressor */ + cur = buf; + end = buf + MAX_PEEK_SIZE; + while (cur < end && (bytes_read = Eread(fds[0], cur, end - cur - 1)) > 0) + cur += bytes_read; + + /* get rid of the child */ + kill(child, SIGTERM); + wait(NULL); + + ret[1] = find_format(head, buf); + free(buf); + } + } + else + ret[1] = NULL; + + Eclose(fd); + + return 0; +} + +static inline void +byteswap(void *p, size_t len) +{ + size_t i; + char *buf = p, tmp; + for (i = 0; i < (len >> 1); i++) { + tmp = buf[len - i - 1]; + buf[len - i - 1] = buf[i]; + buf[i] = tmp; + } +} + +static inline ALWAYSINLINE void +WRITE_INT(int fd, int num) +{ + char buf[sizeof(num)*3+2]; + size_t l; + + l = utilvserver_fmt_long(buf,num); + + Vwrite(fd, buf, l); +} + +static int +load_description(const char *file, file_format_t **head) +{ + file_format_t *prev = NULL, + *i = NULL; + int fd, + line_no = 0; + char buf[512], + *field, + *end = buf, + *ptr, + *eol; + ssize_t bytes_read; + + fd = EopenD(file, O_RDONLY, 0); + + *buf = '\0'; + while (1) { + if ((eol = strchr(buf, '\n')) == NULL && (end - buf) < (sizeof(buf) - 1)) { + bytes_read = Eread(fd, end, sizeof(buf) - 1 - (end - buf)); + /* EOF, implicit newline */ + if (bytes_read == 0) { + if (end == buf) + break; + eol = end; + *(end++) = '\n'; + } + end += bytes_read; + *end = '\0'; + continue; + } + else if (eol == NULL) { + WRITE_MSG(2, ENSC_WRAPPERS_PREFIX); + WRITE_STR(2, file); + WRITE_MSG(2, ":"); + WRITE_INT(2, line_no); + WRITE_MSG(2, " is a really long line\n"); + Eclose(fd); + return -1; + } + *eol = '\0'; + line_no++; + + if (*buf == '#' || *buf == '\0') + goto new_line; + if (*head == NULL) + i = *head = calloc(1, sizeof(file_format_t)); + else { + i->next = calloc(1, sizeof(file_format_t)); + prev = i; + i = i->next; + } + i->next = NULL; + +#define get_field() for (ptr++; *ptr == '\t' && *ptr != '\0'; ptr++); \ + for (field = ptr; *ptr != '\t' && *ptr != '\0'; ptr++); \ + *ptr = '\0'; + field = ptr = buf; + while (*ptr != '\t' && *ptr != '\0') + ptr++; + *ptr = '\0'; + if (field == ptr) + goto new_line_and_free; + i->offset = strtol(field, NULL, 0); + + get_field(); + if (strcmp(field, "string") == 0) + i->type = FFT_STRING; + else if (strcmp(field, "short") == 0) + i->type = FFT_SHORT; + else if (strcmp(field, "long") == 0) + i->type = FFT_LONG; + else if (strcmp(field, "leshort") == 0) + i->type = FFT_SHORT|FFT_LE; + else if (strcmp(field, "beshort") == 0) + i->type = FFT_SHORT|FFT_BE; + else if (strcmp(field, "lelong") == 0) + i->type = FFT_LONG|FFT_LE; + else if (strcmp(field, "belong") == 0) + i->type = FFT_LONG|FFT_BE; + else { + WRITE_MSG(2, ENSC_WRAPPERS_PREFIX); + WRITE_STR(2, file); + WRITE_MSG(2, ":"); + WRITE_INT(2, line_no); + WRITE_MSG(2, " has an unknown type: "); + WRITE_STR(2, field); + WRITE_MSG(2, "\n"); + goto new_line_and_free; + } + + get_field(); + switch (i->type & ~(FFT_BE|FFT_LE)) { + case FFT_STRING: + { + char *c, *tmp; + i->value.st = tmp = calloc(strlen(field) + 1, sizeof(char)); + for (c = field; *c; c++) { + if (*c == '\\') { + char *endptr; + *(tmp++) = (char)strtol(c + 1, &endptr, 8); + c = endptr - 1; + } + else + *(tmp++) = *c; + } + *tmp = '\0'; + i->len = tmp - i->value.st; + } + break; + case FFT_SHORT: + i->len = sizeof(i->value.sh); + i->value.sh = (__typeof__(i->value.sh))strtol(field, NULL, 0); +#if BYTE_ORDER != BIG_ENDIAN + if (i->type & FFT_BE) +#elif BYTE_ORDER != LITTLE_ENDIAN + if (i->type & FFT_LE) +#else +# error UNKNOWN BYTE ORDER +#endif + byteswap(&i->value.sh, i->len); + break; + case FFT_LONG: + i->len = sizeof(i->value.lo); + i->value.lo = (__typeof__(i->value.lo))strtol(field, NULL, 0); +#if BYTE_ORDER != BIG_ENDIAN + if (i->type & FFT_BE) +#elif BYTE_ORDER != LITTLE_ENDIAN + if (i->type & FFT_LE) +#else +# error UNKNOWN BYTE ORDER +#endif + byteswap(&i->value.lo, i->len); + break; + } + + get_field(); + i->extractor = strdup(field); + + get_field(); + i->peek_inside = (int)strtol(field, NULL, 0); + +#undef get_field + goto new_line; + +new_line_and_free: + free(i); + if (prev) { + i = prev; + free(i->next); + i->next = NULL; + } + else + *head = i = NULL; +new_line: + memmove(buf, eol + 1, end - (eol + 1)); + end = buf + (end - (eol + 1)); + } + + Eclose(fd); + return 0; +} + +int main(int argc, char *argv[]) +{ + char **file = NULL, + *desc = NULL; + file_format_t *head = NULL; + int quiet = 0; + + while (1) { + int c = getopt_long(argc, argv, "+d:q", CMDLINE_OPTIONS, 0); + if (c == -1) break; + + switch (c) { + case CMD_HELP: showHelp(1, argv[0], 0); + case CMD_VERSION: showVersion(); + case 'd': desc = optarg; break; + case 'q': quiet = 1; break; + default: + WRITE_MSG(2, "Try '"); + WRITE_STR(2, argv[0]); + WRITE_MSG(2, " --help' for more information.\n"); + return wrapper_exit_code; + } + } + + if (desc == NULL) { + WRITE_MSG(2, "No descriptions supplied, try '"); + WRITE_STR(2, argv[0]); + WRITE_MSG(2, " --help' for more information.\n"); + return wrapper_exit_code; + } + + head = NULL; + if (load_description(desc, &head) == -1) + return EXIT_FAILURE; + + for (file = argv + optind; *file; file++) { + file_format_t *formats[2]; + if (!quiet) { + WRITE_STR(1, *file); + WRITE_MSG(1, ": "); + } + if (!process_file(head, *file, formats) && formats[0]) { + WRITE_STR(1, formats[0]->extractor); + if (formats[0]->peek_inside) { + WRITE_MSG(1, " | "); + WRITE_STR(1, formats[1] ? formats[1]->extractor : "unknown format"); + } + } + else + WRITE_MSG(1, "unknown format"); + WRITE_MSG(1, "\n"); + } + + return 0; +} -- 1.8.1.5