diff --git a/usr.sbin/makefs/makefs.8 b/usr.sbin/makefs/makefs.8 --- a/usr.sbin/makefs/makefs.8 +++ b/usr.sbin/makefs/makefs.8 @@ -33,7 +33,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd January 19, 2024 +.Dd April 7, 2025 .Dt MAKEFS 8 .Os @@ -601,6 +601,25 @@ .It setuid .El .El +.Sh ENVIRONMENT +.Bl -tag +.It Ev SOURCE_DATE_EPOCH +The +.Ev SOURCE_DATE_EPOCH +environment variable can be used to specify a timestamp +in the same way as the +.Fl T +flag. +When both +.Ev SOURCE_DATE_EPOCH +and +.Fl T +are present, the timestamp specified by the +.Fl T +flag overrides the timestamp specified by the +.Ev SOURCE_DATE_EPOCH +variable. +.Pp .Sh SEE ALSO .Xr mtree 5 , .Xr rc.conf 5 , diff --git a/usr.sbin/makefs/makefs.c b/usr.sbin/makefs/makefs.c --- a/usr.sbin/makefs/makefs.c +++ b/usr.sbin/makefs/makefs.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -87,7 +88,7 @@ struct stat stampst; static fstype_t *get_fstype(const char *); -static int get_tstamp(const char *, struct stat *); +static void set_stampst(time_t); static void usage(fstype_t *, fsinfo_t *); int @@ -98,6 +99,7 @@ fstype_t *fstype; fsinfo_t fsoptions; fsnode *root; + time_t ts; int ch, i, len; const char *subtree; const char *specfile; @@ -134,6 +136,15 @@ if (ch == -1) err(1, "Unable to get system time"); + switch (source_date_epoch(&ts)) { + case -1: + err(1, "Cannot get timestamp from SOURCE_DATE_EPOCH"); + case 0: + set_stampst(ts); + break; + default: + break; + } while ((ch = getopt(argc, argv, "B:b:Dd:f:F:M:m:N:O:o:pR:s:S:t:T:xZ")) != -1) { switch (ch) { @@ -264,11 +275,20 @@ break; case 'T': - if (get_tstamp(optarg, &stampst) == -1) + { + char *eb; + long long l; + + if (stat(optarg, &stampst) != -1) + break; + errno = 0; + l = strtoll(optarg, &eb, 0); + if (eb == optarg || *eb != '\0' || errno) errx(1, "Cannot get timestamp from `%s'", optarg); + set_stampst((time_t)l); break; - + } case 'x': fsoptions.onlyspec = 1; break; @@ -475,30 +495,14 @@ return memcpy(ecalloc(i, sizeof(*o)), o, i * sizeof(*o)); } -static int -get_tstamp(const char *b, struct stat *st) +static void +set_stampst(time_t when) { - 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; + stampst.st_ino = 1; #if HAVE_STRUCT_STAT_BIRTHTIME - st->st_birthtime = + stampst.st_birthtime = #endif - st->st_mtime = st->st_ctime = st->st_atime = when; - return 0; + stampst.st_mtime = stampst.st_ctime = stampst.st_atime = when; } static void diff --git a/usr.sbin/makefs/tests/makefs_ffs_tests.sh b/usr.sbin/makefs/tests/makefs_ffs_tests.sh --- a/usr.sbin/makefs/tests/makefs_ffs_tests.sh +++ b/usr.sbin/makefs/tests/makefs_ffs_tests.sh @@ -315,6 +315,53 @@ common_cleanup } +atf_test_case source_date_epoch cleanup +source_date_epoch_body() +{ + timestamp=1742574909 + create_test_dirs + + mkdir -p $TEST_INPUTS_DIR/dir1 + export SOURCE_DATE_EPOCH=$timestamp + atf_check -e empty -o not-empty -s exit:0 \ + $MAKEFS -M 1m $TEST_IMAGE $TEST_INPUTS_DIR + + mount_image + eval $(stat -s $TEST_MOUNT_DIR/dir1) + atf_check_equal $st_atime $timestamp + atf_check_equal $st_mtime $timestamp + atf_check_equal $st_ctime $timestamp +} + +source_date_epoch_cleanup() +{ + common_cleanup +} + +atf_test_case T_flag_source_date_epoch cleanup +T_flag_source_date_epoch_body() +{ + timestamp_env=1742574909 + timestamp_T=1742574910 + create_test_dirs + + mkdir -p $TEST_INPUTS_DIR/dir1 + export SOURCE_DATE_EPOCH=$timestamp_env + atf_check -e empty -o not-empty -s exit:0 \ + $MAKEFS -T $timestamp_T -M 1m $TEST_IMAGE $TEST_INPUTS_DIR + + mount_image + eval $(stat -s $TEST_MOUNT_DIR/dir1) + atf_check_equal $st_atime $timestamp_T + atf_check_equal $st_mtime $timestamp_T + atf_check_equal $st_ctime $timestamp_T +} + +T_flag_source_date_epoch_cleanup() +{ + common_cleanup +} + atf_init_test_cases() { @@ -326,10 +373,12 @@ atf_add_test_case from_mtree_spec_file atf_add_test_case from_multiple_dirs atf_add_test_case from_single_dir + atf_add_test_case source_date_epoch atf_add_test_case o_flag_version_1 atf_add_test_case o_flag_version_2 atf_add_test_case T_flag_dir atf_add_test_case T_flag_F_flag atf_add_test_case T_flag_mtree + atf_add_test_case T_flag_source_date_epoch }