1
2
3
4
5
6
7
8#include <linux/bug.h>
9#include <linux/kernel.h>
10#include <linux/math64.h>
11#include <linux/export.h>
12#include <linux/ctype.h>
13#include <linux/errno.h>
14#include <linux/fs.h>
15#include <linux/limits.h>
16#include <linux/mm.h>
17#include <linux/slab.h>
18#include <linux/string.h>
19#include <linux/string_helpers.h>
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34void string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
35 char *buf, int len)
36{
37 static const char *const units_10[] = {
38 "B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"
39 };
40 static const char *const units_2[] = {
41 "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"
42 };
43 static const char *const *const units_str[] = {
44 [STRING_UNITS_10] = units_10,
45 [STRING_UNITS_2] = units_2,
46 };
47 static const unsigned int divisor[] = {
48 [STRING_UNITS_10] = 1000,
49 [STRING_UNITS_2] = 1024,
50 };
51 static const unsigned int rounding[] = { 500, 50, 5 };
52 int i = 0, j;
53 u32 remainder = 0, sf_cap;
54 char tmp[8];
55 const char *unit;
56
57 tmp[0] = '\0';
58
59 if (blk_size == 0)
60 size = 0;
61 if (size == 0)
62 goto out;
63
64
65
66
67
68
69
70
71
72
73
74
75 while (blk_size >> 32) {
76 do_div(blk_size, divisor[units]);
77 i++;
78 }
79
80 while (size >> 32) {
81 do_div(size, divisor[units]);
82 i++;
83 }
84
85
86
87 size *= blk_size;
88
89
90 while (size >= divisor[units]) {
91 remainder = do_div(size, divisor[units]);
92 i++;
93 }
94
95
96
97 sf_cap = size;
98 for (j = 0; sf_cap*10 < 1000; j++)
99 sf_cap *= 10;
100
101 if (units == STRING_UNITS_2) {
102
103
104
105 remainder *= 1000;
106 remainder >>= 10;
107 }
108
109
110
111 remainder += rounding[j];
112 if (remainder >= 1000) {
113 remainder -= 1000;
114 size += 1;
115 }
116
117 if (j) {
118 snprintf(tmp, sizeof(tmp), ".%03u", remainder);
119 tmp[j+1] = '\0';
120 }
121
122 out:
123 if (i >= ARRAY_SIZE(units_2))
124 unit = "UNK";
125 else
126 unit = units_str[units][i];
127
128 snprintf(buf, len, "%u%s %s", (u32)size,
129 tmp, unit);
130}
131EXPORT_SYMBOL(string_get_size);
132
133static bool unescape_space(char **src, char **dst)
134{
135 char *p = *dst, *q = *src;
136
137 switch (*q) {
138 case 'n':
139 *p = '\n';
140 break;
141 case 'r':
142 *p = '\r';
143 break;
144 case 't':
145 *p = '\t';
146 break;
147 case 'v':
148 *p = '\v';
149 break;
150 case 'f':
151 *p = '\f';
152 break;
153 default:
154 return false;
155 }
156 *dst += 1;
157 *src += 1;
158 return true;
159}
160
161static bool unescape_octal(char **src, char **dst)
162{
163 char *p = *dst, *q = *src;
164 u8 num;
165
166 if (isodigit(*q) == 0)
167 return false;
168
169 num = (*q++) & 7;
170 while (num < 32 && isodigit(*q) && (q - *src < 3)) {
171 num <<= 3;
172 num += (*q++) & 7;
173 }
174 *p = num;
175 *dst += 1;
176 *src = q;
177 return true;
178}
179
180static bool unescape_hex(char **src, char **dst)
181{
182 char *p = *dst, *q = *src;
183 int digit;
184 u8 num;
185
186 if (*q++ != 'x')
187 return false;
188
189 num = digit = hex_to_bin(*q++);
190 if (digit < 0)
191 return false;
192
193 digit = hex_to_bin(*q);
194 if (digit >= 0) {
195 q++;
196 num = (num << 4) | digit;
197 }
198 *p = num;
199 *dst += 1;
200 *src = q;
201 return true;
202}
203
204static bool unescape_special(char **src, char **dst)
205{
206 char *p = *dst, *q = *src;
207
208 switch (*q) {
209 case '\"':
210 *p = '\"';
211 break;
212 case '\\':
213 *p = '\\';
214 break;
215 case 'a':
216 *p = '\a';
217 break;
218 case 'e':
219 *p = '\e';
220 break;
221 default:
222 return false;
223 }
224 *dst += 1;
225 *src += 1;
226 return true;
227}
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267int string_unescape(char *src, char *dst, size_t size, unsigned int flags)
268{
269 char *out = dst;
270
271 while (*src && --size) {
272 if (src[0] == '\\' && src[1] != '\0' && size > 1) {
273 src++;
274 size--;
275
276 if (flags & UNESCAPE_SPACE &&
277 unescape_space(&src, &out))
278 continue;
279
280 if (flags & UNESCAPE_OCTAL &&
281 unescape_octal(&src, &out))
282 continue;
283
284 if (flags & UNESCAPE_HEX &&
285 unescape_hex(&src, &out))
286 continue;
287
288 if (flags & UNESCAPE_SPECIAL &&
289 unescape_special(&src, &out))
290 continue;
291
292 *out++ = '\\';
293 }
294 *out++ = *src++;
295 }
296 *out = '\0';
297
298 return out - dst;
299}
300EXPORT_SYMBOL(string_unescape);
301
302static bool escape_passthrough(unsigned char c, char **dst, char *end)
303{
304 char *out = *dst;
305
306 if (out < end)
307 *out = c;
308 *dst = out + 1;
309 return true;
310}
311
312static bool escape_space(unsigned char c, char **dst, char *end)
313{
314 char *out = *dst;
315 unsigned char to;
316
317 switch (c) {
318 case '\n':
319 to = 'n';
320 break;
321 case '\r':
322 to = 'r';
323 break;
324 case '\t':
325 to = 't';
326 break;
327 case '\v':
328 to = 'v';
329 break;
330 case '\f':
331 to = 'f';
332 break;
333 default:
334 return false;
335 }
336
337 if (out < end)
338 *out = '\\';
339 ++out;
340 if (out < end)
341 *out = to;
342 ++out;
343
344 *dst = out;
345 return true;
346}
347
348static bool escape_special(unsigned char c, char **dst, char *end)
349{
350 char *out = *dst;
351 unsigned char to;
352
353 switch (c) {
354 case '\\':
355 to = '\\';
356 break;
357 case '\a':
358 to = 'a';
359 break;
360 case '\e':
361 to = 'e';
362 break;
363 default:
364 return false;
365 }
366
367 if (out < end)
368 *out = '\\';
369 ++out;
370 if (out < end)
371 *out = to;
372 ++out;
373
374 *dst = out;
375 return true;
376}
377
378static bool escape_null(unsigned char c, char **dst, char *end)
379{
380 char *out = *dst;
381
382 if (c)
383 return false;
384
385 if (out < end)
386 *out = '\\';
387 ++out;
388 if (out < end)
389 *out = '0';
390 ++out;
391
392 *dst = out;
393 return true;
394}
395
396static bool escape_octal(unsigned char c, char **dst, char *end)
397{
398 char *out = *dst;
399
400 if (out < end)
401 *out = '\\';
402 ++out;
403 if (out < end)
404 *out = ((c >> 6) & 0x07) + '0';
405 ++out;
406 if (out < end)
407 *out = ((c >> 3) & 0x07) + '0';
408 ++out;
409 if (out < end)
410 *out = ((c >> 0) & 0x07) + '0';
411 ++out;
412
413 *dst = out;
414 return true;
415}
416
417static bool escape_hex(unsigned char c, char **dst, char *end)
418{
419 char *out = *dst;
420
421 if (out < end)
422 *out = '\\';
423 ++out;
424 if (out < end)
425 *out = 'x';
426 ++out;
427 if (out < end)
428 *out = hex_asc_hi(c);
429 ++out;
430 if (out < end)
431 *out = hex_asc_lo(c);
432 ++out;
433
434 *dst = out;
435 return true;
436}
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz,
495 unsigned int flags, const char *only)
496{
497 char *p = dst;
498 char *end = p + osz;
499 bool is_dict = only && *only;
500
501 while (isz--) {
502 unsigned char c = *src++;
503
504
505
506
507
508
509
510
511
512
513
514
515 if ((flags & ESCAPE_NP && isprint(c)) ||
516 (is_dict && !strchr(only, c))) {
517
518 } else {
519 if (flags & ESCAPE_SPACE && escape_space(c, &p, end))
520 continue;
521
522 if (flags & ESCAPE_SPECIAL && escape_special(c, &p, end))
523 continue;
524
525 if (flags & ESCAPE_NULL && escape_null(c, &p, end))
526 continue;
527
528
529 if (flags & ESCAPE_OCTAL && escape_octal(c, &p, end))
530 continue;
531
532 if (flags & ESCAPE_HEX && escape_hex(c, &p, end))
533 continue;
534 }
535
536 escape_passthrough(c, &p, end);
537 }
538
539 return p - dst;
540}
541EXPORT_SYMBOL(string_escape_mem);
542
543
544
545
546
547char *kstrdup_quotable(const char *src, gfp_t gfp)
548{
549 size_t slen, dlen;
550 char *dst;
551 const int flags = ESCAPE_HEX;
552 const char esc[] = "\f\n\r\t\v\a\e\\\"";
553
554 if (!src)
555 return NULL;
556 slen = strlen(src);
557
558 dlen = string_escape_mem(src, slen, NULL, 0, flags, esc);
559 dst = kmalloc(dlen + 1, gfp);
560 if (!dst)
561 return NULL;
562
563 WARN_ON(string_escape_mem(src, slen, dst, dlen, flags, esc) != dlen);
564 dst[dlen] = '\0';
565
566 return dst;
567}
568EXPORT_SYMBOL_GPL(kstrdup_quotable);
569
570
571
572
573
574
575char *kstrdup_quotable_cmdline(struct task_struct *task, gfp_t gfp)
576{
577 char *buffer, *quoted;
578 int i, res;
579
580 buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
581 if (!buffer)
582 return NULL;
583
584 res = get_cmdline(task, buffer, PAGE_SIZE - 1);
585 buffer[res] = '\0';
586
587
588 while (--res >= 0 && buffer[res] == '\0')
589 ;
590
591
592 for (i = 0; i <= res; i++)
593 if (buffer[i] == '\0')
594 buffer[i] = ' ';
595
596
597 quoted = kstrdup_quotable(buffer, gfp);
598 kfree(buffer);
599 return quoted;
600}
601EXPORT_SYMBOL_GPL(kstrdup_quotable_cmdline);
602
603
604
605
606
607
608char *kstrdup_quotable_file(struct file *file, gfp_t gfp)
609{
610 char *temp, *pathname;
611
612 if (!file)
613 return kstrdup("<unknown>", gfp);
614
615
616 temp = kmalloc(PATH_MAX + 11, GFP_KERNEL);
617 if (!temp)
618 return kstrdup("<no_memory>", gfp);
619
620 pathname = file_path(file, temp, PATH_MAX + 11);
621 if (IS_ERR(pathname))
622 pathname = kstrdup("<too_long>", gfp);
623 else
624 pathname = kstrdup_quotable(pathname, gfp);
625
626 kfree(temp);
627 return pathname;
628}
629EXPORT_SYMBOL_GPL(kstrdup_quotable_file);
630