summaryrefslogtreecommitdiff
path: root/release/src/router/httpd/upgrade.c
blob: ce3e27c428d1c50d44a061ae0f2174cf54ba37ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*

	Tomato Firmware
	Copyright (C) 2006-2009 Jonathan Zarate

*/

#include "tomato.h"

#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <sys/wait.h>
#include <typedefs.h>
#include <sys/reboot.h>

#if 1
#define MTD_WRITE_CMD	"mtd-write"
#else
#define DEBUG_TEST
#define MTD_WRITE_CMD	"/tmp/mtd-write"
#endif

void prepare_upgrade(void)
{
	int n;

	// stop non-essential stuff & free up some memory
	exec_service("upgrade-start");
	for (n = 30; n > 0; --n) {
		sleep(1);
		if (nvram_match("action_service", "")) break;	// this is cleared at the end
	}
	unlink("/var/log/messages");
	unlink("/var/log/messages.0");
	sync();
}

void wi_upgrade(char *url, int len, char *boundary)
{
	uint8 buf[1024];
	const char *error = "Error reading file";
	int ok = 0;
	int n;

	check_id(url);

	// quickly check if JFFS2 is mounted by checking if /jffs/ is not squashfs
	struct statfs sf;
	if ((statfs("/jffs", &sf) != 0) || (sf.f_type != 0x73717368)) {
		error = "JFFS2 is currently in use. Since an upgrade may overwrite the "
			"JFFS2 partition, please backup the contents, disable JFFS2, then reboot the router";
		goto ERROR;
	}

	// skip the rest of the header
	if (!skip_header(&len)) goto ERROR;

	if (len < (1 * 1024 * 1024)) {
		error = "Invalid file";
		goto ERROR;
	}

	// -- anything after here ends in a reboot --

	rboot = 1;

	led(LED_DIAG, 1);

	signal(SIGTERM, SIG_IGN);
	signal(SIGINT, SIG_IGN);
	signal(SIGHUP, SIG_IGN);
	signal(SIGQUIT, SIG_IGN);

	prepare_upgrade();
	system("cp reboot.asp /tmp");	// copy to memory

	char fifo[] = "/tmp/flashXXXXXX";
	int pid = -1;
	FILE *f = NULL;

	if ((mktemp(fifo) == NULL) ||
		(mkfifo(fifo, S_IRWXU) < 0)) {
		error = "Unable to create a fifo";
		goto ERROR2;
	}

	char *wargv[] = { MTD_WRITE_CMD, "-w", "-i", fifo, "-d", "linux", NULL };
	if (_eval(wargv, ">/tmp/.mtd-write", 0, &pid) != 0) {
		error = "Unable to start flash program";
		goto ERROR2;
	}

	if ((f = fopen(fifo, "w")) == NULL) {
		error = "Unable to start pipe for mtd write";
		goto ERROR2;
	}

	// !!! This will actually write the boundary. But since mtd-write
	// uses trx length... -- zzz

	while (len > 0) {
		 if ((n = web_read(buf, MIN(len, sizeof(buf)))) <= 0) {
			 goto ERROR2;
		 }
		 len -= n;
		 if (safe_fwrite(buf, 1, n, f) != n) {
			 error = "Error writing to pipe";
			 goto ERROR2;
		 }
	}

	error = NULL;
	ok = 1;

ERROR2:
	rboot = 1;
	set_action(ACT_REBOOT);

	if (f) fclose(f);
	if (pid != -1) waitpid(pid, &n, 0);

	resmsg_fread("/tmp/.mtd-write");

	web_eat(len);
	return;

ERROR:
	resmsg_set(error);
	web_eat(len);
}

void wo_flash(char *url)
{
	if (rboot) {
		parse_asp("/tmp/reboot.asp");
		web_close();

#ifdef DEBUG_TEST
		printf("\n\n -- reboot -- \n\n");
		set_action(ACT_IDLE);
#else
		killall("pppoecd", SIGTERM);
		sleep(2);
		//	kill(1, SIGTERM);
		reboot(RB_AUTOBOOT);
#endif
		exit(0);
	}

	parse_asp("error.asp");
}