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 : : }
|