1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 23c9f3681SJames Bottomley /* 33c9f3681SJames Bottomley * Helpers for formatting and printing strings 43c9f3681SJames Bottomley * 53c9f3681SJames Bottomley * Copyright 31 August 2008 James Bottomley 616c7fa05SAndy Shevchenko * Copyright (C) 2013, Intel Corporation 73c9f3681SJames Bottomley */ 8b9f28d86SJames Bottomley #include <linux/bug.h> 93c9f3681SJames Bottomley #include <linux/kernel.h> 103c9f3681SJames Bottomley #include <linux/math64.h> 118bc3bcc9SPaul Gortmaker #include <linux/export.h> 1216c7fa05SAndy Shevchenko #include <linux/ctype.h> 13c8250381SAndy Shevchenko #include <linux/errno.h> 1421985319SKees Cook #include <linux/fs.h> 1521985319SKees Cook #include <linux/limits.h> 160d044328SKees Cook #include <linux/mm.h> 17b53f27e4SKees Cook #include <linux/slab.h> 18c8250381SAndy Shevchenko #include <linux/string.h> 193c9f3681SJames Bottomley #include <linux/string_helpers.h> 203c9f3681SJames Bottomley 213c9f3681SJames Bottomley /** 223c9f3681SJames Bottomley * string_get_size - get the size in the specified units 23b9f28d86SJames Bottomley * @size: The size to be converted in blocks 24b9f28d86SJames Bottomley * @blk_size: Size of the block (use 1 for size in bytes) 253c9f3681SJames Bottomley * @units: units to use (powers of 1000 or 1024) 263c9f3681SJames Bottomley * @buf: buffer to format to 273c9f3681SJames Bottomley * @len: length of buffer 283c9f3681SJames Bottomley * 293c9f3681SJames Bottomley * This function returns a string formatted to 3 significant figures 30d1214c65SRasmus Villemoes * giving the size in the required units. @buf should have room for 31d1214c65SRasmus Villemoes * at least 9 bytes and will always be zero terminated. 323c9f3681SJames Bottomley * 333c9f3681SJames Bottomley */ 34b9f28d86SJames Bottomley void string_get_size(u64 size, u64 blk_size, const enum string_size_units units, 353c9f3681SJames Bottomley char *buf, int len) 363c9f3681SJames Bottomley { 37142cda5dSMathias Krause static const char *const units_10[] = { 38b9f28d86SJames Bottomley "B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" 39142cda5dSMathias Krause }; 40142cda5dSMathias Krause static const char *const units_2[] = { 41b9f28d86SJames Bottomley "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB" 42142cda5dSMathias Krause }; 43142cda5dSMathias Krause static const char *const *const units_str[] = { 443c9f3681SJames Bottomley [STRING_UNITS_10] = units_10, 453c9f3681SJames Bottomley [STRING_UNITS_2] = units_2, 463c9f3681SJames Bottomley }; 4768aecfb9SAndrew Morton static const unsigned int divisor[] = { 483c9f3681SJames Bottomley [STRING_UNITS_10] = 1000, 493c9f3681SJames Bottomley [STRING_UNITS_2] = 1024, 503c9f3681SJames Bottomley }; 51564b026fSJames Bottomley static const unsigned int rounding[] = { 500, 50, 5 }; 52564b026fSJames Bottomley int i = 0, j; 53564b026fSJames Bottomley u32 remainder = 0, sf_cap; 543c9f3681SJames Bottomley char tmp[8]; 55b9f28d86SJames Bottomley const char *unit; 563c9f3681SJames Bottomley 573c9f3681SJames Bottomley tmp[0] = '\0'; 58564b026fSJames Bottomley 59564b026fSJames Bottomley if (blk_size == 0) 60564b026fSJames Bottomley size = 0; 61564b026fSJames Bottomley if (size == 0) 62b9f28d86SJames Bottomley goto out; 63b9f28d86SJames Bottomley 64564b026fSJames Bottomley /* This is Napier's algorithm. Reduce the original block size to 65564b026fSJames Bottomley * 66564b026fSJames Bottomley * coefficient * divisor[units]^i 67564b026fSJames Bottomley * 68564b026fSJames Bottomley * we do the reduction so both coefficients are just under 32 bits so 69564b026fSJames Bottomley * that multiplying them together won't overflow 64 bits and we keep 70564b026fSJames Bottomley * as much precision as possible in the numbers. 71564b026fSJames Bottomley * 72564b026fSJames Bottomley * Note: it's safe to throw away the remainders here because all the 73564b026fSJames Bottomley * precision is in the coefficients. 7462bef58aSVitaly Kuznetsov */ 75564b026fSJames Bottomley while (blk_size >> 32) { 76564b026fSJames Bottomley do_div(blk_size, divisor[units]); 77b9f28d86SJames Bottomley i++; 78b9f28d86SJames Bottomley } 79b9f28d86SJames Bottomley 80564b026fSJames Bottomley while (size >> 32) { 81564b026fSJames Bottomley do_div(size, divisor[units]); 82564b026fSJames Bottomley i++; 83564b026fSJames Bottomley } 84b9f28d86SJames Bottomley 85564b026fSJames Bottomley /* now perform the actual multiplication keeping i as the sum of the 86564b026fSJames Bottomley * two logarithms */ 87564b026fSJames Bottomley size *= blk_size; 88564b026fSJames Bottomley 89564b026fSJames Bottomley /* and logarithmically reduce it until it's just under the divisor */ 907eed8fdeSRasmus Villemoes while (size >= divisor[units]) { 913c9f3681SJames Bottomley remainder = do_div(size, divisor[units]); 92a8659597SH. Peter Anvin i++; 93a8659597SH. Peter Anvin } 943c9f3681SJames Bottomley 95564b026fSJames Bottomley /* work out in j how many digits of precision we need from the 96564b026fSJames Bottomley * remainder */ 973c9f3681SJames Bottomley sf_cap = size; 983c9f3681SJames Bottomley for (j = 0; sf_cap*10 < 1000; j++) 993c9f3681SJames Bottomley sf_cap *= 10; 1003c9f3681SJames Bottomley 101564b026fSJames Bottomley if (units == STRING_UNITS_2) { 102564b026fSJames Bottomley /* express the remainder as a decimal. It's currently the 103564b026fSJames Bottomley * numerator of a fraction whose denominator is 104564b026fSJames Bottomley * divisor[units], which is 1 << 10 for STRING_UNITS_2 */ 1053c9f3681SJames Bottomley remainder *= 1000; 106564b026fSJames Bottomley remainder >>= 10; 107564b026fSJames Bottomley } 108564b026fSJames Bottomley 109564b026fSJames Bottomley /* add a 5 to the digit below what will be printed to ensure 110564b026fSJames Bottomley * an arithmetical round up and carry it through to size */ 111564b026fSJames Bottomley remainder += rounding[j]; 112564b026fSJames Bottomley if (remainder >= 1000) { 113564b026fSJames Bottomley remainder -= 1000; 114564b026fSJames Bottomley size += 1; 115564b026fSJames Bottomley } 116564b026fSJames Bottomley 117564b026fSJames Bottomley if (j) { 11884b9fbedSRasmus Villemoes snprintf(tmp, sizeof(tmp), ".%03u", remainder); 1193c9f3681SJames Bottomley tmp[j+1] = '\0'; 1203c9f3681SJames Bottomley } 121b9f28d86SJames Bottomley 122b9f28d86SJames Bottomley out: 123b9f28d86SJames Bottomley if (i >= ARRAY_SIZE(units_2)) 124b9f28d86SJames Bottomley unit = "UNK"; 125b9f28d86SJames Bottomley else 126b9f28d86SJames Bottomley unit = units_str[units][i]; 1273c9f3681SJames Bottomley 12884b9fbedSRasmus Villemoes snprintf(buf, len, "%u%s %s", (u32)size, 129b9f28d86SJames Bottomley tmp, unit); 1303c9f3681SJames Bottomley } 1313c9f3681SJames Bottomley EXPORT_SYMBOL(string_get_size); 13216c7fa05SAndy Shevchenko 13316c7fa05SAndy Shevchenko static bool unescape_space(char **src, char **dst) 13416c7fa05SAndy Shevchenko { 13516c7fa05SAndy Shevchenko char *p = *dst, *q = *src; 13616c7fa05SAndy Shevchenko 13716c7fa05SAndy Shevchenko switch (*q) { 13816c7fa05SAndy Shevchenko case 'n': 13916c7fa05SAndy Shevchenko *p = '\n'; 14016c7fa05SAndy Shevchenko break; 14116c7fa05SAndy Shevchenko case 'r': 14216c7fa05SAndy Shevchenko *p = '\r'; 14316c7fa05SAndy Shevchenko break; 14416c7fa05SAndy Shevchenko case 't': 14516c7fa05SAndy Shevchenko *p = '\t'; 14616c7fa05SAndy Shevchenko break; 14716c7fa05SAndy Shevchenko case 'v': 14816c7fa05SAndy Shevchenko *p = '\v'; 14916c7fa05SAndy Shevchenko break; 15016c7fa05SAndy Shevchenko case 'f': 15116c7fa05SAndy Shevchenko *p = '\f'; 15216c7fa05SAndy Shevchenko break; 15316c7fa05SAndy Shevchenko default: 15416c7fa05SAndy Shevchenko return false; 15516c7fa05SAndy Shevchenko } 15616c7fa05SAndy Shevchenko *dst += 1; 15716c7fa05SAndy Shevchenko *src += 1; 15816c7fa05SAndy Shevchenko return true; 15916c7fa05SAndy Shevchenko } 16016c7fa05SAndy Shevchenko 16116c7fa05SAndy Shevchenko static bool unescape_octal(char **src, char **dst) 16216c7fa05SAndy Shevchenko { 16316c7fa05SAndy Shevchenko char *p = *dst, *q = *src; 16416c7fa05SAndy Shevchenko u8 num; 16516c7fa05SAndy Shevchenko 16616c7fa05SAndy Shevchenko if (isodigit(*q) == 0) 16716c7fa05SAndy Shevchenko return false; 16816c7fa05SAndy Shevchenko 16916c7fa05SAndy Shevchenko num = (*q++) & 7; 17016c7fa05SAndy Shevchenko while (num < 32 && isodigit(*q) && (q - *src < 3)) { 17116c7fa05SAndy Shevchenko num <<= 3; 17216c7fa05SAndy Shevchenko num += (*q++) & 7; 17316c7fa05SAndy Shevchenko } 17416c7fa05SAndy Shevchenko *p = num; 17516c7fa05SAndy Shevchenko *dst += 1; 17616c7fa05SAndy Shevchenko *src = q; 17716c7fa05SAndy Shevchenko return true; 17816c7fa05SAndy Shevchenko } 17916c7fa05SAndy Shevchenko 18016c7fa05SAndy Shevchenko static bool unescape_hex(char **src, char **dst) 18116c7fa05SAndy Shevchenko { 18216c7fa05SAndy Shevchenko char *p = *dst, *q = *src; 18316c7fa05SAndy Shevchenko int digit; 18416c7fa05SAndy Shevchenko u8 num; 18516c7fa05SAndy Shevchenko 18616c7fa05SAndy Shevchenko if (*q++ != 'x') 18716c7fa05SAndy Shevchenko return false; 18816c7fa05SAndy Shevchenko 18916c7fa05SAndy Shevchenko num = digit = hex_to_bin(*q++); 19016c7fa05SAndy Shevchenko if (digit < 0) 19116c7fa05SAndy Shevchenko return false; 19216c7fa05SAndy Shevchenko 19316c7fa05SAndy Shevchenko digit = hex_to_bin(*q); 19416c7fa05SAndy Shevchenko if (digit >= 0) { 19516c7fa05SAndy Shevchenko q++; 19616c7fa05SAndy Shevchenko num = (num << 4) | digit; 19716c7fa05SAndy Shevchenko } 19816c7fa05SAndy Shevchenko *p = num; 19916c7fa05SAndy Shevchenko *dst += 1; 20016c7fa05SAndy Shevchenko *src = q; 20116c7fa05SAndy Shevchenko return true; 20216c7fa05SAndy Shevchenko } 20316c7fa05SAndy Shevchenko 20416c7fa05SAndy Shevchenko static bool unescape_special(char **src, char **dst) 20516c7fa05SAndy Shevchenko { 20616c7fa05SAndy Shevchenko char *p = *dst, *q = *src; 20716c7fa05SAndy Shevchenko 20816c7fa05SAndy Shevchenko switch (*q) { 20916c7fa05SAndy Shevchenko case '\"': 21016c7fa05SAndy Shevchenko *p = '\"'; 21116c7fa05SAndy Shevchenko break; 21216c7fa05SAndy Shevchenko case '\\': 21316c7fa05SAndy Shevchenko *p = '\\'; 21416c7fa05SAndy Shevchenko break; 21516c7fa05SAndy Shevchenko case 'a': 21616c7fa05SAndy Shevchenko *p = '\a'; 21716c7fa05SAndy Shevchenko break; 21816c7fa05SAndy Shevchenko case 'e': 21916c7fa05SAndy Shevchenko *p = '\e'; 22016c7fa05SAndy Shevchenko break; 22116c7fa05SAndy Shevchenko default: 22216c7fa05SAndy Shevchenko return false; 22316c7fa05SAndy Shevchenko } 22416c7fa05SAndy Shevchenko *dst += 1; 22516c7fa05SAndy Shevchenko *src += 1; 22616c7fa05SAndy Shevchenko return true; 22716c7fa05SAndy Shevchenko } 22816c7fa05SAndy Shevchenko 229d295634eSAndy Shevchenko /** 230d295634eSAndy Shevchenko * string_unescape - unquote characters in the given string 231d295634eSAndy Shevchenko * @src: source buffer (escaped) 232d295634eSAndy Shevchenko * @dst: destination buffer (unescaped) 233d295634eSAndy Shevchenko * @size: size of the destination buffer (0 to unlimit) 234b4658cddSJonathan Corbet * @flags: combination of the flags. 235d295634eSAndy Shevchenko * 236d295634eSAndy Shevchenko * Description: 237d295634eSAndy Shevchenko * The function unquotes characters in the given string. 238d295634eSAndy Shevchenko * 239d295634eSAndy Shevchenko * Because the size of the output will be the same as or less than the size of 240d295634eSAndy Shevchenko * the input, the transformation may be performed in place. 241d295634eSAndy Shevchenko * 242d295634eSAndy Shevchenko * Caller must provide valid source and destination pointers. Be aware that 243d295634eSAndy Shevchenko * destination buffer will always be NULL-terminated. Source string must be 244b4658cddSJonathan Corbet * NULL-terminated as well. The supported flags are:: 245b4658cddSJonathan Corbet * 246b4658cddSJonathan Corbet * UNESCAPE_SPACE: 247b4658cddSJonathan Corbet * '\f' - form feed 248b4658cddSJonathan Corbet * '\n' - new line 249b4658cddSJonathan Corbet * '\r' - carriage return 250b4658cddSJonathan Corbet * '\t' - horizontal tab 251b4658cddSJonathan Corbet * '\v' - vertical tab 252b4658cddSJonathan Corbet * UNESCAPE_OCTAL: 253b4658cddSJonathan Corbet * '\NNN' - byte with octal value NNN (1 to 3 digits) 254b4658cddSJonathan Corbet * UNESCAPE_HEX: 255b4658cddSJonathan Corbet * '\xHH' - byte with hexadecimal value HH (1 to 2 digits) 256b4658cddSJonathan Corbet * UNESCAPE_SPECIAL: 257b4658cddSJonathan Corbet * '\"' - double quote 258b4658cddSJonathan Corbet * '\\' - backslash 259b4658cddSJonathan Corbet * '\a' - alert (BEL) 260b4658cddSJonathan Corbet * '\e' - escape 261b4658cddSJonathan Corbet * UNESCAPE_ANY: 262b4658cddSJonathan Corbet * all previous together 263d295634eSAndy Shevchenko * 264d295634eSAndy Shevchenko * Return: 265d295634eSAndy Shevchenko * The amount of the characters processed to the destination buffer excluding 266d295634eSAndy Shevchenko * trailing '\0' is returned. 267d295634eSAndy Shevchenko */ 26816c7fa05SAndy Shevchenko int string_unescape(char *src, char *dst, size_t size, unsigned int flags) 26916c7fa05SAndy Shevchenko { 27016c7fa05SAndy Shevchenko char *out = dst; 27116c7fa05SAndy Shevchenko 27216c7fa05SAndy Shevchenko while (*src && --size) { 27316c7fa05SAndy Shevchenko if (src[0] == '\\' && src[1] != '\0' && size > 1) { 27416c7fa05SAndy Shevchenko src++; 27516c7fa05SAndy Shevchenko size--; 27616c7fa05SAndy Shevchenko 27716c7fa05SAndy Shevchenko if (flags & UNESCAPE_SPACE && 27816c7fa05SAndy Shevchenko unescape_space(&src, &out)) 27916c7fa05SAndy Shevchenko continue; 28016c7fa05SAndy Shevchenko 28116c7fa05SAndy Shevchenko if (flags & UNESCAPE_OCTAL && 28216c7fa05SAndy Shevchenko unescape_octal(&src, &out)) 28316c7fa05SAndy Shevchenko continue; 28416c7fa05SAndy Shevchenko 28516c7fa05SAndy Shevchenko if (flags & UNESCAPE_HEX && 28616c7fa05SAndy Shevchenko unescape_hex(&src, &out)) 28716c7fa05SAndy Shevchenko continue; 28816c7fa05SAndy Shevchenko 28916c7fa05SAndy Shevchenko if (flags & UNESCAPE_SPECIAL && 29016c7fa05SAndy Shevchenko unescape_special(&src, &out)) 29116c7fa05SAndy Shevchenko continue; 29216c7fa05SAndy Shevchenko 29316c7fa05SAndy Shevchenko *out++ = '\\'; 29416c7fa05SAndy Shevchenko } 29516c7fa05SAndy Shevchenko *out++ = *src++; 29616c7fa05SAndy Shevchenko } 29716c7fa05SAndy Shevchenko *out = '\0'; 29816c7fa05SAndy Shevchenko 29916c7fa05SAndy Shevchenko return out - dst; 30016c7fa05SAndy Shevchenko } 30116c7fa05SAndy Shevchenko EXPORT_SYMBOL(string_unescape); 302c8250381SAndy Shevchenko 3033aeddc7dSRasmus Villemoes static bool escape_passthrough(unsigned char c, char **dst, char *end) 304c8250381SAndy Shevchenko { 305c8250381SAndy Shevchenko char *out = *dst; 306c8250381SAndy Shevchenko 3073aeddc7dSRasmus Villemoes if (out < end) 3083aeddc7dSRasmus Villemoes *out = c; 3093aeddc7dSRasmus Villemoes *dst = out + 1; 3103aeddc7dSRasmus Villemoes return true; 311c8250381SAndy Shevchenko } 312c8250381SAndy Shevchenko 3133aeddc7dSRasmus Villemoes static bool escape_space(unsigned char c, char **dst, char *end) 314c8250381SAndy Shevchenko { 315c8250381SAndy Shevchenko char *out = *dst; 316c8250381SAndy Shevchenko unsigned char to; 317c8250381SAndy Shevchenko 318c8250381SAndy Shevchenko switch (c) { 319c8250381SAndy Shevchenko case '\n': 320c8250381SAndy Shevchenko to = 'n'; 321c8250381SAndy Shevchenko break; 322c8250381SAndy Shevchenko case '\r': 323c8250381SAndy Shevchenko to = 'r'; 324c8250381SAndy Shevchenko break; 325c8250381SAndy Shevchenko case '\t': 326c8250381SAndy Shevchenko to = 't'; 327c8250381SAndy Shevchenko break; 328c8250381SAndy Shevchenko case '\v': 329c8250381SAndy Shevchenko to = 'v'; 330c8250381SAndy Shevchenko break; 331c8250381SAndy Shevchenko case '\f': 332c8250381SAndy Shevchenko to = 'f'; 333c8250381SAndy Shevchenko break; 334c8250381SAndy Shevchenko default: 3353aeddc7dSRasmus Villemoes return false; 336c8250381SAndy Shevchenko } 337c8250381SAndy Shevchenko 3383aeddc7dSRasmus Villemoes if (out < end) 3393aeddc7dSRasmus Villemoes *out = '\\'; 3403aeddc7dSRasmus Villemoes ++out; 3413aeddc7dSRasmus Villemoes if (out < end) 3423aeddc7dSRasmus Villemoes *out = to; 3433aeddc7dSRasmus Villemoes ++out; 344c8250381SAndy Shevchenko 345c8250381SAndy Shevchenko *dst = out; 3463aeddc7dSRasmus Villemoes return true; 347c8250381SAndy Shevchenko } 348c8250381SAndy Shevchenko 3493aeddc7dSRasmus Villemoes static bool escape_special(unsigned char c, char **dst, char *end) 350c8250381SAndy Shevchenko { 351c8250381SAndy Shevchenko char *out = *dst; 352c8250381SAndy Shevchenko unsigned char to; 353c8250381SAndy Shevchenko 354c8250381SAndy Shevchenko switch (c) { 355c8250381SAndy Shevchenko case '\\': 356c8250381SAndy Shevchenko to = '\\'; 357c8250381SAndy Shevchenko break; 358c8250381SAndy Shevchenko case '\a': 359c8250381SAndy Shevchenko to = 'a'; 360c8250381SAndy Shevchenko break; 361c8250381SAndy Shevchenko case '\e': 362c8250381SAndy Shevchenko to = 'e'; 363c8250381SAndy Shevchenko break; 36491027d0aSChris Down case '"': 36591027d0aSChris Down to = '"'; 36691027d0aSChris Down break; 367c8250381SAndy Shevchenko default: 3683aeddc7dSRasmus Villemoes return false; 369c8250381SAndy Shevchenko } 370c8250381SAndy Shevchenko 3713aeddc7dSRasmus Villemoes if (out < end) 3723aeddc7dSRasmus Villemoes *out = '\\'; 3733aeddc7dSRasmus Villemoes ++out; 3743aeddc7dSRasmus Villemoes if (out < end) 3753aeddc7dSRasmus Villemoes *out = to; 3763aeddc7dSRasmus Villemoes ++out; 377c8250381SAndy Shevchenko 378c8250381SAndy Shevchenko *dst = out; 3793aeddc7dSRasmus Villemoes return true; 380c8250381SAndy Shevchenko } 381c8250381SAndy Shevchenko 3823aeddc7dSRasmus Villemoes static bool escape_null(unsigned char c, char **dst, char *end) 383c8250381SAndy Shevchenko { 384c8250381SAndy Shevchenko char *out = *dst; 385c8250381SAndy Shevchenko 386c8250381SAndy Shevchenko if (c) 3873aeddc7dSRasmus Villemoes return false; 388c8250381SAndy Shevchenko 3893aeddc7dSRasmus Villemoes if (out < end) 3903aeddc7dSRasmus Villemoes *out = '\\'; 3913aeddc7dSRasmus Villemoes ++out; 3923aeddc7dSRasmus Villemoes if (out < end) 3933aeddc7dSRasmus Villemoes *out = '0'; 3943aeddc7dSRasmus Villemoes ++out; 3953aeddc7dSRasmus Villemoes 3963aeddc7dSRasmus Villemoes *dst = out; 3973aeddc7dSRasmus Villemoes return true; 3983aeddc7dSRasmus Villemoes } 3993aeddc7dSRasmus Villemoes 4003aeddc7dSRasmus Villemoes static bool escape_octal(unsigned char c, char **dst, char *end) 401c8250381SAndy Shevchenko { 402c8250381SAndy Shevchenko char *out = *dst; 403c8250381SAndy Shevchenko 4043aeddc7dSRasmus Villemoes if (out < end) 4053aeddc7dSRasmus Villemoes *out = '\\'; 4063aeddc7dSRasmus Villemoes ++out; 4073aeddc7dSRasmus Villemoes if (out < end) 4083aeddc7dSRasmus Villemoes *out = ((c >> 6) & 0x07) + '0'; 4093aeddc7dSRasmus Villemoes ++out; 4103aeddc7dSRasmus Villemoes if (out < end) 4113aeddc7dSRasmus Villemoes *out = ((c >> 3) & 0x07) + '0'; 4123aeddc7dSRasmus Villemoes ++out; 4133aeddc7dSRasmus Villemoes if (out < end) 4143aeddc7dSRasmus Villemoes *out = ((c >> 0) & 0x07) + '0'; 4153aeddc7dSRasmus Villemoes ++out; 4163aeddc7dSRasmus Villemoes 4173aeddc7dSRasmus Villemoes *dst = out; 4183aeddc7dSRasmus Villemoes return true; 4193aeddc7dSRasmus Villemoes } 4203aeddc7dSRasmus Villemoes 4213aeddc7dSRasmus Villemoes static bool escape_hex(unsigned char c, char **dst, char *end) 422c8250381SAndy Shevchenko { 423c8250381SAndy Shevchenko char *out = *dst; 424c8250381SAndy Shevchenko 4253aeddc7dSRasmus Villemoes if (out < end) 4263aeddc7dSRasmus Villemoes *out = '\\'; 4273aeddc7dSRasmus Villemoes ++out; 4283aeddc7dSRasmus Villemoes if (out < end) 4293aeddc7dSRasmus Villemoes *out = 'x'; 4303aeddc7dSRasmus Villemoes ++out; 4313aeddc7dSRasmus Villemoes if (out < end) 4323aeddc7dSRasmus Villemoes *out = hex_asc_hi(c); 4333aeddc7dSRasmus Villemoes ++out; 4343aeddc7dSRasmus Villemoes if (out < end) 4353aeddc7dSRasmus Villemoes *out = hex_asc_lo(c); 4363aeddc7dSRasmus Villemoes ++out; 437c8250381SAndy Shevchenko 438c8250381SAndy Shevchenko *dst = out; 4393aeddc7dSRasmus Villemoes return true; 440c8250381SAndy Shevchenko } 441c8250381SAndy Shevchenko 442c8250381SAndy Shevchenko /** 443c8250381SAndy Shevchenko * string_escape_mem - quote characters in the given memory buffer 444c8250381SAndy Shevchenko * @src: source buffer (unescaped) 445c8250381SAndy Shevchenko * @isz: source buffer size 446c8250381SAndy Shevchenko * @dst: destination buffer (escaped) 447c8250381SAndy Shevchenko * @osz: destination buffer size 448b4658cddSJonathan Corbet * @flags: combination of the flags 449b4658cddSJonathan Corbet * @only: NULL-terminated string containing characters used to limit 450b4658cddSJonathan Corbet * the selected escape class. If characters are included in @only 451b4658cddSJonathan Corbet * that would not normally be escaped by the classes selected 452b4658cddSJonathan Corbet * in @flags, they will be copied to @dst unescaped. 453b4658cddSJonathan Corbet * 454b4658cddSJonathan Corbet * Description: 455b4658cddSJonathan Corbet * The process of escaping byte buffer includes several parts. They are applied 456b4658cddSJonathan Corbet * in the following sequence. 457b4658cddSJonathan Corbet * 45862519b88SAndy Shevchenko * 1. The character is not matched to the one from @only string and thus 459b4658cddSJonathan Corbet * must go as-is to the output. 4600362c27fSAndy Shevchenko * 2. The character is matched to the printable and ASCII classes, if asked, 461a0809783SAndy Shevchenko * and in case of match it passes through to the output. 4620362c27fSAndy Shevchenko * 3. The character is matched to the printable or ASCII class, if asked, 4630362c27fSAndy Shevchenko * and in case of match it passes through to the output. 4640362c27fSAndy Shevchenko * 4. The character is checked if it falls into the class given by @flags. 465b4658cddSJonathan Corbet * %ESCAPE_OCTAL and %ESCAPE_HEX are going last since they cover any 466b4658cddSJonathan Corbet * character. Note that they actually can't go together, otherwise 467b4658cddSJonathan Corbet * %ESCAPE_HEX will be ignored. 468b4658cddSJonathan Corbet * 469b4658cddSJonathan Corbet * Caller must provide valid source and destination pointers. Be aware that 470b4658cddSJonathan Corbet * destination buffer will not be NULL-terminated, thus caller have to append 471b4658cddSJonathan Corbet * it if needs. The supported flags are:: 472b4658cddSJonathan Corbet * 473d89a3f73SKees Cook * %ESCAPE_SPACE: (special white space, not space itself) 474c8250381SAndy Shevchenko * '\f' - form feed 475c8250381SAndy Shevchenko * '\n' - new line 476c8250381SAndy Shevchenko * '\r' - carriage return 477c8250381SAndy Shevchenko * '\t' - horizontal tab 478c8250381SAndy Shevchenko * '\v' - vertical tab 479c8250381SAndy Shevchenko * %ESCAPE_SPECIAL: 48091027d0aSChris Down * '\"' - double quote 481c8250381SAndy Shevchenko * '\\' - backslash 482c8250381SAndy Shevchenko * '\a' - alert (BEL) 483c8250381SAndy Shevchenko * '\e' - escape 484c8250381SAndy Shevchenko * %ESCAPE_NULL: 485c8250381SAndy Shevchenko * '\0' - null 486c8250381SAndy Shevchenko * %ESCAPE_OCTAL: 487c8250381SAndy Shevchenko * '\NNN' - byte with octal value NNN (3 digits) 488c8250381SAndy Shevchenko * %ESCAPE_ANY: 489c8250381SAndy Shevchenko * all previous together 490c8250381SAndy Shevchenko * %ESCAPE_NP: 491a0809783SAndy Shevchenko * escape only non-printable characters, checked by isprint() 492c8250381SAndy Shevchenko * %ESCAPE_ANY_NP: 493c8250381SAndy Shevchenko * all previous together 494c8250381SAndy Shevchenko * %ESCAPE_HEX: 495c8250381SAndy Shevchenko * '\xHH' - byte with hexadecimal value HH (2 digits) 496a0809783SAndy Shevchenko * %ESCAPE_NA: 497a0809783SAndy Shevchenko * escape only non-ascii characters, checked by isascii() 4980362c27fSAndy Shevchenko * %ESCAPE_NAP: 4990362c27fSAndy Shevchenko * escape only non-printable or non-ascii characters 500aec0d096SAndy Shevchenko * %ESCAPE_APPEND: 501aec0d096SAndy Shevchenko * append characters from @only to be escaped by the given classes 502aec0d096SAndy Shevchenko * 503aec0d096SAndy Shevchenko * %ESCAPE_APPEND would help to pass additional characters to the escaped, when 504aec0d096SAndy Shevchenko * one of %ESCAPE_NP, %ESCAPE_NA, or %ESCAPE_NAP is provided. 505a0809783SAndy Shevchenko * 5060362c27fSAndy Shevchenko * One notable caveat, the %ESCAPE_NAP, %ESCAPE_NP and %ESCAPE_NA have the 5070362c27fSAndy Shevchenko * higher priority than the rest of the flags (%ESCAPE_NAP is the highest). 508a0809783SAndy Shevchenko * It doesn't make much sense to use either of them without %ESCAPE_OCTAL 509a0809783SAndy Shevchenko * or %ESCAPE_HEX, because they cover most of the other character classes. 5100362c27fSAndy Shevchenko * %ESCAPE_NAP can utilize %ESCAPE_SPACE or %ESCAPE_SPECIAL in addition to 5110362c27fSAndy Shevchenko * the above. 512c8250381SAndy Shevchenko * 513c8250381SAndy Shevchenko * Return: 51441416f23SRasmus Villemoes * The total size of the escaped output that would be generated for 51541416f23SRasmus Villemoes * the given input and flags. To check whether the output was 51641416f23SRasmus Villemoes * truncated, compare the return value to osz. There is room left in 51741416f23SRasmus Villemoes * dst for a '\0' terminator if and only if ret < osz. 518c8250381SAndy Shevchenko */ 51941416f23SRasmus Villemoes int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz, 520b40bdb7fSKees Cook unsigned int flags, const char *only) 521c8250381SAndy Shevchenko { 52241416f23SRasmus Villemoes char *p = dst; 5233aeddc7dSRasmus Villemoes char *end = p + osz; 524b40bdb7fSKees Cook bool is_dict = only && *only; 525aec0d096SAndy Shevchenko bool is_append = flags & ESCAPE_APPEND; 526c8250381SAndy Shevchenko 527c8250381SAndy Shevchenko while (isz--) { 528c8250381SAndy Shevchenko unsigned char c = *src++; 529aec0d096SAndy Shevchenko bool in_dict = is_dict && strchr(only, c); 530c8250381SAndy Shevchenko 531c8250381SAndy Shevchenko /* 532c8250381SAndy Shevchenko * Apply rules in the following sequence: 533b40bdb7fSKees Cook * - the @only string is supplied and does not contain a 534c8250381SAndy Shevchenko * character under question 5350362c27fSAndy Shevchenko * - the character is printable and ASCII, when @flags has 5360362c27fSAndy Shevchenko * %ESCAPE_NAP bit set 53762519b88SAndy Shevchenko * - the character is printable, when @flags has 53862519b88SAndy Shevchenko * %ESCAPE_NP bit set 539a0809783SAndy Shevchenko * - the character is ASCII, when @flags has 540a0809783SAndy Shevchenko * %ESCAPE_NA bit set 541c8250381SAndy Shevchenko * - the character doesn't fall into a class of symbols 542c8250381SAndy Shevchenko * defined by given @flags 543c8250381SAndy Shevchenko * In these cases we just pass through a character to the 544c8250381SAndy Shevchenko * output buffer. 545aec0d096SAndy Shevchenko * 546aec0d096SAndy Shevchenko * When %ESCAPE_APPEND is passed, the characters from @only 547aec0d096SAndy Shevchenko * have been excluded from the %ESCAPE_NAP, %ESCAPE_NP, and 548aec0d096SAndy Shevchenko * %ESCAPE_NA cases. 549c8250381SAndy Shevchenko */ 550aec0d096SAndy Shevchenko if (!(is_append || in_dict) && is_dict && 5517e5969aeSAndy Shevchenko escape_passthrough(c, &p, end)) 5527e5969aeSAndy Shevchenko continue; 5537e5969aeSAndy Shevchenko 554aec0d096SAndy Shevchenko if (!(is_append && in_dict) && isascii(c) && isprint(c) && 5550362c27fSAndy Shevchenko flags & ESCAPE_NAP && escape_passthrough(c, &p, end)) 5560362c27fSAndy Shevchenko continue; 5570362c27fSAndy Shevchenko 558aec0d096SAndy Shevchenko if (!(is_append && in_dict) && isprint(c) && 55962519b88SAndy Shevchenko flags & ESCAPE_NP && escape_passthrough(c, &p, end)) 56062519b88SAndy Shevchenko continue; 56162519b88SAndy Shevchenko 562aec0d096SAndy Shevchenko if (!(is_append && in_dict) && isascii(c) && 563a0809783SAndy Shevchenko flags & ESCAPE_NA && escape_passthrough(c, &p, end)) 564a0809783SAndy Shevchenko continue; 565a0809783SAndy Shevchenko 5663aeddc7dSRasmus Villemoes if (flags & ESCAPE_SPACE && escape_space(c, &p, end)) 567c8250381SAndy Shevchenko continue; 568c8250381SAndy Shevchenko 5693aeddc7dSRasmus Villemoes if (flags & ESCAPE_SPECIAL && escape_special(c, &p, end)) 570c8250381SAndy Shevchenko continue; 571c8250381SAndy Shevchenko 5723aeddc7dSRasmus Villemoes if (flags & ESCAPE_NULL && escape_null(c, &p, end)) 573c8250381SAndy Shevchenko continue; 574c8250381SAndy Shevchenko 575c8250381SAndy Shevchenko /* ESCAPE_OCTAL and ESCAPE_HEX always go last */ 5763aeddc7dSRasmus Villemoes if (flags & ESCAPE_OCTAL && escape_octal(c, &p, end)) 5773aeddc7dSRasmus Villemoes continue; 5783aeddc7dSRasmus Villemoes 5793aeddc7dSRasmus Villemoes if (flags & ESCAPE_HEX && escape_hex(c, &p, end)) 580c8250381SAndy Shevchenko continue; 5813aeddc7dSRasmus Villemoes 5823aeddc7dSRasmus Villemoes escape_passthrough(c, &p, end); 583c8250381SAndy Shevchenko } 584c8250381SAndy Shevchenko 58541416f23SRasmus Villemoes return p - dst; 586c8250381SAndy Shevchenko } 587c8250381SAndy Shevchenko EXPORT_SYMBOL(string_escape_mem); 588b53f27e4SKees Cook 589b53f27e4SKees Cook /* 590b53f27e4SKees Cook * Return an allocated string that has been escaped of special characters 591b53f27e4SKees Cook * and double quotes, making it safe to log in quotes. 592b53f27e4SKees Cook */ 593b53f27e4SKees Cook char *kstrdup_quotable(const char *src, gfp_t gfp) 594b53f27e4SKees Cook { 595b53f27e4SKees Cook size_t slen, dlen; 596b53f27e4SKees Cook char *dst; 597b53f27e4SKees Cook const int flags = ESCAPE_HEX; 598b53f27e4SKees Cook const char esc[] = "\f\n\r\t\v\a\e\\\""; 599b53f27e4SKees Cook 600b53f27e4SKees Cook if (!src) 601b53f27e4SKees Cook return NULL; 602b53f27e4SKees Cook slen = strlen(src); 603b53f27e4SKees Cook 604b53f27e4SKees Cook dlen = string_escape_mem(src, slen, NULL, 0, flags, esc); 605b53f27e4SKees Cook dst = kmalloc(dlen + 1, gfp); 606b53f27e4SKees Cook if (!dst) 607b53f27e4SKees Cook return NULL; 608b53f27e4SKees Cook 609b53f27e4SKees Cook WARN_ON(string_escape_mem(src, slen, dst, dlen, flags, esc) != dlen); 610b53f27e4SKees Cook dst[dlen] = '\0'; 611b53f27e4SKees Cook 612b53f27e4SKees Cook return dst; 613b53f27e4SKees Cook } 614b53f27e4SKees Cook EXPORT_SYMBOL_GPL(kstrdup_quotable); 6150d044328SKees Cook 6160d044328SKees Cook /* 6170d044328SKees Cook * Returns allocated NULL-terminated string containing process 6180d044328SKees Cook * command line, with inter-argument NULLs replaced with spaces, 6190d044328SKees Cook * and other special characters escaped. 6200d044328SKees Cook */ 6210d044328SKees Cook char *kstrdup_quotable_cmdline(struct task_struct *task, gfp_t gfp) 6220d044328SKees Cook { 6230d044328SKees Cook char *buffer, *quoted; 6240d044328SKees Cook int i, res; 6250d044328SKees Cook 6260ee931c4SMichal Hocko buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); 6270d044328SKees Cook if (!buffer) 6280d044328SKees Cook return NULL; 6290d044328SKees Cook 6300d044328SKees Cook res = get_cmdline(task, buffer, PAGE_SIZE - 1); 6310d044328SKees Cook buffer[res] = '\0'; 6320d044328SKees Cook 6330d044328SKees Cook /* Collapse trailing NULLs, leave res pointing to last non-NULL. */ 6340d044328SKees Cook while (--res >= 0 && buffer[res] == '\0') 6350d044328SKees Cook ; 6360d044328SKees Cook 6370d044328SKees Cook /* Replace inter-argument NULLs. */ 6380d044328SKees Cook for (i = 0; i <= res; i++) 6390d044328SKees Cook if (buffer[i] == '\0') 6400d044328SKees Cook buffer[i] = ' '; 6410d044328SKees Cook 6420d044328SKees Cook /* Make sure result is printable. */ 6430d044328SKees Cook quoted = kstrdup_quotable(buffer, gfp); 6440d044328SKees Cook kfree(buffer); 6450d044328SKees Cook return quoted; 6460d044328SKees Cook } 6470d044328SKees Cook EXPORT_SYMBOL_GPL(kstrdup_quotable_cmdline); 64821985319SKees Cook 64921985319SKees Cook /* 65021985319SKees Cook * Returns allocated NULL-terminated string containing pathname, 65121985319SKees Cook * with special characters escaped, able to be safely logged. If 65221985319SKees Cook * there is an error, the leading character will be "<". 65321985319SKees Cook */ 65421985319SKees Cook char *kstrdup_quotable_file(struct file *file, gfp_t gfp) 65521985319SKees Cook { 65621985319SKees Cook char *temp, *pathname; 65721985319SKees Cook 65821985319SKees Cook if (!file) 65921985319SKees Cook return kstrdup("<unknown>", gfp); 66021985319SKees Cook 66121985319SKees Cook /* We add 11 spaces for ' (deleted)' to be appended */ 6620ee931c4SMichal Hocko temp = kmalloc(PATH_MAX + 11, GFP_KERNEL); 66321985319SKees Cook if (!temp) 66421985319SKees Cook return kstrdup("<no_memory>", gfp); 66521985319SKees Cook 66621985319SKees Cook pathname = file_path(file, temp, PATH_MAX + 11); 66721985319SKees Cook if (IS_ERR(pathname)) 66821985319SKees Cook pathname = kstrdup("<too_long>", gfp); 66921985319SKees Cook else 67021985319SKees Cook pathname = kstrdup_quotable(pathname, gfp); 67121985319SKees Cook 67221985319SKees Cook kfree(temp); 67321985319SKees Cook return pathname; 67421985319SKees Cook } 67521985319SKees Cook EXPORT_SYMBOL_GPL(kstrdup_quotable_file); 6760fd16012SBartosz Golaszewski 6770fd16012SBartosz Golaszewski /** 6780fd16012SBartosz Golaszewski * kfree_strarray - free a number of dynamically allocated strings contained 6790fd16012SBartosz Golaszewski * in an array and the array itself 6800fd16012SBartosz Golaszewski * 6810fd16012SBartosz Golaszewski * @array: Dynamically allocated array of strings to free. 6820fd16012SBartosz Golaszewski * @n: Number of strings (starting from the beginning of the array) to free. 6830fd16012SBartosz Golaszewski * 6840fd16012SBartosz Golaszewski * Passing a non-NULL @array and @n == 0 as well as NULL @array are valid 6850fd16012SBartosz Golaszewski * use-cases. If @array is NULL, the function does nothing. 6860fd16012SBartosz Golaszewski */ 6870fd16012SBartosz Golaszewski void kfree_strarray(char **array, size_t n) 6880fd16012SBartosz Golaszewski { 6890fd16012SBartosz Golaszewski unsigned int i; 6900fd16012SBartosz Golaszewski 6910fd16012SBartosz Golaszewski if (!array) 6920fd16012SBartosz Golaszewski return; 6930fd16012SBartosz Golaszewski 6940fd16012SBartosz Golaszewski for (i = 0; i < n; i++) 6950fd16012SBartosz Golaszewski kfree(array[i]); 6960fd16012SBartosz Golaszewski kfree(array); 6970fd16012SBartosz Golaszewski } 6980fd16012SBartosz Golaszewski EXPORT_SYMBOL_GPL(kfree_strarray); 699cfecea6eSKees Cook 700cfecea6eSKees Cook /** 701cfecea6eSKees Cook * strscpy_pad() - Copy a C-string into a sized buffer 702cfecea6eSKees Cook * @dest: Where to copy the string to 703cfecea6eSKees Cook * @src: Where to copy the string from 704cfecea6eSKees Cook * @count: Size of destination buffer 705cfecea6eSKees Cook * 706cfecea6eSKees Cook * Copy the string, or as much of it as fits, into the dest buffer. The 707cfecea6eSKees Cook * behavior is undefined if the string buffers overlap. The destination 708cfecea6eSKees Cook * buffer is always %NUL terminated, unless it's zero-sized. 709cfecea6eSKees Cook * 710cfecea6eSKees Cook * If the source string is shorter than the destination buffer, zeros 711cfecea6eSKees Cook * the tail of the destination buffer. 712cfecea6eSKees Cook * 713cfecea6eSKees Cook * For full explanation of why you may want to consider using the 714cfecea6eSKees Cook * 'strscpy' functions please see the function docstring for strscpy(). 715cfecea6eSKees Cook * 716cfecea6eSKees Cook * Returns: 717cfecea6eSKees Cook * * The number of characters copied (not including the trailing %NUL) 718cfecea6eSKees Cook * * -E2BIG if count is 0 or @src was truncated. 719cfecea6eSKees Cook */ 720cfecea6eSKees Cook ssize_t strscpy_pad(char *dest, const char *src, size_t count) 721cfecea6eSKees Cook { 722cfecea6eSKees Cook ssize_t written; 723cfecea6eSKees Cook 724cfecea6eSKees Cook written = strscpy(dest, src, count); 725cfecea6eSKees Cook if (written < 0 || written == count - 1) 726cfecea6eSKees Cook return written; 727cfecea6eSKees Cook 728cfecea6eSKees Cook memset(dest + written + 1, 0, count - written - 1); 729cfecea6eSKees Cook 730cfecea6eSKees Cook return written; 731cfecea6eSKees Cook } 732cfecea6eSKees Cook EXPORT_SYMBOL(strscpy_pad); 733cfecea6eSKees Cook 734cfecea6eSKees Cook /** 735cfecea6eSKees Cook * skip_spaces - Removes leading whitespace from @str. 736cfecea6eSKees Cook * @str: The string to be stripped. 737cfecea6eSKees Cook * 738cfecea6eSKees Cook * Returns a pointer to the first non-whitespace character in @str. 739cfecea6eSKees Cook */ 740cfecea6eSKees Cook char *skip_spaces(const char *str) 741cfecea6eSKees Cook { 742cfecea6eSKees Cook while (isspace(*str)) 743cfecea6eSKees Cook ++str; 744cfecea6eSKees Cook return (char *)str; 745cfecea6eSKees Cook } 746cfecea6eSKees Cook EXPORT_SYMBOL(skip_spaces); 747cfecea6eSKees Cook 748cfecea6eSKees Cook /** 749cfecea6eSKees Cook * strim - Removes leading and trailing whitespace from @s. 750cfecea6eSKees Cook * @s: The string to be stripped. 751cfecea6eSKees Cook * 752cfecea6eSKees Cook * Note that the first trailing whitespace is replaced with a %NUL-terminator 753cfecea6eSKees Cook * in the given string @s. Returns a pointer to the first non-whitespace 754cfecea6eSKees Cook * character in @s. 755cfecea6eSKees Cook */ 756cfecea6eSKees Cook char *strim(char *s) 757cfecea6eSKees Cook { 758cfecea6eSKees Cook size_t size; 759cfecea6eSKees Cook char *end; 760cfecea6eSKees Cook 761cfecea6eSKees Cook size = strlen(s); 762cfecea6eSKees Cook if (!size) 763cfecea6eSKees Cook return s; 764cfecea6eSKees Cook 765cfecea6eSKees Cook end = s + size - 1; 766cfecea6eSKees Cook while (end >= s && isspace(*end)) 767cfecea6eSKees Cook end--; 768cfecea6eSKees Cook *(end + 1) = '\0'; 769cfecea6eSKees Cook 770cfecea6eSKees Cook return skip_spaces(s); 771cfecea6eSKees Cook } 772cfecea6eSKees Cook EXPORT_SYMBOL(strim); 773cfecea6eSKees Cook 774cfecea6eSKees Cook /** 775cfecea6eSKees Cook * sysfs_streq - return true if strings are equal, modulo trailing newline 776cfecea6eSKees Cook * @s1: one string 777cfecea6eSKees Cook * @s2: another string 778cfecea6eSKees Cook * 779cfecea6eSKees Cook * This routine returns true iff two strings are equal, treating both 780cfecea6eSKees Cook * NUL and newline-then-NUL as equivalent string terminations. It's 781cfecea6eSKees Cook * geared for use with sysfs input strings, which generally terminate 782cfecea6eSKees Cook * with newlines but are compared against values without newlines. 783cfecea6eSKees Cook */ 784cfecea6eSKees Cook bool sysfs_streq(const char *s1, const char *s2) 785cfecea6eSKees Cook { 786cfecea6eSKees Cook while (*s1 && *s1 == *s2) { 787cfecea6eSKees Cook s1++; 788cfecea6eSKees Cook s2++; 789cfecea6eSKees Cook } 790cfecea6eSKees Cook 791cfecea6eSKees Cook if (*s1 == *s2) 792cfecea6eSKees Cook return true; 793cfecea6eSKees Cook if (!*s1 && *s2 == '\n' && !s2[1]) 794cfecea6eSKees Cook return true; 795cfecea6eSKees Cook if (*s1 == '\n' && !s1[1] && !*s2) 796cfecea6eSKees Cook return true; 797cfecea6eSKees Cook return false; 798cfecea6eSKees Cook } 799cfecea6eSKees Cook EXPORT_SYMBOL(sysfs_streq); 800cfecea6eSKees Cook 801cfecea6eSKees Cook /** 802cfecea6eSKees Cook * match_string - matches given string in an array 803cfecea6eSKees Cook * @array: array of strings 804cfecea6eSKees Cook * @n: number of strings in the array or -1 for NULL terminated arrays 805cfecea6eSKees Cook * @string: string to match with 806cfecea6eSKees Cook * 807cfecea6eSKees Cook * This routine will look for a string in an array of strings up to the 808cfecea6eSKees Cook * n-th element in the array or until the first NULL element. 809cfecea6eSKees Cook * 810cfecea6eSKees Cook * Historically the value of -1 for @n, was used to search in arrays that 811cfecea6eSKees Cook * are NULL terminated. However, the function does not make a distinction 812cfecea6eSKees Cook * when finishing the search: either @n elements have been compared OR 813cfecea6eSKees Cook * the first NULL element was found. 814cfecea6eSKees Cook * 815cfecea6eSKees Cook * Return: 816cfecea6eSKees Cook * index of a @string in the @array if matches, or %-EINVAL otherwise. 817cfecea6eSKees Cook */ 818cfecea6eSKees Cook int match_string(const char * const *array, size_t n, const char *string) 819cfecea6eSKees Cook { 820cfecea6eSKees Cook int index; 821cfecea6eSKees Cook const char *item; 822cfecea6eSKees Cook 823cfecea6eSKees Cook for (index = 0; index < n; index++) { 824cfecea6eSKees Cook item = array[index]; 825cfecea6eSKees Cook if (!item) 826cfecea6eSKees Cook break; 827cfecea6eSKees Cook if (!strcmp(item, string)) 828cfecea6eSKees Cook return index; 829cfecea6eSKees Cook } 830cfecea6eSKees Cook 831cfecea6eSKees Cook return -EINVAL; 832cfecea6eSKees Cook } 833cfecea6eSKees Cook EXPORT_SYMBOL(match_string); 834cfecea6eSKees Cook 835cfecea6eSKees Cook /** 836cfecea6eSKees Cook * __sysfs_match_string - matches given string in an array 837cfecea6eSKees Cook * @array: array of strings 838cfecea6eSKees Cook * @n: number of strings in the array or -1 for NULL terminated arrays 839cfecea6eSKees Cook * @str: string to match with 840cfecea6eSKees Cook * 841cfecea6eSKees Cook * Returns index of @str in the @array or -EINVAL, just like match_string(). 842cfecea6eSKees Cook * Uses sysfs_streq instead of strcmp for matching. 843cfecea6eSKees Cook * 844cfecea6eSKees Cook * This routine will look for a string in an array of strings up to the 845cfecea6eSKees Cook * n-th element in the array or until the first NULL element. 846cfecea6eSKees Cook * 847cfecea6eSKees Cook * Historically the value of -1 for @n, was used to search in arrays that 848cfecea6eSKees Cook * are NULL terminated. However, the function does not make a distinction 849cfecea6eSKees Cook * when finishing the search: either @n elements have been compared OR 850cfecea6eSKees Cook * the first NULL element was found. 851cfecea6eSKees Cook */ 852cfecea6eSKees Cook int __sysfs_match_string(const char * const *array, size_t n, const char *str) 853cfecea6eSKees Cook { 854cfecea6eSKees Cook const char *item; 855cfecea6eSKees Cook int index; 856cfecea6eSKees Cook 857cfecea6eSKees Cook for (index = 0; index < n; index++) { 858cfecea6eSKees Cook item = array[index]; 859cfecea6eSKees Cook if (!item) 860cfecea6eSKees Cook break; 861cfecea6eSKees Cook if (sysfs_streq(item, str)) 862cfecea6eSKees Cook return index; 863cfecea6eSKees Cook } 864cfecea6eSKees Cook 865cfecea6eSKees Cook return -EINVAL; 866cfecea6eSKees Cook } 867cfecea6eSKees Cook EXPORT_SYMBOL(__sysfs_match_string); 868cfecea6eSKees Cook 869cfecea6eSKees Cook /** 870cfecea6eSKees Cook * strreplace - Replace all occurrences of character in string. 871cfecea6eSKees Cook * @s: The string to operate on. 872cfecea6eSKees Cook * @old: The character being replaced. 873cfecea6eSKees Cook * @new: The character @old is replaced with. 874cfecea6eSKees Cook * 875cfecea6eSKees Cook * Returns pointer to the nul byte at the end of @s. 876cfecea6eSKees Cook */ 877cfecea6eSKees Cook char *strreplace(char *s, char old, char new) 878cfecea6eSKees Cook { 879cfecea6eSKees Cook for (; *s; ++s) 880cfecea6eSKees Cook if (*s == old) 881cfecea6eSKees Cook *s = new; 882cfecea6eSKees Cook return s; 883cfecea6eSKees Cook } 884cfecea6eSKees Cook EXPORT_SYMBOL(strreplace); 885cfecea6eSKees Cook 886*c430f600SKees Cook #ifdef CONFIG_FORTIFY_SOURCE 887cfecea6eSKees Cook void fortify_panic(const char *name) 888cfecea6eSKees Cook { 889cfecea6eSKees Cook pr_emerg("detected buffer overflow in %s\n", name); 890cfecea6eSKees Cook BUG(); 891cfecea6eSKees Cook } 892cfecea6eSKees Cook EXPORT_SYMBOL(fortify_panic); 893*c430f600SKees Cook #endif /* CONFIG_FORTIFY_SOURCE */ 894