Index | Thread | Search

From:
Mark Kettenis <mark.kettenis@xs4all.nl>
Subject:
Re: ctime(3) can fail (libexec and sbin)
To:
Florian Obser <florian@openbsd.org>
Cc:
tech@openbsd.org
Date:
Tue, 30 Apr 2024 10:32:21 +0200

Download raw body.

Thread
> From: Florian Obser <florian@openbsd.org>
> Date: Tue, 30 Apr 2024 07:06:25 +0200
> Content-Type: text/plain
> 
> It's not just localtime and gmtime that were missing error checks...
> 
> OK?

A few drive-by comments.  Not a proper review...

> diff --git libexec/ftpd/ftpd.c libexec/ftpd/ftpd.c
> index 810933525da..f0d0409bedf 100644
> --- libexec/ftpd/ftpd.c
> +++ libexec/ftpd/ftpd.c
> @@ -2739,7 +2739,10 @@ logxfer(const char *name, off_t size, time_t start)
>  	int len;
>  
>  	if ((statfd >= 0) && (getcwd(dir, sizeof(dir)) != NULL)) {
> +		char *cnow;
> +
>  		time(&now);
> +		cnow = ctime(&now);
>  
>  		vpw = malloc(strlen(guest ? guestpw : pw->pw_name) * 4 + 1);
>  		if (vpw == NULL)
> @@ -2755,7 +2758,8 @@ logxfer(const char *name, off_t size, time_t start)
>  
>  		len = snprintf(buf, sizeof(buf),
>  		    "%.24s %lld %s %lld %s %c %s %c %c %s ftp %d %s %s\n",
> -		    ctime(&now), (long long)(now - start + (now == start)),
> +		    cnow != NULL? cnow : "?",

cnow ? cnow : "?"

> +		    (long long)(now - start + (now == start)),
>  		    vremotehost, (long long)size, vpath,
>  		    ((type == TYPE_A) ? 'a' : 'b'), "*" /* none yet */,
>  		    'o', ((guest) ? 'a' : 'r'),
> diff --git libexec/mail.local/mail.local.c libexec/mail.local/mail.local.c
> index 7d0dfb4abb1..9ac46b54187 100644
> --- libexec/mail.local/mail.local.c
> +++ libexec/mail.local/mail.local.c
> @@ -112,7 +112,7 @@ storemail(char *from)
>  	FILE *fp = NULL;
>  	time_t tval;
>  	int fd, eline = 1;
> -	char *tbuf, *line = NULL;
> +	char *tbuf, *line = NULL, *cnow;
>  	size_t linesize = 0;
>  	ssize_t linelen;
>  
> @@ -124,7 +124,8 @@ storemail(char *from)
>  	free(tbuf);
>  
>  	(void)time(&tval);
> -	(void)fprintf(fp, "From %s %s", from, ctime(&tval));
> +	cnow = ctime(&tval);
> +	(void)fprintf(fp, "From %s %s", from, cnow != NULL ? cnow : "?");
>  
>  	while ((linelen = getline(&line, &linesize, stdin)) != -1) {
>  		if (line[linelen - 1] == '\n')
> diff --git libexec/spamd/spamd.c libexec/spamd/spamd.c
> index 1be4c4b5527..0158cf469c6 100644
> --- libexec/spamd/spamd.c
> +++ libexec/spamd/spamd.c
> @@ -730,6 +730,7 @@ initcon(struct con *cp, int fd, struct sockaddr *sa)
>  	    NI_NUMERICHOST);
>  	if (error)
>  		strlcpy(cp->addr, "<unknown>", sizeof(cp->addr));
> +	memset(ctimebuf, 0, sizeof(ctimebuf));
>  	ctime_r(&t, ctimebuf);
>  	ctimebuf[sizeof(ctimebuf) - 2] = '\0'; /* nuke newline */
>  	snprintf(cp->obuf, cp->osize, "220 %s ESMTP %s; %s\r\n",
> diff --git sbin/dump/itime.c sbin/dump/itime.c
> index 4498d91b19c..6fb656086fa 100644
> --- sbin/dump/itime.c
> +++ sbin/dump/itime.c
> @@ -162,7 +162,7 @@ putdumptime(void)
>  	FILE *df;
>  	struct dumpdates *dtwalk;
>  	int fd, i;
> -	char *fname;
> +	char *fname, *ct;
>  	time_t t;
>  
>  	if(uflag == 0)
> @@ -213,12 +213,21 @@ putdumptime(void)
>  		quit("ftruncate (%s): %s\n", dumpdates, strerror(errno));
>  	(void) fclose(df);
>  	t = (time_t)spcl.c_date;
> -	msg("level %c dump on %s", level, t == 0 ? "the epoch\n" : ctime(&t));
> +	if (t == 0)
> +		ct = "the epoch\n";
> +	else if ((ct = ctime(&t)) == NULL)
> +		ct = "?\n";
> +	msg("level %c dump on %s", level, ct);
>  }
>  
>  static void
>  dumprecout(FILE *file, struct dumpdates *what)
>  {
> +	char *ct;
> +
> +	ct = ctime(&what->dd_ddate);
> +	if (ct == NULL)
> +		quit("Cannot convert date\n");
>  
>  	if (fprintf(file, DUMPOUTFMT,
>  		    what->dd_name,
> @@ -243,8 +252,22 @@ getrecord(FILE *df, struct dumpdates *ddatep)
>  			dumpdates, recno);
>  
>  #ifdef FDEBUG
> -	msg("getrecord: %s %c %s", ddatep->dd_name, ddatep->dd_level,
> -	    ddatep->dd_ddate == 0 ? "the epoch\n" : ctime(&ddatep->dd_ddate));
> +	{
> +		char *ct;
> +
> +		if (ddatep->dd_ddate == 0)
> +			ct = "the epoch\n";
> +		else
> +			ct = ctime(&ddatep->dd_ddate);
> +
> +		if (ct != NULL)
> +			msg("getrecord: %s %c %s", ddatep->dd_name,
> +			    ddatep->dd_level, ct);
> +		else
> +			msg("getrecord: %s %c %lld seconds after the epoch",
> +			    ddatep->dd_name, ddatep->dd_level,
> +			    ddatep->dd_ddate);
> +	}
>  #endif
>  	return(0);
>  }
> diff --git sbin/dump/main.c sbin/dump/main.c
> index a5071abedd3..4d2cbf64088 100644
> --- sbin/dump/main.c
> +++ sbin/dump/main.c
> @@ -117,7 +117,7 @@ main(int argc, char *argv[])
>  	ino_t maxino;
>  	time_t t;
>  	int dirlist;
> -	char *toplevel, *str, *mount_point = NULL, *realpath;
> +	char *toplevel, *str, *mount_point = NULL, *realpath, *ct;
>  	int just_estimate = 0;
>  	u_int64_t zero_uid = 0;
>  
> @@ -423,11 +423,13 @@ main(int argc, char *argv[])
>  	        getdumptime();		/* /etc/dumpdates snarfed */
>  
>  	t = (time_t)spcl.c_date;
> +	ct = ctime(&t);
>  	msg("Date of this level %c dump: %s", level,
> -		t == 0 ? "the epoch\n" : ctime(&t));
> +	    t == 0 ? "the epoch\n" : ct != NULL ? ct : "?\n");
>  	t = (time_t)spcl.c_ddate;
> +	ct = ctime(&t);
>   	msg("Date of last level %c dump: %s", lastlevel,
> -		t == 0 ? "the epoch\n" : ctime(&t));
> +	    t == 0 ? "the epoch\n" : ct != NULL ? ct : "?\n");
>  	msg("Dumping %s ", disk);
>  	if (mount_point != NULL)
>  		msgtail("(%s) ", mount_point);
> @@ -589,10 +591,12 @@ main(int argc, char *argv[])
>  		    spcl.c_tapea, spcl.c_volume,
>  		    (spcl.c_volume == 1) ? "" : "s");
>  	t = (time_t)spcl.c_date;
> +	ct = ctime(&t);
>  	msg("Date of this level %c dump: %s", level,
> -	    t == 0 ? "the epoch\n" : ctime(&t));
> +	    t == 0 ? "the epoch\n" : ct != NULL ? ct : "?\n");
>  	t = do_stats();
> -	msg("Date this dump completed:  %s", ctime(&t));
> +	ct = ctime(&t);
> +	msg("Date this dump completed:  %s", ct != NULL ? ct : "?\n");
>  	msg("Average transfer rate: %ld KB/s\n", xferrate / tapeno);
>  	putdumptime();
>  	trewind();
> diff --git sbin/dump/optr.c sbin/dump/optr.c
> index 43f11d58457..7e20bba5535 100644
> --- sbin/dump/optr.c
> +++ sbin/dump/optr.c
> @@ -394,8 +394,11 @@ lastdump(int arg)
>  		if (strncmp(lastname, dtwalk->dd_name,
>  		    sizeof(dtwalk->dd_name)) == 0)
>  			continue;
> -		date = (char *)ctime(&dtwalk->dd_ddate);
> -		date[16] = '\0';	/* blast away seconds and year */
> +		date = ctime(&dtwalk->dd_ddate);
> +		if (date != NULL)
> +			date[16] = '\0'; /* blast away seconds and year */
> +		else
> +			date = "?";
>  		lastname = dtwalk->dd_name;
>  		dt = fstabsearch(dtwalk->dd_name);
>  		dumpme = (dt != NULL &&
> diff --git sbin/dump/tape.c sbin/dump/tape.c
> index 835fd223835..12fbffb0619 100644
> --- sbin/dump/tape.c
> +++ sbin/dump/tape.c
> @@ -231,11 +231,13 @@ do_stats(void)
>  {
>  	time_t tnow, ttaken;
>  	int64_t blocks;
> +	char *ct;
>  
>  	(void)time(&tnow);
>  	ttaken = tnow - tstart_volume;
>  	blocks = spcl.c_tapea - tapea_volume;
> -	msg("Volume %d completed at: %s", tapeno, ctime(&tnow));
> +	ct = ctime(&tnow);
> +	msg("Volume %d completed at: %s", tapeno, ct != NULL ? ct : "?\n");
>  	if (ttaken > 0) {
>  		msg("Volume %d took %lld:%02lld:%02lld\n", tapeno,
>  		    (long long)ttaken / 3600, ((long long)ttaken % 3600) / 60,
> @@ -565,7 +567,7 @@ startnewtape(int top)
>  	pid_t	childpid;
>  	int	status;
>  	pid_t	waitingpid;
> -	char	*p;
> +	char	*p, *ct;
>  	sig_t	interrupt_save;
>  
>  	interrupt_save = signal(SIGINT, SIG_IGN);
> @@ -688,7 +690,9 @@ restore_check_point:
>  		writeheader((ino_t)slp->inode);
>  		if (sblock->fs_magic != FS_UFS2_MAGIC)
>  			spcl.c_flags &=~ DR_NEWHEADER;
> -		msg("Volume %d started at: %s", tapeno, ctime(&tstart_volume));
> +		ct = ctime(&tstart_volume);
> +		msg("Volume %d started at: %s", tapeno,
> +		    ct != NULL ? ct : "?\n");

I don't think your want that "\n" here.  Could also be "ct ? ct : "?".

>  		if (tapeno > 1)
>  			msg("Volume %d begins with blocks from inode %llu\n",
>  			    tapeno, (unsigned long long)slp->inode);
> diff --git sbin/dumpfs/dumpfs.c sbin/dumpfs/dumpfs.c
> index 481f5b41e95..764a7ad320b 100644
> --- sbin/dumpfs/dumpfs.c
> +++ sbin/dumpfs/dumpfs.c
> @@ -163,13 +163,19 @@ dumpfs(int fd, const char *name)
>  	off_t off;
>  	int i, j;
>  	u_int cg;
> +	char *ct;
>  
>  	switch (afs.fs_magic) {
>  	case FS_UFS2_MAGIC:
>  		fssize = afs.fs_size;
>  		fstime = afs.fs_time;
> -		printf("magic\t%x (FFS2)\ttime\t%s",
> -		    afs.fs_magic, ctime(&fstime));
> +		ct = ctime(&fstime);
> +		if (ct)
> +			printf("magic\t%x (FFS2)\ttime\t%s",
> +			    afs.fs_magic, ctime(&fstime));
> +		else
> +			printf("magic\t%x (FFS2)\ttime\t%lld",
> +			    afs.fs_magic, fstime);
>  		printf("superblock location\t%jd\tid\t[ %x %x ]\n",
>  		    (intmax_t)afs.fs_sblockloc, afs.fs_id[0], afs.fs_id[1]);
>  		printf("ncg\t%u\tsize\t%jd\tblocks\t%jd\n",
> @@ -178,8 +184,13 @@ dumpfs(int fd, const char *name)
>  	case FS_UFS1_MAGIC:
>  		fssize = afs.fs_ffs1_size;
>  		fstime = afs.fs_ffs1_time;
> -		printf("magic\t%x (FFS1)\ttime\t%s",
> -		    afs.fs_magic, ctime(&fstime));
> +		ct = ctime(&fstime);
> +		if (ct)
> +			printf("magic\t%x (FFS1)\ttime\t%s",
> +			    afs.fs_magic, ctime(&fstime));
> +		else
> +			printf("magic\t%x (FFS1)\ttime\t%lld",
> +			    afs.fs_magic, fstime);
>  		printf("id\t[ %x %x ]\n", afs.fs_id[0], afs.fs_id[1]);
>  		i = 0;
>  		if (afs.fs_postblformat != FS_42POSTBLFMT) {
> @@ -325,6 +336,7 @@ dumpcg(const char *name, int fd, u_int c)
>  	time_t cgtime;
>  	off_t cur;
>  	int i, j;
> +	char *ct;
>  
>  	printf("\ncg %u:\n", c);
>  	cur = (off_t)fsbtodb(&afs, cgtod(&afs, c)) * DEV_BSIZE;
> @@ -335,18 +347,30 @@ dumpcg(const char *name, int fd, u_int c)
>  	switch (afs.fs_magic) {
>  	case FS_UFS2_MAGIC:
>  		cgtime = acg.cg_ffs2_time;
> -		printf("magic\t%x\ttell\t%jx\ttime\t%s",
> -		    acg.cg_magic, (intmax_t)cur, ctime(&cgtime));
> +		ct = ctime(&cgtime);
> +		if (ct)
> +			printf("magic\t%x\ttell\t%jx\ttime\t%s",
> +			    acg.cg_magic, (intmax_t)cur, ct);
> +		else
> +			printf("magic\t%x\ttell\t%jx\ttime\t%lld",
> +			    acg.cg_magic, (intmax_t)cur, cgtime);
>  		printf("cgx\t%u\tndblk\t%u\tniblk\t%u\tinitiblk %u\n",
>  		    acg.cg_cgx, acg.cg_ndblk, acg.cg_ffs2_niblk,
>  		    acg.cg_initediblk);
>  		break;
>  	case FS_UFS1_MAGIC:
>  		cgtime = acg.cg_time;
> -		printf("magic\t%x\ttell\t%jx\ttime\t%s",
> -		    afs.fs_postblformat == FS_42POSTBLFMT ?
> -		    ((struct ocg *)&acg)->cg_magic : acg.cg_magic,
> -		    (intmax_t)cur, ctime(&cgtime));
> +		ct = ctime(&cgtime);
> +		if (ct)
> +			printf("magic\t%x\ttell\t%jx\ttime\t%s",
> +			    afs.fs_postblformat == FS_42POSTBLFMT ?
> +			    ((struct ocg *)&acg)->cg_magic : acg.cg_magic,
> +			    (intmax_t)cur, ct);
> +		else
> +			printf("magic\t%x\ttell\t%jx\ttime\t%lld",
> +			    afs.fs_postblformat == FS_42POSTBLFMT ?
> +			    ((struct ocg *)&acg)->cg_magic : acg.cg_magic,
> +			    (intmax_t)cur, cgtime);
>  		printf("cgx\t%u\tncyl\t%d\tniblk\t%d\tndblk\t%u\n",
>  		    acg.cg_cgx, acg.cg_ncyl, acg.cg_niblk, acg.cg_ndblk);
>  		break;
> diff --git sbin/fsck_ext2fs/inode.c sbin/fsck_ext2fs/inode.c
> index a1861b08623..0a4579e46a2 100644
> --- sbin/fsck_ext2fs/inode.c
> +++ sbin/fsck_ext2fs/inode.c
> @@ -581,7 +581,10 @@ pinode(ino_t ino)
>  	printf("SIZE=%llu ", (long long)inosize(dp));
>  	t = (time_t) letoh32(dp->e2di_mtime);
>  	p = ctime(&t);
> -	printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
> +	if (p)
> +		printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
> +	else
> +		printf("MTIME=%lld", t);
>  }
>  
>  void
> diff --git sbin/fsck_ext2fs/pass1.c sbin/fsck_ext2fs/pass1.c
> index 377852c1c80..e30e67f3c14 100644
> --- sbin/fsck_ext2fs/pass1.c
> +++ sbin/fsck_ext2fs/pass1.c
> @@ -167,8 +167,12 @@ checkinode(ino_t inumber, struct inodesc *idesc)
>  	if (dp->e2di_dtime != 0) {
>  		time_t t = letoh32(dp->e2di_dtime);
>  		char *p = ctime(&t);
> -		pwarn("INODE I=%llu HAS DTIME=%12.12s %4.4s",
> -		    (unsigned long long)inumber, &p[4], &p[20]);
> +		if (p)
> +			pwarn("INODE I=%llu HAS DTIME=%12.12s %4.4s",
> +			    (unsigned long long)inumber, &p[4], &p[20]);
> +		else
> +			pwarn("INODE I=%llu HAS DTIME=%lld",
> +			    (unsigned long long)inumber, t);
>  		if (preen) {
>  			printf(" (CORRECTED)\n");
>  		}
> diff --git sbin/fsck_ffs/inode.c sbin/fsck_ffs/inode.c
> index ebda1d4a10d..831d8f30be8 100644
> --- sbin/fsck_ffs/inode.c
> +++ sbin/fsck_ffs/inode.c
> @@ -544,7 +544,10 @@ pinode(ino_t ino)
>  	printf("SIZE=%llu ", (unsigned long long)DIP(dp, di_size));
>  	t = DIP(dp, di_mtime);
>  	p = ctime(&t);
> -	printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
> +	if (p)
> +		printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
> +	else
> +		printf("MTIME=%lld ", t);
>  }
>  
>  void
> diff --git sbin/fsdb/fsdbutil.c sbin/fsdb/fsdbutil.c
> index cb6e842a747..2bc8113cff4 100644
> --- sbin/fsdb/fsdbutil.c
> +++ sbin/fsdb/fsdbutil.c
> @@ -127,17 +127,25 @@ printstat(const char *cp, ino_t inum, union dinode *dp)
>  	    DIP(dp, di_mode), DIP(dp, di_size));
>  	t = DIP(dp, di_mtime);
>  	p = ctime(&t);
> -	printf("\n\tMTIME=%15.15s %4.4s [%d nsec]", &p[4], &p[20],
> -	    DIP(dp, di_mtimensec));
> +	if (p)
> +		printf("\n\tMTIME=%15.15s %4.4s [%d nsec]", &p[4], &p[20],
> +		    DIP(dp, di_mtimensec));
> +	else
> +		printf("\n\tMTIME=%lld [%d nsec]", t, DIP(dp, di_mtimensec));
>  	t = DIP(dp, di_ctime);
>  	p = ctime(&t);
> -	printf("\n\tCTIME=%15.15s %4.4s [%d nsec]", &p[4], &p[20],
> -	    DIP(dp, di_ctimensec));
> +	if (p)
> +		printf("\n\tCTIME=%15.15s %4.4s [%d nsec]", &p[4], &p[20],
> +		    DIP(dp, di_ctimensec));
> +	else
> +		printf("\n\tCTIME=%lld [%d nsec]", t, DIP(dp, di_ctimensec));
>  	t = DIP(dp, di_atime);
>  	p = ctime(&t);
> -	printf("\n\tATIME=%15.15s %4.4s [%d nsec]\n", &p[4], &p[20],
> -	    DIP(dp, di_atimensec));
> -
> +	if (p)
> +		printf("\n\tATIME=%15.15s %4.4s [%d nsec]\n", &p[4], &p[20],
> +		    DIP(dp, di_atimensec));
> +	else
> +		printf("\n\tATIME=%lld [%d nsec]\n", t, DIP(dp, di_atimensec));
>  	if ((name = user_from_uid(DIP(dp, di_uid), 1)) != NULL)
>  		printf("OWNER=%s ", name);
>  	else
> diff --git sbin/fsirand/fsirand.c sbin/fsirand/fsirand.c
> index 8aef979ae94..e9430d8ac9b 100644
> --- sbin/fsirand/fsirand.c
> +++ sbin/fsirand/fsirand.c
> @@ -226,8 +226,13 @@ fsirand(char *device)
>  	if (printonly && (sblock->fs_id[0] || sblock->fs_id[1])) {
>  		if (sblock->fs_inodefmt >= FS_44INODEFMT && sblock->fs_id[0]) {
>  			time_t t = sblock->fs_id[0];	/* XXX 2038 */
> -			(void)printf("%s was randomized on %s", devpath,
> -			    ctime(&t));
> +			char *ct = ctime(&t);
> +			if (ct)
> +				(void)printf("%s was randomized on %s", devpath,
> +				    ct);
> +			else
> +				(void)printf("%s was randomized on %lld",
> +				    devpath, t);
>  		}
>  		(void)printf("fsid: %x %x\n", sblock->fs_id[0],
>  		    sblock->fs_id[1]);
> diff --git sbin/mount/mount.c sbin/mount/mount.c
> index eaff190b572..b830077c432 100644
> --- sbin/mount/mount.c
> +++ sbin/mount/mount.c
> @@ -503,9 +503,11 @@ prmount(struct statfs *sf)
>  		char buf[26];
>  		time_t t = sf->f_ctime;
>  
> -		ctime_r(&t, buf);
> -		buf[24] = '\0';
> -		printf(", ctime=%s", buf);
> +		if (ctime_r(&t, buf)) {
> +			buf[24] = '\0';
> +			printf(", ctime=%s", buf);
> +		} else
> +			printf(", ctime=%lld", t);
>  	}
>  
>  	/*
> diff --git sbin/pfctl/pfctl_table.c sbin/pfctl/pfctl_table.c
> index ba21402943d..d34206614ad 100644
> --- sbin/pfctl/pfctl_table.c
> +++ sbin/pfctl/pfctl_table.c
> @@ -389,14 +389,19 @@ print_table(struct pfr_table *ta, int verbose, int debug)
>  void
>  print_tstats(struct pfr_tstats *ts, int debug)
>  {
> -	time_t	time = ts->pfrts_tzero;
> -	int	dir, op;
> +	time_t	 time = ts->pfrts_tzero;
> +	int	 dir, op;
> +	char	*ct;
>  
>  	if (!debug && !(ts->pfrts_flags & PFR_TFLAG_ACTIVE))
>  		return;
> +	ct = ctime(&time);
>  	print_table(&ts->pfrts_t, 1, debug);
>  	printf("\tAddresses:   %d\n", ts->pfrts_cnt);
> -	printf("\tCleared:     %s", ctime(&time));
> +	if (ct)
> +		printf("\tCleared:     %s", ct);
> +	else
> +		printf("\tCleared:     %lld", time);
>  	printf("\tReferences:  [ Anchors: %-18d Rules: %-18d ]\n",
>  	    ts->pfrts_refcnt[PFR_REFCNT_ANCHOR],
>  	    ts->pfrts_refcnt[PFR_REFCNT_RULE]);
> @@ -487,11 +492,16 @@ print_addrx(struct pfr_addr *ad, struct pfr_addr *rad, int dns)
>  void
>  print_astats(struct pfr_astats *as, int dns)
>  {
> -	time_t	time = as->pfras_tzero;
> -	int	dir, op;
> +	time_t	 time = as->pfras_tzero;
> +	int	 dir, op;
> +	char	*ct;
>  
> +	ct = ctime(&time);
>  	print_addrx(&as->pfras_a, NULL, dns);
> -	printf("\tCleared:     %s", ctime(&time));
> +	if (ct)
> +		printf("\tCleared:     %s", ctime(&time));
> +	else
> +		printf("\tCleared:     %lld", time);
>  	if (as->pfras_a.pfra_states)
>  		printf("\tActive States:      %d\n", as->pfras_a.pfra_states);
>  	if (as->pfras_a.pfra_type == PFRKE_COST)
> @@ -603,8 +613,9 @@ pfctl_show_ifaces(const char *filter, int opts)
>  void
>  print_iface(struct pfi_kif *p, int opts)
>  {
> -	time_t	tzero = p->pfik_tzero;
> -	int	i, af, dir, act;
> +	time_t	 tzero = p->pfik_tzero;
> +	int	 i, af, dir, act;
> +	char	*ct;
>  
>  	printf("%s", p->pfik_name);
>  	if (opts & PF_OPT_VERBOSE) {
> @@ -615,7 +626,12 @@ print_iface(struct pfi_kif *p, int opts)
>  
>  	if (!(opts & PF_OPT_VERBOSE2))
>  		return;
> -	printf("\tCleared:     %s", ctime(&tzero));
> +
> +	ct = ctime(&tzero);
> +	if (ct)
> +		printf("\tCleared:     %s", ct);
> +	else
> +		printf("\tCleared:     %lld", tzero);
>  	printf("\tReferences:  [ States:  %-18d Rules: %-18d ]\n",
>  	    p->pfik_states, p->pfik_rules);
>  	for (i = 0; i < 8; i++) {
> diff --git sbin/restore/tape.c sbin/restore/tape.c
> index 4288c79e1a6..26e7ee5b807 100644
> --- sbin/restore/tape.c
> +++ sbin/restore/tape.c
> @@ -387,8 +387,17 @@ gethdr:
>  	}
>  	if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
>  		time_t t = (time_t)tmpbuf.c_date;
> -		fprintf(stderr, "Wrong dump date\n\tgot: %s", ctime(&t));
> -		fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
> +		char *ct1, *ct2;
> +
> +		ct1 = ctime(&t);
> +		ct2 = ctime(&dumpdate);
> +		if (ct1 != NULL && ct2 != NULL) {
> +			fprintf(stderr, "Wrong dump date\n\tgot: %s", ct1);
> +			fprintf(stderr, "\twanted: %s", ct2);
> +		} else {
> +			fprintf(stderr, "Wrong dump date\n\tgot: %lld", t);
> +			fprintf(stderr, "\twanted: %lld", dumpdate);
> +		}
>  		volno = 0;
>  		goto again;
>  	}
> @@ -488,12 +497,21 @@ void
>  printdumpinfo(void)
>  {
>  	time_t t;
> +	char *ct;
>  
>  	t = (time_t)spcl.c_date;
> -	fprintf(stdout, "Dump   date: %s", ctime(&t));
> +	ct = ctime(&t);
> +	if (ct)
> +		fprintf(stdout, "Dump   date: %s", ct);
> +	else
> +		fprintf(stdout, "Dump   date: %lld", t);
>  	t = (time_t)spcl.c_ddate;
> -	fprintf(stdout, "Dumped from: %s",
> -	    (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&t));
> +	ct = ctime(&t);
> +	if (ct)
> +		fprintf(stdout, "Dumped from: %s",
> +		    (spcl.c_ddate == 0) ? "the epoch\n" : ct);
> +	else
> +		fprintf(stdout, "Dumped from: %lld", t);
>  	if (spcl.c_host[0] == '\0')
>  		return;
>  	fprintf(stderr, "Level %d dump of %s on %s:%s\n",
> diff --git sbin/route/route.c sbin/route/route.c
> index 4228114edc7..8cd43b6fa3b 100644
> --- sbin/route/route.c
> +++ sbin/route/route.c
> @@ -1140,6 +1140,7 @@ monitor(int argc, char *argv[])
>  	int n;
>  	char msg[2048];
>  	time_t now;
> +	char *ct;
>  
>  	verbose = 1;
>  	for (;;) {
> @@ -1149,7 +1150,11 @@ monitor(int argc, char *argv[])
>  			err(1, "read");
>  		}
>  		now = time(NULL);
> -		printf("got message of size %d on %s", n, ctime(&now));
> +		ct = ctime(&now);
> +		if (ct)
> +			printf("got message of size %d on %s", n, ct);
> +		else
> +			printf("got message of size %d on %lld", n, now);
>  		print_rtmsg((struct rt_msghdr *)msg, n);
>  	}
>  }
> diff --git sbin/savecore/savecore.c sbin/savecore/savecore.c
> index afc223e5a08..23356c76b2b 100644
> --- sbin/savecore/savecore.c
> +++ sbin/savecore/savecore.c
> @@ -608,6 +608,7 @@ int
>  get_crashtime(void)
>  {
>  	time_t dumptime;			/* Time the dump was taken. */
> +	char *ct;
>  
>  	(void)KREAD(kd_dump, dump_nl[X_TIME].n_value, &dumptime);
>  	if (dumptime == 0) {
> @@ -615,7 +616,12 @@ get_crashtime(void)
>  			syslog(LOG_ERR, "dump time is zero");
>  		return (0);
>  	}
> -	(void)printf("savecore: system went down at %s", ctime(&dumptime));
> +	ct = ctime(&dumptime);
> +	if (ct)
> +		printf("savecore: system went down at %s", ct);
> +	else
> +		printf("savecore: system went down %lld seconds after the epoch",
> +		    dumptime);
>  #define	SECSPERDAY	(24 * 60 * 60)
>  #define	LEEWAY		(7 * SECSPERDAY)
>  	if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) {
> diff --git sbin/scan_ffs/scan_ffs.c sbin/scan_ffs/scan_ffs.c
> index d1b673c4dca..43d96240dea 100644
> --- sbin/scan_ffs/scan_ffs.c
> +++ sbin/scan_ffs/scan_ffs.c
> @@ -87,14 +87,30 @@ ufsscan(int fd, daddr_t beg, daddr_t end, int flags)
>  					} else {
>  						/* XXX 2038 */
>  						time_t t = sb->fs_ffs1_time;
> +						char *ct = ctime(&t);
> +						if (ct)
> +							printf("ffs at %lld "
> +							    "size %lld "
> +							    "mount %s time %s",
> +							    (long long)(blk+
> +							    (n/512) -
> +							    (2*SBSIZE/512)),
> +							    (long long)(off_t)
> +							    sb->fs_ffs1_size *
> +							    sb->fs_fsize,
> +							    lastmount, ct);
> +						else
> +							printf("ffs at %lld "
> +							    "size %lld "
> +							    "mount %s time %lld",
> +							    (long long)(blk+
> +							    (n/512) -
> +							    (2*SBSIZE/512)),
> +							    (long long)(off_t)
> +							    sb->fs_ffs1_size *
> +							    sb->fs_fsize,
> +							    lastmount, t);

This *is* getting a bit silly...  Time to split stuff off into a
separate function?

>  
> -						printf("ffs at %lld size %lld "
> -						    "mount %s time %s",
> -						    (long long)(blk+(n/512) -
> -						    (2*SBSIZE/512)),
> -						    (long long)(off_t)sb->fs_ffs1_size *
> -						    sb->fs_fsize,
> -						    lastmount, ctime(&t));
>  					}
>  
>  					if (flags & FLAG_SMART) {
> diff --git sbin/sysctl/sysctl.c sbin/sysctl/sysctl.c
> index 9beb8167536..43b36939d4a 100644
> --- sbin/sysctl/sysctl.c
> +++ sbin/sysctl/sysctl.c
> @@ -937,8 +937,13 @@ parse(char *string, int flags)
>  		struct timeval *btp = (struct timeval *)buf;
>  
>  		if (!nflag) {
> +			char *ct;
>  			boottime = btp->tv_sec;
> -			(void)printf("%s%s%s", string, equ, ctime(&boottime));
> +			ct = ctime(&boottime);
> +			if (ct)
> +				(void)printf("%s%s%s", string, equ, ct);
> +			else
> +				(void)printf("%s%s%lld", string, equ, boottime);
>  		} else
>  			(void)printf("%lld\n", (long long)btp->tv_sec);
>  		return;
> @@ -2855,9 +2860,11 @@ print_sensor(struct sensor *s)
>  		time_t t = s->tv.tv_sec;
>  		char ct[26];
>  
> -		ctime_r(&t, ct);
> -		ct[19] = '\0';
> -		printf(", %s.%03ld", ct, s->tv.tv_usec / 1000);
> +		if (ctime_r(&t, ct)) {
> +			ct[19] = '\0';
> +			printf(", %s.%03ld", ct, s->tv.tv_usec / 1000);
> +		} else
> +			printf(", %lld.%03ld", t, s->tv.tv_usec / 1000);
>  	}
>  }
>  
> diff --git sbin/unwind/libunbound/validator/autotrust.c sbin/unwind/libunbound/validator/autotrust.c
> index 3eb13b35c22..2c386644d7a 100644
> --- sbin/unwind/libunbound/validator/autotrust.c
> +++ sbin/unwind/libunbound/validator/autotrust.c
> @@ -1084,7 +1084,11 @@ trustanchor_state2str(autr_state_type s)
>  /** ctime r for autotrust */
>  static char* autr_ctime_r(time_t* t, char* s)
>  {
> -	ctime_r(t, s);
> +	if (ctime_r(t, s) == NULL) {
> +		s[0] = '?';
> +		s[1] = '\n';
> +		s[2] = '\0';
> +	}
>  #ifdef USE_WINSOCK
>  	if(strlen(s) > 10 && s[7]==' ' && s[8]=='0')
>  		s[8]=' '; /* fix error in windows ctime */
> 
> 
> 
> -- 
> In my defence, I have been left unsupervised.
> 
>