blob: b02636777863119f1c94f7ae807de8ad51b8cd5f [file] [log] [blame]
mj.qu49441c22025-02-10 18:11:48 -08001#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <unistd.h>
5#include <fcntl.h>
6#include <errno.h>
7
8#define BUFFER_SIZE (1024 * 20) // Define the buffer size for each read
9#define FIND_STR_LEN 128 // Define the length of the string to find
10#define FOTA_UPDATE_STATUS_FILE "/cache/zte_fota/update_status"
11
12// Custom memmem function
13static void* custom_memmem(const void* haystack, size_t haystack_len, const void* needle, size_t needle_len)
14{
15 if (needle_len == 0 || haystack_len < needle_len)
16 {
17 return NULL;
18 }
19
20 size_t i = 0;
21 const unsigned char* h = (const unsigned char*)haystack;
22 const unsigned char* n = (const unsigned char*)needle;
23
24 for (i = 0; i <= haystack_len - needle_len; ++i)
25 {
26 if (memcmp(h + i, n, needle_len) == 0)
27 {
28 return (void*)(h + i);
29 }
30 }
31
32 return NULL;
33}
34
35// Remove the last boundary marker from the file
36static int remove_last_boundary(const char *filename, const char *boundary_marker, int boundary_marker_len)
37{
38 int fd = open(filename, O_RDWR);
39 if (fd == -1)
40 {
41 perror("Unable to open file for reading and writing");
42 return 1;
43 }
44
45 // Get the file size
46 off_t file_size = lseek(fd, 0, SEEK_END);
47 if (file_size == -1)
48 {
49 perror("Unable to get file size");
50 close(fd);
51 return 1;
52 }
53
54 // Search for the boundary_marker from the end of the file
55 off_t search_start = file_size - FIND_STR_LEN;
56 if (search_start < 0)
57 {
58 search_start = 0;
59 }
60
61 lseek(fd, search_start, SEEK_SET);
62
63 char buffer[FIND_STR_LEN + 1]; // +1 for storing '\0'
64 int bytes_read = read(fd, buffer, FIND_STR_LEN);
65 if (bytes_read <= 0)
66 {
67 perror("Unable to read file");
68 close(fd);
69 return 1;
70 }
71 buffer[bytes_read] = '\0'; // Ensure the string is null-terminated
72
73 // Find the boundary_marker
74 char *boundary = custom_memmem(buffer, bytes_read, boundary_marker, boundary_marker_len);
75 if (boundary)
76 {
77 // Found boundary_marker, calculate the truncate position
78 off_t truncate_pos = search_start + (boundary - buffer);
79 if (ftruncate(fd, truncate_pos) == -1)
80 {
81 perror("Unable to truncate file");
82 close(fd);
83 return 1;
84 }
85 }
86
87 close(fd);
88 return 0;
89}
90
91// Function to handle file upload
92static int handle_file_upload(const char *source_filename, const char *target_filename, int content_length)
93{
94 char buffer[BUFFER_SIZE];
95 int bytes_read;
96 int target_fd = -1;
97 int source_fd = -1; // Source file descriptor
98 char *content_start_ptr = NULL;
99 int content_start = 0;
100 const char *boundary_marker = "\r\n------WebKitFormBoundary"; // Boundary marker
101 int boundary_marker_len = strlen(boundary_marker);
102
103 // Open the target file
104 target_fd = open(target_filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
105 if (target_fd == -1)
106 {
107 perror("Unable to open target file");
108 return 1;
109 }
110
111 // Open the source file
112 source_fd = open(source_filename, O_RDONLY);
113 if (source_fd == -1)
114 {
115 perror("Unable to open source file");
116 close(target_fd);
117 return 1;
118 }
119
120 // Read the request header to find the start position of file content
121 bytes_read = read(source_fd, buffer, BUFFER_SIZE);
122 if (bytes_read <= 0)
123 {
124 printf("Content-type: text/html\r\n\r\n");
125 printf("<h1>Error: Failed to read data</h1>");
126 printf("<p>Error number: %d - %s</p>", errno, strerror(errno));
127 close(target_fd);
128 close(source_fd);
129 return 1;
130 }
131
132 // Find the start position of the file content (usually after \r\n\r\n)
133 content_start_ptr = strstr(buffer, "\r\n\r\n");
134 if (!content_start_ptr)
135 {
136 printf("Content-type: text/html\r\n\r\n");
137 printf("<h1>Error: Unable to find the start position of file content</h1>");
138 close(target_fd);
139 close(source_fd);
140 return 1;
141 }
142
143 // Calculate the actual start position of the file content
144 content_start = content_start_ptr - buffer + 4;
145
146 // Write the first part of the file content
147 if (content_start < bytes_read)
148 {
149 if (write(target_fd, buffer + content_start, bytes_read - content_start) == -1)
150 {
151 perror("Unable to write to target file");
152 close(target_fd);
153 close(source_fd);
154 return 1;
155 }
156 }
157
158 // Update the remaining content length
159 content_length -= (bytes_read - content_start);
160
161 // Continue reading and writing the file in segments
162 while (content_length > 0)
163 {
164 bytes_read = read(source_fd, buffer, BUFFER_SIZE);
165 if (bytes_read <= 0)
166 {
167 // If reading is complete, normally break out of the loop
168 break;
169 }
170
171 // Write the file content
172 if (write(target_fd, buffer, bytes_read) == -1)
173 {
174 perror("Unable to write to target file");
175 close(target_fd);
176 close(source_fd);
177 return 1;
178 }
179
180 // Update the remaining content length
181 content_length -= bytes_read;
182 }
183
184 // Close file descriptors
185 close(target_fd);
186 close(source_fd);
187
188 // Remove the last boundary marker from the file
189 return remove_last_boundary(target_filename, boundary_marker, boundary_marker_len);
190}
191
192static int fota_is_file_exist(const char* path)
193{
194 if ( (path == NULL) || (*path == '\0') )
195 return 0;
196 if (access(path, R_OK) != 0)
197 return 0;
198
199 return 1;
200}
201
202static int fota_read_file(const char*path, char*buf, size_t sz)
203{
204 int fd = -1;
205 size_t cnt;
206
207 fd = open(path, O_RDONLY, 0);
208 if(fd < 0)
209 {
210 printf("fota_read_file failed to open %s: %s\n", path, strerror(errno));
211 cnt = -1;
212 return cnt;
213 }
214 cnt = read(fd, buf, sz - 1);
215 if(cnt <= 0)
216 {
217 printf("failed to read %s: %s\n", path, strerror(errno));
218 close(fd);
219 cnt = -1;
220 return cnt;
221 }
222 buf[cnt] = '\0';
223 if(buf[cnt - 1] == '\n')
224 {
225 cnt--;
226 buf[cnt] = '\0';
227 }
228 close(fd);
229
230 return cnt;
231}
232
233static int fota_read_file_int(const char* path, int *val)
234{
235 char buf[32];
236 char *end;
237 int ret;
238 int tmp;
239
240 ret = fota_read_file(path, buf, sizeof(buf));
241 if(ret < 0)
242 return -1;
243
244 errno = 0;
245 tmp = strtol(buf, &end, 0);
246 if (errno == ERANGE)
247 {
248 printf("strtol errno %d: %s\n", errno, strerror(errno));
249 }
250
251 if ((end == buf) || ((end < buf + sizeof(buf)) && (*end != '\0')))
252 {
253 return -1;
254 }
255
256 *val = tmp;
257
258 return 0;
259}
260
261static int fota_get_update_status(int *fota_status)
262{
263 int status = 0;
264 int ret = 0;
265 if(!fota_is_file_exist(FOTA_UPDATE_STATUS_FILE))
266 {
267 *fota_status = -1;
268 return -1;
269 }
270 ret = fota_read_file_int(FOTA_UPDATE_STATUS_FILE, &status);
271 if(ret < 0)
272 {
273 *fota_status = -1;
274 return -1;
275 }
276 *fota_status = status;
277 return 0;
278}
279
mj.qu290d6552025-02-11 22:34:46 -0800280static void print_json_response(int success, const char* message)
281{
282 printf("Content-type: application/json\r\n\r\n");
283 printf("{\"success\": %d, \"message\": \"%s\"}\n", success, message);
284}
285
mj.qu49441c22025-02-10 18:11:48 -0800286static void cgi_fota_update_progress()
287{
288 int upgradeStatus, result;
289
290 system("fota_upi -u verify > /dev/null 2>&1");
mj.qu290d6552025-02-11 22:34:46 -0800291 result = fota_get_update_status(&upgradeStatus);
292 if(result < 0)
293 {
294 print_json_response(0, "Fail to read update file");
295 }
296 else if(upgradeStatus != 0)
297 {
298 print_json_response(0, "Verify update file failed");
299 }
300 else
301 {
302 print_json_response(1, "File verification successful, start updating...");
303 sleep(1);
304 system("fota_upi -u recovery > /dev/null 2>&1 &");
305 }
mj.qu49441c22025-02-10 18:11:48 -0800306}
307
308int main()
309{
mj.quc4b3b122025-02-12 23:53:45 -0800310 const char *source_filename = "/tmp/firmware_tmp_file"; // Source file path
mj.qu49441c22025-02-10 18:11:48 -0800311 const char *target_filename = "/cache/zte_fota/delta.package"; // Target file path
312 const char *content_length_str = NULL;
313 int content_length = 0;
314
315 system("rm -rf /cache/zte_fota");
316 system("mkdir -p /cache/zte_fota");
317
318 // Get environment variables
319 content_length_str = getenv("CONTENT_LENGTH");
320 if (!content_length_str)
321 {
mj.quc4b3b122025-02-12 23:53:45 -0800322 system("rm -rf /tmp/firmware_tmp_file");
mj.qu290d6552025-02-11 22:34:46 -0800323 print_json_response(0, "Missing CONTENT_LENGTH environment variable");
mj.qu49441c22025-02-10 18:11:48 -0800324 return 1;
325 }
326
327 content_length = atoi(content_length_str);
328 if (content_length <= 0)
329 {
mj.quc4b3b122025-02-12 23:53:45 -0800330 system("rm -rf /tmp/firmware_tmp_file");
mj.qu290d6552025-02-11 22:34:46 -0800331 print_json_response(0, "Invalid CONTENT_LENGTH");
mj.qu49441c22025-02-10 18:11:48 -0800332 return 1;
333 }
334
335 // Call the file upload handling function
336 if (handle_file_upload(source_filename, target_filename, content_length) != 0)
337 {
mj.quc4b3b122025-02-12 23:53:45 -0800338 system("rm -rf /tmp/firmware_tmp_file");
mj.qu290d6552025-02-11 22:34:46 -0800339 print_json_response(0, "File upload failed");
mj.qu49441c22025-02-10 18:11:48 -0800340 return 1;
341 }
342
343 // Output success information
mj.qu290d6552025-02-11 22:34:46 -0800344 //print_json_response(1, "File upload successful");
mj.quc4b3b122025-02-12 23:53:45 -0800345 system("rm -rf /tmp/firmware_tmp_file");
mj.qu49441c22025-02-10 18:11:48 -0800346
347 cgi_fota_update_progress();
348
mj.qu49441c22025-02-10 18:11:48 -0800349 return 0;
350}