diff options
Diffstat (limited to 'src/miscellaneous.c')
-rw-r--r-- | src/miscellaneous.c | 666 |
1 files changed, 666 insertions, 0 deletions
diff --git a/src/miscellaneous.c b/src/miscellaneous.c new file mode 100644 index 0000000..bc2dc01 --- /dev/null +++ b/src/miscellaneous.c @@ -0,0 +1,666 @@ +/* + * 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 ); + } +} |