source: src/router/httpd/modules/upgrade_x86.c @ 15460

Last change on this file since 15460 was 15460, checked in by BrainSlayer, 3 years ago

buffered write

File size: 7.8 KB
Line 
1
2/*
3 * Broadcom Home Gateway Reference Design
4 * Web Page Configuration Support Routines
5 *
6 * Copyright 2001-2003, Broadcom Corporation
7 * All Rights Reserved.
8 *
9 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
10 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
11 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
12 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
13 * $Id: upgrade.c,v 1.4 2005/11/30 11:53:42 seg Exp $
14 */
15
16#include <stdio.h>
17#include <string.h>
18#include <fcntl.h>
19#include <errno.h>
20#include <signal.h>
21#include <sys/stat.h>
22#include <stdlib.h>
23#include <unistd.h>
24#include <sys/wait.h>
25
26#include <broadcom.h>
27#include <cyutils.h>
28
29#define MIN_BUF_SIZE    4096
30#define CODE_PATTERN_ERROR 9999
31static int upgrade_ret;
32
33static int getdiscindex(void)   // works only for squashfs
34{
35        int i;
36
37        for (i = 0; i < 10; i++) {
38                char dev[64];
39
40                sprintf(dev, "/dev/discs/disc%d/part2", i);
41                FILE *in = fopen(dev, "rb");
42
43                if (in == NULL)
44                        continue;       // no second partition or disc does not
45                // exist, skipping
46                char buf[4];
47
48                fread(buf, 4, 1, in);
49                if (buf[0] == 'h' && buf[1] == 's' && buf[2] == 'q'
50                    && buf[3] == 't') {
51                        fclose(in);
52                        // filesystem detected
53                        return i;
54                }
55                fclose(in);
56        }
57        return -1;
58}
59
60void
61// do_upgrade_cgi(char *url, FILE *stream)
62do_upgrade_cgi(struct mime_handler *handler, char *url, webs_t stream, char *query)     // jimmy, https,
63                                                        // 8/6/2003
64{
65#ifndef ANTI_FLASH
66        fprintf(stderr, "do post\n");
67        if (upgrade_ret)
68                do_ej(handler, "Fail_u_s.asp", stream, NULL);
69        else
70                do_ej(handler, "Success_u_s.asp", stream, NULL);
71        fprintf(stderr, "websdone\n");
72
73        websDone(stream, 200);
74        fprintf(stderr, "reboot\n");
75
76        /*
77         * Reboot if successful
78         */
79        if (upgrade_ret == 0) {
80                sleep(4);
81                eval("umount", "/usr/local");
82                sys_reboot();
83        }
84#else
85        do_ej(handler, "Fail_u_s.asp", stream, NULL);
86        websDone(stream, 200);
87#endif
88}
89
90int
91// sys_upgrade(char *url, FILE *stream, int *total)
92sys_upgrade(char *url, webs_t stream, int *total, int type)     // jimmy,
93                                                                // https,
94                                                                // 8/6/2003
95{
96        lcdmessage("System Upgrade");
97#ifndef ANTI_FLASH
98        char upload_fifo[] = "/tmp/uploadXXXXXX";
99        FILE *fifo = NULL;
100        char *write_argv[4];
101        pid_t pid;
102        char *buf = NULL;
103        int count, ret = 0;
104        long flags = -1;
105        int size = BUFSIZ;
106        int i = 0;
107
108        {
109                write_argv[0] = "write";
110                write_argv[1] = upload_fifo;
111                write_argv[2] = "linux";
112                write_argv[3] = NULL;
113        }
114
115        // diag_led(DIAG, START_LED); // blink the diag led
116        C_led(1);
117#ifdef HAVE_HTTPS
118        if (do_ssl)
119                ACTION("ACT_WEBS_UPGRADE");
120        else
121#endif
122                ACTION("ACT_WEB_UPGRADE");
123
124        /*
125         * Feed write from a temporary FIFO
126         */
127        if (!mktemp(upload_fifo) || !(fifo = fopen(upload_fifo, "w"))) {
128                if (!ret)
129                        ret = errno;
130                goto err;
131        }
132
133        /*
134         * Set nonblock on the socket so we can timeout
135         */
136
137        /*
138         ** The buffer must be at least as big as what the stream file is
139         ** using so that it can read all the data that has been buffered
140         ** in the stream file. Otherwise it would be out of sync with fn
141         ** select specially at the end of the data stream in which case
142         ** the select tells there is no more data available but there in
143         ** fact is data buffered in the stream file's buffer. Since no
144         ** one has changed the default stream file's buffer size, let's
145         ** use the constant BUFSIZ until someone changes it.
146         **/
147
148        if (size < MIN_BUF_SIZE)
149                size = MIN_BUF_SIZE;
150        if ((buf = safe_malloc(size)) == NULL) {
151                ret = ENOMEM;
152                goto err;
153        }
154
155        /*
156         * Pipe the rest to the FIFO
157         */
158        cprintf("Upgrading\n");
159        // while (total && *total)
160        {
161                wfread(&buf[0], 1, 5, stream);
162                *total -= 5;
163                if (buf[0] != 'W' || buf[1] != 'R' || buf[2] != 'A'
164                    || buf[3] != 'P' || buf[4] != '1') {
165                        ret = -1;
166                        goto err;
167                }
168                int linuxsize;
169
170                wfread(&linuxsize, 1, 4, stream);
171                *total -= 4;
172                safe_fwrite(&linuxsize, 1, 4, fifo);
173                for (i = 0; i < linuxsize / MIN_BUF_SIZE; i++) {
174                        wfread(&buf[0], 1, MIN_BUF_SIZE, stream);
175                        fwrite(&buf[0], 1, MIN_BUF_SIZE, fifo);
176                }
177
178                wfread(&buf[0], 1, linuxsize % MIN_BUF_SIZE, stream);
179                fwrite(&buf[0], 1, linuxsize % MIN_BUF_SIZE, fifo);
180                *total -= linuxsize;
181
182        }
183        fclose(fifo);
184        fifo = NULL;
185        fifo = fopen(upload_fifo, "rb");
186        unsigned long linuxsize;
187
188        linuxsize = 0;
189        linuxsize += getc(fifo);
190        linuxsize += getc(fifo) * 256;
191        linuxsize += getc(fifo) * 256 * 256;
192        linuxsize += getc(fifo) * 256 * 256 * 256;
193        char dev[128];
194
195        // fprintf (stderr, "Write Linux %d to %s\n", linuxsize,dev);
196        char drive[64];
197        sprintf(drive, "/dev/discs/disc%d/disc", getdiscindex());
198        //backup nvram
199        fprintf(stderr, "backup nvram\n");
200        FILE *in = fopen("/usr/local/nvram/nvram.bin", "rb");
201        if (in) {
202                char *mem = malloc(65536);
203                fread(mem, 65536, 1, in);
204                fclose(in);
205                in = fopen(drive, "r+b");
206                fseek(in, 0, SEEK_END);
207                long mtdlen = ftell(in);
208                fseek(in, mtdlen - (65536 * 2), SEEK_SET);
209                fwrite(mem, 65536, 1, in);
210                fclose(in);
211                eval("sync");
212                in = fopen(drive, "rb");
213                fseek(in, mtdlen - (65536 * 2), SEEK_SET);
214                fread(mem, 65536, 1, in);
215                fclose(in);
216                free(mem);
217        }
218        fprintf(stderr, "write system\n");
219        FILE *out = fopen(drive, "r+b");
220        char *flashbuf = (char *)malloc(linuxsize);
221        if (!flashbuf)          // not enough memory, use direct way
222        {
223                for (i = 0; i < linuxsize; i++)
224                        putc(getc(fifo), out);
225        } else {
226                //read into temp buffer
227                fread(flashbuf, linuxsize, 1, fifo);
228                fwrite(flashbuf, linuxsize, 1, out);
229                free(flashbuf);
230        }
231        fclose(out);
232        fprintf(stderr, "sync system\n");
233        sysprintf("sync");
234        sysprintf("sync");
235        //reread for validation
236        fprintf(stderr, "check system for validation\n");
237        in = fopen(drive, "rb");
238        for (i = 0; i < linuxsize; i++)
239                getc(in);
240        fclose(in);
241        sysprintf("sync");
242        /*
243         * Wait for write to terminate
244         */
245        // waitpid (pid, &ret, 0);
246        cprintf("done\n");
247        ret = 0;
248err:
249        if (buf)
250                free(buf);
251        if (fifo)
252                fclose(fifo);
253        unlink(upload_fifo);
254
255        // diag_led(DIAG, STOP_LED);
256        // C_led (0);
257        fprintf(stderr, "Idle\n");
258        ACTION("ACT_IDLE");
259
260        return ret;
261#else
262        return 0;
263#endif
264}
265
266void
267// do_upgrade_post(char *url, FILE *stream, int len, char *boundary)
268do_upgrade_post(char *url, webs_t stream, int len, char *boundary)      // jimmy,
269                                                                        // https,
270                                                                        // 8/6/2003
271{
272
273        killall("udhcpc", SIGKILL);
274#ifndef ANTI_FLASH
275        char buf[1024];
276        int type = 0;
277
278        upgrade_ret = EINVAL;
279
280        // Let below files loaded to memory
281        // To avoid the successful screen is blank after web upgrade.
282
283        /*
284         * Look for our part
285         */
286        while (len > 0) {
287                if (!wfgets(buf, MIN(len + 1, sizeof(buf)), stream))
288                        return;
289                len -= strlen(buf);
290                if (!strncasecmp(buf, "Content-Disposition:", 20)) {
291                        if (strstr(buf, "name=\"erase\"")) {
292                                while (len > 0 && strcmp(buf, "\n")
293                                       && strcmp(buf, "\r\n")) {
294                                        if (!wfgets
295                                            (buf, MIN(len + 1, sizeof(buf)),
296                                             stream))
297                                                return;
298                                        len -= strlen(buf);
299                                }
300                                if (!wfgets
301                                    (buf, MIN(len + 1, sizeof(buf)), stream))
302                                        return;
303                                len -= strlen(buf);
304                                buf[1] = '\0';  // we only want the 1st digit
305                                nvram_set("sv_restore_defaults", buf);
306                                nvram_commit();
307                        } else if (strstr(buf, "name=\"file\""))        // upgrade image
308                        {
309                                type = 0;
310                                break;
311                        }
312                }
313        }
314
315        /*
316         * Skip boundary and headers
317         */
318        while (len > 0) {
319                if (!wfgets(buf, MIN(len + 1, sizeof(buf)), stream))
320                        return;
321                len -= strlen(buf);
322                if (!strcmp(buf, "\n") || !strcmp(buf, "\r\n"))
323                        break;
324        }
325        upgrade_ret = sys_upgrade(NULL, stream, &len, type);
326        fprintf(stderr, "core upgrade done() %d\n", len);
327        /*
328         * Restore factory original settings if told to. This will also cause a
329         * restore defaults on reboot of a Sveasoft firmware.
330         */
331        if (nvram_match("sv_restore_defaults", "1")) {
332                system2("rm -f /usr/local/nvram/nvram.bin");
333        }
334        /*
335         * Slurp anything remaining in the request
336         */
337        while (len--) {
338#ifdef HAVE_HTTPS
339                if (do_ssl) {
340                        wfgets(buf, 1, stream);
341                } else {
342                        (void)fgetc(stream);
343                }
344#else
345                (void)fgetc(stream);
346#endif
347
348        }
349#endif
350        fprintf(stderr, "upgrade done()\n");
351
352}
Note: See TracBrowser for help on using the repository browser.