man-pages/0000-ctime.3-Document-how-to-check-errors-from-mktime.patch
Patsy Griffin f093551d4c Activate previously added patch to improve mktime documentation and
add 3 related upstream patches including an example.

Related: RHEL-58342
2025-06-20 08:20:54 -04:00

174 lines
5.2 KiB
Diff

commit e541b219854e6be90b5628f88cd62edb44c9e9f2
Author: Alejandro Colomar <alx@kernel.org>
Date: Fri Aug 23 14:34:00 2024 +0200
ctime.3: Document how to check errors from mktime(3)
-1 is a valid successful time_t, for one second before the Epoch. And
mktime(3) is allowed (like most libc calls) to set errno on success.
This makes it impossible to determine errors from the return value or
errno.
ISO C specifies that tp->tm_wday is unmodified after a failed call, and
puts an example where this is used to determine errors. It is indeed
the only way to check for errors from this call.
Document this detail in the RETURN VALUE section, add a CAVEATS section
that warns about this, and write an example program that shows how to
properly call this function.
Most code I've been able to find in several search engines either
doesn't check for errors after mktime(3), or checks them incorrectly, so
this documentation should help fix those.
This is guaranteed since ISO C23 and POSIX.1-2024. Prior to those
standards, there was no standard way to check for errors. However,
there are no known implementations that do not conform to this.
Link: <https://lore.kernel.org/linux-man/20240823131024.GD2713@cventin.lip.ens-lyon.fr/T/#t>
Link: <https://lore.kernel.org/linux-man/6un6baaq5tez23irtycuvzqtuh7a4sdrf2px7tnyb3y6iqoxmq@2ofln4cd27ep/T/#t>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3147.txt>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3148.doc>
Link: <https://austingroupbugs.net/view.php?id=1614>
Link: <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3220.pdf#subsubsection.7.29.2.3>
Reported-by: Paul Eggert <eggert@cs.ucla.edu>
Cc: Vincent Lefevre <vincent@vinc17.net>
Cc: DJ Delorie <dj@redhat.com>
Cc: Carlos O'Donell <carlos@redhat.com>
Cc: Xi Ruoyao <xry111@xry111.site>
Cc: Brian Inglis <Brian.Inglis@SystematicSW.ab.ca>
Cc: "Robert C. Seacord" <rcseacord@gmail.com>
Cc: Jens Gustedt <jens.gustedt@inria.fr>
Cc: Robert Elz <kre@munnari.oz.au>
Cc: Andrew Josey <ajosey@opengroup.org>
Cc: Geoff Clare <gwc@opengroup.org>
Cc: Hans Åberg <haberg-1@telia.com>
Cc: GNU C Library <libc-alpha@sourceware.org>
Cc: Austin Group <austin-group-l@opengroup.org>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Conflicts:
Minor wording differences
diff -Nrup a/man3/ctime.3 b/man3/ctime.3
--- a/man3/ctime.3 2023-04-02 20:27:24.000000000 -0400
+++ b/man3/ctime.3 2025-06-18 09:39:54.782440669 -0400
@@ -247,7 +247,10 @@ expressed as a value of type
On error,
.BR mktime ()
returns the value
-.IR "(time_t)\ \-1" .
+.IR "(time_t)\ \-1" ,
+and leaves the
+.I tm->tm_wday
+member unmodified.
The remaining functions return NULL on error.
On error,
.I errno
@@ -400,6 +403,105 @@ a broken-down time structure and an arra
Execution of any of the functions may overwrite the information returned
in either of these objects by any of the other functions."
This can occur in the glibc implementation.
+.SH CAVEATS
+.SS mktime()
+.I (time_t) \-1
+can represent a valid time
+(one second before the Epoch).
+To determine whether
+.BR mktime ()
+failed,
+one must use the
+.I tm->tm_wday
+field.
+See the example program in EXAMPLES.
+.SH EXAMPLES
+The following shell session shows sample runs of the program:
+.P
+.in +4n
+.EX
+.RB $\~ "TZ=UTC ./a.out 1969 12 31 23 59 59 0" ;
+\-1
+$
+.RB $\~ "export TZ=Europe/Madrid" ;
+$
+.RB $\~ "./a.out 2147483647 2147483647 00 00 00 00 -1" ;
+a.out: mktime: Value too large for defined data type
+$
+.RB $\~ "./a.out 2024 08 23 00 17 53 \-1" ;
+1724365073
+.RB $\~ "./a.out 2024 08 23 00 17 53 0" ;
+1724368673
+.RB $\~ "./a.out 2024 08 23 00 17 53 1" ;
+1724365073
+$
+.RB $\~ "./a.out 2024 02 23 00 17 53 \-1" ;
+1708643873
+.RB $\~ "./a.out 2024 02 23 00 17 53 0" ;
+1708643873
+.RB $\~ "./a.out 2024 02 23 00 17 53 1" ;
+1708640273
+$
+.RB $\~ "./a.out 2023 03 26 02 17 53 \-1" ;
+1679793473
+$
+.RB $\~ "./a.out 2023 10 29 02 17 53 \-1" ;
+1698542273
+.RB $\~ "./a.out 2023 10 29 02 17 53 0" ;
+1698542273
+.RB $\~ "./a.out 2023 10 29 02 17 53 1" ;
+1698538673
+$
+.RB $\~ "./a.out 2023 02 29 12 00 00 \-1" ;
+1677668400
+.EE
+.SS Program source: mktime.c
+\&
+.\" SRC BEGIN (mktime.c)
+.EX
+#include <err.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+\&
+#define is_signed(T) ((T) \-1 < 1)
+\&
+int
+main(int argc, char *argv[])
+{
+ char **p;
+ time_t t;
+ struct tm tm;
+\&
+ if (argc != 8) {
+ fprintf(stderr, "Usage: %s yyyy mm dd HH MM SS isdst\[rs]n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+\&
+ p = &argv[1];
+ tm.tm_year = atoi(*p++) \- 1900;
+ tm.tm_mon = atoi(*p++) \- 1;
+ tm.tm_mday = atoi(*p++);
+ tm.tm_hour = atoi(*p++);
+ tm.tm_min = atoi(*p++);
+ tm.tm_sec = atoi(*p++);
+ tm.tm_isdst = atoi(*p++);
+\&
+ tm.tm_wday = \-1;
+ t = mktime(&tm);
+ if (tm.tm_wday == \-1)
+ err(EXIT_FAILURE, "mktime");
+\&
+ if (is_signed(time_t))
+ printf("%jd\[rs]n", (intmax_t) t);
+ else
+ printf("%ju\[rs]n", (uintmax_t) t);
+\&
+ exit(EXIT_SUCCESS);
+}
+.EE
+.\" SRC END
.SH SEE ALSO
.BR date (1),
.BR gettimeofday (2),