Index: head/usr.sbin/makefs/cd9660.c =================================================================== --- head/usr.sbin/makefs/cd9660.c +++ head/usr.sbin/makefs/cd9660.c @@ -442,7 +442,7 @@ */ void cd9660_makefs(const char *image, const char *dir, fsnode *root, - fsinfo_t *fsopts) + fsinfo_t *fsopts) { int64_t startoffset; int numDirectories; @@ -619,7 +619,7 @@ static void cd9660_finalize_PVD(void) { - time_t tim; + time_t tstamp = stampst.st_ino ? stampst.st_mtime : time(NULL); /* root should be a fixed size of 34 bytes since it has no name */ memcpy(diskStructure.primaryDescriptor.root_directory_record, @@ -668,26 +668,26 @@ diskStructure.primaryDescriptor.bibliographic_file_id, 37); /* Setup dates */ - time(&tim); cd9660_time_8426( (unsigned char *)diskStructure.primaryDescriptor.creation_date, - tim); + tstamp); cd9660_time_8426( (unsigned char *)diskStructure.primaryDescriptor.modification_date, - tim); + tstamp); - /* - cd9660_set_date(diskStructure.primaryDescriptor.expiration_date, now); - */ +#if 0 + cd9660_set_date(diskStructure.primaryDescriptor.expiration_date, + tstamp); +#endif memset(diskStructure.primaryDescriptor.expiration_date, '0', 16); diskStructure.primaryDescriptor.expiration_date[16] = 0; cd9660_time_8426( (unsigned char *)diskStructure.primaryDescriptor.effective_date, - tim); + tstamp); /* make this sane */ cd9660_time_915(diskStructure.rootNode->dot_record->isoDirRecord->date, - tim); + tstamp); } static void @@ -808,7 +808,7 @@ static int cd9660_translate_node_common(cd9660node *newnode) { - time_t tim; + time_t tstamp = stampst.st_ino ? stampst.st_mtime : time(NULL); int test; u_char flag; char temp[ISO_FILENAME_MAXLENGTH_WITH_PADDING]; @@ -829,9 +829,8 @@ /* Set the various dates */ /* If we want to use the current date and time */ - time(&tim); - cd9660_time_915(newnode->isoDirRecord->date, tim); + cd9660_time_915(newnode->isoDirRecord->date, tstamp); cd9660_bothendian_dword(newnode->fileDataLength, newnode->isoDirRecord->size); @@ -876,7 +875,8 @@ return 0; /* Finally, overwrite some of the values that are set by default */ - cd9660_time_915(newnode->isoDirRecord->date, node->inode->st.st_mtime); + cd9660_time_915(newnode->isoDirRecord->date, + stampst.st_ino ? stampst.st_mtime : node->inode->st.st_mtime); return 1; } @@ -1261,6 +1261,8 @@ diskStructure.rootNode, dir); if (diskStructure.rr_moved_dir == NULL) return 0; + cd9660_time_915(diskStructure.rr_moved_dir->isoDirRecord->date, + stampst.st_ino ? stampst.st_mtime : start_time.tv_sec); } /* Create a file with the same ORIGINAL name */ Index: head/usr.sbin/makefs/ffs.c =================================================================== --- head/usr.sbin/makefs/ffs.c +++ head/usr.sbin/makefs/ffs.c @@ -482,6 +482,7 @@ char *buf; int i, bufsize; off_t bufrem; + time_t tstamp; assert (image != NULL); assert (fsopts != NULL); @@ -541,7 +542,15 @@ /* make the file system */ if (debug & DEBUG_FS_CREATE_IMAGE) printf("calling mkfs(\"%s\", ...)\n", image); - fs = ffs_mkfs(image, fsopts); + + if (stampst.st_ino != 0) + tstamp = stampst.st_ctime; + else + tstamp = start_time.tv_sec; + + srandom(tstamp); + + fs = ffs_mkfs(image, fsopts, tstamp); fsopts->superblock = (void *)fs; if (debug & DEBUG_FS_CREATE_IMAGE) { time_t t; @@ -648,19 +657,12 @@ { int slen; void *membuf; + struct stat *st = stampst.st_ino != 0 ? &stampst : &cur->inode->st; memset(dinp, 0, sizeof(*dinp)); dinp->di_mode = cur->inode->st.st_mode; dinp->di_nlink = cur->inode->nlink; dinp->di_size = cur->inode->st.st_size; - dinp->di_atime = cur->inode->st.st_atime; - dinp->di_mtime = cur->inode->st.st_mtime; - dinp->di_ctime = cur->inode->st.st_ctime; -#if HAVE_STRUCT_STAT_ST_MTIMENSEC - dinp->di_atimensec = cur->inode->st.st_atimensec; - dinp->di_mtimensec = cur->inode->st.st_mtimensec; - dinp->di_ctimensec = cur->inode->st.st_ctimensec; -#endif #if HAVE_STRUCT_STAT_ST_FLAGS dinp->di_flags = cur->inode->st.st_flags; #endif @@ -669,6 +671,15 @@ #endif dinp->di_uid = cur->inode->st.st_uid; dinp->di_gid = cur->inode->st.st_gid; + + dinp->di_atime = st->st_atime; + dinp->di_mtime = st->st_mtime; + dinp->di_ctime = st->st_ctime; +#if HAVE_STRUCT_STAT_ST_MTIMENSEC + dinp->di_atimensec = st->st_atimensec; + dinp->di_mtimensec = st->st_mtimensec; + dinp->di_ctimensec = st->st_ctimensec; +#endif /* not set: di_db, di_ib, di_blocks, di_spare */ membuf = NULL; @@ -696,31 +707,33 @@ { int slen; void *membuf; + struct stat *st = stampst.st_ino != 0 ? &stampst : &cur->inode->st; memset(dinp, 0, sizeof(*dinp)); dinp->di_mode = cur->inode->st.st_mode; dinp->di_nlink = cur->inode->nlink; dinp->di_size = cur->inode->st.st_size; - dinp->di_atime = cur->inode->st.st_atime; - dinp->di_mtime = cur->inode->st.st_mtime; - dinp->di_ctime = cur->inode->st.st_ctime; -#if HAVE_STRUCT_STAT_ST_MTIMENSEC - dinp->di_atimensec = cur->inode->st.st_atimensec; - dinp->di_mtimensec = cur->inode->st.st_mtimensec; - dinp->di_ctimensec = cur->inode->st.st_ctimensec; -#endif #if HAVE_STRUCT_STAT_ST_FLAGS dinp->di_flags = cur->inode->st.st_flags; #endif #if HAVE_STRUCT_STAT_ST_GEN dinp->di_gen = cur->inode->st.st_gen; #endif -#if HAVE_STRUCT_STAT_BIRTHTIME - dinp->di_birthtime = cur->inode->st.st_birthtime; - dinp->di_birthnsec = cur->inode->st.st_birthtimensec; -#endif dinp->di_uid = cur->inode->st.st_uid; dinp->di_gid = cur->inode->st.st_gid; + + dinp->di_atime = st->st_atime; + dinp->di_mtime = st->st_mtime; + dinp->di_ctime = st->st_ctime; +#if HAVE_STRUCT_STAT_ST_MTIMENSEC + dinp->di_atimensec = st->st_atimensec; + dinp->di_mtimensec = st->st_mtimensec; + dinp->di_ctimensec = st->st_ctimensec; +#endif +#if HAVE_STRUCT_STAT_BIRTHTIME + dinp->di_birthtime = st->st_birthtime; + dinp->di_birthnsec = st->st_birthtimensec; +#endif /* not set: di_db, di_ib, di_blocks, di_spare */ membuf = NULL; @@ -1125,11 +1138,6 @@ initediblk < ufs_rw32(cgp->cg_niblk, fsopts->needswap)) { memset(buf, 0, fs->fs_bsize); dip = (struct ufs2_dinode *)buf; - /* - * XXX: Time-based seeds should be avoided for - * reproduceable builds. - */ - srandom(time(NULL)); for (i = 0; i < INOPB(fs); i++) { dip->di_gen = random(); dip++; Index: head/usr.sbin/makefs/ffs/mkfs.c =================================================================== --- head/usr.sbin/makefs/ffs/mkfs.c +++ head/usr.sbin/makefs/ffs/mkfs.c @@ -113,7 +113,7 @@ static int avgfpdir; /* expected number of files per directory */ struct fs * -ffs_mkfs(const char *fsys, const fsinfo_t *fsopts) +ffs_mkfs(const char *fsys, const fsinfo_t *fsopts, time_t tstamp) { int fragsperinode, optimalfpg, origdensity, minfpg, lastminfpg; int32_t cylno, i, csfrags; @@ -434,7 +434,7 @@ sblock.fs_state = 0; sblock.fs_clean = FS_ISCLEAN; sblock.fs_ronly = 0; - sblock.fs_id[0] = start_time.tv_sec; + sblock.fs_id[0] = tstamp; sblock.fs_id[1] = random(); sblock.fs_fsmnt[0] = '\0'; csfrags = howmany(sblock.fs_cssize, sblock.fs_fsize); @@ -450,9 +450,9 @@ sblock.fs_cstotal.cs_nifree = sblock.fs_ncg * sblock.fs_ipg - ROOTINO; sblock.fs_cstotal.cs_ndir = 0; sblock.fs_dsize -= csfrags; - sblock.fs_time = start_time.tv_sec; + sblock.fs_time = tstamp; if (Oflag <= 1) { - sblock.fs_old_time = start_time.tv_sec; + sblock.fs_old_time = tstamp; sblock.fs_old_dsize = sblock.fs_dsize; sblock.fs_old_csaddr = sblock.fs_csaddr; sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir; @@ -508,7 +508,7 @@ printf("super-block backups (for fsck -b #) at:"); for (cylno = 0; cylno < sblock.fs_ncg; cylno++) { - initcg(cylno, start_time.tv_sec, fsopts); + initcg(cylno, tstamp, fsopts); if (cylno % nprintcols == 0) printf("\n"); printf(" %*lld,", printcolwidth, @@ -521,7 +521,7 @@ * Now construct the initial file system, * then write out the super-block. */ - sblock.fs_time = start_time.tv_sec; + sblock.fs_time = tstamp; if (Oflag <= 1) { sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir; sblock.fs_old_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree; Index: head/usr.sbin/makefs/ffs/newfs_extern.h =================================================================== --- head/usr.sbin/makefs/ffs/newfs_extern.h +++ head/usr.sbin/makefs/ffs/newfs_extern.h @@ -1,4 +1,4 @@ -/* $NetBSD: newfs_extern.h,v 1.3 2009/10/21 01:07:47 snj Exp $ */ +/* $NetBSD: newfs_extern.h,v 1.4 2015/12/21 00:58:08 christos Exp $ */ /* From: NetBSD: extern.h,v 1.3 2000/12/01 12:03:27 simonb Exp $ */ /* @@ -28,7 +28,7 @@ */ /* prototypes */ -struct fs *ffs_mkfs(const char *, const fsinfo_t *); +struct fs *ffs_mkfs(const char *, const fsinfo_t *, time_t); void ffs_write_superblock(struct fs *, const fsinfo_t *); void ffs_rdfs(daddr_t, int, void *, const fsinfo_t *); void ffs_wtfs(daddr_t, int, void *, const fsinfo_t *); Index: head/usr.sbin/makefs/makefs.h =================================================================== --- head/usr.sbin/makefs/makefs.h +++ head/usr.sbin/makefs/makefs.h @@ -172,6 +172,7 @@ extern u_int debug; extern int dupsok; extern struct timespec start_time; +extern struct stat stampst; /* * If -x is specified, we want to exclude nodes which do not appear Index: head/usr.sbin/makefs/makefs.8 =================================================================== --- head/usr.sbin/makefs/makefs.8 +++ head/usr.sbin/makefs/makefs.8 @@ -35,7 +35,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 9, 2015 +.Dd June 14, 2016 .Dt MAKEFS 8 .Os .Sh NAME @@ -56,6 +56,7 @@ .Op Fl R Ar roundup-size .Op Fl S Ar sector-size .Op Fl s Ar image-size +.Op Fl T Ar timestamp .Op Fl t Ar fs-type .Ar image-file .Ar directory | manifest @@ -212,6 +213,18 @@ .It Fl s Ar image-size Set the size of the file system image to .Ar image-size . +.It Fl T Ar timestamp +Specify a timestamp to be set for all filesystem files and directories +created so that repeatable builds are possible. +The +.Ar timestamp +can be a +.Pa pathname , +where the timestamps are derived from that file, or an integer +value interpreted as the number of seconds from the Epoch. +Note that timestamps specified in an +.Xr mtree 5 +spec file, override the default timestamp. .It Fl t Ar fs-type Create an .Ar fs-type Index: head/usr.sbin/makefs/makefs.c =================================================================== --- head/usr.sbin/makefs/makefs.c +++ head/usr.sbin/makefs/makefs.c @@ -78,8 +78,10 @@ u_int debug; int dupsok; struct timespec start_time; +struct stat stampst; static fstype_t *get_fstype(const char *); +static int get_tstamp(const char *, struct stat *); static void usage(void); int main(int, char *[]); @@ -110,13 +112,15 @@ fstype->prepare_options(&fsoptions); specfile = NULL; - if (gettimeofday(&start, NULL) == -1) - err(1, "Unable to get system time"); - + ch = gettimeofday(&start, NULL); start_time.tv_sec = start.tv_sec; start_time.tv_nsec = start.tv_usec * 1000; - while ((ch = getopt(argc, argv, "B:b:Dd:f:F:M:m:N:o:pR:s:S:t:xZ")) != -1) { + if (ch == -1) + err(1, "Unable to get system time"); + + + while ((ch = getopt(argc, argv, "B:b:Dd:f:F:M:m:N:o:pR:s:S:t:T:xZ")) != -1) { switch (ch) { case 'B': @@ -239,6 +243,12 @@ fstype->prepare_options(&fsoptions); break; + case 'T': + if (get_tstamp(optarg, &stampst) == -1) + errx(1, "Cannot get timestamp from `%s'", + optarg); + break; + case 'x': fsoptions.onlyspec = 1; break; @@ -360,6 +370,32 @@ return (NULL); } +static int +get_tstamp(const char *b, struct stat *st) +{ + time_t when; + char *eb; + long long l; + + if (stat(b, st) != -1) + return 0; + + { + errno = 0; + l = strtoll(b, &eb, 0); + if (b == eb || *eb || errno) + return -1; + when = (time_t)l; + } + + st->st_ino = 1; +#ifdef HAVE_STRUCT_STAT_BIRTHTIME + st->st_birthtime = +#endif + st->st_mtime = st->st_ctime = st->st_atime = when; + return 0; +} + static void usage(void) { @@ -370,7 +406,8 @@ "usage: %s [-t fs-type] [-o fs-options] [-d debug-mask] [-B endian]\n" "\t[-S sector-size] [-M minimum-size] [-m maximum-size] [-R roundup-size]\n" "\t[-s image-size] [-b free-blocks] [-f free-files] [-F mtree-specfile]\n" -"\t[-xZ] [-N userdb-dir] image-file directory | manifest [extra-directory ...]\n", +"\t[-xZ] [-N userdb-dir] [-T ]\n" +"\timage-file directory | manifest [extra-directory ...]\n", prog); exit(1); } Index: head/usr.sbin/makefs/walk.c =================================================================== --- head/usr.sbin/makefs/walk.c +++ head/usr.sbin/makefs/walk.c @@ -229,6 +229,20 @@ cur->type = stbuf->st_mode & S_IFMT; cur->inode->nlink = 1; cur->inode->st = *stbuf; + if (stampst.st_ino) { + cur->inode->st.st_atime = stampst.st_atime; + cur->inode->st.st_mtime = stampst.st_mtime; + cur->inode->st.st_ctime = stampst.st_ctime; +#if HAVE_STRUCT_STAT_ST_MTIMENSEC + cur->inode->st.st_atimensec = stampst.st_atimensec; + cur->inode->st.st_mtimensec = stampst.st_mtimensec; + cur->inode->st.st_ctimensec = stampst.st_ctimensec; +#endif +#if HAVE_STRUCT_STAT_BIRTHTIME + cur->inode->st.st_birthtime = stampst.st_birthtime; + cur->inode->st.st_birthtimensec = stampst.st_birthtimensec; +#endif + } return (cur); }