18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Helpers for formatting and printing strings
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 31 August 2008 James Bottomley
68c2ecf20Sopenharmony_ci * Copyright (C) 2013, Intel Corporation
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#include <linux/bug.h>
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/math64.h>
118c2ecf20Sopenharmony_ci#include <linux/export.h>
128c2ecf20Sopenharmony_ci#include <linux/ctype.h>
138c2ecf20Sopenharmony_ci#include <linux/errno.h>
148c2ecf20Sopenharmony_ci#include <linux/fs.h>
158c2ecf20Sopenharmony_ci#include <linux/limits.h>
168c2ecf20Sopenharmony_ci#include <linux/mm.h>
178c2ecf20Sopenharmony_ci#include <linux/slab.h>
188c2ecf20Sopenharmony_ci#include <linux/string.h>
198c2ecf20Sopenharmony_ci#include <linux/string_helpers.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/**
228c2ecf20Sopenharmony_ci * string_get_size - get the size in the specified units
238c2ecf20Sopenharmony_ci * @size:	The size to be converted in blocks
248c2ecf20Sopenharmony_ci * @blk_size:	Size of the block (use 1 for size in bytes)
258c2ecf20Sopenharmony_ci * @units:	units to use (powers of 1000 or 1024)
268c2ecf20Sopenharmony_ci * @buf:	buffer to format to
278c2ecf20Sopenharmony_ci * @len:	length of buffer
288c2ecf20Sopenharmony_ci *
298c2ecf20Sopenharmony_ci * This function returns a string formatted to 3 significant figures
308c2ecf20Sopenharmony_ci * giving the size in the required units.  @buf should have room for
318c2ecf20Sopenharmony_ci * at least 9 bytes and will always be zero terminated.
328c2ecf20Sopenharmony_ci *
338c2ecf20Sopenharmony_ci */
348c2ecf20Sopenharmony_civoid string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
358c2ecf20Sopenharmony_ci		     char *buf, int len)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	static const char *const units_10[] = {
388c2ecf20Sopenharmony_ci		"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"
398c2ecf20Sopenharmony_ci	};
408c2ecf20Sopenharmony_ci	static const char *const units_2[] = {
418c2ecf20Sopenharmony_ci		"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"
428c2ecf20Sopenharmony_ci	};
438c2ecf20Sopenharmony_ci	static const char *const *const units_str[] = {
448c2ecf20Sopenharmony_ci		[STRING_UNITS_10] = units_10,
458c2ecf20Sopenharmony_ci		[STRING_UNITS_2] = units_2,
468c2ecf20Sopenharmony_ci	};
478c2ecf20Sopenharmony_ci	static const unsigned int divisor[] = {
488c2ecf20Sopenharmony_ci		[STRING_UNITS_10] = 1000,
498c2ecf20Sopenharmony_ci		[STRING_UNITS_2] = 1024,
508c2ecf20Sopenharmony_ci	};
518c2ecf20Sopenharmony_ci	static const unsigned int rounding[] = { 500, 50, 5 };
528c2ecf20Sopenharmony_ci	int i = 0, j;
538c2ecf20Sopenharmony_ci	u32 remainder = 0, sf_cap;
548c2ecf20Sopenharmony_ci	char tmp[8];
558c2ecf20Sopenharmony_ci	const char *unit;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	tmp[0] = '\0';
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	if (blk_size == 0)
608c2ecf20Sopenharmony_ci		size = 0;
618c2ecf20Sopenharmony_ci	if (size == 0)
628c2ecf20Sopenharmony_ci		goto out;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	/* This is Napier's algorithm.  Reduce the original block size to
658c2ecf20Sopenharmony_ci	 *
668c2ecf20Sopenharmony_ci	 * coefficient * divisor[units]^i
678c2ecf20Sopenharmony_ci	 *
688c2ecf20Sopenharmony_ci	 * we do the reduction so both coefficients are just under 32 bits so
698c2ecf20Sopenharmony_ci	 * that multiplying them together won't overflow 64 bits and we keep
708c2ecf20Sopenharmony_ci	 * as much precision as possible in the numbers.
718c2ecf20Sopenharmony_ci	 *
728c2ecf20Sopenharmony_ci	 * Note: it's safe to throw away the remainders here because all the
738c2ecf20Sopenharmony_ci	 * precision is in the coefficients.
748c2ecf20Sopenharmony_ci	 */
758c2ecf20Sopenharmony_ci	while (blk_size >> 32) {
768c2ecf20Sopenharmony_ci		do_div(blk_size, divisor[units]);
778c2ecf20Sopenharmony_ci		i++;
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	while (size >> 32) {
818c2ecf20Sopenharmony_ci		do_div(size, divisor[units]);
828c2ecf20Sopenharmony_ci		i++;
838c2ecf20Sopenharmony_ci	}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	/* now perform the actual multiplication keeping i as the sum of the
868c2ecf20Sopenharmony_ci	 * two logarithms */
878c2ecf20Sopenharmony_ci	size *= blk_size;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	/* and logarithmically reduce it until it's just under the divisor */
908c2ecf20Sopenharmony_ci	while (size >= divisor[units]) {
918c2ecf20Sopenharmony_ci		remainder = do_div(size, divisor[units]);
928c2ecf20Sopenharmony_ci		i++;
938c2ecf20Sopenharmony_ci	}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	/* work out in j how many digits of precision we need from the
968c2ecf20Sopenharmony_ci	 * remainder */
978c2ecf20Sopenharmony_ci	sf_cap = size;
988c2ecf20Sopenharmony_ci	for (j = 0; sf_cap*10 < 1000; j++)
998c2ecf20Sopenharmony_ci		sf_cap *= 10;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	if (units == STRING_UNITS_2) {
1028c2ecf20Sopenharmony_ci		/* express the remainder as a decimal.  It's currently the
1038c2ecf20Sopenharmony_ci		 * numerator of a fraction whose denominator is
1048c2ecf20Sopenharmony_ci		 * divisor[units], which is 1 << 10 for STRING_UNITS_2 */
1058c2ecf20Sopenharmony_ci		remainder *= 1000;
1068c2ecf20Sopenharmony_ci		remainder >>= 10;
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	/* add a 5 to the digit below what will be printed to ensure
1108c2ecf20Sopenharmony_ci	 * an arithmetical round up and carry it through to size */
1118c2ecf20Sopenharmony_ci	remainder += rounding[j];
1128c2ecf20Sopenharmony_ci	if (remainder >= 1000) {
1138c2ecf20Sopenharmony_ci		remainder -= 1000;
1148c2ecf20Sopenharmony_ci		size += 1;
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	if (j) {
1188c2ecf20Sopenharmony_ci		snprintf(tmp, sizeof(tmp), ".%03u", remainder);
1198c2ecf20Sopenharmony_ci		tmp[j+1] = '\0';
1208c2ecf20Sopenharmony_ci	}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci out:
1238c2ecf20Sopenharmony_ci	if (i >= ARRAY_SIZE(units_2))
1248c2ecf20Sopenharmony_ci		unit = "UNK";
1258c2ecf20Sopenharmony_ci	else
1268c2ecf20Sopenharmony_ci		unit = units_str[units][i];
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	snprintf(buf, len, "%u%s %s", (u32)size,
1298c2ecf20Sopenharmony_ci		 tmp, unit);
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(string_get_size);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic bool unescape_space(char **src, char **dst)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	char *p = *dst, *q = *src;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	switch (*q) {
1388c2ecf20Sopenharmony_ci	case 'n':
1398c2ecf20Sopenharmony_ci		*p = '\n';
1408c2ecf20Sopenharmony_ci		break;
1418c2ecf20Sopenharmony_ci	case 'r':
1428c2ecf20Sopenharmony_ci		*p = '\r';
1438c2ecf20Sopenharmony_ci		break;
1448c2ecf20Sopenharmony_ci	case 't':
1458c2ecf20Sopenharmony_ci		*p = '\t';
1468c2ecf20Sopenharmony_ci		break;
1478c2ecf20Sopenharmony_ci	case 'v':
1488c2ecf20Sopenharmony_ci		*p = '\v';
1498c2ecf20Sopenharmony_ci		break;
1508c2ecf20Sopenharmony_ci	case 'f':
1518c2ecf20Sopenharmony_ci		*p = '\f';
1528c2ecf20Sopenharmony_ci		break;
1538c2ecf20Sopenharmony_ci	default:
1548c2ecf20Sopenharmony_ci		return false;
1558c2ecf20Sopenharmony_ci	}
1568c2ecf20Sopenharmony_ci	*dst += 1;
1578c2ecf20Sopenharmony_ci	*src += 1;
1588c2ecf20Sopenharmony_ci	return true;
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic bool unescape_octal(char **src, char **dst)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	char *p = *dst, *q = *src;
1648c2ecf20Sopenharmony_ci	u8 num;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	if (isodigit(*q) == 0)
1678c2ecf20Sopenharmony_ci		return false;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	num = (*q++) & 7;
1708c2ecf20Sopenharmony_ci	while (num < 32 && isodigit(*q) && (q - *src < 3)) {
1718c2ecf20Sopenharmony_ci		num <<= 3;
1728c2ecf20Sopenharmony_ci		num += (*q++) & 7;
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci	*p = num;
1758c2ecf20Sopenharmony_ci	*dst += 1;
1768c2ecf20Sopenharmony_ci	*src = q;
1778c2ecf20Sopenharmony_ci	return true;
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistatic bool unescape_hex(char **src, char **dst)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	char *p = *dst, *q = *src;
1838c2ecf20Sopenharmony_ci	int digit;
1848c2ecf20Sopenharmony_ci	u8 num;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	if (*q++ != 'x')
1878c2ecf20Sopenharmony_ci		return false;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	num = digit = hex_to_bin(*q++);
1908c2ecf20Sopenharmony_ci	if (digit < 0)
1918c2ecf20Sopenharmony_ci		return false;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	digit = hex_to_bin(*q);
1948c2ecf20Sopenharmony_ci	if (digit >= 0) {
1958c2ecf20Sopenharmony_ci		q++;
1968c2ecf20Sopenharmony_ci		num = (num << 4) | digit;
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci	*p = num;
1998c2ecf20Sopenharmony_ci	*dst += 1;
2008c2ecf20Sopenharmony_ci	*src = q;
2018c2ecf20Sopenharmony_ci	return true;
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic bool unescape_special(char **src, char **dst)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	char *p = *dst, *q = *src;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	switch (*q) {
2098c2ecf20Sopenharmony_ci	case '\"':
2108c2ecf20Sopenharmony_ci		*p = '\"';
2118c2ecf20Sopenharmony_ci		break;
2128c2ecf20Sopenharmony_ci	case '\\':
2138c2ecf20Sopenharmony_ci		*p = '\\';
2148c2ecf20Sopenharmony_ci		break;
2158c2ecf20Sopenharmony_ci	case 'a':
2168c2ecf20Sopenharmony_ci		*p = '\a';
2178c2ecf20Sopenharmony_ci		break;
2188c2ecf20Sopenharmony_ci	case 'e':
2198c2ecf20Sopenharmony_ci		*p = '\e';
2208c2ecf20Sopenharmony_ci		break;
2218c2ecf20Sopenharmony_ci	default:
2228c2ecf20Sopenharmony_ci		return false;
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci	*dst += 1;
2258c2ecf20Sopenharmony_ci	*src += 1;
2268c2ecf20Sopenharmony_ci	return true;
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci/**
2308c2ecf20Sopenharmony_ci * string_unescape - unquote characters in the given string
2318c2ecf20Sopenharmony_ci * @src:	source buffer (escaped)
2328c2ecf20Sopenharmony_ci * @dst:	destination buffer (unescaped)
2338c2ecf20Sopenharmony_ci * @size:	size of the destination buffer (0 to unlimit)
2348c2ecf20Sopenharmony_ci * @flags:	combination of the flags.
2358c2ecf20Sopenharmony_ci *
2368c2ecf20Sopenharmony_ci * Description:
2378c2ecf20Sopenharmony_ci * The function unquotes characters in the given string.
2388c2ecf20Sopenharmony_ci *
2398c2ecf20Sopenharmony_ci * Because the size of the output will be the same as or less than the size of
2408c2ecf20Sopenharmony_ci * the input, the transformation may be performed in place.
2418c2ecf20Sopenharmony_ci *
2428c2ecf20Sopenharmony_ci * Caller must provide valid source and destination pointers. Be aware that
2438c2ecf20Sopenharmony_ci * destination buffer will always be NULL-terminated. Source string must be
2448c2ecf20Sopenharmony_ci * NULL-terminated as well.  The supported flags are::
2458c2ecf20Sopenharmony_ci *
2468c2ecf20Sopenharmony_ci *	UNESCAPE_SPACE:
2478c2ecf20Sopenharmony_ci *		'\f' - form feed
2488c2ecf20Sopenharmony_ci *		'\n' - new line
2498c2ecf20Sopenharmony_ci *		'\r' - carriage return
2508c2ecf20Sopenharmony_ci *		'\t' - horizontal tab
2518c2ecf20Sopenharmony_ci *		'\v' - vertical tab
2528c2ecf20Sopenharmony_ci *	UNESCAPE_OCTAL:
2538c2ecf20Sopenharmony_ci *		'\NNN' - byte with octal value NNN (1 to 3 digits)
2548c2ecf20Sopenharmony_ci *	UNESCAPE_HEX:
2558c2ecf20Sopenharmony_ci *		'\xHH' - byte with hexadecimal value HH (1 to 2 digits)
2568c2ecf20Sopenharmony_ci *	UNESCAPE_SPECIAL:
2578c2ecf20Sopenharmony_ci *		'\"' - double quote
2588c2ecf20Sopenharmony_ci *		'\\' - backslash
2598c2ecf20Sopenharmony_ci *		'\a' - alert (BEL)
2608c2ecf20Sopenharmony_ci *		'\e' - escape
2618c2ecf20Sopenharmony_ci *	UNESCAPE_ANY:
2628c2ecf20Sopenharmony_ci *		all previous together
2638c2ecf20Sopenharmony_ci *
2648c2ecf20Sopenharmony_ci * Return:
2658c2ecf20Sopenharmony_ci * The amount of the characters processed to the destination buffer excluding
2668c2ecf20Sopenharmony_ci * trailing '\0' is returned.
2678c2ecf20Sopenharmony_ci */
2688c2ecf20Sopenharmony_ciint string_unescape(char *src, char *dst, size_t size, unsigned int flags)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	char *out = dst;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	while (*src && --size) {
2738c2ecf20Sopenharmony_ci		if (src[0] == '\\' && src[1] != '\0' && size > 1) {
2748c2ecf20Sopenharmony_ci			src++;
2758c2ecf20Sopenharmony_ci			size--;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci			if (flags & UNESCAPE_SPACE &&
2788c2ecf20Sopenharmony_ci					unescape_space(&src, &out))
2798c2ecf20Sopenharmony_ci				continue;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci			if (flags & UNESCAPE_OCTAL &&
2828c2ecf20Sopenharmony_ci					unescape_octal(&src, &out))
2838c2ecf20Sopenharmony_ci				continue;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci			if (flags & UNESCAPE_HEX &&
2868c2ecf20Sopenharmony_ci					unescape_hex(&src, &out))
2878c2ecf20Sopenharmony_ci				continue;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci			if (flags & UNESCAPE_SPECIAL &&
2908c2ecf20Sopenharmony_ci					unescape_special(&src, &out))
2918c2ecf20Sopenharmony_ci				continue;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci			*out++ = '\\';
2948c2ecf20Sopenharmony_ci		}
2958c2ecf20Sopenharmony_ci		*out++ = *src++;
2968c2ecf20Sopenharmony_ci	}
2978c2ecf20Sopenharmony_ci	*out = '\0';
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	return out - dst;
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ciEXPORT_SYMBOL(string_unescape);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic bool escape_passthrough(unsigned char c, char **dst, char *end)
3048c2ecf20Sopenharmony_ci{
3058c2ecf20Sopenharmony_ci	char *out = *dst;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	if (out < end)
3088c2ecf20Sopenharmony_ci		*out = c;
3098c2ecf20Sopenharmony_ci	*dst = out + 1;
3108c2ecf20Sopenharmony_ci	return true;
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic bool escape_space(unsigned char c, char **dst, char *end)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	char *out = *dst;
3168c2ecf20Sopenharmony_ci	unsigned char to;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	switch (c) {
3198c2ecf20Sopenharmony_ci	case '\n':
3208c2ecf20Sopenharmony_ci		to = 'n';
3218c2ecf20Sopenharmony_ci		break;
3228c2ecf20Sopenharmony_ci	case '\r':
3238c2ecf20Sopenharmony_ci		to = 'r';
3248c2ecf20Sopenharmony_ci		break;
3258c2ecf20Sopenharmony_ci	case '\t':
3268c2ecf20Sopenharmony_ci		to = 't';
3278c2ecf20Sopenharmony_ci		break;
3288c2ecf20Sopenharmony_ci	case '\v':
3298c2ecf20Sopenharmony_ci		to = 'v';
3308c2ecf20Sopenharmony_ci		break;
3318c2ecf20Sopenharmony_ci	case '\f':
3328c2ecf20Sopenharmony_ci		to = 'f';
3338c2ecf20Sopenharmony_ci		break;
3348c2ecf20Sopenharmony_ci	default:
3358c2ecf20Sopenharmony_ci		return false;
3368c2ecf20Sopenharmony_ci	}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	if (out < end)
3398c2ecf20Sopenharmony_ci		*out = '\\';
3408c2ecf20Sopenharmony_ci	++out;
3418c2ecf20Sopenharmony_ci	if (out < end)
3428c2ecf20Sopenharmony_ci		*out = to;
3438c2ecf20Sopenharmony_ci	++out;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	*dst = out;
3468c2ecf20Sopenharmony_ci	return true;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic bool escape_special(unsigned char c, char **dst, char *end)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	char *out = *dst;
3528c2ecf20Sopenharmony_ci	unsigned char to;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	switch (c) {
3558c2ecf20Sopenharmony_ci	case '\\':
3568c2ecf20Sopenharmony_ci		to = '\\';
3578c2ecf20Sopenharmony_ci		break;
3588c2ecf20Sopenharmony_ci	case '\a':
3598c2ecf20Sopenharmony_ci		to = 'a';
3608c2ecf20Sopenharmony_ci		break;
3618c2ecf20Sopenharmony_ci	case '\e':
3628c2ecf20Sopenharmony_ci		to = 'e';
3638c2ecf20Sopenharmony_ci		break;
3648c2ecf20Sopenharmony_ci	default:
3658c2ecf20Sopenharmony_ci		return false;
3668c2ecf20Sopenharmony_ci	}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	if (out < end)
3698c2ecf20Sopenharmony_ci		*out = '\\';
3708c2ecf20Sopenharmony_ci	++out;
3718c2ecf20Sopenharmony_ci	if (out < end)
3728c2ecf20Sopenharmony_ci		*out = to;
3738c2ecf20Sopenharmony_ci	++out;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	*dst = out;
3768c2ecf20Sopenharmony_ci	return true;
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_cistatic bool escape_null(unsigned char c, char **dst, char *end)
3808c2ecf20Sopenharmony_ci{
3818c2ecf20Sopenharmony_ci	char *out = *dst;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	if (c)
3848c2ecf20Sopenharmony_ci		return false;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	if (out < end)
3878c2ecf20Sopenharmony_ci		*out = '\\';
3888c2ecf20Sopenharmony_ci	++out;
3898c2ecf20Sopenharmony_ci	if (out < end)
3908c2ecf20Sopenharmony_ci		*out = '0';
3918c2ecf20Sopenharmony_ci	++out;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	*dst = out;
3948c2ecf20Sopenharmony_ci	return true;
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistatic bool escape_octal(unsigned char c, char **dst, char *end)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	char *out = *dst;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	if (out < end)
4028c2ecf20Sopenharmony_ci		*out = '\\';
4038c2ecf20Sopenharmony_ci	++out;
4048c2ecf20Sopenharmony_ci	if (out < end)
4058c2ecf20Sopenharmony_ci		*out = ((c >> 6) & 0x07) + '0';
4068c2ecf20Sopenharmony_ci	++out;
4078c2ecf20Sopenharmony_ci	if (out < end)
4088c2ecf20Sopenharmony_ci		*out = ((c >> 3) & 0x07) + '0';
4098c2ecf20Sopenharmony_ci	++out;
4108c2ecf20Sopenharmony_ci	if (out < end)
4118c2ecf20Sopenharmony_ci		*out = ((c >> 0) & 0x07) + '0';
4128c2ecf20Sopenharmony_ci	++out;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	*dst = out;
4158c2ecf20Sopenharmony_ci	return true;
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic bool escape_hex(unsigned char c, char **dst, char *end)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	char *out = *dst;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	if (out < end)
4238c2ecf20Sopenharmony_ci		*out = '\\';
4248c2ecf20Sopenharmony_ci	++out;
4258c2ecf20Sopenharmony_ci	if (out < end)
4268c2ecf20Sopenharmony_ci		*out = 'x';
4278c2ecf20Sopenharmony_ci	++out;
4288c2ecf20Sopenharmony_ci	if (out < end)
4298c2ecf20Sopenharmony_ci		*out = hex_asc_hi(c);
4308c2ecf20Sopenharmony_ci	++out;
4318c2ecf20Sopenharmony_ci	if (out < end)
4328c2ecf20Sopenharmony_ci		*out = hex_asc_lo(c);
4338c2ecf20Sopenharmony_ci	++out;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	*dst = out;
4368c2ecf20Sopenharmony_ci	return true;
4378c2ecf20Sopenharmony_ci}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci/**
4408c2ecf20Sopenharmony_ci * string_escape_mem - quote characters in the given memory buffer
4418c2ecf20Sopenharmony_ci * @src:	source buffer (unescaped)
4428c2ecf20Sopenharmony_ci * @isz:	source buffer size
4438c2ecf20Sopenharmony_ci * @dst:	destination buffer (escaped)
4448c2ecf20Sopenharmony_ci * @osz:	destination buffer size
4458c2ecf20Sopenharmony_ci * @flags:	combination of the flags
4468c2ecf20Sopenharmony_ci * @only:	NULL-terminated string containing characters used to limit
4478c2ecf20Sopenharmony_ci *		the selected escape class. If characters are included in @only
4488c2ecf20Sopenharmony_ci *		that would not normally be escaped by the classes selected
4498c2ecf20Sopenharmony_ci *		in @flags, they will be copied to @dst unescaped.
4508c2ecf20Sopenharmony_ci *
4518c2ecf20Sopenharmony_ci * Description:
4528c2ecf20Sopenharmony_ci * The process of escaping byte buffer includes several parts. They are applied
4538c2ecf20Sopenharmony_ci * in the following sequence.
4548c2ecf20Sopenharmony_ci *
4558c2ecf20Sopenharmony_ci *	1. The character is matched to the printable class, if asked, and in
4568c2ecf20Sopenharmony_ci *	   case of match it passes through to the output.
4578c2ecf20Sopenharmony_ci *	2. The character is not matched to the one from @only string and thus
4588c2ecf20Sopenharmony_ci *	   must go as-is to the output.
4598c2ecf20Sopenharmony_ci *	3. The character is checked if it falls into the class given by @flags.
4608c2ecf20Sopenharmony_ci *	   %ESCAPE_OCTAL and %ESCAPE_HEX are going last since they cover any
4618c2ecf20Sopenharmony_ci *	   character. Note that they actually can't go together, otherwise
4628c2ecf20Sopenharmony_ci *	   %ESCAPE_HEX will be ignored.
4638c2ecf20Sopenharmony_ci *
4648c2ecf20Sopenharmony_ci * Caller must provide valid source and destination pointers. Be aware that
4658c2ecf20Sopenharmony_ci * destination buffer will not be NULL-terminated, thus caller have to append
4668c2ecf20Sopenharmony_ci * it if needs.   The supported flags are::
4678c2ecf20Sopenharmony_ci *
4688c2ecf20Sopenharmony_ci *	%ESCAPE_SPACE: (special white space, not space itself)
4698c2ecf20Sopenharmony_ci *		'\f' - form feed
4708c2ecf20Sopenharmony_ci *		'\n' - new line
4718c2ecf20Sopenharmony_ci *		'\r' - carriage return
4728c2ecf20Sopenharmony_ci *		'\t' - horizontal tab
4738c2ecf20Sopenharmony_ci *		'\v' - vertical tab
4748c2ecf20Sopenharmony_ci *	%ESCAPE_SPECIAL:
4758c2ecf20Sopenharmony_ci *		'\\' - backslash
4768c2ecf20Sopenharmony_ci *		'\a' - alert (BEL)
4778c2ecf20Sopenharmony_ci *		'\e' - escape
4788c2ecf20Sopenharmony_ci *	%ESCAPE_NULL:
4798c2ecf20Sopenharmony_ci *		'\0' - null
4808c2ecf20Sopenharmony_ci *	%ESCAPE_OCTAL:
4818c2ecf20Sopenharmony_ci *		'\NNN' - byte with octal value NNN (3 digits)
4828c2ecf20Sopenharmony_ci *	%ESCAPE_ANY:
4838c2ecf20Sopenharmony_ci *		all previous together
4848c2ecf20Sopenharmony_ci *	%ESCAPE_NP:
4858c2ecf20Sopenharmony_ci *		escape only non-printable characters (checked by isprint)
4868c2ecf20Sopenharmony_ci *	%ESCAPE_ANY_NP:
4878c2ecf20Sopenharmony_ci *		all previous together
4888c2ecf20Sopenharmony_ci *	%ESCAPE_HEX:
4898c2ecf20Sopenharmony_ci *		'\xHH' - byte with hexadecimal value HH (2 digits)
4908c2ecf20Sopenharmony_ci *
4918c2ecf20Sopenharmony_ci * Return:
4928c2ecf20Sopenharmony_ci * The total size of the escaped output that would be generated for
4938c2ecf20Sopenharmony_ci * the given input and flags. To check whether the output was
4948c2ecf20Sopenharmony_ci * truncated, compare the return value to osz. There is room left in
4958c2ecf20Sopenharmony_ci * dst for a '\0' terminator if and only if ret < osz.
4968c2ecf20Sopenharmony_ci */
4978c2ecf20Sopenharmony_ciint string_escape_mem(const char *src, size_t isz, char *dst, size_t osz,
4988c2ecf20Sopenharmony_ci		      unsigned int flags, const char *only)
4998c2ecf20Sopenharmony_ci{
5008c2ecf20Sopenharmony_ci	char *p = dst;
5018c2ecf20Sopenharmony_ci	char *end = p + osz;
5028c2ecf20Sopenharmony_ci	bool is_dict = only && *only;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	while (isz--) {
5058c2ecf20Sopenharmony_ci		unsigned char c = *src++;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci		/*
5088c2ecf20Sopenharmony_ci		 * Apply rules in the following sequence:
5098c2ecf20Sopenharmony_ci		 *	- the character is printable, when @flags has
5108c2ecf20Sopenharmony_ci		 *	  %ESCAPE_NP bit set
5118c2ecf20Sopenharmony_ci		 *	- the @only string is supplied and does not contain a
5128c2ecf20Sopenharmony_ci		 *	  character under question
5138c2ecf20Sopenharmony_ci		 *	- the character doesn't fall into a class of symbols
5148c2ecf20Sopenharmony_ci		 *	  defined by given @flags
5158c2ecf20Sopenharmony_ci		 * In these cases we just pass through a character to the
5168c2ecf20Sopenharmony_ci		 * output buffer.
5178c2ecf20Sopenharmony_ci		 */
5188c2ecf20Sopenharmony_ci		if ((flags & ESCAPE_NP && isprint(c)) ||
5198c2ecf20Sopenharmony_ci		    (is_dict && !strchr(only, c))) {
5208c2ecf20Sopenharmony_ci			/* do nothing */
5218c2ecf20Sopenharmony_ci		} else {
5228c2ecf20Sopenharmony_ci			if (flags & ESCAPE_SPACE && escape_space(c, &p, end))
5238c2ecf20Sopenharmony_ci				continue;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci			if (flags & ESCAPE_SPECIAL && escape_special(c, &p, end))
5268c2ecf20Sopenharmony_ci				continue;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci			if (flags & ESCAPE_NULL && escape_null(c, &p, end))
5298c2ecf20Sopenharmony_ci				continue;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci			/* ESCAPE_OCTAL and ESCAPE_HEX always go last */
5328c2ecf20Sopenharmony_ci			if (flags & ESCAPE_OCTAL && escape_octal(c, &p, end))
5338c2ecf20Sopenharmony_ci				continue;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci			if (flags & ESCAPE_HEX && escape_hex(c, &p, end))
5368c2ecf20Sopenharmony_ci				continue;
5378c2ecf20Sopenharmony_ci		}
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci		escape_passthrough(c, &p, end);
5408c2ecf20Sopenharmony_ci	}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	return p - dst;
5438c2ecf20Sopenharmony_ci}
5448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(string_escape_mem);
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ciint string_escape_mem_ascii(const char *src, size_t isz, char *dst,
5478c2ecf20Sopenharmony_ci					size_t osz)
5488c2ecf20Sopenharmony_ci{
5498c2ecf20Sopenharmony_ci	char *p = dst;
5508c2ecf20Sopenharmony_ci	char *end = p + osz;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	while (isz--) {
5538c2ecf20Sopenharmony_ci		unsigned char c = *src++;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci		if (!isprint(c) || !isascii(c) || c == '"' || c == '\\')
5568c2ecf20Sopenharmony_ci			escape_hex(c, &p, end);
5578c2ecf20Sopenharmony_ci		else
5588c2ecf20Sopenharmony_ci			escape_passthrough(c, &p, end);
5598c2ecf20Sopenharmony_ci	}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	return p - dst;
5628c2ecf20Sopenharmony_ci}
5638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(string_escape_mem_ascii);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci/*
5668c2ecf20Sopenharmony_ci * Return an allocated string that has been escaped of special characters
5678c2ecf20Sopenharmony_ci * and double quotes, making it safe to log in quotes.
5688c2ecf20Sopenharmony_ci */
5698c2ecf20Sopenharmony_cichar *kstrdup_quotable(const char *src, gfp_t gfp)
5708c2ecf20Sopenharmony_ci{
5718c2ecf20Sopenharmony_ci	size_t slen, dlen;
5728c2ecf20Sopenharmony_ci	char *dst;
5738c2ecf20Sopenharmony_ci	const int flags = ESCAPE_HEX;
5748c2ecf20Sopenharmony_ci	const char esc[] = "\f\n\r\t\v\a\e\\\"";
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	if (!src)
5778c2ecf20Sopenharmony_ci		return NULL;
5788c2ecf20Sopenharmony_ci	slen = strlen(src);
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	dlen = string_escape_mem(src, slen, NULL, 0, flags, esc);
5818c2ecf20Sopenharmony_ci	dst = kmalloc(dlen + 1, gfp);
5828c2ecf20Sopenharmony_ci	if (!dst)
5838c2ecf20Sopenharmony_ci		return NULL;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	WARN_ON(string_escape_mem(src, slen, dst, dlen, flags, esc) != dlen);
5868c2ecf20Sopenharmony_ci	dst[dlen] = '\0';
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	return dst;
5898c2ecf20Sopenharmony_ci}
5908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kstrdup_quotable);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci/*
5938c2ecf20Sopenharmony_ci * Returns allocated NULL-terminated string containing process
5948c2ecf20Sopenharmony_ci * command line, with inter-argument NULLs replaced with spaces,
5958c2ecf20Sopenharmony_ci * and other special characters escaped.
5968c2ecf20Sopenharmony_ci */
5978c2ecf20Sopenharmony_cichar *kstrdup_quotable_cmdline(struct task_struct *task, gfp_t gfp)
5988c2ecf20Sopenharmony_ci{
5998c2ecf20Sopenharmony_ci	char *buffer, *quoted;
6008c2ecf20Sopenharmony_ci	int i, res;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
6038c2ecf20Sopenharmony_ci	if (!buffer)
6048c2ecf20Sopenharmony_ci		return NULL;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	res = get_cmdline(task, buffer, PAGE_SIZE - 1);
6078c2ecf20Sopenharmony_ci	buffer[res] = '\0';
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	/* Collapse trailing NULLs, leave res pointing to last non-NULL. */
6108c2ecf20Sopenharmony_ci	while (--res >= 0 && buffer[res] == '\0')
6118c2ecf20Sopenharmony_ci		;
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	/* Replace inter-argument NULLs. */
6148c2ecf20Sopenharmony_ci	for (i = 0; i <= res; i++)
6158c2ecf20Sopenharmony_ci		if (buffer[i] == '\0')
6168c2ecf20Sopenharmony_ci			buffer[i] = ' ';
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	/* Make sure result is printable. */
6198c2ecf20Sopenharmony_ci	quoted = kstrdup_quotable(buffer, gfp);
6208c2ecf20Sopenharmony_ci	kfree(buffer);
6218c2ecf20Sopenharmony_ci	return quoted;
6228c2ecf20Sopenharmony_ci}
6238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kstrdup_quotable_cmdline);
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci/*
6268c2ecf20Sopenharmony_ci * Returns allocated NULL-terminated string containing pathname,
6278c2ecf20Sopenharmony_ci * with special characters escaped, able to be safely logged. If
6288c2ecf20Sopenharmony_ci * there is an error, the leading character will be "<".
6298c2ecf20Sopenharmony_ci */
6308c2ecf20Sopenharmony_cichar *kstrdup_quotable_file(struct file *file, gfp_t gfp)
6318c2ecf20Sopenharmony_ci{
6328c2ecf20Sopenharmony_ci	char *temp, *pathname;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	if (!file)
6358c2ecf20Sopenharmony_ci		return kstrdup("<unknown>", gfp);
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	/* We add 11 spaces for ' (deleted)' to be appended */
6388c2ecf20Sopenharmony_ci	temp = kmalloc(PATH_MAX + 11, GFP_KERNEL);
6398c2ecf20Sopenharmony_ci	if (!temp)
6408c2ecf20Sopenharmony_ci		return kstrdup("<no_memory>", gfp);
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	pathname = file_path(file, temp, PATH_MAX + 11);
6438c2ecf20Sopenharmony_ci	if (IS_ERR(pathname))
6448c2ecf20Sopenharmony_ci		pathname = kstrdup("<too_long>", gfp);
6458c2ecf20Sopenharmony_ci	else
6468c2ecf20Sopenharmony_ci		pathname = kstrdup_quotable(pathname, gfp);
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	kfree(temp);
6498c2ecf20Sopenharmony_ci	return pathname;
6508c2ecf20Sopenharmony_ci}
6518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kstrdup_quotable_file);
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci/**
6548c2ecf20Sopenharmony_ci * kfree_strarray - free a number of dynamically allocated strings contained
6558c2ecf20Sopenharmony_ci *                  in an array and the array itself
6568c2ecf20Sopenharmony_ci *
6578c2ecf20Sopenharmony_ci * @array: Dynamically allocated array of strings to free.
6588c2ecf20Sopenharmony_ci * @n: Number of strings (starting from the beginning of the array) to free.
6598c2ecf20Sopenharmony_ci *
6608c2ecf20Sopenharmony_ci * Passing a non-NULL @array and @n == 0 as well as NULL @array are valid
6618c2ecf20Sopenharmony_ci * use-cases. If @array is NULL, the function does nothing.
6628c2ecf20Sopenharmony_ci */
6638c2ecf20Sopenharmony_civoid kfree_strarray(char **array, size_t n)
6648c2ecf20Sopenharmony_ci{
6658c2ecf20Sopenharmony_ci	unsigned int i;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	if (!array)
6688c2ecf20Sopenharmony_ci		return;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	for (i = 0; i < n; i++)
6718c2ecf20Sopenharmony_ci		kfree(array[i]);
6728c2ecf20Sopenharmony_ci	kfree(array);
6738c2ecf20Sopenharmony_ci}
6748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kfree_strarray);
675