| // SPDX-License-Identifier: GPL-2.0 | 
 | /* | 
 |  * Copyright (c) 2003-2005 Silicon Graphics, Inc. | 
 |  * All Rights Reserved. | 
 |  */ | 
 | #include "platform_defs.h" | 
 | #include "input.h" | 
 | #include <ctype.h> | 
 | #include <stdbool.h> | 
 |  | 
 | size_t | 
 | numlen( | 
 | 	uint64_t	val, | 
 | 	size_t		base) | 
 | { | 
 | 	uint64_t	tmp; | 
 | 	size_t		len; | 
 |  | 
 | 	for (len = 0, tmp = val; tmp > 0; tmp = tmp / base) | 
 | 		len++; | 
 | 	return len == 0 ? 1 : len; | 
 | } | 
 |  | 
 | /* | 
 |  * Convert string to int64_t, set errno if the conversion fails or | 
 |  * doesn't fit.  Does not allow unit specifiers.  Sets errno to zero | 
 |  * prior to conversion so you can check for bad inputs by examining | 
 |  * errno immediately after the call. | 
 |  */ | 
 | int64_t | 
 | cvt_s64( | 
 | 	char		*s, | 
 | 	int		base) | 
 | { | 
 | 	long long	i; | 
 | 	char		*sp; | 
 |  | 
 | 	errno = 0; | 
 | 	i = strtoll(s, &sp, base); | 
 | 	/* | 
 | 	 * If the input would over or underflow, return the clamped | 
 | 	 * value and let the user check errno.  If we went all the | 
 | 	 * way to the end of the input, return the converted value; | 
 | 	 * errno will be zero. | 
 | 	 */ | 
 | 	if (errno || (*sp == '\0' && sp != s)) | 
 | 		return i; | 
 |  | 
 | 	/* Not all the input was consumed, return error. */ | 
 | 	errno = ERANGE; | 
 | 	return INT64_MIN; | 
 | } | 
 |  | 
 | /* | 
 |  * Convert string to int32_t, set errno if the conversion fails or | 
 |  * doesn't fit.  Does not allow unit specifiers.  Sets errno to zero | 
 |  * prior to conversion so you can check for bad inputs by examining | 
 |  * errno immediately after the call. | 
 |  */ | 
 | int32_t | 
 | cvt_s32( | 
 | 	char		*s, | 
 | 	int		base) | 
 | { | 
 | 	int64_t		i; | 
 |  | 
 | 	i = cvt_s64(s, base); | 
 | 	if (errno) | 
 | 		return i; | 
 | 	if (i > INT32_MAX || i < INT32_MIN) { | 
 | 		errno = ERANGE; | 
 | 		return INT32_MIN; | 
 | 	} | 
 | 	return i; | 
 | } | 
 |  | 
 | /* | 
 |  * Convert string to int16_t, set errno if the conversion fails or | 
 |  * doesn't fit.  Does not allow unit specifiers.  Sets errno to zero | 
 |  * prior to conversion so you can check for bad inputs by examining | 
 |  * errno immediately after the call. | 
 |  */ | 
 | int16_t | 
 | cvt_s16( | 
 | 	char		*s, | 
 | 	int		base) | 
 | { | 
 | 	int64_t		i; | 
 |  | 
 | 	i = cvt_s64(s, base); | 
 | 	if (errno) | 
 | 		return i; | 
 | 	if (i > INT16_MAX || i < INT16_MIN) { | 
 | 		errno = ERANGE; | 
 | 		return INT16_MIN; | 
 | 	} | 
 | 	return i; | 
 | } | 
 |  | 
 | /* | 
 |  * Convert string to uint64_t, set errno if the conversion fails or | 
 |  * doesn't fit.  Does not allow unit specifiers.  Sets errno to zero | 
 |  * prior to conversion so you can check for bad inputs by examining | 
 |  * errno immediately after the call. | 
 |  */ | 
 | uint64_t | 
 | cvt_u64( | 
 | 	char			*s, | 
 | 	int			base) | 
 | { | 
 | 	unsigned long long	i; | 
 | 	char			*sp; | 
 |  | 
 | 	errno = 0; | 
 | 	i = strtoull(s, &sp, base); | 
 | 	/* | 
 | 	 * If the input would over or underflow, return the clamped | 
 | 	 * value and let the user check errno.  If we went all the | 
 | 	 * way to the end of the input, return the converted value; | 
 | 	 * errno will be zero. | 
 | 	 */ | 
 | 	if (errno || (*sp == '\0' && sp != s)) | 
 | 		return i; | 
 |  | 
 | 	/* Not all the input was consumed, return error. */ | 
 | 	errno = ERANGE; | 
 | 	return UINT64_MAX; | 
 | } | 
 |  | 
 | /* | 
 |  * Convert string to uint32_t, set errno if the conversion fails or | 
 |  * doesn't fit.  Does not allow unit specifiers.  Sets errno to zero | 
 |  * prior to conversion so you can check for bad inputs by examining | 
 |  * errno immediately after the call. | 
 |  */ | 
 | uint32_t | 
 | cvt_u32( | 
 | 	char		*s, | 
 | 	int		base) | 
 | { | 
 | 	uint64_t	i; | 
 |  | 
 | 	i = cvt_u64(s, base); | 
 | 	if (errno) | 
 | 		return i; | 
 | 	if (i > UINT32_MAX) { | 
 | 		errno = ERANGE; | 
 | 		return UINT32_MAX; | 
 | 	} | 
 | 	return i; | 
 | } | 
 |  | 
 | /* | 
 |  * Convert string to uint16_t, set errno if the conversion fails or | 
 |  * doesn't fit.  Does not allow unit specifiers.  Sets errno to zero | 
 |  * prior to conversion so you can check for bad inputs by examining | 
 |  * errno immediately after the call. | 
 |  */ | 
 | uint16_t | 
 | cvt_u16( | 
 | 	char		*s, | 
 | 	int		base) | 
 | { | 
 | 	uint64_t	i; | 
 |  | 
 | 	i = cvt_u64(s, base); | 
 | 	if (errno) | 
 | 		return i; | 
 | 	if (i > UINT16_MAX) { | 
 | 		errno = ERANGE; | 
 | 		return UINT16_MAX; | 
 | 	} | 
 | 	return i; | 
 | } | 
 |  | 
 | #define EXABYTES(x)	((long long)(x) << 60) | 
 | #define PETABYTES(x)	((long long)(x) << 50) | 
 | #define TERABYTES(x)	((long long)(x) << 40) | 
 | #define GIGABYTES(x)	((long long)(x) << 30) | 
 | #define MEGABYTES(x)	((long long)(x) << 20) | 
 | #define KILOBYTES(x)	((long long)(x) << 10) | 
 |  | 
 | long long | 
 | cvtnum( | 
 | 	size_t		blksize, | 
 | 	size_t		sectsize, | 
 | 	const char	*s) | 
 | { | 
 | 	long long	i; | 
 | 	char		*sp; | 
 | 	int		c; | 
 |  | 
 | 	i = strtoll(s, &sp, 0); | 
 | 	if (i == 0 && sp == s) | 
 | 		return -1LL; | 
 | 	if (*sp == '\0') | 
 | 		return i; | 
 |  | 
 | 	if (sp[1] != '\0') | 
 | 		return -1LL; | 
 |  | 
 | 	c = tolower(*sp); | 
 | 	switch (c) { | 
 | 	case 'b': | 
 | 		if (!blksize) | 
 | 			return -1LL; | 
 | 		return i * blksize; | 
 | 	case 's': | 
 | 		if (!sectsize) | 
 | 			return -1LL; | 
 | 		return i * sectsize; | 
 | 	case 'k': | 
 | 		return KILOBYTES(i); | 
 | 	case 'm': | 
 | 		return MEGABYTES(i); | 
 | 	case 'g': | 
 | 		return GIGABYTES(i); | 
 | 	case 't': | 
 | 		return TERABYTES(i); | 
 | 	case 'p': | 
 | 		return PETABYTES(i); | 
 | 	case 'e': | 
 | 		return  EXABYTES(i); | 
 | 	} | 
 | 	return -1LL; | 
 | } | 
 |  | 
 | #define TO_EXABYTES(x)	((x) / EXABYTES(1)) | 
 | #define TO_PETABYTES(x)	((x) / PETABYTES(1)) | 
 | #define TO_TERABYTES(x)	((x) / TERABYTES(1)) | 
 | #define TO_GIGABYTES(x)	((x) / GIGABYTES(1)) | 
 | #define TO_MEGABYTES(x)	((x) / MEGABYTES(1)) | 
 | #define TO_KILOBYTES(x)	((x) / KILOBYTES(1)) | 
 |  | 
 | void | 
 | cvtstr( | 
 | 	double		value, | 
 | 	char		*str, | 
 | 	size_t		size) | 
 | { | 
 | 	char		*fmt; | 
 | 	int		precise; | 
 |  | 
 | 	precise = ((double)value * 1000 == (double)(int)value * 1000); | 
 |  | 
 | 	if (value >= EXABYTES(1)) { | 
 | 		fmt = precise ? "%.f EiB" : "%.3f EiB"; | 
 | 		snprintf(str, size, fmt, TO_EXABYTES(value)); | 
 | 	} else if (value >= PETABYTES(1)) { | 
 | 		fmt = precise ? "%.f PiB" : "%.3f PiB"; | 
 | 		snprintf(str, size, fmt, TO_PETABYTES(value)); | 
 | 	} else if (value >= TERABYTES(1)) { | 
 | 		fmt = precise ? "%.f TiB" : "%.3f TiB"; | 
 | 		snprintf(str, size, fmt, TO_TERABYTES(value)); | 
 | 	} else if (value >= GIGABYTES(1)) { | 
 | 		fmt = precise ? "%.f GiB" : "%.3f GiB"; | 
 | 		snprintf(str, size, fmt, TO_GIGABYTES(value)); | 
 | 	} else if (value >= MEGABYTES(1)) { | 
 | 		fmt = precise ? "%.f MiB" : "%.3f MiB"; | 
 | 		snprintf(str, size, fmt, TO_MEGABYTES(value)); | 
 | 	} else if (value >= KILOBYTES(1)) { | 
 | 		fmt = precise ? "%.f KiB" : "%.3f KiB"; | 
 | 		snprintf(str, size, fmt, TO_KILOBYTES(value)); | 
 | 	} else { | 
 | 		snprintf(str, size, "%f bytes", value); | 
 | 	} | 
 | } | 
 |  | 
 | #define MINUTES_TO_SECONDS(m)	((m) * 60) | 
 | #define HOURS_TO_SECONDS(h)	((h) * MINUTES_TO_SECONDS(60)) | 
 | #define DAYS_TO_SECONDS(d)	((d) * HOURS_TO_SECONDS(24)) | 
 | #define WEEKS_TO_SECONDS(w)	((w) * DAYS_TO_SECONDS(7)) | 
 |  | 
 | time64_t | 
 | cvttime( | 
 | 	char		*s) | 
 | { | 
 | 	time64_t	i; | 
 | 	char		*sp; | 
 |  | 
 | 	i = strtoll(s, &sp, 0); | 
 | 	if (i == 0 && sp == s) | 
 | 		return 0; | 
 | 	if (*sp == '\0') | 
 | 		return i; | 
 | 	if ((*sp == 'm' && sp[1] == '\0') || | 
 | 	    (strcmp(sp, "minutes") == 0) || | 
 | 	    (strcmp(sp, "minute") == 0)) | 
 | 		return MINUTES_TO_SECONDS(i); | 
 | 	if ((*sp == 'h' && sp[1] == '\0') || | 
 | 	    (strcmp(sp, "hours") == 0) || | 
 | 	    (strcmp(sp, "hour") == 0)) | 
 | 		return HOURS_TO_SECONDS(i); | 
 | 	if ((*sp == 'd' && sp[1] == '\0') || | 
 | 	    (strcmp(sp, "days") == 0) || | 
 | 	    (strcmp(sp, "day") == 0)) | 
 | 		return DAYS_TO_SECONDS(i); | 
 | 	if ((*sp == 'w' && sp[1] == '\0') || | 
 | 	    (strcmp(sp, "weeks") == 0) || | 
 | 	    (strcmp(sp, "week") == 0)) | 
 | 		return WEEKS_TO_SECONDS(i); | 
 | 	return 0; | 
 | } | 
 |  | 
 | /* | 
 |  * Convert from arbitrary user strings into a numeric ID. | 
 |  * If it's all numeric, we convert that inplace, else we do | 
 |  * the name lookup, and return the found identifier. | 
 |  */ | 
 |  | 
 | prid_t | 
 | prid_from_string( | 
 | 	char		*project) | 
 | { | 
 | 	fs_project_t	*prj; | 
 | 	unsigned long	prid_long; | 
 | 	char		*sp; | 
 |  | 
 | 	/* | 
 | 	 * Allow either a full numeric or a valid projectname, even | 
 | 	 * if it starts with a digit. | 
 | 	 */ | 
 | 	prid_long = strtoul(project, &sp, 10); | 
 | 	if (*project != '\0' && *sp == '\0') { | 
 | 		if ((prid_long == ULONG_MAX && errno == ERANGE) | 
 | 				|| (prid_long > (prid_t)-1)) | 
 | 			return -1; | 
 | 		return (prid_t)prid_long; | 
 | 	} | 
 | 	prj = getprnam(project); | 
 | 	if (prj) | 
 | 		return prj->pr_prid; | 
 | 	return -1; | 
 | } | 
 |  | 
 | uid_t | 
 | uid_from_string( | 
 | 	char		*user) | 
 | { | 
 | 	struct passwd	*pwd; | 
 | 	unsigned long	uid_long; | 
 | 	char		*sp; | 
 |  | 
 | 	uid_long = strtoul(user, &sp, 10); | 
 | 	if (sp != user && *sp == '\0') { | 
 | 		if ((uid_long == ULONG_MAX && errno == ERANGE) | 
 | 				|| (uid_long > (uid_t)-1)) | 
 | 			return -1; | 
 | 		return (uid_t)uid_long; | 
 | 	} | 
 | 	pwd = getpwnam(user); | 
 | 	if (pwd) | 
 | 		return pwd->pw_uid; | 
 | 	return -1; | 
 | } | 
 |  | 
 | gid_t | 
 | gid_from_string( | 
 | 	char		*group) | 
 | { | 
 | 	struct group	*grp; | 
 | 	unsigned long	gid_long; | 
 | 	char		*sp; | 
 |  | 
 | 	gid_long = strtoul(group, &sp, 10); | 
 | 	if (sp != group && *sp == '\0') { | 
 | 		if ((gid_long == ULONG_MAX && errno == ERANGE) | 
 | 				|| (gid_long > (gid_t)-1)) | 
 | 			return -1; | 
 | 		return (gid_t)gid_long; | 
 | 	} | 
 | 	grp = getgrnam(group); | 
 | 	if (grp) | 
 | 		return grp->gr_gid; | 
 | 	return -1; | 
 | } |