blob: b02636777863119f1c94f7ae807de8ad51b8cd5f [file] [log] [blame]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#define BUFFER_SIZE (1024 * 20) // Define the buffer size for each read
#define FIND_STR_LEN 128 // Define the length of the string to find
#define FOTA_UPDATE_STATUS_FILE "/cache/zte_fota/update_status"
// Custom memmem function
static void* custom_memmem(const void* haystack, size_t haystack_len, const void* needle, size_t needle_len)
{
if (needle_len == 0 || haystack_len < needle_len)
{
return NULL;
}
size_t i = 0;
const unsigned char* h = (const unsigned char*)haystack;
const unsigned char* n = (const unsigned char*)needle;
for (i = 0; i <= haystack_len - needle_len; ++i)
{
if (memcmp(h + i, n, needle_len) == 0)
{
return (void*)(h + i);
}
}
return NULL;
}
// Remove the last boundary marker from the file
static int remove_last_boundary(const char *filename, const char *boundary_marker, int boundary_marker_len)
{
int fd = open(filename, O_RDWR);
if (fd == -1)
{
perror("Unable to open file for reading and writing");
return 1;
}
// Get the file size
off_t file_size = lseek(fd, 0, SEEK_END);
if (file_size == -1)
{
perror("Unable to get file size");
close(fd);
return 1;
}
// Search for the boundary_marker from the end of the file
off_t search_start = file_size - FIND_STR_LEN;
if (search_start < 0)
{
search_start = 0;
}
lseek(fd, search_start, SEEK_SET);
char buffer[FIND_STR_LEN + 1]; // +1 for storing '\0'
int bytes_read = read(fd, buffer, FIND_STR_LEN);
if (bytes_read <= 0)
{
perror("Unable to read file");
close(fd);
return 1;
}
buffer[bytes_read] = '\0'; // Ensure the string is null-terminated
// Find the boundary_marker
char *boundary = custom_memmem(buffer, bytes_read, boundary_marker, boundary_marker_len);
if (boundary)
{
// Found boundary_marker, calculate the truncate position
off_t truncate_pos = search_start + (boundary - buffer);
if (ftruncate(fd, truncate_pos) == -1)
{
perror("Unable to truncate file");
close(fd);
return 1;
}
}
close(fd);
return 0;
}
// Function to handle file upload
static int handle_file_upload(const char *source_filename, const char *target_filename, int content_length)
{
char buffer[BUFFER_SIZE];
int bytes_read;
int target_fd = -1;
int source_fd = -1; // Source file descriptor
char *content_start_ptr = NULL;
int content_start = 0;
const char *boundary_marker = "\r\n------WebKitFormBoundary"; // Boundary marker
int boundary_marker_len = strlen(boundary_marker);
// Open the target file
target_fd = open(target_filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (target_fd == -1)
{
perror("Unable to open target file");
return 1;
}
// Open the source file
source_fd = open(source_filename, O_RDONLY);
if (source_fd == -1)
{
perror("Unable to open source file");
close(target_fd);
return 1;
}
// Read the request header to find the start position of file content
bytes_read = read(source_fd, buffer, BUFFER_SIZE);
if (bytes_read <= 0)
{
printf("Content-type: text/html\r\n\r\n");
printf("<h1>Error: Failed to read data</h1>");
printf("<p>Error number: %d - %s</p>", errno, strerror(errno));
close(target_fd);
close(source_fd);
return 1;
}
// Find the start position of the file content (usually after \r\n\r\n)
content_start_ptr = strstr(buffer, "\r\n\r\n");
if (!content_start_ptr)
{
printf("Content-type: text/html\r\n\r\n");
printf("<h1>Error: Unable to find the start position of file content</h1>");
close(target_fd);
close(source_fd);
return 1;
}
// Calculate the actual start position of the file content
content_start = content_start_ptr - buffer + 4;
// Write the first part of the file content
if (content_start < bytes_read)
{
if (write(target_fd, buffer + content_start, bytes_read - content_start) == -1)
{
perror("Unable to write to target file");
close(target_fd);
close(source_fd);
return 1;
}
}
// Update the remaining content length
content_length -= (bytes_read - content_start);
// Continue reading and writing the file in segments
while (content_length > 0)
{
bytes_read = read(source_fd, buffer, BUFFER_SIZE);
if (bytes_read <= 0)
{
// If reading is complete, normally break out of the loop
break;
}
// Write the file content
if (write(target_fd, buffer, bytes_read) == -1)
{
perror("Unable to write to target file");
close(target_fd);
close(source_fd);
return 1;
}
// Update the remaining content length
content_length -= bytes_read;
}
// Close file descriptors
close(target_fd);
close(source_fd);
// Remove the last boundary marker from the file
return remove_last_boundary(target_filename, boundary_marker, boundary_marker_len);
}
static int fota_is_file_exist(const char* path)
{
if ( (path == NULL) || (*path == '\0') )
return 0;
if (access(path, R_OK) != 0)
return 0;
return 1;
}
static int fota_read_file(const char*path, char*buf, size_t sz)
{
int fd = -1;
size_t cnt;
fd = open(path, O_RDONLY, 0);
if(fd < 0)
{
printf("fota_read_file failed to open %s: %s\n", path, strerror(errno));
cnt = -1;
return cnt;
}
cnt = read(fd, buf, sz - 1);
if(cnt <= 0)
{
printf("failed to read %s: %s\n", path, strerror(errno));
close(fd);
cnt = -1;
return cnt;
}
buf[cnt] = '\0';
if(buf[cnt - 1] == '\n')
{
cnt--;
buf[cnt] = '\0';
}
close(fd);
return cnt;
}
static int fota_read_file_int(const char* path, int *val)
{
char buf[32];
char *end;
int ret;
int tmp;
ret = fota_read_file(path, buf, sizeof(buf));
if(ret < 0)
return -1;
errno = 0;
tmp = strtol(buf, &end, 0);
if (errno == ERANGE)
{
printf("strtol errno %d: %s\n", errno, strerror(errno));
}
if ((end == buf) || ((end < buf + sizeof(buf)) && (*end != '\0')))
{
return -1;
}
*val = tmp;
return 0;
}
static int fota_get_update_status(int *fota_status)
{
int status = 0;
int ret = 0;
if(!fota_is_file_exist(FOTA_UPDATE_STATUS_FILE))
{
*fota_status = -1;
return -1;
}
ret = fota_read_file_int(FOTA_UPDATE_STATUS_FILE, &status);
if(ret < 0)
{
*fota_status = -1;
return -1;
}
*fota_status = status;
return 0;
}
static void print_json_response(int success, const char* message)
{
printf("Content-type: application/json\r\n\r\n");
printf("{\"success\": %d, \"message\": \"%s\"}\n", success, message);
}
static void cgi_fota_update_progress()
{
int upgradeStatus, result;
system("fota_upi -u verify > /dev/null 2>&1");
result = fota_get_update_status(&upgradeStatus);
if(result < 0)
{
print_json_response(0, "Fail to read update file");
}
else if(upgradeStatus != 0)
{
print_json_response(0, "Verify update file failed");
}
else
{
print_json_response(1, "File verification successful, start updating...");
sleep(1);
system("fota_upi -u recovery > /dev/null 2>&1 &");
}
}
int main()
{
const char *source_filename = "/tmp/firmware_tmp_file"; // Source file path
const char *target_filename = "/cache/zte_fota/delta.package"; // Target file path
const char *content_length_str = NULL;
int content_length = 0;
system("rm -rf /cache/zte_fota");
system("mkdir -p /cache/zte_fota");
// Get environment variables
content_length_str = getenv("CONTENT_LENGTH");
if (!content_length_str)
{
system("rm -rf /tmp/firmware_tmp_file");
print_json_response(0, "Missing CONTENT_LENGTH environment variable");
return 1;
}
content_length = atoi(content_length_str);
if (content_length <= 0)
{
system("rm -rf /tmp/firmware_tmp_file");
print_json_response(0, "Invalid CONTENT_LENGTH");
return 1;
}
// Call the file upload handling function
if (handle_file_upload(source_filename, target_filename, content_length) != 0)
{
system("rm -rf /tmp/firmware_tmp_file");
print_json_response(0, "File upload failed");
return 1;
}
// Output success information
//print_json_response(1, "File upload successful");
system("rm -rf /tmp/firmware_tmp_file");
cgi_fota_update_progress();
return 0;
}