Skip to content

Commit 4d42c44

Browse files
andy-shevalexandrebelloni
authored andcommitted
lib/vsprintf: Print time and date in human readable format via %pt
There are users which print time and date represented by content of struct rtc_time in human readable format. Instead of open coding that each time introduce %ptR[dt][r] specifier. Cc: Arnd Bergmann <arnd@arndb.de> Cc: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Cc: Guan Xuetao <gxt@mprc.pku.edu.cn> Cc: Ingo Molnar <mingo@kernel.org> Cc: Jason Wessel <jason.wessel@windriver.com> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Jonathan Hunter <jonathanh@nvidia.com> Cc: Krzysztof Kozlowski <krzk@kernel.org> Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net> Cc: Thierry Reding <thierry.reding@gmail.com> Cc: Petr Mladek <pmladek@suse.com> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Reviewed-by: Petr Mladek <pmladek@suse.com> Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
1 parent 8c4cf16 commit 4d42c44

File tree

3 files changed

+176
-3
lines changed

3 files changed

+176
-3
lines changed

Documentation/core-api/printk-formats.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,24 @@ Examples::
412412

413413
Passed by reference.
414414

415+
Time and date (struct rtc_time)
416+
-------------------------------
417+
418+
::
419+
420+
%ptR YYYY-mm-ddTHH:MM:SS
421+
%ptRd YYYY-mm-dd
422+
%ptRt HH:MM:SS
423+
%ptR[dt][r]
424+
425+
For printing date and time as represented by struct rtc_time structure in
426+
human readable format.
427+
428+
By default year will be incremented by 1900 and month by 1. Use %ptRr (raw)
429+
to suppress this behaviour.
430+
431+
Passed by reference.
432+
415433
struct clk
416434
----------
417435

lib/test_printf.c

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/module.h>
1010
#include <linux/printk.h>
1111
#include <linux/random.h>
12+
#include <linux/rtc.h>
1213
#include <linux/slab.h>
1314
#include <linux/string.h>
1415

@@ -249,12 +250,11 @@ plain_format(void)
249250
#endif /* BITS_PER_LONG == 64 */
250251

251252
static int __init
252-
plain_hash(void)
253+
plain_hash_to_buffer(const void *p, char *buf, size_t len)
253254
{
254-
char buf[PLAIN_BUF_SIZE];
255255
int nchars;
256256

257-
nchars = snprintf(buf, PLAIN_BUF_SIZE, "%p", PTR);
257+
nchars = snprintf(buf, len, "%p", p);
258258

259259
if (nchars != PTR_WIDTH)
260260
return -1;
@@ -265,6 +265,20 @@ plain_hash(void)
265265
return 0;
266266
}
267267

268+
return 0;
269+
}
270+
271+
272+
static int __init
273+
plain_hash(void)
274+
{
275+
char buf[PLAIN_BUF_SIZE];
276+
int ret;
277+
278+
ret = plain_hash_to_buffer(PTR, buf, PLAIN_BUF_SIZE);
279+
if (ret)
280+
return ret;
281+
268282
if (strncmp(buf, PTR_STR, PTR_WIDTH) == 0)
269283
return -1;
270284

@@ -294,6 +308,23 @@ plain(void)
294308
}
295309
}
296310

311+
static void __init
312+
test_hashed(const char *fmt, const void *p)
313+
{
314+
char buf[PLAIN_BUF_SIZE];
315+
int ret;
316+
317+
/*
318+
* No need to increase failed test counter since this is assumed
319+
* to be called after plain().
320+
*/
321+
ret = plain_hash_to_buffer(p, buf, PLAIN_BUF_SIZE);
322+
if (ret)
323+
return;
324+
325+
test(buf, fmt, p);
326+
}
327+
297328
static void __init
298329
symbol_ptr(void)
299330
{
@@ -418,6 +449,29 @@ struct_va_format(void)
418449
{
419450
}
420451

452+
static void __init
453+
struct_rtc_time(void)
454+
{
455+
/* 1543210543 */
456+
const struct rtc_time tm = {
457+
.tm_sec = 43,
458+
.tm_min = 35,
459+
.tm_hour = 5,
460+
.tm_mday = 26,
461+
.tm_mon = 10,
462+
.tm_year = 118,
463+
};
464+
465+
test_hashed("%pt", &tm);
466+
467+
test("2018-11-26T05:35:43", "%ptR", &tm);
468+
test("0118-10-26T05:35:43", "%ptRr", &tm);
469+
test("05:35:43|2018-11-26", "%ptRt|%ptRd", &tm, &tm);
470+
test("05:35:43|0118-10-26", "%ptRtr|%ptRdr", &tm, &tm);
471+
test("05:35:43|2018-11-26", "%ptRttr|%ptRdtr", &tm, &tm);
472+
test("05:35:43 tr|2018-11-26 tr", "%ptRt tr|%ptRd tr", &tm, &tm);
473+
}
474+
421475
static void __init
422476
struct_clk(void)
423477
{
@@ -529,6 +583,7 @@ test_pointer(void)
529583
uuid();
530584
dentry();
531585
struct_va_format();
586+
struct_rtc_time();
532587
struct_clk();
533588
bitmap();
534589
netdev_features();

lib/vsprintf.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <linux/ioport.h>
3131
#include <linux/dcache.h>
3232
#include <linux/cred.h>
33+
#include <linux/rtc.h>
3334
#include <linux/uuid.h>
3435
#include <linux/of.h>
3536
#include <net/addrconf.h>
@@ -822,6 +823,20 @@ static const struct printf_spec default_dec_spec = {
822823
.precision = -1,
823824
};
824825

826+
static const struct printf_spec default_dec02_spec = {
827+
.base = 10,
828+
.field_width = 2,
829+
.precision = -1,
830+
.flags = ZEROPAD,
831+
};
832+
833+
static const struct printf_spec default_dec04_spec = {
834+
.base = 10,
835+
.field_width = 4,
836+
.precision = -1,
837+
.flags = ZEROPAD,
838+
};
839+
825840
static noinline_for_stack
826841
char *resource_string(char *buf, char *end, struct resource *res,
827842
struct printf_spec spec, const char *fmt)
@@ -1549,6 +1564,87 @@ char *address_val(char *buf, char *end, const void *addr, const char *fmt)
15491564
return special_hex_number(buf, end, num, size);
15501565
}
15511566

1567+
static noinline_for_stack
1568+
char *date_str(char *buf, char *end, const struct rtc_time *tm, bool r)
1569+
{
1570+
int year = tm->tm_year + (r ? 0 : 1900);
1571+
int mon = tm->tm_mon + (r ? 0 : 1);
1572+
1573+
buf = number(buf, end, year, default_dec04_spec);
1574+
if (buf < end)
1575+
*buf = '-';
1576+
buf++;
1577+
1578+
buf = number(buf, end, mon, default_dec02_spec);
1579+
if (buf < end)
1580+
*buf = '-';
1581+
buf++;
1582+
1583+
return number(buf, end, tm->tm_mday, default_dec02_spec);
1584+
}
1585+
1586+
static noinline_for_stack
1587+
char *time_str(char *buf, char *end, const struct rtc_time *tm, bool r)
1588+
{
1589+
buf = number(buf, end, tm->tm_hour, default_dec02_spec);
1590+
if (buf < end)
1591+
*buf = ':';
1592+
buf++;
1593+
1594+
buf = number(buf, end, tm->tm_min, default_dec02_spec);
1595+
if (buf < end)
1596+
*buf = ':';
1597+
buf++;
1598+
1599+
return number(buf, end, tm->tm_sec, default_dec02_spec);
1600+
}
1601+
1602+
static noinline_for_stack
1603+
char *rtc_str(char *buf, char *end, const struct rtc_time *tm, const char *fmt)
1604+
{
1605+
bool have_t = true, have_d = true;
1606+
bool raw = false;
1607+
int count = 2;
1608+
1609+
switch (fmt[count]) {
1610+
case 'd':
1611+
have_t = false;
1612+
count++;
1613+
break;
1614+
case 't':
1615+
have_d = false;
1616+
count++;
1617+
break;
1618+
}
1619+
1620+
raw = fmt[count] == 'r';
1621+
1622+
if (have_d)
1623+
buf = date_str(buf, end, tm, raw);
1624+
if (have_d && have_t) {
1625+
/* Respect ISO 8601 */
1626+
if (buf < end)
1627+
*buf = 'T';
1628+
buf++;
1629+
}
1630+
if (have_t)
1631+
buf = time_str(buf, end, tm, raw);
1632+
1633+
return buf;
1634+
}
1635+
1636+
static noinline_for_stack
1637+
char *time_and_date(char *buf, char *end, void *ptr, struct printf_spec spec,
1638+
const char *fmt)
1639+
{
1640+
switch (fmt[1]) {
1641+
case 'R':
1642+
return rtc_str(buf, end, (const struct rtc_time *)ptr, fmt);
1643+
default:
1644+
return ptr_to_id(buf, end, ptr, spec);
1645+
}
1646+
}
1647+
15521648
static noinline_for_stack
15531649
char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec,
15541650
const char *fmt)
@@ -1828,6 +1924,8 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,
18281924
* - 'd[234]' For a dentry name (optionally 2-4 last components)
18291925
* - 'D[234]' Same as 'd' but for a struct file
18301926
* - 'g' For block_device name (gendisk + partition number)
1927+
* - 't[R][dt][r]' For time and date as represented:
1928+
* R struct rtc_time
18311929
* - 'C' For a clock, it prints the name (Common Clock Framework) or address
18321930
* (legacy clock framework) of the clock
18331931
* - 'Cn' For a clock, it prints the name (Common Clock Framework) or address
@@ -1952,6 +2050,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
19522050
return address_val(buf, end, ptr, fmt);
19532051
case 'd':
19542052
return dentry_name(buf, end, ptr, spec, fmt);
2053+
case 't':
2054+
return time_and_date(buf, end, ptr, spec, fmt);
19552055
case 'C':
19562056
return clock(buf, end, ptr, spec, fmt);
19572057
case 'D':

0 commit comments

Comments
 (0)