blob: 3aaddd0a1d615089e0070ff5cb68308c40db4680 [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
280static void cgi_fota_update_progress()
281{
282 int upgradeStatus, result;
283
284 system("fota_upi -u verify > /dev/null 2>&1");
285 result = fota_get_update_status(&upgradeStatus);
286 if(result < 0)
287 {
288 printf("<h1 style='color: red;'>Error: Fail to read update file!</h1>");
289 }
290 else if(upgradeStatus != 0)
291 {
292 printf("<h1 style='color: red;'>Error: Verify update file failed!</h1>");
293 }
294 else
295 {
296 printf("<h1 style='color: green;'>File verification successful, start updating...</h1>");
297 system("fota_upi -u recovery &");
298 }
299}
300
301static void html_print_start()
302{
303 printf("Content-type: text/html\r\n\r\n");
304 printf("<!DOCTYPE html>\n");
305 printf("<html lang=\"en\">\n");
306 printf("<head>\n");
307 printf("<meta charset=\"UTF-8\">\n");
308 printf("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n");
309 printf("<title>File Upload Status</title>\n");
310 printf("<style>\n");
311 printf("body { font-family: Arial, sans-serif; background-color: #f4f4f4; margin: 0; padding: 0; padding-top: 20px; }\n");
312 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");
313 printf("h1 { margin: 10px 0; }\n");
314 printf("</style>\n");
315 printf("</head>\n");
316 printf("<body>\n");
317 printf("<div class=\"container\">\n");
318}
319
320static void html_print_end()
321{
322 printf("</div>\n");
323 printf("</body>\n");
324 printf("</html>\n");
325}
326
327int main()
328{
329 const char *source_filename = "/firmware_tmp_file"; // Source file path
330 const char *target_filename = "/cache/zte_fota/delta.package"; // Target file path
331 const char *content_length_str = NULL;
332 int content_length = 0;
333
334 system("rm -rf /cache/zte_fota");
335 system("mkdir -p /cache/zte_fota");
336
337 // Get environment variables
338 content_length_str = getenv("CONTENT_LENGTH");
339 if (!content_length_str)
340 {
341 printf("Content-type: text/html\r\n\r\n");
342 printf("<h1>Error: Missing CONTENT_LENGTH environment variable</h1>");
343 return 1;
344 }
345
346 content_length = atoi(content_length_str);
347 if (content_length <= 0)
348 {
349 printf("Content-type: text/html\r\n\r\n");
350 printf("<h1>Error: Invalid CONTENT_LENGTH</h1>");
351 return 1;
352 }
353
354 // Call the file upload handling function
355 if (handle_file_upload(source_filename, target_filename, content_length) != 0)
356 {
357 printf("Content-type: text/html\r\n\r\n");
358 printf("<h1>Error: File upload failed</h1>");
359 return 1;
360 }
361
362 // Output success information
363 html_print_start();
364 printf("<h1 style='color: green;'>File upload successful!</h1>");
365 //printf("<p>The file has been saved to %s</p>", target_filename);
366
367 cgi_fota_update_progress();
368
369 html_print_end();
370
371 return 0;
372}