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
267
268int string_unescape(char *src, char *dst, size_t size, unsigned int flags)
269{
270 char *out = dst;
271
272 while (*src && --size) {
273 if (src[0] == '\\' && src[1] != '\0' && size > 1) {
274 src++;
275 size--;
276
277 if (flags & UNESCAPE_SPACE &&
278 unescape_space(&src, &out))
279 continue;
280
281 if (flags & UNESCAPE_OCTAL &&
282 unescape_octal(&src, &out))
283 continue;
284
285 if (flags & UNESCAPE_HEX &&
286 unescape_hex(&src, &out))
287 continue;
288
289 if (flags & UNESCAPE_SPECIAL &&
290 unescape_special(&src, &out))
291 continue;
292
293 *out++ = '\\';
294 }
295 *out++ = *src++;
296 }
297 *out = '\0';
298
299 return out - dst;
300}
301EXPORT_SYMBOL(string_unescape);
302
303static bool escape_passthrough(unsigned char c, char **dst, char *end)
304{
305 char *out = *dst;
306
307 if (out < end)
308 *out = c;
309 *dst = out + 1;
310 return true;
311}
312
313static bool escape_space(unsigned char c, char **dst, char *end)
314{
315 char *out = *dst;
316 unsigned char to;
317
318 switch (c) {
319 case '\n':
320 to = 'n';
321 break;
322 case '\r':
323 to = 'r';
324 break;
325 case '\t':
326 to = 't';
327 break;
328 case '\v':
329 to = 'v';
330 break;
331 case '\f':
332 to = 'f';
333 break;
334 default:
335 return false;
336 }
337
338 if (out < end)
339 *out = '\\';
340 ++out;
341 if (out < end)
342 *out = to;
343 ++out;
344
345 *dst = out;
346 return true;
347}
348
349static bool escape_special(unsigned char c, char **dst, char *end)
350{
351 char *out = *dst;
352 unsigned char to;
353
354 switch (c) {
355 case '\\':
356 to = '\\';
357 break;
358 case '\a':
359 to = 'a';
360 break;
361 case '\e':
362 to = 'e';
363 break;
364 case '"':
365 to = '"';
366 break;
367 default:
368 return false;
369 }
370
371 if (out < end)
372 *out = '\\';
373 ++out;
374 if (out < end)
375 *out = to;
376 ++out;
377
378 *dst = out;
379 return true;
380}
381
382static bool escape_null(unsigned char c, char **dst, char *end)
383{
384 char *out = *dst;
385
386 if (c)
387 return false;
388
389 if (out < end)
390 *out = '\\';
391 ++out;
392 if (out < end)
393 *out = '0';
394 ++out;
395
396 *dst = out;
397 return true;
398}
399
400static bool escape_octal(unsigned char c, char **dst, char *end)
401{
402 char *out = *dst;
403
404 if (out < end)
405 *out = '\\';
406 ++out;
407 if (out < end)
408 *out = ((c >> 6) & 0x07) + '0';
409 ++out;
410 if (out < end)
411 *out = ((c >> 3) & 0x07) + '0';
412 ++out;
413 if (out < end)
414 *out = ((c >> 0) & 0x07) + '0';
415 ++out;
416
417 *dst = out;
418 return true;
419}
420
421static bool escape_hex(unsigned char c, char **dst, char *end)
422{
423 char *out = *dst;
424
425 if (out < end)
426 *out = '\\';
427 ++out;
428 if (out < end)
429 *out = 'x';
430 ++out;
431 if (out < end)
432 *out = hex_asc_hi(c);
433 ++out;
434 if (out < end)
435 *out = hex_asc_lo(c);
436 ++out;
437
438 *dst = out;
439 return true;
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
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz,
520 unsigned int flags, const char *only)
521{
522 char *p = dst;
523 char *end = p + osz;
524 bool is_dict = only && *only;
525 bool is_append = flags & ESCAPE_APPEND;
526
527 while (isz--) {
528 unsigned char c = *src++;
529 bool in_dict = is_dict && strchr(only, c);
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550 if (!(is_append || in_dict) && is_dict &&
551 escape_passthrough(c, &p, end))
552 continue;
553
554 if (!(is_append && in_dict) && isascii(c) && isprint(c) &&
555 flags & ESCAPE_NAP && escape_passthrough(c, &p, end))
556 continue;
557
558 if (!(is_append && in_dict) && isprint(c) &&
559 flags & ESCAPE_NP && escape_passthrough(c, &p, end))
560 continue;
561
562 if (!(is_append && in_dict) && isascii(c) &&
563 flags & ESCAPE_NA && escape_passthrough(c, &p, end))
564 continue;
565
566 if (flags & ESCAPE_SPACE && escape_space(c, &p, end))
567 continue;
568
569 if (flags & ESCAPE_SPECIAL && escape_special(c, &p, end))
570 continue;
571
572 if (flags & ESCAPE_NULL && escape_null(c, &p, end))
573 continue;
574
575
576 if (flags & ESCAPE_OCTAL && escape_octal(c, &p, end))
577 continue;
578
579 if (flags & ESCAPE_HEX && escape_hex(c, &p, end))
580 continue;
581
582 escape_passthrough(c, &p, end);
583 }
584
585 return p - dst;
586}
587EXPORT_SYMBOL(string_escape_mem);
588
589
590
591
592
593char *kstrdup_quotable(const char *src, gfp_t gfp)
594{
595 size_t slen, dlen;
596 char *dst;
597 const int flags = ESCAPE_HEX;
598 const char esc[] = "\f\n\r\t\v\a\e\\\"";
599
600 if (!src)
601 return NULL;
602 slen = strlen(src);
603
604 dlen = string_escape_mem(src, slen, NULL, 0, flags, esc);
605 dst = kmalloc(dlen + 1, gfp);
606 if (!dst)
607 return NULL;
608
609 WARN_ON(string_escape_mem(src, slen, dst, dlen, flags, esc) != dlen);
610 dst[dlen] = '\0';
611
612 return dst;
613}
614EXPORT_SYMBOL_GPL(kstrdup_quotable);
615
616
617
618
619
620
621char *kstrdup_quotable_cmdline(struct task_struct *task, gfp_t gfp)
622{
623 char *buffer, *quoted;
624 int i, res;
625
626 buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
627 if (!buffer)
628 return NULL;
629
630 res = get_cmdline(task, buffer, PAGE_SIZE - 1);
631 buffer[res] = '\0';
632
633
634 while (--res >= 0 && buffer[res] == '\0')
635 ;
636
637
638 for (i = 0; i <= res; i++)
639 if (buffer[i] == '\0')
640 buffer[i] = ' ';
641
642
643 quoted = kstrdup_quotable(buffer, gfp);
644 kfree(buffer);
645 return quoted;
646}
647EXPORT_SYMBOL_GPL(kstrdup_quotable_cmdline);
648
649
650
651
652
653
654char *kstrdup_quotable_file(struct file *file, gfp_t gfp)
655{
656 char *temp, *pathname;
657
658 if (!file)
659 return kstrdup("<unknown>", gfp);
660
661
662 temp = kmalloc(PATH_MAX + 11, GFP_KERNEL);
663 if (!temp)
664 return kstrdup("<no_memory>", gfp);
665
666 pathname = file_path(file, temp, PATH_MAX + 11);
667 if (IS_ERR(pathname))
668 pathname = kstrdup("<too_long>", gfp);
669 else
670 pathname = kstrdup_quotable(pathname, gfp);
671
672 kfree(temp);
673 return pathname;
674}
675EXPORT_SYMBOL_GPL(kstrdup_quotable_file);
676
677
678
679
680
681
682
683
684
685
686
687void kfree_strarray(char **array, size_t n)
688{
689 unsigned int i;
690
691 if (!array)
692 return;
693
694 for (i = 0; i < n; i++)
695 kfree(array[i]);
696 kfree(array);
697}
698EXPORT_SYMBOL_GPL(kfree_strarray);
699