2010-11-18 02:28:20 +03:00
/*
2012-09-29 01:25:59 +04:00
* Copyright 2011 The Chromium Authors , All Rights Reserved .
2010-11-18 02:28:20 +03:00
* Copyright 2008 Jon Loeliger , Freescale Semiconductor , Inc .
*
2012-09-29 01:25:59 +04:00
* util_is_printable_string contributed by
* Pantelis Antoniou < pantelis . antoniou AT gmail . com >
*
2010-11-18 02:28:20 +03:00
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation ; either version 2 of the
* License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307
* USA
*/
2012-09-29 01:25:59 +04:00
# include <ctype.h>
2010-11-18 02:28:20 +03:00
# include <stdio.h>
# include <stdlib.h>
# include <stdarg.h>
# include <string.h>
2012-09-29 01:25:59 +04:00
# include <assert.h>
# include <errno.h>
# include <fcntl.h>
# include <unistd.h>
2010-11-18 02:28:20 +03:00
2012-09-29 01:25:59 +04:00
# include "libfdt.h"
2010-11-18 02:28:20 +03:00
# include "util.h"
2014-01-21 16:54:49 +04:00
# include "version_gen.h"
2010-11-18 02:28:20 +03:00
char * xstrdup ( const char * s )
{
int len = strlen ( s ) + 1 ;
2015-04-30 00:00:05 +03:00
char * d = xmalloc ( len ) ;
2010-11-18 02:28:20 +03:00
2015-04-30 00:00:05 +03:00
memcpy ( d , s , len ) ;
2010-11-18 02:28:20 +03:00
2015-04-30 00:00:05 +03:00
return d ;
2010-11-18 02:28:20 +03:00
}
2017-01-04 19:45:20 +03:00
/* based in part from (3) vsnprintf */
int xasprintf ( char * * strp , const char * fmt , . . . )
{
int n , size = 128 ; /* start with 128 bytes */
char * p ;
va_list ap ;
/* initial pointer is NULL making the fist realloc to be malloc */
p = NULL ;
while ( 1 ) {
p = xrealloc ( p , size ) ;
/* Try to print in the allocated space. */
va_start ( ap , fmt ) ;
n = vsnprintf ( p , size , fmt , ap ) ;
va_end ( ap ) ;
/* If that worked, return the string. */
if ( n > - 1 & & n < size )
break ;
/* Else try again with more space. */
if ( n > - 1 ) /* glibc 2.1 */
size = n + 1 ; /* precisely what is needed */
else /* glibc 2.0 */
size * = 2 ; /* twice the old size */
}
* strp = p ;
return strlen ( p ) ;
}
2010-11-18 02:28:20 +03:00
char * join_path ( const char * path , const char * name )
{
int lenp = strlen ( path ) ;
int lenn = strlen ( name ) ;
int len ;
int needslash = 1 ;
char * str ;
len = lenp + lenn + 2 ;
if ( ( lenp > 0 ) & & ( path [ lenp - 1 ] = = ' / ' ) ) {
needslash = 0 ;
len - - ;
}
str = xmalloc ( len ) ;
memcpy ( str , path , lenp ) ;
if ( needslash ) {
str [ lenp ] = ' / ' ;
lenp + + ;
}
memcpy ( str + lenp , name , lenn + 1 ) ;
return str ;
}
2012-09-29 01:25:59 +04:00
2015-04-30 00:00:05 +03:00
bool util_is_printable_string ( const void * data , int len )
2012-09-29 01:25:59 +04:00
{
const char * s = data ;
2014-01-21 16:54:49 +04:00
const char * ss , * se ;
2012-09-29 01:25:59 +04:00
/* zero length is not */
if ( len = = 0 )
return 0 ;
/* must terminate with zero */
if ( s [ len - 1 ] ! = ' \0 ' )
return 0 ;
2014-01-21 16:54:49 +04:00
se = s + len ;
2012-09-29 01:25:59 +04:00
2014-01-21 16:54:49 +04:00
while ( s < se ) {
ss = s ;
2015-04-30 00:00:05 +03:00
while ( s < se & & * s & & isprint ( ( unsigned char ) * s ) )
2014-01-21 16:54:49 +04:00
s + + ;
/* not zero, or not done yet */
if ( * s ! = ' \0 ' | | s = = ss )
return 0 ;
s + + ;
}
2012-09-29 01:25:59 +04:00
return 1 ;
}
/*
* Parse a octal encoded character starting at index i in string s . The
* resulting character will be returned and the index i will be updated to
* point at the character directly after the end of the encoding , this may be
* the ' \0 ' terminator of the string .
*/
static char get_oct_char ( const char * s , int * i )
{
char x [ 4 ] ;
char * endx ;
long val ;
x [ 3 ] = ' \0 ' ;
strncpy ( x , s + * i , 3 ) ;
val = strtol ( x , & endx , 8 ) ;
assert ( endx > x ) ;
( * i ) + = endx - x ;
return val ;
}
/*
* Parse a hexadecimal encoded character starting at index i in string s . The
* resulting character will be returned and the index i will be updated to
* point at the character directly after the end of the encoding , this may be
* the ' \0 ' terminator of the string .
*/
static char get_hex_char ( const char * s , int * i )
{
char x [ 3 ] ;
char * endx ;
long val ;
x [ 2 ] = ' \0 ' ;
strncpy ( x , s + * i , 2 ) ;
val = strtol ( x , & endx , 16 ) ;
if ( ! ( endx > x ) )
die ( " \\ x used with no following hex digits \n " ) ;
( * i ) + = endx - x ;
return val ;
}
char get_escape_char ( const char * s , int * i )
{
char c = s [ * i ] ;
int j = * i + 1 ;
char val ;
switch ( c ) {
case ' a ' :
val = ' \a ' ;
break ;
case ' b ' :
val = ' \b ' ;
break ;
case ' t ' :
val = ' \t ' ;
break ;
case ' n ' :
val = ' \n ' ;
break ;
case ' v ' :
val = ' \v ' ;
break ;
case ' f ' :
val = ' \f ' ;
break ;
case ' r ' :
val = ' \r ' ;
break ;
case ' 0 ' :
case ' 1 ' :
case ' 2 ' :
case ' 3 ' :
case ' 4 ' :
case ' 5 ' :
case ' 6 ' :
case ' 7 ' :
j - - ; /* need to re-read the first digit as
* part of the octal value */
val = get_oct_char ( s , & j ) ;
break ;
case ' x ' :
val = get_hex_char ( s , & j ) ;
break ;
default :
val = c ;
}
( * i ) = j ;
return val ;
}
2014-01-21 16:54:49 +04:00
int utilfdt_read_err_len ( const char * filename , char * * buffp , off_t * len )
2012-09-29 01:25:59 +04:00
{
int fd = 0 ; /* assume stdin */
char * buf = NULL ;
off_t bufsize = 1024 , offset = 0 ;
int ret = 0 ;
* buffp = NULL ;
if ( strcmp ( filename , " - " ) ! = 0 ) {
fd = open ( filename , O_RDONLY ) ;
if ( fd < 0 )
return errno ;
}
/* Loop until we have read everything */
2014-01-21 16:54:49 +04:00
buf = xmalloc ( bufsize ) ;
2012-09-29 01:25:59 +04:00
do {
/* Expand the buffer to hold the next chunk */
if ( offset = = bufsize ) {
bufsize * = 2 ;
2014-01-21 16:54:49 +04:00
buf = xrealloc ( buf , bufsize ) ;
2012-09-29 01:25:59 +04:00
}
ret = read ( fd , & buf [ offset ] , bufsize - offset ) ;
if ( ret < 0 ) {
ret = errno ;
break ;
}
offset + = ret ;
} while ( ret ! = 0 ) ;
/* Clean up, including closing stdin; return errno on error */
close ( fd ) ;
if ( ret )
free ( buf ) ;
else
* buffp = buf ;
2014-01-21 16:54:49 +04:00
* len = bufsize ;
2012-09-29 01:25:59 +04:00
return ret ;
}
2014-01-21 16:54:49 +04:00
int utilfdt_read_err ( const char * filename , char * * buffp )
{
off_t len ;
return utilfdt_read_err_len ( filename , buffp , & len ) ;
}
char * utilfdt_read_len ( const char * filename , off_t * len )
2012-09-29 01:25:59 +04:00
{
char * buff ;
2014-01-21 16:54:49 +04:00
int ret = utilfdt_read_err_len ( filename , & buff , len ) ;
2012-09-29 01:25:59 +04:00
if ( ret ) {
fprintf ( stderr , " Couldn't open blob from '%s': %s \n " , filename ,
strerror ( ret ) ) ;
return NULL ;
}
/* Successful read */
return buff ;
}
2014-01-21 16:54:49 +04:00
char * utilfdt_read ( const char * filename )
{
off_t len ;
return utilfdt_read_len ( filename , & len ) ;
}
2012-09-29 01:25:59 +04:00
int utilfdt_write_err ( const char * filename , const void * blob )
{
int fd = 1 ; /* assume stdout */
int totalsize ;
int offset ;
int ret = 0 ;
const char * ptr = blob ;
if ( strcmp ( filename , " - " ) ! = 0 ) {
fd = open ( filename , O_WRONLY | O_CREAT | O_TRUNC , 0666 ) ;
if ( fd < 0 )
return errno ;
}
totalsize = fdt_totalsize ( blob ) ;
offset = 0 ;
while ( offset < totalsize ) {
ret = write ( fd , ptr + offset , totalsize - offset ) ;
if ( ret < 0 ) {
ret = - errno ;
break ;
}
offset + = ret ;
}
/* Close the file/stdin; return errno on error */
if ( fd ! = 1 )
close ( fd ) ;
return ret < 0 ? - ret : 0 ;
}
int utilfdt_write ( const char * filename , const void * blob )
{
int ret = utilfdt_write_err ( filename , blob ) ;
if ( ret ) {
fprintf ( stderr , " Couldn't write blob to '%s': %s \n " , filename ,
strerror ( ret ) ) ;
}
return ret ? - 1 : 0 ;
}
int utilfdt_decode_type ( const char * fmt , int * type , int * size )
{
int qualifier = 0 ;
if ( ! * fmt )
return - 1 ;
/* get the conversion qualifier */
* size = - 1 ;
if ( strchr ( " hlLb " , * fmt ) ) {
qualifier = * fmt + + ;
if ( qualifier = = * fmt ) {
switch ( * fmt + + ) {
/* TODO: case 'l': qualifier = 'L'; break;*/
case ' h ' :
qualifier = ' b ' ;
break ;
}
}
}
/* we should now have a type */
if ( ( * fmt = = ' \0 ' ) | | ! strchr ( " iuxs " , * fmt ) )
return - 1 ;
/* convert qualifier (bhL) to byte size */
if ( * fmt ! = ' s ' )
* size = qualifier = = ' b ' ? 1 :
qualifier = = ' h ' ? 2 :
qualifier = = ' l ' ? 4 : - 1 ;
* type = * fmt + + ;
/* that should be it! */
if ( * fmt )
return - 1 ;
return 0 ;
}
2014-01-21 16:54:49 +04:00
void utilfdt_print_data ( const char * data , int len )
{
int i ;
const char * s ;
/* no data, don't print */
if ( len = = 0 )
return ;
if ( util_is_printable_string ( data , len ) ) {
printf ( " = " ) ;
s = data ;
do {
printf ( " \" %s \" " , s ) ;
s + = strlen ( s ) + 1 ;
if ( s < data + len )
printf ( " , " ) ;
} while ( s < data + len ) ;
} else if ( ( len % 4 ) = = 0 ) {
2017-03-21 17:01:08 +03:00
const fdt32_t * cell = ( const fdt32_t * ) data ;
2014-01-21 16:54:49 +04:00
printf ( " = < " ) ;
2015-04-30 00:00:05 +03:00
for ( i = 0 , len / = 4 ; i < len ; i + + )
2014-01-21 16:54:49 +04:00
printf ( " 0x%08x%s " , fdt32_to_cpu ( cell [ i ] ) ,
2015-04-30 00:00:05 +03:00
i < ( len - 1 ) ? " " : " " ) ;
2014-01-21 16:54:49 +04:00
printf ( " > " ) ;
} else {
2016-01-26 18:04:11 +03:00
const unsigned char * p = ( const unsigned char * ) data ;
2014-01-21 16:54:49 +04:00
printf ( " = [ " ) ;
for ( i = 0 ; i < len ; i + + )
printf ( " %02x%s " , * p + + , i < len - 1 ? " " : " " ) ;
printf ( " ] " ) ;
}
}
2017-03-21 17:01:08 +03:00
void NORETURN util_version ( void )
2014-01-21 16:54:49 +04:00
{
printf ( " Version: %s \n " , DTC_VERSION ) ;
exit ( 0 ) ;
}
2017-03-21 17:01:08 +03:00
void NORETURN util_usage ( const char * errmsg , const char * synopsis ,
const char * short_opts ,
struct option const long_opts [ ] ,
const char * const opts_help [ ] )
2014-01-21 16:54:49 +04:00
{
FILE * fp = errmsg ? stderr : stdout ;
const char a_arg [ ] = " <arg> " ;
size_t a_arg_len = strlen ( a_arg ) + 1 ;
size_t i ;
int optlen ;
fprintf ( fp ,
" Usage: %s \n "
" \n "
" Options: -[%s] \n " , synopsis , short_opts ) ;
/* prescan the --long opt length to auto-align */
optlen = 0 ;
for ( i = 0 ; long_opts [ i ] . name ; + + i ) {
/* +1 is for space between --opt and help text */
int l = strlen ( long_opts [ i ] . name ) + 1 ;
if ( long_opts [ i ] . has_arg = = a_argument )
l + = a_arg_len ;
if ( optlen < l )
optlen = l ;
}
for ( i = 0 ; long_opts [ i ] . name ; + + i ) {
/* helps when adding new applets or options */
assert ( opts_help [ i ] ! = NULL ) ;
/* first output the short flag if it has one */
if ( long_opts [ i ] . val > ' ~ ' )
fprintf ( fp , " " ) ;
else
fprintf ( fp , " -%c, " , long_opts [ i ] . val ) ;
/* then the long flag */
if ( long_opts [ i ] . has_arg = = no_argument )
fprintf ( fp , " --%-*s " , optlen , long_opts [ i ] . name ) ;
else
fprintf ( fp , " --%s %s%*s " , long_opts [ i ] . name , a_arg ,
( int ) ( optlen - strlen ( long_opts [ i ] . name ) - a_arg_len ) , " " ) ;
/* finally the help text */
fprintf ( fp , " %s \n " , opts_help [ i ] ) ;
}
if ( errmsg ) {
fprintf ( fp , " \n Error: %s \n " , errmsg ) ;
exit ( EXIT_FAILURE ) ;
} else
exit ( EXIT_SUCCESS ) ;
}