[ UP ] update cgi. add display percentege bar icons.
[archserver.git] / cgi / libutil.lua
blobfdf338b0b1a7178812a2e919ca08cc51851c3204
2 -- return output & return value
3 function myexec(cmd)
4 cmd = cmd..[[ 2>&1; echo -e "\nKylin_RETURN$?"]]
5 local _pfile = assert(io.popen(cmd))
6 local _s = _pfile:read("*all")
7 _pfile:close()
8 _,_,_s, _r= string.find(_s, "(.*)\nKylin_RETURN(%d+)")
9 return _s, tonumber(_r)
10 end
12 ----------------------------------------------
13 function myread(file)
14 local _f = assert(io.open(file, "r"))
15 local _t = _f:read("*all")
16 _f:close()
17 return _t
18 end
20 function mywrite(file, s)
21 local _tn = os.tmpname()
22 local _tf = assert(io.open(_tn, "w"))
23 _tf:write(s)
24 _tf:close()
25 assert(0 == os.execute("sudo /bin/cp ".._tn.." "..file), "[Error] - ".."cp ".._tn.." "..file)
26 return os.execute("rm ".._tn)
27 end
29 function read_file_lines(filename)
30 local t = myread(filename)
31 local lines = {}
32 string.gsub(t, "(.-[\n$])", function(l) table.insert(lines,l) end)
33 return lines
34 end
36 function flush_file_lines(filename, lines)
37 mywrite(filename, table.concat(lines))
38 end
40 function one_two(v)
41 if (v == 1) then return 2 end
42 return 1
43 end
45 function sec2string(t)
46 sec = assert(tonumber(t))
47 if (sec < 60 ) then
48 return sec.."秒"
49 elseif (sec < 60*60 ) then
50 return string.format("%d分%d秒", sec/60, sec%60)
51 elseif (sec < 86400) then
52 return string.format("%d小时%d分%d秒", sec/(3600), (sec%3600)/60,sec%3600%60)
53 else
54 return string.format("%d天%d小时%d分%d秒",sec/(86400), (sec%86400)/(3600),
55 (sec%86400%3600)/60, sec%86400%3600%60)
56 end
57 end
59 function time2date(t)
60 return string.format("%02d:%02d:%02d/%4d年%02d月%02d日",
61 t["hour"],t["min"],t["sec"],t["year"],t["month"],t["day"])
62 end
64 function size2hum(size)
65 s = assert(tonumber(string.sub(size, 1, -2)), "size2hum: Not number")
66 u = string.lower(string.sub(size, -1, -1))
67 assert(u == "b" or u == "k" or u == "m", [[size2hum: Unit not 'b' or 'k' or 'm']])
69 if u == 'b' then
70 if (s < 1024 ) then return s.."Byte"
71 elseif (s < 1048576 ) then return string.format("%.2f", s/1024).." Kb"
72 elseif (s < 1073741824 ) then return string.format("%.2f", s/1024/1024).." MB"
73 elseif (s < 1073741824*1024) then return string.format("%.2f", s/1024/1024/1024).." GB"
74 else return string.format("%.2f", s/1024/1024/1024/1024).."TB"
75 end
76 elseif u == 'k' then
77 if (s < 1024 ) then return s.." Kb"
78 elseif (s < 1048576 ) then return string.format("%.2f", s/1024).." Mb"
79 elseif (s < 1073741824 ) then return string.format("%.2f", s/1024/1024).." GB"
80 else return string.format("%.2f", s/1024/1024/1024).." TB"
81 end
82 elseif u == 'm' then
83 if (s < 1024 ) then return s.." Mb"
84 elseif (s < 1048576 ) then return string.format("%.2f", s/1024).." Gb"
85 else return string.format("%.2f", s/1024/1024).." TB"
86 end
87 end
88 end
90 -- do string.gsub on a file instead of on a string
91 function file_gsub(file, s, g)
92 local _f = assert(io.open(file, "r"))
93 local _t = _f:read("*all")
94 _t = string.gsub(_t, s, g)
95 _f:close()
97 local _tn = os.tmpname()
98 local _tf = assert(io.open(_tn, "w"))
99 _tf:write(_t)
100 _tf:close()
102 assert(0 == os.execute("sudo /bin/cp ".._tn.." "..file), "[Error] - ".."cp ".._tn.." "..file)
103 os.execute("rm ".._tn)
106 -----------------------------------------------------------------------------
107 -- check with the email string is valid
109 --@param email the email string
110 --@return the email string or false
111 -----------------------------------------------------------------------------
112 function is_email_valid(email)
113 return string.match(email,"^[%a][%w%.%-]*[%a%d]*@[%a%d][%w%.%-]*[%a%d]%.[%a][%a]?[%a]?[%a]$")
115 -----------------------------------------------------------------------------
116 -- CGI utilities
117 -----------------------------------------------------------------------------
119 -- message box
120 function message_err(s)
121 print([[<div class="messageblock messageblock-error">
122 <div class="messageblock-internal">
123 <p><ul><strong>出现了下面的错误</strong><li>]]..s..[[
124 </li><ul></p>
125 </div></div>]])
128 function ui_message_err(s)
129 print([[<div class="messageblock messageblock-error">
130 <div class="messageblock-internal">
131 <p><ul><strong>出现了下面的错误</strong><li>]]..s..[[
132 </li><ul></p>
133 </div></div>]])
136 function ui_message_warning(s)
137 print([[<div class="messageblock messageblock-warning">
138 <div class="messageblock-internal">
139 <p>]]..s..[[
140 </p>
141 </div></div>]])
144 function ui_message_info(s)
145 print([[<div class="messageblock messageblock-info">
146 <div class="messageblock-internal">
147 <p>]]..s..[[
148 </p>
149 </div></div>]])
151 function ui_message_success(s)
152 local success = " ... <font color=green><strong>成功</strong></font><br>"
153 print(s..success)
156 function ui_redblue_img(red, blue)
157 wred = red*300/(red+blue)
158 wred = string.format("%d", wred)
159 wblue = 300 - wred
160 return "<img src=images/red.gif width="..wred.." height=10><img src=images/blue.gif width="..wblue.." height=10>"
161 -- return [[<img width="1" hspace="0" height="8" border="0" alt="disk usage" src="images/backgrounds/bar-start.gif"/><img width="]] ..wred.. [[" hspace="0" height="8" border="0" alt="disk usage" src="images/backgrounds/bar-active-2-2.gif"/><img width="8" hspace="0" height="]] ..wblue.. [[" border="0" alt="disk usage" src="images/backgrounds/bar-inactive.gif"/><img width="1" hspace="0" height="8" border="0" alt="score" src="images/backgrounds/bar-stop.gif"/>]]
164 function ui_myexec(cmd)
165 local _s, _r
166 _s, _r= myexec(cmd)
167 if _r ~= 0 then ui_message_err(_s) return nil end
168 return _s
171 function ui_getqp()
172 local _tbl = {}
173 local _t = myexec("set")
174 string.gsub(_t, "(.-)=(.-)\n", function(n,v)
175 n=tostring(n)
176 if(string.sub(n,1,2) == "F_") then _tbl[string.sub(n,3,-1)] = v end
177 end)
178 return _tbl
181 -----------------------------------------------------------------------------
183 -- Network utility
185 -----------------------------------------------------------------------------
187 -----------------------------------------------------------------------------
188 -- LVM and Raid utility
189 -----------------------------------------------------------------------------
191 -- return a table {["vgname"]}.{["size"], ["pvs"]}
192 function get_vg()
193 local lvm = {}
195 local fstr = myexec("sudo /sbin/vgdisplay")
196 for str in string.gmatch(fstr, "(---%s*Volume group.-\n)%s*\n") do
197 string.gsub(str, "VG%s*Name%s*(%S+).-VG%s*Size%s*(.-)\n.-Total%s+PE%s+(%d+)\n", function(v, s, pe)
198 lvm[v] = {["size"] = s, ["pvs"] = "", ["totalpe"] = pe}
199 end)
201 fstr = myexec("sudo /sbin/pvdisplay")
202 string.gsub(fstr, "PV%s+Name%s+(%S+)\n.-VG%s+Name%s+(%S+)\n", function(p,v)
203 lvm[v]["pvs"] = lvm[v].pvs.." "..p
204 end)
207 return lvm
210 function is_vg_exist(vgname)
211 local vg = get_vg()
212 for k,v in pairs(vg) do
213 if k==vgname then return true end
215 return nil
218 function get_lv()
219 t = myexec("/bin/df /mnt")
220 local lvtbl = nil
221 string.gsub(t, "(%S+)%s*(%S+)%s*(%S+)%s*(%S+)%s*(%S+)%s*/mnt", function(p,t,u,a,c)
222 lvtbl = {["fs"] = p,
223 ["total"] = t,
224 ["used"] = u,
225 ["free"] = a,
226 ["percentage"] =c }
227 end)
228 if lvtbl then return lvtbl else return nil end
231 function display_lv()
232 local lv = get_lv()
233 if not lv then print("something wrong: no logic volume") return end
235 print([[
236 <div class="sysinfo">
237 <table class="box">
238 <tr class="boxheader">
239 <td class="boxheader">共享信息</td>
240 </tr>
241 <tr class="boxbody">
242 <td class="boxbody">
243 <table border="0" width="100%" align="center">
245 print([[<tr valign="top"><td><strong>共享卷使用</strong></td><td>]]
246 ..ui_redblue_img(lv.used,lv.free)..
247 "( 已使用"..size2hum(lv.used..'k').." / 共"..size2hum(lv.total..'k')..")<strong> 空闲 "..size2hum(lv.free..'k').."</strong></td></tr>")
248 print("</table></td></tr></table>")
251 -- return table {["md"]}.{"active", "level", "devices", "size", "err"}
252 function get_mdstat()
253 local fstr = myexec("cat /proc/mdstat")
254 local mdstat = {}
255 for str in string.gmatch(fstr, "(md%d%s*:.-\n)%s*\n") do
256 local _tbl
257 string.gsub(str, "(md%d+)%s*:%s*(%S+)%s*(%S+)%s*(.-)\n%s*(%d+)%s*blocks%s*(.-)\n", function(m,a,l,d,s,e)
258 mdstat["/dev/"..m] = {["active"]=a,
259 ["level"] = l,
260 ["devices"] =d,
261 ["size"] = s,
262 ["err"] = e}
263 end)
264 string.gsub(str,"(md%d+)%s*:.-resync%s*=%s*([0-9%.]+).*$", function(m, y)
265 mdstat["/dev/"..m]["resync"] = y
266 end)
270 for k,v in pairs(mdstat) do
271 mdstat[k]["size"] = size2hum(mdstat[k]["size"].."k")
272 mdstat[k]["devices"] = string.gsub(mdstat[k]["devices"], "(%S+)%[.-%]", "/dev/%1")
274 return mdstat
277 -- return table: {["device"] = ["filesystem"]}
278 function get_mtab()
279 local fstr = myexec("cat /etc/mtab")
280 local mtab = {}
281 string.gsub(fstr, "(/dev/%S+)%s+(/%S*)", function(d,f)
282 mtab[d] = f
283 end)
284 return mtab
287 -- return table {["device"] }. {["size"],["vendor"],["model"]}
288 function _get_physical_disks()
289 local fstr = myexec("sudo /sbin/fdisk -l")
291 local disktbl = {}
292 string.gsub(fstr, "Disk%s+(/dev/%S+):%s+(.-),", function(d, s)
293 disktbl[d] = {["size"] = s}
294 local istr = myexec("sudo /usr/bin/sginfo "..d)
295 string.gsub(istr, "Vendor:%s*(%S.-)\nProduct:%s+(%S.-)\n", function(v,p)
296 disktbl[d]["vendor"] = v
297 disktbl[d]["model"] = p
298 end)
299 end)
300 return disktbl
304 -- return table {["device"] }. {["size"],["vendor"],["model"], ["used"]}
305 function _get_block_devices(mtab, vg, raid, ttype)
306 local disks = _get_physical_disks()
307 for d in pairs(mtab) do
308 local d1=string.match(d, "(%S+)%d")
309 if d1 then
310 for d2 in pairs(disks) do
311 if d1 == d2 then disks[d1]["used"] = "fs" end
315 for m in pairs(raid) do
316 for d1 in string.gmatch(raid[m].devices, "(%S+)%d") do
317 if d1 then
318 for d2 in pairs(disks) do
319 if d1 == d2 then disks[d1]["used"] = "raid" end
325 for v in pairs(vg) do
326 for d1 in string.gmatch(vg[v].pvs, "(%S+)%d") do
327 if d1 then
328 for d2 in pairs(disks) do
329 if d1 == d2 then disks[d1]["used"] = "lvm" end
335 if ttype == "b" then
336 for m in pairs(raid) do
337 disks[m] = {
338 ["size"] = raid[m].size,
339 ["devices"] = raid[m].devices,
340 ["model"] = raid[m].level
342 for v in pairs(vg) do
343 for d1 in string.gmatch(vg[v].pvs, "(%S+%d+)") do
344 if d1 == m then disks[m]["used"] = "lvm" end
349 return disks
352 -- return physical disks table {["device"] }. {["size"],["vendor"],["model"], ["used"]}
353 function get_disks()
354 local mtab = get_mtab()
355 local vg = get_vg()
356 local raid = get_mdstat()
357 return _get_block_devices(mtab, vg, raid, "d")
361 -- return block device table {["device"] }. {["size"],["vendor"],["model"], ["used"]}
362 function get_block_devices()
363 local mtab = get_mtab()
364 local vg = get_vg()
365 local raid = get_mdstat()
366 return _get_block_devices(mtab, vg, raid, "b")
369 -- parted a disk to 2 partitions: 1.swap and 2.xfs, then mount swap,write to fstab
370 function do_disk(disk)
371 local success = "<font color=green><strong>成功</strong></font><br>"
372 local fstr = myexec("sudo /usr/sbin/parted "..disk.." p")
373 local disksize = string.match(fstr, "\nDisk%s+"..disk..":%s+(%S+)\n")
374 print("<br>disksize: "..disksize)
375 if not disksize then ui_message_err("Not get disk size") return end
376 local cmd = {
377 ["label"] = "sudo /usr/sbin/parted -s "..disk.." mklabel msdos",
378 ["swap"] = "sudo /usr/sbin/parted -s "..disk.." mkpart primary linux-swap 0 512",
379 ["xfs"] = "sudo /usr/sbin/parted -s "..disk.." mkpart primary xfs 512 "..disksize
381 local err,ret
382 local conf = disk.."1\tswap\tswap\tdefaults\t0\t0\n"
384 print("<br>正在为磁盘 "..disk.."分区")
385 myexec("sudo /sbin/swapoff "..disk.."1")
386 err, ret = myexec(cmd.label)
387 if ret ~= 0 then ui_message_err(err) return nil end
388 err, ret = myexec(cmd.swap)
389 if ret ~= 0 then ui_message_err(err) return nil end
390 err, ret = myexec(cmd.xfs)
391 if ret ~= 0 then ui_message_err(err) return nil else print(success) end
393 file_gsub("/etc/fstab", "\n"..disk.."1.-\n", "\n")
394 err, ret = mywrite("/etc/fstab", myread("/etc/fstab")..conf)
395 myexec("sudo /sbin/mkswap "..disk.."1 && sudo /sbin/swapon "..disk.."1")
396 return true
400 -- @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
401 -- ############## SAMBA Utilities #################
402 -- @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
403 smbshare = {}
404 smbshare.config = "/etc/samba/smb.conf"
405 smbshare.version = "# Generated by smbshare util.\n# Author: kang, 2008-09-26\n# e-mail: kkmm99@gmail.com\n"
407 -- return a table from smb.conf: {share,} = {name = value,}
408 function smbshare.get()
409 local t = myread(smbshare.config)
410 t = string.gsub(t, "\n%s*#[^\n]+", "\n")
411 t = string.gsub(t, "\n%s*;[^\n]+", "\n")
412 t = string.gsub(t, "\n+", "\n") --remove multi lines to one line
413 t = string.gsub(t, "%[", "\n%[") -- make an tag "\n\n" at every end of a share
414 t = string.gsub(t, "$", "\n\n"); -- make sure there is a tag at end of file
416 tb={}
417 string.gsub(t, "%[(.-)%]%s*\n(.-\n)\n", function(sh, p)
418 tb[sh] = {}
419 string.gsub(p, "%s*(.-)%s*=%s*(.-)%s*\n", function(n,v)
420 tb[sh][n] = v
421 end)
422 end)
423 return tb
426 -- write the table to smb.conf
427 function smbshare.put(tb)
428 smbconf = smbshare.version.."[global]\n"
429 for n, v in pairs(tb.global) do
430 smbconf = smbconf.."\t"..n.." = "..v.."\n"
433 for s,k in pairs(tb) do
434 if s ~= "global" then
435 smbconf = smbconf.."["..s.."]\n"
436 for n, v in pairs(tb[s]) do
437 smbconf = smbconf.."\t"..n.." = "..v.."\n"
441 mywrite(smbshare.config, smbconf)
444 -- return a template share table
445 function smbshare.new()
446 return {["path"] = "/tmp",
447 ["comment"] = "no comment",
448 ["writable"] = yes,
449 ["create mask"] = 666,
450 ["directory mask"] = 777,
451 ["readlist"] = "",
452 ["writelist"] = ""
456 -- ADD or set a share, and write to smb.conf
457 function smbshare.set(share, path, readlist, writelist, comment)
458 local conftable = smbshare.get()
459 local tb = smbshare.new()
461 tb["path"] = path
462 tb["readlist"] = ","..readlist
463 tb["writelist"] = ","..writelist
464 tb["comment"] = comment
465 conftable[share] = tb
466 smbshare.put(conftable)
469 -- REMOVE a share from smb.conf
470 function smbshare.remove(share)
471 local conftable = smbshare.get()
472 local t = {}
473 for s, v in pairs(conftable) do
474 if s ~= share then t[s] = v end
476 smbshare.put(t)
479 -- return a local user table: {user,} = {uid,gid,comment,home,shell}
480 function get_local_user()
481 local fstr = myread("/etc/passwd")
482 local tbl = {}
483 string.gsub(fstr, "[%^\n](%S+):%S+:(%d+):(%d+):(.-):(%S+):([^\n]+)",
484 function(u,uid,gid,c,h,s)
485 if tonumber(uid) >= 1000 then
486 tbl[u] = {["uid"] = uid, ["gid"] = gid, ["comment"] = c, ["home"] = h, ["shell"] = s }
488 end)
489 return tbl
491 -- return a samba user table: {user = uid, }
492 function get_samba_user()
493 local fstr = myexec("sudo /bin/cat /etc/samba/private/smbpasswd")
494 local tbl = {}
495 string.gsub(fstr, "([%w_]+):(%d+)[^\n]+", function(u,uid) tbl[u] = uid end)
496 return tbl
498 -- smbshare.set("a new share", "/root/seconf", "nouser", "nogroup", "ok, comment")
499 -- smbshare.remove("a new share")
501 -- vim:ts=3 ss=3 sw=3 expandtab