Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 06 Feb 2003 12:10:48 -0800
From:      Tim Kientzle <kientzle@acm.org>
To:        freebsd-hackers@FreeBSD.ORG
Subject:   Making pkg_XXX tools smarter about file types...
Message-ID:  <3E42C148.4050807@acm.org>

next in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------010009080904010803020102
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

The attached patch modifies the pkg_install
tools to inspect the file contents--rather than the
filename extension--to determine the
compression method in use.  It then feeds the data
into the correct invocation of 'tar'.
I've also modified exec.c/lib.h to
factor out and expose some common code that
formats shell command lines.

This approach makes it possible, for instance, to
fix a single file extension (e.g. '.freebsd'
or '.package') that would not have to change
even if the internal format of a package were
to change (as has already occurred once, with
the transition from gzip to bzip2 compression).

Note that this could also be fairly easily extended
to support a variety of alternative archive
types.  (E.g., the pkg_XXX tools could be
modified to support 'zip' or 'tar' archives
transparently to the user.)

Tim Kientzle

P.S.  Similar logic should no doubt be
added to 'tar' itself, thus eliminating the
need for the -z/-j/-y options.

--------------010009080904010803020102
Content-Type: text/plain;
 name="kientzle_pkg_install.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="kientzle_pkg_install.diff"

Index: lib/exec.c
===================================================================
RCS file: /usr/src/cvs/src/usr.sbin/pkg_install/lib/exec.c,v
retrieving revision 1.10
diff -c -r1.10 exec.c
*** lib/exec.c	2002/04/01 09:39:07	1.10
--- lib/exec.c	2003/02/06 19:05:28
***************
*** 25,59 ****
  #include <err.h>
  
  /*
!  * Unusual system() substitute.  Accepts format string and args,
!  * builds and executes command.  Returns exit code.
   */
! 
! int
! vsystem(const char *fmt, ...)
  {
!     va_list args;
      char *cmd;
-     int ret, maxargs;
  
      maxargs = sysconf(_SC_ARG_MAX);
      maxargs -= 32;			/* some slop for the sh -c */
      cmd = malloc(maxargs);
      if (!cmd) {
! 	warnx("vsystem can't alloc arg space");
! 	return 1;
      }
- 
-     va_start(args, fmt);
      if (vsnprintf(cmd, maxargs, fmt, args) > maxargs) {
! 	warnx("vsystem args are too long");
! 	return 1;
      }
  #ifdef DEBUG
  printf("Executing %s\n", cmd);
  #endif
      ret = system(cmd);
-     va_end(args);
      free(cmd);
      return ret;
  }
--- 25,83 ----
  #include <err.h>
  
  /*
!  * Format a command, allocating a buffer along the way.
   */
! static char *
! va_system_cmd(const char *fmt, va_list args)
  {
!     int maxargs;
      char *cmd;
  
      maxargs = sysconf(_SC_ARG_MAX);
      maxargs -= 32;			/* some slop for the sh -c */
      cmd = malloc(maxargs);
      if (!cmd) {
! 	warnx("can't allocate memory to format program command line");
! 	return NULL;
      }
      if (vsnprintf(cmd, maxargs, fmt, args) > maxargs) {
! 	warnx("argument list is too long");
! 	return NULL;
      }
+     return cmd;
+ }
+ 
+ char *
+ system_cmd(const char *fmt, ...)
+ {
+     va_list args;
+     char *cmd;
+ 
+     va_start(args, fmt);
+     cmd = va_system_cmd(fmt,args);
+     va_end(args);
+     return cmd;
+ }
+ 
+ /*
+  * Unusual system() substitute.  Accepts format string and args,
+  * builds and executes command.  Returns exit code.
+  */
+ int
+ vsystem(const char *fmt, ...)
+ {
+     va_list args;
+     char *cmd;
+     int ret;
+ 
+     va_start(args, fmt);
+     cmd = va_system_cmd(fmt,args);
+     va_end(args);
+     if(cmd == NULL) return 1;
  #ifdef DEBUG
  printf("Executing %s\n", cmd);
  #endif
      ret = system(cmd);
      free(cmd);
      return ret;
  }
***************
*** 63,69 ****
  {
     FILE *fp;
     char *cmd, *rp;
-    int maxargs;
     va_list args;
  
      rp = malloc(MAXPATHLEN);
--- 87,92 ----
***************
*** 71,94 ****
          warnx("vpipe can't alloc buffer space");
          return NULL;
      }
!     maxargs = sysconf(_SC_ARG_MAX);
!     maxargs -= 32;			    /* some slop for the sh -c */
!     cmd = alloca(maxargs);
!     if (!cmd) {
! 	warnx("vpipe can't alloc arg space");
! 	return NULL;
!     }
  
-     va_start(args, fmt);
-     if (vsnprintf(cmd, maxargs, fmt, args) > maxargs) {
- 	warnx("vsystem args are too long");
- 	return NULL;
-     }
  #ifdef DEBUG
      fprintf(stderr, "Executing %s\n", cmd);
  #endif
      fflush(NULL);
      fp = popen(cmd, "r");
      if (fp == NULL) {
  	warnx("popen() failed");
  	return NULL;
--- 94,110 ----
          warnx("vpipe can't alloc buffer space");
          return NULL;
      }
!     va_start(args,fmt);
!     cmd = va_system_cmd(fmt,args);
!     va_end(args);
!     if(cmd == NULL) return NULL;
  
  #ifdef DEBUG
      fprintf(stderr, "Executing %s\n", cmd);
  #endif
      fflush(NULL);
      fp = popen(cmd, "r");
+     free(cmd);
      if (fp == NULL) {
  	warnx("popen() failed");
  	return NULL;
***************
*** 97,103 ****
  #ifdef DEBUG
      fprintf(stderr, "Returned %s\n", rp);
  #endif
-     va_end(args);
      if (pclose(fp) || (strlen(rp) == 0)) {
  	free(rp);
  	return NULL;
--- 113,118 ----
Index: lib/file.c
===================================================================
RCS file: /usr/src/cvs/src/usr.sbin/pkg_install/lib/file.c,v
retrieving revision 1.64
diff -c -r1.64 file.c
*** lib/file.c	2003/01/06 07:39:02	1.64
--- lib/file.c	2003/02/06 19:50:22
***************
*** 27,32 ****
--- 27,36 ----
  #include <time.h>
  #include <sys/wait.h>
  
+ static int file_is_gzip(const unsigned char *, size_t);
+ static int file_is_bzip2(const unsigned char *, size_t);
+ 
+ 
  /* Quick check to see if a file exists */
  Boolean
  fexists(const char *fname)
***************
*** 328,362 ****
  int
  unpack(const char *pkg, const char *flist)
  {
!     char args[10], suff[80], *cp;
  
!     args[0] = '\0';
!     /*
!      * Figure out by a crude heuristic whether this or not this is probably
!      * compressed and whichever compression utility was used (gzip or bzip2).
!      */
      if (strcmp(pkg, "-")) {
! 	cp = strrchr(pkg, '.');
! 	if (cp) {
! 	    strcpy(suff, cp + 1);
! 	    if (strchr(suff, 'z') || strchr(suff, 'Z')) {
! 		if (strchr(suff, 'b'))
! 		    strcpy(args, "-j");
! 		else
! 		    strcpy(args, "-z");
! 	    }
! 	}
      }
!     else
! 	/* XXX: need to handle .tgz also */
! 	strcpy(args, "-j");
!     strcat(args, " -xpf");
!     if (vsystem("tar %s '%s' %s", args, pkg, flist ? flist : "")) {
  	warnx("tar extract of %s failed!", pkg);
  	return 1;
      }
      return 0;
  }
  
  /*
   * Using fmt, replace all instances of:
--- 332,410 ----
  int
  unpack(const char *pkg, const char *flist)
  {
!     char *cmd;
!     char *compression;
!     FILE *pkg_file;
!     FILE *out_pipe;
!     unsigned char *buff;
!     size_t buff_allocation;
!     size_t buff_size;
  
!     buff_allocation = 8*1024;
! 
!     buff = (unsigned char *)malloc(buff_allocation);
!     /* Determine compression by inspecting file signature */
      if (strcmp(pkg, "-")) {
!         pkg_file = fopen(pkg,"r");
!     } else {
!         pkg_file = stdin;
      }
!     if(pkg_file == NULL) {
!         warnx("couldn't open %s",pkg);
! 	return 1;
!     }
! 
!     /* Select appropriate compression argument for tar by
!      * inspecting file signature */
!     buff_size = fread(buff,1,buff_allocation,pkg_file);
!     if(file_is_gzip(buff,buff_size)) {
!         compression = "z";
!     } else if(file_is_bzip2(buff,buff_size)) {
!         compression = "j";
!     } else {
!         compression = "";
!     }
! 
!     cmd = system_cmd("tar -xp%sf - %s",compression,flist ? flist : "");
!     if(cmd == NULL) return 1;
! 
!     /* Cat entire file through tar */
! #ifdef DEBUG
!     printf("Piping package '%s' to cmd '%s'\n", pkg,cmd);
! #endif
!     out_pipe = popen(cmd,"w");
!     free(cmd);
! 
!     if(out_pipe == NULL) return 1;
!     while(buff_size > 0) {
!         buff_size = fwrite(buff,1,buff_size,out_pipe);
! 	buff_size = fread(buff,1,buff_allocation,pkg_file);
!     }
!     if(pclose(out_pipe)) {
  	warnx("tar extract of %s failed!", pkg);
  	return 1;
      }
      return 0;
  }
+ 
+ /*
+  * Returns 1 if buffer holds initial bytes of a gzipped file
+  */
+ static int
+ file_is_gzip(const unsigned char *head, size_t s) {
+   if(s < 2) return 0;
+   return (head[0]==0037 && head[1]==0213);
+ }
+ 
+ /*
+  * Returns 1 if buffer holds initial bytes of a bzip2-ed file
+  */
+ static int
+ file_is_bzip2(const unsigned char *head, size_t s) {
+   if(s < 3) return 0;
+   return (head[0]=='B' && head[1]=='Z' && head[2]=='h');
+ }
+ 
  
  /*
   * Using fmt, replace all instances of:
Index: lib/lib.h
===================================================================
RCS file: /usr/src/cvs/src/usr.sbin/pkg_install/lib/lib.h,v
retrieving revision 1.47
diff -c -r1.47 lib.h
*** lib/lib.h	2003/01/06 07:39:02	1.47
--- lib/lib.h	2003/02/06 19:05:38
***************
*** 137,142 ****
--- 137,143 ----
  /* Prototypes */
  /* Misc */
  int		vsystem(const char *, ...);
+ char *		system_cmd(const char *, ...);
  char		*vpipe(const char *, ...);
  void		cleanup(int);
  char		*make_playpen(char *, off_t);

--------------010009080904010803020102--


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3E42C148.4050807>