modules/admin-*: Fixes for firmware upgrade and system reset
[project/luci.git] / modules / admin-full / luasrc / controller / admin / system.lua
1 --[[
2 LuCI - Lua Configuration Interface
3
4 Copyright 2008 Steven Barth <steven@midlink.org>
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10         http://www.apache.org/licenses/LICENSE-2.0
11
12 $Id$
13 ]]--
14 module("luci.controller.admin.system", package.seeall)
15
16 function index()
17         luci.i18n.loadc("admin-core")
18         local i18n = luci.i18n.translate
19         
20         entry({"admin", "system"}, template("admin_system/index"), i18n("system", "System"), 30)
21         entry({"admin", "system", "packages"}, call("action_packages"), i18n("a_s_packages", "Paketverwaltung"), 10)
22         entry({"admin", "system", "packages", "ipkg"}, call("action_ipkg"), i18n("a_s_p_ipkg", "IPKG-Konfiguration"))
23         entry({"admin", "system", "passwd"}, call("action_passwd"), i18n("a_s_changepw", "Passwort ändern"), 20)
24         entry({"admin", "system", "sshkeys"}, call("action_sshkeys"), i18n("a_s_sshkeys", "SSH-Schlüssel"), 30)
25         entry({"admin", "system", "system"}, cbi("admin_system/system"), i18n("system", "System"), 40)
26         entry({"admin", "system", "fstab"}, cbi("admin_system/fstab"), i18n("a_s_fstab", "Einhängepunkte"), 50)
27         entry({"admin", "system", "backup"}, call("action_backup"), i18n("a_s_backup"), 60)
28         entry({"admin", "system", "upgrade"}, call("action_upgrade"), i18n("a_s_flash", "Firmwareupgrade"), 70)
29         entry({"admin", "system", "reboot"}, call("action_reboot"), i18n("reboot", "Neu starten"), 80)
30 end
31
32 function action_editor()
33         local file = luci.http.formvalue("file", "")
34         local data = luci.http.formvalue("data")
35         local err  = nil
36         local msg  = nil
37         local stat = true
38         
39         if file and data then
40                 stat, err = luci.fs.writefile(file, data)
41         end
42         
43         if not stat then
44                 err = luci.util.split(err, " ")
45                 table.remove(err, 1)
46                 msg = table.concat(err, " ")
47         end
48         
49         local cnt, err = luci.fs.readfile(file)
50         if cnt then
51                 cnt = luci.util.pcdata(cnt)
52         end
53         luci.template.render("admin_system/editor", {fn=file, cnt=cnt, msg=msg})        
54 end
55
56 function action_ipkg()
57         local file = "/etc/ipkg.conf"
58         local data = luci.http.formvalue("data")
59         local stat = nil
60         local err  = nil
61         
62         if data then
63                 stat, err = luci.fs.writefile(file, data)
64         end     
65         
66         local cnt  = luci.fs.readfile(file)     
67         if cnt then
68                 cnt = luci.util.pcdata(cnt)
69         end
70         
71         luci.template.render("admin_system/ipkg", {cnt=cnt, msg=err})   
72 end
73
74 function action_packages()
75         local ipkg = require("luci.model.ipkg")
76         local void = nil
77         local submit = luci.http.formvalue("submit")
78         
79         
80         -- Search query
81         local query = luci.http.formvalue("query")
82         query = (query ~= '') and query or nil
83         
84         
85         -- Packets to be installed
86         local install = submit and luci.http.formvaluetable("install")
87         
88         -- Install from URL
89         local url = luci.http.formvalue("url")
90         if url and url ~= '' and submit then
91                 if not install then
92                         install = {}
93                 end
94                 install[url] = 1
95         end
96         
97         -- Do install
98         if install then
99                 for k, v in pairs(install) do
100                         void, install[k] = ipkg.install(k)
101                 end
102         end
103         
104         
105         -- Remove packets
106         local remove = submit and luci.http.formvaluetable("remove")
107         if remove then  
108                 for k, v in pairs(remove) do
109                         void, remove[k] = ipkg.remove(k)
110                 end     
111         end
112         
113         
114         -- Update all packets
115         local update = luci.http.formvalue("update")
116         if update then
117                 void, update = ipkg.update()
118         end
119         
120         
121         -- Upgrade all packets
122         local upgrade = luci.http.formvalue("upgrade")
123         if upgrade then
124                 void, upgrade = ipkg.upgrade()
125         end
126         
127         
128         -- Package info
129         local info = luci.model.ipkg.info(query)
130         info = info or {}
131         local pkgs = {}
132         
133         -- Sort after status and name
134         for k, v in pairs(info) do
135                 local x = 0
136                 for i, j in pairs(pkgs) do
137                         local vins = (v.Status and v.Status.installed)
138                         local jins = (j.Status and j.Status.installed)
139                         if vins ~= jins then
140                                 if vins then
141                                         break
142                                 end
143                         else
144                                 if j.Package > v.Package then
145                                         break
146                                 end
147                         end
148                         x = i
149                 end
150                 table.insert(pkgs, x+1, v)
151         end 
152         
153         luci.template.render("admin_system/packages", {pkgs=pkgs, query=query,
154          install=install, remove=remove, update=update, upgrade=upgrade})       
155 end
156
157 function action_backup()
158         local reset_avail = os.execute([[grep '"rootfs_data"' /proc/mtd >/dev/null 2>&1]]) == 0
159         local restore_cmd = "gunzip | tar -xC/ >/dev/null 2>&1"
160         local backup_cmd  = "tar -c %s | gzip 2>/dev/null"
161         
162         local restore_fpi 
163         luci.http.setfilehandler(
164                 function(meta, chunk, eof)
165                         if not restore_fpi then
166                                 restore_fpi = io.popen(restore_cmd, "w")
167                         end
168                         if chunk then
169                                 restore_fpi:write(chunk)
170                         end
171                         if eof then
172                                 restore_fpi:close()
173                         end
174                 end
175         )
176                   
177         local upload = luci.http.formvalue("archive")
178         local backup = luci.http.formvalue("backup")
179         local reset  = reset_avail and luci.http.formvalue("reset")
180         
181         if upload and #upload > 0 then
182                 luci.template.render("admin_system/applyreboot")
183                 luci.sys.reboot()
184         elseif backup then
185                 luci.util.perror(backup_cmd:format(_keep_pattern()))
186                 local backup_fpi = io.popen(backup_cmd:format(_keep_pattern()), "r")
187                 luci.http.header('Content-Disposition', 'attachment; filename="backup.tar.gz"')
188                 luci.http.prepare_content("application/x-targz")
189                 luci.ltn12.pump.all(luci.ltn12.source.file(backup_fpi), luci.http.write)
190         elseif reset then
191                 luci.template.render("admin_system/applyreboot")
192                 luci.sys.exec("mtd -r erase rootfs_data")
193         else
194                 luci.template.render("admin_system/backup", {reset_avail = reset_avail})
195         end
196 end
197
198 function action_passwd()
199         local p1 = luci.http.formvalue("pwd1")
200         local p2 = luci.http.formvalue("pwd2")
201         local stat = nil
202         
203         if p1 or p2 then
204                 if p1 == p2 then
205                         stat = luci.sys.user.setpasswd("root", p1)
206                 else
207                         stat = 10
208                 end
209         end
210         
211         luci.template.render("admin_system/passwd", {stat=stat})
212 end
213
214 function action_reboot()
215         local reboot = luci.http.formvalue("reboot")
216         luci.template.render("admin_system/reboot", {reboot=reboot})
217         if reboot then
218                 luci.sys.reboot()
219         end
220 end
221
222 function action_sshkeys()
223         local file = "/etc/dropbear/authorized_keys"
224         local data = luci.http.formvalue("data")
225         local stat = nil
226         local err  = nil
227         
228         if data then
229                 stat, err = luci.fs.writefile(file, data)
230         end     
231         
232         local cnt  = luci.fs.readfile(file)     
233         if cnt then
234                 cnt = luci.util.pcdata(cnt)
235         end
236         
237         luci.template.render("admin_system/sshkeys", {cnt=cnt, msg=err})        
238 end
239
240 function action_upgrade()
241         require("luci.model.uci")
242
243         local ret  = nil
244         local plat = luci.fs.mtime("/lib/upgrade/platform.sh")
245         local broadcom = os.execute('grep brcm_ /lib/upgrade/platform.sh >/dev/null 2>&1') == 0
246         local tmpfile = "/tmp/firmware.img"
247         
248         local keep_avail = not broadcom
249
250         local file
251         luci.http.setfilehandler(
252                 function(meta, chunk, eof)
253                         if not file then
254                                 file = io.open(tmpfile, "w")
255                         end
256                         if chunk then
257                                 file:write(chunk)
258                         end
259                         if eof then
260                                 file:close()
261                         end
262                 end
263         )
264
265         local fname   = luci.http.formvalue("image")
266         local keepcfg = keep_avail and luci.http.formvalue("keepcfg")
267
268         if plat and fname then
269                 ret = luci.sys.flash(tmpfile, keepcfg and _keep_pattern())
270         end
271
272         luci.template.render("admin_system/upgrade", {sysupgrade=plat, ret=ret, keep_avail=keep_avail})
273 end
274
275 function _keep_pattern()
276         local kpattern = ""
277         local files = luci.model.uci.get_all("luci", "flash_keep")
278         if files then
279                 kpattern = ""
280                 for k,v in pairs(files) do
281                         kpattern = kpattern .. " " ..  v
282                 end
283         end
284         return kpattern
285 end