LCOV - code coverage report
Current view: top level - src/deb - build.c (source / functions) Coverage Total Hit
Test: dpkg 1.22.7-3-g89f48 C code coverage Lines: 80.3 % 314 252
Test Date: 2024-07-17 02:53:43 Functions: 93.8 % 16 15
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 65.9 % 176 116

             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                 :          18 : control_treewalk_feed(const char *dir, int fd_out)
      62                 :             : {
      63                 :             :   struct treeroot *tree;
      64                 :             :   struct treenode *node;
      65                 :             : 
      66                 :          18 :   tree = treewalk_open(dir, TREEWALK_NONE, NULL);
      67         [ +  + ]:          57 :   for (node = treewalk_node(tree); node; node = treewalk_next(tree)) {
      68                 :             :     char *nodename;
      69                 :             : 
      70                 :          39 :     nodename = str_fmt("./%s", treenode_get_virtname(node));
      71         [ -  + ]:          39 :     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                 :          39 :     free(nodename);
      75                 :             :   }
      76                 :          18 :   treewalk_close(tree);
      77                 :          18 : }
      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                 :          20 : file_info_list_free(struct file_info *fi)
     144                 :             : {
     145         [ +  + ]:          25 :   while (fi) {
     146                 :             :     struct file_info *fl;
     147                 :             : 
     148                 :           5 :     fl=fi; fi=fi->next;
     149                 :           5 :     file_info_free(fl);
     150                 :             :   }
     151                 :          20 : }
     152                 :             : 
     153                 :             : static void
     154                 :          18 : file_treewalk_feed(const char *dir, int fd_out)
     155                 :             : {
     156                 :             :   struct treeroot *tree;
     157                 :             :   struct treenode *node;
     158                 :             :   struct file_info *fi;
     159                 :          18 :   struct file_info *symlist = NULL;
     160                 :          18 :   struct file_info *symlist_end = NULL;
     161                 :             : 
     162                 :          18 :   tree = treewalk_open(dir, TREEWALK_NONE, NULL);
     163         [ +  + ]:          98 :   for (node = treewalk_node(tree); node ; node = treewalk_next(tree)) {
     164                 :          81 :     const char *virtname = treenode_get_virtname(node);
     165                 :             :     char *nodename;
     166                 :             : 
     167         [ +  + ]:          81 :     if (strncmp(virtname, BUILDCONTROLDIR, strlen(BUILDCONTROLDIR)) == 0)
     168                 :          39 :       continue;
     169                 :             : 
     170                 :          42 :     nodename = str_fmt("./%s", virtname);
     171                 :             : 
     172   [ +  -  +  + ]:          42 :     if (!opt_nocheck && 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         [ -  + ]:          41 :     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         [ -  + ]:          41 :     } else if (fd_write(fd_out, nodename, strlen(nodename) + 1) < 0) {
     181                 :           0 :       ohshite(_("failed to write filename to tar pipe (%s)"),
     182                 :             :               _("data member"));
     183                 :             :     }
     184                 :             : 
     185                 :          41 :     free(nodename);
     186                 :             :   }
     187                 :          17 :   treewalk_close(tree);
     188                 :             : 
     189         [ -  + ]:          17 :   for (fi = symlist; fi; fi = fi->next)
     190         [ #  # ]:           0 :     if (fd_write(fd_out, fi->fn, strlen(fi->fn) + 1) < 0)
     191                 :           0 :       ohshite(_("failed to write filename to tar pipe (%s)"), _("data member"));
     192                 :             : 
     193                 :          17 :   file_info_list_free(symlist);
     194                 :          17 : }
     195                 :             : 
     196                 :             : static const char *const maintainerscripts[] = {
     197                 :             :   PREINSTFILE,
     198                 :             :   POSTINSTFILE,
     199                 :             :   PRERMFILE,
     200                 :             :   POSTRMFILE,
     201                 :             :   MAINTSCRIPT_FILE_CONFIG,
     202                 :             :   NULL,
     203                 :             : };
     204                 :             : 
     205                 :             : /**
     206                 :             :  * Check control directory and file permissions.
     207                 :             :  */
     208                 :             : static void
     209                 :          27 : check_file_perms(const char *ctrldir)
     210                 :             : {
     211                 :          27 :   struct varbuf path = VARBUF_INIT;
     212                 :             :   const char *const *mscriptp;
     213                 :             :   struct stat mscriptstab;
     214                 :             : 
     215                 :          27 :   varbuf_printf(&path, "%s/", ctrldir);
     216         [ -  + ]:          27 :   if (lstat(path.buf, &mscriptstab))
     217                 :           0 :     ohshite(_("unable to stat control directory"));
     218         [ -  + ]:          27 :   if (!S_ISDIR(mscriptstab.st_mode))
     219                 :           0 :     ohshit(_("control directory is not a directory"));
     220         [ -  + ]:          27 :   if ((mscriptstab.st_mode & 07757) != 0755)
     221                 :           0 :     ohshit(_("control directory has bad permissions %03lo "
     222                 :             :              "(must be >=0755 and <=0775)"),
     223                 :           0 :            (unsigned long)(mscriptstab.st_mode & 07777));
     224                 :             : 
     225         [ +  + ]:         162 :   for (mscriptp = maintainerscripts; *mscriptp; mscriptp++) {
     226                 :         135 :     varbuf_reset(&path);
     227                 :         135 :     varbuf_printf(&path, "%s/%s", ctrldir, *mscriptp);
     228         [ -  + ]:         135 :     if (!lstat(path.buf, &mscriptstab)) {
     229         [ #  # ]:           0 :       if (S_ISLNK(mscriptstab.st_mode))
     230                 :           0 :         continue;
     231         [ #  # ]:           0 :       if (!S_ISREG(mscriptstab.st_mode))
     232                 :           0 :         ohshit(_("maintainer script '%.50s' is not a plain file or symlink"),
     233                 :             :                *mscriptp);
     234         [ #  # ]:           0 :       if ((mscriptstab.st_mode & 07557) != 0555)
     235                 :           0 :         ohshit(_("maintainer script '%.50s' has bad permissions %03lo "
     236                 :             :                  "(must be >=0555 and <=0775)"),
     237                 :           0 :                *mscriptp, (unsigned long)(mscriptstab.st_mode & 07777));
     238         [ -  + ]:         135 :     } else if (errno != ENOENT) {
     239                 :           0 :       ohshite(_("maintainer script '%.50s' is not stattable"), *mscriptp);
     240                 :             :     }
     241                 :             :   }
     242                 :             : 
     243                 :          27 :   varbuf_destroy(&path);
     244                 :          27 : }
     245                 :             : 
     246                 :             : /**
     247                 :             :  * Check if conffiles contains sane information.
     248                 :             :  */
     249                 :             : static void
     250                 :          27 : check_conffiles(const char *ctrldir, const char *rootdir)
     251                 :             : {
     252                 :             :   FILE *cf;
     253                 :          27 :   struct varbuf controlfile = VARBUF_INIT;
     254                 :             :   char conffilenamebuf[MAXCONFFILENAME + 1];
     255                 :          27 :   struct file_info *conffiles_head = NULL;
     256                 :          27 :   struct file_info *conffiles_tail = NULL;
     257                 :             : 
     258                 :          27 :   varbuf_printf(&controlfile, "%s/%s", ctrldir, CONFFILESFILE);
     259                 :             : 
     260                 :          27 :   cf = fopen(controlfile.buf, "r");
     261         [ +  + ]:          27 :   if (cf == NULL) {
     262         [ +  - ]:          15 :     if (errno == ENOENT) {
     263                 :          15 :       varbuf_destroy(&controlfile);
     264                 :          15 :       return;
     265                 :             :     }
     266                 :             : 
     267                 :           0 :     ohshite(_("error opening conffiles file"));
     268                 :             :   }
     269                 :             : 
     270         [ +  + ]:          19 :   while (fgets(conffilenamebuf, MAXCONFFILENAME + 1, cf)) {
     271                 :             :     struct stat controlstab;
     272                 :          16 :     char *conffilename = conffilenamebuf;
     273                 :             :     int n;
     274                 :          16 :     bool remove_on_upgrade = false;
     275                 :             : 
     276                 :          16 :     n = strlen(conffilename);
     277         [ -  + ]:          16 :     if (!n)
     278                 :           0 :       ohshite(_("empty string from fgets reading conffiles"));
     279                 :             : 
     280         [ +  + ]:          16 :     if (conffilename[n - 1] != '\n')
     281                 :           2 :       ohshit(_("conffile name '%s' is too long, or missing final newline"),
     282                 :             :              conffilename);
     283                 :             : 
     284                 :          14 :     conffilename[--n] = '\0';
     285                 :             : 
     286         [ +  + ]:          14 :     if (c_isspace(conffilename[0])) {
     287                 :             :       /* The conffiles lines cannot start with whitespace; by handling this
     288                 :             :        * case now, we simplify the remaining code. Move past the whitespace
     289                 :             :        * to give a better error. */
     290         [ +  + ]:           6 :       while (c_isspace(conffilename[0]))
     291                 :           4 :         conffilename++;
     292         [ +  + ]:           2 :       if (conffilename[0] == '\0')
     293                 :           1 :           ohshit(_("empty and whitespace-only lines are not allowed in "
     294                 :             :                    "conffiles"));
     295                 :           1 :       ohshit(_("line with conffile filename '%s' has leading white spaces"),
     296                 :             :              conffilename);
     297                 :             :     }
     298                 :             : 
     299         [ +  + ]:          12 :     if (conffilename[0] != '/') {
     300                 :           9 :       char *flag = conffilename;
     301                 :           9 :       char *flag_end = strchr(flag, ' ');
     302                 :             : 
     303         [ +  + ]:           9 :       if (flag_end) {
     304                 :           8 :         conffilename = flag_end + 1;
     305                 :           8 :         n -= conffilename - flag;
     306                 :             :       }
     307                 :             : 
     308                 :             :       /* If no flag separator is found, assume a missing leading slash. */
     309   [ +  +  +  +  :           9 :       if (flag_end == NULL || (conffilename[0] && conffilename[0] != '/'))
                   +  + ]
     310                 :           2 :         ohshit(_("conffile name '%s' is not an absolute pathname"), conffilename);
     311                 :             : 
     312                 :           7 :       flag_end[0] = '\0';
     313                 :             : 
     314                 :             :       /* Otherwise assume a missing filename after the flag separator. */
     315         [ +  + ]:           7 :       if (conffilename[0] == '\0')
     316                 :           1 :         ohshit(_("conffile name missing after flag '%s'"), flag);
     317                 :             : 
     318         [ +  + ]:           6 :       if (strcmp(flag, "remove-on-upgrade") == 0)
     319                 :           5 :         remove_on_upgrade = true;
     320                 :             :       else
     321                 :           1 :         ohshit(_("unknown flag '%s' for conffile '%s'"), flag, conffilename);
     322                 :             :     }
     323                 :             : 
     324                 :           8 :     varbuf_reset(&controlfile);
     325                 :           8 :     varbuf_printf(&controlfile, "%s%s", rootdir, conffilename);
     326         [ +  + ]:           8 :     if (lstat(controlfile.buf, &controlstab)) {
     327         [ +  - ]:           4 :       if (errno == ENOENT) {
     328   [ +  -  -  + ]:           4 :         if ((n > 1) && c_isspace(conffilename[n - 1]))
     329                 :           0 :           warning(_("conffile filename '%s' contains trailing white spaces"),
     330                 :             :                   conffilename);
     331         [ -  + ]:           4 :         if (!remove_on_upgrade)
     332                 :           0 :           ohshit(_("conffile '%.250s' does not appear in package"), conffilename);
     333                 :             :       } else
     334                 :           0 :         ohshite(_("conffile '%.250s' is not stattable"), conffilename);
     335         [ +  + ]:           4 :     } else if (remove_on_upgrade) {
     336                 :           1 :         ohshit(_("conffile '%s' is present but is requested to be removed"),
     337                 :             :                conffilename);
     338         [ -  + ]:           3 :     } else if (!S_ISREG(controlstab.st_mode)) {
     339                 :           0 :       warning(_("conffile '%s' is not a plain file"), conffilename);
     340                 :             :     }
     341                 :             : 
     342         [ +  + ]:           7 :     if (file_info_find_name(conffiles_head, conffilename)) {
     343                 :           2 :       warning(_("conffile name '%s' is duplicated"), conffilename);
     344                 :             :     } else {
     345                 :             :       struct file_info *conffile;
     346                 :             : 
     347                 :           5 :       conffile = file_info_new(conffilename);
     348                 :           5 :       file_info_list_append(&conffiles_head, &conffiles_tail, conffile);
     349                 :             :     }
     350                 :             :   }
     351                 :             : 
     352                 :           3 :   file_info_list_free(conffiles_head);
     353                 :           3 :   varbuf_destroy(&controlfile);
     354                 :             : 
     355         [ -  + ]:           3 :   if (ferror(cf))
     356                 :           0 :     ohshite(_("error reading conffiles file"));
     357                 :           3 :   fclose(cf);
     358                 :             : }
     359                 :             : 
     360                 :             : /**
     361                 :             :  * Check the control file.
     362                 :             :  *
     363                 :             :  * @param ctrldir The directory from where to build the binary package.
     364                 :             :  * @return The pkginfo struct from the parsed control file.
     365                 :             :  */
     366                 :             : static struct pkginfo *
     367                 :          27 : check_control_file(const char *ctrldir)
     368                 :             : {
     369                 :             :   struct pkginfo *pkg;
     370                 :             :   char *controlfile;
     371                 :             : 
     372                 :          27 :   controlfile = str_fmt("%s/%s", ctrldir, CONTROLFILE);
     373                 :          27 :   parsedb(controlfile, pdb_parse_binary, &pkg);
     374                 :             : 
     375                 :          27 :   if (strspn(pkg->set->name, "abcdefghijklmnopqrstuvwxyz0123456789+-.") !=
     376         [ -  + ]:          27 :       strlen(pkg->set->name))
     377                 :           0 :     ohshit(_("package name has characters that aren't lowercase alphanums or '-+.'"));
     378         [ +  - ]:          27 :   if (pkg->available.arch->type == DPKG_ARCH_NONE ||
     379         [ -  + ]:          27 :       pkg->available.arch->type == DPKG_ARCH_EMPTY)
     380                 :           0 :     ohshit(_("package architecture is missing or empty"));
     381         [ -  + ]:          27 :   if (pkg->priority == PKG_PRIO_OTHER)
     382                 :           0 :     warning(_("'%s' contains user-defined Priority value '%s'"),
     383                 :           0 :             controlfile, pkg->otherpriority);
     384                 :             : 
     385                 :          27 :   free(controlfile);
     386                 :             : 
     387                 :          27 :   return pkg;
     388                 :             : }
     389                 :             : 
     390                 :             : /**
     391                 :             :  * Perform some sanity checks on the to-be-built package control area.
     392                 :             :  *
     393                 :             :  * @param ctrldir The directory from where to build the binary package.
     394                 :             :  * @return The pkginfo struct from the parsed control file.
     395                 :             :  */
     396                 :             : static struct pkginfo *
     397                 :          27 : check_control_area(const char *ctrldir, const char *rootdir)
     398                 :             : {
     399                 :             :   struct pkginfo *pkg;
     400                 :             :   int warns;
     401                 :             : 
     402                 :             :   /* Start by reading in the control file so we can check its contents. */
     403                 :          27 :   pkg = check_control_file(ctrldir);
     404                 :          27 :   check_file_perms(ctrldir);
     405                 :          27 :   check_conffiles(ctrldir, rootdir);
     406                 :             : 
     407                 :          18 :   warns = warning_get_count();
     408         [ +  + ]:          18 :   if (warns)
     409                 :           3 :     warning(P_("ignoring %d warning about the control file(s)",
     410                 :             :                "ignoring %d warnings about the control file(s)", warns),
     411                 :             :             warns);
     412                 :             : 
     413                 :          18 :   return pkg;
     414                 :             : }
     415                 :             : 
     416                 :             : /**
     417                 :             :  * Generate the pathname for the destination binary package.
     418                 :             :  *
     419                 :             :  * If the pathname cannot be computed, because the destination is a directory,
     420                 :             :  * then NULL will be returned.
     421                 :             :  *
     422                 :             :  * @param dir   The directory from where to build the binary package.
     423                 :             :  * @param dest  The destination name, either a file or directory name.
     424                 :             :  * @return      The pathname for the package being built.
     425                 :             :  */
     426                 :             : static char *
     427                 :          27 : gen_dest_pathname(const char *dir, const char *dest)
     428                 :             : {
     429         [ +  + ]:          27 :   if (dest) {
     430                 :             :     struct stat dest_stab;
     431                 :             : 
     432         [ +  - ]:          14 :     if (stat(dest, &dest_stab)) {
     433         [ -  + ]:          14 :       if (errno != ENOENT)
     434                 :           0 :         ohshite(_("unable to check for existence of archive '%.250s'"), dest);
     435         [ #  # ]:           0 :     } else if (S_ISDIR(dest_stab.st_mode)) {
     436                 :             :       /* Need to compute the destination name from the package control file. */
     437                 :           0 :       return NULL;
     438                 :             :     }
     439                 :             : 
     440                 :          14 :     return m_strdup(dest);
     441                 :             :   } else {
     442                 :             :     char *pathname;
     443                 :             : 
     444                 :          13 :     pathname = m_malloc(strlen(dir) + sizeof(DEBEXT));
     445                 :          13 :     strcpy(pathname, dir);
     446                 :          13 :     path_trim_slash_slashdot(pathname);
     447                 :          13 :     strcat(pathname, DEBEXT);
     448                 :             : 
     449                 :          13 :     return pathname;
     450                 :             :   }
     451                 :             : }
     452                 :             : 
     453                 :             : /**
     454                 :             :  * Generate the pathname for the destination binary package from control file.
     455                 :             :  *
     456                 :             :  * @return The pathname for the package being built.
     457                 :             :  */
     458                 :             : static char *
     459                 :           0 : gen_dest_pathname_from_pkg(const char *dir, struct pkginfo *pkg)
     460                 :             : {
     461                 :           0 :   return str_fmt("%s/%s_%s_%s%s", dir, pkg->set->name,
     462                 :           0 :                  versiondescribe(&pkg->available.version, vdew_never),
     463                 :           0 :                  pkg->available.arch->name, DEBEXT);
     464                 :             : }
     465                 :             : 
     466                 :             : typedef void filenames_feed_func(const char *dir, int fd_out);
     467                 :             : 
     468                 :             : struct tar_pack_options {
     469                 :             :   intmax_t timestamp;
     470                 :             :   const char *mode;
     471                 :             :   bool root_owner_group;
     472                 :             : };
     473                 :             : 
     474                 :             : /**
     475                 :             :  * Pack the contents of a directory into a tarball.
     476                 :             :  */
     477                 :             : static void
     478                 :          36 : tarball_pack(const char *dir, filenames_feed_func *tar_filenames_feeder,
     479                 :             :              struct tar_pack_options *options,
     480                 :             :              struct compress_params *tar_compress_params, int fd_out)
     481                 :             : {
     482                 :             :   int pipe_filenames[2], pipe_tarball[2];
     483                 :             :   pid_t pid_tar, pid_comp;
     484                 :             : 
     485                 :             :   /* Fork off a tar. We will feed it a list of filenames on stdin later. */
     486                 :          36 :   m_pipe(pipe_filenames);
     487                 :          36 :   m_pipe(pipe_tarball);
     488                 :          36 :   pid_tar = subproc_fork();
     489         [ +  + ]:          72 :   if (pid_tar == 0) {
     490                 :             :     struct command cmd;
     491                 :             :     char mtime[50];
     492                 :             : 
     493                 :          36 :     m_dup2(pipe_filenames[0], 0);
     494                 :          36 :     close(pipe_filenames[0]);
     495                 :          36 :     close(pipe_filenames[1]);
     496                 :          36 :     m_dup2(pipe_tarball[1], 1);
     497                 :          36 :     close(pipe_tarball[0]);
     498                 :          36 :     close(pipe_tarball[1]);
     499                 :             : 
     500         [ -  + ]:          36 :     if (chdir(dir))
     501                 :           0 :       ohshite(_("failed to chdir to '%.255s'"), dir);
     502                 :             : 
     503                 :          36 :     snprintf(mtime, sizeof(mtime), "@%jd", options->timestamp);
     504                 :             : 
     505                 :          36 :     command_init(&cmd, TAR, "tar -cf");
     506                 :          36 :     command_add_args(&cmd, "tar", "-cf", "-", "--format=gnu",
     507                 :             :                            "--mtime", mtime, "--clamp-mtime", NULL);
     508                 :             :     /* Mode might become a positional argument, pass it before -T. */
     509         [ +  + ]:          36 :     if (options->mode)
     510                 :          18 :       command_add_args(&cmd, "--mode", options->mode, NULL);
     511         [ +  + ]:          36 :     if (options->root_owner_group)
     512                 :          29 :       command_add_args(&cmd, "--owner", "root:0", "--group", "root:0", NULL);
     513                 :          36 :     command_add_args(&cmd, "--null", "--no-unquote", "--no-recursion",
     514                 :             :                            "-T", "-", NULL);
     515                 :          36 :     command_exec(&cmd);
     516                 :             :   }
     517                 :          36 :   close(pipe_filenames[0]);
     518                 :          36 :   close(pipe_tarball[1]);
     519                 :             : 
     520                 :             :   /* Of course we should not forget to compress the archive as well. */
     521                 :          36 :   pid_comp = subproc_fork();
     522         [ +  + ]:          72 :   if (pid_comp == 0) {
     523                 :          36 :     close(pipe_filenames[1]);
     524                 :          36 :     compress_filter(tar_compress_params, pipe_tarball[0], fd_out,
     525                 :          36 :                     _("compressing tar member"));
     526                 :          36 :     exit(0);
     527                 :             :   }
     528                 :          36 :   close(pipe_tarball[0]);
     529                 :             : 
     530                 :             :   /* All the pipes are set, now lets start feeding filenames to tar. */
     531                 :          36 :   tar_filenames_feeder(dir, pipe_filenames[1]);
     532                 :             : 
     533                 :             :   /* All done, clean up wait for tar and <compress> to finish their job. */
     534                 :          35 :   close(pipe_filenames[1]);
     535                 :          35 :   subproc_reap(pid_comp, _("<compress> from tar -cf"), 0);
     536                 :          35 :   subproc_reap(pid_tar, "tar -cf", 0);
     537                 :          35 : }
     538                 :             : 
     539                 :             : static intmax_t
     540                 :          18 : parse_timestamp(const char *value)
     541                 :             : {
     542                 :             :   intmax_t timestamp;
     543                 :             :   char *end;
     544                 :             : 
     545                 :          18 :   errno = 0;
     546                 :          18 :   timestamp = strtoimax(value, &end, 10);
     547   [ +  -  -  + ]:          18 :   if (value == end || *end)
     548                 :           0 :     ohshit(_("unable to parse timestamp '%.255s'"), value);
     549         [ -  + ]:          18 :   else if (errno != 0)
     550                 :           0 :     ohshite(_("unable to parse timestamp '%.255s'"), value);
     551                 :             : 
     552                 :          18 :   return timestamp;
     553                 :             : }
     554                 :             : 
     555                 :             : /**
     556                 :             :  * Overly complex function that builds a .deb file.
     557                 :             :  */
     558                 :             : int
     559                 :          27 : do_build(const char *const *argv)
     560                 :             : {
     561                 :             :   struct compress_params control_compress_params;
     562                 :             :   struct tar_pack_options tar_options;
     563                 :             :   struct dpkg_error err;
     564                 :             :   struct dpkg_ar *ar;
     565                 :             :   intmax_t timestamp;
     566                 :             :   const char *timestamp_str;
     567                 :             :   const char *dir, *dest;
     568                 :             :   char *ctrldir;
     569                 :             :   char *debar;
     570                 :             :   char *tfbuf;
     571                 :             :   int gzfd;
     572                 :             : 
     573                 :             :   /* Decode our arguments. */
     574                 :          27 :   dir = *argv++;
     575         [ -  + ]:          27 :   if (!dir)
     576                 :           0 :     badusage(_("--%s needs a <directory> argument"), cipaction->olong);
     577                 :             : 
     578                 :          27 :   dest = *argv++;
     579   [ +  +  -  + ]:          27 :   if (dest && *argv)
     580                 :           0 :     badusage(_("--%s takes at most two arguments"), cipaction->olong);
     581                 :             : 
     582                 :          27 :   debar = gen_dest_pathname(dir, dest);
     583                 :          27 :   ctrldir = str_fmt("%s/%s", dir, BUILDCONTROLDIR);
     584                 :             : 
     585                 :             :   /* Perform some sanity checks on the to-be-build package. */
     586         [ -  + ]:          27 :   if (opt_nocheck) {
     587         [ #  # ]:           0 :     if (debar == NULL)
     588                 :           0 :       ohshit(_("target is directory - cannot skip control file check"));
     589                 :           0 :     warning(_("not checking contents of control area"));
     590                 :           0 :     info(_("building an unknown package in '%s'."), debar);
     591                 :             :   } else {
     592                 :             :     struct pkginfo *pkg;
     593                 :             : 
     594                 :          27 :     pkg = check_control_area(ctrldir, dir);
     595         [ -  + ]:          18 :     if (debar == NULL)
     596                 :           0 :       debar = gen_dest_pathname_from_pkg(dest, pkg);
     597                 :          18 :     info(_("building package '%s' in '%s'."), pkg->set->name, debar);
     598                 :             :   }
     599                 :          18 :   m_output(stdout, _("<standard output>"));
     600                 :             : 
     601                 :          18 :   timestamp_str = getenv("SOURCE_DATE_EPOCH");
     602         [ +  - ]:          18 :   if (str_is_set(timestamp_str))
     603                 :          18 :     timestamp = parse_timestamp(timestamp_str);
     604                 :             :   else
     605                 :           0 :     timestamp = time(NULL);
     606                 :             : 
     607                 :             :   /* Now that we have verified everything it is time to actually
     608                 :             :    * build something. Let's start by making the ar-wrapper. */
     609                 :          18 :   ar = dpkg_ar_create(debar, 0644);
     610                 :             : 
     611                 :          18 :   dpkg_ar_set_mtime(ar, timestamp);
     612                 :             : 
     613                 :          18 :   unsetenv("TAR_OPTIONS");
     614                 :             : 
     615                 :             :   /* Create a temporary file to store the control data in. Immediately
     616                 :             :    * unlink our temporary file so others can't mess with it. */
     617                 :          18 :   tfbuf = path_make_temp_template("dpkg-deb");
     618                 :          18 :   gzfd = mkstemp(tfbuf);
     619         [ -  + ]:          18 :   if (gzfd < 0)
     620                 :           0 :     ohshite(_("failed to make temporary file (%s)"), _("control member"));
     621                 :             :   /* Make sure it's gone, the fd will remain until we close it. */
     622         [ -  + ]:          18 :   if (unlink(tfbuf))
     623                 :           0 :     ohshit(_("failed to unlink temporary file (%s), %s"), _("control member"),
     624                 :             :            tfbuf);
     625                 :          18 :   free(tfbuf);
     626                 :             : 
     627                 :             :   /* Select the compressor to use for our control archive. */
     628         [ +  - ]:          18 :   if (opt_uniform_compression) {
     629                 :          18 :     control_compress_params = compress_params;
     630                 :             :   } else {
     631                 :           0 :     control_compress_params = compress_params_deb0;
     632                 :             : 
     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                 :          18 :   tar_options.mode = "u+rw,go=rX";
     639                 :          18 :   tar_options.timestamp = timestamp;
     640                 :          18 :   tar_options.root_owner_group = true;
     641                 :          18 :   tarball_pack(ctrldir, control_treewalk_feed, &tar_options,
     642                 :             :                &control_compress_params, gzfd);
     643                 :             : 
     644                 :          18 :   free(ctrldir);
     645                 :             : 
     646         [ -  + ]:          18 :   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         [ +  + ]:          18 :   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         [ +  - ]:          17 :   } else if (deb_format.major == 2) {
     665                 :          17 :     const char deb_magic[] = ARCHIVEVERSION "\n";
     666                 :             :     char adminmember[16 + 1];
     667                 :             : 
     668                 :          17 :     sprintf(adminmember, "%s%s", ADMINMEMBER,
     669                 :             :             compressor_get_extension(control_compress_params.type));
     670                 :             : 
     671                 :          17 :     dpkg_ar_put_magic(ar);
     672                 :          17 :     dpkg_ar_member_put_mem(ar, DEBMAGIC, deb_magic, strlen(deb_magic));
     673                 :          17 :     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                 :          18 :   close(gzfd);
     679                 :             : 
     680                 :             :   /* Control is done, now we need to archive the data. */
     681         [ +  + ]:          18 :   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         [ +  - ]:          17 :   } 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                 :          17 :     tfbuf = path_make_temp_template("dpkg-deb");
     690                 :          17 :     gzfd = mkstemp(tfbuf);
     691         [ -  + ]:          17 :     if (gzfd < 0)
     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         [ -  + ]:          17 :     if (unlink(tfbuf))
     695                 :           0 :       ohshit(_("failed to unlink temporary file (%s), %s"), _("data member"),
     696                 :             :              tfbuf);
     697                 :          17 :     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                 :          18 :   tar_options.mode = NULL;
     704                 :          18 :   tar_options.timestamp = timestamp;
     705                 :          18 :   tar_options.root_owner_group = opt_root_owner_group;
     706                 :          18 :   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         [ +  + ]:          17 :   if (deb_format.major == 2) {
     710                 :             :     char datamember[16 + 1];
     711                 :             : 
     712                 :          16 :     sprintf(datamember, "%s%s", DATAMEMBER,
     713                 :             :             compressor_get_extension(compress_params.type));
     714                 :             : 
     715         [ -  + ]:          16 :     if (lseek(gzfd, 0, SEEK_SET))
     716                 :           0 :       ohshite(_("failed to rewind temporary file (%s)"), _("data member"));
     717                 :             : 
     718                 :          16 :     dpkg_ar_member_put_file(ar, datamember, gzfd, -1);
     719                 :             : 
     720                 :          16 :     close(gzfd);
     721                 :             :   }
     722         [ -  + ]:          17 :   if (fsync(ar->fd))
     723                 :           0 :     ohshite(_("unable to sync file '%s'"), ar->name);
     724                 :             : 
     725                 :          17 :   dpkg_ar_close(ar);
     726                 :             : 
     727                 :          17 :   free(debar);
     728                 :             : 
     729                 :          17 :   return 0;
     730                 :             : }
        

Generated by: LCOV version 2.0-1