Blame view

lib/vsprintf.c 82.1 KB
457c89965   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
  /*
   *  linux/lib/vsprintf.c
   *
   *  Copyright (C) 1991, 1992  Linus Torvalds
   */
  
  /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
  /*
   * Wirzenius wrote this portably, Torvalds fucked it up :-)
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
12
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
15
16
17
18
19
   * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
   * - changed to provide snprintf and vsnprintf functions
   * So Feb  1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de>
   * - scnprintf and vscnprintf
   */
  
  #include <stdarg.h>
ef27ac18b   Rasmus Villemoes   lib/vsprintf.c: m...
20
  #include <linux/build_bug.h>
0d1d7a558   Stephen Boyd   lib/vsprintf.c: I...
21
  #include <linux/clk.h>
900cca294   Geert Uytterhoeven   lib/vsprintf: add...
22
  #include <linux/clk-provider.h>
57f5677e5   Rasmus Villemoes   printf: add suppo...
23
  #include <linux/errname.h>
8bc3bcc93   Paul Gortmaker   lib: reduce the u...
24
  #include <linux/module.h>	/* for KSYM_SYMBOL_LEN */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
27
28
  #include <linux/types.h>
  #include <linux/string.h>
  #include <linux/ctype.h>
  #include <linux/kernel.h>
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
29
  #include <linux/kallsyms.h>
53809751a   Jan Beulich   sscanf: don't ign...
30
  #include <linux/math64.h>
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
31
  #include <linux/uaccess.h>
332d2e783   Linus Torvalds   Implement %pR to ...
32
  #include <linux/ioport.h>
4b6ccca70   Al Viro   add formats for d...
33
  #include <linux/dcache.h>
312b4e226   Ryan Mallon   vsprintf: check r...
34
  #include <linux/cred.h>
4d42c4472   Andy Shevchenko   lib/vsprintf: Pri...
35
  #include <linux/rtc.h>
7daac5b2f   Andy Shevchenko   lib/vsprintf: Pri...
36
  #include <linux/time.h>
2b1b0d667   Andy Shevchenko   lib/uuid.c: intro...
37
  #include <linux/uuid.h>
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
38
  #include <linux/of.h>
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
39
  #include <net/addrconf.h>
ad67b74d2   Tobin C. Harding   printk: hash addr...
40
41
  #include <linux/siphash.h>
  #include <linux/compiler.h>
a92eb7621   Sakari Ailus   lib/vsprintf: Mak...
42
  #include <linux/property.h>
1031bc589   Dmitry Monakhov   lib/vsprintf: add...
43
44
45
  #ifdef CONFIG_BLOCK
  #include <linux/blkdev.h>
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46

edf14cdbf   Vlastimil Babka   mm, printk: intro...
47
  #include "../mm/internal.h"	/* For the trace_print_flags arrays */
4e57b6817   Tim Schmielau   [PATCH] fix missi...
48
  #include <asm/page.h>		/* for PAGE_SIZE */
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
49
  #include <asm/byteorder.h>	/* cpu_to_le16 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50

71dca95d5   Andy Shevchenko   lib/vsprintf: add...
51
  #include <linux/string_helpers.h>
1dff46d69   Alexey Dobriyan   lib/kstrtox: comm...
52
  #include "kstrtox.h"
aa46a63ef   Harvey Harrison   lib: pull base-gu...
53

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
  /**
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
55
   * simple_strtoull - convert a string to an unsigned long long
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
   * @cp: The start of the string
   * @endp: A pointer to the end of the parsed string will be placed here
   * @base: The number base to use
462e47110   Eldad Zack   simple_strto*: an...
59
   *
e8cc2b97c   Andy Shevchenko   lib/vsprintf: upd...
60
   * This function has caveats. Please use kstrtoull instead.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
   */
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
62
  unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
  {
1dff46d69   Alexey Dobriyan   lib/kstrtox: comm...
64
65
  	unsigned long long result;
  	unsigned int rv;
aa46a63ef   Harvey Harrison   lib: pull base-gu...
66

1dff46d69   Alexey Dobriyan   lib/kstrtox: comm...
67
68
69
70
  	cp = _parse_integer_fixup_radix(cp, &base);
  	rv = _parse_integer(cp, base, &result);
  	/* FIXME */
  	cp += (rv & ~KSTRTOX_OVERFLOW);
aa46a63ef   Harvey Harrison   lib: pull base-gu...
71

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
  	if (endp)
  		*endp = (char *)cp;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
74

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
  	return result;
  }
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
77
  EXPORT_SYMBOL(simple_strtoull);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
79
  
  /**
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
80
   * simple_strtoul - convert a string to an unsigned long
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
83
   * @cp: The start of the string
   * @endp: A pointer to the end of the parsed string will be placed here
   * @base: The number base to use
462e47110   Eldad Zack   simple_strto*: an...
84
   *
e8cc2b97c   Andy Shevchenko   lib/vsprintf: upd...
85
   * This function has caveats. Please use kstrtoul instead.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
   */
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
87
  unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
  {
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
89
  	return simple_strtoull(cp, endp, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
  }
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
91
  EXPORT_SYMBOL(simple_strtoul);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
  
  /**
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
94
   * simple_strtol - convert a string to a signed long
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
97
   * @cp: The start of the string
   * @endp: A pointer to the end of the parsed string will be placed here
   * @base: The number base to use
462e47110   Eldad Zack   simple_strto*: an...
98
   *
e8cc2b97c   Andy Shevchenko   lib/vsprintf: upd...
99
   * This function has caveats. Please use kstrtol instead.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
   */
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
101
  long simple_strtol(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  {
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
103
104
  	if (*cp == '-')
  		return -simple_strtoul(cp + 1, endp, base);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
105

922ac25c9   André Goddard Rosa   vsprintf: reuse a...
106
  	return simple_strtoul(cp, endp, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
  }
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
108
  EXPORT_SYMBOL(simple_strtol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
110
111
112
113
114
  
  /**
   * simple_strtoll - convert a string to a signed long long
   * @cp: The start of the string
   * @endp: A pointer to the end of the parsed string will be placed here
   * @base: The number base to use
462e47110   Eldad Zack   simple_strto*: an...
115
   *
e8cc2b97c   Andy Shevchenko   lib/vsprintf: upd...
116
   * This function has caveats. Please use kstrtoll instead.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
   */
22d27051b   Harvey Harrison   lib: trivial whit...
118
  long long simple_strtoll(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
  {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
120
  	if (*cp == '-')
22d27051b   Harvey Harrison   lib: trivial whit...
121
  		return -simple_strtoull(cp + 1, endp, base);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
122

22d27051b   Harvey Harrison   lib: trivial whit...
123
  	return simple_strtoull(cp, endp, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
  }
98d5ce0d0   Hans Verkuil   lib/vsprintf.c: a...
125
  EXPORT_SYMBOL(simple_strtoll);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126

cf3b429b0   Joe Perches   vsprintf.c: use n...
127
128
  static noinline_for_stack
  int skip_atoi(const char **s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
  {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
130
  	int i = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131

43e5b666c   Rasmus Villemoes   lib/vsprintf.c: r...
132
  	do {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
  		i = i*10 + *((*s)++) - '0';
43e5b666c   Rasmus Villemoes   lib/vsprintf.c: r...
134
  	} while (isdigit(**s));
7b9186f5e   André Goddard Rosa   vsprintf: give it...
135

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
  	return i;
  }
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
  /*
   * Decimal conversion is by far the most typical, and is used for
   * /proc and /sys data. This directly impacts e.g. top performance
   * with many processes running. We optimize it for speed by emitting
   * two characters at a time, using a 200 byte lookup table. This
   * roughly halves the number of multiplications compared to computing
   * the digits one at a time. Implementation strongly inspired by the
   * previous version, which in turn used ideas described at
   * <http://www.cs.uiowa.edu/~jones/bcd/divide.html> (with permission
   * from the author, Douglas W. Jones).
   *
   * It turns out there is precisely one 26 bit fixed-point
   * approximation a of 64/100 for which x/100 == (x * (u64)a) >> 32
   * holds for all x in [0, 10^8-1], namely a = 0x28f5c29. The actual
   * range happens to be somewhat larger (x <= 1073741898), but that's
   * irrelevant for our purpose.
   *
   * For dividing a number in the range [10^4, 10^6-1] by 100, we still
   * need a 32x32->64 bit multiply, so we simply use the same constant.
   *
   * For dividing a number in the range [100, 10^4-1] by 100, there are
   * several options. The simplest is (x * 0x147b) >> 19, which is valid
   * for all x <= 43698.
133fd9f5c   Denys Vlasenko   vsprintf: further...
161
   */
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
162

7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
  static const u16 decpair[100] = {
  #define _(x) (__force u16) cpu_to_le16(((x % 10) | ((x / 10) << 8)) + 0x3030)
  	_( 0), _( 1), _( 2), _( 3), _( 4), _( 5), _( 6), _( 7), _( 8), _( 9),
  	_(10), _(11), _(12), _(13), _(14), _(15), _(16), _(17), _(18), _(19),
  	_(20), _(21), _(22), _(23), _(24), _(25), _(26), _(27), _(28), _(29),
  	_(30), _(31), _(32), _(33), _(34), _(35), _(36), _(37), _(38), _(39),
  	_(40), _(41), _(42), _(43), _(44), _(45), _(46), _(47), _(48), _(49),
  	_(50), _(51), _(52), _(53), _(54), _(55), _(56), _(57), _(58), _(59),
  	_(60), _(61), _(62), _(63), _(64), _(65), _(66), _(67), _(68), _(69),
  	_(70), _(71), _(72), _(73), _(74), _(75), _(76), _(77), _(78), _(79),
  	_(80), _(81), _(82), _(83), _(84), _(85), _(86), _(87), _(88), _(89),
  	_(90), _(91), _(92), _(93), _(94), _(95), _(96), _(97), _(98), _(99),
  #undef _
  };
  
  /*
   * This will print a single '0' even if r == 0, since we would
675cf53c1   Rasmus Villemoes   lib/vsprintf.c: i...
180
181
182
   * immediately jump to out_r where two 0s would be written but only
   * one of them accounted for in buf. This is needed by ip4_string
   * below. All other callers pass a non-zero value of r.
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
183
  */
cf3b429b0   Joe Perches   vsprintf.c: use n...
184
  static noinline_for_stack
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
185
  char *put_dec_trunc8(char *buf, unsigned r)
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
186
  {
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
  	unsigned q;
  
  	/* 1 <= r < 10^8 */
  	if (r < 100)
  		goto out_r;
  
  	/* 100 <= r < 10^8 */
  	q = (r * (u64)0x28f5c29) >> 32;
  	*((u16 *)buf) = decpair[r - 100*q];
  	buf += 2;
  
  	/* 1 <= q < 10^6 */
  	if (q < 100)
  		goto out_q;
  
  	/*  100 <= q < 10^6 */
  	r = (q * (u64)0x28f5c29) >> 32;
  	*((u16 *)buf) = decpair[q - 100*r];
  	buf += 2;
  
  	/* 1 <= r < 10^4 */
  	if (r < 100)
  		goto out_r;
  
  	/* 100 <= r < 10^4 */
  	q = (r * 0x147b) >> 19;
  	*((u16 *)buf) = decpair[r - 100*q];
  	buf += 2;
  out_q:
  	/* 1 <= q < 100 */
  	r = q;
  out_r:
  	/* 1 <= r < 100 */
  	*((u16 *)buf) = decpair[r];
675cf53c1   Rasmus Villemoes   lib/vsprintf.c: i...
221
  	buf += r < 10 ? 1 : 2;
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
222
223
  	return buf;
  }
133fd9f5c   Denys Vlasenko   vsprintf: further...
224

7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
225
  #if BITS_PER_LONG == 64 && BITS_PER_LONG_LONG == 64
cf3b429b0   Joe Perches   vsprintf.c: use n...
226
  static noinline_for_stack
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
227
  char *put_dec_full8(char *buf, unsigned r)
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
228
  {
133fd9f5c   Denys Vlasenko   vsprintf: further...
229
  	unsigned q;
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
230
231
232
233
  	/* 0 <= r < 10^8 */
  	q = (r * (u64)0x28f5c29) >> 32;
  	*((u16 *)buf) = decpair[r - 100*q];
  	buf += 2;
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
234

7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
235
236
237
238
  	/* 0 <= q < 10^6 */
  	r = (q * (u64)0x28f5c29) >> 32;
  	*((u16 *)buf) = decpair[q - 100*r];
  	buf += 2;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
239

7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
240
241
242
243
  	/* 0 <= r < 10^4 */
  	q = (r * 0x147b) >> 19;
  	*((u16 *)buf) = decpair[r - 100*q];
  	buf += 2;
133fd9f5c   Denys Vlasenko   vsprintf: further...
244

7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
245
246
247
248
249
  	/* 0 <= q < 100 */
  	*((u16 *)buf) = decpair[q];
  	buf += 2;
  	return buf;
  }
133fd9f5c   Denys Vlasenko   vsprintf: further...
250

7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
251
  static noinline_for_stack
133fd9f5c   Denys Vlasenko   vsprintf: further...
252
253
  char *put_dec(char *buf, unsigned long long n)
  {
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
254
255
256
257
258
259
  	if (n >= 100*1000*1000)
  		buf = put_dec_full8(buf, do_div(n, 100*1000*1000));
  	/* 1 <= n <= 1.6e11 */
  	if (n >= 100*1000*1000)
  		buf = put_dec_full8(buf, do_div(n, 100*1000*1000));
  	/* 1 <= n < 1e8 */
133fd9f5c   Denys Vlasenko   vsprintf: further...
260
  	return put_dec_trunc8(buf, n);
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
261
  }
133fd9f5c   Denys Vlasenko   vsprintf: further...
262

7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
263
  #elif BITS_PER_LONG == 32 && BITS_PER_LONG_LONG == 64
133fd9f5c   Denys Vlasenko   vsprintf: further...
264

7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
265
266
  static void
  put_dec_full4(char *buf, unsigned r)
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
267
  {
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
268
269
270
271
272
273
274
275
  	unsigned q;
  
  	/* 0 <= r < 10^4 */
  	q = (r * 0x147b) >> 19;
  	*((u16 *)buf) = decpair[r - 100*q];
  	buf += 2;
  	/* 0 <= q < 100 */
  	*((u16 *)buf) = decpair[q];
2359172a7   George Spelvin   lib: vsprintf: op...
276
277
278
279
280
281
282
  }
  
  /*
   * Call put_dec_full4 on x % 10000, return x / 10000.
   * The approximation x/10000 == (x * 0x346DC5D7) >> 43
   * holds for all x < 1,128,869,999.  The largest value this
   * helper will ever be asked to convert is 1,125,520,955.
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
283
   * (second call in the put_dec code, assuming n is all-ones).
2359172a7   George Spelvin   lib: vsprintf: op...
284
   */
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
285
  static noinline_for_stack
2359172a7   George Spelvin   lib: vsprintf: op...
286
287
288
289
290
291
  unsigned put_dec_helper4(char *buf, unsigned x)
  {
          uint32_t q = (x * (uint64_t)0x346DC5D7) >> 43;
  
          put_dec_full4(buf, x - q * 10000);
          return q;
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
292
  }
133fd9f5c   Denys Vlasenko   vsprintf: further...
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
  /* Based on code by Douglas W. Jones found at
   * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour>
   * (with permission from the author).
   * Performs no 64-bit division and hence should be fast on 32-bit machines.
   */
  static
  char *put_dec(char *buf, unsigned long long n)
  {
  	uint32_t d3, d2, d1, q, h;
  
  	if (n < 100*1000*1000)
  		return put_dec_trunc8(buf, n);
  
  	d1  = ((uint32_t)n >> 16); /* implicit "& 0xffff" */
  	h   = (n >> 32);
  	d2  = (h      ) & 0xffff;
  	d3  = (h >> 16); /* implicit "& 0xffff" */
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
310
311
  	/* n = 2^48 d3 + 2^32 d2 + 2^16 d1 + d0
  	     = 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */
133fd9f5c   Denys Vlasenko   vsprintf: further...
312
  	q   = 656 * d3 + 7296 * d2 + 5536 * d1 + ((uint32_t)n & 0xffff);
2359172a7   George Spelvin   lib: vsprintf: op...
313
314
315
316
317
318
319
  	q = put_dec_helper4(buf, q);
  
  	q += 7671 * d3 + 9496 * d2 + 6 * d1;
  	q = put_dec_helper4(buf+4, q);
  
  	q += 4749 * d3 + 42 * d2;
  	q = put_dec_helper4(buf+8, q);
133fd9f5c   Denys Vlasenko   vsprintf: further...
320

2359172a7   George Spelvin   lib: vsprintf: op...
321
322
323
324
325
  	q += 281 * d3;
  	buf += 12;
  	if (q)
  		buf = put_dec_trunc8(buf, q);
  	else while (buf[-1] == '0')
133fd9f5c   Denys Vlasenko   vsprintf: further...
326
327
328
329
330
331
  		--buf;
  
  	return buf;
  }
  
  #endif
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
332
333
334
335
336
337
  /*
   * Convert passed number to decimal string.
   * Returns the length of string.  On buffer overflow, returns 0.
   *
   * If speed is not important, use snprintf(). It's easy to read the code.
   */
d1be35cb6   Andrei Vagin   proc: add seq_put...
338
  int num_to_str(char *buf, int size, unsigned long long num, unsigned int width)
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
339
  {
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
340
341
  	/* put_dec requires 2-byte alignment of the buffer. */
  	char tmp[sizeof(num) * 3] __aligned(2);
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
342
  	int idx, len;
133fd9f5c   Denys Vlasenko   vsprintf: further...
343
344
345
346
347
348
349
  	/* put_dec() may work incorrectly for num = 0 (generate "", not "0") */
  	if (num <= 9) {
  		tmp[0] = '0' + num;
  		len = 1;
  	} else {
  		len = put_dec(tmp, num) - tmp;
  	}
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
350

d1be35cb6   Andrei Vagin   proc: add seq_put...
351
  	if (len > size || width > size)
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
352
  		return 0;
d1be35cb6   Andrei Vagin   proc: add seq_put...
353
354
355
356
357
358
359
360
  
  	if (width > len) {
  		width = width - len;
  		for (idx = 0; idx < width; idx++)
  			buf[idx] = ' ';
  	} else {
  		width = 0;
  	}
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
361
  	for (idx = 0; idx < len; ++idx)
d1be35cb6   Andrei Vagin   proc: add seq_put...
362
363
364
  		buf[idx + width] = tmp[len - idx - 1];
  
  	return len + width;
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
365
  }
51be17dff   Rasmus Villemoes   lib/vsprintf.c: e...
366
  #define SIGN	1		/* unsigned/signed, must be 1 */
d1c1b1213   Rasmus Villemoes   lib/vsprintf.c: a...
367
  #define LEFT	2		/* left justified */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
369
  #define PLUS	4		/* show plus */
  #define SPACE	8		/* space if plus */
d1c1b1213   Rasmus Villemoes   lib/vsprintf.c: a...
370
  #define ZEROPAD	16		/* pad with zero, must be 16 == '0' - ' ' */
b89dc5d6b   Bjorn Helgaas   vsprintf: clarify...
371
372
  #define SMALL	32		/* use lowercase in hex (must be 32 == 0x20) */
  #define SPECIAL	64		/* prefix hex with "0x", octal with "0" */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373

b886690d1   Andy Shevchenko   lib/vsprintf: Rep...
374
375
  static_assert(ZEROPAD == ('0' - ' '));
  static_assert(SMALL == ' ');
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
376
377
  enum format_type {
  	FORMAT_TYPE_NONE, /* Just a string part */
ed681a91a   Vegard Nossum   vsprintf: unify t...
378
  	FORMAT_TYPE_WIDTH,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
379
380
381
382
383
384
385
386
387
  	FORMAT_TYPE_PRECISION,
  	FORMAT_TYPE_CHAR,
  	FORMAT_TYPE_STR,
  	FORMAT_TYPE_PTR,
  	FORMAT_TYPE_PERCENT_CHAR,
  	FORMAT_TYPE_INVALID,
  	FORMAT_TYPE_LONG_LONG,
  	FORMAT_TYPE_ULONG,
  	FORMAT_TYPE_LONG,
a4e94ef0d   Zhaolei   printk: add suppo...
388
389
  	FORMAT_TYPE_UBYTE,
  	FORMAT_TYPE_BYTE,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
390
391
392
393
  	FORMAT_TYPE_USHORT,
  	FORMAT_TYPE_SHORT,
  	FORMAT_TYPE_UINT,
  	FORMAT_TYPE_INT,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
394
395
396
397
398
  	FORMAT_TYPE_SIZE_T,
  	FORMAT_TYPE_PTRDIFF
  };
  
  struct printf_spec {
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
399
400
401
402
403
404
  	unsigned int	type:8;		/* format_type enum */
  	signed int	field_width:24;	/* width of output field */
  	unsigned int	flags:8;	/* flags to number() */
  	unsigned int	base:8;		/* number base, 8, 10 or 16 only */
  	signed int	precision:16;	/* # of digits/chars */
  } __packed;
ef27ac18b   Rasmus Villemoes   lib/vsprintf.c: m...
405
  static_assert(sizeof(struct printf_spec) == 8);
4d72ba014   Rasmus Villemoes   lib/vsprintf.c: w...
406
407
  #define FIELD_WIDTH_MAX ((1 << 23) - 1)
  #define PRECISION_MAX ((1 << 15) - 1)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
408

cf3b429b0   Joe Perches   vsprintf.c: use n...
409
410
411
  static noinline_for_stack
  char *number(char *buf, char *end, unsigned long long num,
  	     struct printf_spec spec)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
  {
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
413
414
  	/* put_dec requires 2-byte alignment of the buffer. */
  	char tmp[3 * sizeof(num)] __aligned(2);
9b706aee7   Denys Vlasenko   x86: trivial prin...
415
416
  	char sign;
  	char locase;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
417
  	int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
  	int i;
7c2034223   Pierre Carrier   lib/vsprintf.c: "...
419
  	bool is_zero = num == 0LL;
1c7a8e622   Rasmus Villemoes   lib/vsprintf.c: h...
420
421
  	int field_width = spec.field_width;
  	int precision = spec.precision;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422

9b706aee7   Denys Vlasenko   x86: trivial prin...
423
424
  	/* locase = 0 or 0x20. ORing digits or letters with 'locase'
  	 * produces same digits or (maybe lowercased) letters */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
425
426
427
  	locase = (spec.flags & SMALL);
  	if (spec.flags & LEFT)
  		spec.flags &= ~ZEROPAD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
  	sign = 0;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
429
  	if (spec.flags & SIGN) {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
430
  		if ((signed long long)num < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
  			sign = '-';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
432
  			num = -(signed long long)num;
1c7a8e622   Rasmus Villemoes   lib/vsprintf.c: h...
433
  			field_width--;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
434
  		} else if (spec.flags & PLUS) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
  			sign = '+';
1c7a8e622   Rasmus Villemoes   lib/vsprintf.c: h...
436
  			field_width--;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
437
  		} else if (spec.flags & SPACE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
  			sign = ' ';
1c7a8e622   Rasmus Villemoes   lib/vsprintf.c: h...
439
  			field_width--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
441
  		}
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
442
  	if (need_pfx) {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
443
  		if (spec.base == 16)
1c7a8e622   Rasmus Villemoes   lib/vsprintf.c: h...
444
  			field_width -= 2;
7c2034223   Pierre Carrier   lib/vsprintf.c: "...
445
  		else if (!is_zero)
1c7a8e622   Rasmus Villemoes   lib/vsprintf.c: h...
446
  			field_width--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
447
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
448
449
  
  	/* generate full string in tmp[], in reverse order */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
  	i = 0;
133fd9f5c   Denys Vlasenko   vsprintf: further...
451
  	if (num < spec.base)
3ea8d440a   Rasmus Villemoes   lib/vsprintf.c: e...
452
  		tmp[i++] = hex_asc_upper[num] | locase;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
453
454
  	else if (spec.base != 10) { /* 8 or 16 */
  		int mask = spec.base - 1;
b39a73409   Denis Vlasenko   vsprintf.c: optim...
455
  		int shift = 3;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
456
457
458
  
  		if (spec.base == 16)
  			shift = 4;
b39a73409   Denis Vlasenko   vsprintf.c: optim...
459
  		do {
3ea8d440a   Rasmus Villemoes   lib/vsprintf.c: e...
460
  			tmp[i++] = (hex_asc_upper[((unsigned char)num) & mask] | locase);
b39a73409   Denis Vlasenko   vsprintf.c: optim...
461
462
  			num >>= shift;
  		} while (num);
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
463
464
465
  	} else { /* base 10 */
  		i = put_dec(tmp, num) - tmp;
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
466
467
  
  	/* printing 100 using %2d gives "100", not "00" */
1c7a8e622   Rasmus Villemoes   lib/vsprintf.c: h...
468
469
  	if (i > precision)
  		precision = i;
b39a73409   Denis Vlasenko   vsprintf.c: optim...
470
  	/* leading space padding */
1c7a8e622   Rasmus Villemoes   lib/vsprintf.c: h...
471
  	field_width -= precision;
51be17dff   Rasmus Villemoes   lib/vsprintf.c: e...
472
  	if (!(spec.flags & (ZEROPAD | LEFT))) {
1c7a8e622   Rasmus Villemoes   lib/vsprintf.c: h...
473
  		while (--field_width >= 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
474
  			if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
476
477
478
  				*buf = ' ';
  			++buf;
  		}
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
479
  	/* sign */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
  	if (sign) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
481
  		if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
484
  			*buf = sign;
  		++buf;
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
485
486
  	/* "0x" / "0" prefix */
  	if (need_pfx) {
7c2034223   Pierre Carrier   lib/vsprintf.c: "...
487
488
489
490
491
  		if (spec.base == 16 || !is_zero) {
  			if (buf < end)
  				*buf = '0';
  			++buf;
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
492
  		if (spec.base == 16) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
493
  			if (buf < end)
9b706aee7   Denys Vlasenko   x86: trivial prin...
494
  				*buf = ('X' | locase);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
496
497
  			++buf;
  		}
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
498
  	/* zero or space padding */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
499
  	if (!(spec.flags & LEFT)) {
d1c1b1213   Rasmus Villemoes   lib/vsprintf.c: a...
500
  		char c = ' ' + (spec.flags & ZEROPAD);
b886690d1   Andy Shevchenko   lib/vsprintf: Rep...
501

1c7a8e622   Rasmus Villemoes   lib/vsprintf.c: h...
502
  		while (--field_width >= 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
503
  			if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
505
506
507
  				*buf = c;
  			++buf;
  		}
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
508
  	/* hmm even more zero padding? */
1c7a8e622   Rasmus Villemoes   lib/vsprintf.c: h...
509
  	while (i <= --precision) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
510
  		if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
512
513
  			*buf = '0';
  		++buf;
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
514
515
  	/* actual digits of result */
  	while (--i >= 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
516
  		if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
518
519
  			*buf = tmp[i];
  		++buf;
  	}
b39a73409   Denis Vlasenko   vsprintf.c: optim...
520
  	/* trailing space padding */
1c7a8e622   Rasmus Villemoes   lib/vsprintf.c: h...
521
  	while (--field_width >= 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
522
  		if (buf < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
525
  			*buf = ' ';
  		++buf;
  	}
7b9186f5e   André Goddard Rosa   vsprintf: give it...
526

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
528
  	return buf;
  }
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
529
530
531
532
533
534
535
536
537
538
539
540
541
  static noinline_for_stack
  char *special_hex_number(char *buf, char *end, unsigned long long num, int size)
  {
  	struct printf_spec spec;
  
  	spec.type = FORMAT_TYPE_PTR;
  	spec.field_width = 2 + 2 * size;	/* 0x + hex */
  	spec.flags = SPECIAL | SMALL | ZEROPAD;
  	spec.base = 16;
  	spec.precision = -1;
  
  	return number(buf, end, num, spec);
  }
cfccde04e   Rasmus Villemoes   lib/vsprintf.c: p...
542
  static void move_right(char *buf, char *end, unsigned len, unsigned spaces)
4b6ccca70   Al Viro   add formats for d...
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
  {
  	size_t size;
  	if (buf >= end)	/* nowhere to put anything */
  		return;
  	size = end - buf;
  	if (size <= spaces) {
  		memset(buf, ' ', size);
  		return;
  	}
  	if (len) {
  		if (len > size - spaces)
  			len = size - spaces;
  		memmove(buf + spaces, buf, len);
  	}
  	memset(buf, ' ', spaces);
  }
cfccde04e   Rasmus Villemoes   lib/vsprintf.c: p...
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
  /*
   * Handle field width padding for a string.
   * @buf: current buffer position
   * @n: length of string
   * @end: end of output buffer
   * @spec: for field width and flags
   * Returns: new buffer position after padding.
   */
  static noinline_for_stack
  char *widen_string(char *buf, int n, char *end, struct printf_spec spec)
  {
  	unsigned spaces;
  
  	if (likely(n >= spec.field_width))
  		return buf;
  	/* we want to pad the sucker */
  	spaces = spec.field_width - n;
  	if (!(spec.flags & LEFT)) {
  		move_right(buf - n, end, n, spaces);
  		return buf + spaces;
  	}
  	while (spaces--) {
  		if (buf < end)
  			*buf = ' ';
  		++buf;
  	}
  	return buf;
  }
d529ac419   Petr Mladek   vsprintf: Do not ...
587
588
589
  /* Handle string from a well known address. */
  static char *string_nocheck(char *buf, char *end, const char *s,
  			    struct printf_spec spec)
95508cfa1   Rasmus Villemoes   lib/vsprintf.c: m...
590
  {
34fc8b907   Rasmus Villemoes   lib/vsprintf.c: e...
591
  	int len = 0;
b314dd49a   Youngmin Nam   vsprintf: fix dat...
592
  	int lim = spec.precision;
95508cfa1   Rasmus Villemoes   lib/vsprintf.c: m...
593

34fc8b907   Rasmus Villemoes   lib/vsprintf.c: e...
594
595
596
597
  	while (lim--) {
  		char c = *s++;
  		if (!c)
  			break;
95508cfa1   Rasmus Villemoes   lib/vsprintf.c: m...
598
  		if (buf < end)
34fc8b907   Rasmus Villemoes   lib/vsprintf.c: e...
599
  			*buf = c;
95508cfa1   Rasmus Villemoes   lib/vsprintf.c: m...
600
  		++buf;
34fc8b907   Rasmus Villemoes   lib/vsprintf.c: e...
601
  		++len;
95508cfa1   Rasmus Villemoes   lib/vsprintf.c: m...
602
  	}
34fc8b907   Rasmus Villemoes   lib/vsprintf.c: e...
603
  	return widen_string(buf, len, end, spec);
95508cfa1   Rasmus Villemoes   lib/vsprintf.c: m...
604
  }
57f5677e5   Rasmus Villemoes   printf: add suppo...
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
  static char *err_ptr(char *buf, char *end, void *ptr,
  		     struct printf_spec spec)
  {
  	int err = PTR_ERR(ptr);
  	const char *sym = errname(err);
  
  	if (sym)
  		return string_nocheck(buf, end, sym, spec);
  
  	/*
  	 * Somebody passed ERR_PTR(-1234) or some other non-existing
  	 * Efoo - or perhaps CONFIG_SYMBOLIC_ERRNAME=n. Fall back to
  	 * printing it as its decimal representation.
  	 */
  	spec.flags |= SIGN;
  	spec.base = 10;
  	return number(buf, end, err, spec);
  }
c8c3b5843   Petr Mladek   vsprintf: Limit t...
623
624
625
626
627
628
629
630
631
632
633
634
635
636
  /* Be careful: error messages must fit into the given buffer. */
  static char *error_string(char *buf, char *end, const char *s,
  			  struct printf_spec spec)
  {
  	/*
  	 * Hard limit to avoid a completely insane messages. It actually
  	 * works pretty well because most error messages are in
  	 * the many pointer format modifiers.
  	 */
  	if (spec.precision == -1)
  		spec.precision = 2 * sizeof(void *);
  
  	return string_nocheck(buf, end, s, spec);
  }
3e5903eb9   Petr Mladek   vsprintf: Prevent...
637
  /*
2ac5a3bf7   Petr Mladek   vsprintf: Do not ...
638
639
640
   * Do not call any complex external code here. Nested printk()/vsprintf()
   * might cause infinite loops. Failures might break printk() and would
   * be hard to debug.
3e5903eb9   Petr Mladek   vsprintf: Prevent...
641
642
643
   */
  static const char *check_pointer_msg(const void *ptr)
  {
3e5903eb9   Petr Mladek   vsprintf: Prevent...
644
645
  	if (!ptr)
  		return "(null)";
2ac5a3bf7   Petr Mladek   vsprintf: Do not ...
646
  	if ((unsigned long)ptr < PAGE_SIZE || IS_ERR_VALUE(ptr))
3e5903eb9   Petr Mladek   vsprintf: Prevent...
647
648
649
650
651
652
653
654
655
656
657
658
  		return "(efault)";
  
  	return NULL;
  }
  
  static int check_pointer(char **buf, char *end, const void *ptr,
  			 struct printf_spec spec)
  {
  	const char *err_msg;
  
  	err_msg = check_pointer_msg(ptr);
  	if (err_msg) {
c8c3b5843   Petr Mladek   vsprintf: Limit t...
659
  		*buf = error_string(*buf, end, err_msg, spec);
3e5903eb9   Petr Mladek   vsprintf: Prevent...
660
661
662
663
664
  		return -EFAULT;
  	}
  
  	return 0;
  }
95508cfa1   Rasmus Villemoes   lib/vsprintf.c: m...
665
  static noinline_for_stack
d529ac419   Petr Mladek   vsprintf: Do not ...
666
667
668
  char *string(char *buf, char *end, const char *s,
  	     struct printf_spec spec)
  {
3e5903eb9   Petr Mladek   vsprintf: Prevent...
669
670
  	if (check_pointer(&buf, end, s, spec))
  		return buf;
d529ac419   Petr Mladek   vsprintf: Do not ...
671
672
673
  
  	return string_nocheck(buf, end, s, spec);
  }
ce9d3eceb   YueHaibing   lib/vsprintf: Mak...
674
675
676
  static char *pointer_string(char *buf, char *end,
  			    const void *ptr,
  			    struct printf_spec spec)
9073dac14   Geert Uytterhoeven   lib/vsprintf: Pre...
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
  {
  	spec.base = 16;
  	spec.flags |= SMALL;
  	if (spec.field_width == -1) {
  		spec.field_width = 2 * sizeof(ptr);
  		spec.flags |= ZEROPAD;
  	}
  
  	return number(buf, end, (unsigned long int)ptr, spec);
  }
  
  /* Make pointers available for printing early in the boot sequence. */
  static int debug_boot_weak_hash __ro_after_init;
  
  static int __init debug_boot_weak_hash_enable(char *str)
  {
  	debug_boot_weak_hash = 1;
  	pr_info("debug_boot_weak_hash enabled
  ");
  	return 0;
  }
  early_param("debug_boot_weak_hash", debug_boot_weak_hash_enable);
  
  static DEFINE_STATIC_KEY_TRUE(not_filled_random_ptr_key);
  static siphash_key_t ptr_key __read_mostly;
  
  static void enable_ptr_key_workfn(struct work_struct *work)
  {
  	get_random_bytes(&ptr_key, sizeof(ptr_key));
  	/* Needs to run from preemptible context */
  	static_branch_disable(&not_filled_random_ptr_key);
  }
  
  static DECLARE_WORK(enable_ptr_key_work, enable_ptr_key_workfn);
  
  static void fill_random_ptr_key(struct random_ready_callback *unused)
  {
  	/* This may be in an interrupt handler. */
  	queue_work(system_unbound_wq, &enable_ptr_key_work);
  }
  
  static struct random_ready_callback random_ready = {
  	.func = fill_random_ptr_key
  };
  
  static int __init initialize_ptr_random(void)
  {
  	int key_size = sizeof(ptr_key);
  	int ret;
  
  	/* Use hw RNG if available. */
  	if (get_random_bytes_arch(&ptr_key, key_size) == key_size) {
  		static_branch_disable(&not_filled_random_ptr_key);
  		return 0;
  	}
  
  	ret = add_random_ready_callback(&random_ready);
  	if (!ret) {
  		return 0;
  	} else if (ret == -EALREADY) {
  		/* This is in preemptible context */
  		enable_ptr_key_workfn(&enable_ptr_key_work);
  		return 0;
  	}
  
  	return ret;
  }
  early_initcall(initialize_ptr_random);
  
  /* Maps a pointer to a 32 bit unique identifier. */
e4dcad204   Joel Fernandes (Google)   rss_stat: add sup...
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
  static inline int __ptr_to_hashval(const void *ptr, unsigned long *hashval_out)
  {
  	unsigned long hashval;
  
  	if (static_branch_unlikely(&not_filled_random_ptr_key))
  		return -EAGAIN;
  
  #ifdef CONFIG_64BIT
  	hashval = (unsigned long)siphash_1u64((u64)ptr, &ptr_key);
  	/*
  	 * Mask off the first 32 bits, this makes explicit that we have
  	 * modified the address (and 32 bits is plenty for a unique ID).
  	 */
  	hashval = hashval & 0xffffffff;
  #else
  	hashval = (unsigned long)siphash_1u32((u32)ptr, &ptr_key);
  #endif
  	*hashval_out = hashval;
  	return 0;
  }
  
  int ptr_to_hashval(const void *ptr, unsigned long *hashval_out)
  {
  	return __ptr_to_hashval(ptr, hashval_out);
  }
9073dac14   Geert Uytterhoeven   lib/vsprintf: Pre...
772
773
774
775
776
  static char *ptr_to_id(char *buf, char *end, const void *ptr,
  		       struct printf_spec spec)
  {
  	const char *str = sizeof(ptr) == 8 ? "(____ptrval____)" : "(ptrval)";
  	unsigned long hashval;
e4dcad204   Joel Fernandes (Google)   rss_stat: add sup...
777
  	int ret;
9073dac14   Geert Uytterhoeven   lib/vsprintf: Pre...
778

7bd57fbc4   Ilya Dryomov   vsprintf: don't o...
779
780
781
782
783
784
  	/*
  	 * Print the real pointer value for NULL and error pointers,
  	 * as they are not actual addresses.
  	 */
  	if (IS_ERR_OR_NULL(ptr))
  		return pointer_string(buf, end, ptr, spec);
9073dac14   Geert Uytterhoeven   lib/vsprintf: Pre...
785
786
787
788
789
  	/* When debugging early boot use non-cryptographically secure hash. */
  	if (unlikely(debug_boot_weak_hash)) {
  		hashval = hash_long((unsigned long)ptr, 32);
  		return pointer_string(buf, end, (const void *)hashval, spec);
  	}
e4dcad204   Joel Fernandes (Google)   rss_stat: add sup...
790
791
  	ret = __ptr_to_hashval(ptr, &hashval);
  	if (ret) {
9073dac14   Geert Uytterhoeven   lib/vsprintf: Pre...
792
793
  		spec.field_width = 2 * sizeof(ptr);
  		/* string length must be less than default_width */
c8c3b5843   Petr Mladek   vsprintf: Limit t...
794
  		return error_string(buf, end, str, spec);
9073dac14   Geert Uytterhoeven   lib/vsprintf: Pre...
795
  	}
9073dac14   Geert Uytterhoeven   lib/vsprintf: Pre...
796
797
  	return pointer_string(buf, end, (const void *)hashval, spec);
  }
6eea242f9   Petr Mladek   vsprintf: Shuffle...
798
799
800
801
802
803
804
805
  int kptr_restrict __read_mostly;
  
  static noinline_for_stack
  char *restricted_pointer(char *buf, char *end, const void *ptr,
  			 struct printf_spec spec)
  {
  	switch (kptr_restrict) {
  	case 0:
1ac2f9789   Petr Mladek   vsprintf: Consist...
806
807
  		/* Handle as %p, hash and do _not_ leak addresses. */
  		return ptr_to_id(buf, end, ptr, spec);
6eea242f9   Petr Mladek   vsprintf: Shuffle...
808
809
810
811
812
813
814
815
816
817
  	case 1: {
  		const struct cred *cred;
  
  		/*
  		 * kptr_restrict==1 cannot be used in IRQ context
  		 * because its test for CAP_SYSLOG would be meaningless.
  		 */
  		if (in_irq() || in_serving_softirq() || in_nmi()) {
  			if (spec.field_width == -1)
  				spec.field_width = 2 * sizeof(ptr);
c8c3b5843   Petr Mladek   vsprintf: Limit t...
818
  			return error_string(buf, end, "pK-error", spec);
6eea242f9   Petr Mladek   vsprintf: Shuffle...
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
  		}
  
  		/*
  		 * Only print the real pointer value if the current
  		 * process has CAP_SYSLOG and is running with the
  		 * same credentials it started with. This is because
  		 * access to files is checked at open() time, but %pK
  		 * checks permission at read() time. We don't want to
  		 * leak pointer values if a binary opens a file using
  		 * %pK and then elevates privileges before reading it.
  		 */
  		cred = current_cred();
  		if (!has_capability_noaudit(current, CAP_SYSLOG) ||
  		    !uid_eq(cred->euid, cred->uid) ||
  		    !gid_eq(cred->egid, cred->gid))
  			ptr = NULL;
  		break;
  	}
  	case 2:
  	default:
  		/* Always print 0's for %pK */
  		ptr = NULL;
  		break;
  	}
  
  	return pointer_string(buf, end, ptr, spec);
  }
9073dac14   Geert Uytterhoeven   lib/vsprintf: Pre...
846
  static noinline_for_stack
4b6ccca70   Al Viro   add formats for d...
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
  char *dentry_name(char *buf, char *end, const struct dentry *d, struct printf_spec spec,
  		  const char *fmt)
  {
  	const char *array[4], *s;
  	const struct dentry *p;
  	int depth;
  	int i, n;
  
  	switch (fmt[1]) {
  		case '2': case '3': case '4':
  			depth = fmt[1] - '0';
  			break;
  		default:
  			depth = 1;
  	}
  
  	rcu_read_lock();
  	for (i = 0; i < depth; i++, d = p) {
3e5903eb9   Petr Mladek   vsprintf: Prevent...
865
866
867
868
  		if (check_pointer(&buf, end, d, spec)) {
  			rcu_read_unlock();
  			return buf;
  		}
6aa7de059   Mark Rutland   locking/atomics: ...
869
870
  		p = READ_ONCE(d->d_parent);
  		array[i] = READ_ONCE(d->d_name.name);
4b6ccca70   Al Viro   add formats for d...
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
  		if (p == d) {
  			if (i)
  				array[i] = "";
  			i++;
  			break;
  		}
  	}
  	s = array[--i];
  	for (n = 0; n != spec.precision; n++, buf++) {
  		char c = *s++;
  		if (!c) {
  			if (!i)
  				break;
  			c = '/';
  			s = array[--i];
  		}
  		if (buf < end)
  			*buf = c;
  	}
  	rcu_read_unlock();
cfccde04e   Rasmus Villemoes   lib/vsprintf.c: p...
891
  	return widen_string(buf, n, end, spec);
4b6ccca70   Al Viro   add formats for d...
892
  }
36594b317   Jia He   vsprintf: Prevent...
893
894
895
896
897
898
899
900
901
  static noinline_for_stack
  char *file_dentry_name(char *buf, char *end, const struct file *f,
  			struct printf_spec spec, const char *fmt)
  {
  	if (check_pointer(&buf, end, f, spec))
  		return buf;
  
  	return dentry_name(buf, end, f->f_path.dentry, spec, fmt);
  }
1031bc589   Dmitry Monakhov   lib/vsprintf: add...
902
903
904
905
906
  #ifdef CONFIG_BLOCK
  static noinline_for_stack
  char *bdev_name(char *buf, char *end, struct block_device *bdev,
  		struct printf_spec spec, const char *fmt)
  {
3e5903eb9   Petr Mladek   vsprintf: Prevent...
907
908
909
910
911
912
  	struct gendisk *hd;
  
  	if (check_pointer(&buf, end, bdev, spec))
  		return buf;
  
  	hd = bdev->bd_disk;
1031bc589   Dmitry Monakhov   lib/vsprintf: add...
913
  	buf = string(buf, end, hd->disk_name, spec);
700cd59db   Christoph Hellwig   vsprintf: use bd_...
914
  	if (bdev->bd_partno) {
1031bc589   Dmitry Monakhov   lib/vsprintf: add...
915
916
917
918
919
  		if (isdigit(hd->disk_name[strlen(hd->disk_name)-1])) {
  			if (buf < end)
  				*buf = 'p';
  			buf++;
  		}
700cd59db   Christoph Hellwig   vsprintf: use bd_...
920
  		buf = number(buf, end, bdev->bd_partno, spec);
1031bc589   Dmitry Monakhov   lib/vsprintf: add...
921
922
923
924
  	}
  	return buf;
  }
  #endif
cf3b429b0   Joe Perches   vsprintf.c: use n...
925
926
  static noinline_for_stack
  char *symbol_string(char *buf, char *end, void *ptr,
b0d33c2bd   Joe Perches   vsprintf: Add ext...
927
  		    struct printf_spec spec, const char *fmt)
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
928
  {
b0d33c2bd   Joe Perches   vsprintf: Add ext...
929
  	unsigned long value;
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
930
931
  #ifdef CONFIG_KALLSYMS
  	char sym[KSYM_SYMBOL_LEN];
b0d33c2bd   Joe Perches   vsprintf: Add ext...
932
933
934
935
936
937
938
939
  #endif
  
  	if (fmt[1] == 'R')
  		ptr = __builtin_extract_return_addr(ptr);
  	value = (unsigned long)ptr;
  
  #ifdef CONFIG_KALLSYMS
  	if (*fmt == 'B')
0f77a8d37   Namhyung Kim   vsprintf: Introdu...
940
  		sprint_backtrace(sym, value);
9af770649   Sakari Ailus   lib/vsprintf: Rem...
941
  	else if (*fmt != 's')
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
942
943
  		sprint_symbol(sym, value);
  	else
4796dd200   Stephen Boyd   vsprintf: fix %ps...
944
  		sprint_symbol_no_offset(sym, value);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
945

d529ac419   Petr Mladek   vsprintf: Do not ...
946
  	return string_nocheck(buf, end, sym, spec);
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
947
  #else
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
948
  	return special_hex_number(buf, end, value, sizeof(void *));
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
949
950
  #endif
  }
abd4fe627   Andy Shevchenko   lib/vsprintf: Mak...
951
952
953
954
  static const struct printf_spec default_str_spec = {
  	.field_width = -1,
  	.precision = -1,
  };
544339730   Andy Shevchenko   lib/vsprintf: Mak...
955
956
957
958
959
  static const struct printf_spec default_flag_spec = {
  	.base = 16,
  	.precision = -1,
  	.flags = SPECIAL | SMALL,
  };
ce0b4910b   Andy Shevchenko   lib/vsprintf: Mak...
960
961
962
963
  static const struct printf_spec default_dec_spec = {
  	.base = 10,
  	.precision = -1,
  };
4d42c4472   Andy Shevchenko   lib/vsprintf: Pri...
964
965
966
967
968
969
970
971
972
973
974
975
976
  static const struct printf_spec default_dec02_spec = {
  	.base = 10,
  	.field_width = 2,
  	.precision = -1,
  	.flags = ZEROPAD,
  };
  
  static const struct printf_spec default_dec04_spec = {
  	.base = 10,
  	.field_width = 4,
  	.precision = -1,
  	.flags = ZEROPAD,
  };
cf3b429b0   Joe Perches   vsprintf.c: use n...
977
978
979
  static noinline_for_stack
  char *resource_string(char *buf, char *end, struct resource *res,
  		      struct printf_spec spec, const char *fmt)
332d2e783   Linus Torvalds   Implement %pR to ...
980
981
  {
  #ifndef IO_RSRC_PRINTK_SIZE
284053722   Bjorn Helgaas   vsprintf: fix io/...
982
  #define IO_RSRC_PRINTK_SIZE	6
332d2e783   Linus Torvalds   Implement %pR to ...
983
984
985
  #endif
  
  #ifndef MEM_RSRC_PRINTK_SIZE
284053722   Bjorn Helgaas   vsprintf: fix io/...
986
  #define MEM_RSRC_PRINTK_SIZE	10
332d2e783   Linus Torvalds   Implement %pR to ...
987
  #endif
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
988
  	static const struct printf_spec io_spec = {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
989
  		.base = 16,
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
990
  		.field_width = IO_RSRC_PRINTK_SIZE,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
991
992
993
  		.precision = -1,
  		.flags = SPECIAL | SMALL | ZEROPAD,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
994
995
996
997
998
999
  	static const struct printf_spec mem_spec = {
  		.base = 16,
  		.field_width = MEM_RSRC_PRINTK_SIZE,
  		.precision = -1,
  		.flags = SPECIAL | SMALL | ZEROPAD,
  	};
0f4050c7d   Bjorn Helgaas   resource: add bus...
1000
1001
1002
1003
1004
1005
  	static const struct printf_spec bus_spec = {
  		.base = 16,
  		.field_width = 2,
  		.precision = -1,
  		.flags = SMALL | ZEROPAD,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
1006
  	static const struct printf_spec str_spec = {
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
1007
1008
1009
1010
  		.field_width = -1,
  		.precision = 10,
  		.flags = LEFT,
  	};
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
1011
1012
1013
1014
1015
  
  	/* 32-bit res (sizeof==4): 10 chars in dec, 10 in hex ("0x" + 8)
  	 * 64-bit res (sizeof==8): 20 chars in dec, 18 in hex ("0x" + 16) */
  #define RSRC_BUF_SIZE		((2 * sizeof(resource_size_t)) + 4)
  #define FLAG_BUF_SIZE		(2 * sizeof(res->flags))
9d7cca042   Bjorn Helgaas   resource: add win...
1016
  #define DECODED_BUF_SIZE	sizeof("[mem - 64bit pref window disabled]")
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
1017
1018
1019
  #define RAW_BUF_SIZE		sizeof("[mem - flags 0x]")
  	char sym[max(2*RSRC_BUF_SIZE + DECODED_BUF_SIZE,
  		     2*RSRC_BUF_SIZE + FLAG_BUF_SIZE + RAW_BUF_SIZE)];
332d2e783   Linus Torvalds   Implement %pR to ...
1020
  	char *p = sym, *pend = sym + sizeof(sym);
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
1021
  	int decode = (fmt[0] == 'R') ? 1 : 0;
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
1022
  	const struct printf_spec *specp;
332d2e783   Linus Torvalds   Implement %pR to ...
1023

3e5903eb9   Petr Mladek   vsprintf: Prevent...
1024
1025
  	if (check_pointer(&buf, end, res, spec))
  		return buf;
332d2e783   Linus Torvalds   Implement %pR to ...
1026
  	*p++ = '[';
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
1027
  	if (res->flags & IORESOURCE_IO) {
d529ac419   Petr Mladek   vsprintf: Do not ...
1028
  		p = string_nocheck(p, pend, "io  ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
1029
1030
  		specp = &io_spec;
  	} else if (res->flags & IORESOURCE_MEM) {
d529ac419   Petr Mladek   vsprintf: Do not ...
1031
  		p = string_nocheck(p, pend, "mem ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
1032
1033
  		specp = &mem_spec;
  	} else if (res->flags & IORESOURCE_IRQ) {
d529ac419   Petr Mladek   vsprintf: Do not ...
1034
  		p = string_nocheck(p, pend, "irq ", str_spec);
ce0b4910b   Andy Shevchenko   lib/vsprintf: Mak...
1035
  		specp = &default_dec_spec;
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
1036
  	} else if (res->flags & IORESOURCE_DMA) {
d529ac419   Petr Mladek   vsprintf: Do not ...
1037
  		p = string_nocheck(p, pend, "dma ", str_spec);
ce0b4910b   Andy Shevchenko   lib/vsprintf: Mak...
1038
  		specp = &default_dec_spec;
0f4050c7d   Bjorn Helgaas   resource: add bus...
1039
  	} else if (res->flags & IORESOURCE_BUS) {
d529ac419   Petr Mladek   vsprintf: Do not ...
1040
  		p = string_nocheck(p, pend, "bus ", str_spec);
0f4050c7d   Bjorn Helgaas   resource: add bus...
1041
  		specp = &bus_spec;
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
1042
  	} else {
d529ac419   Petr Mladek   vsprintf: Do not ...
1043
  		p = string_nocheck(p, pend, "??? ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
1044
  		specp = &mem_spec;
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
1045
  		decode = 0;
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
1046
  	}
d19cb803a   Bjorn Helgaas   vsprintf: Add sup...
1047
  	if (decode && res->flags & IORESOURCE_UNSET) {
d529ac419   Petr Mladek   vsprintf: Do not ...
1048
  		p = string_nocheck(p, pend, "size ", str_spec);
d19cb803a   Bjorn Helgaas   vsprintf: Add sup...
1049
1050
1051
1052
1053
1054
1055
  		p = number(p, pend, resource_size(res), *specp);
  	} else {
  		p = number(p, pend, res->start, *specp);
  		if (res->start != res->end) {
  			*p++ = '-';
  			p = number(p, pend, res->end, *specp);
  		}
c91d3376e   Bjorn Helgaas   vsprintf: add %pR...
1056
  	}
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
1057
  	if (decode) {
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
1058
  		if (res->flags & IORESOURCE_MEM_64)
d529ac419   Petr Mladek   vsprintf: Do not ...
1059
  			p = string_nocheck(p, pend, " 64bit", str_spec);
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
1060
  		if (res->flags & IORESOURCE_PREFETCH)
d529ac419   Petr Mladek   vsprintf: Do not ...
1061
  			p = string_nocheck(p, pend, " pref", str_spec);
9d7cca042   Bjorn Helgaas   resource: add win...
1062
  		if (res->flags & IORESOURCE_WINDOW)
d529ac419   Petr Mladek   vsprintf: Do not ...
1063
  			p = string_nocheck(p, pend, " window", str_spec);
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
1064
  		if (res->flags & IORESOURCE_DISABLED)
d529ac419   Petr Mladek   vsprintf: Do not ...
1065
  			p = string_nocheck(p, pend, " disabled", str_spec);
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
1066
  	} else {
d529ac419   Petr Mladek   vsprintf: Do not ...
1067
  		p = string_nocheck(p, pend, " flags ", str_spec);
544339730   Andy Shevchenko   lib/vsprintf: Mak...
1068
  		p = number(p, pend, res->flags, default_flag_spec);
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
1069
  	}
332d2e783   Linus Torvalds   Implement %pR to ...
1070
  	*p++ = ']';
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
1071
  	*p = '\0';
332d2e783   Linus Torvalds   Implement %pR to ...
1072

d529ac419   Petr Mladek   vsprintf: Do not ...
1073
  	return string_nocheck(buf, end, sym, spec);
332d2e783   Linus Torvalds   Implement %pR to ...
1074
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
1075
  static noinline_for_stack
31550a16a   Andy Shevchenko   vsprintf: add sup...
1076
1077
1078
  char *hex_string(char *buf, char *end, u8 *addr, struct printf_spec spec,
  		 const char *fmt)
  {
360603a1b   Steven Rostedt   sprintf: hex_stri...
1079
  	int i, len = 1;		/* if we pass '%ph[CDN]', field width remains
31550a16a   Andy Shevchenko   vsprintf: add sup...
1080
1081
1082
1083
1084
1085
  				   negative value, fallback to the default */
  	char separator;
  
  	if (spec.field_width == 0)
  		/* nothing to print */
  		return buf;
3e5903eb9   Petr Mladek   vsprintf: Prevent...
1086
1087
  	if (check_pointer(&buf, end, addr, spec))
  		return buf;
31550a16a   Andy Shevchenko   vsprintf: add sup...
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
  
  	switch (fmt[1]) {
  	case 'C':
  		separator = ':';
  		break;
  	case 'D':
  		separator = '-';
  		break;
  	case 'N':
  		separator = 0;
  		break;
  	default:
  		separator = ' ';
  		break;
  	}
  
  	if (spec.field_width > 0)
  		len = min_t(int, spec.field_width, 64);
9c98f2359   Rasmus Villemoes   lib/vsprintf.c: f...
1106
1107
1108
1109
1110
1111
1112
  	for (i = 0; i < len; ++i) {
  		if (buf < end)
  			*buf = hex_asc_hi(addr[i]);
  		++buf;
  		if (buf < end)
  			*buf = hex_asc_lo(addr[i]);
  		++buf;
31550a16a   Andy Shevchenko   vsprintf: add sup...
1113

9c98f2359   Rasmus Villemoes   lib/vsprintf.c: f...
1114
1115
1116
1117
1118
  		if (separator && i != len - 1) {
  			if (buf < end)
  				*buf = separator;
  			++buf;
  		}
31550a16a   Andy Shevchenko   vsprintf: add sup...
1119
1120
1121
1122
1123
1124
  	}
  
  	return buf;
  }
  
  static noinline_for_stack
dbc760bcc   Tejun Heo   lib/vsprintf: imp...
1125
1126
1127
1128
1129
1130
1131
  char *bitmap_string(char *buf, char *end, unsigned long *bitmap,
  		    struct printf_spec spec, const char *fmt)
  {
  	const int CHUNKSZ = 32;
  	int nr_bits = max_t(int, spec.field_width, 0);
  	int i, chunksz;
  	bool first = true;
3e5903eb9   Petr Mladek   vsprintf: Prevent...
1132
1133
  	if (check_pointer(&buf, end, bitmap, spec))
  		return buf;
dbc760bcc   Tejun Heo   lib/vsprintf: imp...
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
  	/* reused to print numbers */
  	spec = (struct printf_spec){ .flags = SMALL | ZEROPAD, .base = 16 };
  
  	chunksz = nr_bits & (CHUNKSZ - 1);
  	if (chunksz == 0)
  		chunksz = CHUNKSZ;
  
  	i = ALIGN(nr_bits, CHUNKSZ) - CHUNKSZ;
  	for (; i >= 0; i -= CHUNKSZ) {
  		u32 chunkmask, val;
  		int word, bit;
  
  		chunkmask = ((1ULL << chunksz) - 1);
  		word = i / BITS_PER_LONG;
  		bit = i % BITS_PER_LONG;
  		val = (bitmap[word] >> bit) & chunkmask;
  
  		if (!first) {
  			if (buf < end)
  				*buf = ',';
  			buf++;
  		}
  		first = false;
  
  		spec.field_width = DIV_ROUND_UP(chunksz, 4);
  		buf = number(buf, end, val, spec);
  
  		chunksz = CHUNKSZ;
  	}
  	return buf;
  }
  
  static noinline_for_stack
  char *bitmap_list_string(char *buf, char *end, unsigned long *bitmap,
  			 struct printf_spec spec, const char *fmt)
  {
  	int nr_bits = max_t(int, spec.field_width, 0);
  	/* current bit is 'cur', most recently seen range is [rbot, rtop] */
  	int cur, rbot, rtop;
  	bool first = true;
3e5903eb9   Petr Mladek   vsprintf: Prevent...
1174
1175
  	if (check_pointer(&buf, end, bitmap, spec))
  		return buf;
dbc760bcc   Tejun Heo   lib/vsprintf: imp...
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
  	rbot = cur = find_first_bit(bitmap, nr_bits);
  	while (cur < nr_bits) {
  		rtop = cur;
  		cur = find_next_bit(bitmap, nr_bits, cur + 1);
  		if (cur < nr_bits && cur <= rtop + 1)
  			continue;
  
  		if (!first) {
  			if (buf < end)
  				*buf = ',';
  			buf++;
  		}
  		first = false;
ce0b4910b   Andy Shevchenko   lib/vsprintf: Mak...
1189
  		buf = number(buf, end, rbot, default_dec_spec);
dbc760bcc   Tejun Heo   lib/vsprintf: imp...
1190
1191
1192
1193
  		if (rbot < rtop) {
  			if (buf < end)
  				*buf = '-';
  			buf++;
ce0b4910b   Andy Shevchenko   lib/vsprintf: Mak...
1194
  			buf = number(buf, end, rtop, default_dec_spec);
dbc760bcc   Tejun Heo   lib/vsprintf: imp...
1195
1196
1197
1198
1199
1200
1201
1202
  		}
  
  		rbot = cur;
  	}
  	return buf;
  }
  
  static noinline_for_stack
cf3b429b0   Joe Perches   vsprintf.c: use n...
1203
1204
  char *mac_address_string(char *buf, char *end, u8 *addr,
  			 struct printf_spec spec, const char *fmt)
dd45c9cf6   Harvey Harrison   printk: add %pM f...
1205
  {
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1206
  	char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")];
dd45c9cf6   Harvey Harrison   printk: add %pM f...
1207
1208
  	char *p = mac_addr;
  	int i;
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
1209
  	char separator;
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
1210
  	bool reversed = false;
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
1211

3e5903eb9   Petr Mladek   vsprintf: Prevent...
1212
1213
  	if (check_pointer(&buf, end, addr, spec))
  		return buf;
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
1214
1215
  	switch (fmt[1]) {
  	case 'F':
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
1216
  		separator = '-';
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
1217
1218
1219
1220
  		break;
  
  	case 'R':
  		reversed = true;
6a9dc5fd6   Gustavo A. R. Silva   lib: Revert use o...
1221
  		/* fall through */
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
1222
1223
  
  	default:
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
1224
  		separator = ':';
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
1225
  		break;
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
1226
  	}
dd45c9cf6   Harvey Harrison   printk: add %pM f...
1227
1228
  
  	for (i = 0; i < 6; i++) {
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
1229
1230
1231
1232
  		if (reversed)
  			p = hex_byte_pack(p, addr[5 - i]);
  		else
  			p = hex_byte_pack(p, addr[i]);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1233
  		if (fmt[0] == 'M' && i != 5)
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
1234
  			*p++ = separator;
dd45c9cf6   Harvey Harrison   printk: add %pM f...
1235
1236
  	}
  	*p = '\0';
d529ac419   Petr Mladek   vsprintf: Do not ...
1237
  	return string_nocheck(buf, end, mac_addr, spec);
dd45c9cf6   Harvey Harrison   printk: add %pM f...
1238
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
1239
1240
  static noinline_for_stack
  char *ip4_string(char *p, const u8 *addr, const char *fmt)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1241
1242
  {
  	int i;
0159f24ee   Joe Perches   lib/vsprintf.c: A...
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
  	bool leading_zeros = (fmt[0] == 'i');
  	int index;
  	int step;
  
  	switch (fmt[2]) {
  	case 'h':
  #ifdef __BIG_ENDIAN
  		index = 0;
  		step = 1;
  #else
  		index = 3;
  		step = -1;
  #endif
  		break;
  	case 'l':
  		index = 3;
  		step = -1;
  		break;
  	case 'n':
  	case 'b':
  	default:
  		index = 0;
  		step = 1;
  		break;
  	}
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1268
  	for (i = 0; i < 4; i++) {
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
1269
  		char temp[4] __aligned(2);	/* hold each IP quad in reverse order */
133fd9f5c   Denys Vlasenko   vsprintf: further...
1270
  		int digits = put_dec_trunc8(temp, addr[index]) - temp;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
  		if (leading_zeros) {
  			if (digits < 3)
  				*p++ = '0';
  			if (digits < 2)
  				*p++ = '0';
  		}
  		/* reverse the digits in the quad */
  		while (digits--)
  			*p++ = temp[digits];
  		if (i < 3)
  			*p++ = '.';
0159f24ee   Joe Perches   lib/vsprintf.c: A...
1282
  		index += step;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1283
  	}
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1284
  	*p = '\0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1285

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1286
1287
  	return p;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
1288
1289
  static noinline_for_stack
  char *ip6_compressed_string(char *p, const char *addr)
689afa7da   Harvey Harrison   printk: add %p6 f...
1290
  {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1291
  	int i, j, range;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1292
1293
1294
1295
  	unsigned char zerolength[8];
  	int longest = 1;
  	int colonpos = -1;
  	u16 word;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1296
  	u8 hi, lo;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1297
  	bool needcolon = false;
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
1298
1299
1300
1301
1302
1303
  	bool useIPv4;
  	struct in6_addr in6;
  
  	memcpy(&in6, addr, sizeof(struct in6_addr));
  
  	useIPv4 = ipv6_addr_v4mapped(&in6) || ipv6_addr_is_isatap(&in6);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
  
  	memset(zerolength, 0, sizeof(zerolength));
  
  	if (useIPv4)
  		range = 6;
  	else
  		range = 8;
  
  	/* find position of longest 0 run */
  	for (i = 0; i < range; i++) {
  		for (j = i; j < range; j++) {
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
1315
  			if (in6.s6_addr16[j] != 0)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
  				break;
  			zerolength[i]++;
  		}
  	}
  	for (i = 0; i < range; i++) {
  		if (zerolength[i] > longest) {
  			longest = zerolength[i];
  			colonpos = i;
  		}
  	}
29cf519ee   Joe Perches   vsprintf: Update ...
1326
1327
  	if (longest == 1)		/* don't compress a single 0 */
  		colonpos = -1;
689afa7da   Harvey Harrison   printk: add %p6 f...
1328

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
  	/* emit address */
  	for (i = 0; i < range; i++) {
  		if (i == colonpos) {
  			if (needcolon || i == 0)
  				*p++ = ':';
  			*p++ = ':';
  			needcolon = false;
  			i += longest - 1;
  			continue;
  		}
  		if (needcolon) {
  			*p++ = ':';
  			needcolon = false;
  		}
  		/* hex u16 without leading 0s */
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
1344
  		word = ntohs(in6.s6_addr16[i]);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1345
1346
1347
1348
  		hi = word >> 8;
  		lo = word & 0xff;
  		if (hi) {
  			if (hi > 0x0f)
55036ba76   Andy Shevchenko   lib: rename pack_...
1349
  				p = hex_byte_pack(p, hi);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1350
1351
  			else
  				*p++ = hex_asc_lo(hi);
55036ba76   Andy Shevchenko   lib: rename pack_...
1352
  			p = hex_byte_pack(p, lo);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1353
  		}
b5ff992b0   André Goddard Rosa   vsprintf: reduce ...
1354
  		else if (lo > 0x0f)
55036ba76   Andy Shevchenko   lib: rename pack_...
1355
  			p = hex_byte_pack(p, lo);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1356
1357
1358
1359
1360
1361
1362
1363
  		else
  			*p++ = hex_asc_lo(lo);
  		needcolon = true;
  	}
  
  	if (useIPv4) {
  		if (needcolon)
  			*p++ = ':';
0159f24ee   Joe Perches   lib/vsprintf.c: A...
1364
  		p = ip4_string(p, &in6.s6_addr[12], "I4");
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1365
  	}
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1366
  	*p = '\0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1367

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1368
1369
  	return p;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
1370
1371
  static noinline_for_stack
  char *ip6_string(char *p, const char *addr, const char *fmt)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1372
1373
  {
  	int i;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1374

689afa7da   Harvey Harrison   printk: add %p6 f...
1375
  	for (i = 0; i < 8; i++) {
55036ba76   Andy Shevchenko   lib: rename pack_...
1376
1377
  		p = hex_byte_pack(p, *addr++);
  		p = hex_byte_pack(p, *addr++);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1378
  		if (fmt[0] == 'I' && i != 7)
689afa7da   Harvey Harrison   printk: add %p6 f...
1379
1380
1381
  			*p++ = ':';
  	}
  	*p = '\0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1382

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1383
1384
  	return p;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
1385
1386
1387
  static noinline_for_stack
  char *ip6_addr_string(char *buf, char *end, const u8 *addr,
  		      struct printf_spec spec, const char *fmt)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1388
1389
1390
1391
  {
  	char ip6_addr[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
  
  	if (fmt[0] == 'I' && fmt[2] == 'c')
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
1392
  		ip6_compressed_string(ip6_addr, addr);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1393
  	else
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
1394
  		ip6_string(ip6_addr, addr, fmt);
689afa7da   Harvey Harrison   printk: add %p6 f...
1395

d529ac419   Petr Mladek   vsprintf: Do not ...
1396
  	return string_nocheck(buf, end, ip6_addr, spec);
689afa7da   Harvey Harrison   printk: add %p6 f...
1397
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
1398
1399
1400
  static noinline_for_stack
  char *ip4_addr_string(char *buf, char *end, const u8 *addr,
  		      struct printf_spec spec, const char *fmt)
4aa996066   Harvey Harrison   printk: add %I4, ...
1401
  {
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1402
  	char ip4_addr[sizeof("255.255.255.255")];
4aa996066   Harvey Harrison   printk: add %I4, ...
1403

0159f24ee   Joe Perches   lib/vsprintf.c: A...
1404
  	ip4_string(ip4_addr, addr, fmt);
4aa996066   Harvey Harrison   printk: add %I4, ...
1405

d529ac419   Petr Mladek   vsprintf: Do not ...
1406
  	return string_nocheck(buf, end, ip4_addr, spec);
4aa996066   Harvey Harrison   printk: add %I4, ...
1407
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
1408
  static noinline_for_stack
106796430   Daniel Borkmann   lib: vsprintf: ad...
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
  char *ip6_addr_string_sa(char *buf, char *end, const struct sockaddr_in6 *sa,
  			 struct printf_spec spec, const char *fmt)
  {
  	bool have_p = false, have_s = false, have_f = false, have_c = false;
  	char ip6_addr[sizeof("[xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255]") +
  		      sizeof(":12345") + sizeof("/123456789") +
  		      sizeof("%1234567890")];
  	char *p = ip6_addr, *pend = ip6_addr + sizeof(ip6_addr);
  	const u8 *addr = (const u8 *) &sa->sin6_addr;
  	char fmt6[2] = { fmt[0], '6' };
  	u8 off = 0;
  
  	fmt++;
  	while (isalpha(*++fmt)) {
  		switch (*fmt) {
  		case 'p':
  			have_p = true;
  			break;
  		case 'f':
  			have_f = true;
  			break;
  		case 's':
  			have_s = true;
  			break;
  		case 'c':
  			have_c = true;
  			break;
  		}
  	}
  
  	if (have_p || have_s || have_f) {
  		*p = '[';
  		off = 1;
  	}
  
  	if (fmt6[0] == 'I' && have_c)
  		p = ip6_compressed_string(ip6_addr + off, addr);
  	else
  		p = ip6_string(ip6_addr + off, addr, fmt6);
  
  	if (have_p || have_s || have_f)
  		*p++ = ']';
  
  	if (have_p) {
  		*p++ = ':';
  		p = number(p, pend, ntohs(sa->sin6_port), spec);
  	}
  	if (have_f) {
  		*p++ = '/';
  		p = number(p, pend, ntohl(sa->sin6_flowinfo &
  					  IPV6_FLOWINFO_MASK), spec);
  	}
  	if (have_s) {
  		*p++ = '%';
  		p = number(p, pend, sa->sin6_scope_id, spec);
  	}
  	*p = '\0';
d529ac419   Petr Mladek   vsprintf: Do not ...
1466
  	return string_nocheck(buf, end, ip6_addr, spec);
106796430   Daniel Borkmann   lib: vsprintf: ad...
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
  }
  
  static noinline_for_stack
  char *ip4_addr_string_sa(char *buf, char *end, const struct sockaddr_in *sa,
  			 struct printf_spec spec, const char *fmt)
  {
  	bool have_p = false;
  	char *p, ip4_addr[sizeof("255.255.255.255") + sizeof(":12345")];
  	char *pend = ip4_addr + sizeof(ip4_addr);
  	const u8 *addr = (const u8 *) &sa->sin_addr.s_addr;
  	char fmt4[3] = { fmt[0], '4', 0 };
  
  	fmt++;
  	while (isalpha(*++fmt)) {
  		switch (*fmt) {
  		case 'p':
  			have_p = true;
  			break;
  		case 'h':
  		case 'l':
  		case 'n':
  		case 'b':
  			fmt4[2] = *fmt;
  			break;
  		}
  	}
  
  	p = ip4_string(ip4_addr, addr, fmt4);
  	if (have_p) {
  		*p++ = ':';
  		p = number(p, pend, ntohs(sa->sin_port), spec);
  	}
  	*p = '\0';
d529ac419   Petr Mladek   vsprintf: Do not ...
1500
  	return string_nocheck(buf, end, ip4_addr, spec);
106796430   Daniel Borkmann   lib: vsprintf: ad...
1501
1502
1503
  }
  
  static noinline_for_stack
f00cc102b   Petr Mladek   vsprintf: Factor ...
1504
1505
1506
  char *ip_addr_string(char *buf, char *end, const void *ptr,
  		     struct printf_spec spec, const char *fmt)
  {
0b74d4d76   Petr Mladek   vsprintf: Consoli...
1507
  	char *err_fmt_msg;
3e5903eb9   Petr Mladek   vsprintf: Prevent...
1508
1509
  	if (check_pointer(&buf, end, ptr, spec))
  		return buf;
f00cc102b   Petr Mladek   vsprintf: Factor ...
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
  	switch (fmt[1]) {
  	case '6':
  		return ip6_addr_string(buf, end, ptr, spec, fmt);
  	case '4':
  		return ip4_addr_string(buf, end, ptr, spec, fmt);
  	case 'S': {
  		const union {
  			struct sockaddr		raw;
  			struct sockaddr_in	v4;
  			struct sockaddr_in6	v6;
  		} *sa = ptr;
  
  		switch (sa->raw.sa_family) {
  		case AF_INET:
  			return ip4_addr_string_sa(buf, end, &sa->v4, spec, fmt);
  		case AF_INET6:
  			return ip6_addr_string_sa(buf, end, &sa->v6, spec, fmt);
  		default:
c8c3b5843   Petr Mladek   vsprintf: Limit t...
1528
  			return error_string(buf, end, "(einval)", spec);
f00cc102b   Petr Mladek   vsprintf: Factor ...
1529
1530
  		}}
  	}
0b74d4d76   Petr Mladek   vsprintf: Consoli...
1531
  	err_fmt_msg = fmt[0] == 'i' ? "(%pi?)" : "(%pI?)";
c8c3b5843   Petr Mladek   vsprintf: Limit t...
1532
  	return error_string(buf, end, err_fmt_msg, spec);
f00cc102b   Petr Mladek   vsprintf: Factor ...
1533
1534
1535
  }
  
  static noinline_for_stack
71dca95d5   Andy Shevchenko   lib/vsprintf: add...
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
  char *escaped_string(char *buf, char *end, u8 *addr, struct printf_spec spec,
  		     const char *fmt)
  {
  	bool found = true;
  	int count = 1;
  	unsigned int flags = 0;
  	int len;
  
  	if (spec.field_width == 0)
  		return buf;				/* nothing to print */
3e5903eb9   Petr Mladek   vsprintf: Prevent...
1546
1547
  	if (check_pointer(&buf, end, addr, spec))
  		return buf;
71dca95d5   Andy Shevchenko   lib/vsprintf: add...
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
  
  	do {
  		switch (fmt[count++]) {
  		case 'a':
  			flags |= ESCAPE_ANY;
  			break;
  		case 'c':
  			flags |= ESCAPE_SPECIAL;
  			break;
  		case 'h':
  			flags |= ESCAPE_HEX;
  			break;
  		case 'n':
  			flags |= ESCAPE_NULL;
  			break;
  		case 'o':
  			flags |= ESCAPE_OCTAL;
  			break;
  		case 'p':
  			flags |= ESCAPE_NP;
  			break;
  		case 's':
  			flags |= ESCAPE_SPACE;
  			break;
  		default:
  			found = false;
  			break;
  		}
  	} while (found);
  
  	if (!flags)
  		flags = ESCAPE_ANY_NP;
  
  	len = spec.field_width < 0 ? 1 : spec.field_width;
41416f233   Rasmus Villemoes   lib/string_helper...
1582
1583
1584
1585
1586
1587
  	/*
  	 * string_escape_mem() writes as many characters as it can to
  	 * the given buffer, and returns the total size of the output
  	 * had the buffer been big enough.
  	 */
  	buf += string_escape_mem(addr, len, buf, buf < end ? end - buf : 0, flags, NULL);
71dca95d5   Andy Shevchenko   lib/vsprintf: add...
1588
1589
1590
  
  	return buf;
  }
3e5903eb9   Petr Mladek   vsprintf: Prevent...
1591
1592
  static char *va_format(char *buf, char *end, struct va_format *va_fmt,
  		       struct printf_spec spec, const char *fmt)
45c3e93d7   Petr Mladek   vsprintf: Factor ...
1593
1594
  {
  	va_list va;
3e5903eb9   Petr Mladek   vsprintf: Prevent...
1595
1596
  	if (check_pointer(&buf, end, va_fmt, spec))
  		return buf;
45c3e93d7   Petr Mladek   vsprintf: Factor ...
1597
1598
1599
1600
1601
1602
  	va_copy(va, *va_fmt->va);
  	buf += vsnprintf(buf, end > buf ? end - buf : 0, va_fmt->fmt, va);
  	va_end(va);
  
  	return buf;
  }
71dca95d5   Andy Shevchenko   lib/vsprintf: add...
1603
  static noinline_for_stack
cf3b429b0   Joe Perches   vsprintf.c: use n...
1604
1605
  char *uuid_string(char *buf, char *end, const u8 *addr,
  		  struct printf_spec spec, const char *fmt)
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1606
  {
2b1b0d667   Andy Shevchenko   lib/uuid.c: intro...
1607
  	char uuid[UUID_STRING_LEN + 1];
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1608
1609
  	char *p = uuid;
  	int i;
f9727a17d   Christoph Hellwig   uuid: rename uuid...
1610
  	const u8 *index = uuid_index;
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1611
  	bool uc = false;
3e5903eb9   Petr Mladek   vsprintf: Prevent...
1612
1613
  	if (check_pointer(&buf, end, addr, spec))
  		return buf;
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1614
1615
  	switch (*(++fmt)) {
  	case 'L':
df561f668   Gustavo A. R. Silva   treewide: Use fal...
1616
  		uc = true;
6a9dc5fd6   Gustavo A. R. Silva   lib: Revert use o...
1617
  		/* fall through */
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1618
  	case 'l':
f9727a17d   Christoph Hellwig   uuid: rename uuid...
1619
  		index = guid_index;
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1620
1621
1622
1623
1624
1625
1626
  		break;
  	case 'B':
  		uc = true;
  		break;
  	}
  
  	for (i = 0; i < 16; i++) {
aa4ea1c3b   Andy Shevchenko   lib/vsprintf: sim...
1627
1628
1629
1630
  		if (uc)
  			p = hex_byte_pack_upper(p, addr[index[i]]);
  		else
  			p = hex_byte_pack(p, addr[index[i]]);
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
  		switch (i) {
  		case 3:
  		case 5:
  		case 7:
  		case 9:
  			*p++ = '-';
  			break;
  		}
  	}
  
  	*p = 0;
d529ac419   Petr Mladek   vsprintf: Do not ...
1642
  	return string_nocheck(buf, end, uuid, spec);
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1643
  }
5b17aecfc   Andy Shevchenko   lib/vsprintf: fac...
1644
  static noinline_for_stack
431bca243   Geert Uytterhoeven   lib/vsprintf: Has...
1645
1646
  char *netdev_bits(char *buf, char *end, const void *addr,
  		  struct printf_spec spec,  const char *fmt)
c8f44affb   Michał Mirosław   net: introduce an...
1647
  {
5b17aecfc   Andy Shevchenko   lib/vsprintf: fac...
1648
1649
  	unsigned long long num;
  	int size;
3e5903eb9   Petr Mladek   vsprintf: Prevent...
1650
1651
  	if (check_pointer(&buf, end, addr, spec))
  		return buf;
5b17aecfc   Andy Shevchenko   lib/vsprintf: fac...
1652
1653
1654
1655
1656
1657
  	switch (fmt[1]) {
  	case 'F':
  		num = *(const netdev_features_t *)addr;
  		size = sizeof(netdev_features_t);
  		break;
  	default:
c8c3b5843   Petr Mladek   vsprintf: Limit t...
1658
  		return error_string(buf, end, "(%pN?)", spec);
5b17aecfc   Andy Shevchenko   lib/vsprintf: fac...
1659
  	}
c8f44affb   Michał Mirosław   net: introduce an...
1660

3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
1661
  	return special_hex_number(buf, end, num, size);
c8f44affb   Michał Mirosław   net: introduce an...
1662
  }
aaf07621b   Joe Perches   vsprintf: add %pa...
1663
  static noinline_for_stack
3e5903eb9   Petr Mladek   vsprintf: Prevent...
1664
1665
  char *address_val(char *buf, char *end, const void *addr,
  		  struct printf_spec spec, const char *fmt)
aaf07621b   Joe Perches   vsprintf: add %pa...
1666
1667
  {
  	unsigned long long num;
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
1668
  	int size;
aaf07621b   Joe Perches   vsprintf: add %pa...
1669

3e5903eb9   Petr Mladek   vsprintf: Prevent...
1670
1671
  	if (check_pointer(&buf, end, addr, spec))
  		return buf;
aaf07621b   Joe Perches   vsprintf: add %pa...
1672
1673
1674
  	switch (fmt[1]) {
  	case 'd':
  		num = *(const dma_addr_t *)addr;
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
1675
  		size = sizeof(dma_addr_t);
aaf07621b   Joe Perches   vsprintf: add %pa...
1676
1677
1678
1679
  		break;
  	case 'p':
  	default:
  		num = *(const phys_addr_t *)addr;
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
1680
  		size = sizeof(phys_addr_t);
aaf07621b   Joe Perches   vsprintf: add %pa...
1681
1682
  		break;
  	}
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
1683
  	return special_hex_number(buf, end, num, size);
aaf07621b   Joe Perches   vsprintf: add %pa...
1684
  }
900cca294   Geert Uytterhoeven   lib/vsprintf: add...
1685
  static noinline_for_stack
4d42c4472   Andy Shevchenko   lib/vsprintf: Pri...
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
  char *date_str(char *buf, char *end, const struct rtc_time *tm, bool r)
  {
  	int year = tm->tm_year + (r ? 0 : 1900);
  	int mon = tm->tm_mon + (r ? 0 : 1);
  
  	buf = number(buf, end, year, default_dec04_spec);
  	if (buf < end)
  		*buf = '-';
  	buf++;
  
  	buf = number(buf, end, mon, default_dec02_spec);
  	if (buf < end)
  		*buf = '-';
  	buf++;
  
  	return number(buf, end, tm->tm_mday, default_dec02_spec);
  }
  
  static noinline_for_stack
  char *time_str(char *buf, char *end, const struct rtc_time *tm, bool r)
  {
  	buf = number(buf, end, tm->tm_hour, default_dec02_spec);
  	if (buf < end)
  		*buf = ':';
  	buf++;
  
  	buf = number(buf, end, tm->tm_min, default_dec02_spec);
  	if (buf < end)
  		*buf = ':';
  	buf++;
  
  	return number(buf, end, tm->tm_sec, default_dec02_spec);
  }
  
  static noinline_for_stack
3e5903eb9   Petr Mladek   vsprintf: Prevent...
1721
1722
  char *rtc_str(char *buf, char *end, const struct rtc_time *tm,
  	      struct printf_spec spec, const char *fmt)
4d42c4472   Andy Shevchenko   lib/vsprintf: Pri...
1723
1724
1725
1726
  {
  	bool have_t = true, have_d = true;
  	bool raw = false;
  	int count = 2;
3e5903eb9   Petr Mladek   vsprintf: Prevent...
1727
1728
  	if (check_pointer(&buf, end, tm, spec))
  		return buf;
4d42c4472   Andy Shevchenko   lib/vsprintf: Pri...
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
  	switch (fmt[count]) {
  	case 'd':
  		have_t = false;
  		count++;
  		break;
  	case 't':
  		have_d = false;
  		count++;
  		break;
  	}
  
  	raw = fmt[count] == 'r';
  
  	if (have_d)
  		buf = date_str(buf, end, tm, raw);
  	if (have_d && have_t) {
  		/* Respect ISO 8601 */
  		if (buf < end)
  			*buf = 'T';
  		buf++;
  	}
  	if (have_t)
  		buf = time_str(buf, end, tm, raw);
  
  	return buf;
  }
  
  static noinline_for_stack
7daac5b2f   Andy Shevchenko   lib/vsprintf: Pri...
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
  char *time64_str(char *buf, char *end, const time64_t time,
  		 struct printf_spec spec, const char *fmt)
  {
  	struct rtc_time rtc_time;
  	struct tm tm;
  
  	time64_to_tm(time, 0, &tm);
  
  	rtc_time.tm_sec = tm.tm_sec;
  	rtc_time.tm_min = tm.tm_min;
  	rtc_time.tm_hour = tm.tm_hour;
  	rtc_time.tm_mday = tm.tm_mday;
  	rtc_time.tm_mon = tm.tm_mon;
  	rtc_time.tm_year = tm.tm_year;
  	rtc_time.tm_wday = tm.tm_wday;
  	rtc_time.tm_yday = tm.tm_yday;
  
  	rtc_time.tm_isdst = 0;
  
  	return rtc_str(buf, end, &rtc_time, spec, fmt);
  }
  
  static noinline_for_stack
4d42c4472   Andy Shevchenko   lib/vsprintf: Pri...
1780
1781
1782
1783
1784
  char *time_and_date(char *buf, char *end, void *ptr, struct printf_spec spec,
  		    const char *fmt)
  {
  	switch (fmt[1]) {
  	case 'R':
3e5903eb9   Petr Mladek   vsprintf: Prevent...
1785
  		return rtc_str(buf, end, (const struct rtc_time *)ptr, spec, fmt);
7daac5b2f   Andy Shevchenko   lib/vsprintf: Pri...
1786
1787
  	case 'T':
  		return time64_str(buf, end, *(const time64_t *)ptr, spec, fmt);
4d42c4472   Andy Shevchenko   lib/vsprintf: Pri...
1788
  	default:
7daac5b2f   Andy Shevchenko   lib/vsprintf: Pri...
1789
  		return error_string(buf, end, "(%pt?)", spec);
4d42c4472   Andy Shevchenko   lib/vsprintf: Pri...
1790
1791
1792
1793
  	}
  }
  
  static noinline_for_stack
900cca294   Geert Uytterhoeven   lib/vsprintf: add...
1794
1795
1796
  char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec,
  	    const char *fmt)
  {
0b74d4d76   Petr Mladek   vsprintf: Consoli...
1797
  	if (!IS_ENABLED(CONFIG_HAVE_CLK))
c8c3b5843   Petr Mladek   vsprintf: Limit t...
1798
  		return error_string(buf, end, "(%pC?)", spec);
0b74d4d76   Petr Mladek   vsprintf: Consoli...
1799

3e5903eb9   Petr Mladek   vsprintf: Prevent...
1800
1801
  	if (check_pointer(&buf, end, clk, spec))
  		return buf;
900cca294   Geert Uytterhoeven   lib/vsprintf: add...
1802
1803
  
  	switch (fmt[1]) {
900cca294   Geert Uytterhoeven   lib/vsprintf: add...
1804
1805
1806
1807
1808
  	case 'n':
  	default:
  #ifdef CONFIG_COMMON_CLK
  		return string(buf, end, __clk_get_name(clk), spec);
  #else
4ca96aa99   Geert Uytterhoeven   lib/vsprintf: Rei...
1809
  		return ptr_to_id(buf, end, clk, spec);
900cca294   Geert Uytterhoeven   lib/vsprintf: add...
1810
1811
1812
  #endif
  	}
  }
edf14cdbf   Vlastimil Babka   mm, printk: intro...
1813
1814
1815
1816
1817
  static
  char *format_flags(char *buf, char *end, unsigned long flags,
  					const struct trace_print_flags *names)
  {
  	unsigned long mask;
edf14cdbf   Vlastimil Babka   mm, printk: intro...
1818
1819
1820
1821
1822
  
  	for ( ; flags && names->name; names++) {
  		mask = names->mask;
  		if ((flags & mask) != mask)
  			continue;
abd4fe627   Andy Shevchenko   lib/vsprintf: Mak...
1823
  		buf = string(buf, end, names->name, default_str_spec);
edf14cdbf   Vlastimil Babka   mm, printk: intro...
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
  
  		flags &= ~mask;
  		if (flags) {
  			if (buf < end)
  				*buf = '|';
  			buf++;
  		}
  	}
  
  	if (flags)
544339730   Andy Shevchenko   lib/vsprintf: Mak...
1834
  		buf = number(buf, end, flags, default_flag_spec);
edf14cdbf   Vlastimil Babka   mm, printk: intro...
1835
1836
1837
1838
1839
  
  	return buf;
  }
  
  static noinline_for_stack
0b74d4d76   Petr Mladek   vsprintf: Consoli...
1840
1841
  char *flags_string(char *buf, char *end, void *flags_ptr,
  		   struct printf_spec spec, const char *fmt)
edf14cdbf   Vlastimil Babka   mm, printk: intro...
1842
1843
1844
  {
  	unsigned long flags;
  	const struct trace_print_flags *names;
3e5903eb9   Petr Mladek   vsprintf: Prevent...
1845
1846
  	if (check_pointer(&buf, end, flags_ptr, spec))
  		return buf;
edf14cdbf   Vlastimil Babka   mm, printk: intro...
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
  	switch (fmt[1]) {
  	case 'p':
  		flags = *(unsigned long *)flags_ptr;
  		/* Remove zone id */
  		flags &= (1UL << NR_PAGEFLAGS) - 1;
  		names = pageflag_names;
  		break;
  	case 'v':
  		flags = *(unsigned long *)flags_ptr;
  		names = vmaflag_names;
  		break;
  	case 'g':
30d497a0e   Andy Shevchenko   lib/vsprintf: For...
1859
  		flags = (__force unsigned long)(*(gfp_t *)flags_ptr);
edf14cdbf   Vlastimil Babka   mm, printk: intro...
1860
1861
1862
  		names = gfpflag_names;
  		break;
  	default:
c8c3b5843   Petr Mladek   vsprintf: Limit t...
1863
  		return error_string(buf, end, "(%pG?)", spec);
edf14cdbf   Vlastimil Babka   mm, printk: intro...
1864
1865
1866
1867
  	}
  
  	return format_flags(buf, end, flags, names);
  }
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
1868
  static noinline_for_stack
a92eb7621   Sakari Ailus   lib/vsprintf: Mak...
1869
1870
  char *fwnode_full_name_string(struct fwnode_handle *fwnode, char *buf,
  			      char *end)
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
1871
1872
  {
  	int depth;
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
1873

a92eb7621   Sakari Ailus   lib/vsprintf: Mak...
1874
1875
1876
1877
  	/* Loop starting from the root node to the current node. */
  	for (depth = fwnode_count_parents(fwnode); depth >= 0; depth--) {
  		struct fwnode_handle *__fwnode =
  			fwnode_get_nth_parent(fwnode, depth);
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
1878

a92eb7621   Sakari Ailus   lib/vsprintf: Mak...
1879
  		buf = string(buf, end, fwnode_get_name_prefix(__fwnode),
abd4fe627   Andy Shevchenko   lib/vsprintf: Mak...
1880
  			     default_str_spec);
a92eb7621   Sakari Ailus   lib/vsprintf: Mak...
1881
  		buf = string(buf, end, fwnode_get_name(__fwnode),
abd4fe627   Andy Shevchenko   lib/vsprintf: Mak...
1882
  			     default_str_spec);
a92eb7621   Sakari Ailus   lib/vsprintf: Mak...
1883
1884
  
  		fwnode_handle_put(__fwnode);
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
1885
  	}
a92eb7621   Sakari Ailus   lib/vsprintf: Mak...
1886

ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
  	return buf;
  }
  
  static noinline_for_stack
  char *device_node_string(char *buf, char *end, struct device_node *dn,
  			 struct printf_spec spec, const char *fmt)
  {
  	char tbuf[sizeof("xxxx") + 1];
  	const char *p;
  	int ret;
  	char *buf_start = buf;
  	struct property *prop;
  	bool has_mult, pass;
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
1900
1901
1902
  
  	struct printf_spec str_spec = spec;
  	str_spec.field_width = -1;
83abc5a77   Sakari Ailus   lib/vsprintf: OF ...
1903
1904
  	if (fmt[0] != 'F')
  		return error_string(buf, end, "(%pO?)", spec);
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
1905
  	if (!IS_ENABLED(CONFIG_OF))
c8c3b5843   Petr Mladek   vsprintf: Limit t...
1906
  		return error_string(buf, end, "(%pOF?)", spec);
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
1907

3e5903eb9   Petr Mladek   vsprintf: Prevent...
1908
1909
  	if (check_pointer(&buf, end, dn, spec))
  		return buf;
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
1910
1911
1912
1913
1914
1915
1916
  
  	/* simple case without anything any more format specifiers */
  	fmt++;
  	if (fmt[0] == '\0' || strcspn(fmt,"fnpPFcC") > 0)
  		fmt = "f";
  
  	for (pass = false; strspn(fmt,"fnpPFcC"); fmt++, pass = true) {
6d0a70a28   Rob Herring   vsprintf: print O...
1917
  		int precision;
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
1918
1919
1920
1921
1922
1923
1924
1925
  		if (pass) {
  			if (buf < end)
  				*buf = ':';
  			buf++;
  		}
  
  		switch (*fmt) {
  		case 'f':	/* full_name */
a92eb7621   Sakari Ailus   lib/vsprintf: Mak...
1926
1927
  			buf = fwnode_full_name_string(of_fwnode_handle(dn), buf,
  						      end);
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
1928
1929
  			break;
  		case 'n':	/* name */
a92eb7621   Sakari Ailus   lib/vsprintf: Mak...
1930
  			p = fwnode_get_name(of_fwnode_handle(dn));
6d0a70a28   Rob Herring   vsprintf: print O...
1931
1932
1933
1934
  			precision = str_spec.precision;
  			str_spec.precision = strchrnul(p, '@') - p;
  			buf = string(buf, end, p, str_spec);
  			str_spec.precision = precision;
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
1935
1936
  			break;
  		case 'p':	/* phandle */
09ceb8d76   Andy Shevchenko   lib/vsprintf: Rep...
1937
  			buf = number(buf, end, (unsigned int)dn->phandle, default_dec_spec);
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
1938
1939
  			break;
  		case 'P':	/* path-spec */
a92eb7621   Sakari Ailus   lib/vsprintf: Mak...
1940
  			p = fwnode_get_name(of_fwnode_handle(dn));
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
  			if (!p[1])
  				p = "/";
  			buf = string(buf, end, p, str_spec);
  			break;
  		case 'F':	/* flags */
  			tbuf[0] = of_node_check_flag(dn, OF_DYNAMIC) ? 'D' : '-';
  			tbuf[1] = of_node_check_flag(dn, OF_DETACHED) ? 'd' : '-';
  			tbuf[2] = of_node_check_flag(dn, OF_POPULATED) ? 'P' : '-';
  			tbuf[3] = of_node_check_flag(dn, OF_POPULATED_BUS) ? 'B' : '-';
  			tbuf[4] = 0;
d529ac419   Petr Mladek   vsprintf: Do not ...
1951
  			buf = string_nocheck(buf, end, tbuf, str_spec);
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
  			break;
  		case 'c':	/* major compatible string */
  			ret = of_property_read_string(dn, "compatible", &p);
  			if (!ret)
  				buf = string(buf, end, p, str_spec);
  			break;
  		case 'C':	/* full compatible string */
  			has_mult = false;
  			of_property_for_each_string(dn, "compatible", prop, p) {
  				if (has_mult)
d529ac419   Petr Mladek   vsprintf: Do not ...
1962
1963
  					buf = string_nocheck(buf, end, ",", str_spec);
  				buf = string_nocheck(buf, end, "\"", str_spec);
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
1964
  				buf = string(buf, end, p, str_spec);
d529ac419   Petr Mladek   vsprintf: Do not ...
1965
  				buf = string_nocheck(buf, end, "\"", str_spec);
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
  
  				has_mult = true;
  			}
  			break;
  		default:
  			break;
  		}
  	}
  
  	return widen_string(buf, buf - buf_start, end, spec);
  }
3bd32d6a2   Sakari Ailus   lib/vsprintf: Add...
1977
1978
1979
  static noinline_for_stack
  char *fwnode_string(char *buf, char *end, struct fwnode_handle *fwnode,
  		    struct printf_spec spec, const char *fmt)
798cc27a3   Petr Mladek   vsprintf: Factor ...
1980
  {
3bd32d6a2   Sakari Ailus   lib/vsprintf: Add...
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
  	struct printf_spec str_spec = spec;
  	char *buf_start = buf;
  
  	str_spec.field_width = -1;
  
  	if (*fmt != 'w')
  		return error_string(buf, end, "(%pf?)", spec);
  
  	if (check_pointer(&buf, end, fwnode, spec))
  		return buf;
  
  	fmt++;
  
  	switch (*fmt) {
  	case 'P':	/* name */
  		buf = string(buf, end, fwnode_get_name(fwnode), str_spec);
  		break;
  	case 'f':	/* full_name */
  	default:
  		buf = fwnode_full_name_string(fwnode, buf, end);
  		break;
798cc27a3   Petr Mladek   vsprintf: Factor ...
2002
  	}
3bd32d6a2   Sakari Ailus   lib/vsprintf: Add...
2003
  	return widen_string(buf, buf - buf_start, end, spec);
798cc27a3   Petr Mladek   vsprintf: Factor ...
2004
  }
4d8a743cd   Linus Torvalds   vsprintf: add inf...
2005
2006
2007
2008
2009
  /*
   * Show a '%p' thing.  A kernel extension is that the '%p' is followed
   * by an extra set of alphanumeric characters that are extended format
   * specifiers.
   *
0b523769e   Joe Perches   checkpatch: add a...
2010
2011
2012
   * Please update scripts/checkpatch.pl when adding/removing conversion
   * characters.  (Search for "check for vsprintf extension").
   *
332d2e783   Linus Torvalds   Implement %pR to ...
2013
2014
   * Right now we handle:
   *
cdb7e52d9   Sergey Senozhatsky   vsprintf: Tweak p...
2015
2016
   * - 'S' For symbolic direct pointers (or function descriptors) with offset
   * - 's' For symbolic direct pointers (or function descriptors) without offset
9af770649   Sakari Ailus   lib/vsprintf: Rem...
2017
   * - '[Ss]R' as above with __builtin_extract_return_addr() translation
1586c5ae2   Sakari Ailus   lib/vsprintf: Add...
2018
2019
   * - '[Ff]' %pf and %pF were obsoleted and later removed in favor of
   *	    %ps and %pS. Be careful when re-using these specifiers.
0f77a8d37   Namhyung Kim   vsprintf: Introdu...
2020
   * - 'B' For backtraced symbolic direct pointers with offset
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
2021
2022
   * - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref]
   * - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201]
dbc760bcc   Tejun Heo   lib/vsprintf: imp...
2023
2024
2025
2026
   * - 'b[l]' For a bitmap, the number of bits is determined by the field
   *       width which must be explicitly specified either as part of the
   *       format string '%32b[l]' or through '%*b[l]', [l] selects
   *       range-list format instead of hex format
dd45c9cf6   Harvey Harrison   printk: add %pM f...
2027
2028
   * - 'M' For a 6-byte MAC address, it prints the address in the
   *       usual colon-separated hex notation
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
2029
   * - 'm' For a 6-byte MAC address, it prints the hex address without colons
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
2030
   * - 'MF' For a 6-byte MAC FDDI address, it prints the address
c8e000604   Joe Perches   lib: Kill bit-rev...
2031
   *       with a dash-separated hex notation
7c59154e7   Andy Shevchenko   lib/vsprintf: upd...
2032
   * - '[mM]R' For a 6-byte MAC address, Reverse order (Bluetooth)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
2033
2034
2035
   * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way
   *       IPv4 uses dot-separated decimal without leading 0's (1.2.3.4)
   *       IPv6 uses colon separated network-order 16 bit hex with leading 0's
106796430   Daniel Borkmann   lib: vsprintf: ad...
2036
2037
2038
   *       [S][pfs]
   *       Generic IPv4/IPv6 address (struct sockaddr *) that falls back to
   *       [4] or [6] and is able to print port [p], flowinfo [f], scope [s]
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
2039
2040
2041
   * - 'i' [46] for 'raw' IPv4/IPv6 addresses
   *       IPv6 omits the colons (01020304...0f)
   *       IPv4 uses dot-separated decimal with leading 0's (010.123.045.006)
106796430   Daniel Borkmann   lib: vsprintf: ad...
2042
2043
2044
2045
2046
   *       [S][pfs]
   *       Generic IPv4/IPv6 address (struct sockaddr *) that falls back to
   *       [4] or [6] and is able to print port [p], flowinfo [f], scope [s]
   * - '[Ii][4S][hnbl]' IPv4 addresses in host, network, big or little endian order
   * - 'I[6S]c' for IPv6 addresses printed as specified by
8eda94bde   Alexander A. Klimov   Replace HTTP link...
2047
   *       https://tools.ietf.org/html/rfc5952
71dca95d5   Andy Shevchenko   lib/vsprintf: add...
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
   * - 'E[achnops]' For an escaped buffer, where rules are defined by combination
   *                of the following flags (see string_escape_mem() for the
   *                details):
   *                  a - ESCAPE_ANY
   *                  c - ESCAPE_SPECIAL
   *                  h - ESCAPE_HEX
   *                  n - ESCAPE_NULL
   *                  o - ESCAPE_OCTAL
   *                  p - ESCAPE_NP
   *                  s - ESCAPE_SPACE
   *                By default ESCAPE_ANY_NP is used.
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
   * - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form
   *       "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
   *       Options for %pU are:
   *         b big endian lower case hex (default)
   *         B big endian UPPER case hex
   *         l little endian lower case hex
   *         L little endian UPPER case hex
   *           big endian output byte order is:
   *             [0][1][2][3]-[4][5]-[6][7]-[8][9]-[10][11][12][13][14][15]
   *           little endian output byte order is:
   *             [3][2][1][0]-[5][4]-[7][6]-[8][9]-[10][11][12][13][14][15]
7db6f5fb6   Joe Perches   vsprintf: Recursi...
2070
2071
2072
2073
2074
   * - 'V' For a struct va_format which contains a format string * and va_list *,
   *       call vsnprintf(->format, *->va_list).
   *       Implements a "recursive vsnprintf".
   *       Do not use this feature without some mechanism to verify the
   *       correctness of the format string and va_list arguments.
455cd5ab3   Dan Rosenberg   kptr_restrict for...
2075
   * - 'K' For a kernel pointer that should be hidden from unprivileged users
c8f44affb   Michał Mirosław   net: introduce an...
2076
   * - 'NF' For a netdev_features_t
31550a16a   Andy Shevchenko   vsprintf: add sup...
2077
2078
2079
2080
2081
2082
2083
   * - 'h[CDN]' For a variable-length buffer, it prints it as a hex string with
   *            a certain separator (' ' by default):
   *              C colon
   *              D dash
   *              N no separator
   *            The maximum supported length is 64 bytes of the input. Consider
   *            to use print_hex_dump() for the larger input.
aaf07621b   Joe Perches   vsprintf: add %pa...
2084
2085
   * - 'a[pd]' For address types [p] phys_addr_t, [d] dma_addr_t and derivatives
   *           (default assumed to be phys_addr_t, passed by reference)
c0d92a57a   Olof Johansson   lib/vsprintf.c: d...
2086
2087
   * - 'd[234]' For a dentry name (optionally 2-4 last components)
   * - 'D[234]' Same as 'd' but for a struct file
1031bc589   Dmitry Monakhov   lib/vsprintf: add...
2088
   * - 'g' For block_device name (gendisk + partition number)
7daac5b2f   Andy Shevchenko   lib/vsprintf: Pri...
2089
   * - 't[RT][dt][r]' For time and date as represented by:
4d42c4472   Andy Shevchenko   lib/vsprintf: Pri...
2090
   *      R    struct rtc_time
7daac5b2f   Andy Shevchenko   lib/vsprintf: Pri...
2091
   *      T    time64_t
900cca294   Geert Uytterhoeven   lib/vsprintf: add...
2092
2093
2094
2095
   * - 'C' For a clock, it prints the name (Common Clock Framework) or address
   *       (legacy clock framework) of the clock
   * - 'Cn' For a clock, it prints the name (Common Clock Framework) or address
   *        (legacy clock framework) of the clock
edf14cdbf   Vlastimil Babka   mm, printk: intro...
2096
2097
2098
2099
2100
   * - 'G' For flags to be printed as a collection of symbolic strings that would
   *       construct the specific value. Supported flags given by option:
   *       p page flags (see struct page) given as pointer to unsigned long
   *       g gfp flags (GFP_* and __GFP_*) given as pointer to gfp_t
   *       v vma flags (VM_*) given as pointer to unsigned long
94ac8f207   Geert Uytterhoeven   doc: printk-forma...
2101
2102
2103
2104
2105
2106
2107
2108
2109
   * - 'OF[fnpPcCF]'  For a device tree object
   *                  Without any optional arguments prints the full_name
   *                  f device node full_name
   *                  n device node name
   *                  p device node phandle
   *                  P device node path spec (name + @unit)
   *                  F device node flags
   *                  c major compatible string
   *                  C full compatible string
3bd32d6a2   Sakari Ailus   lib/vsprintf: Add...
2110
2111
2112
2113
   * - 'fw[fP]'	For a firmware node (struct fwnode_handle) pointer
   *		Without an option prints the full name of the node
   *		f full name
   *		P node name, including a possible unit address
7b1924a1d   Tobin C. Harding   vsprintf: add pri...
2114
   * - 'x' For printing the address. Equivalent to "%lx".
b2a5212fb   Daniel Borkmann   bpf: Restrict bpf...
2115
2116
2117
2118
   * - '[ku]s' For a BPF/tracing related format specifier, e.g. used out of
   *           bpf_trace_printk() where [ku] prefix specifies either kernel (k)
   *           or user (u) memory to probe, and:
   *              s a string, equivalent to "%s" on direct vsnprintf() use
7b1924a1d   Tobin C. Harding   vsprintf: add pri...
2119
   *
b3ed23213   Tobin C. Harding   doc: convert prin...
2120
2121
   * ** When making changes please also update:
   *	Documentation/core-api/printk-formats.rst
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
2122
   *
ad67b74d2   Tobin C. Harding   printk: hash addr...
2123
2124
   * Note: The default behaviour (unadorned %p) is to hash the address,
   * rendering it useful as a unique identifier.
4d8a743cd   Linus Torvalds   vsprintf: add inf...
2125
   */
cf3b429b0   Joe Perches   vsprintf.c: use n...
2126
2127
2128
  static noinline_for_stack
  char *pointer(const char *fmt, char *buf, char *end, void *ptr,
  	      struct printf_spec spec)
78a8bf69b   Linus Torvalds   vsprintf: split o...
2129
  {
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
2130
  	switch (*fmt) {
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
2131
  	case 'S':
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
2132
  	case 's':
04b8eb7a4   Sergey Senozhatsky   symbol lookup: in...
2133
  		ptr = dereference_symbol_descriptor(ptr);
6a9dc5fd6   Gustavo A. R. Silva   lib: Revert use o...
2134
  		/* fall through */
0f77a8d37   Namhyung Kim   vsprintf: Introdu...
2135
  	case 'B':
b0d33c2bd   Joe Perches   vsprintf: Add ext...
2136
  		return symbol_string(buf, end, ptr, spec, fmt);
332d2e783   Linus Torvalds   Implement %pR to ...
2137
  	case 'R':
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
2138
  	case 'r':
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
2139
  		return resource_string(buf, end, ptr, spec, fmt);
31550a16a   Andy Shevchenko   vsprintf: add sup...
2140
2141
  	case 'h':
  		return hex_string(buf, end, ptr, spec, fmt);
dbc760bcc   Tejun Heo   lib/vsprintf: imp...
2142
2143
2144
2145
2146
2147
2148
  	case 'b':
  		switch (fmt[1]) {
  		case 'l':
  			return bitmap_list_string(buf, end, ptr, spec, fmt);
  		default:
  			return bitmap_string(buf, end, ptr, spec, fmt);
  		}
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
2149
2150
  	case 'M':			/* Colon separated: 00:01:02:03:04:05 */
  	case 'm':			/* Contiguous: 000102030405 */
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
2151
2152
  					/* [mM]F (FDDI) */
  					/* [mM]R (Reverse order; Bluetooth) */
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
  		return mac_address_string(buf, end, ptr, spec, fmt);
  	case 'I':			/* Formatted IP supported
  					 * 4:	1.2.3.4
  					 * 6:	0001:0203:...:0708
  					 * 6c:	1::708 or 1::1.2.3.4
  					 */
  	case 'i':			/* Contiguous:
  					 * 4:	001.002.003.004
  					 * 6:   000102...0f
  					 */
f00cc102b   Petr Mladek   vsprintf: Factor ...
2163
  		return ip_addr_string(buf, end, ptr, spec, fmt);
71dca95d5   Andy Shevchenko   lib/vsprintf: add...
2164
2165
  	case 'E':
  		return escaped_string(buf, end, ptr, spec, fmt);
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
2166
2167
  	case 'U':
  		return uuid_string(buf, end, ptr, spec, fmt);
7db6f5fb6   Joe Perches   vsprintf: Recursi...
2168
  	case 'V':
3e5903eb9   Petr Mladek   vsprintf: Prevent...
2169
  		return va_format(buf, end, ptr, spec, fmt);
455cd5ab3   Dan Rosenberg   kptr_restrict for...
2170
  	case 'K':
57e734423   Tobin C. Harding   vsprintf: refacto...
2171
  		return restricted_pointer(buf, end, ptr, spec);
c8f44affb   Michał Mirosław   net: introduce an...
2172
  	case 'N':
431bca243   Geert Uytterhoeven   lib/vsprintf: Has...
2173
  		return netdev_bits(buf, end, ptr, spec, fmt);
7d7992108   Stepan Moskovchenko   lib/vsprintf.c: a...
2174
  	case 'a':
3e5903eb9   Petr Mladek   vsprintf: Prevent...
2175
  		return address_val(buf, end, ptr, spec, fmt);
4b6ccca70   Al Viro   add formats for d...
2176
2177
  	case 'd':
  		return dentry_name(buf, end, ptr, spec, fmt);
4d42c4472   Andy Shevchenko   lib/vsprintf: Pri...
2178
2179
  	case 't':
  		return time_and_date(buf, end, ptr, spec, fmt);
900cca294   Geert Uytterhoeven   lib/vsprintf: add...
2180
2181
  	case 'C':
  		return clock(buf, end, ptr, spec, fmt);
4b6ccca70   Al Viro   add formats for d...
2182
  	case 'D':
36594b317   Jia He   vsprintf: Prevent...
2183
  		return file_dentry_name(buf, end, ptr, spec, fmt);
1031bc589   Dmitry Monakhov   lib/vsprintf: add...
2184
2185
2186
2187
  #ifdef CONFIG_BLOCK
  	case 'g':
  		return bdev_name(buf, end, ptr, spec, fmt);
  #endif
edf14cdbf   Vlastimil Babka   mm, printk: intro...
2188
  	case 'G':
0b74d4d76   Petr Mladek   vsprintf: Consoli...
2189
  		return flags_string(buf, end, ptr, spec, fmt);
ce4fecf1f   Pantelis Antoniou   vsprintf: Add %p ...
2190
  	case 'O':
83abc5a77   Sakari Ailus   lib/vsprintf: OF ...
2191
  		return device_node_string(buf, end, ptr, spec, fmt + 1);
3bd32d6a2   Sakari Ailus   lib/vsprintf: Add...
2192
2193
  	case 'f':
  		return fwnode_string(buf, end, ptr, spec, fmt + 1);
7b1924a1d   Tobin C. Harding   vsprintf: add pri...
2194
2195
  	case 'x':
  		return pointer_string(buf, end, ptr, spec);
57f5677e5   Rasmus Villemoes   printf: add suppo...
2196
2197
2198
2199
2200
  	case 'e':
  		/* %pe with a non-ERR_PTR gets treated as plain %p */
  		if (!IS_ERR(ptr))
  			break;
  		return err_ptr(buf, end, ptr, spec);
b2a5212fb   Daniel Borkmann   bpf: Restrict bpf...
2201
2202
2203
2204
2205
2206
2207
2208
  	case 'u':
  	case 'k':
  		switch (fmt[1]) {
  		case 's':
  			return string(buf, end, ptr, spec);
  		default:
  			return error_string(buf, end, "(einval)", spec);
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2209
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2210

ad67b74d2   Tobin C. Harding   printk: hash addr...
2211
2212
  	/* default is to _not_ leak addresses, hash before printing */
  	return ptr_to_id(buf, end, ptr, spec);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
  }
  
  /*
   * Helper function to decode printf style format.
   * Each call decode a token from the format and return the
   * number of characters read (or likely the delta where it wants
   * to go on the next call).
   * The decoded token is returned through the parameters
   *
   * 'h', 'l', or 'L' for integer fields
   * 'z' support added 23/7/1999 S.H.
   * 'z' changed to 'Z' --davidm 1/25/99
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
2225
   * 'Z' changed to 'z' --adobriyan 2017-01-25
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
   * 't' added for ptrdiff_t
   *
   * @fmt: the format string
   * @type of the token returned
   * @flags: various flags such as +, -, # tokens..
   * @field_width: overwritten width
   * @base: base of the number (octal, hex, ...)
   * @precision: precision of a number
   * @qualifier: qualifier of a number (long, size_t, ...)
   */
cf3b429b0   Joe Perches   vsprintf.c: use n...
2236
2237
  static noinline_for_stack
  int format_decode(const char *fmt, struct printf_spec *spec)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2238
2239
  {
  	const char *start = fmt;
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
2240
  	char qualifier;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2241
2242
  
  	/* we finished early by reading the field width */
ed681a91a   Vegard Nossum   vsprintf: unify t...
2243
  	if (spec->type == FORMAT_TYPE_WIDTH) {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
  		if (spec->field_width < 0) {
  			spec->field_width = -spec->field_width;
  			spec->flags |= LEFT;
  		}
  		spec->type = FORMAT_TYPE_NONE;
  		goto precision;
  	}
  
  	/* we finished early by reading the precision */
  	if (spec->type == FORMAT_TYPE_PRECISION) {
  		if (spec->precision < 0)
  			spec->precision = 0;
  
  		spec->type = FORMAT_TYPE_NONE;
  		goto qualifier;
  	}
  
  	/* By default */
  	spec->type = FORMAT_TYPE_NONE;
  
  	for (; *fmt ; ++fmt) {
  		if (*fmt == '%')
  			break;
  	}
  
  	/* Return the current non-format string */
  	if (fmt != start || !*fmt)
  		return fmt - start;
  
  	/* Process flags */
  	spec->flags = 0;
  
  	while (1) { /* this also skips first '%' */
  		bool found = true;
  
  		++fmt;
  
  		switch (*fmt) {
  		case '-': spec->flags |= LEFT;    break;
  		case '+': spec->flags |= PLUS;    break;
  		case ' ': spec->flags |= SPACE;   break;
  		case '#': spec->flags |= SPECIAL; break;
  		case '0': spec->flags |= ZEROPAD; break;
  		default:  found = false;
  		}
  
  		if (!found)
  			break;
  	}
  
  	/* get field width */
  	spec->field_width = -1;
  
  	if (isdigit(*fmt))
  		spec->field_width = skip_atoi(&fmt);
  	else if (*fmt == '*') {
  		/* it's the next argument */
ed681a91a   Vegard Nossum   vsprintf: unify t...
2301
  		spec->type = FORMAT_TYPE_WIDTH;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
  		return ++fmt - start;
  	}
  
  precision:
  	/* get the precision */
  	spec->precision = -1;
  	if (*fmt == '.') {
  		++fmt;
  		if (isdigit(*fmt)) {
  			spec->precision = skip_atoi(&fmt);
  			if (spec->precision < 0)
  				spec->precision = 0;
  		} else if (*fmt == '*') {
  			/* it's the next argument */
adf26f84a   Vegard Nossum   fix regression fr...
2316
  			spec->type = FORMAT_TYPE_PRECISION;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2317
2318
2319
2320
2321
2322
  			return ++fmt - start;
  		}
  	}
  
  qualifier:
  	/* get the conversion qualifier */
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
2323
  	qualifier = 0;
75fb8f269   Andy Shevchenko   lib: make _tolowe...
2324
  	if (*fmt == 'h' || _tolower(*fmt) == 'l' ||
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
2325
  	    *fmt == 'z' || *fmt == 't') {
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
2326
2327
2328
2329
  		qualifier = *fmt++;
  		if (unlikely(qualifier == *fmt)) {
  			if (qualifier == 'l') {
  				qualifier = 'L';
a4e94ef0d   Zhaolei   printk: add suppo...
2330
  				++fmt;
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
2331
2332
  			} else if (qualifier == 'h') {
  				qualifier = 'H';
a4e94ef0d   Zhaolei   printk: add suppo...
2333
2334
  				++fmt;
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
  		}
  	}
  
  	/* default base */
  	spec->base = 10;
  	switch (*fmt) {
  	case 'c':
  		spec->type = FORMAT_TYPE_CHAR;
  		return ++fmt - start;
  
  	case 's':
  		spec->type = FORMAT_TYPE_STR;
  		return ++fmt - start;
  
  	case 'p':
  		spec->type = FORMAT_TYPE_PTR;
ffbfed03b   Rasmus Villemoes   lib/vsprintf.c: c...
2351
  		return ++fmt - start;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2352

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
  	case '%':
  		spec->type = FORMAT_TYPE_PERCENT_CHAR;
  		return ++fmt - start;
  
  	/* integer number formats - set up the flags and "break" */
  	case 'o':
  		spec->base = 8;
  		break;
  
  	case 'x':
  		spec->flags |= SMALL;
6a9dc5fd6   Gustavo A. R. Silva   lib: Revert use o...
2364
  		/* fall through */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2365
2366
2367
2368
2369
2370
2371
  
  	case 'X':
  		spec->base = 16;
  		break;
  
  	case 'd':
  	case 'i':
39e874f8a   Frederic Weisbecker   vsprintf: fix bug...
2372
  		spec->flags |= SIGN;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2373
  	case 'u':
4aa996066   Harvey Harrison   printk: add %I4, ...
2374
  		break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2375

708d96fd0   Ryan Mallon   vsprintf: remove ...
2376
2377
  	case 'n':
  		/*
b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
2378
2379
2380
  		 * Since %n poses a greater security risk than
  		 * utility, treat it as any other invalid or
  		 * unsupported format specifier.
708d96fd0   Ryan Mallon   vsprintf: remove ...
2381
  		 */
6a9dc5fd6   Gustavo A. R. Silva   lib: Revert use o...
2382
  		/* fall through */
708d96fd0   Ryan Mallon   vsprintf: remove ...
2383

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2384
  	default:
b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
2385
2386
  		WARN_ONCE(1, "Please remove unsupported %%%c in format string
  ", *fmt);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2387
2388
  		spec->type = FORMAT_TYPE_INVALID;
  		return fmt - start;
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
2389
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2390

d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
2391
  	if (qualifier == 'L')
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2392
  		spec->type = FORMAT_TYPE_LONG_LONG;
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
2393
  	else if (qualifier == 'l') {
51be17dff   Rasmus Villemoes   lib/vsprintf.c: e...
2394
2395
  		BUILD_BUG_ON(FORMAT_TYPE_ULONG + SIGN != FORMAT_TYPE_LONG);
  		spec->type = FORMAT_TYPE_ULONG + (spec->flags & SIGN);
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
2396
  	} else if (qualifier == 'z') {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2397
  		spec->type = FORMAT_TYPE_SIZE_T;
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
2398
  	} else if (qualifier == 't') {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2399
  		spec->type = FORMAT_TYPE_PTRDIFF;
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
2400
  	} else if (qualifier == 'H') {
51be17dff   Rasmus Villemoes   lib/vsprintf.c: e...
2401
2402
  		BUILD_BUG_ON(FORMAT_TYPE_UBYTE + SIGN != FORMAT_TYPE_BYTE);
  		spec->type = FORMAT_TYPE_UBYTE + (spec->flags & SIGN);
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
2403
  	} else if (qualifier == 'h') {
51be17dff   Rasmus Villemoes   lib/vsprintf.c: e...
2404
2405
  		BUILD_BUG_ON(FORMAT_TYPE_USHORT + SIGN != FORMAT_TYPE_SHORT);
  		spec->type = FORMAT_TYPE_USHORT + (spec->flags & SIGN);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2406
  	} else {
51be17dff   Rasmus Villemoes   lib/vsprintf.c: e...
2407
2408
  		BUILD_BUG_ON(FORMAT_TYPE_UINT + SIGN != FORMAT_TYPE_INT);
  		spec->type = FORMAT_TYPE_UINT + (spec->flags & SIGN);
78a8bf69b   Linus Torvalds   vsprintf: split o...
2409
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2410
2411
  
  	return ++fmt - start;
78a8bf69b   Linus Torvalds   vsprintf: split o...
2412
  }
4d72ba014   Rasmus Villemoes   lib/vsprintf.c: w...
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
  static void
  set_field_width(struct printf_spec *spec, int width)
  {
  	spec->field_width = width;
  	if (WARN_ONCE(spec->field_width != width, "field width %d too large", width)) {
  		spec->field_width = clamp(width, -FIELD_WIDTH_MAX, FIELD_WIDTH_MAX);
  	}
  }
  
  static void
  set_precision(struct printf_spec *spec, int prec)
  {
  	spec->precision = prec;
  	if (WARN_ONCE(spec->precision != prec, "precision %d too large", prec)) {
  		spec->precision = clamp(prec, 0, PRECISION_MAX);
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2430
2431
2432
2433
2434
2435
2436
  /**
   * vsnprintf - Format a string and place it in a buffer
   * @buf: The buffer to place the result into
   * @size: The size of the buffer, including the trailing null space
   * @fmt: The format string to use
   * @args: Arguments for the format string
   *
d7ec9a05d   Rasmus Villemoes   lib/vsprintf.c: u...
2437
2438
2439
   * This function generally follows C99 vsnprintf, but has some
   * extensions and a few limitations:
   *
6cc89134c   mchehab@s-opensource.com   kernel-api.rst: f...
2440
2441
   *  - ``%n`` is unsupported
   *  - ``%p*`` is handled by pointer()
5e4ee7b13   Martin Kletzander   printk: synchroni...
2442
   *
27e7c0e81   Jonathan Corbet   vsprintf: Fix a d...
2443
   * See pointer() or Documentation/core-api/printk-formats.rst for more
5e4ee7b13   Martin Kletzander   printk: synchroni...
2444
   * extensive description.
20036fdca   Andi Kleen   Add kerneldoc doc...
2445
   *
6cc89134c   mchehab@s-opensource.com   kernel-api.rst: f...
2446
   * **Please update the documentation in both places when making changes**
80f548e04   Andrew Morton   lib/vsprintf.c: r...
2447
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2448
2449
2450
2451
   * The return value is the number of characters which would
   * be generated for the given input, excluding the trailing
   * '\0', as per ISO C99. If you want to have the exact
   * number of characters written into @buf as return value
72fd4a35a   Robert P. J. Day   [PATCH] Numerous ...
2452
   * (not including the trailing '\0'), use vscnprintf(). If the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2453
2454
2455
   * return is greater than or equal to @size, the resulting
   * string is truncated.
   *
ba1835eb3   Uwe Kleine-König   vsprintf: make co...
2456
   * If you're not already dealing with a va_list consider using snprintf().
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2457
2458
2459
   */
  int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2460
  	unsigned long long num;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2461
  	char *str, *end;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2462
  	struct printf_spec spec = {0};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2463

f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
2464
2465
  	/* Reject out-of-range values early.  Large positive sizes are
  	   used for unknown buffer sizes. */
2aa2f9e21   Rasmus Villemoes   lib/vsprintf.c: i...
2466
  	if (WARN_ON_ONCE(size > INT_MAX))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2467
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2468
2469
  
  	str = buf;
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
2470
  	end = buf + size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2471

f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
2472
2473
2474
2475
  	/* Make sure end is always >= buf */
  	if (end < buf) {
  		end = ((void *)-1);
  		size = end - buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2476
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2477
2478
  	while (*fmt) {
  		const char *old_fmt = fmt;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2479
  		int read = format_decode(fmt, &spec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2480

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2481
  		fmt += read;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2482

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2483
2484
2485
2486
2487
2488
2489
  		switch (spec.type) {
  		case FORMAT_TYPE_NONE: {
  			int copy = read;
  			if (str < end) {
  				if (copy > end - str)
  					copy = end - str;
  				memcpy(str, old_fmt, copy);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2490
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2491
2492
  			str += read;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2493
  		}
ed681a91a   Vegard Nossum   vsprintf: unify t...
2494
  		case FORMAT_TYPE_WIDTH:
4d72ba014   Rasmus Villemoes   lib/vsprintf.c: w...
2495
  			set_field_width(&spec, va_arg(args, int));
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2496
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2497

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2498
  		case FORMAT_TYPE_PRECISION:
4d72ba014   Rasmus Villemoes   lib/vsprintf.c: w...
2499
  			set_precision(&spec, va_arg(args, int));
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2500
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2501

d4be151b2   André Goddard Rosa   vsprintf: move lo...
2502
2503
  		case FORMAT_TYPE_CHAR: {
  			char c;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2504
2505
  			if (!(spec.flags & LEFT)) {
  				while (--spec.field_width > 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
2506
  					if (str < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2507
2508
  						*str = ' ';
  					++str;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2509

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2510
2511
2512
2513
2514
2515
2516
  				}
  			}
  			c = (unsigned char) va_arg(args, int);
  			if (str < end)
  				*str = c;
  			++str;
  			while (--spec.field_width > 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
2517
  				if (str < end)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2518
  					*str = ' ';
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2519
  				++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2520
2521
  			}
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2522
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2523

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2524
2525
2526
  		case FORMAT_TYPE_STR:
  			str = string(str, end, va_arg(args, char *), spec);
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2527

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2528
  		case FORMAT_TYPE_PTR:
ffbfed03b   Rasmus Villemoes   lib/vsprintf.c: c...
2529
  			str = pointer(fmt, str, end, va_arg(args, void *),
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2530
2531
2532
2533
  				      spec);
  			while (isalnum(*fmt))
  				fmt++;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2534

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2535
2536
2537
2538
2539
  		case FORMAT_TYPE_PERCENT_CHAR:
  			if (str < end)
  				*str = '%';
  			++str;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2540

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2541
  		case FORMAT_TYPE_INVALID:
b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
2542
2543
2544
2545
2546
2547
2548
2549
2550
  			/*
  			 * Presumably the arguments passed gcc's type
  			 * checking, but there is no safe or sane way
  			 * for us to continue parsing the format and
  			 * fetching from the va_list; the remaining
  			 * specifiers and arguments would be out of
  			 * sync.
  			 */
  			goto out;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2551

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
  		default:
  			switch (spec.type) {
  			case FORMAT_TYPE_LONG_LONG:
  				num = va_arg(args, long long);
  				break;
  			case FORMAT_TYPE_ULONG:
  				num = va_arg(args, unsigned long);
  				break;
  			case FORMAT_TYPE_LONG:
  				num = va_arg(args, long);
  				break;
  			case FORMAT_TYPE_SIZE_T:
ef1249602   Jason Gunthorpe   lib/vsprintf.c: f...
2564
2565
2566
2567
  				if (spec.flags & SIGN)
  					num = va_arg(args, ssize_t);
  				else
  					num = va_arg(args, size_t);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2568
2569
2570
2571
  				break;
  			case FORMAT_TYPE_PTRDIFF:
  				num = va_arg(args, ptrdiff_t);
  				break;
a4e94ef0d   Zhaolei   printk: add suppo...
2572
2573
2574
2575
2576
2577
  			case FORMAT_TYPE_UBYTE:
  				num = (unsigned char) va_arg(args, int);
  				break;
  			case FORMAT_TYPE_BYTE:
  				num = (signed char) va_arg(args, int);
  				break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2578
2579
2580
2581
2582
2583
  			case FORMAT_TYPE_USHORT:
  				num = (unsigned short) va_arg(args, int);
  				break;
  			case FORMAT_TYPE_SHORT:
  				num = (short) va_arg(args, int);
  				break;
39e874f8a   Frederic Weisbecker   vsprintf: fix bug...
2584
2585
  			case FORMAT_TYPE_INT:
  				num = (int) va_arg(args, int);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2586
2587
2588
2589
2590
2591
  				break;
  			default:
  				num = va_arg(args, unsigned int);
  			}
  
  			str = number(str, end, num, spec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2592
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2593
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2594

b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
2595
  out:
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
2596
2597
2598
2599
  	if (size > 0) {
  		if (str < end)
  			*str = '\0';
  		else
0a6047eef   Linus Torvalds   Fix vsnprintf off...
2600
  			end[-1] = '\0';
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
2601
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2602

f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
2603
  	/* the trailing null byte doesn't count towards the total */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2604
  	return str-buf;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2605

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2606
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
  EXPORT_SYMBOL(vsnprintf);
  
  /**
   * vscnprintf - Format a string and place it in a buffer
   * @buf: The buffer to place the result into
   * @size: The size of the buffer, including the trailing null space
   * @fmt: The format string to use
   * @args: Arguments for the format string
   *
   * The return value is the number of characters which have been written into
b921c69fb   Anton Arapov   lib/vsprintf.c: f...
2617
   * the @buf not including the trailing '\0'. If @size is == 0 the function
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2618
2619
   * returns 0.
   *
ba1835eb3   Uwe Kleine-König   vsprintf: make co...
2620
   * If you're not already dealing with a va_list consider using scnprintf().
20036fdca   Andi Kleen   Add kerneldoc doc...
2621
2622
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2623
2624
2625
2626
   */
  int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
  {
  	int i;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2627
  	i = vsnprintf(buf, size, fmt, args);
b921c69fb   Anton Arapov   lib/vsprintf.c: f...
2628
2629
2630
2631
2632
  	if (likely(i < size))
  		return i;
  	if (size != 0)
  		return size - 1;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2633
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
  EXPORT_SYMBOL(vscnprintf);
  
  /**
   * snprintf - Format a string and place it in a buffer
   * @buf: The buffer to place the result into
   * @size: The size of the buffer, including the trailing null space
   * @fmt: The format string to use
   * @...: Arguments for the format string
   *
   * The return value is the number of characters which would be
   * generated for the given input, excluding the trailing null,
   * as per ISO C99.  If the return is greater than or equal to
   * @size, the resulting string is truncated.
20036fdca   Andi Kleen   Add kerneldoc doc...
2647
2648
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2649
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2650
  int snprintf(char *buf, size_t size, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2651
2652
2653
2654
2655
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2656
  	i = vsnprintf(buf, size, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2657
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2658

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2659
2660
  	return i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
  EXPORT_SYMBOL(snprintf);
  
  /**
   * scnprintf - Format a string and place it in a buffer
   * @buf: The buffer to place the result into
   * @size: The size of the buffer, including the trailing null space
   * @fmt: The format string to use
   * @...: Arguments for the format string
   *
   * The return value is the number of characters written into @buf not including
b903c0b88   Changli Gao   lib: fix scnprint...
2671
   * the trailing '\0'. If @size is == 0 the function returns 0.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2672
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2673
  int scnprintf(char *buf, size_t size, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2674
2675
2676
2677
2678
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
b921c69fb   Anton Arapov   lib/vsprintf.c: f...
2679
  	i = vscnprintf(buf, size, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2680
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2681

b921c69fb   Anton Arapov   lib/vsprintf.c: f...
2682
  	return i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
  }
  EXPORT_SYMBOL(scnprintf);
  
  /**
   * vsprintf - Format a string and place it in a buffer
   * @buf: The buffer to place the result into
   * @fmt: The format string to use
   * @args: Arguments for the format string
   *
   * The function returns the number of characters written
72fd4a35a   Robert P. J. Day   [PATCH] Numerous ...
2693
   * into @buf. Use vsnprintf() or vscnprintf() in order to avoid
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2694
2695
   * buffer overflows.
   *
ba1835eb3   Uwe Kleine-König   vsprintf: make co...
2696
   * If you're not already dealing with a va_list consider using sprintf().
20036fdca   Andi Kleen   Add kerneldoc doc...
2697
2698
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2699
2700
2701
2702
2703
   */
  int vsprintf(char *buf, const char *fmt, va_list args)
  {
  	return vsnprintf(buf, INT_MAX, fmt, args);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2704
2705
2706
2707
2708
2709
2710
2711
2712
  EXPORT_SYMBOL(vsprintf);
  
  /**
   * sprintf - Format a string and place it in a buffer
   * @buf: The buffer to place the result into
   * @fmt: The format string to use
   * @...: Arguments for the format string
   *
   * The function returns the number of characters written
72fd4a35a   Robert P. J. Day   [PATCH] Numerous ...
2713
   * into @buf. Use snprintf() or scnprintf() in order to avoid
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2714
   * buffer overflows.
20036fdca   Andi Kleen   Add kerneldoc doc...
2715
2716
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2717
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2718
  int sprintf(char *buf, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2719
2720
2721
2722
2723
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2724
  	i = vsnprintf(buf, INT_MAX, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2725
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2726

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2727
2728
  	return i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2729
  EXPORT_SYMBOL(sprintf);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
  #ifdef CONFIG_BINARY_PRINTF
  /*
   * bprintf service:
   * vbin_printf() - VA arguments to binary data
   * bstr_printf() - Binary data to text string
   */
  
  /**
   * vbin_printf - Parse a format string and place args' binary value in a buffer
   * @bin_buf: The buffer to place args' binary value
   * @size: The size of the buffer(by words(32bits), not characters)
   * @fmt: The format string to use
   * @args: Arguments for the format string
   *
   * The format follows C99 vsnprintf, except %n is ignored, and its argument
da3dae54e   Masanari Iida   Documentation: Do...
2745
   * is skipped.
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
   *
   * The return value is the number of words(32bits) which would be generated for
   * the given input.
   *
   * NOTE:
   * If the return value is greater than @size, the resulting bin_buf is NOT
   * valid for bstr_printf().
   */
  int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args)
  {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2756
  	struct printf_spec spec = {0};
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2757
  	char *str, *end;
841a915d2   Steven Rostedt (VMware)   vsprintf: Do not ...
2758
  	int width;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2759
2760
2761
2762
2763
  
  	str = (char *)bin_buf;
  	end = (char *)(bin_buf + size);
  
  #define save_arg(type)							\
841a915d2   Steven Rostedt (VMware)   vsprintf: Do not ...
2764
2765
  ({									\
  	unsigned long long value;					\
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2766
  	if (sizeof(type) == 8) {					\
841a915d2   Steven Rostedt (VMware)   vsprintf: Do not ...
2767
  		unsigned long long val8;				\
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2768
  		str = PTR_ALIGN(str, sizeof(u32));			\
841a915d2   Steven Rostedt (VMware)   vsprintf: Do not ...
2769
  		val8 = va_arg(args, unsigned long long);		\
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2770
  		if (str + sizeof(type) <= end) {			\
841a915d2   Steven Rostedt (VMware)   vsprintf: Do not ...
2771
2772
  			*(u32 *)str = *(u32 *)&val8;			\
  			*(u32 *)(str + 4) = *((u32 *)&val8 + 1);	\
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2773
  		}							\
841a915d2   Steven Rostedt (VMware)   vsprintf: Do not ...
2774
  		value = val8;						\
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2775
  	} else {							\
841a915d2   Steven Rostedt (VMware)   vsprintf: Do not ...
2776
  		unsigned int val4;					\
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2777
  		str = PTR_ALIGN(str, sizeof(type));			\
841a915d2   Steven Rostedt (VMware)   vsprintf: Do not ...
2778
  		val4 = va_arg(args, int);				\
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2779
  		if (str + sizeof(type) <= end)				\
841a915d2   Steven Rostedt (VMware)   vsprintf: Do not ...
2780
2781
  			*(typeof(type) *)str = (type)(long)val4;	\
  		value = (unsigned long long)val4;			\
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2782
2783
  	}								\
  	str += sizeof(type);						\
841a915d2   Steven Rostedt (VMware)   vsprintf: Do not ...
2784
2785
  	value;								\
  })
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2786

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2787
  	while (*fmt) {
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2788
  		int read = format_decode(fmt, &spec);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2789

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2790
  		fmt += read;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2791

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2792
2793
  		switch (spec.type) {
  		case FORMAT_TYPE_NONE:
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2794
  		case FORMAT_TYPE_PERCENT_CHAR:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2795
  			break;
b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
2796
2797
  		case FORMAT_TYPE_INVALID:
  			goto out;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2798

ed681a91a   Vegard Nossum   vsprintf: unify t...
2799
  		case FORMAT_TYPE_WIDTH:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2800
  		case FORMAT_TYPE_PRECISION:
841a915d2   Steven Rostedt (VMware)   vsprintf: Do not ...
2801
2802
2803
2804
  			width = (int)save_arg(int);
  			/* Pointers may require the width */
  			if (*fmt == 'p')
  				set_field_width(&spec, width);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2805
2806
2807
  			break;
  
  		case FORMAT_TYPE_CHAR:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2808
  			save_arg(char);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2809
2810
2811
  			break;
  
  		case FORMAT_TYPE_STR: {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2812
  			const char *save_str = va_arg(args, char *);
3e5903eb9   Petr Mladek   vsprintf: Prevent...
2813
  			const char *err_msg;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2814
  			size_t len;
6c3566341   André Goddard Rosa   vsprintf: pre-cal...
2815

3e5903eb9   Petr Mladek   vsprintf: Prevent...
2816
2817
2818
  			err_msg = check_pointer_msg(save_str);
  			if (err_msg)
  				save_str = err_msg;
6c3566341   André Goddard Rosa   vsprintf: pre-cal...
2819
2820
2821
2822
  			len = strlen(save_str) + 1;
  			if (str + len < end)
  				memcpy(str, save_str, len);
  			str += len;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2823
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2824
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2825
2826
  
  		case FORMAT_TYPE_PTR:
841a915d2   Steven Rostedt (VMware)   vsprintf: Do not ...
2827
2828
2829
2830
2831
  			/* Dereferenced pointers must be done now */
  			switch (*fmt) {
  			/* Dereference of functions is still OK */
  			case 'S':
  			case 's':
1e6338cfb   Steven Rostedt (VMware)   vsprintf: Do not ...
2832
2833
  			case 'x':
  			case 'K':
57f5677e5   Rasmus Villemoes   printf: add suppo...
2834
  			case 'e':
841a915d2   Steven Rostedt (VMware)   vsprintf: Do not ...
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
  				save_arg(void *);
  				break;
  			default:
  				if (!isalnum(*fmt)) {
  					save_arg(void *);
  					break;
  				}
  				str = pointer(fmt, str, end, va_arg(args, void *),
  					      spec);
  				if (str + 1 < end)
  					*str++ = '\0';
  				else
  					end[-1] = '\0'; /* Must be nul terminated */
  			}
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2849
  			/* skip all alphanumeric pointer suffixes */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2850
  			while (isalnum(*fmt))
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2851
  				fmt++;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2852
  			break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2853
2854
2855
2856
  		default:
  			switch (spec.type) {
  
  			case FORMAT_TYPE_LONG_LONG:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2857
  				save_arg(long long);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2858
2859
2860
  				break;
  			case FORMAT_TYPE_ULONG:
  			case FORMAT_TYPE_LONG:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2861
  				save_arg(unsigned long);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2862
2863
  				break;
  			case FORMAT_TYPE_SIZE_T:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2864
  				save_arg(size_t);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2865
2866
  				break;
  			case FORMAT_TYPE_PTRDIFF:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2867
  				save_arg(ptrdiff_t);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2868
  				break;
a4e94ef0d   Zhaolei   printk: add suppo...
2869
2870
2871
2872
  			case FORMAT_TYPE_UBYTE:
  			case FORMAT_TYPE_BYTE:
  				save_arg(char);
  				break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2873
2874
  			case FORMAT_TYPE_USHORT:
  			case FORMAT_TYPE_SHORT:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2875
  				save_arg(short);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2876
2877
  				break;
  			default:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2878
  				save_arg(int);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2879
  			}
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2880
2881
  		}
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2882

b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
2883
  out:
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2884
  	return (u32 *)(PTR_ALIGN(str, sizeof(u32))) - bin_buf;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2885
  #undef save_arg
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
  }
  EXPORT_SYMBOL_GPL(vbin_printf);
  
  /**
   * bstr_printf - Format a string from binary arguments and place it in a buffer
   * @buf: The buffer to place the result into
   * @size: The size of the buffer, including the trailing null space
   * @fmt: The format string to use
   * @bin_buf: Binary arguments for the format string
   *
   * This function like C99 vsnprintf, but the difference is that vsnprintf gets
   * arguments from stack, and bstr_printf gets arguments from @bin_buf which is
   * a binary buffer that generated by vbin_printf.
   *
   * The format follows C99 vsnprintf, but has some extensions:
0efb4d207   Steven Rostedt   vsnprintf: remove...
2901
   *  see vsnprintf comment for details.
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
   *
   * The return value is the number of characters which would
   * be generated for the given input, excluding the trailing
   * '\0', as per ISO C99. If you want to have the exact
   * number of characters written into @buf as return value
   * (not including the trailing '\0'), use vscnprintf(). If the
   * return is greater than or equal to @size, the resulting
   * string is truncated.
   */
  int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf)
  {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2913
  	struct printf_spec spec = {0};
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2914
2915
  	char *str, *end;
  	const char *args = (const char *)bin_buf;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2916

762abb515   Rasmus Villemoes   lib/vsprintf.c: a...
2917
  	if (WARN_ON_ONCE(size > INT_MAX))
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2918
  		return 0;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
  
  	str = buf;
  	end = buf + size;
  
  #define get_arg(type)							\
  ({									\
  	typeof(type) value;						\
  	if (sizeof(type) == 8) {					\
  		args = PTR_ALIGN(args, sizeof(u32));			\
  		*(u32 *)&value = *(u32 *)args;				\
  		*((u32 *)&value + 1) = *(u32 *)(args + 4);		\
  	} else {							\
  		args = PTR_ALIGN(args, sizeof(type));			\
  		value = *(typeof(type) *)args;				\
  	}								\
  	args += sizeof(type);						\
  	value;								\
  })
  
  	/* Make sure end is always >= buf */
  	if (end < buf) {
  		end = ((void *)-1);
  		size = end - buf;
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2943
  	while (*fmt) {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2944
  		const char *old_fmt = fmt;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2945
  		int read = format_decode(fmt, &spec);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2946

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2947
  		fmt += read;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2948

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2949
2950
2951
2952
2953
2954
2955
  		switch (spec.type) {
  		case FORMAT_TYPE_NONE: {
  			int copy = read;
  			if (str < end) {
  				if (copy > end - str)
  					copy = end - str;
  				memcpy(str, old_fmt, copy);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2956
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2957
2958
  			str += read;
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2959
  		}
ed681a91a   Vegard Nossum   vsprintf: unify t...
2960
  		case FORMAT_TYPE_WIDTH:
4d72ba014   Rasmus Villemoes   lib/vsprintf.c: w...
2961
  			set_field_width(&spec, get_arg(int));
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2962
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2963

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2964
  		case FORMAT_TYPE_PRECISION:
4d72ba014   Rasmus Villemoes   lib/vsprintf.c: w...
2965
  			set_precision(&spec, get_arg(int));
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2966
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2967

d4be151b2   André Goddard Rosa   vsprintf: move lo...
2968
2969
  		case FORMAT_TYPE_CHAR: {
  			char c;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2970
2971
  			if (!(spec.flags & LEFT)) {
  				while (--spec.field_width > 0) {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2972
2973
2974
2975
2976
2977
2978
2979
2980
  					if (str < end)
  						*str = ' ';
  					++str;
  				}
  			}
  			c = (unsigned char) get_arg(char);
  			if (str < end)
  				*str = c;
  			++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2981
  			while (--spec.field_width > 0) {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2982
2983
2984
2985
  				if (str < end)
  					*str = ' ';
  				++str;
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2986
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2987
  		}
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2988

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2989
  		case FORMAT_TYPE_STR: {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2990
  			const char *str_arg = args;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2991
  			args += strlen(str_arg) + 1;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2992
2993
  			str = string(str, end, (char *)str_arg, spec);
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2994
  		}
841a915d2   Steven Rostedt (VMware)   vsprintf: Do not ...
2995
2996
2997
2998
2999
3000
3001
3002
3003
  		case FORMAT_TYPE_PTR: {
  			bool process = false;
  			int copy, len;
  			/* Non function dereferences were already done */
  			switch (*fmt) {
  			case 'S':
  			case 's':
  			case 'F':
  			case 'f':
1e6338cfb   Steven Rostedt (VMware)   vsprintf: Do not ...
3004
3005
  			case 'x':
  			case 'K':
57f5677e5   Rasmus Villemoes   printf: add suppo...
3006
  			case 'e':
841a915d2   Steven Rostedt (VMware)   vsprintf: Do not ...
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
  				process = true;
  				break;
  			default:
  				if (!isalnum(*fmt)) {
  					process = true;
  					break;
  				}
  				/* Pointer dereference was already processed */
  				if (str < end) {
  					len = copy = strlen(args);
  					if (copy > end - str)
  						copy = end - str;
  					memcpy(str, args, copy);
  					str += len;
62165600a   Steven Rostedt (VMware)   vsprintf: Fix off...
3021
  					args += len + 1;
841a915d2   Steven Rostedt (VMware)   vsprintf: Do not ...
3022
3023
3024
3025
  				}
  			}
  			if (process)
  				str = pointer(fmt, str, end, get_arg(void *), spec);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
3026
  			while (isalnum(*fmt))
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
3027
  				fmt++;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
3028
  			break;
841a915d2   Steven Rostedt (VMware)   vsprintf: Do not ...
3029
  		}
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
3030

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
3031
  		case FORMAT_TYPE_PERCENT_CHAR:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
3032
3033
3034
  			if (str < end)
  				*str = '%';
  			++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
3035
  			break;
b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
3036
3037
  		case FORMAT_TYPE_INVALID:
  			goto out;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
3038
3039
  		default: {
  			unsigned long long num;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
3040
3041
3042
3043
3044
3045
  			switch (spec.type) {
  
  			case FORMAT_TYPE_LONG_LONG:
  				num = get_arg(long long);
  				break;
  			case FORMAT_TYPE_ULONG:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
3046
3047
3048
3049
3050
3051
3052
3053
3054
  			case FORMAT_TYPE_LONG:
  				num = get_arg(unsigned long);
  				break;
  			case FORMAT_TYPE_SIZE_T:
  				num = get_arg(size_t);
  				break;
  			case FORMAT_TYPE_PTRDIFF:
  				num = get_arg(ptrdiff_t);
  				break;
a4e94ef0d   Zhaolei   printk: add suppo...
3055
3056
3057
3058
3059
3060
  			case FORMAT_TYPE_UBYTE:
  				num = get_arg(unsigned char);
  				break;
  			case FORMAT_TYPE_BYTE:
  				num = get_arg(signed char);
  				break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
  			case FORMAT_TYPE_USHORT:
  				num = get_arg(unsigned short);
  				break;
  			case FORMAT_TYPE_SHORT:
  				num = get_arg(short);
  				break;
  			case FORMAT_TYPE_UINT:
  				num = get_arg(unsigned int);
  				break;
  			default:
  				num = get_arg(int);
  			}
  
  			str = number(str, end, num, spec);
d4be151b2   André Goddard Rosa   vsprintf: move lo...
3075
3076
3077
  		} /* default: */
  		} /* switch(spec.type) */
  	} /* while(*fmt) */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
3078

b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
3079
  out:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
3080
3081
3082
3083
3084
3085
  	if (size > 0) {
  		if (str < end)
  			*str = '\0';
  		else
  			end[-1] = '\0';
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
3086

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
  #undef get_arg
  
  	/* the trailing null byte doesn't count towards the total */
  	return str - buf;
  }
  EXPORT_SYMBOL_GPL(bstr_printf);
  
  /**
   * bprintf - Parse a format string and place args' binary value in a buffer
   * @bin_buf: The buffer to place args' binary value
   * @size: The size of the buffer(by words(32bits), not characters)
   * @fmt: The format string to use
   * @...: Arguments for the format string
   *
   * The function returns the number of words(u32) written
   * into @bin_buf.
   */
  int bprintf(u32 *bin_buf, size_t size, const char *fmt, ...)
  {
  	va_list args;
  	int ret;
  
  	va_start(args, fmt);
  	ret = vbin_printf(bin_buf, size, fmt, args);
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
3112

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
3113
3114
3115
3116
3117
  	return ret;
  }
  EXPORT_SYMBOL_GPL(bprintf);
  
  #endif /* CONFIG_BINARY_PRINTF */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3118
3119
3120
3121
3122
3123
  /**
   * vsscanf - Unformat a buffer into a list of arguments
   * @buf:	input buffer
   * @fmt:	format of buffer
   * @args:	arguments
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
3124
  int vsscanf(const char *buf, const char *fmt, va_list args)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3125
3126
3127
3128
3129
  {
  	const char *str = buf;
  	char *next;
  	char digit;
  	int num = 0;
ef0658f3d   Joe Perches   vsprintf.c: Reduc...
3130
  	u8 qualifier;
53809751a   Jan Beulich   sscanf: don't ign...
3131
3132
3133
3134
3135
  	unsigned int base;
  	union {
  		long long s;
  		unsigned long long u;
  	} val;
ef0658f3d   Joe Perches   vsprintf.c: Reduc...
3136
  	s16 field_width;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
3137
  	bool is_sign;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3138

da99075c1   Jan Beulich   lib/vsprintf.c: i...
3139
  	while (*fmt) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3140
3141
3142
3143
3144
  		/* skip any white space in format */
  		/* white space in format matchs any amount of
  		 * white space, including none, in the input.
  		 */
  		if (isspace(*fmt)) {
e7d2860b6   André Goddard Rosa   tree-wide: conver...
3145
3146
  			fmt = skip_spaces(++fmt);
  			str = skip_spaces(str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
  		}
  
  		/* anything that is not a conversion must match exactly */
  		if (*fmt != '%' && *fmt) {
  			if (*fmt++ != *str++)
  				break;
  			continue;
  		}
  
  		if (!*fmt)
  			break;
  		++fmt;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
3159

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3160
3161
3162
3163
  		/* skip this conversion.
  		 * advance both strings to next white space
  		 */
  		if (*fmt == '*') {
da99075c1   Jan Beulich   lib/vsprintf.c: i...
3164
3165
  			if (!*str)
  				break;
f9310b2f9   Jessica Yu   sscanf: implement...
3166
3167
3168
3169
  			while (!isspace(*fmt) && *fmt != '%' && *fmt) {
  				/* '%*[' not yet supported, invalid format */
  				if (*fmt == '[')
  					return num;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3170
  				fmt++;
f9310b2f9   Jessica Yu   sscanf: implement...
3171
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3172
3173
3174
3175
3176
3177
3178
  			while (!isspace(*str) && *str)
  				str++;
  			continue;
  		}
  
  		/* get field width */
  		field_width = -1;
53809751a   Jan Beulich   sscanf: don't ign...
3179
  		if (isdigit(*fmt)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3180
  			field_width = skip_atoi(&fmt);
53809751a   Jan Beulich   sscanf: don't ign...
3181
3182
3183
  			if (field_width <= 0)
  				break;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3184
3185
3186
  
  		/* get conversion qualifier */
  		qualifier = -1;
75fb8f269   Andy Shevchenko   lib: make _tolowe...
3187
  		if (*fmt == 'h' || _tolower(*fmt) == 'l' ||
5b5e0928f   Alexey Dobriyan   lib/vsprintf.c: r...
3188
  		    *fmt == 'z') {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
  			qualifier = *fmt++;
  			if (unlikely(qualifier == *fmt)) {
  				if (qualifier == 'h') {
  					qualifier = 'H';
  					fmt++;
  				} else if (qualifier == 'l') {
  					qualifier = 'L';
  					fmt++;
  				}
  			}
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3200

da99075c1   Jan Beulich   lib/vsprintf.c: i...
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
  		if (!*fmt)
  			break;
  
  		if (*fmt == 'n') {
  			/* return number of characters read so far */
  			*va_arg(args, int *) = str - buf;
  			++fmt;
  			continue;
  		}
  
  		if (!*str)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3212
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
3213
  		base = 10;
3f623eba2   Fabian Frederick   lib/vsprintf.c: f...
3214
  		is_sign = false;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
3215

7b9186f5e   André Goddard Rosa   vsprintf: give it...
3216
  		switch (*fmt++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3217
3218
  		case 'c':
  		{
7b9186f5e   André Goddard Rosa   vsprintf: give it...
3219
  			char *s = (char *)va_arg(args, char*);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
  			if (field_width == -1)
  				field_width = 1;
  			do {
  				*s++ = *str++;
  			} while (--field_width > 0 && *str);
  			num++;
  		}
  		continue;
  		case 's':
  		{
7b9186f5e   André Goddard Rosa   vsprintf: give it...
3230
3231
  			char *s = (char *)va_arg(args, char *);
  			if (field_width == -1)
4be929be3   Alexey Dobriyan   kernel-wide: repl...
3232
  				field_width = SHRT_MAX;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3233
  			/* first, skip leading white space in buffer */
e7d2860b6   André Goddard Rosa   tree-wide: conver...
3234
  			str = skip_spaces(str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3235
3236
  
  			/* now copy until next white space */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
3237
  			while (*str && !isspace(*str) && field_width--)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3238
  				*s++ = *str++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3239
3240
3241
3242
  			*s = '\0';
  			num++;
  		}
  		continue;
f9310b2f9   Jessica Yu   sscanf: implement...
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
  		/*
  		 * Warning: This implementation of the '[' conversion specifier
  		 * deviates from its glibc counterpart in the following ways:
  		 * (1) It does NOT support ranges i.e. '-' is NOT a special
  		 *     character
  		 * (2) It cannot match the closing bracket ']' itself
  		 * (3) A field width is required
  		 * (4) '%*[' (discard matching input) is currently not supported
  		 *
  		 * Example usage:
  		 * ret = sscanf("00:0a:95","%2[^:]:%2[^:]:%2[^:]",
  		 *		buf1, buf2, buf3);
  		 * if (ret < 3)
  		 *    // etc..
  		 */
  		case '[':
  		{
  			char *s = (char *)va_arg(args, char *);
  			DECLARE_BITMAP(set, 256) = {0};
  			unsigned int len = 0;
  			bool negate = (*fmt == '^');
  
  			/* field width is required */
  			if (field_width == -1)
  				return num;
  
  			if (negate)
  				++fmt;
  
  			for ( ; *fmt && *fmt != ']'; ++fmt, ++len)
  				set_bit((u8)*fmt, set);
  
  			/* no ']' or no character set found */
  			if (!*fmt || !len)
  				return num;
  			++fmt;
  
  			if (negate) {
  				bitmap_complement(set, set, 256);
  				/* exclude null '\0' byte */
  				clear_bit(0, set);
  			}
  
  			/* match must be non-empty */
  			if (!test_bit((u8)*str, set))
  				return num;
  
  			while (test_bit((u8)*str, set) && field_width--)
  				*s++ = *str++;
  			*s = '\0';
  			++num;
  		}
  		continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3296
3297
3298
3299
3300
3301
3302
3303
  		case 'o':
  			base = 8;
  			break;
  		case 'x':
  		case 'X':
  			base = 16;
  			break;
  		case 'i':
7b9186f5e   André Goddard Rosa   vsprintf: give it...
3304
  			base = 0;
6a9dc5fd6   Gustavo A. R. Silva   lib: Revert use o...
3305
  			/* fall through */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3306
  		case 'd':
3f623eba2   Fabian Frederick   lib/vsprintf.c: f...
3307
  			is_sign = true;
6a9dc5fd6   Gustavo A. R. Silva   lib: Revert use o...
3308
  			/* fall through */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3309
3310
3311
3312
  		case 'u':
  			break;
  		case '%':
  			/* looking for '%' in str */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
3313
  			if (*str++ != '%')
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
  				return num;
  			continue;
  		default:
  			/* invalid format; stop here */
  			return num;
  		}
  
  		/* have some sort of integer conversion.
  		 * first, skip white space in buffer.
  		 */
e7d2860b6   André Goddard Rosa   tree-wide: conver...
3324
  		str = skip_spaces(str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3325
3326
3327
3328
3329
3330
  
  		digit = *str;
  		if (is_sign && digit == '-')
  			digit = *(str + 1);
  
  		if (!digit
7b9186f5e   André Goddard Rosa   vsprintf: give it...
3331
3332
3333
3334
3335
  		    || (base == 16 && !isxdigit(digit))
  		    || (base == 10 && !isdigit(digit))
  		    || (base == 8 && (!isdigit(digit) || digit > '7'))
  		    || (base == 0 && !isdigit(digit)))
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3336

53809751a   Jan Beulich   sscanf: don't ign...
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
  		if (is_sign)
  			val.s = qualifier != 'L' ?
  				simple_strtol(str, &next, base) :
  				simple_strtoll(str, &next, base);
  		else
  			val.u = qualifier != 'L' ?
  				simple_strtoul(str, &next, base) :
  				simple_strtoull(str, &next, base);
  
  		if (field_width > 0 && next - str > field_width) {
  			if (base == 0)
  				_parse_integer_fixup_radix(str, &base);
  			while (next - str > field_width) {
  				if (is_sign)
  					val.s = div_s64(val.s, base);
  				else
  					val.u = div_u64(val.u, base);
  				--next;
  			}
  		}
7b9186f5e   André Goddard Rosa   vsprintf: give it...
3357
  		switch (qualifier) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3358
  		case 'H':	/* that's 'hh' in format */
53809751a   Jan Beulich   sscanf: don't ign...
3359
3360
3361
3362
  			if (is_sign)
  				*va_arg(args, signed char *) = val.s;
  			else
  				*va_arg(args, unsigned char *) = val.u;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3363
3364
  			break;
  		case 'h':
53809751a   Jan Beulich   sscanf: don't ign...
3365
3366
3367
3368
  			if (is_sign)
  				*va_arg(args, short *) = val.s;
  			else
  				*va_arg(args, unsigned short *) = val.u;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3369
3370
  			break;
  		case 'l':
53809751a   Jan Beulich   sscanf: don't ign...
3371
3372
3373
3374
  			if (is_sign)
  				*va_arg(args, long *) = val.s;
  			else
  				*va_arg(args, unsigned long *) = val.u;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3375
3376
  			break;
  		case 'L':
53809751a   Jan Beulich   sscanf: don't ign...
3377
3378
3379
3380
  			if (is_sign)
  				*va_arg(args, long long *) = val.s;
  			else
  				*va_arg(args, unsigned long long *) = val.u;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3381
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3382
  		case 'z':
53809751a   Jan Beulich   sscanf: don't ign...
3383
3384
  			*va_arg(args, size_t *) = val.u;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3385
  		default:
53809751a   Jan Beulich   sscanf: don't ign...
3386
3387
3388
3389
  			if (is_sign)
  				*va_arg(args, int *) = val.s;
  			else
  				*va_arg(args, unsigned int *) = val.u;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3390
3391
3392
3393
3394
3395
3396
3397
  			break;
  		}
  		num++;
  
  		if (!next)
  			break;
  		str = next;
  	}
c6b40d16d   Johannes Berg   fix sscanf %n mat...
3398

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3399
3400
  	return num;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3401
3402
3403
3404
3405
3406
3407
3408
  EXPORT_SYMBOL(vsscanf);
  
  /**
   * sscanf - Unformat a buffer into a list of arguments
   * @buf:	input buffer
   * @fmt:	formatting of buffer
   * @...:	resulting arguments
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
3409
  int sscanf(const char *buf, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3410
3411
3412
  {
  	va_list args;
  	int i;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
3413
3414
  	va_start(args, fmt);
  	i = vsscanf(buf, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3415
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
3416

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3417
3418
  	return i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3419
  EXPORT_SYMBOL(sscanf);