root/luci/trunk/modules/admin-full/luasrc/controller/admin/system.lua

Revision 9563, 10.3 KB (checked in by jow, 5 months ago)

don't use symlink to /lib/functions.sh

Signed-off-by: Luka Perkov <luka@…>

  • Property svn:keywords set to Id
Line 
1--[[
2LuCI - Lua Configuration Interface
3
4Copyright 2008 Steven Barth <steven@midlink.org>
5Copyright 2008-2011 Jo-Philipp Wich <xm@subsignal.org>
6
7Licensed under the Apache License, Version 2.0 (the "License");
8you may not use this file except in compliance with the License.
9You may obtain a copy of the License at
10
11    http://www.apache.org/licenses/LICENSE-2.0
12
13$Id$
14]]--
15
16module("luci.controller.admin.system", package.seeall)
17
18function index()
19    entry({"admin", "system"}, alias("admin", "system", "system"), _("System"), 30).index = true
20    entry({"admin", "system", "system"}, cbi("admin_system/system"), _("System"), 1)
21    entry({"admin", "system", "clock_status"}, call("action_clock_status"))
22
23    entry({"admin", "system", "admin"}, cbi("admin_system/admin"), _("Administration"), 2)
24
25    if nixio.fs.access("/bin/opkg") then
26        entry({"admin", "system", "packages"}, call("action_packages"), _("Software"), 10)
27        entry({"admin", "system", "packages", "ipkg"}, form("admin_system/ipkg"))
28    end
29
30    entry({"admin", "system", "startup"}, form("admin_system/startup"), _("Startup"), 45)
31    entry({"admin", "system", "crontab"}, form("admin_system/crontab"), _("Scheduled Tasks"), 46)
32
33    if nixio.fs.access("/etc/config/fstab") then
34        entry({"admin", "system", "fstab"}, cbi("admin_system/fstab"), _("Mount Points"), 50)
35        entry({"admin", "system", "fstab", "mount"}, cbi("admin_system/fstab/mount"), nil).leaf = true
36        entry({"admin", "system", "fstab", "swap"},  cbi("admin_system/fstab/swap"),  nil).leaf = true
37    end
38
39    if nixio.fs.access("/sys/class/leds") then
40        entry({"admin", "system", "leds"}, cbi("admin_system/leds"), _("<abbr title=\"Light Emitting Diode\">LED</abbr> Configuration"), 60)
41    end
42
43    entry({"admin", "system", "flashops"}, call("action_flashops"), _("Backup / Flash Firmware"), 70)
44    entry({"admin", "system", "flashops", "backupfiles"}, form("admin_system/backupfiles"))
45
46    entry({"admin", "system", "reboot"}, call("action_reboot"), _("Reboot"), 90)
47end
48
49function action_clock_status()
50    local set = tonumber(luci.http.formvalue("set"))
51    if set ~= nil and set > 0 then
52        local date = os.date("*t", set)
53        if date then
54            luci.sys.call("date -s '%04d-%02d-%02d %02d:%02d:%02d'" %{
55                date.year, date.month, date.day, date.hour, date.min, date.sec
56            })
57        end
58    end
59
60    luci.http.prepare_content("application/json")
61    luci.http.write_json({ timestring = os.date("%c") })
62end
63
64function action_packages()
65    local ipkg = require("luci.model.ipkg")
66    local submit = luci.http.formvalue("submit")
67    local changes = false
68    local install = { }
69    local remove  = { }
70    local stdout  = { "" }
71    local stderr  = { "" }
72    local out, err
73
74    -- Display
75    local display = luci.http.formvalue("display") or "installed"
76
77    -- Letter
78    local letter = string.byte(luci.http.formvalue("letter") or "A", 1)
79    letter = (letter == 35 or (letter >= 65 and letter <= 90)) and letter or 65
80
81    -- Search query
82    local query = luci.http.formvalue("query")
83    query = (query ~= '') and query or nil
84
85
86    -- Packets to be installed
87    local ninst = submit and luci.http.formvalue("install")
88    local uinst = nil
89
90    -- Install from URL
91    local url = luci.http.formvalue("url")
92    if url and url ~= '' and submit then
93        uinst = url
94    end
95
96    -- Do install
97    if ninst then
98        install[ninst], out, err = ipkg.install(ninst)
99        stdout[#stdout+1] = out
100        stderr[#stderr+1] = err
101        changes = true
102    end
103
104    if uinst then
105        local pkg
106        for pkg in luci.util.imatch(uinst) do
107            install[uinst], out, err = ipkg.install(pkg)
108            stdout[#stdout+1] = out
109            stderr[#stderr+1] = err
110            changes = true
111        end
112    end
113
114    -- Remove packets
115    local rem = submit and luci.http.formvalue("remove")
116    if rem then
117        remove[rem], out, err = ipkg.remove(rem)
118        stdout[#stdout+1] = out
119        stderr[#stderr+1] = err
120        changes = true
121    end
122
123
124    -- Update all packets
125    local update = luci.http.formvalue("update")
126    if update then
127        update, out, err = ipkg.update()
128        stdout[#stdout+1] = out
129        stderr[#stderr+1] = err
130    end
131
132
133    -- Upgrade all packets
134    local upgrade = luci.http.formvalue("upgrade")
135    if upgrade then
136        upgrade, out, err = ipkg.upgrade()
137        stdout[#stdout+1] = out
138        stderr[#stderr+1] = err
139    end
140
141
142    -- List state
143    local no_lists = true
144    local old_lists = false
145    local tmp = nixio.fs.dir("/var/opkg-lists/")
146    if tmp then
147        for tmp in tmp do
148            no_lists = false
149            tmp = nixio.fs.stat("/var/opkg-lists/"..tmp)
150            if tmp and tmp.mtime < (os.time() - (24 * 60 * 60)) then
151                old_lists = true
152                break
153            end
154        end
155    end
156
157
158    luci.template.render("admin_system/packages", {
159        display   = display,
160        letter    = letter,
161        query     = query,
162        install   = install,
163        remove    = remove,
164        update    = update,
165        upgrade   = upgrade,
166        no_lists  = no_lists,
167        old_lists = old_lists,
168        stdout    = table.concat(stdout, ""),
169        stderr    = table.concat(stderr, "")
170    })
171
172    -- Remove index cache
173    if changes then
174        nixio.fs.unlink("/tmp/luci-indexcache")
175    end
176end
177
178function action_flashops()
179    local sys = require "luci.sys"
180    local fs  = require "luci.fs"
181
182    local upgrade_avail = nixio.fs.access("/lib/upgrade/platform.sh")
183    local reset_avail   = os.execute([[grep '"rootfs_data"' /proc/mtd >/dev/null 2>&1]]) == 0
184
185    local restore_cmd = "tar -xzC/ >/dev/null 2>&1"
186    local backup_cmd  = "sysupgrade --create-backup - 2>/dev/null"
187    local image_tmp   = "/tmp/firmware.img"
188
189    local function image_supported()
190        -- XXX: yay...
191        return ( 0 == os.execute(
192            ". /lib/functions.sh; " ..
193            "include /lib/upgrade; " ..
194            "platform_check_image %q >/dev/null"
195                % image_tmp
196        ) )
197    end
198
199    local function image_checksum()
200        return (luci.sys.exec("md5sum %q" % image_tmp):match("^([^%s]+)"))
201    end
202
203    local function storage_size()
204        local size = 0
205        if nixio.fs.access("/proc/mtd") then
206            for l in io.lines("/proc/mtd") do
207                local d, s, e, n = l:match('^([^%s]+)%s+([^%s]+)%s+([^%s]+)%s+"([^%s]+)"')
208                if n == "linux" or n == "firmware" then
209                    size = tonumber(s, 16)
210                    break
211                end
212            end
213        elseif nixio.fs.access("/proc/partitions") then
214            for l in io.lines("/proc/partitions") do
215                local x, y, b, n = l:match('^%s*(%d+)%s+(%d+)%s+([^%s]+)%s+([^%s]+)')
216                if b and n and not n:match('[0-9]') then
217                    size = tonumber(b) * 1024
218                    break
219                end
220            end
221        end
222        return size
223    end
224
225
226    local fp
227    luci.http.setfilehandler(
228        function(meta, chunk, eof)
229            if not fp then
230                if meta and meta.name == "image" then
231                    fp = io.open(image_tmp, "w")
232                else
233                    fp = io.popen(restore_cmd, "w")
234                end
235            end
236            if chunk then
237                fp:write(chunk)
238            end
239            if eof then
240                fp:close()
241            end
242        end
243    )
244
245    if luci.http.formvalue("backup") then
246        --
247        -- Assemble file list, generate backup
248        --
249        local reader = ltn12_popen(backup_cmd)
250        luci.http.header('Content-Disposition', 'attachment; filename="backup-%s-%s.tar.gz"' % {
251            luci.sys.hostname(), os.date("%Y-%m-%d")})
252        luci.http.prepare_content("application/x-targz")
253        luci.ltn12.pump.all(reader, luci.http.write)
254    elseif luci.http.formvalue("restore") then
255        --
256        -- Unpack received .tar.gz
257        --
258        local upload = luci.http.formvalue("archive")
259        if upload and #upload > 0 then
260            luci.template.render("admin_system/applyreboot")
261            luci.sys.reboot()
262        end
263    elseif luci.http.formvalue("image") or luci.http.formvalue("step") then
264        --
265        -- Initiate firmware flash
266        --
267        local step = tonumber(luci.http.formvalue("step") or 1)
268        if step == 1 then
269            if image_supported() then
270                luci.template.render("admin_system/upgrade", {
271                    checksum = image_checksum(),
272                    storage  = storage_size(),
273                    size     = nixio.fs.stat(image_tmp).size,
274                    keep     = (not not luci.http.formvalue("keep"))
275                })
276            else
277                nixio.fs.unlink(image_tmp)
278                luci.template.render("admin_system/flashops", {
279                    reset_avail   = reset_avail,
280                    upgrade_avail = upgrade_avail,
281                    image_invalid = true
282                })
283            end
284        --
285        -- Start sysupgrade flash
286        --
287        elseif step == 2 then
288            local keep = (luci.http.formvalue("keep") == "1") and "" or "-n"
289            luci.template.render("admin_system/applyreboot", {
290                title = luci.i18n.translate("Flashing..."),
291                msg   = luci.i18n.translate("The system is flashing now.<br /> DO NOT POWER OFF THE DEVICE!<br /> Wait a few minutes until you try to reconnect. It might be necessary to renew the address of your computer to reach the device again, depending on your settings."),
292                addr  = (#keep > 0) and "192.168.1.1" or nil
293            })
294            fork_exec("killall dropbear uhttpd; sleep 1; /sbin/sysupgrade %s %q" %{ keep, image_tmp })
295        end
296    elseif reset_avail and luci.http.formvalue("reset") then
297        --
298        -- Reset system
299        --
300        luci.template.render("admin_system/applyreboot", {
301            title = luci.i18n.translate("Erasing..."),
302            msg   = luci.i18n.translate("The system is erasing the configuration partition now and will reboot itself when finished."),
303            addr  = "192.168.1.1"
304        })
305        fork_exec("killall dropbear uhttpd; sleep 1; mtd -r erase rootfs_data")
306    else
307        --
308        -- Overview
309        --
310        luci.template.render("admin_system/flashops", {
311            reset_avail   = reset_avail,
312            upgrade_avail = upgrade_avail
313        })
314    end
315end
316
317function action_passwd()
318    local p1 = luci.http.formvalue("pwd1")
319    local p2 = luci.http.formvalue("pwd2")
320    local stat = nil
321
322    if p1 or p2 then
323        if p1 == p2 then
324            stat = luci.sys.user.setpasswd("root", p1)
325        else
326            stat = 10
327        end
328    end
329
330    luci.template.render("admin_system/passwd", {stat=stat})
331end
332
333function action_reboot()
334    local reboot = luci.http.formvalue("reboot")
335    luci.template.render("admin_system/reboot", {reboot=reboot})
336    if reboot then
337        luci.sys.reboot()
338    end
339end
340
341function fork_exec(command)
342    local pid = nixio.fork()
343    if pid > 0 then
344        return
345    elseif pid == 0 then
346        -- change to root dir
347        nixio.chdir("/")
348
349        -- patch stdin, out, err to /dev/null
350        local null = nixio.open("/dev/null", "w+")
351        if null then
352            nixio.dup(null, nixio.stderr)
353            nixio.dup(null, nixio.stdout)
354            nixio.dup(null, nixio.stdin)
355            if null:fileno() > 2 then
356                null:close()
357            end
358        end
359
360        -- replace with target command
361        nixio.exec("/bin/sh", "-c", command)
362    end
363end
364
365function ltn12_popen(command)
366
367    local fdi, fdo = nixio.pipe()
368    local pid = nixio.fork()
369
370    if pid > 0 then
371        fdo:close()
372        local close
373        return function()
374            local buffer = fdi:read(2048)
375            local wpid, stat = nixio.waitpid(pid, "nohang")
376            if not close and wpid and stat == "exited" then
377                close = true
378            end
379
380            if buffer and #buffer > 0 then
381                return buffer
382            elseif close then
383                fdi:close()
384                return nil
385            end
386        end
387    elseif pid == 0 then
388        nixio.dup(fdo, nixio.stdout)
389        fdi:close()
390        fdo:close()
391        nixio.exec("/bin/sh", "-c", command)
392    end
393end
Note: See TracBrowser for help on using the browser.