| 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 | #ifdef HAVE_X86 |
|---|
| 34 | static char *getdisc(void) // works only for squashfs |
|---|
| 35 | { |
|---|
| 36 | int i; |
|---|
| 37 | unsigned char *disks[]={"/dev/sda2","/dev/sdb2","/dev/sdc2","/dev/sdd2","/dev/sde2","/dev/sdf2","/dev/sdg2","/dev/sdh2","/dev/sdi2"}; |
|---|
| 38 | for (i = 0; i < 9; i++) { |
|---|
| 39 | char dev[64]; |
|---|
| 40 | |
|---|
| 41 | strcpy(dev, disks[i]); |
|---|
| 42 | FILE *in = fopen(dev, "rb"); |
|---|
| 43 | |
|---|
| 44 | if (in == NULL) |
|---|
| 45 | continue; // no second partition or disc does not |
|---|
| 46 | // exist, skipping |
|---|
| 47 | char buf[4]; |
|---|
| 48 | |
|---|
| 49 | fread(buf, 4, 1, in); |
|---|
| 50 | if (buf[0] == 'h' && buf[1] == 's' && buf[2] == 'q' |
|---|
| 51 | && buf[3] == 't') { |
|---|
| 52 | fclose(in); |
|---|
| 53 | // filesystem detected |
|---|
| 54 | return disks[i]; |
|---|
| 55 | } |
|---|
| 56 | fclose(in); |
|---|
| 57 | } |
|---|
| 58 | return NULL; |
|---|
| 59 | } |
|---|
| 60 | #endif |
|---|
| 61 | void |
|---|
| 62 | // do_upgrade_cgi(char *url, FILE *stream) |
|---|
| 63 | do_upgrade_cgi(struct mime_handler *handler, char *url, webs_t stream, char *query) // jimmy, https, |
|---|
| 64 | // 8/6/2003 |
|---|
| 65 | { |
|---|
| 66 | #ifndef ANTI_FLASH |
|---|
| 67 | fprintf(stderr, "do post\n"); |
|---|
| 68 | if (upgrade_ret) |
|---|
| 69 | do_ej(handler, "Fail_u_s.asp", stream, NULL); |
|---|
| 70 | else |
|---|
| 71 | do_ej(handler, "Success_u_s.asp", stream, NULL); |
|---|
| 72 | fprintf(stderr, "websdone\n"); |
|---|
| 73 | |
|---|
| 74 | websDone(stream, 200); |
|---|
| 75 | fprintf(stderr, "reboot\n"); |
|---|
| 76 | |
|---|
| 77 | /* |
|---|
| 78 | * Reboot if successful |
|---|
| 79 | */ |
|---|
| 80 | if (upgrade_ret == 0) { |
|---|
| 81 | sleep(4); |
|---|
| 82 | eval("umount", "/usr/local"); |
|---|
| 83 | sys_reboot(); |
|---|
| 84 | } |
|---|
| 85 | #else |
|---|
| 86 | do_ej(handler, "Fail_u_s.asp", stream, NULL); |
|---|
| 87 | websDone(stream, 200); |
|---|
| 88 | #endif |
|---|
| 89 | } |
|---|
| 90 | |
|---|
| 91 | #ifdef HAVE_RB600 |
|---|
| 92 | #define swap(x) \ |
|---|
| 93 | ((unsigned int )( \ |
|---|
| 94 | (((unsigned int )(x) & (unsigned int )0x000000ffUL) << 24) | \ |
|---|
| 95 | (((unsigned int )(x) & (unsigned int )0x0000ff00UL) << 8) | \ |
|---|
| 96 | (((unsigned int )(x) & (unsigned int )0x00ff0000UL) >> 8) | \ |
|---|
| 97 | (((unsigned int )(x) & (unsigned int )0xff000000UL) >> 24) )) |
|---|
| 98 | |
|---|
| 99 | |
|---|
| 100 | #endif |
|---|
| 101 | |
|---|
| 102 | int |
|---|
| 103 | // sys_upgrade(char *url, FILE *stream, int *total) |
|---|
| 104 | sys_upgrade(char *url, webs_t stream, int *total, int type) // jimmy, |
|---|
| 105 | // https, |
|---|
| 106 | // 8/6/2003 |
|---|
| 107 | { |
|---|
| 108 | lcdmessage("System Upgrade"); |
|---|
| 109 | #ifndef ANTI_FLASH |
|---|
| 110 | char upload_fifo[] = "/tmp/uploadXXXXXX"; |
|---|
| 111 | FILE *fifo = NULL; |
|---|
| 112 | char *write_argv[4]; |
|---|
| 113 | pid_t pid; |
|---|
| 114 | char *buf = NULL; |
|---|
| 115 | int count, ret = 0; |
|---|
| 116 | long flags = -1; |
|---|
| 117 | int size = BUFSIZ; |
|---|
| 118 | int i = 0; |
|---|
| 119 | |
|---|
| 120 | { |
|---|
| 121 | write_argv[0] = "write"; |
|---|
| 122 | write_argv[1] = upload_fifo; |
|---|
| 123 | write_argv[2] = "linux"; |
|---|
| 124 | write_argv[3] = NULL; |
|---|
| 125 | } |
|---|
| 126 | |
|---|
| 127 | // diag_led(DIAG, START_LED); // blink the diag led |
|---|
| 128 | C_led(1); |
|---|
| 129 | #ifdef HAVE_HTTPS |
|---|
| 130 | if (do_ssl) |
|---|
| 131 | ACTION("ACT_WEBS_UPGRADE"); |
|---|
| 132 | else |
|---|
| 133 | #endif |
|---|
| 134 | ACTION("ACT_WEB_UPGRADE"); |
|---|
| 135 | |
|---|
| 136 | /* |
|---|
| 137 | * Feed write from a temporary FIFO |
|---|
| 138 | */ |
|---|
| 139 | if (!mktemp(upload_fifo) || !(fifo = fopen(upload_fifo, "w"))) { |
|---|
| 140 | if (!ret) |
|---|
| 141 | ret = errno; |
|---|
| 142 | goto err; |
|---|
| 143 | } |
|---|
| 144 | |
|---|
| 145 | /* |
|---|
| 146 | * Set nonblock on the socket so we can timeout |
|---|
| 147 | */ |
|---|
| 148 | |
|---|
| 149 | /* |
|---|
| 150 | ** The buffer must be at least as big as what the stream file is |
|---|
| 151 | ** using so that it can read all the data that has been buffered |
|---|
| 152 | ** in the stream file. Otherwise it would be out of sync with fn |
|---|
| 153 | ** select specially at the end of the data stream in which case |
|---|
| 154 | ** the select tells there is no more data available but there in |
|---|
| 155 | ** fact is data buffered in the stream file's buffer. Since no |
|---|
| 156 | ** one has changed the default stream file's buffer size, let's |
|---|
| 157 | ** use the constant BUFSIZ until someone changes it. |
|---|
| 158 | **/ |
|---|
| 159 | |
|---|
| 160 | if (size < MIN_BUF_SIZE) |
|---|
| 161 | size = MIN_BUF_SIZE; |
|---|
| 162 | if ((buf = safe_malloc(size)) == NULL) { |
|---|
| 163 | ret = ENOMEM; |
|---|
| 164 | goto err; |
|---|
| 165 | } |
|---|
| 166 | |
|---|
| 167 | /* |
|---|
| 168 | * Pipe the rest to the FIFO |
|---|
| 169 | */ |
|---|
| 170 | cprintf("Upgrading\n"); |
|---|
| 171 | // while (total && *total) |
|---|
| 172 | { |
|---|
| 173 | wfread(&buf[0], 1, 5, stream); |
|---|
| 174 | *total -= 5; |
|---|
| 175 | if (buf[0] != 'W' || buf[1] != 'R' || buf[2] != 'A' |
|---|
| 176 | || buf[3] != 'P' || buf[4] != '1') { |
|---|
| 177 | ret = -1; |
|---|
| 178 | goto err; |
|---|
| 179 | } |
|---|
| 180 | int linuxsize; |
|---|
| 181 | |
|---|
| 182 | wfread(&linuxsize, 1, 4, stream); |
|---|
| 183 | *total -= 4; |
|---|
| 184 | safe_fwrite(&linuxsize, 1, 4, fifo); |
|---|
| 185 | #ifdef HAVE_RB600 |
|---|
| 186 | linuxsize=swap(linuxsize); |
|---|
| 187 | #endif |
|---|
| 188 | for (i = 0; i < linuxsize / MIN_BUF_SIZE; i++) { |
|---|
| 189 | wfread(&buf[0], 1, MIN_BUF_SIZE, stream); |
|---|
| 190 | fwrite(&buf[0], 1, MIN_BUF_SIZE, fifo); |
|---|
| 191 | } |
|---|
| 192 | |
|---|
| 193 | wfread(&buf[0], 1, linuxsize % MIN_BUF_SIZE, stream); |
|---|
| 194 | fwrite(&buf[0], 1, linuxsize % MIN_BUF_SIZE, fifo); |
|---|
| 195 | *total -= linuxsize; |
|---|
| 196 | |
|---|
| 197 | } |
|---|
| 198 | fclose(fifo); |
|---|
| 199 | fifo = NULL; |
|---|
| 200 | fifo = fopen(upload_fifo, "rb"); |
|---|
| 201 | unsigned long linuxsize; |
|---|
| 202 | |
|---|
| 203 | linuxsize = 0; |
|---|
| 204 | linuxsize += getc(fifo); |
|---|
| 205 | linuxsize += getc(fifo) * 256; |
|---|
| 206 | linuxsize += getc(fifo) * 256 * 256; |
|---|
| 207 | linuxsize += getc(fifo) * 256 * 256 * 256; |
|---|
| 208 | char dev[128]; |
|---|
| 209 | |
|---|
| 210 | char drive[64]; |
|---|
| 211 | #ifdef HAVE_RB600 |
|---|
| 212 | sprintf(drive, "/dev/sda"); |
|---|
| 213 | #else |
|---|
| 214 | strcpy(drive, getdisc()); |
|---|
| 215 | #endif |
|---|
| 216 | fprintf (stderr, "Write Linux %d to %s\n", linuxsize,dev); |
|---|
| 217 | //backup nvram |
|---|
| 218 | fprintf(stderr, "backup nvram\n"); |
|---|
| 219 | FILE *in = fopen("/usr/local/nvram/nvram.bin", "rb"); |
|---|
| 220 | if (in) { |
|---|
| 221 | char *mem = malloc(65536); |
|---|
| 222 | fread(mem, 65536, 1, in); |
|---|
| 223 | fclose(in); |
|---|
| 224 | in = fopen(drive, "r+b"); |
|---|
| 225 | fseeko(in, 0, SEEK_END); |
|---|
| 226 | off_t mtdlen = ftello(in); |
|---|
| 227 | fseeko(in, mtdlen - (65536 * 2), SEEK_SET); |
|---|
| 228 | fwrite(mem, 65536, 1, in); |
|---|
| 229 | fclose(in); |
|---|
| 230 | eval("sync"); |
|---|
| 231 | in = fopen(drive, "rb"); |
|---|
| 232 | fseeko(in, mtdlen - (65536 * 2), SEEK_SET); |
|---|
| 233 | fread(mem, 65536, 1, in); |
|---|
| 234 | fclose(in); |
|---|
| 235 | free(mem); |
|---|
| 236 | } |
|---|
| 237 | fprintf(stderr, "write system\n"); |
|---|
| 238 | FILE *out = fopen(drive, "r+b"); |
|---|
| 239 | char *flashbuf = (char *)malloc(linuxsize); |
|---|
| 240 | if (!flashbuf) // not enough memory, use direct way |
|---|
| 241 | { |
|---|
| 242 | for (i = 0; i < linuxsize; i++) |
|---|
| 243 | putc(getc(fifo), out); |
|---|
| 244 | } else { |
|---|
| 245 | //read into temp buffer |
|---|
| 246 | fread(flashbuf, linuxsize, 1, fifo); |
|---|
| 247 | fwrite(flashbuf, linuxsize, 1, out); |
|---|
| 248 | free(flashbuf); |
|---|
| 249 | } |
|---|
| 250 | fclose(out); |
|---|
| 251 | fprintf(stderr, "sync system\n"); |
|---|
| 252 | sysprintf("sync"); |
|---|
| 253 | sysprintf("sync"); |
|---|
| 254 | sysprintf("echo 1 > /proc/sys/vm/drop_caches"); // flush fs cache |
|---|
| 255 | //reread for validation |
|---|
| 256 | fprintf(stderr, "check system for validation\n"); |
|---|
| 257 | in = fopen(drive, "rb"); |
|---|
| 258 | for (i = 0; i < linuxsize; i++) |
|---|
| 259 | getc(in); |
|---|
| 260 | fclose(in); |
|---|
| 261 | sysprintf("sync"); |
|---|
| 262 | /* |
|---|
| 263 | * Wait for write to terminate |
|---|
| 264 | */ |
|---|
| 265 | // waitpid (pid, &ret, 0); |
|---|
| 266 | cprintf("done\n"); |
|---|
| 267 | ret = 0; |
|---|
| 268 | err: |
|---|
| 269 | if (buf) |
|---|
| 270 | free(buf); |
|---|
| 271 | if (fifo) |
|---|
| 272 | fclose(fifo); |
|---|
| 273 | unlink(upload_fifo); |
|---|
| 274 | |
|---|
| 275 | // diag_led(DIAG, STOP_LED); |
|---|
| 276 | // C_led (0); |
|---|
| 277 | fprintf(stderr, "Idle\n"); |
|---|
| 278 | ACTION("ACT_IDLE"); |
|---|
| 279 | |
|---|
| 280 | return ret; |
|---|
| 281 | #else |
|---|
| 282 | return 0; |
|---|
| 283 | #endif |
|---|
| 284 | } |
|---|
| 285 | |
|---|
| 286 | void |
|---|
| 287 | // do_upgrade_post(char *url, FILE *stream, int len, char *boundary) |
|---|
| 288 | do_upgrade_post(char *url, webs_t stream, int len, char *boundary) // jimmy, |
|---|
| 289 | // https, |
|---|
| 290 | // 8/6/2003 |
|---|
| 291 | { |
|---|
| 292 | |
|---|
| 293 | killall("udhcpc", SIGKILL); |
|---|
| 294 | #ifndef ANTI_FLASH |
|---|
| 295 | char buf[1024]; |
|---|
| 296 | int type = 0; |
|---|
| 297 | |
|---|
| 298 | upgrade_ret = EINVAL; |
|---|
| 299 | |
|---|
| 300 | // Let below files loaded to memory |
|---|
| 301 | // To avoid the successful screen is blank after web upgrade. |
|---|
| 302 | |
|---|
| 303 | /* |
|---|
| 304 | * Look for our part |
|---|
| 305 | */ |
|---|
| 306 | while (len > 0) { |
|---|
| 307 | if (!wfgets(buf, MIN(len + 1, sizeof(buf)), stream)) |
|---|
| 308 | return; |
|---|
| 309 | len -= strlen(buf); |
|---|
| 310 | if (!strncasecmp(buf, "Content-Disposition:", 20)) { |
|---|
| 311 | if (strstr(buf, "name=\"erase\"")) { |
|---|
| 312 | while (len > 0 && strcmp(buf, "\n") |
|---|
| 313 | && strcmp(buf, "\r\n")) { |
|---|
| 314 | if (!wfgets |
|---|
| 315 | (buf, MIN(len + 1, sizeof(buf)), |
|---|
| 316 | stream)) |
|---|
| 317 | return; |
|---|
| 318 | len -= strlen(buf); |
|---|
| 319 | } |
|---|
| 320 | if (!wfgets |
|---|
| 321 | (buf, MIN(len + 1, sizeof(buf)), stream)) |
|---|
| 322 | return; |
|---|
| 323 | len -= strlen(buf); |
|---|
| 324 | buf[1] = '\0'; // we only want the 1st digit |
|---|
| 325 | nvram_set("sv_restore_defaults", buf); |
|---|
| 326 | nvram_commit(); |
|---|
| 327 | } else if (strstr(buf, "name=\"file\"")) // upgrade image |
|---|
| 328 | { |
|---|
| 329 | type = 0; |
|---|
| 330 | break; |
|---|
| 331 | } |
|---|
| 332 | } |
|---|
| 333 | } |
|---|
| 334 | |
|---|
| 335 | /* |
|---|
| 336 | * Skip boundary and headers |
|---|
| 337 | */ |
|---|
| 338 | while (len > 0) { |
|---|
| 339 | if (!wfgets(buf, MIN(len + 1, sizeof(buf)), stream)) |
|---|
| 340 | return; |
|---|
| 341 | len -= strlen(buf); |
|---|
| 342 | if (!strcmp(buf, "\n") || !strcmp(buf, "\r\n")) |
|---|
| 343 | break; |
|---|
| 344 | } |
|---|
| 345 | upgrade_ret = sys_upgrade(NULL, stream, &len, type); |
|---|
| 346 | fprintf(stderr, "core upgrade done() %d\n", len); |
|---|
| 347 | /* |
|---|
| 348 | * Restore factory original settings if told to. This will also cause a |
|---|
| 349 | * restore defaults on reboot of a Sveasoft firmware. |
|---|
| 350 | */ |
|---|
| 351 | if (nvram_match("sv_restore_defaults", "1")) { |
|---|
| 352 | system2("rm -f /usr/local/nvram/nvram.bin"); |
|---|
| 353 | char drive[64]; |
|---|
| 354 | #ifdef HAVE_RB600 |
|---|
| 355 | sprintf(drive, "/dev/sda"); |
|---|
| 356 | #else |
|---|
| 357 | strcpy(drive, getdisc()); |
|---|
| 358 | #endif |
|---|
| 359 | FILE *in = fopen(drive, "r+b"); |
|---|
| 360 | fseeko(in, 0, SEEK_END); |
|---|
| 361 | off_t mtdlen = ftell(in); |
|---|
| 362 | fseeko(in, mtdlen - (65536 * 2), SEEK_SET); |
|---|
| 363 | int i; |
|---|
| 364 | for (i = 0; i < 65536; i++) |
|---|
| 365 | putc(0, in); // erase backup area |
|---|
| 366 | fclose(in); |
|---|
| 367 | } |
|---|
| 368 | /* |
|---|
| 369 | * Slurp anything remaining in the request |
|---|
| 370 | */ |
|---|
| 371 | while (len--) { |
|---|
| 372 | #ifdef HAVE_HTTPS |
|---|
| 373 | if (do_ssl) { |
|---|
| 374 | wfgets(buf, 1, stream); |
|---|
| 375 | } else { |
|---|
| 376 | (void)fgetc(stream); |
|---|
| 377 | } |
|---|
| 378 | #else |
|---|
| 379 | (void)fgetc(stream); |
|---|
| 380 | #endif |
|---|
| 381 | |
|---|
| 382 | } |
|---|
| 383 | #endif |
|---|
| 384 | fprintf(stderr, "upgrade done()\n"); |
|---|
| 385 | |
|---|
| 386 | } |
|---|