diff --git a/bin/pax/options.c b/bin/pax/options.c index 1af5fe4b7c0f..84542ab13668 100644 --- a/bin/pax/options.c +++ b/bin/pax/options.c @@ -1,4 +1,4 @@ -/* $NetBSD: options.c,v 1.116 2015/04/11 15:41:33 christos Exp $ */ +/* $NetBSD: options.c,v 1.117 2015/12/19 18:28:54 christos Exp $ */ /*- * Copyright (c) 1992 Keith Muller. @@ -42,7 +42,7 @@ #if 0 static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 4/18/94"; #else -__RCSID("$NetBSD: options.c,v 1.116 2015/04/11 15:41:33 christos Exp $"); +__RCSID("$NetBSD: options.c,v 1.117 2015/12/19 18:28:54 christos Exp $"); #endif #endif /* not lint */ @@ -64,6 +64,7 @@ __RCSID("$NetBSD: options.c,v 1.116 2015/04/11 15:41:33 christos Exp $"); #include #include #include +#include #include "pax.h" #include "options.h" #include "cpio.h" @@ -76,6 +77,7 @@ __RCSID("$NetBSD: options.c,v 1.116 2015/04/11 15:41:33 christos Exp $"); /* * Routines which handle command line options */ +struct stat tst; /* Timestamp to set if non-0 */ static int nopids; /* tar mode: suppress "pids" for -p option */ static char flgch[] = FLGCH; /* list of all possible flags (pax) */ @@ -88,6 +90,9 @@ static void printflg(unsigned int); static int c_frmt(const void *, const void *); static off_t str_offt(char *); static char *get_line(FILE *fp); +#ifndef SMALL +static int set_tstamp(const char *, struct stat *); +#endif static void pax_options(int, char **); __dead static void pax_usage(void); static void tar_options(int, char **); @@ -129,8 +134,9 @@ static int get_line_error; #define OPT_SPARSE 16 #define OPT_XZ 17 #define OPT_GNU 18 +#define OPT_TIMESTAMP 19 #if !HAVE_NBTOOL_CONFIG_H -#define OPT_CHROOT 19 +#define OPT_CHROOT 20 #endif /* @@ -803,6 +809,8 @@ struct option tar_longopts[] = { { "chroot", no_argument, 0, OPT_CHROOT }, #endif + { "timestamp", required_argument, 0, + OPT_TIMESTAMP }, #if 0 /* Not implemented */ { "catenate", no_argument, 0, 'A' }, /* F */ { "concatenate", no_argument, 0, 'A' }, /* F */ @@ -1143,6 +1151,14 @@ tar_options(int argc, char **argv) case OPT_CHROOT: do_chroot = 1; break; +#endif +#ifndef SMALL + case OPT_TIMESTAMP: + if (set_tstamp(optarg, &tst) == -1) { + tty_warn(1, "Invalid timestamp `%s'", optarg); + tar_usage(); + } + break; #endif default: tar_usage(); @@ -2083,6 +2099,43 @@ get_line(FILE *f) return temp; } +#ifndef SMALL +/* + * set_tstamp() + * Use a specific timestamp for all individual files created in the + * archive + */ +static int +set_tstamp(const char *b, struct stat *st) +{ + time_t when; + char *eb; + long long l; + + if (stat(b, st) != -1) + return 0; + +#ifndef HAVE_NBTOOL_CONFIG_H + errno = 0; + if ((when = parsedate(b, NULL, NULL)) == -1 && errno != 0) +#endif + { + errno = 0; + l = strtoll(b, &eb, 0); + if (b == eb || *eb || errno) + return -1; + when = (time_t)l; + } + + st->st_ino = 1; +#if HAVE_STRUCT_STAT_BIRTHTIME + st->st_birthtime = +#endif + st->st_mtime = st->st_ctime = st->st_atime = when; + return 0; +} +#endif + /* * no_op() * for those option functions where the archive format has nothing to do. diff --git a/bin/pax/tar.1 b/bin/pax/tar.1 index 97ac36f439f9..d265f71ef970 100644 --- a/bin/pax/tar.1 +++ b/bin/pax/tar.1 @@ -1,4 +1,4 @@ -.\" $NetBSD: tar.1,v 1.35 2015/04/11 16:22:07 wiz Exp $ +.\" $NetBSD: tar.1,v 1.36 2015/12/19 18:28:54 christos Exp $ .\" .\" Copyright (c) 1996 SigmaSoft, Th. Lockert .\" All rights reserved. @@ -25,7 +25,7 @@ .\" .\" OpenBSD: tar.1,v 1.28 2000/11/09 23:58:56 aaron Exp .\" -.Dd April 11, 2015 +.Dd December 19, 2015 .Dt TAR 1 .Os .Sh NAME @@ -297,6 +297,19 @@ can be processed. Cause files of type directory being copied or archived, or archive members of type directory being extracted, to match only the directory file or archive member and not the file hierarchy rooted at the directory. +.It Fl Fl timestamp Ar timestamp +Store all modification times in the archive with the +.Ar timestamp +given instead of the actual modification time of the individual archive member +so that repeatable builds are possible. +The +.Ar timestamp +can be a +.Pa pathname , +where the timestamps are derived from that file, a parseable date for +.Xr parsedate 3 +(this option is not yet available in the tools build), or an integer value +interpreted as the number of seconds from the Epoch. .El .Pp The options diff --git a/bin/pax/tar.c b/bin/pax/tar.c index f4d57d41fa2c..45903f12b0be 100644 --- a/bin/pax/tar.c +++ b/bin/pax/tar.c @@ -1,4 +1,4 @@ -/* $NetBSD: tar.c,v 1.72 2015/06/16 22:31:08 christos Exp $ */ +/* $NetBSD: tar.c,v 1.73 2015/12/19 18:28:54 christos Exp $ */ /*- * Copyright (c) 1992 Keith Muller. @@ -42,7 +42,7 @@ #if 0 static char sccsid[] = "@(#)tar.c 8.2 (Berkeley) 4/18/94"; #else -__RCSID("$NetBSD: tar.c,v 1.72 2015/06/16 22:31:08 christos Exp $"); +__RCSID("$NetBSD: tar.c,v 1.73 2015/12/19 18:28:54 christos Exp $"); #endif #endif /* not lint */ @@ -64,6 +64,8 @@ __RCSID("$NetBSD: tar.c,v 1.72 2015/06/16 22:31:08 christos Exp $"); #include "extern.h" #include "tar.h" +extern struct stat tst; + /* * Routines for reading, writing and header identify of various versions of tar */ @@ -587,6 +589,7 @@ tar_wr(ARCHD *arcn) { HD_TAR *hd; int len; + uintmax_t mtime; char hdblk[sizeof(HD_TAR)]; /* @@ -695,10 +698,11 @@ tar_wr(ARCHD *arcn) /* * copy those fields that are independent of the type */ + mtime = tst.st_ino ? tst.st_mtime : arcn->sb.st_mtime; if (u32_oct((uintmax_t)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 0) || u32_oct((uintmax_t)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 0) || u32_oct((uintmax_t)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 0) || - u32_oct((uintmax_t)arcn->sb.st_mtime, hd->mtime, sizeof(hd->mtime), 1)) + u32_oct(mtime, hd->mtime, sizeof(hd->mtime), 1)) goto out; /* @@ -1046,6 +1050,7 @@ ustar_wr(ARCHD *arcn) { HD_USTAR *hd; char *pt; + uintmax_t mtime; char hdblk[sizeof(HD_USTAR)]; const char *user, *group; @@ -1210,7 +1215,8 @@ ustar_wr(ARCHD *arcn) return size_err("UID", arcn); if (u32_oct((uintmax_t)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 3)) return size_err("GID", arcn); - if (u32_oct((uintmax_t)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),3)) + mtime = tst.st_ino ? tst.st_mtime : arcn->sb.st_mtime; + if (u32_oct(mtime, hd->mtime, sizeof(hd->mtime), 3)) return size_err("MTIME", arcn); user = user_from_uid(arcn->sb.st_uid, 1); group = group_from_gid(arcn->sb.st_gid, 1);