mirror of
https://github.com/martijnvanbrummelen/nwipe.git
synced 2026-03-14 12:32:10 +00:00
667 lines
20 KiB
C
667 lines
20 KiB
C
/*
|
|
* miscellaneous.c: functions that may be generally used throughout nwipes code,
|
|
* mainly string processing functions but also time related functions.
|
|
*
|
|
* Copyright PartialVolume <https://github.com/PartialVolume>.
|
|
*
|
|
* 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, version 2.
|
|
*
|
|
* 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.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
*/
|
|
|
|
#ifndef _DEFAULT_SOURCE
|
|
#define _DEFAULT_SOURCE
|
|
#endif
|
|
|
|
#ifndef _POSIX_SOURCE
|
|
#define _POSIX_SOURCE
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include "nwipe.h"
|
|
#include "context.h"
|
|
#include "logging.h"
|
|
#include "miscellaneous.h"
|
|
|
|
/* Convert string to upper case
|
|
*/
|
|
void strupper( char* str )
|
|
{
|
|
int idx;
|
|
|
|
idx = 0;
|
|
while( str[idx] != 0 )
|
|
{
|
|
/* If upper case alpha character, change to lower case */
|
|
if( str[idx] >= 'A' && str[idx] <= 'Z' )
|
|
{
|
|
str[idx] -= 32;
|
|
}
|
|
|
|
idx++;
|
|
}
|
|
}
|
|
|
|
/* Convert string to lower case
|
|
*/
|
|
void strlower( char* str )
|
|
{
|
|
int idx;
|
|
|
|
idx = 0;
|
|
while( str[idx] != 0 )
|
|
{
|
|
/* If upper case alpha character, change to lower case */
|
|
if( str[idx] >= 'A' && str[idx] <= 'Z' )
|
|
{
|
|
str[idx] += 32;
|
|
}
|
|
|
|
idx++;
|
|
}
|
|
}
|
|
|
|
void strip_CR_LF( char* str )
|
|
{
|
|
/* In the specified string, replace any CR or LF with a space */
|
|
int idx = 0;
|
|
int len = strlen( str );
|
|
while( idx < len )
|
|
{
|
|
if( str[idx] == 0x0A || str[idx] == 0x0D )
|
|
{
|
|
str[idx] = ' ';
|
|
}
|
|
idx++;
|
|
}
|
|
}
|
|
|
|
/* Search a string for a positive number, convert the first
|
|
* number found to binary and return the binary number.
|
|
* returns the number or -1 if number too large or -2 if
|
|
* no number found.
|
|
*/
|
|
|
|
u64 str_ascii_number_to_ll( char* str )
|
|
{
|
|
int idx;
|
|
int idx2;
|
|
char number_copy[20];
|
|
|
|
idx = 0; // index into the main string we are searching
|
|
idx2 = 0; // index used for backup copy of ascii number
|
|
|
|
while( str[idx] != 0 )
|
|
{
|
|
/* Find the start of the number */
|
|
if( str[idx] >= '0' && str[idx] <= '9' )
|
|
{
|
|
while( str[idx] != 0 )
|
|
{
|
|
/* Find the end of the number */
|
|
if( str[idx] >= '0' && str[idx] <= '9' )
|
|
{
|
|
if( idx2 < sizeof( number_copy ) - 1 )
|
|
{
|
|
number_copy[idx2++] = str[idx++];
|
|
}
|
|
else
|
|
{
|
|
/* Number is too large ! */
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* end found */
|
|
number_copy[idx2] = 0; // terminate our copy
|
|
|
|
/* convert ascii number to longlong */
|
|
return atoll( number_copy );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
idx++;
|
|
}
|
|
}
|
|
return -2; /* no number found */
|
|
}
|
|
|
|
void Determine_C_B_nomenclature( u64 qty, char* result, int result_array_size )
|
|
{
|
|
|
|
/* C_B ? Determine Capacity or Bandwidth nomenclature
|
|
*
|
|
* A pointer to a result character string with a minimum of 13 characters in length
|
|
* should be provided.
|
|
*
|
|
* Outputs a string of the form xxxTB, xxxGB, xxxMB, xxxKB B depending on the value of 'qty'
|
|
*/
|
|
|
|
/* Initialise the output array */
|
|
int idx = 0;
|
|
|
|
while( idx < result_array_size )
|
|
{
|
|
result[idx++] = 0;
|
|
}
|
|
|
|
/* Determine the size of throughput so that the correct nomenclature can be used */
|
|
if( qty >= INT64_C( 10000000000000 ) )
|
|
{
|
|
snprintf( result, result_array_size, "%4llu TB", qty / INT64_C( 1000000000000 ) );
|
|
}
|
|
else if( qty >= INT64_C( 10000000000 ) )
|
|
{
|
|
snprintf( result, result_array_size, "%4llu GB", qty / INT64_C( 1000000000 ) );
|
|
}
|
|
else if( qty >= INT64_C( 10000000 ) )
|
|
{
|
|
snprintf( result, result_array_size, "%4llu MB", qty / INT64_C( 1000000 ) );
|
|
}
|
|
else if( qty >= INT64_C( 10000 ) )
|
|
{
|
|
snprintf( result, result_array_size, "%4llu KB", qty / INT64_C( 1000 ) );
|
|
}
|
|
else
|
|
{
|
|
snprintf( result, result_array_size, "%4llu B", qty / INT64_C( 1 ) );
|
|
}
|
|
}
|
|
|
|
void convert_seconds_to_hours_minutes_seconds( u64 total_seconds, int* hours, int* minutes, int* seconds )
|
|
{
|
|
/* Convert binary seconds into binary hours, minutes and seconds */
|
|
|
|
if( total_seconds % 60 )
|
|
{
|
|
*minutes = total_seconds / 60;
|
|
|
|
*seconds = total_seconds - ( *minutes * 60 );
|
|
}
|
|
else
|
|
{
|
|
*minutes = total_seconds / 60;
|
|
|
|
*seconds = 0;
|
|
}
|
|
if( *minutes > 59 )
|
|
{
|
|
*hours = *minutes / 60;
|
|
if( *minutes % 60 )
|
|
{
|
|
*minutes = *minutes - ( *hours * 60 );
|
|
}
|
|
else
|
|
{
|
|
*minutes = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
int nwipe_strip_path( char* output, char* input )
|
|
{
|
|
/* Take the input string, say "/dev/sda" and remove the "/dev/", prefix the result
|
|
* with 'length' spaces. So if length=8 and input=/dev/sda, output will
|
|
* be " sda", a string 8 characters long right justified with spaces.
|
|
*/
|
|
int idx_dest;
|
|
int idx_src;
|
|
idx_dest = 8;
|
|
// idx_dest = length;
|
|
output[idx_dest--] = 0;
|
|
idx_src = strlen( input );
|
|
idx_src--;
|
|
|
|
while( idx_dest >= 0 )
|
|
{
|
|
/* if the device name contains a / start prefixing spaces */
|
|
if( input[idx_src] == '/' )
|
|
{
|
|
output[idx_dest--] = ' ';
|
|
continue;
|
|
}
|
|
if( idx_src >= 0 )
|
|
{
|
|
output[idx_dest--] = input[idx_src--];
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void replace_non_alphanumeric( char* str, char replacement_char )
|
|
{
|
|
int i = 0;
|
|
while( str[i] != 0 )
|
|
{
|
|
if( str[i] < '0' || ( str[i] > '9' && str[i] < 'A' ) || ( str[i] > 'Z' && str[i] < 'a' ) || str[i] > 'z' )
|
|
{
|
|
str[i] = replacement_char;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
void convert_double_to_string( char* output_str, double value )
|
|
{
|
|
int idx = 0;
|
|
int idx2;
|
|
int idx3 = 0;
|
|
|
|
char percstr[512] = "";
|
|
|
|
snprintf( percstr, sizeof( percstr ), "%5.32lf", value );
|
|
|
|
while( percstr[idx] != 0 )
|
|
{
|
|
if( percstr[idx] == '.' )
|
|
{
|
|
for( idx2 = 0; idx2 < 3; idx2++ )
|
|
{
|
|
output_str[idx3++] = percstr[idx++];
|
|
}
|
|
break;
|
|
}
|
|
output_str[idx3++] = percstr[idx++];
|
|
}
|
|
output_str[idx3] = 0;
|
|
}
|
|
|
|
int read_system_datetime( char* year, char* month, char* day, char* hours, char* minutes, char* seconds )
|
|
{
|
|
/* Reads system date & time and populates the caller provided strings.
|
|
* Each string is null terminated by this function. The calling program
|
|
* must provide the minimum string sizes as shown below.
|
|
*
|
|
* year 5 bytes (4 numeric digits plus NULL terminator)
|
|
* month 3 bytes (2 numeric digits plus NULL terminator)
|
|
* day 3 bytes (2 numeric digits plus NULL terminator)
|
|
* hours 3 bytes (2 numeric digits plus NULL terminator)
|
|
* minutes 3 bytes (2 numeric digits plus NULL terminator)
|
|
* seconds 3 bytes (2 numeric digits plus NULL terminator)
|
|
*
|
|
* return value:
|
|
* 0 = success
|
|
* -1 = Failure, see nwipe log for detail.
|
|
*/
|
|
FILE* fp;
|
|
int r; // A result buffer.
|
|
int idx; // general index
|
|
int status = 0;
|
|
|
|
/**
|
|
* Obtain the year
|
|
*/
|
|
fp = popen( "date +%Y", "r" );
|
|
if( fp == NULL )
|
|
{
|
|
nwipe_log( NWIPE_LOG_ERROR, "Failed to obtain system year using commmand = date +%Y" );
|
|
}
|
|
else
|
|
{
|
|
/* Read the first line and validate it. Should be 4 numeric digits */
|
|
if( fgets( year, FOUR_DIGITS + 1, fp ) != NULL )
|
|
{
|
|
idx = 0;
|
|
while( idx < 4 )
|
|
{
|
|
if( year[idx] >= '0' && year[idx] <= '9' )
|
|
{
|
|
idx++;
|
|
}
|
|
else
|
|
{
|
|
/* if we haven't reached the correct number of digits due to invalid data, log error */
|
|
year[++idx] = 0; /* terminate the string, prior to using in nwipe_log */
|
|
nwipe_log( NWIPE_LOG_ERROR,
|
|
"Obtained system year using command = date +%Y, but result appears invalid = %s",
|
|
year );
|
|
status = -1;
|
|
break;
|
|
}
|
|
}
|
|
year[idx] = 0; /* terminate the string */
|
|
}
|
|
r = pclose( fp );
|
|
}
|
|
|
|
/**
|
|
* Obtain the month
|
|
*/
|
|
fp = popen( "date +%m", "r" );
|
|
if( fp == NULL )
|
|
{
|
|
nwipe_log( NWIPE_LOG_ERROR, "Failed to obtain system month using the command = date +%m" );
|
|
}
|
|
else
|
|
{
|
|
/* Read the first line and validate it. Should be 2 numeric digits */
|
|
if( fgets( month, TWO_DIGITS + 1, fp ) != NULL )
|
|
{
|
|
idx = 0;
|
|
while( idx < 2 )
|
|
{
|
|
if( month[idx] >= '0' && month[idx] <= '9' )
|
|
{
|
|
idx++;
|
|
}
|
|
else
|
|
{
|
|
/* if we haven't reached the correct number of digits due to invalid data, log error */
|
|
month[++idx] = 0; /* terminate the string, prior to using in nwipe_log */
|
|
nwipe_log( NWIPE_LOG_ERROR,
|
|
"Obtained system month using command = date +%m, but result appears invalid = %s",
|
|
month );
|
|
status = -1;
|
|
break;
|
|
}
|
|
}
|
|
month[idx] = 0; /* terminate the string */
|
|
}
|
|
r = pclose( fp );
|
|
}
|
|
|
|
/**
|
|
* Obtain the day
|
|
*/
|
|
fp = popen( "date +\%d", "r" );
|
|
if( fp == NULL )
|
|
{
|
|
nwipe_log( NWIPE_LOG_ERROR, "Failed to obtain system day using the command = date +\%d" );
|
|
}
|
|
else
|
|
{
|
|
/* Read the first line and validate it. Should be 2 numeric digits */
|
|
if( fgets( day, TWO_DIGITS + 1, fp ) != NULL )
|
|
{
|
|
idx = 0;
|
|
while( idx < 2 )
|
|
{
|
|
if( day[idx] >= '0' && day[idx] <= '9' )
|
|
{
|
|
idx++;
|
|
}
|
|
else
|
|
{
|
|
/* if we haven't reached the correct number of digits due to invalid data, log error */
|
|
day[++idx] = 0; /* terminate the string, prior to using in nwipe_log */
|
|
nwipe_log( NWIPE_LOG_ERROR,
|
|
"Obtained system day using command = date +\%d, but result appears invalid = %s",
|
|
day );
|
|
status = -1;
|
|
break;
|
|
}
|
|
}
|
|
day[idx] = 0; /* terminate the string */
|
|
}
|
|
r = pclose( fp );
|
|
}
|
|
|
|
/**
|
|
* Obtain the hours
|
|
*/
|
|
fp = popen( "date +%H", "r" );
|
|
if( fp == NULL )
|
|
{
|
|
nwipe_log( NWIPE_LOG_ERROR, "Failed to obtain system hour using the command = date +%H" );
|
|
}
|
|
else
|
|
{
|
|
/* Read the first line and validate it. Should be 2 numeric digits */
|
|
if( fgets( hours, TWO_DIGITS + 1, fp ) != NULL )
|
|
{
|
|
// nwipe_log( NWIPE_LOG_INFO, "Seconds = %s, Year = %s", seconds, year);
|
|
idx = 0;
|
|
while( idx < 2 )
|
|
{
|
|
if( hours[idx] >= '0' && hours[idx] <= '9' )
|
|
{
|
|
idx++;
|
|
}
|
|
else
|
|
{
|
|
/* if we haven't reached the correct number of digits due to invalid data, log error */
|
|
hours[++idx] = 0; /* terminate the string, prior to using in nwipe_log */
|
|
nwipe_log( NWIPE_LOG_ERROR,
|
|
"Obtained system hours using command = date +%H, but result appears invalid = %s",
|
|
hours );
|
|
status = -1;
|
|
break;
|
|
}
|
|
}
|
|
hours[idx] = 0; /* terminate the string */
|
|
}
|
|
r = pclose( fp );
|
|
}
|
|
|
|
/**
|
|
* Obtain the minutes
|
|
*/
|
|
fp = popen( "date +%M", "r" );
|
|
if( fp == NULL )
|
|
{
|
|
nwipe_log( NWIPE_LOG_ERROR, "Failed to obtain system minutes using the command = date +%M" );
|
|
}
|
|
else
|
|
{
|
|
/* Read the first line and validate it. Should be 2 numeric digits */
|
|
if( fgets( minutes, TWO_DIGITS + 1, fp ) != NULL )
|
|
{
|
|
// nwipe_log( NWIPE_LOG_INFO, "Seconds = %s, Year = %s", seconds, year);
|
|
idx = 0;
|
|
while( idx < 2 )
|
|
{
|
|
if( minutes[idx] >= '0' && minutes[idx] <= '9' )
|
|
{
|
|
idx++;
|
|
}
|
|
else
|
|
{
|
|
/* if we haven't reached the correct number of digits due to invalid data, log the error */
|
|
minutes[++idx] = 0; /* terminate the string, prior to using in nwipe_log */
|
|
nwipe_log( NWIPE_LOG_ERROR,
|
|
"Obtained system minutes using command = date +%H, but result appears invalid = %s",
|
|
minutes );
|
|
status = -1;
|
|
break;
|
|
}
|
|
}
|
|
minutes[idx] = 0; /* terminate the string */
|
|
}
|
|
r = pclose( fp );
|
|
}
|
|
|
|
/**
|
|
* Obtain the seconds
|
|
*/
|
|
fp = popen( "date +%S", "r" );
|
|
if( fp == NULL )
|
|
{
|
|
nwipe_log( NWIPE_LOG_ERROR, "Failed to obtain system seconds using the command = date +%S" );
|
|
}
|
|
else
|
|
{
|
|
/* Read the first line and validate it. Should be 2 numeric digits */
|
|
if( fgets( seconds, TWO_DIGITS + 1, fp ) != NULL )
|
|
{
|
|
// nwipe_log( NWIPE_LOG_INFO, "Seconds = %s, Year = %s", seconds, year);
|
|
idx = 0;
|
|
while( idx < 2 )
|
|
{
|
|
if( seconds[idx] >= '0' && seconds[idx] <= '9' )
|
|
{
|
|
idx++;
|
|
}
|
|
else
|
|
{
|
|
/* if we haven't reached the correct number of digits due to invalid data, log error */
|
|
seconds[++idx] = 0; /* terminate the string, prior to using in nwipe_log */
|
|
nwipe_log( NWIPE_LOG_ERROR,
|
|
"Obtained system seconds using command = date +%S, but result appears invalid = %s",
|
|
seconds );
|
|
status = -1;
|
|
break;
|
|
}
|
|
}
|
|
seconds[idx] = 0; /* terminate the string */
|
|
}
|
|
r = pclose( fp );
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
int write_system_datetime( char* year, char* month, char* day, char* hours, char* minutes, char* seconds )
|
|
{
|
|
/* Writes the system date & time using data from the caller provided strings.
|
|
* The calling program must provide the minimum string sizes as shown below
|
|
* populated with current date and time data.
|
|
*
|
|
* year 5 bytes (4 numeric digits plus NULL terminator)
|
|
* month 3 bytes (2 numeric digits plus NULL terminator)
|
|
* day 3 bytes (2 numeric digits plus NULL terminator)
|
|
* hours 3 bytes (2 numeric digits plus NULL terminator)
|
|
* minutes 3 bytes (2 numeric digits plus NULL terminator)
|
|
* seconds 3 bytes (2 numeric digits plus NULL terminator)
|
|
*
|
|
* return value:
|
|
* 0 = success
|
|
* -1 = Failure, see nwipe log for detail.
|
|
*/
|
|
FILE* fp;
|
|
int r; // A result buffer.
|
|
int idx; // general index
|
|
int strIdx; // Index into each string
|
|
int bufferIdx; // Index into the buffer
|
|
char buffer[5];
|
|
|
|
/**
|
|
* Basic validation that confirms the input strings are numeric and of the correct length, we do this
|
|
* by first constructing three arrays. The first are the names of the variables in order
|
|
* year, month, day, hours, minutes and seconds. The second array contains the address of
|
|
* each of those strings. The third array are the lengths.
|
|
* This allows us to create a single loop to validate all fields.
|
|
*/
|
|
|
|
char* names[] = { "year", "month", "day", "hours", "minutes", "seconds" };
|
|
char* pdata[] = { year, month, day, hours, minutes, seconds };
|
|
int lengths[] = { 4, 2, 2, 2, 2, 2 };
|
|
char cmd_format[] = "date %s%s%s%s%s.%s >/dev/null 2>&1";
|
|
char cmd[256];
|
|
|
|
for( idx = 0; idx < 6; idx++ )
|
|
{
|
|
strIdx = 0; // initialise string index
|
|
|
|
/* check each characters is numeric */
|
|
while( strIdx < lengths[idx] )
|
|
{
|
|
if( pdata[idx][strIdx] >= '0' && pdata[idx][strIdx] <= '9' )
|
|
{
|
|
strIdx++;
|
|
}
|
|
else
|
|
{
|
|
/* if we haven't reached the correct number of digits due to invalid data, log error,
|
|
* but first we read the valid data acquired so far into a buffer, this is done to avoid
|
|
* writing to the user provided string because if they did not size the string correctly
|
|
* writing a zero at the end could cause a segfault.
|
|
*/
|
|
|
|
for( bufferIdx = 0; bufferIdx < strIdx + 1; bufferIdx++ )
|
|
{
|
|
buffer[bufferIdx] = pdata[idx][bufferIdx];
|
|
}
|
|
buffer[bufferIdx] = 0; /* terminate the string, prior to using in nwipe_log */
|
|
|
|
/* A typical error will look like ..
|
|
* "User provided year data that appear invalid = 202£" */
|
|
nwipe_log( NWIPE_LOG_ERROR, "User provided %s data that appears invalid = %s", names[idx], buffer );
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Now using the validated strings construct the date command that we will use to write the system date/time
|
|
*/
|
|
sprintf( cmd, cmd_format, month, day, hours, minutes, year, seconds );
|
|
|
|
/**
|
|
* Run the date command to write the new date/time
|
|
*/
|
|
|
|
fp = popen( cmd, "w" );
|
|
r = pclose( fp );
|
|
|
|
if( fp == NULL || r != 0 )
|
|
{
|
|
nwipe_log( NWIPE_LOG_ERROR, "Failed to write system date/time using command = %s", cmd );
|
|
}
|
|
else
|
|
{
|
|
nwipe_log( NWIPE_LOG_INFO, "Date/time succesfully writen to system using command = %s", cmd );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void fix_endian_model_names( char* model )
|
|
{
|
|
/* Some IDE USB adapters get the endian wrong, we can't determine the endian from the drive
|
|
* as the drive standard doesn't provide that information, so we have to resort to matching
|
|
* the model name against known strings with the endian incorrect, then reverse the endian.
|
|
*/
|
|
|
|
int idx = 0;
|
|
int idx2 = 0;
|
|
unsigned int length = 0;
|
|
char* tmp_string;
|
|
|
|
length = strlen( model );
|
|
|
|
tmp_string = calloc( length, 1 );
|
|
|
|
/* "ASSMNU G" = "SAMSUNG ", tested against model Samsung HM160HC so that
|
|
* "ASSMNU G MH61H0 C" becomes "SAMSUNG HM160HC ")
|
|
*/
|
|
if( !( strncmp( model, "ASSMNU G", 8 ) ) )
|
|
{
|
|
while( model[idx] != 0 )
|
|
{
|
|
tmp_string[idx2 + 1] = model[idx];
|
|
if( model[idx + 1] != 0 )
|
|
{
|
|
tmp_string[idx2] = model[idx + 1];
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
if( tmp_string[idx2 + 1] == ' ' && model[idx + 2] == ' ' )
|
|
{
|
|
idx++;
|
|
}
|
|
|
|
idx += 2;
|
|
idx2 += 2;
|
|
}
|
|
|
|
tmp_string[idx2 + 1] = 0;
|
|
strcpy( model, tmp_string );
|
|
}
|
|
}
|