|  | // 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; | 
|  | } |