Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 7 Aug 2010 22:37:07 GMT
From:      Julien Laffaye <jlaffaye@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 182047 for review
Message-ID:  <201008072237.o77Mb7af072120@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@182047?ac=10

Change 182047 by jlaffaye@jlaffaye-chulak on 2010/08/07 22:36:29

	pkg_info(1) tells if a package archive is a complete package. If it is, it list
	the packages in the set.
	Use libarchive to show informations of a package archive instead of making a playpen.
	(It is a bit hackish because we dont show the files in the order they are stored
	in the tarball so we've to read the archive first, saving the required files'
	content in memory, then print the content in the proper order).

Affected files ...

.. //depot/projects/soc2010/pkg_complete/usr.sbin/pkg_install/info/info.h#2 edit
.. //depot/projects/soc2010/pkg_complete/usr.sbin/pkg_install/info/perform.c#3 edit
.. //depot/projects/soc2010/pkg_complete/usr.sbin/pkg_install/info/show.c#2 edit

Differences ...

==== //depot/projects/soc2010/pkg_complete/usr.sbin/pkg_install/info/info.h#2 (text+ko) ====

@@ -62,6 +62,12 @@
 };
 TAILQ_HEAD(which_head, which_entry);
 
+struct archive_file {
+	int flag;
+	const char *fname;
+	char *data;
+};
+
 extern int Flags;
 extern Boolean QUIET;
 extern Boolean UseBlkSz;
@@ -74,6 +80,8 @@
 extern struct which_head *whead;
 
 extern void	show_file(const char *, const char *);
+extern void	show_file_archive(const char *, const char *,
+				  struct archive_file *);
 extern void	show_plist(const char *, Package *, plist_t, Boolean);
 extern void	show_files(const char *, Package *);
 extern void	show_index(const char *, const char *);

==== //depot/projects/soc2010/pkg_complete/usr.sbin/pkg_install/info/perform.c#3 (text+ko) ====

@@ -21,6 +21,8 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/usr.sbin/pkg_install/info/perform.c,v 1.57 2010/04/23 11:07:43 flz Exp $");
 
+#include <archive.h>
+#include <archive_entry.h>
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -30,7 +32,6 @@
 #include "cleanup.h"
 #include "info.h"
 
-void		cleanup(void);
 static int	pkg_do(char *);
 static int	find_pkg(struct which_head *);
 static int	cmp_path(const char *, const char *, const char *);
@@ -46,9 +47,6 @@
     int errcode;
     int i;
 
-    if (register_cleanup_handler(cleanup, NULL, NULL, 0) == -1)
-	err(EXIT_FAILURE, "failed to initialize cleanup exit handler");
-
     /* Overriding action? */
     if (Flags & SHOW_PKGNAME)
 	return matched_packages(pkgs);
@@ -94,69 +92,135 @@
 static int
 pkg_do(char *pkg)
 {
-    Boolean installed = FALSE, isTMP = FALSE;
+    struct archive *a = NULL;
+    Boolean installed = FALSE;
     char log_dir[FILENAME_MAX];
-    char fname[FILENAME_MAX];
     Package plist;
-    struct stat sb;
     const char *cp = NULL;
+    int i;
     int code = 0;
     int fd = -1;
     int rc;
     int serrno;
 
+    struct archive_file files[] = {
+	{ SHOW_COMMENT,		COMMENT_FNAME,		NULL },
+	{ SHOW_DESC,		DESC_FNAME,		NULL },
+	{ SHOW_DISPLAY,		DISPLAY_FNAME,		NULL },
+	{ SHOW_REQUIRE,		REQUIRE_FNAME,		NULL },
+	{ SHOW_INSTALL,		INSTALL_FNAME,		NULL },
+	{ SHOW_INSTALL,		POST_INSTALL_FNAME,	NULL },
+	{ SHOW_DEINSTALL,	DEINSTALL_FNAME,	NULL },
+	{ SHOW_DEINSTALL,	POST_DEINSTALL_FNAME,	NULL },
+	{ SHOW_MTREE,		MTREE_FNAME,		NULL },
+	{ 0,			NULL,			NULL }
+    };
+    plist.head = plist.tail = NULL;
+
     if (isURL(pkg)) {
-	if ((cp = fileGetURL(NULL, pkg, KeepPackage)) != NULL) {
-	    if (!getcwd(fname, FILENAME_MAX))
-		err(EXIT_FAILURE, "getcwd()");
-	    isTMP = TRUE;
-	} else {
-	    cleanup();
-	    goto bail;
+	if ((fd = fetch_archive(pkg, KeepPackage)) == -1) {
+	    warnx("can not fetch %s - aborting", pkg);
+	    return (1);
 	}
     }
-    else if (fexists(pkg) && isfile(pkg)) {
-	int len;
+    else {
+	if (fexists(pkg) && isfile(pkg))
+	    cp = pkg;
+	if (cp == NULL)
+	    cp = fileFindByPath(NULL, pkg);
+	if (cp != NULL)
+	    if ((fd = open(cp, O_RDONLY)) == -1) {
+		warn("open(%s)", cp);
+		return (1);
+	    }
+    }
+    /* It is a package archive: extract the required files in memory. */
+    if (fd > 0) {
+	struct archive_entry *entry;
+	Boolean first_file = TRUE;
+	Boolean is_meta = FALSE;
+	Boolean is_complete = FALSE;
+	const char *pathname;
+	char *buf = NULL;
+	ssize_t size;
+
+	a = archive_read_new();
+	archive_read_support_compression_all(a);
+	archive_read_support_format_tar(a);
 
-	if (*pkg != '/') {
-	    if (!getcwd(fname, FILENAME_MAX))
-		err(EXIT_FAILURE, "getcwd()");
-	    len = strlen(fname);
-	    snprintf(&fname[len], FILENAME_MAX - len, "/%s", pkg);
+	if (archive_read_open_fd(a, fd, 10240) != ARCHIVE_OK) {
+	    warnx("archive_read_open_fd(): %s", archive_error_string(a));
+	    code = 1;
+	    goto cleanup;
 	}
-	else
-	    strcpy(fname, pkg);
-	cp = fname;
-    }
-    else {
-	if ((cp = fileFindByPath(NULL, pkg)) != NULL)
-	    strncpy(fname, cp, FILENAME_MAX);
-    }
-    if (cp) {
-	if (!isURL(pkg)) {
-	    /*
-	     * Apply a crude heuristic to see how much space the package will
-	     * take up once it's unpacked.  I've noticed that most packages
-	     * compress an average of 75%, but we're only unpacking the + files
-	     * to be very optimistic.
-	     */
-	    if (stat(fname, &sb) == -1) {
-	        warnx("can't stat package file '%s'", fname);
-	        code = 1;
-	        goto bail;
+	
+	while ((rc = archive_read_next_header(a, &entry)) == ARCHIVE_OK &&
+	       (first_file || is_meta || is_complete)) {
+
+	    pathname = archive_entry_pathname(entry);
+	    if (first_file) {
+		if (strcmp(pathname, CONTENTS_FNAME) == 0) {
+		    size = archive_entry_size(entry);
+		    buf = malloc(size + 1);
+		    if (buf == NULL)
+			err(1, NULL);
+		    if (archive_read_data(a, buf, size) != size)
+			errx(1, "%s", archive_error_string(a));
+		    buf[size] = '\0';
+		    rc = read_plist_from_buffer(&plist, buf, size);
+		    free(buf);
+		    if (rc != 0) {
+			warnx("failure occured reading plist");
+			code = 1;
+			goto cleanup;
+		    }
+		    is_meta = TRUE;
+		}
+		else if (strcmp(pathname, PKG_COMPLETE_FNAME) == 0) {
+		    is_complete = TRUE;
+		    printf("%s is a complete package containing:\n", pkg);
+		}
+		else {
+		    warnx("bad package archive");
+		    code = 1;
+		    goto cleanup;
+		}
+		first_file = FALSE;
+		continue;
 	    }
-	    else if (make_playpen(PlayPen, sb.st_size / 2) == NULL) {
-		warn("failed to create a playpen");
-		cleanup();
-		code = 1;
-		goto bail;
+
+	    /* If it is a complete package, just print the contained packages */
+	    if (is_complete)
+		printf("%s\n", pathname);
+	    else {
+		is_meta = FALSE;
+		for (i = 0; files[i].flag != 0; i++) {
+		    if (strcmp(pathname, files[i].fname) == 0) {
+			is_meta = TRUE;
+			if (Flags & files[i].flag) {
+			    size = archive_entry_size(entry);
+			    files[i].data = malloc(size + 1);
+			    if (files[i].data == NULL)
+				err(1, "malloc()");
+			    if (archive_read_data(a, files[i].data, size) !=
+				size)
+				errx(1, "%s", archive_error_string(a));
+			    files[i].data[size] = '\0';
+			}
+			break;
+		    }
+		}
 	    }
-	    else if (unpack_to_disk(fname, "+*")) {
-		warnx("error during unpacking, no info for '%s' available",
-		    pkg);
-		code = 1;
-		goto bail;
-	    }
+	}
+	if (rc != ARCHIVE_OK && rc != ARCHIVE_EOF) {
+	    warnx("can not read archive: %s", archive_error_string(a));
+	    code = 1;
+	    goto cleanup;
+	}
+	/* If it is a complete package, we've already done our job */
+	if (is_complete) {
+	    code = 0;
+	    goto cleanup;
 	}
     }
     /* It's not an uninstalled package, try and find it among the installed */
@@ -174,25 +238,21 @@
 	    warnx("can't change directory to '%s'!", log_dir);
 	    return 1;
 	}
+
+	fd = open(CONTENTS_FNAME, O_RDONLY);
+	if (fd == -1) {
+	    warnx("unable to open %s file", CONTENTS_FNAME);
+	    return (1);
+	}
+	rc = read_plist(&plist, fd);
+	serrno = errno;
+	(void) close(fd);
+	if (rc == -1)
+	    errx(EXIT_FAILURE, "failure occurred reading plist: %s",
+		 strerror(serrno));
 	installed = TRUE;
     }
 
-    /* Suck in the contents list */
-    plist.head = plist.tail = NULL;
-    fd = open(CONTENTS_FNAME, O_RDONLY);
-    if (fd == -1) {
-	warnx("unable to open %s file", CONTENTS_FNAME);
-	code = 1;
-	goto bail;
-    }
-    /* If we have a prefix, add it now */
-    rc = read_plist(&plist, fd);
-    serrno = errno;
-    (void) close(fd);
-    if (rc == -1)
-	errx(EXIT_FAILURE, "failure occurred reading plist: %s",
-	    strerror(serrno));
-
     /*
      * Index is special info type that has to override all others to make
      * any sense.
@@ -204,35 +264,42 @@
 	show_index(tmp, COMMENT_FNAME);
     }
     else {
+#define SHOW_FILE(title, fname) {			\
+    if (installed)					\
+	show_file(title, fname);			\
+    else						\
+	show_file_archive(title, fname, files);		\
+}
+
 	/* Start showing the package contents */
 	if (!Quiet)
 	    printf("%sInformation for %s:\n\n", InfoPrefix, pkg);
 	else if (QUIET)
 	    printf("%s%s:", InfoPrefix, pkg);
 	if (Flags & SHOW_COMMENT)
-	    show_file("Comment:\n", COMMENT_FNAME);
+	    SHOW_FILE("Comment:\n", COMMENT_FNAME);
 	if (Flags & SHOW_DEPEND)
 	    show_plist("Depends on:\n", &plist, PLIST_PKGDEP, FALSE);
 	if ((Flags & SHOW_REQBY) && !isemptyfile(REQUIRED_BY_FNAME))
 	    show_file("Required by:\n", REQUIRED_BY_FNAME);
 	if (Flags & SHOW_DESC)
-	    show_file("Description:\n", DESC_FNAME);
+	    SHOW_FILE("Description:\n", DESC_FNAME);
 	if ((Flags & SHOW_DISPLAY) && fexists(DISPLAY_FNAME))
-	    show_file("Install notice:\n", DISPLAY_FNAME);
+	    SHOW_FILE("Install notice:\n", DISPLAY_FNAME);
 	if (Flags & SHOW_PLIST)
 	    show_plist("Packing list:\n", &plist, (plist_t)0, TRUE);
 	if (Flags & SHOW_REQUIRE && fexists(REQUIRE_FNAME))
-	    show_file("Requirements script:\n", REQUIRE_FNAME);
+	    SHOW_FILE("Requirements script:\n", REQUIRE_FNAME);
 	if ((Flags & SHOW_INSTALL) && fexists(INSTALL_FNAME))
-	    show_file("Install script:\n", INSTALL_FNAME);
+	    SHOW_FILE("Install script:\n", INSTALL_FNAME);
 	if ((Flags & SHOW_INSTALL) && fexists(POST_INSTALL_FNAME))
-	    show_file("Post-Install script:\n", POST_INSTALL_FNAME);
+	    SHOW_FILE("Post-Install script:\n", POST_INSTALL_FNAME);
 	if ((Flags & SHOW_DEINSTALL) && fexists(DEINSTALL_FNAME))
-	    show_file("De-Install script:\n", DEINSTALL_FNAME);
+	    SHOW_FILE("De-Install script:\n", DEINSTALL_FNAME);
 	if ((Flags & SHOW_DEINSTALL) && fexists(POST_DEINSTALL_FNAME))
-	    show_file("Post-DeInstall script:\n", POST_DEINSTALL_FNAME);
+	    SHOW_FILE("Post-DeInstall script:\n", POST_DEINSTALL_FNAME);
 	if ((Flags & SHOW_MTREE) && fexists(MTREE_FNAME))
-	    show_file("mtree file:\n", MTREE_FNAME);
+	    SHOW_FILE("mtree file:\n", MTREE_FNAME);
 	if (Flags & SHOW_PREFIX)
 	    show_plist("Prefix(s):\n", &plist, PLIST_CWD, FALSE);
 	if (Flags & SHOW_FILES)
@@ -248,20 +315,18 @@
 	if (!Quiet)
 	    puts(InfoPrefix);
     }
-    free_plist(&plist);
- bail:
-    leave_playpen();
-    if (isTMP)
-	unlink(fname);
+
+    cleanup:
+    if (plist.head != NULL)
+	free_plist(&plist);
+    if (!installed) {
+	archive_read_finish(a);
+	for (i = 0; files[i].flag != 0; i++)
+	    free(files[i].data);
+    }
     return code;
 }
 
-void
-cleanup(void)
-{
-	leave_playpen();
-}
-
 /*
  * Return an absolute path, additionally removing all .'s, ..'s, and extraneous
  * /'s, as realpath() would, but without resolving symlinks, because that can

==== //depot/projects/soc2010/pkg_complete/usr.sbin/pkg_install/info/show.c#2 (text+ko) ====

@@ -55,6 +55,20 @@
 }
 
 void
+show_file_archive(const char *title, const char *fname, 
+		  struct archive_file *files)
+{
+	int i;
+    	for (i = 0; files[i].flag != 0; i++) {
+	    if (strcmp(fname, files[i].fname) == 0) {
+		if (files[i].data != NULL)
+		    printf("%s%s\n", title, files[i].data);
+		break;
+	    }
+	}
+}
+
+void
 show_index(const char *title, const char *fname)
 {
     FILE *fp;



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