[Feature][S300][task-view-993][webui] add web upload upgrade package upgrade function
Change-Id: Ieba32458a073443c11f112036c5834ca089624cf
diff --git a/lynq/CPE_COMMON/ap/app/cgi/cgi.c b/lynq/CPE_COMMON/ap/app/cgi/cgi.c
new file mode 100755
index 0000000..3aaddd0
--- /dev/null
+++ b/lynq/CPE_COMMON/ap/app/cgi/cgi.c
@@ -0,0 +1,372 @@
+#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 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)
+ {
+ printf("<h1 style='color: red;'>Error: Fail to read update file!</h1>");
+ }
+ else if(upgradeStatus != 0)
+ {
+ printf("<h1 style='color: red;'>Error: Verify update file failed!</h1>");
+ }
+ else
+ {
+ printf("<h1 style='color: green;'>File verification successful, start updating...</h1>");
+ system("fota_upi -u recovery &");
+ }
+}
+
+static void html_print_start()
+{
+ printf("Content-type: text/html\r\n\r\n");
+ printf("<!DOCTYPE html>\n");
+ printf("<html lang=\"en\">\n");
+ printf("<head>\n");
+ printf("<meta charset=\"UTF-8\">\n");
+ printf("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n");
+ printf("<title>File Upload Status</title>\n");
+ printf("<style>\n");
+ printf("body { font-family: Arial, sans-serif; background-color: #f4f4f4; margin: 0; padding: 0; padding-top: 20px; }\n");
+ printf(".container { background-color: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); text-align: center; width: 80%%; max-width: 500px; margin: 0 auto; }\n");
+ printf("h1 { margin: 10px 0; }\n");
+ printf("</style>\n");
+ printf("</head>\n");
+ printf("<body>\n");
+ printf("<div class=\"container\">\n");
+}
+
+static void html_print_end()
+{
+ printf("</div>\n");
+ printf("</body>\n");
+ printf("</html>\n");
+}
+
+int main()
+{
+ const char *source_filename = "/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)
+ {
+ printf("Content-type: text/html\r\n\r\n");
+ printf("<h1>Error: Missing CONTENT_LENGTH environment variable</h1>");
+ return 1;
+ }
+
+ content_length = atoi(content_length_str);
+ if (content_length <= 0)
+ {
+ printf("Content-type: text/html\r\n\r\n");
+ printf("<h1>Error: Invalid CONTENT_LENGTH</h1>");
+ return 1;
+ }
+
+ // Call the file upload handling function
+ if (handle_file_upload(source_filename, target_filename, content_length) != 0)
+ {
+ printf("Content-type: text/html\r\n\r\n");
+ printf("<h1>Error: File upload failed</h1>");
+ return 1;
+ }
+
+ // Output success information
+ html_print_start();
+ printf("<h1 style='color: green;'>File upload successful!</h1>");
+ //printf("<p>The file has been saved to %s</p>", target_filename);
+
+ cgi_fota_update_progress();
+
+ html_print_end();
+
+ return 0;
+}