LCOV - code coverage report
Current view: top level - src/deb - build.c (source / functions) Hit Total Coverage
Test: dpkg 1.21.11 C code coverage Lines: 251 314 79.9 %
Date: 2022-12-03 00:40:01 Functions: 15 16 93.8 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 116 176 65.9 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * dpkg-deb - construction and deconstruction of *.deb archives
       3                 :            :  * build.c - building archives
       4                 :            :  *
       5                 :            :  * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
       6                 :            :  * Copyright © 2000,2001 Wichert Akkerman <wakkerma@debian.org>
       7                 :            :  * Copyright © 2007-2015 Guillem Jover <guillem@debian.org>
       8                 :            :  *
       9                 :            :  * This is free software; you can redistribute it and/or modify
      10                 :            :  * it under the terms of the GNU General Public License as published by
      11                 :            :  * the Free Software Foundation; either version 2 of the License, or
      12                 :            :  * (at your option) any later version.
      13                 :            :  *
      14                 :            :  * This is distributed in the hope that it will be useful,
      15                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17                 :            :  * GNU General Public License for more details.
      18                 :            :  *
      19                 :            :  * You should have received a copy of the GNU General Public License
      20                 :            :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21                 :            :  */
      22                 :            : 
      23                 :            : #include <config.h>
      24                 :            : #include <compat.h>
      25                 :            : 
      26                 :            : #include <sys/types.h>
      27                 :            : #include <sys/stat.h>
      28                 :            : #include <sys/wait.h>
      29                 :            : 
      30                 :            : #include <errno.h>
      31                 :            : #include <limits.h>
      32                 :            : #include <inttypes.h>
      33                 :            : #include <string.h>
      34                 :            : #include <time.h>
      35                 :            : #include <dirent.h>
      36                 :            : #include <fcntl.h>
      37                 :            : #include <unistd.h>
      38                 :            : #include <stdbool.h>
      39                 :            : #include <stdint.h>
      40                 :            : #include <stdlib.h>
      41                 :            : #include <stdio.h>
      42                 :            : 
      43                 :            : #include <dpkg/i18n.h>
      44                 :            : #include <dpkg/c-ctype.h>
      45                 :            : #include <dpkg/dpkg.h>
      46                 :            : #include <dpkg/dpkg-db.h>
      47                 :            : #include <dpkg/path.h>
      48                 :            : #include <dpkg/treewalk.h>
      49                 :            : #include <dpkg/varbuf.h>
      50                 :            : #include <dpkg/fdio.h>
      51                 :            : #include <dpkg/buffer.h>
      52                 :            : #include <dpkg/subproc.h>
      53                 :            : #include <dpkg/command.h>
      54                 :            : #include <dpkg/compress.h>
      55                 :            : #include <dpkg/ar.h>
      56                 :            : #include <dpkg/options.h>
      57                 :            : 
      58                 :            : #include "dpkg-deb.h"
      59                 :            : 
      60                 :            : static void
      61                 :         10 : control_treewalk_feed(const char *dir, int fd_out)
      62                 :            : {
      63                 :            :   struct treeroot *tree;
      64                 :            :   struct treenode *node;
      65                 :            : 
      66                 :         10 :   tree = treewalk_open(dir, TREEWALK_NONE, NULL);
      67         [ +  + ]:         33 :   for (node = treewalk_node(tree); node; node = treewalk_next(tree)) {
      68                 :            :     char *nodename;
      69                 :            : 
      70                 :         23 :     nodename = str_fmt("./%s", treenode_get_virtname(node));
      71         [ -  + ]:         23 :     if (fd_write(fd_out, nodename, strlen(nodename) + 1) < 0)
      72                 :          0 :       ohshite(_("failed to write filename to tar pipe (%s)"),
      73                 :            :               _("control member"));
      74                 :         23 :     free(nodename);
      75                 :            :   }
      76                 :         10 :   treewalk_close(tree);
      77                 :         10 : }
      78                 :            : 
      79                 :            : /**
      80                 :            :  * Simple structure to store information about a file.
      81                 :            :  */
      82                 :            : struct file_info {
      83                 :            :   struct file_info *next;
      84                 :            :   char *fn;
      85                 :            : };
      86                 :            : 
      87                 :            : static struct file_info *
      88                 :          5 : file_info_new(const char *filename)
      89                 :            : {
      90                 :            :   struct file_info *fi;
      91                 :            : 
      92                 :          5 :   fi = m_malloc(sizeof(*fi));
      93                 :          5 :   fi->fn = m_strdup(filename);
      94                 :          5 :   fi->next = NULL;
      95                 :            : 
      96                 :          5 :   return fi;
      97                 :            : }
      98                 :            : 
      99                 :            : static void
     100                 :          5 : file_info_free(struct file_info *fi)
     101                 :            : {
     102                 :          5 :   free(fi->fn);
     103                 :          5 :   free(fi);
     104                 :          5 : }
     105                 :            : 
     106                 :            : static struct file_info *
     107                 :          7 : file_info_find_name(struct file_info *list, const char *filename)
     108                 :            : {
     109                 :            :   struct file_info *node;
     110                 :            : 
     111         [ +  + ]:          9 :   for (node = list; node; node = node->next)
     112         [ +  + ]:          4 :     if (strcmp(node->fn, filename) == 0)
     113                 :          2 :       return node;
     114                 :            : 
     115                 :          5 :   return NULL;
     116                 :            : }
     117                 :            : 
     118                 :            : /**
     119                 :            :  * Add a new file_info struct to a single linked list of file_info structs.
     120                 :            :  *
     121                 :            :  * We perform a slight optimization to work around a ‘feature’ in tar: tar
     122                 :            :  * always recurses into subdirectories if you list a subdirectory. So if an
     123                 :            :  * entry is added and the previous entry in the list is its subdirectory we
     124                 :            :  * remove the subdirectory.
     125                 :            :  *
     126                 :            :  * After a file_info struct is added to a list it may no longer be freed, we
     127                 :            :  * assume full responsibility for its memory.
     128                 :            :  */
     129                 :            : static void
     130                 :          5 : file_info_list_append(struct file_info **head, struct file_info **tail,
     131                 :            :                       struct file_info *fi)
     132                 :            : {
     133         [ +  + ]:          5 :   if (*head == NULL)
     134                 :          3 :     *head = *tail = fi;
     135                 :            :   else
     136                 :          2 :     *tail = (*tail)->next =fi;
     137                 :          5 : }
     138                 :            : 
     139                 :            : /**
     140                 :            :  * Free the memory for all entries in a list of file_info structs.
     141                 :            :  */
     142                 :            : static void
     143                 :         12 : file_info_list_free(struct file_info *fi)
     144                 :            : {
     145         [ +  + ]:         17 :   while (fi) {
     146                 :            :     struct file_info *fl;
     147                 :            : 
     148                 :          5 :     fl=fi; fi=fi->next;
     149                 :          5 :     file_info_free(fl);
     150                 :            :   }
     151                 :         12 : }
     152                 :            : 
     153                 :            : static void
     154                 :         10 : file_treewalk_feed(const char *dir, int fd_out)
     155                 :            : {
     156                 :            :   struct treeroot *tree;
     157                 :            :   struct treenode *node;
     158                 :            :   struct file_info *fi;
     159                 :         10 :   struct file_info *symlist = NULL;
     160                 :         10 :   struct file_info *symlist_end = NULL;
     161                 :            : 
     162                 :         10 :   tree = treewalk_open(dir, TREEWALK_NONE, NULL);
     163         [ +  + ]:         48 :   for (node = treewalk_node(tree); node ; node = treewalk_next(tree)) {
     164                 :         39 :     const char *virtname = treenode_get_virtname(node);
     165                 :            :     char *nodename;
     166                 :            : 
     167         [ +  + ]:         39 :     if (strncmp(virtname, BUILDCONTROLDIR, strlen(BUILDCONTROLDIR)) == 0)
     168                 :         23 :       continue;
     169                 :            : 
     170                 :         16 :     nodename = str_fmt("./%s", virtname);
     171                 :            : 
     172   [ +  -  +  + ]:         16 :     if (!nocheckflag && strchr(nodename, '\n'))
     173                 :          1 :       ohshit(_("newline not allowed in pathname '%s'"), nodename);
     174                 :            : 
     175                 :            :     /* We need to reorder the files so we can make sure that symlinks
     176                 :            :      * will not appear before their target. */
     177         [ -  + ]:         15 :     if (S_ISLNK(treenode_get_mode(node))) {
     178                 :          0 :       fi = file_info_new(nodename);
     179                 :          0 :       file_info_list_append(&symlist, &symlist_end, fi);
     180                 :            :     } else {
     181         [ -  + ]:         15 :       if (fd_write(fd_out, nodename, strlen(nodename) + 1) < 0)
     182                 :          0 :         ohshite(_("failed to write filename to tar pipe (%s)"),
     183                 :            :                 _("data member"));
     184                 :            :     }
     185                 :            : 
     186                 :         15 :     free(nodename);
     187                 :            :   }
     188                 :          9 :   treewalk_close(tree);
     189                 :            : 
     190         [ -  + ]:          9 :   for (fi = symlist; fi; fi = fi->next)
     191         [ #  # ]:          0 :     if (fd_write(fd_out, fi->fn, strlen(fi->fn) + 1) < 0)
     192                 :          0 :       ohshite(_("failed to write filename to tar pipe (%s)"), _("data member"));
     193                 :            : 
     194                 :          9 :   file_info_list_free(symlist);
     195                 :          9 : }
     196                 :            : 
     197                 :            : static const char *const maintainerscripts[] = {
     198                 :            :   PREINSTFILE,
     199                 :            :   POSTINSTFILE,
     200                 :            :   PRERMFILE,
     201                 :            :   POSTRMFILE,
     202                 :            :   MAINTSCRIPT_FILE_CONFIG,
     203                 :            :   NULL,
     204                 :            : };
     205                 :            : 
     206                 :            : /**
     207                 :            :  * Check control directory and file permissions.
     208                 :            :  */
     209                 :            : static void
     210                 :         19 : check_file_perms(const char *ctrldir)
     211                 :            : {
     212                 :         19 :   struct varbuf path = VARBUF_INIT;
     213                 :            :   const char *const *mscriptp;
     214                 :            :   struct stat mscriptstab;
     215                 :            : 
     216                 :         19 :   varbuf_printf(&path, "%s/", ctrldir);
     217         [ -  + ]:         19 :   if (lstat(path.buf, &mscriptstab))
     218                 :          0 :     ohshite(_("unable to stat control directory"));
     219         [ -  + ]:         19 :   if (!S_ISDIR(mscriptstab.st_mode))
     220                 :          0 :     ohshit(_("control directory is not a directory"));
     221         [ -  + ]:         19 :   if ((mscriptstab.st_mode & 07757) != 0755)
     222                 :          0 :     ohshit(_("control directory has bad permissions %03lo "
     223                 :            :              "(must be >=0755 and <=0775)"),
     224                 :          0 :            (unsigned long)(mscriptstab.st_mode & 07777));
     225                 :            : 
     226         [ +  + ]:        114 :   for (mscriptp = maintainerscripts; *mscriptp; mscriptp++) {
     227                 :         95 :     varbuf_reset(&path);
     228                 :         95 :     varbuf_printf(&path, "%s/%s", ctrldir, *mscriptp);
     229         [ -  + ]:         95 :     if (!lstat(path.buf, &mscriptstab)) {
     230         [ #  # ]:          0 :       if (S_ISLNK(mscriptstab.st_mode))
     231                 :          0 :         continue;
     232         [ #  # ]:          0 :       if (!S_ISREG(mscriptstab.st_mode))
     233                 :          0 :         ohshit(_("maintainer script '%.50s' is not a plain file or symlink"),
     234                 :            :                *mscriptp);
     235         [ #  # ]:          0 :       if ((mscriptstab.st_mode & 07557) != 0555)
     236                 :          0 :         ohshit(_("maintainer script '%.50s' has bad permissions %03lo "
     237                 :            :                  "(must be >=0555 and <=0775)"),
     238                 :          0 :                *mscriptp, (unsigned long)(mscriptstab.st_mode & 07777));
     239         [ -  + ]:         95 :     } else if (errno != ENOENT) {
     240                 :          0 :       ohshite(_("maintainer script '%.50s' is not stattable"), *mscriptp);
     241                 :            :     }
     242                 :            :   }
     243                 :            : 
     244                 :         19 :   varbuf_destroy(&path);
     245                 :         19 : }
     246                 :            : 
     247                 :            : /**
     248                 :            :  * Check if conffiles contains sane information.
     249                 :            :  */
     250                 :            : static void
     251                 :         19 : check_conffiles(const char *ctrldir, const char *rootdir)
     252                 :            : {
     253                 :            :   FILE *cf;
     254                 :         19 :   struct varbuf controlfile = VARBUF_INIT;
     255                 :            :   char conffilenamebuf[MAXCONFFILENAME + 1];
     256                 :         19 :   struct file_info *conffiles_head = NULL;
     257                 :         19 :   struct file_info *conffiles_tail = NULL;
     258                 :            : 
     259                 :         19 :   varbuf_printf(&controlfile, "%s/%s", ctrldir, CONFFILESFILE);
     260                 :            : 
     261                 :         19 :   cf = fopen(controlfile.buf, "r");
     262         [ +  + ]:         19 :   if (cf == NULL) {
     263         [ +  - ]:          7 :     if (errno == ENOENT) {
     264                 :          7 :       varbuf_destroy(&controlfile);
     265                 :          7 :       return;
     266                 :            :     }
     267                 :            : 
     268                 :          0 :     ohshite(_("error opening conffiles file"));
     269                 :            :   }
     270                 :            : 
     271         [ +  + ]:         19 :   while (fgets(conffilenamebuf, MAXCONFFILENAME + 1, cf)) {
     272                 :            :     struct stat controlstab;
     273                 :         16 :     char *conffilename = conffilenamebuf;
     274                 :            :     int n;
     275                 :         16 :     bool remove_on_upgrade = false;
     276                 :            : 
     277                 :         16 :     n = strlen(conffilename);
     278         [ -  + ]:         16 :     if (!n)
     279                 :          0 :       ohshite(_("empty string from fgets reading conffiles"));
     280                 :            : 
     281         [ +  + ]:         16 :     if (conffilename[n - 1] != '\n')
     282                 :          2 :       ohshit(_("conffile name '%s' is too long, or missing final newline"),
     283                 :            :              conffilename);
     284                 :            : 
     285                 :         14 :     conffilename[--n] = '\0';
     286                 :            : 
     287         [ +  + ]:         14 :     if (c_isspace(conffilename[0])) {
     288                 :            :       /* The conffiles lines cannot start with whitespace; by handling this
     289                 :            :        * case now, we simplify the remaining code. Move past the whitespace
     290                 :            :        * to give a better error. */
     291         [ +  + ]:          6 :       while (c_isspace(conffilename[0]))
     292                 :          4 :         conffilename++;
     293         [ +  + ]:          2 :       if (conffilename[0] == '\0')
     294                 :          1 :           ohshit(_("empty and whitespace-only lines are not allowed in "
     295                 :            :                    "conffiles"));
     296                 :          1 :       ohshit(_("line with conffile filename '%s' has leading white spaces"),
     297                 :            :              conffilename);
     298                 :            :     }
     299                 :            : 
     300         [ +  + ]:         12 :     if (conffilename[0] != '/') {
     301                 :          9 :       char *flag = conffilename;
     302                 :          9 :       char *flag_end = strchr(flag, ' ');
     303                 :            : 
     304         [ +  + ]:          9 :       if (flag_end) {
     305                 :          8 :         conffilename = flag_end + 1;
     306                 :          8 :         n -= conffilename - flag;
     307                 :            :       }
     308                 :            : 
     309                 :            :       /* If no flag separator is found, assume a missing leading slash. */
     310   [ +  +  +  +  :          9 :       if (flag_end == NULL || (conffilename[0] && conffilename[0] != '/'))
                   +  + ]
     311                 :          2 :         ohshit(_("conffile name '%s' is not an absolute pathname"), conffilename);
     312                 :            : 
     313                 :          7 :       flag_end[0] = '\0';
     314                 :            : 
     315                 :            :       /* Otherwise assume a missing filename after the flag separator. */
     316         [ +  + ]:          7 :       if (conffilename[0] == '\0')
     317                 :          1 :         ohshit(_("conffile name missing after flag '%s'"), flag);
     318                 :            : 
     319         [ +  + ]:          6 :       if (strcmp(flag, "remove-on-upgrade") == 0)
     320                 :          5 :         remove_on_upgrade = true;
     321                 :            :       else
     322                 :          1 :         ohshit(_("unknown flag '%s' for conffile '%s'"), flag, conffilename);
     323                 :            :     }
     324                 :            : 
     325                 :          8 :     varbuf_reset(&controlfile);
     326                 :          8 :     varbuf_printf(&controlfile, "%s%s", rootdir, conffilename);
     327         [ +  + ]:          8 :     if (lstat(controlfile.buf, &controlstab)) {
     328         [ +  - ]:          4 :       if (errno == ENOENT) {
     329   [ +  -  -  + ]:          4 :         if ((n > 1) && c_isspace(conffilename[n - 1]))
     330                 :          0 :           warning(_("conffile filename '%s' contains trailing white spaces"),
     331                 :            :                   conffilename);
     332         [ -  + ]:          4 :         if (!remove_on_upgrade)
     333                 :          0 :           ohshit(_("conffile '%.250s' does not appear in package"), conffilename);
     334                 :            :       } else
     335                 :          0 :         ohshite(_("conffile '%.250s' is not stattable"), conffilename);
     336         [ +  + ]:          4 :     } else if (remove_on_upgrade) {
     337                 :          1 :         ohshit(_("conffile '%s' is present but is requested to be removed"),
     338                 :            :                conffilename);
     339         [ -  + ]:          3 :     } else if (!S_ISREG(controlstab.st_mode)) {
     340                 :          0 :       warning(_("conffile '%s' is not a plain file"), conffilename);
     341                 :            :     }
     342                 :            : 
     343         [ +  + ]:          7 :     if (file_info_find_name(conffiles_head, conffilename)) {
     344                 :          2 :       warning(_("conffile name '%s' is duplicated"), conffilename);
     345                 :            :     } else {
     346                 :            :       struct file_info *conffile;
     347                 :            : 
     348                 :          5 :       conffile = file_info_new(conffilename);
     349                 :          5 :       file_info_list_append(&conffiles_head, &conffiles_tail, conffile);
     350                 :            :     }
     351                 :            :   }
     352                 :            : 
     353                 :          3 :   file_info_list_free(conffiles_head);
     354                 :          3 :   varbuf_destroy(&controlfile);
     355                 :            : 
     356         [ -  + ]:          3 :   if (ferror(cf))
     357                 :          0 :     ohshite(_("error reading conffiles file"));
     358                 :          3 :   fclose(cf);
     359                 :            : }
     360                 :            : 
     361                 :            : /**
     362                 :            :  * Check the control file.
     363                 :            :  *
     364                 :            :  * @param ctrldir The directory from where to build the binary package.
     365                 :            :  * @return The pkginfo struct from the parsed control file.
     366                 :            :  */
     367                 :            : static struct pkginfo *
     368                 :         19 : check_control_file(const char *ctrldir)
     369                 :            : {
     370                 :            :   struct pkginfo *pkg;
     371                 :            :   char *controlfile;
     372                 :            : 
     373                 :         19 :   controlfile = str_fmt("%s/%s", ctrldir, CONTROLFILE);
     374                 :         19 :   parsedb(controlfile, pdb_parse_binary, &pkg);
     375                 :            : 
     376                 :         19 :   if (strspn(pkg->set->name, "abcdefghijklmnopqrstuvwxyz0123456789+-.") !=
     377         [ -  + ]:         19 :       strlen(pkg->set->name))
     378                 :          0 :     ohshit(_("package name has characters that aren't lowercase alphanums or '-+.'"));
     379         [ +  - ]:         19 :   if (pkg->available.arch->type == DPKG_ARCH_NONE ||
     380         [ -  + ]:         19 :       pkg->available.arch->type == DPKG_ARCH_EMPTY)
     381                 :          0 :     ohshit(_("package architecture is missing or empty"));
     382         [ -  + ]:         19 :   if (pkg->priority == PKG_PRIO_OTHER)
     383                 :          0 :     warning(_("'%s' contains user-defined Priority value '%s'"),
     384                 :          0 :             controlfile, pkg->otherpriority);
     385                 :            : 
     386                 :         19 :   free(controlfile);
     387                 :            : 
     388                 :         19 :   return pkg;
     389                 :            : }
     390                 :            : 
     391                 :            : /**
     392                 :            :  * Perform some sanity checks on the to-be-built package control area.
     393                 :            :  *
     394                 :            :  * @param ctrldir The directory from where to build the binary package.
     395                 :            :  * @return The pkginfo struct from the parsed control file.
     396                 :            :  */
     397                 :            : static struct pkginfo *
     398                 :         19 : check_control_area(const char *ctrldir, const char *rootdir)
     399                 :            : {
     400                 :            :   struct pkginfo *pkg;
     401                 :            :   int warns;
     402                 :            : 
     403                 :            :   /* Start by reading in the control file so we can check its contents. */
     404                 :         19 :   pkg = check_control_file(ctrldir);
     405                 :         19 :   check_file_perms(ctrldir);
     406                 :         19 :   check_conffiles(ctrldir, rootdir);
     407                 :            : 
     408                 :         10 :   warns = warning_get_count();
     409         [ +  + ]:         10 :   if (warns)
     410                 :          3 :     warning(P_("ignoring %d warning about the control file(s)",
     411                 :            :                "ignoring %d warnings about the control file(s)", warns),
     412                 :            :             warns);
     413                 :            : 
     414                 :         10 :   return pkg;
     415                 :            : }
     416                 :            : 
     417                 :            : /**
     418                 :            :  * Generate the pathname for the destination binary package.
     419                 :            :  *
     420                 :            :  * If the pathname cannot be computed, because the destination is a directory,
     421                 :            :  * then NULL will be returned.
     422                 :            :  *
     423                 :            :  * @param dir   The directory from where to build the binary package.
     424                 :            :  * @param dest  The destination name, either a file or directory name.
     425                 :            :  * @return      The pathname for the package being built.
     426                 :            :  */
     427                 :            : static char *
     428                 :         19 : gen_dest_pathname(const char *dir, const char *dest)
     429                 :            : {
     430         [ +  + ]:         19 :   if (dest) {
     431                 :            :     struct stat dest_stab;
     432                 :            : 
     433         [ +  - ]:         10 :     if (stat(dest, &dest_stab)) {
     434         [ -  + ]:         10 :       if (errno != ENOENT)
     435                 :          0 :         ohshite(_("unable to check for existence of archive '%.250s'"), dest);
     436         [ #  # ]:          0 :     } else if (S_ISDIR(dest_stab.st_mode)) {
     437                 :            :       /* Need to compute the destination name from the package control file. */
     438                 :          0 :       return NULL;
     439                 :            :     }
     440                 :            : 
     441                 :         10 :     return m_strdup(dest);
     442                 :            :   } else {
     443                 :            :     char *pathname;
     444                 :            : 
     445                 :          9 :     pathname = m_malloc(strlen(dir) + sizeof(DEBEXT));
     446                 :          9 :     strcpy(pathname, dir);
     447                 :          9 :     path_trim_slash_slashdot(pathname);
     448                 :          9 :     strcat(pathname, DEBEXT);
     449                 :            : 
     450                 :          9 :     return pathname;
     451                 :            :   }
     452                 :            : }
     453                 :            : 
     454                 :            : /**
     455                 :            :  * Generate the pathname for the destination binary package from control file.
     456                 :            :  *
     457                 :            :  * @return The pathname for the package being built.
     458                 :            :  */
     459                 :            : static char *
     460                 :          0 : gen_dest_pathname_from_pkg(const char *dir, struct pkginfo *pkg)
     461                 :            : {
     462                 :          0 :   return str_fmt("%s/%s_%s_%s%s", dir, pkg->set->name,
     463                 :          0 :                  versiondescribe(&pkg->available.version, vdew_never),
     464                 :          0 :                  pkg->available.arch->name, DEBEXT);
     465                 :            : }
     466                 :            : 
     467                 :            : typedef void filenames_feed_func(const char *dir, int fd_out);
     468                 :            : 
     469                 :            : struct tar_pack_options {
     470                 :            :   intmax_t timestamp;
     471                 :            :   const char *mode;
     472                 :            :   bool root_owner_group;
     473                 :            : };
     474                 :            : 
     475                 :            : /**
     476                 :            :  * Pack the contents of a directory into a tarball.
     477                 :            :  */
     478                 :            : static void
     479                 :         20 : tarball_pack(const char *dir, filenames_feed_func *tar_filenames_feeder,
     480                 :            :              struct tar_pack_options *options,
     481                 :            :              struct compress_params *tar_compress_params, int fd_out)
     482                 :            : {
     483                 :            :   int pipe_filenames[2], pipe_tarball[2];
     484                 :            :   pid_t pid_tar, pid_comp;
     485                 :            : 
     486                 :            :   /* Fork off a tar. We will feed it a list of filenames on stdin later. */
     487                 :         20 :   m_pipe(pipe_filenames);
     488                 :         20 :   m_pipe(pipe_tarball);
     489                 :         20 :   pid_tar = subproc_fork();
     490         [ +  + ]:         40 :   if (pid_tar == 0) {
     491                 :            :     struct command cmd;
     492                 :            :     char mtime[50];
     493                 :            : 
     494                 :         20 :     m_dup2(pipe_filenames[0], 0);
     495                 :         20 :     close(pipe_filenames[0]);
     496                 :         20 :     close(pipe_filenames[1]);
     497                 :         20 :     m_dup2(pipe_tarball[1], 1);
     498                 :         20 :     close(pipe_tarball[0]);
     499                 :         20 :     close(pipe_tarball[1]);
     500                 :            : 
     501         [ -  + ]:         20 :     if (chdir(dir))
     502                 :          0 :       ohshite(_("failed to chdir to '%.255s'"), dir);
     503                 :            : 
     504                 :         20 :     snprintf(mtime, sizeof(mtime), "@%jd", options->timestamp);
     505                 :            : 
     506                 :         20 :     command_init(&cmd, TAR, "tar -cf");
     507                 :         20 :     command_add_args(&cmd, "tar", "-cf", "-", "--format=gnu",
     508                 :            :                            "--mtime", mtime, "--clamp-mtime", NULL);
     509                 :            :     /* Mode might become a positional argument, pass it before -T. */
     510         [ +  + ]:         20 :     if (options->mode)
     511                 :         10 :       command_add_args(&cmd, "--mode", options->mode, NULL);
     512         [ +  + ]:         20 :     if (options->root_owner_group)
     513                 :         13 :       command_add_args(&cmd, "--owner", "root:0", "--group", "root:0", NULL);
     514                 :         20 :     command_add_args(&cmd, "--null", "--no-unquote", "--no-recursion",
     515                 :            :                            "-T", "-", NULL);
     516                 :         20 :     command_exec(&cmd);
     517                 :            :   }
     518                 :         20 :   close(pipe_filenames[0]);
     519                 :         20 :   close(pipe_tarball[1]);
     520                 :            : 
     521                 :            :   /* Of course we should not forget to compress the archive as well. */
     522                 :         20 :   pid_comp = subproc_fork();
     523         [ +  + ]:         40 :   if (pid_comp == 0) {
     524                 :         20 :     close(pipe_filenames[1]);
     525                 :         20 :     compress_filter(tar_compress_params, pipe_tarball[0], fd_out,
     526                 :         20 :                     _("compressing tar member"));
     527                 :         20 :     exit(0);
     528                 :            :   }
     529                 :         20 :   close(pipe_tarball[0]);
     530                 :            : 
     531                 :            :   /* All the pipes are set, now lets start feeding filenames to tar. */
     532                 :         20 :   tar_filenames_feeder(dir, pipe_filenames[1]);
     533                 :            : 
     534                 :            :   /* All done, clean up wait for tar and <compress> to finish their job. */
     535                 :         19 :   close(pipe_filenames[1]);
     536                 :         19 :   subproc_reap(pid_comp, _("<compress> from tar -cf"), 0);
     537                 :         19 :   subproc_reap(pid_tar, "tar -cf", 0);
     538                 :         19 : }
     539                 :            : 
     540                 :            : static intmax_t
     541                 :         10 : parse_timestamp(const char *value)
     542                 :            : {
     543                 :            :   intmax_t timestamp;
     544                 :            :   char *end;
     545                 :            : 
     546                 :         10 :   errno = 0;
     547                 :         10 :   timestamp = strtoimax(value, &end, 10);
     548   [ +  -  +  -  :         10 :   if (value == end || *end || errno != 0)
                   -  + ]
     549                 :          0 :     ohshite(_("unable to parse timestamp '%.255s'"), value);
     550                 :            : 
     551                 :         10 :   return timestamp;
     552                 :            : }
     553                 :            : 
     554                 :            : /**
     555                 :            :  * Overly complex function that builds a .deb file.
     556                 :            :  */
     557                 :            : int
     558                 :         19 : do_build(const char *const *argv)
     559                 :            : {
     560                 :            :   struct compress_params control_compress_params;
     561                 :            :   struct tar_pack_options tar_options;
     562                 :            :   struct dpkg_error err;
     563                 :            :   struct dpkg_ar *ar;
     564                 :            :   intmax_t timestamp;
     565                 :            :   const char *timestamp_str;
     566                 :            :   const char *dir, *dest;
     567                 :            :   char *ctrldir;
     568                 :            :   char *debar;
     569                 :            :   char *tfbuf;
     570                 :            :   int gzfd;
     571                 :            : 
     572                 :            :   /* Decode our arguments. */
     573                 :         19 :   dir = *argv++;
     574         [ -  + ]:         19 :   if (!dir)
     575                 :          0 :     badusage(_("--%s needs a <directory> argument"), cipaction->olong);
     576                 :            : 
     577                 :         19 :   dest = *argv++;
     578   [ +  +  -  + ]:         19 :   if (dest && *argv)
     579                 :          0 :     badusage(_("--%s takes at most two arguments"), cipaction->olong);
     580                 :            : 
     581                 :         19 :   debar = gen_dest_pathname(dir, dest);
     582                 :         19 :   ctrldir = str_fmt("%s/%s", dir, BUILDCONTROLDIR);
     583                 :            : 
     584                 :            :   /* Perform some sanity checks on the to-be-build package. */
     585         [ -  + ]:         19 :   if (nocheckflag) {
     586         [ #  # ]:          0 :     if (debar == NULL)
     587                 :          0 :       ohshit(_("target is directory - cannot skip control file check"));
     588                 :          0 :     warning(_("not checking contents of control area"));
     589                 :          0 :     info(_("building an unknown package in '%s'."), debar);
     590                 :            :   } else {
     591                 :            :     struct pkginfo *pkg;
     592                 :            : 
     593                 :         19 :     pkg = check_control_area(ctrldir, dir);
     594         [ -  + ]:         10 :     if (debar == NULL)
     595                 :          0 :       debar = gen_dest_pathname_from_pkg(dest, pkg);
     596                 :         10 :     info(_("building package '%s' in '%s'."), pkg->set->name, debar);
     597                 :            :   }
     598                 :         10 :   m_output(stdout, _("<standard output>"));
     599                 :            : 
     600                 :         10 :   timestamp_str = getenv("SOURCE_DATE_EPOCH");
     601         [ +  - ]:         10 :   if (timestamp_str)
     602                 :         10 :     timestamp = parse_timestamp(timestamp_str);
     603                 :            :   else
     604                 :          0 :     timestamp = time(NULL);
     605                 :            : 
     606                 :            :   /* Now that we have verified everything it is time to actually
     607                 :            :    * build something. Let's start by making the ar-wrapper. */
     608                 :         10 :   ar = dpkg_ar_create(debar, 0644);
     609                 :            : 
     610                 :         10 :   dpkg_ar_set_mtime(ar, timestamp);
     611                 :            : 
     612                 :         10 :   unsetenv("TAR_OPTIONS");
     613                 :            : 
     614                 :            :   /* Create a temporary file to store the control data in. Immediately
     615                 :            :    * unlink our temporary file so others can't mess with it. */
     616                 :         10 :   tfbuf = path_make_temp_template("dpkg-deb");
     617                 :         10 :   gzfd = mkstemp(tfbuf);
     618         [ -  + ]:         10 :   if (gzfd == -1)
     619                 :          0 :     ohshite(_("failed to make temporary file (%s)"), _("control member"));
     620                 :            :   /* Make sure it's gone, the fd will remain until we close it. */
     621         [ -  + ]:         10 :   if (unlink(tfbuf))
     622                 :          0 :     ohshit(_("failed to unlink temporary file (%s), %s"), _("control member"),
     623                 :            :            tfbuf);
     624                 :         10 :   free(tfbuf);
     625                 :            : 
     626                 :            :   /* Select the compressor to use for our control archive. */
     627         [ +  - ]:         10 :   if (opt_uniform_compression) {
     628                 :         10 :     control_compress_params = compress_params;
     629                 :            :   } else {
     630                 :          0 :     control_compress_params.type = COMPRESSOR_TYPE_GZIP;
     631                 :          0 :     control_compress_params.strategy = COMPRESSOR_STRATEGY_NONE;
     632                 :          0 :     control_compress_params.level = -1;
     633         [ #  # ]:          0 :     if (!compressor_check_params(&control_compress_params, &err))
     634                 :          0 :       internerr("invalid control member compressor params: %s", err.str);
     635                 :            :   }
     636                 :            : 
     637                 :            :   /* Fork a tar to package the control-section of the package. */
     638                 :         10 :   tar_options.mode = "u+rw,go=rX";
     639                 :         10 :   tar_options.timestamp = timestamp;
     640                 :         10 :   tar_options.root_owner_group = true;
     641                 :         10 :   tarball_pack(ctrldir, control_treewalk_feed, &tar_options,
     642                 :            :                &control_compress_params, gzfd);
     643                 :            : 
     644                 :         10 :   free(ctrldir);
     645                 :            : 
     646         [ -  + ]:         10 :   if (lseek(gzfd, 0, SEEK_SET))
     647                 :          0 :     ohshite(_("failed to rewind temporary file (%s)"), _("control member"));
     648                 :            : 
     649                 :            :   /* We have our first file for the ar-archive. Write a header for it
     650                 :            :    * to the package and insert it. */
     651         [ +  + ]:         10 :   if (deb_format.major == 0) {
     652                 :            :     struct stat controlstab;
     653                 :            :     char versionbuf[40];
     654                 :            : 
     655         [ -  + ]:          1 :     if (fstat(gzfd, &controlstab))
     656                 :          0 :       ohshite(_("failed to stat temporary file (%s)"), _("control member"));
     657                 :          1 :     sprintf(versionbuf, "%-8s\n%jd\n", OLDARCHIVEVERSION,
     658                 :          1 :             (intmax_t)controlstab.st_size);
     659         [ -  + ]:          1 :     if (fd_write(ar->fd, versionbuf, strlen(versionbuf)) < 0)
     660                 :          0 :       ohshite(_("error writing '%s'"), debar);
     661         [ -  + ]:          1 :     if (fd_fd_copy(gzfd, ar->fd, -1, &err) < 0)
     662                 :          0 :       ohshit(_("cannot copy '%s' into archive '%s': %s"), _("control member"),
     663                 :            :              ar->name, err.str);
     664         [ +  - ]:          9 :   } else if (deb_format.major == 2) {
     665                 :          9 :     const char deb_magic[] = ARCHIVEVERSION "\n";
     666                 :            :     char adminmember[16 + 1];
     667                 :            : 
     668                 :          9 :     sprintf(adminmember, "%s%s", ADMINMEMBER,
     669                 :            :             compressor_get_extension(control_compress_params.type));
     670                 :            : 
     671                 :          9 :     dpkg_ar_put_magic(ar);
     672                 :          9 :     dpkg_ar_member_put_mem(ar, DEBMAGIC, deb_magic, strlen(deb_magic));
     673                 :          9 :     dpkg_ar_member_put_file(ar, adminmember, gzfd, -1);
     674                 :            :   } else {
     675                 :          0 :     internerr("unknown deb format version %d.%d", deb_format.major, deb_format.minor);
     676                 :            :   }
     677                 :            : 
     678                 :         10 :   close(gzfd);
     679                 :            : 
     680                 :            :   /* Control is done, now we need to archive the data. */
     681         [ +  + ]:         10 :   if (deb_format.major == 0) {
     682                 :            :     /* In old format, the data member is just concatenated after the
     683                 :            :      * control member, so we do not need a temporary file and can use
     684                 :            :      * the compression file descriptor. */
     685                 :          1 :     gzfd = ar->fd;
     686         [ +  - ]:          9 :   } else if (deb_format.major == 2) {
     687                 :            :     /* Start by creating a new temporary file. Immediately unlink the
     688                 :            :      * temporary file so others can't mess with it. */
     689                 :          9 :     tfbuf = path_make_temp_template("dpkg-deb");
     690                 :          9 :     gzfd = mkstemp(tfbuf);
     691         [ -  + ]:          9 :     if (gzfd == -1)
     692                 :          0 :       ohshite(_("failed to make temporary file (%s)"), _("data member"));
     693                 :            :     /* Make sure it's gone, the fd will remain until we close it. */
     694         [ -  + ]:          9 :     if (unlink(tfbuf))
     695                 :          0 :       ohshit(_("failed to unlink temporary file (%s), %s"), _("data member"),
     696                 :            :              tfbuf);
     697                 :          9 :     free(tfbuf);
     698                 :            :   } else {
     699                 :          0 :     internerr("unknown deb format version %d.%d", deb_format.major, deb_format.minor);
     700                 :            :   }
     701                 :            : 
     702                 :            :   /* Pack the directory into a tarball, feeding files from the callback. */
     703                 :         10 :   tar_options.mode = NULL;
     704                 :         10 :   tar_options.timestamp = timestamp;
     705                 :         10 :   tar_options.root_owner_group = opt_root_owner_group;
     706                 :         10 :   tarball_pack(dir, file_treewalk_feed, &tar_options, &compress_params, gzfd);
     707                 :            : 
     708                 :            :   /* Okay, we have data.tar as well now, add it to the ar wrapper. */
     709         [ +  + ]:          9 :   if (deb_format.major == 2) {
     710                 :            :     char datamember[16 + 1];
     711                 :            : 
     712                 :          8 :     sprintf(datamember, "%s%s", DATAMEMBER,
     713                 :            :             compressor_get_extension(compress_params.type));
     714                 :            : 
     715         [ -  + ]:          8 :     if (lseek(gzfd, 0, SEEK_SET))
     716                 :          0 :       ohshite(_("failed to rewind temporary file (%s)"), _("data member"));
     717                 :            : 
     718                 :          8 :     dpkg_ar_member_put_file(ar, datamember, gzfd, -1);
     719                 :            : 
     720                 :          8 :     close(gzfd);
     721                 :            :   }
     722         [ -  + ]:          9 :   if (fsync(ar->fd))
     723                 :          0 :     ohshite(_("unable to sync file '%s'"), ar->name);
     724                 :            : 
     725                 :          9 :   dpkg_ar_close(ar);
     726                 :            : 
     727                 :          9 :   free(debar);
     728                 :            : 
     729                 :          9 :   return 0;
     730                 :            : }

Generated by: LCOV version 1.16