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