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