LCOV - code coverage report
Current view: top level - libpkg - pkg_create.c (source / functions) Hit Total Coverage
Test: cov.info Lines: 147 204 72.1 %
Date: 2015-08-15 Functions: 9 10 90.0 %

          Line data    Source code
       1             : /*-
       2             :  * Copyright (c) 2011-2014 Baptiste Daroussin <bapt@FreeBSD.org>
       3             :  * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
       4             :  * Copyright (c) 2014-2015 Matthew Seaman <matthew@FreeBSD.org>
       5             :  * Copyright (c) 2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
       6             :  * All rights reserved.
       7             :  * 
       8             :  * Redistribution and use in source and binary forms, with or without
       9             :  * modification, are permitted provided that the following conditions
      10             :  * are met:
      11             :  * 1. Redistributions of source code must retain the above copyright
      12             :  *    notice, this list of conditions and the following disclaimer
      13             :  *    in this position and unchanged.
      14             :  * 2. Redistributions in binary form must reproduce the above copyright
      15             :  *    notice, this list of conditions and the following disclaimer in the
      16             :  *    documentation and/or other materials provided with the distribution.
      17             :  * 
      18             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
      19             :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      20             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      21             :  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
      22             :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      23             :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      24             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      25             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      26             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      27             :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      28             :  */
      29             : 
      30             : #include <sys/stat.h>
      31             : 
      32             : #include <errno.h>
      33             : #include <regex.h>
      34             : #include <fcntl.h>
      35             : 
      36             : #include <bsd_compat.h>
      37             : 
      38             : #include "pkg.h"
      39             : #include "private/event.h"
      40             : #include "private/pkg.h"
      41             : 
      42             : #define TICK    100
      43             : 
      44             : static int pkg_create_from_dir(struct pkg *, const char *, struct packing *);
      45             : static void counter_init(const char *what, int64_t max);
      46             : static void counter_count();
      47             : static void counter_end();
      48             : 
      49             : static int
      50          59 : pkg_create_from_dir(struct pkg *pkg, const char *root,
      51             :     struct packing *pkg_archive)
      52             : {
      53             :         char             fpath[MAXPATHLEN];
      54          59 :         struct pkg_file *file = NULL;
      55          59 :         struct pkg_dir  *dir = NULL;
      56             :         int              ret;
      57             :         struct stat      st;
      58          59 :         int64_t          flatsize = 0;
      59             :         int64_t          nfiles;
      60             :         const char      *relocation;
      61             :         hardlinks_t     *hardlinks;
      62             : 
      63          59 :         if (pkg_is_valid(pkg) != EPKG_OK) {
      64           0 :                 pkg_emit_error("the package is not valid");
      65           0 :                 return (EPKG_FATAL);
      66             :         }
      67             : 
      68          59 :         relocation = pkg_kv_get(&pkg->annotations, "relocated");
      69          59 :         if (relocation == NULL)
      70          59 :                 relocation = "";
      71          59 :         if (pkg_rootdir != NULL)
      72           0 :                 relocation = pkg_rootdir;
      73             : 
      74             :         /*
      75             :          * Get / compute size / checksum if not provided in the manifest
      76             :          */
      77             : 
      78          59 :         nfiles = kh_count(pkg->files);
      79          59 :         counter_init("file sizes/checksums", nfiles);
      80             : 
      81          59 :         hardlinks = kh_init_hardlinks();
      82         166 :         while (pkg_files(pkg, &file) == EPKG_OK) {
      83             : 
      84          48 :                 snprintf(fpath, sizeof(fpath), "%s%s%s", root ? root : "",
      85          48 :                     relocation, file->path);
      86             : 
      87          48 :                 if (lstat(fpath, &st) == -1) {
      88           0 :                         pkg_emit_error("file '%s' is missing", fpath);
      89           0 :                         return (EPKG_FATAL);
      90             :                 }
      91             : 
      92          48 :                 if (file->size == 0)
      93          48 :                         file->size = (int64_t)st.st_size;
      94             : 
      95          48 :                 if (st.st_nlink == 1 || !check_for_hardlink(hardlinks, &st)) {
      96          48 :                         flatsize += file->size;
      97             :                 }
      98             : 
      99          48 :                 file->sum = pkg_checksum_generate_file(fpath,
     100             :                     PKG_HASH_TYPE_SHA256_HEX);
     101          48 :                 if (file->sum == NULL)
     102           0 :                         return (EPKG_FATAL);
     103             : 
     104          48 :                 counter_count();
     105             :         }
     106          59 :         kh_destroy_hardlinks(hardlinks);
     107             : 
     108          59 :         counter_end();
     109             : 
     110          59 :         pkg->flatsize = flatsize;
     111             : 
     112          59 :         if (pkg->type == PKG_OLD_FILE) {
     113           0 :                 pkg_emit_error("Cannot create an old format package");
     114           0 :                 return (EPKG_FATAL);
     115             :         } else {
     116             :                 /*
     117             :                  * Register shared libraries used by the package if
     118             :                  * SHLIBS enabled in conf.  Deletes shlib info if not.
     119             :                  */
     120          59 :                 struct sbuf *b = sbuf_new_auto();
     121             : 
     122          59 :                 pkg_analyse_files(NULL, pkg, root);
     123             : 
     124          59 :                 pkg_emit_manifest_sbuf(pkg, b, PKG_MANIFEST_EMIT_COMPACT, NULL);
     125          59 :                 packing_append_buffer(pkg_archive, sbuf_data(b), "+COMPACT_MANIFEST", sbuf_len(b));
     126          59 :                 sbuf_clear(b);
     127          59 :                 pkg_emit_manifest_sbuf(pkg, b, 0, NULL);
     128          59 :                 sbuf_finish(b);
     129          59 :                 packing_append_buffer(pkg_archive, sbuf_data(b), "+MANIFEST", sbuf_len(b));
     130          59 :                 sbuf_delete(b);
     131             :         }
     132             : 
     133          59 :         counter_init("packing files", nfiles);
     134             : 
     135         166 :         while (pkg_files(pkg, &file) == EPKG_OK) {
     136             : 
     137          48 :                 snprintf(fpath, sizeof(fpath), "%s%s%s", root ? root : "",
     138          48 :                     relocation, file->path);
     139             : 
     140         144 :                 ret = packing_append_file_attr(pkg_archive, fpath, file->path,
     141         144 :                     file->uname, file->gname, file->perm, file->fflags);
     142          48 :                 if (developer_mode && ret != EPKG_OK)
     143           0 :                         return (ret);
     144          48 :                 counter_count();
     145             :         }
     146             : 
     147          59 :         counter_end();
     148             : 
     149          59 :         nfiles = kh_count(pkg->dirs);
     150          59 :         counter_init("packing directories", nfiles);
     151             : 
     152         126 :         while (pkg_dirs(pkg, &dir) == EPKG_OK) {
     153           8 :                 snprintf(fpath, sizeof(fpath), "%s%s%s", root ? root : "",
     154           8 :                     relocation, dir->path);
     155             : 
     156          24 :                 ret = packing_append_file_attr(pkg_archive, fpath, dir->path,
     157          24 :                     dir->uname, dir->gname, dir->perm, dir->fflags);
     158           8 :                 if (developer_mode && ret != EPKG_OK)
     159           0 :                         return (ret);
     160           8 :                 counter_count();
     161             :         }
     162             : 
     163          59 :         counter_end();
     164             : 
     165          59 :         return (EPKG_OK);
     166             : }
     167             : 
     168             : static struct packing *
     169          59 : pkg_create_archive(const char *outdir, struct pkg *pkg, pkg_formats format,
     170             :     unsigned required_flags)
     171             : {
     172          59 :         char            *pkg_path = NULL;
     173          59 :         struct packing  *pkg_archive = NULL;
     174             : 
     175             :         /*
     176             :          * Ensure that we have all the information we need
     177             :          */
     178          59 :         if (pkg->type != PKG_OLD_FILE)
     179          59 :                 assert((pkg->flags & required_flags) == required_flags);
     180             : 
     181          59 :         if (mkdirs(outdir) != EPKG_OK)
     182           0 :                 return NULL;
     183             : 
     184          59 :         if (pkg_asprintf(&pkg_path, "%S/%n-%v", outdir, pkg, pkg) == -1) {
     185           0 :                 pkg_emit_errno("pkg_asprintf", "");
     186           0 :                 return (NULL);
     187             :         }
     188             : 
     189          59 :         if (packing_init(&pkg_archive, pkg_path, format, false) != EPKG_OK)
     190           0 :                 pkg_archive = NULL;
     191             : 
     192          59 :         free(pkg_path);
     193             : 
     194          59 :         return pkg_archive;
     195             : }
     196             : 
     197             : static const char * const scripts[] = {
     198             :         "+INSTALL",
     199             :         "+PRE_INSTALL",
     200             :         "+POST_INSTALL",
     201             :         "+POST_INSTALL",
     202             :         "+DEINSTALL",
     203             :         "+PRE_DEINSTALL",
     204             :         "+POST_DEINSTALL",
     205             :         "+UPGRADE",
     206             :         "+PRE_UPGRADE",
     207             :         "+POST_UPGRADE",
     208             :         "pkg-install",
     209             :         "pkg-pre-install",
     210             :         "pkg-post-install",
     211             :         "pkg-deinstall",
     212             :         "pkg-pre-deinstall",
     213             :         "pkg-post-deinstall",
     214             :         "pkg-upgrade",
     215             :         "pkg-pre-upgrade",
     216             :         "pkg-post-upgrade",
     217             :         NULL
     218             : };
     219             : 
     220             : 
     221             : /* The "no concessions to old pkg_tools" variant: just get everything
     222             :  * from the manifest */
     223             : int
     224          41 : pkg_create_from_manifest(const char *outdir, pkg_formats format,
     225             :     const char *rootdir, const char *manifest, const char *plist)
     226             : {
     227          41 :         struct pkg      *pkg = NULL;
     228          41 :         struct packing  *pkg_archive = NULL;
     229             :         char             arch[BUFSIZ];
     230          41 :         int              ret = ENOMEM;
     231          41 :         struct pkg_manifest_key *keys = NULL;
     232             : 
     233          41 :         pkg_debug(1, "Creating package from stage directory: '%s'", rootdir);
     234             : 
     235          41 :         if(pkg_new(&pkg, PKG_FILE) != EPKG_OK) {
     236           0 :                 ret = EPKG_FATAL;
     237           0 :                 goto cleanup;
     238             :         }
     239             : 
     240          41 :         pkg_manifest_keys_new(&keys);
     241          41 :         if ((ret = pkg_parse_manifest_file(pkg, manifest, keys)) != EPKG_OK) {
     242           0 :                 ret = EPKG_FATAL;
     243           0 :                 goto cleanup;
     244             :         }
     245             : 
     246             :         /* if no arch autodetermine it */
     247          41 :         if (pkg->abi == NULL) {
     248          24 :                 pkg_get_myarch(arch, BUFSIZ);
     249          24 :                 pkg->abi = strdup(arch);
     250             :         }
     251             : 
     252          42 :         if (plist != NULL &&
     253           1 :             ports_parse_plist(pkg, plist, rootdir) != EPKG_OK) {
     254           0 :                 ret = EPKG_FATAL;
     255           0 :                 goto cleanup;
     256             :         }
     257             : 
     258             :         /* Create the archive */
     259          41 :         pkg_archive = pkg_create_archive(outdir, pkg, format, 0);
     260          41 :         if (pkg_archive == NULL) {
     261           0 :                 ret = EPKG_FATAL; /* XXX do better */
     262           0 :                 goto cleanup;
     263             :         }
     264             : 
     265          41 :         pkg_create_from_dir(pkg, rootdir, pkg_archive);
     266          41 :         ret = EPKG_OK;
     267             : 
     268             : cleanup:
     269          41 :         free(pkg);
     270          41 :         pkg_manifest_keys_free(keys);
     271          41 :         packing_finish(pkg_archive);
     272             : 
     273          41 :         return (ret);
     274             : }
     275             : 
     276             : static void
     277          25 : pkg_load_from_file(int fd, struct pkg *pkg, pkg_attr attr, const char *path)
     278             : {
     279             : 
     280          25 :         if (faccessat(fd, path, F_OK, 0) == 0) {
     281           0 :                 pkg_debug(1, "Reading: '%s'", path);
     282           0 :                 pkg_set_from_fileat(fd, pkg, attr, path, false);
     283             :         }
     284          25 : }
     285             : 
     286             : int
     287          25 : pkg_create_staged(const char *outdir, pkg_formats format, const char *rootdir,
     288             :     const char *md_dir, char *plist)
     289             : {
     290          25 :         struct pkg      *pkg = NULL;
     291          25 :         struct pkg_file *file = NULL;
     292          25 :         struct pkg_dir  *dir = NULL;
     293          25 :         struct packing  *pkg_archive = NULL;
     294          25 :         char            *manifest = NULL;
     295             :         char             arch[BUFSIZ];
     296          25 :         int              ret = ENOMEM;
     297             :         int              i, mfd;
     298             :         regex_t          preg;
     299             :         regmatch_t       pmatch[2];
     300             :         size_t           size;
     301          25 :         struct pkg_manifest_key *keys = NULL;
     302             : 
     303          25 :         pkg_debug(1, "Creating package from stage directory: '%s'", rootdir);
     304             : 
     305          25 :         if ((mfd = open(md_dir, O_DIRECTORY)) == -1) {
     306           0 :                 pkg_emit_errno("open", md_dir);
     307           0 :                 goto cleanup;
     308             :         }
     309             : 
     310          25 :         if(pkg_new(&pkg, PKG_FILE) != EPKG_OK) {
     311           0 :                 ret = EPKG_FATAL;
     312           0 :                 goto cleanup;
     313             :         }
     314             : 
     315          25 :         pkg_manifest_keys_new(&keys);
     316             :         /* Load the manifest from the metadata directory */
     317          25 :         if ((ret = pkg_parse_manifest_fileat(mfd, pkg, "+MANIFEST", keys))
     318             :             != EPKG_OK) {
     319           0 :                 ret = EPKG_FATAL;
     320           0 :                 goto cleanup;
     321             :         }
     322             : 
     323             :         /* if no descriptions provided then try to get it from a file */
     324          25 :         if (pkg->desc == NULL)
     325           0 :                 pkg_load_from_file(mfd, pkg, PKG_DESC, "+DESC");
     326             : 
     327             :         /* if no message try to get it from a file */
     328          25 :         if (pkg->message == NULL)
     329          25 :                 pkg_load_from_file(mfd, pkg, PKG_MESSAGE, "+DISPLAY");
     330             : 
     331             :         /* if no arch autodetermine it */
     332          25 :         if (pkg->abi == NULL) {
     333           1 :                 pkg_get_myarch(arch, BUFSIZ);
     334           1 :                 pkg->abi = strdup(arch);
     335             :         }
     336             : 
     337         500 :         for (i = 0; scripts[i] != NULL; i++) {
     338         475 :                 if (faccessat(mfd, scripts[i], F_OK, 0) == 0)
     339           0 :                         pkg_addscript_fileat(mfd, pkg, scripts[i]);
     340             :         }
     341             : 
     342          49 :         if (plist != NULL &&
     343          24 :             ports_parse_plist(pkg, plist, rootdir) != EPKG_OK) {
     344           7 :                 ret = EPKG_FATAL;
     345           7 :                 goto cleanup;
     346             :         }
     347             : 
     348          18 :         if (pkg->www == NULL) {
     349           0 :                 if (pkg->desc == NULL) {
     350           0 :                         pkg_emit_error("No www or desc defined in manifest");
     351           0 :                         ret = EPKG_FATAL;
     352           0 :                         goto cleanup;
     353             :                 }
     354           0 :                 regcomp(&preg, "^WWW:[[:space:]]*(.*)$",
     355             :                     REG_EXTENDED|REG_ICASE|REG_NEWLINE);
     356           0 :                 if (regexec(&preg, pkg->desc, 2, pmatch, 0) == 0) {
     357           0 :                         size = pmatch[1].rm_eo - pmatch[1].rm_so;
     358           0 :                         pkg->www = strndup(&pkg->desc[pmatch[1].rm_so], size);
     359             :                 } else {
     360           0 :                         pkg->www = strdup("UNKNOWN");
     361             :                 }
     362           0 :                 regfree(&preg);
     363             :         }
     364             : 
     365             :         /* Create the archive */
     366          18 :         pkg_archive = pkg_create_archive(outdir, pkg, format, 0);
     367          18 :         if (pkg_archive == NULL) {
     368           0 :                 ret = EPKG_FATAL; /* XXX do better */
     369           0 :                 goto cleanup;
     370             :         }
     371             : 
     372             :         /* XXX: autoplist support doesn't work right with meta-ports */
     373             :         if (0 && pkg_files(pkg, &file) != EPKG_OK &&
     374             :             pkg_dirs(pkg, &dir) != EPKG_OK) {
     375             :                 /* Now traverse the file directories, adding to the archive */
     376             :                 packing_append_tree(pkg_archive, md_dir, NULL);
     377             :                 packing_append_tree(pkg_archive, rootdir, "/");
     378             :                 ret = EPKG_OK;
     379             :         } else {
     380          18 :                 ret = pkg_create_from_dir(pkg, rootdir, pkg_archive);
     381             :         }
     382             : 
     383             : 
     384             : cleanup:
     385          25 :         if (mfd != -1)
     386          25 :                 close(mfd);
     387          25 :         free(pkg);
     388          25 :         free(manifest);
     389          25 :         pkg_manifest_keys_free(keys);
     390          25 :         packing_finish(pkg_archive);
     391             : 
     392          25 :         return (ret);
     393             : }
     394             : 
     395             : int
     396           0 : pkg_create_installed(const char *outdir, pkg_formats format, struct pkg *pkg)
     397             : {
     398             :         struct packing  *pkg_archive;
     399             : 
     400           0 :         unsigned         required_flags = PKG_LOAD_DEPS | PKG_LOAD_FILES |
     401             :                 PKG_LOAD_CATEGORIES | PKG_LOAD_DIRS | PKG_LOAD_SCRIPTS |
     402             :                 PKG_LOAD_OPTIONS | PKG_LOAD_LICENSES ;
     403             : 
     404           0 :         assert(pkg->type == PKG_INSTALLED || pkg->type == PKG_OLD_FILE);
     405             : 
     406           0 :         pkg_archive = pkg_create_archive(outdir, pkg, format, required_flags);
     407           0 :         if (pkg_archive == NULL) {
     408           0 :                 pkg_emit_error("unable to create archive");
     409           0 :                 return (EPKG_FATAL);
     410             :         }
     411             : 
     412           0 :         pkg_create_from_dir(pkg, NULL, pkg_archive);
     413             : 
     414           0 :         packing_finish(pkg_archive);
     415             : 
     416           0 :         return (EPKG_OK);
     417             : }
     418             : 
     419             : static int64_t  count;
     420             : static int64_t  maxcount;
     421             : static const char *what;
     422             : 
     423         177 : static int magnitude(int64_t num)
     424             : {
     425             :         int oom;
     426             : 
     427         177 :         if (num == 0)
     428          79 :                 return (1);
     429          98 :         if (num < 0)
     430           0 :                 num = -num;
     431             : 
     432          98 :         for (oom = 1; num >= 10; oom++)
     433           0 :                 num /= 10;
     434             : 
     435          98 :         return (oom);
     436             : }
     437             : 
     438             : static void
     439         177 : counter_init(const char *count_what, int64_t max)
     440             : {
     441         177 :         count = 0;
     442         177 :         what = count_what;
     443         177 :         maxcount = max;
     444         354 :         pkg_emit_progress_start("%-20s%*s[%ld]", what,
     445         177 :             6 - magnitude(maxcount), " ", maxcount);
     446             : 
     447         177 :         return;
     448             : }
     449             : 
     450             : static void
     451         104 : counter_count()
     452             : {
     453         104 :         count++;
     454             : 
     455         104 :         if (count % TICK == 0)
     456           0 :                 pkg_emit_progress_tick(count, maxcount);
     457             : 
     458         104 :         return;
     459             : }
     460             : 
     461             : static void
     462         177 : counter_end()
     463             : {
     464         177 :         pkg_emit_progress_tick(count, maxcount);
     465         177 :         return;
     466             : }

Generated by: LCOV version 1.10