1172029Spjd/*- 2172029Spjd * Copyright (c) 2007 Eric Anderson <anderson@FreeBSD.org> 3172029Spjd * Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org> 4172029Spjd * All rights reserved. 5172029Spjd * 6172029Spjd * Redistribution and use in source and binary forms, with or without 7172029Spjd * modification, are permitted provided that the following conditions 8172029Spjd * are met: 9172029Spjd * 1. Redistributions of source code must retain the above copyright 10172029Spjd * notice, this list of conditions and the following disclaimer. 11172029Spjd * 2. Redistributions in binary form must reproduce the above copyright 12172029Spjd * notice, this list of conditions and the following disclaimer in the 13172029Spjd * documentation and/or other materials provided with the distribution. 14172029Spjd * 15172029Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 16172029Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17172029Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18172029Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 19172029Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20172029Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21172029Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22172029Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23172029Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24172029Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25172029Spjd * SUCH DAMAGE. 26172029Spjd */ 27172029Spjd 28172029Spjd#include <sys/cdefs.h> 29172029Spjd__FBSDID("$FreeBSD$"); 30172029Spjd 31172029Spjd#include <sys/types.h> 32172029Spjd#include <ctype.h> 33172029Spjd#include <errno.h> 34180347Skib#include <inttypes.h> 35172029Spjd#include <libutil.h> 36172029Spjd#include <stdint.h> 37172029Spjd 38172029Spjdint 39211304Sdesexpand_number(const char *buf, uint64_t *num) 40172029Spjd{ 41255069Spluknet char *endptr; 42255069Spluknet uintmax_t umaxval; 43211304Sdes uint64_t number; 44211343Sdes unsigned shift; 45255069Spluknet int serrno; 46172029Spjd 47255069Spluknet serrno = errno; 48254621Spluknet errno = 0; 49255069Spluknet umaxval = strtoumax(buf, &endptr, 0); 50255069Spluknet if (umaxval > UINT64_MAX) 51255069Spluknet errno = ERANGE; 52255069Spluknet if (errno != 0) 53254600Spluknet return (-1); 54255069Spluknet errno = serrno; 55255069Spluknet number = umaxval; 56254600Spluknet 57211304Sdes switch (tolower((unsigned char)*endptr)) { 58211304Sdes case 'e': 59211343Sdes shift = 60; 60211343Sdes break; 61211304Sdes case 'p': 62211343Sdes shift = 50; 63211343Sdes break; 64211304Sdes case 't': 65211343Sdes shift = 40; 66211343Sdes break; 67211304Sdes case 'g': 68211343Sdes shift = 30; 69211343Sdes break; 70211304Sdes case 'm': 71211343Sdes shift = 20; 72211343Sdes break; 73211304Sdes case 'k': 74211343Sdes shift = 10; 75211343Sdes break; 76172049Spjd case 'b': 77211343Sdes case '\0': /* No unit. */ 78211343Sdes *num = number; 79211343Sdes return (0); 80172049Spjd default: 81172049Spjd /* Unrecognized unit. */ 82172049Spjd errno = EINVAL; 83172049Spjd return (-1); 84172049Spjd } 85172049Spjd 86211343Sdes if ((number << shift) >> shift != number) { 87211343Sdes /* Overflow */ 88211343Sdes errno = ERANGE; 89211343Sdes return (-1); 90211343Sdes } 91211343Sdes *num = number << shift; 92172029Spjd return (0); 93172029Spjd} 94