| 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 |
|---|
| 31 | static int upgrade_ret; |
|---|
| 32 | |
|---|
| 33 | static 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 | |
|---|
| 60 | void |
|---|
| 61 | // do_upgrade_cgi(char *url, FILE *stream) |
|---|
| 62 | do_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 | |
|---|
| 90 | int |
|---|
| 91 | // sys_upgrade(char *url, FILE *stream, int *total) |
|---|
| 92 | sys_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 | for (i = 0; i < linuxsize; i++) |
|---|
| 221 | putc(getc(fifo), out); |
|---|
| 222 | fclose(out); |
|---|
| 223 | fprintf(stderr, "sync system\n"); |
|---|
| 224 | |
|---|
| 225 | sysprintf("sync"); |
|---|
| 226 | sysprintf("sync"); |
|---|
| 227 | //reread for validation |
|---|
| 228 | fprintf(stderr, "check system for validation\n"); |
|---|
| 229 | in = fopen(drive, "rb"); |
|---|
| 230 | for (i = 0; i < linuxsize; i++) |
|---|
| 231 | getc(in); |
|---|
| 232 | fclose(in); |
|---|
| 233 | sysprintf("sync"); |
|---|
| 234 | /* |
|---|
| 235 | * Wait for write to terminate |
|---|
| 236 | */ |
|---|
| 237 | // waitpid (pid, &ret, 0); |
|---|
| 238 | cprintf("done\n"); |
|---|
| 239 | ret = 0; |
|---|
| 240 | err: |
|---|
| 241 | if (buf) |
|---|
| 242 | free(buf); |
|---|
| 243 | if (fifo) |
|---|
| 244 | fclose(fifo); |
|---|
| 245 | unlink(upload_fifo); |
|---|
| 246 | |
|---|
| 247 | // diag_led(DIAG, STOP_LED); |
|---|
| 248 | // C_led (0); |
|---|
| 249 | fprintf(stderr, "Idle\n"); |
|---|
| 250 | ACTION("ACT_IDLE"); |
|---|
| 251 | |
|---|
| 252 | return ret; |
|---|
| 253 | #else |
|---|
| 254 | return 0; |
|---|
| 255 | #endif |
|---|
| 256 | } |
|---|
| 257 | |
|---|
| 258 | void |
|---|
| 259 | // do_upgrade_post(char *url, FILE *stream, int len, char *boundary) |
|---|
| 260 | do_upgrade_post(char *url, webs_t stream, int len, char *boundary) // jimmy, |
|---|
| 261 | // https, |
|---|
| 262 | // 8/6/2003 |
|---|
| 263 | { |
|---|
| 264 | |
|---|
| 265 | killall("udhcpc", SIGKILL); |
|---|
| 266 | #ifndef ANTI_FLASH |
|---|
| 267 | char buf[1024]; |
|---|
| 268 | int type = 0; |
|---|
| 269 | |
|---|
| 270 | upgrade_ret = EINVAL; |
|---|
| 271 | |
|---|
| 272 | // Let below files loaded to memory |
|---|
| 273 | // To avoid the successful screen is blank after web upgrade. |
|---|
| 274 | |
|---|
| 275 | /* |
|---|
| 276 | * Look for our part |
|---|
| 277 | */ |
|---|
| 278 | while (len > 0) { |
|---|
| 279 | if (!wfgets(buf, MIN(len + 1, sizeof(buf)), stream)) |
|---|
| 280 | return; |
|---|
| 281 | len -= strlen(buf); |
|---|
| 282 | if (!strncasecmp(buf, "Content-Disposition:", 20)) { |
|---|
| 283 | if (strstr(buf, "name=\"erase\"")) { |
|---|
| 284 | while (len > 0 && strcmp(buf, "\n") |
|---|
| 285 | && strcmp(buf, "\r\n")) { |
|---|
| 286 | if (!wfgets |
|---|
| 287 | (buf, MIN(len + 1, sizeof(buf)), |
|---|
| 288 | stream)) |
|---|
| 289 | return; |
|---|
| 290 | len -= strlen(buf); |
|---|
| 291 | } |
|---|
| 292 | if (!wfgets |
|---|
| 293 | (buf, MIN(len + 1, sizeof(buf)), stream)) |
|---|
| 294 | return; |
|---|
| 295 | len -= strlen(buf); |
|---|
| 296 | buf[1] = '\0'; // we only want the 1st digit |
|---|
| 297 | nvram_set("sv_restore_defaults", buf); |
|---|
| 298 | nvram_commit(); |
|---|
| 299 | } else if (strstr(buf, "name=\"file\"")) // upgrade image |
|---|
| 300 | { |
|---|
| 301 | type = 0; |
|---|
| 302 | break; |
|---|
| 303 | } |
|---|
| 304 | } |
|---|
| 305 | } |
|---|
| 306 | |
|---|
| 307 | /* |
|---|
| 308 | * Skip boundary and headers |
|---|
| 309 | */ |
|---|
| 310 | while (len > 0) { |
|---|
| 311 | if (!wfgets(buf, MIN(len + 1, sizeof(buf)), stream)) |
|---|
| 312 | return; |
|---|
| 313 | len -= strlen(buf); |
|---|
| 314 | if (!strcmp(buf, "\n") || !strcmp(buf, "\r\n")) |
|---|
| 315 | break; |
|---|
| 316 | } |
|---|
| 317 | upgrade_ret = sys_upgrade(NULL, stream, &len, type); |
|---|
| 318 | fprintf(stderr, "core upgrade done() %d\n", len); |
|---|
| 319 | /* |
|---|
| 320 | * Restore factory original settings if told to. This will also cause a |
|---|
| 321 | * restore defaults on reboot of a Sveasoft firmware. |
|---|
| 322 | */ |
|---|
| 323 | if (nvram_match("sv_restore_defaults", "1")) { |
|---|
| 324 | system2("rm -f /usr/local/nvram/nvram.bin"); |
|---|
| 325 | } |
|---|
| 326 | /* |
|---|
| 327 | * Slurp anything remaining in the request |
|---|
| 328 | */ |
|---|
| 329 | while (len--) { |
|---|
| 330 | #ifdef HAVE_HTTPS |
|---|
| 331 | if (do_ssl) { |
|---|
| 332 | wfgets(buf, 1, stream); |
|---|
| 333 | } else { |
|---|
| 334 | (void)fgetc(stream); |
|---|
| 335 | } |
|---|
| 336 | #else |
|---|
| 337 | (void)fgetc(stream); |
|---|
| 338 | #endif |
|---|
| 339 | |
|---|
| 340 | } |
|---|
| 341 | #endif |
|---|
| 342 | fprintf(stderr, "upgrade done()\n"); |
|---|
| 343 | |
|---|
| 344 | } |
|---|