int fruid_modify()

in common/recipes-lib/fruid/files/fruid.c [1255:1949]


int fruid_modify(const char * cur_bin, const char * new_bin, const char * field, const char * content)
{
  int fruid_len, ret;
  FILE *fruid_fd;
  uint8_t *old_eeprom, *eeprom = NULL;
  int total_field_opt_size = sizeof(fruid_field_all_opt)/sizeof(fruid_field_all_opt[0]);
  fruid_info_t fruid;
  int i, len;
  int target = -1;
  char *tmp_content = NULL;
  int content_len;
  int new_fruid_len;
  uint8_t type_length;

  /* Reset parser return value */
  ret = 0;

  /* Open the FRUID binary file */
  fruid_fd = fopen(cur_bin, "rb");
  if (!fruid_fd) {
#ifdef DEBUG
    syslog(LOG_ERR, "fruid: unable to open the file");
#endif
    return ENOENT;
  }

  /* Get the size of the binary file */
  fseek(fruid_fd, 0, SEEK_END);
  fruid_len = (uint32_t) ftell(fruid_fd);

  fseek(fruid_fd, 0, SEEK_SET);

  old_eeprom = (uint8_t *) malloc(fruid_len);
  if (!old_eeprom) {
#ifdef DEBUG
    syslog(LOG_WARNING, "fruid: malloc: memory allocation failed\n");
#endif
    return ENOMEM;
  }

  /* Read the binary file */
  ret = fread(old_eeprom, sizeof(uint8_t), fruid_len, fruid_fd);
  if (ret != fruid_len) {
    printf("Failed to read binary file, inconsistent length\n");
    return -1;
  }

  /* Close the FRUID binary file */
  fclose(fruid_fd);

  /* Parse eeprom dump*/
  ret = fruid_parse_eeprom(old_eeprom, fruid_len, &fruid);

  /* Free the eeprom malloced memory */
  free(old_eeprom);

  if (ret) {
    printf("Failed to parse FRU!\n");
    return -1;
  }

  for(i = 0; i < total_field_opt_size; i++) {
    if (!strcmp(field, fruid_field_all_opt[i])) {
      target = i;
      break;
    }
  }
  if (target == -1) {
    printf("Parameter \"%s\" is invalid!\n", field);
    return -1;
  }

  if (target <= CCD6) {
    if (fruid.chassis.flag != 1) {
      printf("Chassis Area is invalid!\n");
      return -1;
    }
  } else if (target <= BCD6) {
    if (fruid.board.flag != 1) {
      printf("Board Area is invalid!\n");
      return -1;
    }
  } else {
    if (fruid.product.flag != 1) {
      printf("Product Area is invalid!\n");
      return -1;
    }
  }

  tmp_content = extract_content(content);
  content_len = strlen(tmp_content);

  if (content_len > MAX_FIELD_LENGTH) {
    printf("Content length \"%s\" is more than its maximum length:%d !\n", field, MAX_FIELD_LENGTH);
    return -1;
  }

  if (content_len)
    type_length = 0xc0 + content_len;
  else
    type_length = 0;

  // check custom field type length
  switch (target) {
    case CCD1:
    case CCD2:
    case CCD3:
    case CCD4:
    case CCD5:
    case CCD6:
    case BCD1:
    case BCD2:
    case BCD3:
    case BCD4:
    case BCD5:
    case BCD6:
    case PCD1:
    case PCD2:
    case PCD3:
    case PCD4:
    case PCD5:
    case PCD6:
      if (type_length == NO_MORE_DATA_BYTE) {
        printf("Content length \"%s\" should not be 1 !\n", field);
        return -1;
      }
      break;
    default:
      break;
  }

  // alter field content
  switch (target) {
    case CPN:
      fruid.chassis.part_type_len = type_length;
      alter_field_content(&fruid.chassis.part,tmp_content);
      break;
    case CSN:
      fruid.chassis.serial_type_len = type_length;
      alter_field_content(&fruid.chassis.serial,tmp_content);
      break;
    case CCD1:
      fruid.chassis.custom1_type_len = type_length;
      alter_field_content(&fruid.chassis.custom1,tmp_content);
      break;
    case CCD2:
      if (fruid.chassis.custom1_type_len == NO_MORE_DATA_BYTE)
        fruid.chassis.custom1_type_len = 0;
      fruid.chassis.custom2_type_len = type_length;
      alter_field_content(&fruid.chassis.custom2,tmp_content);
      break;
    case CCD3:
      if (fruid.chassis.custom1_type_len == NO_MORE_DATA_BYTE)
        fruid.chassis.custom1_type_len = 0;
      if (fruid.chassis.custom2_type_len == NO_MORE_DATA_BYTE)
        fruid.chassis.custom2_type_len = 0;
      fruid.chassis.custom3_type_len = type_length;
      alter_field_content(&fruid.chassis.custom3,tmp_content);
      break;
    case CCD4:
      if (fruid.chassis.custom1_type_len == NO_MORE_DATA_BYTE)
        fruid.chassis.custom1_type_len = 0;
      if (fruid.chassis.custom2_type_len == NO_MORE_DATA_BYTE)
        fruid.chassis.custom2_type_len = 0;
      if (fruid.chassis.custom3_type_len == NO_MORE_DATA_BYTE)
        fruid.chassis.custom3_type_len = 0;
      fruid.chassis.custom4_type_len = type_length;
      alter_field_content(&fruid.chassis.custom4,tmp_content);
      break;
    case CCD5:
      if (fruid.chassis.custom1_type_len == NO_MORE_DATA_BYTE)
        fruid.chassis.custom1_type_len = 0;
      if (fruid.chassis.custom2_type_len == NO_MORE_DATA_BYTE)
        fruid.chassis.custom2_type_len = 0;
      if (fruid.chassis.custom3_type_len == NO_MORE_DATA_BYTE)
        fruid.chassis.custom3_type_len = 0;
      if (fruid.chassis.custom4_type_len == NO_MORE_DATA_BYTE)
        fruid.chassis.custom4_type_len = 0;
      fruid.chassis.custom5_type_len = type_length;
      alter_field_content(&fruid.chassis.custom5,tmp_content);
      break;
    case CCD6:
      if (fruid.chassis.custom1_type_len == NO_MORE_DATA_BYTE)
        fruid.chassis.custom1_type_len = 0;
      if (fruid.chassis.custom2_type_len == NO_MORE_DATA_BYTE)
        fruid.chassis.custom2_type_len = 0;
      if (fruid.chassis.custom3_type_len == NO_MORE_DATA_BYTE)
        fruid.chassis.custom3_type_len = 0;
      if (fruid.chassis.custom4_type_len == NO_MORE_DATA_BYTE)
        fruid.chassis.custom4_type_len = 0;
      if (fruid.chassis.custom5_type_len == NO_MORE_DATA_BYTE)
        fruid.chassis.custom5_type_len = 0;
      fruid.chassis.custom6_type_len = type_length;
      alter_field_content(&fruid.chassis.custom6,tmp_content);
      break;
    case BMD:
      if(set_mfg_time(fruid.board.mfg_time, tmp_content) < 0) {
        return -1;
      }
      break;
    case BM:
      fruid.board.mfg_type_len = type_length;
      alter_field_content(&fruid.board.mfg,tmp_content);
      break;
    case BP:
      fruid.board.name_type_len = type_length;
      alter_field_content(&fruid.board.name,tmp_content);
      break;
    case BSN:
      fruid.board.serial_type_len = type_length;
      alter_field_content(&fruid.board.serial,tmp_content);
      break;
    case BPN:
      fruid.board.part_type_len = type_length;
      alter_field_content(&fruid.board.part,tmp_content);
      break;
    case BFI:
      fruid.board.fruid_type_len = type_length;
      alter_field_content(&fruid.board.fruid,tmp_content);
      break;
    case BCD1:
      fruid.board.custom1_type_len = type_length;
      alter_field_content(&fruid.board.custom1,tmp_content);
      break;
    case BCD2:
      if (fruid.board.custom1_type_len == NO_MORE_DATA_BYTE)
        fruid.board.custom1_type_len = 0;
      fruid.board.custom2_type_len = type_length;
      alter_field_content(&fruid.board.custom2,tmp_content);
      break;
    case BCD3:
      if (fruid.board.custom1_type_len == NO_MORE_DATA_BYTE)
        fruid.board.custom1_type_len = 0;
      if (fruid.board.custom2_type_len == NO_MORE_DATA_BYTE)
        fruid.board.custom2_type_len = 0;
      fruid.board.custom3_type_len = type_length;
      alter_field_content(&fruid.board.custom3,tmp_content);
      break;
    case BCD4:
      if (fruid.board.custom1_type_len == NO_MORE_DATA_BYTE)
        fruid.board.custom1_type_len = 0;
      if (fruid.board.custom2_type_len == NO_MORE_DATA_BYTE)
        fruid.board.custom2_type_len = 0;
      if (fruid.board.custom3_type_len == NO_MORE_DATA_BYTE)
        fruid.board.custom3_type_len = 0;
      fruid.board.custom4_type_len = type_length;
      alter_field_content(&fruid.board.custom4,tmp_content);
      break;
    case BCD5:
      if (fruid.board.custom1_type_len == NO_MORE_DATA_BYTE)
        fruid.board.custom1_type_len = 0;
      if (fruid.board.custom2_type_len == NO_MORE_DATA_BYTE)
        fruid.board.custom2_type_len = 0;
      if (fruid.board.custom3_type_len == NO_MORE_DATA_BYTE)
        fruid.board.custom3_type_len = 0;
      if (fruid.board.custom4_type_len == NO_MORE_DATA_BYTE)
        fruid.board.custom4_type_len = 0;
      fruid.board.custom5_type_len = type_length;
      alter_field_content(&fruid.board.custom5,tmp_content);
      break;
    case BCD6:
      if (fruid.board.custom1_type_len == NO_MORE_DATA_BYTE)
        fruid.board.custom1_type_len = 0;
      if (fruid.board.custom2_type_len == NO_MORE_DATA_BYTE)
        fruid.board.custom2_type_len = 0;
      if (fruid.board.custom3_type_len == NO_MORE_DATA_BYTE)
        fruid.board.custom3_type_len = 0;
      if (fruid.board.custom4_type_len == NO_MORE_DATA_BYTE)
        fruid.board.custom4_type_len = 0;
      if (fruid.board.custom5_type_len == NO_MORE_DATA_BYTE)
        fruid.board.custom5_type_len = 0;
      fruid.board.custom6_type_len = type_length;
      alter_field_content(&fruid.board.custom6,tmp_content);
      break;
    case PM:
      fruid.product.mfg_type_len = type_length;
      alter_field_content(&fruid.product.mfg,tmp_content);
      break;
    case PN:
      fruid.product.name_type_len = type_length;
      alter_field_content(&fruid.product.name,tmp_content);
      break;
    case PPN:
      fruid.product.part_type_len = type_length;
      alter_field_content(&fruid.product.part,tmp_content);
      break;
    case PV:
      fruid.product.version_type_len = type_length;
      alter_field_content(&fruid.product.version,tmp_content);
      break;
    case PSN:
      fruid.product.serial_type_len = type_length;
      alter_field_content(&fruid.product.serial,tmp_content);
      break;
    case PAT:
      fruid.product.asset_tag_type_len = type_length;
      alter_field_content(&fruid.product.asset_tag,tmp_content);
      break;
    case PFI:
      fruid.product.fruid_type_len = type_length;
      alter_field_content(&fruid.product.fruid,tmp_content);
      break;
    case PCD1:
      fruid.product.custom1_type_len = type_length;
      alter_field_content(&fruid.product.custom1,tmp_content);
      break;
    case PCD2:
      if (fruid.product.custom1_type_len == NO_MORE_DATA_BYTE)
        fruid.product.custom1_type_len = 0;
      fruid.product.custom2_type_len = type_length;
      alter_field_content(&fruid.product.custom2,tmp_content);
      break;
    case PCD3:
      if (fruid.product.custom1_type_len == NO_MORE_DATA_BYTE)
        fruid.product.custom1_type_len = 0;
      if (fruid.product.custom2_type_len == NO_MORE_DATA_BYTE)
        fruid.product.custom2_type_len = 0;
      fruid.product.custom3_type_len = type_length;
      alter_field_content(&fruid.product.custom3,tmp_content);
      break;
    case PCD4:
      if (fruid.product.custom1_type_len == NO_MORE_DATA_BYTE)
        fruid.product.custom1_type_len = 0;
      if (fruid.product.custom2_type_len == NO_MORE_DATA_BYTE)
        fruid.product.custom2_type_len = 0;
      if (fruid.product.custom3_type_len == NO_MORE_DATA_BYTE)
        fruid.product.custom3_type_len = 0;
      fruid.product.custom4_type_len = type_length;
      alter_field_content(&fruid.product.custom4,tmp_content);
      break;
    case PCD5:
      if (fruid.product.custom1_type_len == NO_MORE_DATA_BYTE)
        fruid.product.custom1_type_len = 0;
      if (fruid.product.custom2_type_len == NO_MORE_DATA_BYTE)
        fruid.product.custom2_type_len = 0;
      if (fruid.product.custom3_type_len == NO_MORE_DATA_BYTE)
        fruid.product.custom3_type_len = 0;
      if (fruid.product.custom4_type_len == NO_MORE_DATA_BYTE)
        fruid.product.custom4_type_len = 0;
      fruid.product.custom5_type_len = type_length;
      alter_field_content(&fruid.product.custom5,tmp_content);
      break;
    case PCD6:
      if (fruid.product.custom1_type_len == NO_MORE_DATA_BYTE)
        fruid.product.custom1_type_len = 0;
      if (fruid.product.custom2_type_len == NO_MORE_DATA_BYTE)
        fruid.product.custom2_type_len = 0;
      if (fruid.product.custom3_type_len == NO_MORE_DATA_BYTE)
        fruid.product.custom3_type_len = 0;
      if (fruid.product.custom4_type_len == NO_MORE_DATA_BYTE)
        fruid.product.custom4_type_len = 0;
      if (fruid.product.custom5_type_len == NO_MORE_DATA_BYTE)
        fruid.product.custom5_type_len = 0;
      fruid.product.custom6_type_len = type_length;
      alter_field_content(&fruid.product.custom6,tmp_content);
      break;
    default:
      return -1;
      break;
  }

  // create new FRU alloc new eeprom
  // We need the existing length + length of new content, but we can also add
  // new optional fields (for instance if custom1 is added, the others become 0
  // byte fields, but with a type/len byte).  For safety add enough bytes to
  // cover all the optional fields to prevent buffer overruns.  We track the
  // number of bytes added to the array, so only that number will be written to
  // the eeprom.
  new_fruid_len = fruid_len + ((content_len / 8) + 1) * 8 + total_field_opt_size;
  eeprom = (uint8_t *) malloc(new_fruid_len);
  memset(eeprom, 0, new_fruid_len);
  if (!eeprom) {
#ifdef DEBUG
    syslog(LOG_WARNING, "%s: malloc: memory allocation failed", __func__);
#endif
    return ENOMEM;
  }

  // chassis area
  i = 8;
  len = 0;
  int start = i;
  if (fruid.chassis.flag == 1) {
    eeprom[i++] = fruid.chassis.format_ver;
    eeprom[i++] = fruid.chassis.area_len;
    eeprom[i++] = fruid.chassis.type;

    eeprom[i++] = fruid.chassis.part_type_len;
    len = FIELD_LEN(fruid.chassis.part_type_len);
    memcpy(&eeprom[i], fruid.chassis.part, len);
    i += len;

    eeprom[i++] = fruid.chassis.serial_type_len;
    len = FIELD_LEN(fruid.chassis.serial_type_len);
    memcpy(&eeprom[i], fruid.chassis.serial, len);
    i += len;

    eeprom[i++] = fruid.chassis.custom1_type_len;
    if (fruid.chassis.custom1_type_len == NO_MORE_DATA_BYTE)
      goto chasis_chksum;
    len = FIELD_LEN(fruid.chassis.custom1_type_len);
    memcpy(&eeprom[i], fruid.chassis.custom1, len);
    i += len;

    eeprom[i++] = fruid.chassis.custom2_type_len;
    if (fruid.chassis.custom2_type_len == NO_MORE_DATA_BYTE)
      goto chasis_chksum;
    len = FIELD_LEN(fruid.chassis.custom2_type_len);
    memcpy(&eeprom[i], fruid.chassis.custom2, len);
    i += len;

    eeprom[i++] = fruid.chassis.custom3_type_len;
    if (fruid.chassis.custom3_type_len == NO_MORE_DATA_BYTE)
      goto chasis_chksum;
    len = FIELD_LEN(fruid.chassis.custom3_type_len);
    memcpy(&eeprom[i], fruid.chassis.custom3, len);
    i += len;

    eeprom[i++] = fruid.chassis.custom4_type_len;
    if (fruid.chassis.custom4_type_len == NO_MORE_DATA_BYTE)
      goto chasis_chksum;
    len = FIELD_LEN(fruid.chassis.custom4_type_len);
    memcpy(&eeprom[i], fruid.chassis.custom4, len);
    i += len;

    eeprom[i++] = fruid.chassis.custom5_type_len;
    if (fruid.chassis.custom5_type_len == NO_MORE_DATA_BYTE)
      goto chasis_chksum;
    len = FIELD_LEN(fruid.chassis.custom5_type_len);
    memcpy(&eeprom[i], fruid.chassis.custom5, len);
    i += len;

    eeprom[i++] = fruid.chassis.custom6_type_len;
    if (fruid.chassis.custom6_type_len == NO_MORE_DATA_BYTE)
      goto chasis_chksum;
    len = FIELD_LEN(fruid.chassis.custom6_type_len);
    memcpy(&eeprom[i], fruid.chassis.custom6, len);
    i += len;

  chasis_chksum:
    if (eeprom[i - 1] != NO_MORE_DATA_BYTE) {
      eeprom[i++] = NO_MORE_DATA_BYTE;
    }
    i += (7 - (i % 8));
    fruid.chassis.area_len = i - start + 1;
    eeprom[start + 1] = fruid.chassis.area_len / FRUID_AREA_LEN_MULTIPLIER;
    ret = calculate_chksum(&eeprom[start], fruid.chassis.area_len);
    if (ret < 0) {
      printf("Update chassis checksum fail!\n");
      goto error_exit;
    }
    i++;
  } else {
    fruid.chassis.area_len = 0;
  }

  // board area
  start = i;
  if (fruid.board.flag == 1) {
    eeprom[i++] = fruid.board.format_ver;
    eeprom[i++] = fruid.board.area_len;
    eeprom[i++] = fruid.board.lang_code;

    memcpy(&eeprom[i], fruid.board.mfg_time, 3);
    i += 3;

    eeprom[i++] = fruid.board.mfg_type_len;
    len = FIELD_LEN(fruid.board.mfg_type_len);
    memcpy(&eeprom[i], fruid.board.mfg, len);
    i += len;

    eeprom[i++] = fruid.board.name_type_len;
    len = FIELD_LEN(fruid.board.name_type_len);
    memcpy(&eeprom[i], fruid.board.name, len);
    i += len;

    eeprom[i++] = fruid.board.serial_type_len;
    len = FIELD_LEN(fruid.board.serial_type_len);
    memcpy(&eeprom[i], fruid.board.serial, len);
    i += len;

    eeprom[i++] = fruid.board.part_type_len;
    len = FIELD_LEN(fruid.board.part_type_len);
    memcpy(&eeprom[i], fruid.board.part, len);
    i += len;

    eeprom[i++] = fruid.board.fruid_type_len;
    len = FIELD_LEN(fruid.board.fruid_type_len);
    memcpy(&eeprom[i], fruid.board.fruid, len);
    i += len;

    eeprom[i++] = fruid.board.custom1_type_len;
    if (fruid.board.custom1_type_len == NO_MORE_DATA_BYTE)
      goto board_chksum;
    len = FIELD_LEN(fruid.board.custom1_type_len);
    memcpy(&eeprom[i], fruid.board.custom1, len);
    i += len;

    eeprom[i++] = fruid.board.custom2_type_len;
    if (fruid.board.custom2_type_len == NO_MORE_DATA_BYTE)
      goto board_chksum;
    len = FIELD_LEN(fruid.board.custom2_type_len);
    memcpy(&eeprom[i], fruid.board.custom2, len);
    i += len;

    eeprom[i++] = fruid.board.custom3_type_len;
    if (fruid.board.custom3_type_len == NO_MORE_DATA_BYTE)
      goto board_chksum;
    len = FIELD_LEN(fruid.board.custom3_type_len);
    memcpy(&eeprom[i], fruid.board.custom3, len);
    i += len;

    eeprom[i++] = fruid.board.custom4_type_len;
    if (fruid.board.custom4_type_len == NO_MORE_DATA_BYTE)
      goto board_chksum;
    len = FIELD_LEN(fruid.board.custom4_type_len);
    memcpy(&eeprom[i], fruid.board.custom4, len);
    i += len;

    eeprom[i++] = fruid.board.custom5_type_len;
    if (fruid.board.custom5_type_len == NO_MORE_DATA_BYTE)
      goto board_chksum;
    len = FIELD_LEN(fruid.board.custom5_type_len);
    memcpy(&eeprom[i], fruid.board.custom5, len);
    i += len;

    eeprom[i++] = fruid.board.custom6_type_len;
    if (fruid.board.custom6_type_len == NO_MORE_DATA_BYTE)
      goto board_chksum;
    len = FIELD_LEN(fruid.board.custom6_type_len);
    memcpy(&eeprom[i], fruid.board.custom6, len);
    i += len;

  board_chksum:
    if (eeprom[i - 1] != NO_MORE_DATA_BYTE) {
      eeprom[i++] = NO_MORE_DATA_BYTE;
    }
    i += (7 - (i % 8));
    fruid.board.area_len = i - start + 1;
    eeprom[start + 1] = fruid.board.area_len / FRUID_AREA_LEN_MULTIPLIER;
    ret = calculate_chksum(&eeprom[start], fruid.board.area_len);
    if (ret < 0) {
      printf("Update board checksum fail!\n");
      goto error_exit;
    }
    i++;
  } else {
    fruid.board.area_len = 0;
  }

  // product area
  start = i;
  if (fruid.product.flag == 1) {
    eeprom[i++] = fruid.product.format_ver;
    eeprom[i++] = fruid.product.area_len;
    eeprom[i++] = fruid.product.lang_code;

    eeprom[i++] = fruid.product.mfg_type_len;
    len = FIELD_LEN(fruid.product.mfg_type_len);
    memcpy(&eeprom[i], fruid.product.mfg, len);
    i += len;

    eeprom[i++] = fruid.product.name_type_len;
    len = FIELD_LEN(fruid.product.name_type_len);
    memcpy(&eeprom[i], fruid.product.name, len);
    i += len;

    eeprom[i++] = fruid.product.part_type_len;
    len = FIELD_LEN(fruid.product.part_type_len);
    memcpy(&eeprom[i], fruid.product.part, len);
    i += len;

    eeprom[i++] = fruid.product.version_type_len;
    len = FIELD_LEN(fruid.product.version_type_len);
    memcpy(&eeprom[i], fruid.product.version, len);
    i += len;

    eeprom[i++] = fruid.product.serial_type_len;
    len = FIELD_LEN(fruid.product.serial_type_len);
    memcpy(&eeprom[i], fruid.product.serial, len);
    i += len;

    eeprom[i++] = fruid.product.asset_tag_type_len;
    len = FIELD_LEN(fruid.product.asset_tag_type_len);
    memcpy(&eeprom[i], fruid.product.asset_tag, len);
    i += len;

    eeprom[i++] = fruid.product.fruid_type_len;
    len = FIELD_LEN(fruid.product.fruid_type_len);
    memcpy(&eeprom[i], fruid.product.fruid, len);
    i += len;

    eeprom[i++] = fruid.product.custom1_type_len;
    if (fruid.product.custom1_type_len == NO_MORE_DATA_BYTE)
      goto product_chksum;
    len = FIELD_LEN(fruid.product.custom1_type_len);
    memcpy(&eeprom[i], fruid.product.custom1, len);
    i += len;

    eeprom[i++] = fruid.product.custom2_type_len;
    if (fruid.product.custom2_type_len == NO_MORE_DATA_BYTE)
      goto product_chksum;
    len = FIELD_LEN(fruid.product.custom2_type_len);
    memcpy(&eeprom[i], fruid.product.custom2, len);
    i += len;

    eeprom[i++] = fruid.product.custom3_type_len;
    if (fruid.product.custom3_type_len == NO_MORE_DATA_BYTE)
      goto product_chksum;
    len = FIELD_LEN(fruid.product.custom3_type_len);
    memcpy(&eeprom[i], fruid.product.custom3, len);
    i += len;

    eeprom[i++] = fruid.product.custom4_type_len;
    if (fruid.product.custom4_type_len == NO_MORE_DATA_BYTE)
      goto product_chksum;
    len = FIELD_LEN(fruid.product.custom4_type_len);
    memcpy(&eeprom[i], fruid.product.custom4, len);
    i += len;

    eeprom[i++] = fruid.product.custom5_type_len;
    if (fruid.product.custom5_type_len == NO_MORE_DATA_BYTE)
      goto product_chksum;
    len = FIELD_LEN(fruid.product.custom5_type_len);
    memcpy(&eeprom[i], fruid.product.custom5, len);
    i += len;

    eeprom[i++] = fruid.product.custom6_type_len;
    if (fruid.product.custom6_type_len == NO_MORE_DATA_BYTE)
      goto product_chksum;
    len = FIELD_LEN(fruid.product.custom6_type_len);
    memcpy(&eeprom[i], fruid.product.custom6, len);
    i += len;

  product_chksum:
    if (eeprom[i - 1] != NO_MORE_DATA_BYTE) {
      eeprom[i++] = NO_MORE_DATA_BYTE;
    }
    i += (7 - (i % 8));
    fruid.product.area_len = i - start + 1;
    eeprom[start + 1] = fruid.product.area_len / FRUID_AREA_LEN_MULTIPLIER;
    ret = calculate_chksum(&eeprom[start], fruid.product.area_len);
    if (ret < 0) {
      printf("Update product checksum fail!\n");
      goto error_exit;
    }
    i++;
  } else {
    fruid.product.area_len = 0;
  }

  // update header
  int offset = 1;
  eeprom[0] = 0x01; // format version
  if (fruid.chassis.flag == 1) {
    eeprom[2] = offset; // chassis area offset
  }
  if (fruid.board.flag == 1) {
    offset += fruid.chassis.area_len / FRUID_AREA_LEN_MULTIPLIER; // board area offset
    eeprom[3] = offset;
  }
  if (fruid.product.flag == 1) {
    offset += fruid.board.area_len / FRUID_AREA_LEN_MULTIPLIER; // product area offset
    eeprom[4] = offset;
  }

  //  update header checksum
  ret = calculate_chksum(&eeprom[0], 8);
  if (ret < 0) {
    printf("Update header checksum fail!\n");
    goto error_exit;
  }

  /* Open the FRUID binary file */
  fruid_fd = fopen(new_bin, "wb");
  if (!fruid_fd) {
#ifdef DEBUG
    syslog(LOG_ERR, "%s: unable to open the file %s", __func__, new_bin);
#endif
    return ENOENT;
  }

  /* Write the binary file */
  fwrite(eeprom, sizeof(uint8_t), i, fruid_fd);

  /* Close the FRUID binary file */
  fclose(fruid_fd);

error_exit:
  /* Free the eeprom malloced memory */
  free(eeprom);
  /* Free the malloced memory for the fruid information */
  free_fruid_info(&fruid);
  return ret;
}