tech-pkg archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

pkg_tarup inclusion in pkg_create



Hi,

in the pkg_tarup comments you can read somebody proposing the integration of
pkg_tarup to pkg_admin. pkg_admin is not suited for that, but pkg_create is,
as it is the tool behind pkg_tarup.
I'm not much into the whole packaging thing, but I need this functionality, so
I numbly took over all the functionality of pkg_tarup to pkg_admin.

It adds the option `-e $DIR` to create packages to directory $DIR, optionally
with option `-r` to work on all dependencies as well.

On the way, cleaned options and manpage to match code reality.


After having finished the code, I saw that FreeBSD's pkg_create already can
do that, but whatever... ;-)
Please have a look at the code and comment it. Especially have a look at
pkg_tarup and what it does, perhaps some of the work it's doing is outdated.
This is just what pkg_tarup did.


Regards, Julian

PS: Please CC me in replies as I'm not subscribed to tech-pkg.
--- external/bsd/pkg_install/dist/create/create.h
+++ external/bsd/pkg_install/dist/create/create.h
@@ -23,10 +23,13 @@
  */
 
 #ifndef _INST_CREATE_H_INCLUDE
 #define _INST_CREATE_H_INCLUDE
 
+#define PKG_CREATE     0
+#define PKG_TARUP      1
+
 struct memory_file {
        struct stat st;
        const char *name;
        const char *owner;
        const char *group;
@@ -52,13 +55,15 @@
 extern char *SizeAll;
 extern char *Preserve;
 extern char *realprefix;
 extern char *DefaultOwner;
 extern char *DefaultGroup;
+extern char *TargetDir;
 extern const char *CompressionType;
 extern int PlistOnly;
 extern int RelativeLinks;
+extern int DoDepends;
 extern int update_pkgdb;
 extern int create_views;
 
 void    check_list(package_t *, const char *);
 void    copy_plist(char *, package_t *);
@@ -69,9 +74,10 @@
 struct memory_file
        *make_memory_file(const char *, void *, size_t,
                          const char *, const char *, mode_t);
 void   free_memory_file(struct memory_file *);
 
-int    pkg_perform(const char *);
+int    pkg_create(const char *, FILE *);
+int    pkg_tarup(char *);
 int    pkg_build(const char *, const char *, const char *, package_t *plist);
 
 #endif                         /* _INST_CREATE_H_INCLUDE */

--- external/bsd/pkg_install/dist/create/main.c
+++ external/bsd/pkg_install/dist/create/main.c
@@ -24,11 +24,11 @@
 #include <err.h>
 #endif
 #include "lib.h"
 #include "create.h"
 
-static const char Options[] = 
"B:C:D:EF:I:K:L:OP:S:T:UVb:c:d:f:g:i:k:ln:p:r:s:u:v";
+static const char Options[] = 
"B:C:D:EF:I:K:L:OP:S:T:UVb:c:d:e:f:g:i:k:ln:p:rs:u:v";
 
 char   *Prefix = NULL;
 char   *Comment = NULL;
 char   *Desc = NULL;
 char   *Display = NULL;
@@ -43,31 +43,35 @@
 char   *SizePkg = NULL;
 char   *SizeAll = NULL;
 char   *Preserve = NULL;
 char   *DefaultOwner = NULL;
 char   *DefaultGroup = NULL;
+char   *TargetDir = NULL;
 char   *realprefix = NULL;
 const char *CompressionType = NULL;
 int    update_pkgdb = 1;
 int    create_views = 0;
 int     PlistOnly = 0;
 int     RelativeLinks = 0;
+int     DoDepends = 0;
+int PkgAction = PKG_CREATE;
 Boolean File2Pkg = FALSE;
 
 static void
 usage(void)
 {
        fprintf(stderr,
            "usage: pkg_create [-ElOUVv] [-B build-info-file] [-b 
build-version-file]\n"
             "                  [-C cpkgs] [-D displayfile] [-F compression] \n"
-           "                  [-I realprefix] [-i iscript]\n"
-            "                  [-K pkg_dbdir] [-k dscript]\n"
+                   "                  [-I realprefix] [-i iscript]\n"
+            "                  [-K pkg_dbdir] [-k dscript] [-l] [-O]\n"
             "                  [-n preserve-file] [-P dpkgs] [-p prefix] [-r 
rscript]\n"
             "                  [-S size-all-file] [-s size-pkg-file]\n"
-           "                  [-T buildpkgs] [-u owner] [-g group]\n"
+               "                  [-T buildpkgs] [-U] [-u owner] [-g group]\n"
             "                  -c comment -d description -f packlist\n"
-            "                  pkg-name\n");
+            "                  pkg-name\n"
+                       "   pkg_create -e targetdir [-r] pkg-name ...\n");
        exit(1);
 }
 
 int
 main(int argc, char **argv)
@@ -109,10 +113,19 @@
                        SizePkg = optarg;
                        break;
 
                case 'S':
                        SizeAll = optarg;
+                       break;
+
+               case 'e':
+                       TargetDir = optarg;
+                       PkgAction = PKG_TARUP;
+                       break;
+
+               case 'r':
+                       DoDepends = 1;
                        break;
 
                case 'f':
                        Contents = optarg;
                        break;
@@ -203,15 +216,18 @@
        if (argc != 1) {
                warnx("only one package name allowed");
                usage();
        }
 
-       if (pkg_perform(*argv))
+       if (PkgAction & PKG_CREATE && pkg_create(*argv, NULL))
+               return 0;
+       else if (PkgAction & PKG_TARUP && pkg_tarup(*argv))
                return 0;
+
        if (Verbose) {
                if (PlistOnly)
                        warnx("package registration failed");
                else
                        warnx("package creation failed");
        }
        return 1;
 }

--- external/bsd/pkg_install/dist/create/perform.c
+++ external/bsd/pkg_install/dist/create/perform.c
@@ -41,17 +41,17 @@
 #if HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 
 static void
-sanity_check(void)
+sanity_check(FILE *tmp_in)
 {
        if (!Comment)
                errx(2, "required package comment string is missing (-c 
comment)");
        if (!Desc)
                errx(2, "required package description string is missing (-d 
desc)");
-       if (!Contents)
+       if (!Contents && tmp_in == NULL)
                errx(2, "required package contents list is missing (-f 
[-]file)");
 }
 
 static void
 register_depends(package_t *plist, char *deps, int build_only)
@@ -126,12 +126,302 @@
                *s = xstrdup(*s + 1);
        else
                *s = fileGetContents(*s); 
 }
 
+/* free() orgy */
+static void
+freestrings(char *pkgname, char *pkgpath, char *pkgdir)
+{
+       return; // XXX
+       if (pkgname)
+               free(pkgname);
+       if (pkgpath)
+               free(pkgpath);
+       if (pkgdir)
+               free(pkgdir);
+       if (Comment)
+               free(Comment);
+       if (Desc)
+               free(Desc);
+       if (Display)
+               free(Display);
+       if (Install)
+               free(Install);
+       if (DeInstall)
+               free(DeInstall);
+       if (BuildVersion)
+               free(BuildVersion);
+       if (BuildInfo)
+               free(BuildInfo);
+       if (SizePkg)
+               free(SizePkg);
+       if (SizeAll)
+               free(SizeAll);
+       if (Preserve)
+               free(Preserve);
+}
+
+/* Concatenate a string from a given type of package from list */
+static int
+listtostr(package_t *plist, char **buffer, int type)
+{
+       plist_t *p;
+       int tmplen = BUFSIZ;
+       int i, j;
+
+       *buffer = calloc(1, sizeof(char)*tmplen);
+       i = j = 0;
+       for (p = plist->head; i < (int)(sizeof(char)*tmplen)
+                       && p != NULL; p = p->next) 
+               if (p->type == type) {
+                       if (i == 0) {
+                               i += snprintf(*buffer + i, tmplen - i - 1, 
"%s", p->name);
+                               if (i != j + (int)strlen(p->name)) {
+                                       warn("could not concatenate string");
+                                       return 1;
+                               }
+                       } else {
+                               i += snprintf(*buffer + i, tmplen - i - 1, " 
%s", p->name);
+                               if (i != j + (int)strlen(p->name) + 1) {
+                                       warn("could not concatenate string");
+                                       return 1;
+                               }
+                       }
+                       j = i;
+                       if (i == tmplen - 1) {
+                               warnx("string buffer is full");
+                               return 1;
+                       }
+               }
+       
+       if (strlen(*buffer) == 0) {
+               free(*buffer);
+               *buffer = NULL;
+       }
+
+       return 0;
+}
+
+/* Get package meta information */
+static char *
+get_contentdata(const char *pkgname)
+{
+       char *fname;
+       char *ret;
+       int fd;
+       struct stat st;
+
+       fname = pkgdb_pkg_file(pkgname, CONTENTS_FNAME);
+       fd = open(fname, O_RDONLY, 0);
+       free(fname);
+       if (fd == -1) {
+               warn("cannot read meta data for %s", pkgname);
+               return NULL;
+       }
+
+       if (fstat(fd, &st) == -1) {
+               warn("cannot stat meta data for %s", pkgname);
+               return NULL;
+       } else if ((st.st_mode & S_IFMT) != S_IFREG) {
+               warnx("meta data is not regular file for %s", pkgname);
+               return NULL;
+       } else if (st.st_size > SSIZE_MAX - 1) {
+               warn("meta data file for %s too large to process", pkgname);
+               return NULL;
+       }
+
+       ret = xmalloc(st.st_size + 1);
+       if (read(fd, ret, st.st_size) != st.st_size) {
+               free(ret);
+               warn("cannot read meta data for %s", pkgname);
+               return NULL;
+       }
+       (ret)[st.st_size] = '\0';
+       close(fd);
+
+       return ret;
+}
+
+/* Fill strings with filenames, if they exist */
+static int
+fill_strings(const char *pkgdir)
+{
+       struct stat st;
+       struct tarupspec {
+               char **t_target;
+               const char *t_fname;
+       };
+       struct tarupspec *tmptarup;
+       struct tarupspec tarupvars[] = {
+               { &Comment, COMMENT_FNAME },
+               { &Desc, DESC_FNAME },
+               { &Display, DISPLAY_FNAME },
+               { &Install, INSTALL_FNAME },
+               { &DeInstall, DEINSTALL_FNAME },
+               { &BuildVersion, BUILD_VERSION_FNAME },
+               { &BuildInfo, BUILD_INFO_FNAME },
+               { &SizePkg, SIZE_PKG_FNAME },
+               { &SizeAll, SIZE_ALL_FNAME },
+               { &Preserve, PRESERVE_FNAME },
+               { NULL, NULL }
+       };
+
+       for (tmptarup = tarupvars; tmptarup->t_fname != NULL; tmptarup++) {
+               if (!asprintf(tmptarup->t_target, "%s/%s", pkgdir, 
+                               tmptarup->t_fname)) {
+                       warn("could not allocate string");
+                       return 1;
+               }
+               if (stat(*tmptarup->t_target, &st)) {
+                       free(*tmptarup->t_target);
+                       *tmptarup->t_target = NULL;
+               } else if ((st.st_mode & S_IFMT) != S_IFREG) {
+                       warn("%s is not a file", *tmptarup->t_target);
+                       free(*tmptarup->t_target);
+                       *tmptarup->t_target = NULL;
+               }
+       }
+
+       return 0;
+}
+
+/* Run through the list of packages given, fill the data we should be given 
with 
+ * separate arguments, and run pkg_create on that. */
+int
+pkg_tarup(char *pkglist)
+{
+       package_t plist;
+       char strbuf[MAXPATHLEN+1];
+       char *pkglistbuf = NULL;
+       char *pkgtok, *tokstr, *pkgname, *pkgpath, *pkgdir, *pkgmeta;
+       const char *pkgdb_dir;
+       char *tmpcfile;
+       int ret = 0;
+       int i, done, donenext = 0;
+       FILE   *pkg_in, *tmp_out;
+       const char *ignorekeywords[] = { "@comment MD5:", "@comment Symlink:",
+               "@mtree", "@cwd", "@src", NULL };
+       const char *ignorenext = "@ignore";
+
+       pkgdb_dir = pkgdb_get_dir();
+
+       for (pkgtok = strtok_r(pkglist, " ", &tokstr); pkgtok;
+                       pkgtok = strtok_r(NULL, " ", &tokstr)) {
+
+               /* Get package information */
+               pkgname = find_best_matching_installed_pkg(pkgtok);
+               pkgdir = pkgdb_pkg_dir(pkgname);
+               if (!fexists(pkgdir) || !(isdir(pkgdir) || 
islinktodir(pkgdir))) {
+                       warnx("can't find package `%s'", pkgtok);
+                       ret += 1;
+                       continue;
+               }
+               /* Get metadata and contents list */
+               pkgmeta = get_contentdata(pkgname);
+               if (pkgmeta == NULL) {
+                       warnx("invalid package `%s' skipped", pkgname);
+                       ret += 1;
+                       continue;
+               }
+               parse_plist(&plist, pkgmeta);
+
+               /* Cosmetics to remove slashes */
+               if (TargetDir) {
+                       if ((TargetDir[strlen(TargetDir) - 1] == '/'
+                                       && !asprintf(&pkgpath, "%s%s.tgz", 
TargetDir, pkgname))
+                                       || !asprintf(&pkgpath, "%s/%s.tgz", 
TargetDir, pkgname)) {
+                               warn("could not allocate string");
+                               ret += 1;
+                               continue;
+                       }
+               } else {
+                       pkgpath = pkgname;
+               }
+
+               /* Handle simple values */
+               if (fill_strings(pkgdir)) {
+                       ret += 1;
+                       continue;
+               }
+
+               /* Handle dependencies */
+               if (listtostr(&plist, &Pkgdeps, PLIST_PKGDEP)
+                               || listtostr(&plist, &BuildPkgdeps, 
PLIST_BLDDEP)
+                               || listtostr(&plist, &Pkgcfl, PLIST_PKGCFL)
+                               || listtostr(&plist, &Prefix, PLIST_CWD)) {
+                       ret += 1;
+                       continue;
+               }
+               /* We want only one prefix entry */
+               Prefix = stresep(&Prefix, " ", '\\');
+               realprefix = Prefix;
+               if (DoDepends && Pkgdeps != NULL) {
+                       pkglistbuf = strdup(Pkgdeps);
+               }
+
+               /* Copy old +CONTENT to new +CONTENT */
+               if (!asprintf(&tmpcfile, "%s/%s", pkgdir, CONTENTS_FNAME)) {
+                       warn("could not allocate string");
+                       ret += 1;
+                       continue;
+               }
+               pkg_in = fopen(tmpcfile, "r");
+               if (!pkg_in)
+                       errx(2, "unable to open contents file '%s' for input", 
tmpcfile);
+               free(tmpcfile);
+               if (!asprintf(&tmpcfile, "/tmp/+CONTENTS.XXXXXX")) {
+                       warn("could not allocate string");
+                       ret += 1;
+                       continue;
+               }
+               i = mkstemp(tmpcfile);
+               if (i == -1 || !(tmp_out = fdopen(i, "w+")))
+                       errx(2, "unable to open temporary file '%s'", Contents);
+
+               bzero(strbuf, sizeof(strbuf));
+               while (fgets(strbuf, sizeof(strbuf), pkg_in)) {
+                       done = 0;
+                       if (!donenext) {
+                               for (i = 0; ignorekeywords[i] != NULL; i++)
+                                       if (!strncmp(ignorekeywords[i], strbuf, 
strlen(ignorekeywords[i]))) {
+                                               done = 1;
+                                               break;
+                                       }
+
+                               if (!done && !strncmp(ignorenext, strbuf, 
strlen(ignorenext))) {
+                                       done = 1;
+                                       donenext = 1;
+                               }
+
+                               if (!done && !donenext) {
+                                       fputs(strbuf, tmp_out);
+                       //              fputc('\n', tmp_out);
+                               }
+                       } else {
+                               donenext = 0;
+                       }
+               }
+               fclose(pkg_in);
+               rewind(tmp_out);
+
+               ret += pkg_create(pkgpath, tmp_out);
+               /* Clean up strings */
+               unlink(tmpcfile);
+               freestrings(pkgname, pkgpath, pkgdir);
+       }
+
+       // XXX: This could be put to main.c to save memory.
+       if (pkglistbuf != NULL) {
+               ret += pkg_tarup(pkglistbuf);
+               free(pkglistbuf);
+       }
+       return ret;
+}
+
 int
-pkg_perform(const char *pkg)
+pkg_create(const char *pkg, FILE *tmp_in)
 {
        char   *cp;
        FILE   *pkg_in;
        package_t plist;
        const char *full_pkg, *suffix;
@@ -151,18 +441,20 @@
                full_pkg = pkg;
                suffix = "tgz";
        }
 
        /* Preliminary setup */
-       sanity_check();
-       if (Verbose && !PlistOnly)
+       sanity_check(tmp_in);
+       if (!PlistOnly)
                printf("Creating package %s\n", pkg);
        get_dash_string(&Comment);
        get_dash_string(&Desc);
-       if (IS_STDIN(Contents))
+       if (tmp_in != NULL) {
+               pkg_in = tmp_in;
+       } else if (IS_STDIN(Contents)) {
                pkg_in = stdin;
-       else {
+       } else {
                pkg_in = fopen(Contents, "r");
                if (!pkg_in)
                        errx(2, "unable to open contents file '%s' for input", 
Contents);
        }
 
@@ -192,11 +484,11 @@
                        }
                }
                if (Verbose && !PlistOnly)
                        printf(".\n");
        }
-
+       
        /* Slurp in the packing list */
        append_plist(&plist, pkg_in);
 
        if (pkg_in != stdin)
                fclose(pkg_in);
@@ -216,13 +508,13 @@
 
        /* Make first "real contents" pass over it */
        check_list(&plist, basename_of(pkg));
 
        /*
-         * We're just here for to dump out a revised plist for the FreeBSD 
ports
-         * hack.  It's not a real create in progress.
-         */
+        * We're just here for to dump out a revised plist for the FreeBSD ports
+        * hack.  It's not a real create in progress.
+        */
        if (PlistOnly) {
                write_plist(&plist, stdout, realprefix);
                retval = TRUE;
        } else {
 #ifdef BOOTSTRAP

--- external/bsd/pkg_install/dist/create/pkg_create.1
+++ external/bsd/pkg_install/dist/create/pkg_create.1
@@ -95,15 +95,33 @@
 .Ek
 .Bk -words
 .Fl f Ar packlist
 .Ek
 .Ar pkg-name
+.Nm
+.Bk -words
+.Fl e Ar targetdir
+.Ek
+.Bk -words
+.Op Fl r
+.Ek
+.Ar pkg-name ...
 .Sh DESCRIPTION
 The
 .Nm
 command is used to create packages that will subsequently be fed to
 one of the package extraction/info utilities.
+.Pp
+.Nm
+has two modes: The package creation mode from existing packages, i.e. used
+with
+.Fl e
+to pack the installed package(s)
+.Ar pkg-name ...
+so they can be backed up etc.
+.Pp
+The other mode is for creation from scratch.
 The input description and command line arguments for the creation of a
 package are not really meant to be human-generated, though it is easy
 enough to do so.
 It is more expected that you will use a front-end tool for
 the job rather than muddling through it yourself.
@@ -158,10 +176,13 @@
 or, if preceded by
 .Cm - ,
 the argument itself.
 .It Fl E
 Add an empty views file to the package.
+.It Fl e
+Create a package from an existing package, saving them to directory
+.Ar targetdir .
 .It Fl F Ar compression
 Use
 .Ar compression
 as compression algorithm.
 This overrides the heuristic to guess the compression type from the
@@ -254,10 +275,13 @@
 .Ar prefix
 as the initial directory
 .Pq base
 to start from in selecting files for
 the package.
+.It Fl r
+Resolve dependencies. Only used in conjunction with
+.Fl e .
 .It Fl S Ar size-all-file
 Store the given file for later querying with the
 .Xr pkg_info 1
 .Fl S
 flag.
@@ -269,26 +293,10 @@
 .Xr pkg_info 1
 .Fl s
 flag.
 The file is expected to contain the size (in bytes) of all files of
 this package added up and stored as a ASCII string, terminated by a newline.
-.It Fl t Ar template
-Use
-.Ar template
-as the input to
-.Xr mktemp 3 .
-By default, this is the string
-.Pa /tmp/instmp.XXXXXX ,
-but it may be necessary to override it in the situation where
-space in your
-.Pa /tmp
-directory is limited.
-Be sure to leave some number of
-.Sq X
-characters for
-.Xr mktemp 3
-to fill in with a unique ID.
 .It Fl U
 Do not update the package file database with any file information.
 .It Fl u Ar owner
 Make
 .Ar owner

Attachment: signature.asc
Description: PGP signature



Home | Main Index | Thread Index | Old Index