man-pages/0003-ctime.3-EXAMPLES-Document-how-to-detect-invalid-or-ambiguous-times.patch
Patsy Griffin 485889d11c Add RTLD_DI_PHDR to dlinfo(3) man page.
Provide more details on using mktime(3) in the manpage.

Resolves: RHEL-61159
Resolves: RHEL-61136
2025-06-25 17:24:54 -04:00

163 lines
3.8 KiB
Diff

commit bd576aaf5fce40100133c1d48c02eacbf25594c8
Author: Alejandro Colomar <alx@kernel.org>
Date: Sat Aug 24 00:51:55 2024 +0200
ctime.3: EXAMPLES: Document how to detect invalid or ambiguous times
This example documents how to detect some corner cases of mktime(3),
such as DST transitions and other jumps in the calendar.
Link: <https://www.redhat.com/en/blog/brief-history-mktime>
Cc: DJ Delorie <dj@redhat.com>
Cc: Carlos O'Donell <carlos@redhat.com>
Cc: Paul Eggert <eggert@cs.ucla.edu>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
diff --git a/man3/ctime.3 b/man/man3/ctime.3
index 53abab6d9..acd6f1565 100644
--- a/man3/ctime.3
+++ b/man3/ctime.3
@@ -467,6 +467,14 @@ For example, a change in the timezone definition
may cause a clock time to be repeated or skipped
without a corresponding DST change.
.SH EXAMPLES
+The program below defines a wrapper that
+allows detecting invalid and ambiguous times,
+with
+.B EINVAL
+and
+.BR ENOTUNIQ ,
+respectively.
+.P
The following shell session shows sample runs of the program:
.P
.in +4n
@@ -482,6 +490,7 @@ $
.RB $\~ "./a.out 2024 08 23 00 17 53 \-1" ;
1724365073
.RB $\~ "./a.out 2024 08 23 00 17 53 0" ;
+a.out: my_mktime: Invalid argument
1724368673
.RB $\~ "./a.out 2024 08 23 00 17 53 1" ;
1724365073
@@ -491,12 +500,15 @@ $
.RB $\~ "./a.out 2024 02 23 00 17 53 0" ;
1708643873
.RB $\~ "./a.out 2024 02 23 00 17 53 1" ;
+a.out: my_mktime: Invalid argument
1708640273
$
.RB $\~ "./a.out 2023 03 26 02 17 53 \-1" ;
+a.out: my_mktime: Invalid argument
1679793473
$
.RB $\~ "./a.out 2023 10 29 02 17 53 \-1" ;
+a.out: my_mktime: Name not unique on network
1698542273
.RB $\~ "./a.out 2023 10 29 02 17 53 0" ;
1698542273
@@ -504,6 +516,7 @@ $
1698538673
$
.RB $\~ "./a.out 2023 02 29 12 00 00 \-1" ;
+a.out: my_mktime: Invalid argument
1677668400
.EE
.SS Program source: mktime.c
@@ -511,13 +524,17 @@ $
.\" SRC BEGIN (mktime.c)
.EX
#include <err.h>
+#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <time.h>
\&
#define is_signed(T) ((T) \-1 < 1)
\&
+time_t my_mktime(struct tm *tp);
+\&
int
main(int argc, char *argv[])
{
@@ -539,10 +556,13 @@ main(int argc, char *argv[])
tm.tm_sec = atoi(*p++);
tm.tm_isdst = atoi(*p++);
\&
+ errno = 0;
tm.tm_wday = \-1;
- t = mktime(&tm);
+ t = my_mktime(&tm);
if (tm.tm_wday == \-1)
err(EXIT_FAILURE, "mktime");
+ if (errno == EINVAL || errno == ENOTUNIQ)
+ warn("my_mktime");
\&
if (is_signed(time_t))
printf("%jd\[rs]n", (intmax_t) t);
@@ -551,6 +571,62 @@ main(int argc, char *argv[])
\&
exit(EXIT_SUCCESS);
}
+\&
+time_t
+my_mktime(struct tm *tp)
+{
+ int e, isdst;
+ time_t t;
+ struct tm tm;
+ unsigned char wday[sizeof(tp\->tm_wday)];
+\&
+ e = errno;
+\&
+ tm = *tp;
+ isdst = tp\->tm_isdst;
+\&
+ memcpy(wday, &tp\->tm_wday, sizeof(wday));
+ tp\->tm_wday = \-1;
+ t = mktime(tp);
+ if (tp\->tm_wday == \-1) {
+ memcpy(&tp\->tm_wday, wday, sizeof(wday));
+ return \-1;
+ }
+\&
+ if (isdst == \-1)
+ tm.tm_isdst = tp\->tm_isdst;
+\&
+ if ( tm.tm_sec != tp\->tm_sec
+ || tm.tm_min != tp\->tm_min
+ || tm.tm_hour != tp\->tm_hour
+ || tm.tm_mday != tp\->tm_mday
+ || tm.tm_mon != tp\->tm_mon
+ || tm.tm_year != tp\->tm_year
+ || tm.tm_isdst != tp\->tm_isdst)
+ {
+ errno = EINVAL;
+ return t;
+ }
+\&
+ if (isdst != \-1)
+ goto out;
+\&
+ tm = *tp;
+ tm.tm_isdst = !tm.tm_isdst;
+\&
+ tm.tm_wday = \-1;
+ mktime(&tm);
+ if (tm.tm_wday == \-1)
+ goto out;
+\&
+ if (tm.tm_isdst != tp\->tm_isdst) {
+ errno = ENOTUNIQ;
+ return t;
+ }
+out:
+ errno = e;
+ return t;
+}
.EE
.\" SRC END
.SH SEE ALSO