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>