Skip to content

Commit

Permalink
Refactor decoder functions
Browse files Browse the repository at this point in the history
  • Loading branch information
Matsievskiy S.V committed Nov 21, 2022
1 parent 64f296d commit ba93e3c
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 149 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ endfunction()

add_executable(frugen frugen.c)
add_executable(frugen-static frugen.c)
add_library(fru-static STATIC fru.c fru_reader.c)
add_library(fru-shared SHARED fru.c fru_reader.c)
add_library(fru-static STATIC fru.c)
add_library(fru-shared SHARED fru.c)
find_library(JSON_LIB json-c)
SET_TARGET_PROPERTIES(fru-static PROPERTIES OUTPUT_NAME fru CLEAN_DIRECT_OUTPUT 1)
SET_TARGET_PROPERTIES(fru-shared PROPERTIES OUTPUT_NAME fru CLEAN_DIRECT_OUTPUT 1)
Expand Down
6 changes: 0 additions & 6 deletions fatal.h

This file was deleted.

63 changes: 53 additions & 10 deletions fru.c
Original file line number Diff line number Diff line change
Expand Up @@ -404,17 +404,9 @@ fru_field_t * fru_encode_data(int len, const uint8_t *data)
return out;
}

/**
* Decode data from a buffer into another buffer.
*
* For binary data use FRU_FIELDDATALEN(field->typelen) to find
* out the size of valid bytes in the returned buffer.
*
* Return false if there were errors during decoding and true otherwise.
*/
bool fru_decode_data(fru_field_t *field,
typed_field_t *out, //< [out] buffer to decode into
size_t out_len) // <[in] length of output buffer
typed_field_t *out,
size_t out_len)
{
if (!field) return false;

Expand Down Expand Up @@ -1225,6 +1217,57 @@ fru_t * fru_create(fru_area_t area[FRU_MAX_AREAS], size_t *size)
return out;
}

fru_t *find_fru_header(uint8_t *buffer, size_t size) {
if (size < 8) {
errno = ENOBUFS;
return NULL;
}
fru_t *header = (fru_t *) buffer;
if ((header->ver != FRU_VER_1) || (header->rsvd != 0) || (header->pad != 0)) {
errno = EPROTO;
return NULL;
}
if (header->hchecksum != calc_checksum(header, sizeof(fru_t) - 1)) {
errno = EPROTO;
return NULL;
}
return header;
}

#define AREAS \
X(chassis) \
X(board) \
X(product)
#define X(AREA) \
fru_##AREA##_area_t *find_fru_##AREA##_area(uint8_t *buffer, size_t size) { \
fru_t *header = find_fru_header(buffer, size); \
if ((header == NULL) || (header->AREA == 0)) { \
return NULL; \
} \
if ((header->AREA + 3) > size) { \
errno = ENOBUFS; \
return NULL; \
} \
fru_##AREA##_area_t *area = \
(fru_##AREA##_area_t *)(buffer + FRU_BYTES(header->AREA)); \
if (area->ver != 1) { \
errno = EPROTO; \
return NULL; \
} \
if (FRU_BYTES(header->AREA) + FRU_BYTES(area->blocks) > size) { \
errno = ENOBUFS; \
return NULL; \
} \
if (*(((uint8_t *)area) + FRU_BYTES(area->blocks) - 1) != \
calc_checksum(((uint8_t *)area), FRU_BYTES(area->blocks) - 1)) { \
errno = EPROTO; \
return NULL; \
} \
return area; \
}
AREAS
#undef X
#undef AREAS

#ifdef __STANDALONE__

Expand Down
88 changes: 84 additions & 4 deletions fru.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,13 +327,93 @@ fru_mr_reclist_t * add_mr_reclist(fru_mr_reclist_t **reclist);
fru_mr_area_t * fru_mr_area(fru_mr_reclist_t *reclist, size_t *total);

fru_chassis_area_t * fru_encode_chassis_info(const fru_exploded_chassis_t *chassis);
bool fru_decode_chassis_info(const fru_chassis_area_t *area, fru_exploded_chassis_t *chassis_out);
fru_board_area_t * fru_encode_board_info(const fru_exploded_board_t *board);
bool fru_decode_board_info(const fru_board_area_t *area, fru_exploded_board_t *board_out);
fru_product_area_t * fru_encode_product_info(const fru_exploded_product_t *product);
bool fru_decode_product_info(const fru_product_area_t *area, fru_exploded_product_t *product_out);
fru_field_t * fru_encode_data(int len, const uint8_t *data);
bool fru_decode_data(fru_field_t *field, typed_field_t *out, size_t out_len);
fru_t * fru_create(fru_area_t area[FRU_MAX_AREAS], size_t *size);

/**
* @brief Find and validate FRU header in the byte buffer.
*
* @param[in] buffer Byte buffer.
* @param[in] size Byte buffer size.
* @return Pointer to the FRU header in the buffer.
* @retval NULL FRU header not found.
*/
fru_t *find_fru_header(uint8_t *buffer, size_t size);

/**
* @brief Find and validate FRU chassis area in the byte buffer.
*
* @param[in] buffer Byte buffer.
* @param[in] size Byte buffer size.
* @return Pointer to the FRU chassis area in the buffer.
* @retval NULL FRU chassis area not found.
*/
fru_chassis_area_t *find_fru_chassis_area(uint8_t *buffer, size_t size);

/**
* @brief Find and validate FRU board area in the byte buffer.
*
* @param[in] buffer Byte buffer.
* @param[in] size Byte buffer size.
* @return Pointer to the FRU board area in the buffer.
* @retval NULL FRU board area not found.
*/
fru_board_area_t *find_fru_board_area(uint8_t *buffer, size_t size);

/**
* @brief Find and validate FRU product area in the byte buffer.
*
* @param[in] buffer Byte buffer.
* @param[in] size Byte buffer size.
* @return Pointer to the FRU product area in the buffer.
* @retval NULL FRU product area not found.
*/
fru_product_area_t *find_fru_product_area(uint8_t *buffer, size_t size);

/**
* @brief Decode chassis area into \p fru_exploded_chassis_t.
*
* @param[in] area Encoded area.
* @param[out] chassis_out Decoded structure.
* @retval true Success.
* @retval false Failure.
*/
bool fru_decode_chassis_info(const fru_chassis_area_t *area, fru_exploded_chassis_t *chassis_out);

/**
* @brief Decode board area into \p fru_exploded_board_t.
*
* @param[in] area Encoded area.
* @param[out] chassis_out Decoded structure.
* @retval true Success.
* @retval false Failure.
*/
bool fru_decode_board_info(const fru_board_area_t *area, fru_exploded_board_t *board_out);

/**
* @brief Decode product area into \p fru_product_board_t.
*
* @param[in] area Encoded area.
* @param[out] chassis_out Decoded structure.
* @retval true Success.
* @retval false Failure.
*/
bool fru_decode_product_info(const fru_product_area_t *area, fru_exploded_product_t *product_out);

/**
* Decode data from a buffer into another buffer.
*
* For binary data use FRU_FIELDDATALEN(field->typelen) to find
* out the size of valid bytes in the returned buffer.
*
* @param[in] field Encoded data field.
* @param[out] out Decoded field.
* @param[in] out_len Size of the decoded field region.
* @retval true Success.
* @retval false Failure.
*/
bool fru_decode_data(fru_field_t *field, typed_field_t *out, size_t out_len);

#endif // __FRULIB_FRU_H__
84 changes: 0 additions & 84 deletions fru_reader.c

This file was deleted.

5 changes: 0 additions & 5 deletions fru_reader.h

This file was deleted.

75 changes: 37 additions & 38 deletions frugen.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#endif

#define COPYRIGHT_YEARS "2016-2021"
#define MAX_FILE_SIZE 1L * 1024L * 1024L

#define _GNU_SOURCE
#include <getopt.h>
Expand All @@ -23,14 +24,18 @@
#include <time.h>
#include <errno.h>
#include "fru.h"
#include "fru_reader.h"
#include "smbios.h"
#include "fatal.h"

#ifdef __HAS_JSON__
#include <json-c/json.h>
#endif

#define fatal(fmt, args...) do { \
fprintf(stderr, fmt, ##args); \
fprintf(stderr, "\n"); \
exit(1); \
} while(0)

const char* type_names[] = {
"auto",
"binary",
Expand Down Expand Up @@ -749,54 +754,48 @@ int main(int argc, char *argv[])
fatal("Failed to open file: %s", strerror(errno));
}

fru_t *raw_fru = read_fru_header(fd);
if (!raw_fru)
fatal("Failed to read fru header");
struct stat statbuf = {0};
if (fstat(fd, &statbuf)) {
fatal("Failed to get file properties: %s", strerror(errno));
}
if (statbuf.st_size > MAX_FILE_SIZE) {
fatal("File too large");
}

if (raw_fru->chassis != 0) {
if (lseek(fd, 8 * raw_fru->chassis, SEEK_SET) < 0)
fatal("Failed to seek");
uint8_t *buffer = calloc(1, statbuf.st_size);
if (buffer == NULL) {
fatal("Cannot allocate buffer");
}

fru_chassis_area_t *chassis_raw =
read_fru_chassis_area(fd);
bool success = fru_decode_chassis_info(
chassis_raw, &chassis);
if (!success)
fatal("Failed to decode chassis");
if (read(fd, buffer, statbuf.st_size) != statbuf.st_size) {
fatal("Cannot read file");
}
close(fd);

free(chassis_raw);
fru_chassis_area_t *chassis_area =
find_fru_chassis_area(buffer, statbuf.st_size);
if (chassis_area) {
if (!fru_decode_chassis_info(chassis_area, &chassis))
fatal("Failed to decode chassis");
has_chassis = true;
}
if (raw_fru->board != 0) {
if(lseek(fd, 8 * raw_fru->board, SEEK_SET) < 0)
fatal("Failed to seek");

fru_board_area_t *board_raw = read_fru_board_area(fd);
bool success = fru_decode_board_info(board_raw, &board);
if (!success)
fru_board_area_t *board_area =
find_fru_board_area(buffer, statbuf.st_size);
if (board_area) {
if (!fru_decode_board_info(board_area, &board))
fatal("Failed to decode board");

free(board_raw);
has_board = true;
has_bdate = true;
}
if (raw_fru->product != 0) {
if (lseek(fd, 8 * raw_fru->product, SEEK_SET) < 0)
fatal("Failed to seek");

fru_product_area_t *product_raw =
read_fru_product_area(fd);
bool success =
fru_decode_product_info(product_raw, &product);
if (!success)
fatal("Failed to decode product");

free(product_raw);
fru_product_area_t *product_area =
find_fru_product_area(buffer, statbuf.st_size);
if (product_area) {
if (!fru_decode_product_info(product_area, &product))
fatal("Failed to decode product");
has_product = true;
}

free(raw_fru);
close(fd);
free(buffer);
}
else {
fatal("The requested input file format is not supported");
Expand Down

0 comments on commit ba93e3c

Please sign in to comment.