Blame view

lib/vsprintf.c 66.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
  /*
   *  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...
11
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
15
16
17
18
   * 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>
0d1d7a558   Stephen Boyd   lib/vsprintf.c: I...
19
  #include <linux/clk.h>
900cca294   Geert Uytterhoeven   lib/vsprintf: add...
20
  #include <linux/clk-provider.h>
8bc3bcc93   Paul Gortmaker   lib: reduce the u...
21
  #include <linux/module.h>	/* for KSYM_SYMBOL_LEN */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
  #include <linux/types.h>
  #include <linux/string.h>
  #include <linux/ctype.h>
  #include <linux/kernel.h>
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
26
  #include <linux/kallsyms.h>
53809751a   Jan Beulich   sscanf: don't ign...
27
  #include <linux/math64.h>
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
28
  #include <linux/uaccess.h>
332d2e783   Linus Torvalds   Implement %pR to ...
29
  #include <linux/ioport.h>
4b6ccca70   Al Viro   add formats for d...
30
  #include <linux/dcache.h>
312b4e226   Ryan Mallon   vsprintf: check r...
31
  #include <linux/cred.h>
2b1b0d667   Andy Shevchenko   lib/uuid.c: intro...
32
  #include <linux/uuid.h>
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
33
  #include <net/addrconf.h>
1031bc589   Dmitry Monakhov   lib/vsprintf: add...
34
35
36
  #ifdef CONFIG_BLOCK
  #include <linux/blkdev.h>
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37

edf14cdbf   Vlastimil Babka   mm, printk: intro...
38
  #include "../mm/internal.h"	/* For the trace_print_flags arrays */
4e57b6817   Tim Schmielau   [PATCH] fix missi...
39
  #include <asm/page.h>		/* for PAGE_SIZE */
deac93df2   James Bottomley   lib: Correct prin...
40
  #include <asm/sections.h>	/* for dereference_function_descriptor() */
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
41
  #include <asm/byteorder.h>	/* cpu_to_le16 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
  /**
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
47
   * simple_strtoull - convert a string to an unsigned long long
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
50
   * @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...
51
52
   *
   * This function is obsolete. Please use kstrtoull instead.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
   */
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
54
  unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  {
1dff46d69   Alexey Dobriyan   lib/kstrtox: comm...
56
57
  	unsigned long long result;
  	unsigned int rv;
aa46a63ef   Harvey Harrison   lib: pull base-gu...
58

1dff46d69   Alexey Dobriyan   lib/kstrtox: comm...
59
60
61
62
  	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...
63

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
  	return result;
  }
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
69
  EXPORT_SYMBOL(simple_strtoull);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
  
  /**
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
72
   * simple_strtoul - convert a string to an unsigned long
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
75
   * @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...
76
77
   *
   * This function is obsolete. Please use kstrtoul instead.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
   */
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
79
  unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
  {
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
81
  	return simple_strtoull(cp, endp, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
  }
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
83
  EXPORT_SYMBOL(simple_strtoul);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
  
  /**
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
86
   * simple_strtol - convert a string to a signed long
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
89
   * @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...
90
91
   *
   * This function is obsolete. Please use kstrtol instead.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
   */
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
93
  long simple_strtol(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
  {
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
95
96
  	if (*cp == '-')
  		return -simple_strtoul(cp + 1, endp, base);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
97

922ac25c9   André Goddard Rosa   vsprintf: reuse a...
98
  	return simple_strtoul(cp, endp, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
  }
922ac25c9   André Goddard Rosa   vsprintf: reuse a...
100
  EXPORT_SYMBOL(simple_strtol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
103
104
105
106
  
  /**
   * 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...
107
108
   *
   * This function is obsolete. Please use kstrtoll instead.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
   */
22d27051b   Harvey Harrison   lib: trivial whit...
110
  long long simple_strtoll(const char *cp, char **endp, unsigned int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
  {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
112
  	if (*cp == '-')
22d27051b   Harvey Harrison   lib: trivial whit...
113
  		return -simple_strtoull(cp + 1, endp, base);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
114

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

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

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
  	return i;
  }
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
  /*
   * 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...
153
   */
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
154

7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  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...
172
173
174
   * 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...
175
  */
cf3b429b0   Joe Perches   vsprintf.c: use n...
176
  static noinline_for_stack
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
177
  char *put_dec_trunc8(char *buf, unsigned r)
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
178
  {
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
179
180
181
182
183
184
185
186
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
  	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...
213
  	buf += r < 10 ? 1 : 2;
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
214
215
  	return buf;
  }
133fd9f5c   Denys Vlasenko   vsprintf: further...
216

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

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

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

7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
237
238
239
240
241
  	/* 0 <= q < 100 */
  	*((u16 *)buf) = decpair[q];
  	buf += 2;
  	return buf;
  }
133fd9f5c   Denys Vlasenko   vsprintf: further...
242

7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
243
  static noinline_for_stack
133fd9f5c   Denys Vlasenko   vsprintf: further...
244
245
  char *put_dec(char *buf, unsigned long long n)
  {
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
246
247
248
249
250
251
  	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...
252
  	return put_dec_trunc8(buf, n);
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
253
  }
133fd9f5c   Denys Vlasenko   vsprintf: further...
254

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

7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
257
258
  static void
  put_dec_full4(char *buf, unsigned r)
4277eedd7   Denis Vlasenko   vsprintf.c: optim...
259
  {
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
260
261
262
263
264
265
266
267
  	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...
268
269
270
271
272
273
274
  }
  
  /*
   * 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...
275
   * (second call in the put_dec code, assuming n is all-ones).
2359172a7   George Spelvin   lib: vsprintf: op...
276
   */
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
277
  static noinline_for_stack
2359172a7   George Spelvin   lib: vsprintf: op...
278
279
280
281
282
283
  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...
284
  }
133fd9f5c   Denys Vlasenko   vsprintf: further...
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
  /* 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...
302
303
  	/* 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...
304
  	q   = 656 * d3 + 7296 * d2 + 5536 * d1 + ((uint32_t)n & 0xffff);
2359172a7   George Spelvin   lib: vsprintf: op...
305
306
307
308
309
310
311
  	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...
312

2359172a7   George Spelvin   lib: vsprintf: op...
313
314
315
316
317
  	q += 281 * d3;
  	buf += 12;
  	if (q)
  		buf = put_dec_trunc8(buf, q);
  	else while (buf[-1] == '0')
133fd9f5c   Denys Vlasenko   vsprintf: further...
318
319
320
321
322
323
  		--buf;
  
  	return buf;
  }
  
  #endif
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
324
325
326
327
328
329
330
331
  /*
   * 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.
   */
  int num_to_str(char *buf, int size, unsigned long long num)
  {
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
332
333
  	/* put_dec requires 2-byte alignment of the buffer. */
  	char tmp[sizeof(num) * 3] __aligned(2);
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
334
  	int idx, len;
133fd9f5c   Denys Vlasenko   vsprintf: further...
335
336
337
338
339
340
341
  	/* 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...
342
343
344
345
346
  
  	if (len > size)
  		return 0;
  	for (idx = 0; idx < len; ++idx)
  		buf[idx] = tmp[len - idx - 1];
133fd9f5c   Denys Vlasenko   vsprintf: further...
347
  	return len;
1ac101a5d   KAMEZAWA Hiroyuki   procfs: add num_t...
348
  }
51be17dff   Rasmus Villemoes   lib/vsprintf.c: e...
349
  #define SIGN	1		/* unsigned/signed, must be 1 */
d1c1b1213   Rasmus Villemoes   lib/vsprintf.c: a...
350
  #define LEFT	2		/* left justified */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
352
  #define PLUS	4		/* show plus */
  #define SPACE	8		/* space if plus */
d1c1b1213   Rasmus Villemoes   lib/vsprintf.c: a...
353
  #define ZEROPAD	16		/* pad with zero, must be 16 == '0' - ' ' */
b89dc5d6b   Bjorn Helgaas   vsprintf: clarify...
354
355
  #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
356

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
357
358
  enum format_type {
  	FORMAT_TYPE_NONE, /* Just a string part */
ed681a91a   Vegard Nossum   vsprintf: unify t...
359
  	FORMAT_TYPE_WIDTH,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
360
361
362
363
364
365
366
367
368
  	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...
369
370
  	FORMAT_TYPE_UBYTE,
  	FORMAT_TYPE_BYTE,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
371
372
373
374
  	FORMAT_TYPE_USHORT,
  	FORMAT_TYPE_SHORT,
  	FORMAT_TYPE_UINT,
  	FORMAT_TYPE_INT,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
375
376
377
378
379
  	FORMAT_TYPE_SIZE_T,
  	FORMAT_TYPE_PTRDIFF
  };
  
  struct printf_spec {
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
380
381
382
383
384
385
  	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;
4d72ba014   Rasmus Villemoes   lib/vsprintf.c: w...
386
387
  #define FIELD_WIDTH_MAX ((1 << 23) - 1)
  #define PRECISION_MAX ((1 << 15) - 1)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
388

cf3b429b0   Joe Perches   vsprintf.c: use n...
389
390
391
  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
392
  {
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
393
394
  	/* put_dec requires 2-byte alignment of the buffer. */
  	char tmp[3 * sizeof(num)] __aligned(2);
9b706aee7   Denys Vlasenko   x86: trivial prin...
395
396
  	char sign;
  	char locase;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
397
  	int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
  	int i;
7c2034223   Pierre Carrier   lib/vsprintf.c: "...
399
  	bool is_zero = num == 0LL;
1c7a8e622   Rasmus Villemoes   lib/vsprintf.c: h...
400
401
  	int field_width = spec.field_width;
  	int precision = spec.precision;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
  	return buf;
  }
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
510
511
512
513
514
515
516
517
518
519
520
521
522
  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...
523
  static void move_right(char *buf, char *end, unsigned len, unsigned spaces)
4b6ccca70   Al Viro   add formats for d...
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
  {
  	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...
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
  /*
   * 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;
  }
4b6ccca70   Al Viro   add formats for d...
568
  static noinline_for_stack
95508cfa1   Rasmus Villemoes   lib/vsprintf.c: m...
569
570
  char *string(char *buf, char *end, const char *s, struct printf_spec spec)
  {
34fc8b907   Rasmus Villemoes   lib/vsprintf.c: e...
571
572
  	int len = 0;
  	size_t lim = spec.precision;
95508cfa1   Rasmus Villemoes   lib/vsprintf.c: m...
573
574
575
  
  	if ((unsigned long)s < PAGE_SIZE)
  		s = "(null)";
34fc8b907   Rasmus Villemoes   lib/vsprintf.c: e...
576
577
578
579
  	while (lim--) {
  		char c = *s++;
  		if (!c)
  			break;
95508cfa1   Rasmus Villemoes   lib/vsprintf.c: m...
580
  		if (buf < end)
34fc8b907   Rasmus Villemoes   lib/vsprintf.c: e...
581
  			*buf = c;
95508cfa1   Rasmus Villemoes   lib/vsprintf.c: m...
582
  		++buf;
34fc8b907   Rasmus Villemoes   lib/vsprintf.c: e...
583
  		++len;
95508cfa1   Rasmus Villemoes   lib/vsprintf.c: m...
584
  	}
34fc8b907   Rasmus Villemoes   lib/vsprintf.c: e...
585
  	return widen_string(buf, len, end, spec);
95508cfa1   Rasmus Villemoes   lib/vsprintf.c: m...
586
587
588
  }
  
  static noinline_for_stack
4b6ccca70   Al Viro   add formats for d...
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
  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) {
  		p = ACCESS_ONCE(d->d_parent);
  		array[i] = ACCESS_ONCE(d->d_name.name);
  		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...
629
  	return widen_string(buf, n, end, spec);
4b6ccca70   Al Viro   add formats for d...
630
  }
1031bc589   Dmitry Monakhov   lib/vsprintf: add...
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
  #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)
  {
  	struct gendisk *hd = bdev->bd_disk;
  	
  	buf = string(buf, end, hd->disk_name, spec);
  	if (bdev->bd_part->partno) {
  		if (isdigit(hd->disk_name[strlen(hd->disk_name)-1])) {
  			if (buf < end)
  				*buf = 'p';
  			buf++;
  		}
  		buf = number(buf, end, bdev->bd_part->partno, spec);
  	}
  	return buf;
  }
  #endif
cf3b429b0   Joe Perches   vsprintf.c: use n...
650
651
  static noinline_for_stack
  char *symbol_string(char *buf, char *end, void *ptr,
b0d33c2bd   Joe Perches   vsprintf: Add ext...
652
  		    struct printf_spec spec, const char *fmt)
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
653
  {
b0d33c2bd   Joe Perches   vsprintf: Add ext...
654
  	unsigned long value;
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
655
656
  #ifdef CONFIG_KALLSYMS
  	char sym[KSYM_SYMBOL_LEN];
b0d33c2bd   Joe Perches   vsprintf: Add ext...
657
658
659
660
661
662
663
664
  #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...
665
  		sprint_backtrace(sym, value);
b0d33c2bd   Joe Perches   vsprintf: Add ext...
666
  	else if (*fmt != 'f' && *fmt != 's')
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
667
668
  		sprint_symbol(sym, value);
  	else
4796dd200   Stephen Boyd   vsprintf: fix %ps...
669
  		sprint_symbol_no_offset(sym, value);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
670

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
671
  	return string(buf, end, sym, spec);
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
672
  #else
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
673
  	return special_hex_number(buf, end, value, sizeof(void *));
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
674
675
  #endif
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
676
677
678
  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 ...
679
680
  {
  #ifndef IO_RSRC_PRINTK_SIZE
284053722   Bjorn Helgaas   vsprintf: fix io/...
681
  #define IO_RSRC_PRINTK_SIZE	6
332d2e783   Linus Torvalds   Implement %pR to ...
682
683
684
  #endif
  
  #ifndef MEM_RSRC_PRINTK_SIZE
284053722   Bjorn Helgaas   vsprintf: fix io/...
685
  #define MEM_RSRC_PRINTK_SIZE	10
332d2e783   Linus Torvalds   Implement %pR to ...
686
  #endif
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
687
  	static const struct printf_spec io_spec = {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
688
  		.base = 16,
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
689
  		.field_width = IO_RSRC_PRINTK_SIZE,
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
690
691
692
  		.precision = -1,
  		.flags = SPECIAL | SMALL | ZEROPAD,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
693
694
695
696
697
698
  	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...
699
700
701
702
703
704
  	static const struct printf_spec bus_spec = {
  		.base = 16,
  		.field_width = 2,
  		.precision = -1,
  		.flags = SMALL | ZEROPAD,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
705
  	static const struct printf_spec dec_spec = {
c91d3376e   Bjorn Helgaas   vsprintf: add %pR...
706
707
708
709
  		.base = 10,
  		.precision = -1,
  		.flags = 0,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
710
  	static const struct printf_spec str_spec = {
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
711
712
713
714
  		.field_width = -1,
  		.precision = 10,
  		.flags = LEFT,
  	};
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
715
  	static const struct printf_spec flag_spec = {
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
716
717
718
719
  		.base = 16,
  		.precision = -1,
  		.flags = SPECIAL | SMALL,
  	};
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
720
721
722
723
724
  
  	/* 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...
725
  #define DECODED_BUF_SIZE	sizeof("[mem - 64bit pref window disabled]")
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
726
727
728
  #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 ...
729
  	char *p = sym, *pend = sym + sizeof(sym);
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
730
  	int decode = (fmt[0] == 'R') ? 1 : 0;
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
731
  	const struct printf_spec *specp;
332d2e783   Linus Torvalds   Implement %pR to ...
732
733
  
  	*p++ = '[';
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
734
  	if (res->flags & IORESOURCE_IO) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
735
  		p = string(p, pend, "io  ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
736
737
  		specp = &io_spec;
  	} else if (res->flags & IORESOURCE_MEM) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
738
  		p = string(p, pend, "mem ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
739
740
  		specp = &mem_spec;
  	} else if (res->flags & IORESOURCE_IRQ) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
741
  		p = string(p, pend, "irq ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
742
743
  		specp = &dec_spec;
  	} else if (res->flags & IORESOURCE_DMA) {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
744
  		p = string(p, pend, "dma ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
745
  		specp = &dec_spec;
0f4050c7d   Bjorn Helgaas   resource: add bus...
746
747
748
  	} else if (res->flags & IORESOURCE_BUS) {
  		p = string(p, pend, "bus ", str_spec);
  		specp = &bus_spec;
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
749
  	} else {
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
750
  		p = string(p, pend, "??? ", str_spec);
4da0b66c6   Bjorn Helgaas   vsprintf: move %p...
751
  		specp = &mem_spec;
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
752
  		decode = 0;
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
753
  	}
d19cb803a   Bjorn Helgaas   vsprintf: Add sup...
754
755
756
757
758
759
760
761
762
  	if (decode && res->flags & IORESOURCE_UNSET) {
  		p = string(p, pend, "size ", str_spec);
  		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...
763
  	}
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
764
  	if (decode) {
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
765
766
767
768
  		if (res->flags & IORESOURCE_MEM_64)
  			p = string(p, pend, " 64bit", str_spec);
  		if (res->flags & IORESOURCE_PREFETCH)
  			p = string(p, pend, " pref", str_spec);
9d7cca042   Bjorn Helgaas   resource: add win...
769
770
  		if (res->flags & IORESOURCE_WINDOW)
  			p = string(p, pend, " window", str_spec);
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
771
772
  		if (res->flags & IORESOURCE_DISABLED)
  			p = string(p, pend, " disabled", str_spec);
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
773
774
775
  	} else {
  		p = string(p, pend, " flags ", str_spec);
  		p = number(p, pend, res->flags, flag_spec);
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
776
  	}
332d2e783   Linus Torvalds   Implement %pR to ...
777
  	*p++ = ']';
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
778
  	*p = '\0';
332d2e783   Linus Torvalds   Implement %pR to ...
779

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
780
  	return string(buf, end, sym, spec);
332d2e783   Linus Torvalds   Implement %pR to ...
781
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
782
  static noinline_for_stack
31550a16a   Andy Shevchenko   vsprintf: add sup...
783
784
785
  char *hex_string(char *buf, char *end, u8 *addr, struct printf_spec spec,
  		 const char *fmt)
  {
360603a1b   Steven Rostedt   sprintf: hex_stri...
786
  	int i, len = 1;		/* if we pass '%ph[CDN]', field width remains
31550a16a   Andy Shevchenko   vsprintf: add sup...
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
  				   negative value, fallback to the default */
  	char separator;
  
  	if (spec.field_width == 0)
  		/* nothing to print */
  		return buf;
  
  	if (ZERO_OR_NULL_PTR(addr))
  		/* NULL pointer */
  		return string(buf, end, NULL, spec);
  
  	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...
815
816
817
818
819
820
821
  	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...
822

9c98f2359   Rasmus Villemoes   lib/vsprintf.c: f...
823
824
825
826
827
  		if (separator && i != len - 1) {
  			if (buf < end)
  				*buf = separator;
  			++buf;
  		}
31550a16a   Andy Shevchenko   vsprintf: add sup...
828
829
830
831
832
833
  	}
  
  	return buf;
  }
  
  static noinline_for_stack
dbc760bcc   Tejun Heo   lib/vsprintf: imp...
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
  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;
  
  	/* 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;
  
  	/* reused to print numbers */
  	spec = (struct printf_spec){ .base = 10 };
  
  	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;
  
  		buf = number(buf, end, rbot, spec);
  		if (rbot < rtop) {
  			if (buf < end)
  				*buf = '-';
  			buf++;
  
  			buf = number(buf, end, rtop, spec);
  		}
  
  		rbot = cur;
  	}
  	return buf;
  }
  
  static noinline_for_stack
cf3b429b0   Joe Perches   vsprintf.c: use n...
915
916
  char *mac_address_string(char *buf, char *end, u8 *addr,
  			 struct printf_spec spec, const char *fmt)
dd45c9cf6   Harvey Harrison   printk: add %pM f...
917
  {
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
918
  	char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")];
dd45c9cf6   Harvey Harrison   printk: add %pM f...
919
920
  	char *p = mac_addr;
  	int i;
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
921
  	char separator;
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
922
  	bool reversed = false;
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
923

76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
924
925
  	switch (fmt[1]) {
  	case 'F':
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
926
  		separator = '-';
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
927
928
929
930
931
932
933
  		break;
  
  	case 'R':
  		reversed = true;
  		/* fall through */
  
  	default:
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
934
  		separator = ':';
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
935
  		break;
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
936
  	}
dd45c9cf6   Harvey Harrison   printk: add %pM f...
937
938
  
  	for (i = 0; i < 6; i++) {
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
939
940
941
942
  		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...
943
  		if (fmt[0] == 'M' && i != 5)
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
944
  			*p++ = separator;
dd45c9cf6   Harvey Harrison   printk: add %pM f...
945
946
  	}
  	*p = '\0';
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
947
  	return string(buf, end, mac_addr, spec);
dd45c9cf6   Harvey Harrison   printk: add %pM f...
948
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
949
950
  static noinline_for_stack
  char *ip4_string(char *p, const u8 *addr, const char *fmt)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
951
952
  {
  	int i;
0159f24ee   Joe Perches   lib/vsprintf.c: A...
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
  	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...
978
  	for (i = 0; i < 4; i++) {
7c43d9a30   Rasmus Villemoes   lib/vsprintf.c: e...
979
  		char temp[4] __aligned(2);	/* hold each IP quad in reverse order */
133fd9f5c   Denys Vlasenko   vsprintf: further...
980
  		int digits = put_dec_trunc8(temp, addr[index]) - temp;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
981
982
983
984
985
986
987
988
989
990
991
  		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...
992
  		index += step;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
993
  	}
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
994
  	*p = '\0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
995

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
996
997
  	return p;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
998
999
  static noinline_for_stack
  char *ip6_compressed_string(char *p, const char *addr)
689afa7da   Harvey Harrison   printk: add %p6 f...
1000
  {
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1001
  	int i, j, range;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1002
1003
1004
1005
  	unsigned char zerolength[8];
  	int longest = 1;
  	int colonpos = -1;
  	u16 word;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1006
  	u8 hi, lo;
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1007
  	bool needcolon = false;
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
1008
1009
1010
1011
1012
1013
  	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...
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
  
  	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...
1025
  			if (in6.s6_addr16[j] != 0)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
  				break;
  			zerolength[i]++;
  		}
  	}
  	for (i = 0; i < range; i++) {
  		if (zerolength[i] > longest) {
  			longest = zerolength[i];
  			colonpos = i;
  		}
  	}
29cf519ee   Joe Perches   vsprintf: Update ...
1036
1037
  	if (longest == 1)		/* don't compress a single 0 */
  		colonpos = -1;
689afa7da   Harvey Harrison   printk: add %p6 f...
1038

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
  	/* 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...
1054
  		word = ntohs(in6.s6_addr16[i]);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1055
1056
1057
1058
  		hi = word >> 8;
  		lo = word & 0xff;
  		if (hi) {
  			if (hi > 0x0f)
55036ba76   Andy Shevchenko   lib: rename pack_...
1059
  				p = hex_byte_pack(p, hi);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1060
1061
  			else
  				*p++ = hex_asc_lo(hi);
55036ba76   Andy Shevchenko   lib: rename pack_...
1062
  			p = hex_byte_pack(p, lo);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1063
  		}
b5ff992b0   André Goddard Rosa   vsprintf: reduce ...
1064
  		else if (lo > 0x0f)
55036ba76   Andy Shevchenko   lib: rename pack_...
1065
  			p = hex_byte_pack(p, lo);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1066
1067
1068
1069
1070
1071
1072
1073
  		else
  			*p++ = hex_asc_lo(lo);
  		needcolon = true;
  	}
  
  	if (useIPv4) {
  		if (needcolon)
  			*p++ = ':';
0159f24ee   Joe Perches   lib/vsprintf.c: A...
1074
  		p = ip4_string(p, &in6.s6_addr[12], "I4");
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1075
  	}
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1076
  	*p = '\0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1077

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1078
1079
  	return p;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
1080
1081
  static noinline_for_stack
  char *ip6_string(char *p, const char *addr, const char *fmt)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1082
1083
  {
  	int i;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1084

689afa7da   Harvey Harrison   printk: add %p6 f...
1085
  	for (i = 0; i < 8; i++) {
55036ba76   Andy Shevchenko   lib: rename pack_...
1086
1087
  		p = hex_byte_pack(p, *addr++);
  		p = hex_byte_pack(p, *addr++);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1088
  		if (fmt[0] == 'I' && i != 7)
689afa7da   Harvey Harrison   printk: add %p6 f...
1089
1090
1091
  			*p++ = ':';
  	}
  	*p = '\0';
7b9186f5e   André Goddard Rosa   vsprintf: give it...
1092

8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1093
1094
  	return p;
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
1095
1096
1097
  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...
1098
1099
1100
1101
  {
  	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...
1102
  		ip6_compressed_string(ip6_addr, addr);
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1103
  	else
eb78cd26b   Joe Perches   lib/vsprintf.c: A...
1104
  		ip6_string(ip6_addr, addr, fmt);
689afa7da   Harvey Harrison   printk: add %p6 f...
1105

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1106
  	return string(buf, end, ip6_addr, spec);
689afa7da   Harvey Harrison   printk: add %p6 f...
1107
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
1108
1109
1110
  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, ...
1111
  {
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1112
  	char ip4_addr[sizeof("255.255.255.255")];
4aa996066   Harvey Harrison   printk: add %I4, ...
1113

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1116
  	return string(buf, end, ip4_addr, spec);
4aa996066   Harvey Harrison   printk: add %I4, ...
1117
  }
cf3b429b0   Joe Perches   vsprintf.c: use n...
1118
  static noinline_for_stack
106796430   Daniel Borkmann   lib: vsprintf: ad...
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
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
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
  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';
  
  	return string(buf, end, ip6_addr, spec);
  }
  
  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';
  
  	return string(buf, end, ip4_addr, spec);
  }
  
  static noinline_for_stack
71dca95d5   Andy Shevchenko   lib/vsprintf: add...
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
  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 */
  
  	if (ZERO_OR_NULL_PTR(addr))
  		return string(buf, end, NULL, spec);	/* NULL pointer */
  
  
  	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...
1264
1265
1266
1267
1268
1269
  	/*
  	 * 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...
1270
1271
1272
1273
1274
  
  	return buf;
  }
  
  static noinline_for_stack
cf3b429b0   Joe Perches   vsprintf.c: use n...
1275
1276
  char *uuid_string(char *buf, char *end, const u8 *addr,
  		  struct printf_spec spec, const char *fmt)
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1277
  {
2b1b0d667   Andy Shevchenko   lib/uuid.c: intro...
1278
  	char uuid[UUID_STRING_LEN + 1];
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1279
1280
  	char *p = uuid;
  	int i;
2b1b0d667   Andy Shevchenko   lib/uuid.c: intro...
1281
  	const u8 *index = uuid_be_index;
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1282
1283
1284
1285
1286
1287
  	bool uc = false;
  
  	switch (*(++fmt)) {
  	case 'L':
  		uc = true;		/* fall-through */
  	case 'l':
2b1b0d667   Andy Shevchenko   lib/uuid.c: intro...
1288
  		index = uuid_le_index;
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1289
1290
1291
1292
1293
1294
1295
  		break;
  	case 'B':
  		uc = true;
  		break;
  	}
  
  	for (i = 0; i < 16; i++) {
aa4ea1c3b   Andy Shevchenko   lib/vsprintf: sim...
1296
1297
1298
1299
  		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...
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
  		switch (i) {
  		case 3:
  		case 5:
  		case 7:
  		case 9:
  			*p++ = '-';
  			break;
  		}
  	}
  
  	*p = 0;
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1311
1312
  	return string(buf, end, uuid, spec);
  }
5b17aecfc   Andy Shevchenko   lib/vsprintf: fac...
1313
1314
  static noinline_for_stack
  char *netdev_bits(char *buf, char *end, const void *addr, const char *fmt)
c8f44affb   Michał Mirosław   net: introduce an...
1315
  {
5b17aecfc   Andy Shevchenko   lib/vsprintf: fac...
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
  	unsigned long long num;
  	int size;
  
  	switch (fmt[1]) {
  	case 'F':
  		num = *(const netdev_features_t *)addr;
  		size = sizeof(netdev_features_t);
  		break;
  	default:
  		num = (unsigned long)addr;
  		size = sizeof(unsigned long);
  		break;
  	}
c8f44affb   Michał Mirosław   net: introduce an...
1329

3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
1330
  	return special_hex_number(buf, end, num, size);
c8f44affb   Michał Mirosław   net: introduce an...
1331
  }
aaf07621b   Joe Perches   vsprintf: add %pa...
1332
  static noinline_for_stack
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
1333
  char *address_val(char *buf, char *end, const void *addr, const char *fmt)
aaf07621b   Joe Perches   vsprintf: add %pa...
1334
1335
  {
  	unsigned long long num;
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
1336
  	int size;
aaf07621b   Joe Perches   vsprintf: add %pa...
1337
1338
1339
1340
  
  	switch (fmt[1]) {
  	case 'd':
  		num = *(const dma_addr_t *)addr;
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
1341
  		size = sizeof(dma_addr_t);
aaf07621b   Joe Perches   vsprintf: add %pa...
1342
1343
1344
1345
  		break;
  	case 'p':
  	default:
  		num = *(const phys_addr_t *)addr;
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
1346
  		size = sizeof(phys_addr_t);
aaf07621b   Joe Perches   vsprintf: add %pa...
1347
1348
  		break;
  	}
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
1349
  	return special_hex_number(buf, end, num, size);
aaf07621b   Joe Perches   vsprintf: add %pa...
1350
  }
900cca294   Geert Uytterhoeven   lib/vsprintf: add...
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
  static noinline_for_stack
  char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec,
  	    const char *fmt)
  {
  	if (!IS_ENABLED(CONFIG_HAVE_CLK) || !clk)
  		return string(buf, end, NULL, spec);
  
  	switch (fmt[1]) {
  	case 'r':
  		return number(buf, end, clk_get_rate(clk), spec);
  
  	case 'n':
  	default:
  #ifdef CONFIG_COMMON_CLK
  		return string(buf, end, __clk_get_name(clk), spec);
  #else
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
1367
  		return special_hex_number(buf, end, (unsigned long)clk, sizeof(unsigned long));
900cca294   Geert Uytterhoeven   lib/vsprintf: add...
1368
1369
1370
  #endif
  	}
  }
edf14cdbf   Vlastimil Babka   mm, printk: intro...
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
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
  static
  char *format_flags(char *buf, char *end, unsigned long flags,
  					const struct trace_print_flags *names)
  {
  	unsigned long mask;
  	const struct printf_spec strspec = {
  		.field_width = -1,
  		.precision = -1,
  	};
  	const struct printf_spec numspec = {
  		.flags = SPECIAL|SMALL,
  		.field_width = -1,
  		.precision = -1,
  		.base = 16,
  	};
  
  	for ( ; flags && names->name; names++) {
  		mask = names->mask;
  		if ((flags & mask) != mask)
  			continue;
  
  		buf = string(buf, end, names->name, strspec);
  
  		flags &= ~mask;
  		if (flags) {
  			if (buf < end)
  				*buf = '|';
  			buf++;
  		}
  	}
  
  	if (flags)
  		buf = number(buf, end, flags, numspec);
  
  	return buf;
  }
  
  static noinline_for_stack
  char *flags_string(char *buf, char *end, void *flags_ptr, const char *fmt)
  {
  	unsigned long flags;
  	const struct trace_print_flags *names;
  
  	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':
  		flags = *(gfp_t *)flags_ptr;
  		names = gfpflag_names;
  		break;
  	default:
  		WARN_ONCE(1, "Unsupported flags modifier: %c
  ", fmt[1]);
  		return buf;
  	}
  
  	return format_flags(buf, end, flags, names);
  }
411f05f12   Ingo Molnar   vsprintf: Turn kp...
1437
  int kptr_restrict __read_mostly;
455cd5ab3   Dan Rosenberg   kptr_restrict for...
1438

4d8a743cd   Linus Torvalds   vsprintf: add inf...
1439
1440
1441
1442
1443
  /*
   * 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.
   *
332d2e783   Linus Torvalds   Implement %pR to ...
1444
1445
   * Right now we handle:
   *
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
1446
1447
   * - 'F' For symbolic function descriptor pointers with offset
   * - 'f' For simple symbolic function names without offset
0efb4d207   Steven Rostedt   vsnprintf: remove...
1448
1449
   * - 'S' For symbolic direct pointers with offset
   * - 's' For symbolic direct pointers without offset
b0d33c2bd   Joe Perches   vsprintf: Add ext...
1450
   * - '[FfSs]R' as above with __builtin_extract_return_addr() translation
0f77a8d37   Namhyung Kim   vsprintf: Introdu...
1451
   * - 'B' For backtraced symbolic direct pointers with offset
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
1452
1453
   * - '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...
1454
1455
1456
1457
   * - '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...
1458
1459
   * - '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...
1460
   * - 'm' For a 6-byte MAC address, it prints the hex address without colons
bc7259a2c   Joe Perches   lib/vsprintf.c: A...
1461
   * - 'MF' For a 6-byte MAC FDDI address, it prints the address
c8e000604   Joe Perches   lib: Kill bit-rev...
1462
   *       with a dash-separated hex notation
7c59154e7   Andy Shevchenko   lib/vsprintf: upd...
1463
   * - '[mM]R' For a 6-byte MAC address, Reverse order (Bluetooth)
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1464
1465
1466
   * - '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...
1467
1468
1469
   *       [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...
1470
1471
1472
   * - '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...
1473
1474
1475
1476
1477
   *       [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
29cf519ee   Joe Perches   vsprintf: Update ...
1478
   *       http://tools.ietf.org/html/rfc5952
71dca95d5   Andy Shevchenko   lib/vsprintf: add...
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
   * - '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...
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
   * - '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...
1501
1502
1503
1504
1505
   * - '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...
1506
   * - 'K' For a kernel pointer that should be hidden from unprivileged users
c8f44affb   Michał Mirosław   net: introduce an...
1507
   * - 'NF' For a netdev_features_t
31550a16a   Andy Shevchenko   vsprintf: add sup...
1508
1509
1510
1511
1512
1513
1514
   * - '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...
1515
1516
   * - '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...
1517
1518
   * - '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...
1519
   * - 'g' For block_device name (gendisk + partition number)
900cca294   Geert Uytterhoeven   lib/vsprintf: add...
1520
1521
1522
1523
1524
   * - '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
   * - 'Cr' For a clock, it prints the current rate of the clock
edf14cdbf   Vlastimil Babka   mm, printk: intro...
1525
1526
1527
1528
1529
   * - '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
5e4ee7b13   Martin Kletzander   printk: synchroni...
1530
1531
   *
   * ** Please update also Documentation/printk-formats.txt when making changes **
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1532
   *
332d2e783   Linus Torvalds   Implement %pR to ...
1533
1534
1535
   * Note: The difference between 'S' and 'F' is that on ia64 and ppc64
   * function pointers are really function descriptors, which contain a
   * pointer to the real address.
4d8a743cd   Linus Torvalds   vsprintf: add inf...
1536
   */
cf3b429b0   Joe Perches   vsprintf.c: use n...
1537
1538
1539
  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...
1540
  {
80c9eb46f   Rasmus Villemoes   lib/vsprintf.c: r...
1541
  	const int default_width = 2 * sizeof(void *);
725fe002d   Grant Likely   vsprintf: correct...
1542

9f36e2c44   Kees Cook   printk: use %pK f...
1543
  	if (!ptr && *fmt != 'K') {
5e0579812   Joe Perches   vsprintf.c: use d...
1544
1545
1546
1547
1548
  		/*
  		 * Print (null) with the same width as a pointer so it makes
  		 * tabular output look nice.
  		 */
  		if (spec.field_width == -1)
725fe002d   Grant Likely   vsprintf: correct...
1549
  			spec.field_width = default_width;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1550
  		return string(buf, end, "(null)", spec);
5e0579812   Joe Perches   vsprintf.c: use d...
1551
  	}
d97106ab5   Linus Torvalds   Make %p print '(n...
1552

0fe1ef24f   Linus Torvalds   vsprintf: add sup...
1553
1554
  	switch (*fmt) {
  	case 'F':
0c8b946e3   Frederic Weisbecker   vsprintf: introdu...
1555
  	case 'f':
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
1556
1557
1558
  		ptr = dereference_function_descriptor(ptr);
  		/* Fallthrough */
  	case 'S':
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1559
  	case 's':
0f77a8d37   Namhyung Kim   vsprintf: Introdu...
1560
  	case 'B':
b0d33c2bd   Joe Perches   vsprintf: Add ext...
1561
  		return symbol_string(buf, end, ptr, spec, fmt);
332d2e783   Linus Torvalds   Implement %pR to ...
1562
  	case 'R':
c7dabef8a   Bjorn Helgaas   vsprintf: use %pR...
1563
  	case 'r':
fd95541e2   Bjorn Helgaas   vsprintf: add %pR...
1564
  		return resource_string(buf, end, ptr, spec, fmt);
31550a16a   Andy Shevchenko   vsprintf: add sup...
1565
1566
  	case 'h':
  		return hex_string(buf, end, ptr, spec, fmt);
dbc760bcc   Tejun Heo   lib/vsprintf: imp...
1567
1568
1569
1570
1571
1572
1573
  	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...
1574
1575
  	case 'M':			/* Colon separated: 00:01:02:03:04:05 */
  	case 'm':			/* Contiguous: 000102030405 */
76597ff98   Andrei Emeltchenko   vsprintf: add %pM...
1576
1577
  					/* [mM]F (FDDI) */
  					/* [mM]R (Reverse order; Bluetooth) */
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
  		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
  					 */
  		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);
106796430   Daniel Borkmann   lib: vsprintf: ad...
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
  		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:
  				return string(buf, end, "(invalid address)", spec);
  			}}
8a27f7c90   Joe Perches   lib/vsprintf.c: A...
1608
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1609
  		break;
71dca95d5   Andy Shevchenko   lib/vsprintf: add...
1610
1611
  	case 'E':
  		return escaped_string(buf, end, ptr, spec, fmt);
9ac6e44ee   Joe Perches   lib/vsprintf.c: a...
1612
1613
  	case 'U':
  		return uuid_string(buf, end, ptr, spec, fmt);
7db6f5fb6   Joe Perches   vsprintf: Recursi...
1614
  	case 'V':
5756b76e4   Jan Beulich   vsprintf: make %p...
1615
1616
1617
1618
1619
1620
1621
1622
1623
  		{
  			va_list va;
  
  			va_copy(va, *((struct va_format *)ptr)->va);
  			buf += vsnprintf(buf, end > buf ? end - buf : 0,
  					 ((struct va_format *)ptr)->fmt, va);
  			va_end(va);
  			return buf;
  		}
455cd5ab3   Dan Rosenberg   kptr_restrict for...
1624
  	case 'K':
312b4e226   Ryan Mallon   vsprintf: check r...
1625
1626
1627
1628
1629
  		switch (kptr_restrict) {
  		case 0:
  			/* Always print %pK values */
  			break;
  		case 1: {
7eb391299   Jason A. Donenfeld   vsprintf: kptr_re...
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
  			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 = default_width;
  				return string(buf, end, "pK-error", spec);
  			}
312b4e226   Ryan Mallon   vsprintf: check r...
1641
1642
1643
1644
1645
1646
1647
1648
1649
  			/*
  			 * 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.
  			 */
7eb391299   Jason A. Donenfeld   vsprintf: kptr_re...
1650
  			cred = current_cred();
312b4e226   Ryan Mallon   vsprintf: check r...
1651
1652
1653
1654
1655
1656
1657
1658
1659
  			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 */
26297607e   Joe Perches   vsprintf: neaten ...
1660
  			ptr = NULL;
312b4e226   Ryan Mallon   vsprintf: check r...
1661
1662
  			break;
  		}
26297607e   Joe Perches   vsprintf: neaten ...
1663
  		break;
312b4e226   Ryan Mallon   vsprintf: check r...
1664

c8f44affb   Michał Mirosław   net: introduce an...
1665
  	case 'N':
5b17aecfc   Andy Shevchenko   lib/vsprintf: fac...
1666
  		return netdev_bits(buf, end, ptr, fmt);
7d7992108   Stepan Moskovchenko   lib/vsprintf.c: a...
1667
  	case 'a':
3cab1e711   Andy Shevchenko   lib/vsprintf: ref...
1668
  		return address_val(buf, end, ptr, fmt);
4b6ccca70   Al Viro   add formats for d...
1669
1670
  	case 'd':
  		return dentry_name(buf, end, ptr, spec, fmt);
900cca294   Geert Uytterhoeven   lib/vsprintf: add...
1671
1672
  	case 'C':
  		return clock(buf, end, ptr, spec, fmt);
4b6ccca70   Al Viro   add formats for d...
1673
1674
1675
1676
  	case 'D':
  		return dentry_name(buf, end,
  				   ((const struct file *)ptr)->f_path.dentry,
  				   spec, fmt);
1031bc589   Dmitry Monakhov   lib/vsprintf: add...
1677
1678
1679
1680
  #ifdef CONFIG_BLOCK
  	case 'g':
  		return bdev_name(buf, end, ptr, spec, fmt);
  #endif
edf14cdbf   Vlastimil Babka   mm, printk: intro...
1681
1682
  	case 'G':
  		return flags_string(buf, end, ptr, fmt);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1683
1684
1685
  	}
  	spec.flags |= SMALL;
  	if (spec.field_width == -1) {
725fe002d   Grant Likely   vsprintf: correct...
1686
  		spec.field_width = default_width;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
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
  		spec.flags |= ZEROPAD;
  	}
  	spec.base = 16;
  
  	return number(buf, end, (unsigned long) ptr, spec);
  }
  
  /*
   * 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
   * '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...
1714
1715
  static noinline_for_stack
  int format_decode(const char *fmt, struct printf_spec *spec)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1716
1717
  {
  	const char *start = fmt;
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
1718
  	char qualifier;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1719
1720
  
  	/* we finished early by reading the field width */
ed681a91a   Vegard Nossum   vsprintf: unify t...
1721
  	if (spec->type == FORMAT_TYPE_WIDTH) {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1722
1723
1724
1725
1726
1727
1728
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
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
  		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...
1779
  		spec->type = FORMAT_TYPE_WIDTH;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
  		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...
1794
  			spec->type = FORMAT_TYPE_PRECISION;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1795
1796
1797
1798
1799
1800
  			return ++fmt - start;
  		}
  	}
  
  qualifier:
  	/* get the conversion qualifier */
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
1801
  	qualifier = 0;
75fb8f269   Andy Shevchenko   lib: make _tolowe...
1802
1803
  	if (*fmt == 'h' || _tolower(*fmt) == 'l' ||
  	    _tolower(*fmt) == 'z' || *fmt == 't') {
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
1804
1805
1806
1807
  		qualifier = *fmt++;
  		if (unlikely(qualifier == *fmt)) {
  			if (qualifier == 'l') {
  				qualifier = 'L';
a4e94ef0d   Zhaolei   printk: add suppo...
1808
  				++fmt;
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
1809
1810
  			} else if (qualifier == 'h') {
  				qualifier = 'H';
a4e94ef0d   Zhaolei   printk: add suppo...
1811
1812
  				++fmt;
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
  		}
  	}
  
  	/* 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...
1829
  		return ++fmt - start;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1830

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
  	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;
  
  	case 'X':
  		spec->base = 16;
  		break;
  
  	case 'd':
  	case 'i':
39e874f8a   Frederic Weisbecker   vsprintf: fix bug...
1849
  		spec->flags |= SIGN;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1850
  	case 'u':
4aa996066   Harvey Harrison   printk: add %I4, ...
1851
  		break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1852

708d96fd0   Ryan Mallon   vsprintf: remove ...
1853
1854
  	case 'n':
  		/*
b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
1855
1856
1857
  		 * Since %n poses a greater security risk than
  		 * utility, treat it as any other invalid or
  		 * unsupported format specifier.
708d96fd0   Ryan Mallon   vsprintf: remove ...
1858
  		 */
708d96fd0   Ryan Mallon   vsprintf: remove ...
1859
  		/* Fall-through */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1860
  	default:
b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
1861
1862
  		WARN_ONCE(1, "Please remove unsupported %%%c in format string
  ", *fmt);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1863
1864
  		spec->type = FORMAT_TYPE_INVALID;
  		return fmt - start;
0fe1ef24f   Linus Torvalds   vsprintf: add sup...
1865
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1866

d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
1867
  	if (qualifier == 'L')
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1868
  		spec->type = FORMAT_TYPE_LONG_LONG;
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
1869
  	else if (qualifier == 'l') {
51be17dff   Rasmus Villemoes   lib/vsprintf.c: e...
1870
1871
  		BUILD_BUG_ON(FORMAT_TYPE_ULONG + SIGN != FORMAT_TYPE_LONG);
  		spec->type = FORMAT_TYPE_ULONG + (spec->flags & SIGN);
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
1872
  	} else if (_tolower(qualifier) == 'z') {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1873
  		spec->type = FORMAT_TYPE_SIZE_T;
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
1874
  	} else if (qualifier == 't') {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1875
  		spec->type = FORMAT_TYPE_PTRDIFF;
d04841931   Rasmus Villemoes   lib/vsprintf.c: e...
1876
  	} else if (qualifier == 'H') {
51be17dff   Rasmus Villemoes   lib/vsprintf.c: e...
1877
1878
  		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...
1879
  	} else if (qualifier == 'h') {
51be17dff   Rasmus Villemoes   lib/vsprintf.c: e...
1880
1881
  		BUILD_BUG_ON(FORMAT_TYPE_USHORT + SIGN != FORMAT_TYPE_SHORT);
  		spec->type = FORMAT_TYPE_USHORT + (spec->flags & SIGN);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1882
  	} else {
51be17dff   Rasmus Villemoes   lib/vsprintf.c: e...
1883
1884
  		BUILD_BUG_ON(FORMAT_TYPE_UINT + SIGN != FORMAT_TYPE_INT);
  		spec->type = FORMAT_TYPE_UINT + (spec->flags & SIGN);
78a8bf69b   Linus Torvalds   vsprintf: split o...
1885
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1886
1887
  
  	return ++fmt - start;
78a8bf69b   Linus Torvalds   vsprintf: split o...
1888
  }
4d72ba014   Rasmus Villemoes   lib/vsprintf.c: w...
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
  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
1906
1907
1908
1909
1910
1911
1912
  /**
   * 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...
1913
1914
1915
1916
   * This function generally follows C99 vsnprintf, but has some
   * extensions and a few limitations:
   *
   * %n is unsupported
5e4ee7b13   Martin Kletzander   printk: synchroni...
1917
1918
1919
1920
   * %p* is handled by pointer()
   *
   * See pointer() or Documentation/printk-formats.txt for more
   * extensive description.
20036fdca   Andi Kleen   Add kerneldoc doc...
1921
   *
5e4ee7b13   Martin Kletzander   printk: synchroni...
1922
   * ** Please update the documentation in both places when making changes **
80f548e04   Andrew Morton   lib/vsprintf.c: r...
1923
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1924
1925
1926
1927
   * 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 ...
1928
   * (not including the trailing '\0'), use vscnprintf(). If the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1929
1930
1931
   * return is greater than or equal to @size, the resulting
   * string is truncated.
   *
ba1835eb3   Uwe Kleine-König   vsprintf: make co...
1932
   * If you're not already dealing with a va_list consider using snprintf().
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1933
1934
1935
   */
  int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1936
  	unsigned long long num;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1937
  	char *str, *end;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1938
  	struct printf_spec spec = {0};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1939

f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1940
1941
  	/* Reject out-of-range values early.  Large positive sizes are
  	   used for unknown buffer sizes. */
2aa2f9e21   Rasmus Villemoes   lib/vsprintf.c: i...
1942
  	if (WARN_ON_ONCE(size > INT_MAX))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1943
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1944
1945
  
  	str = buf;
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1946
  	end = buf + size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1947

f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1948
1949
1950
1951
  	/* Make sure end is always >= buf */
  	if (end < buf) {
  		end = ((void *)-1);
  		size = end - buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1952
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1953
1954
  	while (*fmt) {
  		const char *old_fmt = fmt;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1955
  		int read = format_decode(fmt, &spec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1956

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1959
1960
1961
1962
1963
1964
1965
  		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
1966
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1967
1968
  			str += read;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1969
  		}
ed681a91a   Vegard Nossum   vsprintf: unify t...
1970
  		case FORMAT_TYPE_WIDTH:
4d72ba014   Rasmus Villemoes   lib/vsprintf.c: w...
1971
  			set_field_width(&spec, va_arg(args, int));
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1972
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1973

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

d4be151b2   André Goddard Rosa   vsprintf: move lo...
1978
1979
  		case FORMAT_TYPE_CHAR: {
  			char c;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1980
1981
  			if (!(spec.flags & LEFT)) {
  				while (--spec.field_width > 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1982
  					if (str < end)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1983
1984
  						*str = ' ';
  					++str;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1985

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1986
1987
1988
1989
1990
1991
1992
  				}
  			}
  			c = (unsigned char) va_arg(args, int);
  			if (str < end)
  				*str = c;
  			++str;
  			while (--spec.field_width > 0) {
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
1993
  				if (str < end)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1994
  					*str = ' ';
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1995
  				++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
1996
1997
  			}
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
1998
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1999

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2004
  		case FORMAT_TYPE_PTR:
ffbfed03b   Rasmus Villemoes   lib/vsprintf.c: c...
2005
  			str = pointer(fmt, str, end, va_arg(args, void *),
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2006
2007
2008
2009
  				      spec);
  			while (isalnum(*fmt))
  				fmt++;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2010

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2011
2012
2013
2014
2015
  		case FORMAT_TYPE_PERCENT_CHAR:
  			if (str < end)
  				*str = '%';
  			++str;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2016

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2017
  		case FORMAT_TYPE_INVALID:
b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
2018
2019
2020
2021
2022
2023
2024
2025
2026
  			/*
  			 * 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...
2027

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
  		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...
2040
2041
2042
2043
  				if (spec.flags & SIGN)
  					num = va_arg(args, ssize_t);
  				else
  					num = va_arg(args, size_t);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2044
2045
2046
2047
  				break;
  			case FORMAT_TYPE_PTRDIFF:
  				num = va_arg(args, ptrdiff_t);
  				break;
a4e94ef0d   Zhaolei   printk: add suppo...
2048
2049
2050
2051
2052
2053
  			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...
2054
2055
2056
2057
2058
2059
  			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...
2060
2061
  			case FORMAT_TYPE_INT:
  				num = (int) va_arg(args, int);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2062
2063
2064
2065
2066
2067
  				break;
  			default:
  				num = va_arg(args, unsigned int);
  			}
  
  			str = number(str, end, num, spec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2068
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2069
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2070

b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
2071
  out:
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
2072
2073
2074
2075
  	if (size > 0) {
  		if (str < end)
  			*str = '\0';
  		else
0a6047eef   Linus Torvalds   Fix vsnprintf off...
2076
  			end[-1] = '\0';
f796937a0   Jeremy Fitzhardinge   [PATCH] Fix bound...
2077
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2078

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2082
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
  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...
2093
   * the @buf not including the trailing '\0'. If @size is == 0 the function
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2094
2095
   * returns 0.
   *
ba1835eb3   Uwe Kleine-König   vsprintf: make co...
2096
   * If you're not already dealing with a va_list consider using scnprintf().
20036fdca   Andi Kleen   Add kerneldoc doc...
2097
2098
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2099
2100
2101
2102
   */
  int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
  {
  	int i;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2103
  	i = vsnprintf(buf, size, fmt, args);
b921c69fb   Anton Arapov   lib/vsprintf.c: f...
2104
2105
2106
2107
2108
  	if (likely(i < size))
  		return i;
  	if (size != 0)
  		return size - 1;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2109
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
  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...
2123
2124
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2125
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2126
  int snprintf(char *buf, size_t size, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2127
2128
2129
2130
2131
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2132
  	i = vsnprintf(buf, size, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2133
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2134

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2135
2136
  	return i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
  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...
2147
   * the trailing '\0'. If @size is == 0 the function returns 0.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2148
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2149
  int scnprintf(char *buf, size_t size, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2150
2151
2152
2153
2154
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
b921c69fb   Anton Arapov   lib/vsprintf.c: f...
2155
  	i = vscnprintf(buf, size, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2156
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2157

b921c69fb   Anton Arapov   lib/vsprintf.c: f...
2158
  	return i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
  }
  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 ...
2169
   * into @buf. Use vsnprintf() or vscnprintf() in order to avoid
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2170
2171
   * buffer overflows.
   *
ba1835eb3   Uwe Kleine-König   vsprintf: make co...
2172
   * If you're not already dealing with a va_list consider using sprintf().
20036fdca   Andi Kleen   Add kerneldoc doc...
2173
2174
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2175
2176
2177
2178
2179
   */
  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
2180
2181
2182
2183
2184
2185
2186
2187
2188
  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 ...
2189
   * into @buf. Use snprintf() or scnprintf() in order to avoid
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2190
   * buffer overflows.
20036fdca   Andi Kleen   Add kerneldoc doc...
2191
2192
   *
   * See the vsnprintf() documentation for format string extensions over C99.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2193
   */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2194
  int sprintf(char *buf, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2195
2196
2197
2198
2199
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2200
  	i = vsnprintf(buf, INT_MAX, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2201
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2202

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2203
2204
  	return i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2205
  EXPORT_SYMBOL(sprintf);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
  #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...
2221
   * is skipped.
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
   *
   * 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...
2232
  	struct printf_spec spec = {0};
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2233
  	char *str, *end;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
  
  	str = (char *)bin_buf;
  	end = (char *)(bin_buf + size);
  
  #define save_arg(type)							\
  do {									\
  	if (sizeof(type) == 8) {					\
  		unsigned long long value;				\
  		str = PTR_ALIGN(str, sizeof(u32));			\
  		value = va_arg(args, unsigned long long);		\
  		if (str + sizeof(type) <= end) {			\
  			*(u32 *)str = *(u32 *)&value;			\
  			*(u32 *)(str + 4) = *((u32 *)&value + 1);	\
  		}							\
  	} else {							\
  		unsigned long value;					\
  		str = PTR_ALIGN(str, sizeof(type));			\
  		value = va_arg(args, int);				\
  		if (str + sizeof(type) <= end)				\
  			*(typeof(type) *)str = (type)value;		\
  	}								\
  	str += sizeof(type);						\
  } while (0)
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2257
  	while (*fmt) {
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2258
  		int read = format_decode(fmt, &spec);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2259

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2262
2263
  		switch (spec.type) {
  		case FORMAT_TYPE_NONE:
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2264
  		case FORMAT_TYPE_PERCENT_CHAR:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2265
  			break;
b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
2266
2267
  		case FORMAT_TYPE_INVALID:
  			goto out;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2268

ed681a91a   Vegard Nossum   vsprintf: unify t...
2269
  		case FORMAT_TYPE_WIDTH:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2270
2271
2272
2273
2274
  		case FORMAT_TYPE_PRECISION:
  			save_arg(int);
  			break;
  
  		case FORMAT_TYPE_CHAR:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2275
  			save_arg(char);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2276
2277
2278
  			break;
  
  		case FORMAT_TYPE_STR: {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2279
2280
  			const char *save_str = va_arg(args, char *);
  			size_t len;
6c3566341   André Goddard Rosa   vsprintf: pre-cal...
2281

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2282
2283
  			if ((unsigned long)save_str > (unsigned long)-PAGE_SIZE
  					|| (unsigned long)save_str < PAGE_SIZE)
0f4f81dce   André Goddard Rosa   vsprintf: factori...
2284
  				save_str = "(null)";
6c3566341   André Goddard Rosa   vsprintf: pre-cal...
2285
2286
2287
2288
  			len = strlen(save_str) + 1;
  			if (str + len < end)
  				memcpy(str, save_str, len);
  			str += len;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2289
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2290
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2291
2292
  
  		case FORMAT_TYPE_PTR:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2293
2294
  			save_arg(void *);
  			/* skip all alphanumeric pointer suffixes */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2295
  			while (isalnum(*fmt))
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2296
  				fmt++;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2297
  			break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2298
2299
2300
2301
  		default:
  			switch (spec.type) {
  
  			case FORMAT_TYPE_LONG_LONG:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2302
  				save_arg(long long);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2303
2304
2305
  				break;
  			case FORMAT_TYPE_ULONG:
  			case FORMAT_TYPE_LONG:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2306
  				save_arg(unsigned long);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2307
2308
  				break;
  			case FORMAT_TYPE_SIZE_T:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2309
  				save_arg(size_t);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2310
2311
  				break;
  			case FORMAT_TYPE_PTRDIFF:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2312
  				save_arg(ptrdiff_t);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2313
  				break;
a4e94ef0d   Zhaolei   printk: add suppo...
2314
2315
2316
2317
  			case FORMAT_TYPE_UBYTE:
  			case FORMAT_TYPE_BYTE:
  				save_arg(char);
  				break;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2318
2319
  			case FORMAT_TYPE_USHORT:
  			case FORMAT_TYPE_SHORT:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2320
  				save_arg(short);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2321
2322
  				break;
  			default:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2323
  				save_arg(int);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2324
  			}
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2325
2326
  		}
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2327

b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
2328
  out:
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2329
  	return (u32 *)(PTR_ALIGN(str, sizeof(u32))) - bin_buf;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2330
  #undef save_arg
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
  }
  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...
2346
   *  see vsnprintf comment for details.
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
   *
   * 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...
2358
  	struct printf_spec spec = {0};
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2359
2360
  	char *str, *end;
  	const char *args = (const char *)bin_buf;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2361

762abb515   Rasmus Villemoes   lib/vsprintf.c: a...
2362
  	if (WARN_ON_ONCE(size > INT_MAX))
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2363
  		return 0;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
  
  	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...
2388
  	while (*fmt) {
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2389
  		const char *old_fmt = fmt;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2390
  		int read = format_decode(fmt, &spec);
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2391

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

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2394
2395
2396
2397
2398
2399
2400
  		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...
2401
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2402
2403
  			str += read;
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2404
  		}
ed681a91a   Vegard Nossum   vsprintf: unify t...
2405
  		case FORMAT_TYPE_WIDTH:
4d72ba014   Rasmus Villemoes   lib/vsprintf.c: w...
2406
  			set_field_width(&spec, get_arg(int));
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2407
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2408

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

d4be151b2   André Goddard Rosa   vsprintf: move lo...
2413
2414
  		case FORMAT_TYPE_CHAR: {
  			char c;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2415
2416
  			if (!(spec.flags & LEFT)) {
  				while (--spec.field_width > 0) {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2417
2418
2419
2420
2421
2422
2423
2424
2425
  					if (str < end)
  						*str = ' ';
  					++str;
  				}
  			}
  			c = (unsigned char) get_arg(char);
  			if (str < end)
  				*str = c;
  			++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2426
  			while (--spec.field_width > 0) {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2427
2428
2429
2430
  				if (str < end)
  					*str = ' ';
  				++str;
  			}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2431
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2432
  		}
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2433

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2434
  		case FORMAT_TYPE_STR: {
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2435
  			const char *str_arg = args;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2436
  			args += strlen(str_arg) + 1;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2437
2438
  			str = string(str, end, (char *)str_arg, spec);
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2439
  		}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2440
  		case FORMAT_TYPE_PTR:
ffbfed03b   Rasmus Villemoes   lib/vsprintf.c: c...
2441
  			str = pointer(fmt, str, end, get_arg(void *), spec);
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2442
  			while (isalnum(*fmt))
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2443
  				fmt++;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2444
  			break;
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2445

fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2446
  		case FORMAT_TYPE_PERCENT_CHAR:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2447
2448
2449
  			if (str < end)
  				*str = '%';
  			++str;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2450
  			break;
b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
2451
2452
  		case FORMAT_TYPE_INVALID:
  			goto out;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2453
2454
  		default: {
  			unsigned long long num;
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2455
2456
2457
2458
2459
2460
  			switch (spec.type) {
  
  			case FORMAT_TYPE_LONG_LONG:
  				num = get_arg(long long);
  				break;
  			case FORMAT_TYPE_ULONG:
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2461
2462
2463
2464
2465
2466
2467
2468
2469
  			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...
2470
2471
2472
2473
2474
2475
  			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...
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
  			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...
2490
2491
2492
  		} /* default: */
  		} /* switch(spec.type) */
  	} /* while(*fmt) */
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2493

b006f19b0   Rasmus Villemoes   lib/vsprintf.c: h...
2494
  out:
4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2495
2496
2497
2498
2499
2500
  	if (size > 0) {
  		if (str < end)
  			*str = '\0';
  		else
  			end[-1] = '\0';
  	}
fef20d9c1   Frederic Weisbecker   vsprintf: unify t...
2501

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
  #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...
2527

4370aa4aa   Lai Jiangshan   vsprintf: add bin...
2528
2529
2530
2531
2532
  	return ret;
  }
  EXPORT_SYMBOL_GPL(bprintf);
  
  #endif /* CONFIG_BINARY_PRINTF */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2533
2534
2535
2536
2537
2538
  /**
   * 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...
2539
  int vsscanf(const char *buf, const char *fmt, va_list args)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2540
2541
2542
2543
2544
  {
  	const char *str = buf;
  	char *next;
  	char digit;
  	int num = 0;
ef0658f3d   Joe Perches   vsprintf.c: Reduc...
2545
  	u8 qualifier;
53809751a   Jan Beulich   sscanf: don't ign...
2546
2547
2548
2549
2550
  	unsigned int base;
  	union {
  		long long s;
  		unsigned long long u;
  	} val;
ef0658f3d   Joe Perches   vsprintf.c: Reduc...
2551
  	s16 field_width;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2552
  	bool is_sign;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2553

da99075c1   Jan Beulich   lib/vsprintf.c: i...
2554
  	while (*fmt) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2555
2556
2557
2558
2559
  		/* 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...
2560
2561
  			fmt = skip_spaces(++fmt);
  			str = skip_spaces(str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
  		}
  
  		/* 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...
2574

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2575
2576
2577
2578
  		/* skip this conversion.
  		 * advance both strings to next white space
  		 */
  		if (*fmt == '*') {
da99075c1   Jan Beulich   lib/vsprintf.c: i...
2579
2580
  			if (!*str)
  				break;
f9310b2f9   Jessica Yu   sscanf: implement...
2581
2582
2583
2584
  			while (!isspace(*fmt) && *fmt != '%' && *fmt) {
  				/* '%*[' not yet supported, invalid format */
  				if (*fmt == '[')
  					return num;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2585
  				fmt++;
f9310b2f9   Jessica Yu   sscanf: implement...
2586
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2587
2588
2589
2590
2591
2592
2593
  			while (!isspace(*str) && *str)
  				str++;
  			continue;
  		}
  
  		/* get field width */
  		field_width = -1;
53809751a   Jan Beulich   sscanf: don't ign...
2594
  		if (isdigit(*fmt)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2595
  			field_width = skip_atoi(&fmt);
53809751a   Jan Beulich   sscanf: don't ign...
2596
2597
2598
  			if (field_width <= 0)
  				break;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2599
2600
2601
  
  		/* get conversion qualifier */
  		qualifier = -1;
75fb8f269   Andy Shevchenko   lib: make _tolowe...
2602
2603
  		if (*fmt == 'h' || _tolower(*fmt) == 'l' ||
  		    _tolower(*fmt) == 'z') {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
  			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
2615

da99075c1   Jan Beulich   lib/vsprintf.c: i...
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
  		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
2627
  			break;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2628
  		base = 10;
3f623eba2   Fabian Frederick   lib/vsprintf.c: f...
2629
  		is_sign = false;
d4be151b2   André Goddard Rosa   vsprintf: move lo...
2630

7b9186f5e   André Goddard Rosa   vsprintf: give it...
2631
  		switch (*fmt++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2632
2633
  		case 'c':
  		{
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2634
  			char *s = (char *)va_arg(args, char*);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
  			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...
2645
2646
  			char *s = (char *)va_arg(args, char *);
  			if (field_width == -1)
4be929be3   Alexey Dobriyan   kernel-wide: repl...
2647
  				field_width = SHRT_MAX;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2648
  			/* first, skip leading white space in buffer */
e7d2860b6   André Goddard Rosa   tree-wide: conver...
2649
  			str = skip_spaces(str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2650
2651
  
  			/* now copy until next white space */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2652
  			while (*str && !isspace(*str) && field_width--)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2653
  				*s++ = *str++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2654
2655
2656
2657
  			*s = '\0';
  			num++;
  		}
  		continue;
f9310b2f9   Jessica Yu   sscanf: implement...
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
  		/*
  		 * 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
2711
2712
2713
2714
2715
2716
2717
2718
  		case 'o':
  			base = 8;
  			break;
  		case 'x':
  		case 'X':
  			base = 16;
  			break;
  		case 'i':
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2719
  			base = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2720
  		case 'd':
3f623eba2   Fabian Frederick   lib/vsprintf.c: f...
2721
  			is_sign = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2722
2723
2724
2725
  		case 'u':
  			break;
  		case '%':
  			/* looking for '%' in str */
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2726
  			if (*str++ != '%')
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
  				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...
2737
  		str = skip_spaces(str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2738
2739
2740
2741
2742
2743
  
  		digit = *str;
  		if (is_sign && digit == '-')
  			digit = *(str + 1);
  
  		if (!digit
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2744
2745
2746
2747
2748
  		    || (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
2749

53809751a   Jan Beulich   sscanf: don't ign...
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
  		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...
2770
  		switch (qualifier) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2771
  		case 'H':	/* that's 'hh' in format */
53809751a   Jan Beulich   sscanf: don't ign...
2772
2773
2774
2775
  			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
2776
2777
  			break;
  		case 'h':
53809751a   Jan Beulich   sscanf: don't ign...
2778
2779
2780
2781
  			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
2782
2783
  			break;
  		case 'l':
53809751a   Jan Beulich   sscanf: don't ign...
2784
2785
2786
2787
  			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
2788
2789
  			break;
  		case 'L':
53809751a   Jan Beulich   sscanf: don't ign...
2790
2791
2792
2793
  			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
2794
2795
2796
  			break;
  		case 'Z':
  		case 'z':
53809751a   Jan Beulich   sscanf: don't ign...
2797
2798
  			*va_arg(args, size_t *) = val.u;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2799
  		default:
53809751a   Jan Beulich   sscanf: don't ign...
2800
2801
2802
2803
  			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
2804
2805
2806
2807
2808
2809
2810
2811
  			break;
  		}
  		num++;
  
  		if (!next)
  			break;
  		str = next;
  	}
c6b40d16d   Johannes Berg   fix sscanf %n mat...
2812

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2813
2814
  	return num;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2815
2816
2817
2818
2819
2820
2821
2822
  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...
2823
  int sscanf(const char *buf, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2824
2825
2826
  {
  	va_list args;
  	int i;
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2827
2828
  	va_start(args, fmt);
  	i = vsscanf(buf, fmt, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2829
  	va_end(args);
7b9186f5e   André Goddard Rosa   vsprintf: give it...
2830

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2831
2832
  	return i;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2833
  EXPORT_SYMBOL(sscanf);