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