[ UP ] cgi
[archserver.git] / cgi / libutil.lua
blobf2f6f07cf12a880a5865d6a19c7202bc88063241
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 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
89 end
91 -- do string.gsub on a file instead of on a string
92 function file_gsub(file, s, g)
93 local _f = assert(io.open(file, "r"))
94 local _t = _f:read("*all")
95 _t = string.gsub(_t, s, g)
96 _f:close()
98 local _tn = os.tmpname()
99 local _tf = assert(io.open(_tn, "w"))
100 _tf:write(_t)
101 _tf:close()
103 assert(0 == os.execute("sudo cp ".._tn.." "..file), "[Error] - ".."cp ".._tn.." "..file)
104 os.execute("rm ".._tn)
107 -- message box
108 function message_err(s)
109 print([[<div class="messageblock messageblock-error">
110 <div class="messageblock-internal">
111 <p><ul><strong>出现了下面的错误</strong><li>]]..s..[[
112 </li><ul></p>
113 </div></div>]])
116 function ui_message_err(s)
117 print([[<div class="messageblock messageblock-error">
118 <div class="messageblock-internal">
119 <p><ul><strong>出现了下面的错误</strong><li>]]..s..[[
120 </li><ul></p>
121 </div></div>]])
124 function ui_message_warning(s)
125 print([[<div class="messageblock messageblock-warning">
126 <div class="messageblock-internal">
127 <p>]]..s..[[
128 </p>
129 </div></div>]])
132 function ui_message_info(s)
133 print([[<div class="messageblock messageblock-info">
134 <div class="messageblock-internal">
135 <p>]]..s..[[
136 </p>
137 </div></div>]])
139 function ui_message_success(s)
140 local success = " ... <font color=green><strong>成功</strong></font><br>"
141 print(s..success)
144 function ui_redblue_img(red, blue)
145 wred = red*300/(red+blue)
146 wred = string.format("%d", wred)
147 wblue = 300 - wred
148 return "<img src=images/red.gif width="..wred.." height=10><img src=images/blue.gif width="..wblue.." height=10>"
151 function ui_myexec(cmd)
152 local _s, _r
153 _s, _r= myexec(cmd)
154 if _r ~= 0 then ui_message_err(_s) return nil end
155 return _s
157 -------------------- CGI utility --------------------------------
158 function ui_getqp()
159 local _tbl = {}
160 local _t = myexec("set")
161 string.gsub(_t, "(.-)=(.-)\n", function(n,v)
162 n=tostring(n)
163 if(string.sub(n,1,2) == "F_") then _tbl[string.sub(n,3,-1)] = v end
164 end)
165 return _tbl
168 -------------------------- Network utility -------------------
170 --------------------- LVM and Raid utility ------------------
172 -- return a table {["vgname"]}.{["size"], ["pvs"]}
173 function get_vg()
174 local lvm = {}
176 local fstr = myexec("sudo vgdisplay")
177 for str in string.gmatch(fstr, "(---%s*Volume group.-\n)%s*\n") do
178 string.gsub(str, "VG%s*Name%s*(%S+).-VG%s*Size%s*(.-)\n.-Total%s+PE%s+(%d+)\n", function(v, s, pe)
179 lvm[v] = {["size"] = s, ["pvs"] = "", ["totalpe"] = pe}
180 end)
182 fstr = myexec("sudo pvdisplay")
183 string.gsub(fstr, "PV%s+Name%s+(%S+)\n.-VG%s+Name%s+(%S+)\n", function(p,v)
184 lvm[v]["pvs"] = lvm[v].pvs.." "..p
185 end)
188 return lvm
191 function is_vg_exist(vgname)
192 local vg = get_vg()
193 for k,v in pairs(vg) do
194 if k==vgname then return true end
196 return nil
199 function get_lv()
200 t = myexec("/bin/df /mnt")
201 local lvtbl = nil
202 string.gsub(t, "(%S+)%s*(%S+)%s*(%S+)%s*(%S+)%s*(%S+)%s*/mnt", function(p,t,u,a,c)
203 lvtbl = {["fs"] = p,
204 ["total"] = t,
205 ["used"] = u,
206 ["free"] = a,
207 ["percentage"] =c }
208 end)
209 if lvtbl then return lvtbl else return nil end
212 function display_lv()
213 local lv = get_lv()
214 if not lv then print("something wrong: no logic volume") return end
216 print([[
217 <div class="sysinfo">
218 <table class="box">
219 <tr class="boxheader">
220 <td class="boxheader">共享信息</td>
221 </tr>
222 <tr class="boxbody">
223 <td class="boxbody">
224 <table border="0" width="100%" align="center">
226 print([[<tr valign="top"><td><strong>共享卷使用</strong></td><td>]]
227 ..ui_redblue_img(lv.used,lv.free)..
228 "( 已使用"..size2hum(lv.used..'k').." / 共"..size2hum(lv.total..'k')..")<strong> 空闲 "..size2hum(lv.free..'k').."</strong></td></tr>")
229 print("</table></td></tr></table>")
232 -- return table {["md"]}.{"active", "level", "devices", "size", "err"}
233 function get_mdstat()
234 local fstr = myexec("cat /proc/mdstat")
235 local mdstat = {}
236 for str in string.gmatch(fstr, "(md%d%s*:.-\n)%s*\n") do
237 local _tbl
238 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)
239 mdstat["/dev/"..m] = {["active"]=a,
240 ["level"] = l,
241 ["devices"] =d,
242 ["size"] = s,
243 ["err"] = e}
244 end)
245 string.gsub(str,"(md%d+)%s*:.-resync%s*=%s*([0-9%.]+).*$", function(m, y)
246 mdstat["/dev/"..m]["resync"] = y
247 end)
251 for k,v in pairs(mdstat) do
252 mdstat[k]["size"] = size2hum(mdstat[k]["size"].."k")
253 mdstat[k]["devices"] = string.gsub(mdstat[k]["devices"], "(%S+)%[.-%]", "/dev/%1")
255 return mdstat
258 -- return table: {["device"] = ["filesystem"]}
259 function get_mtab()
260 local fstr = myexec("cat /etc/mtab")
261 local mtab = {}
262 string.gsub(fstr, "(/dev/%S+)%s+(/%S*)", function(d,f)
263 mtab[d] = f
264 end)
265 return mtab
268 -- return table {["device"] }. {["size"],["vendor"],["model"]}
269 function _get_physical_disks()
270 local fstr = myexec("sudo fdisk -l")
272 local disktbl = {}
273 string.gsub(fstr, "Disk%s+(/dev/%S+):%s+(.-),", function(d, s)
274 disktbl[d] = {["size"] = s}
275 local istr = myexec("sudo /usr/bin/sginfo "..d)
276 string.gsub(istr, "Vendor:%s*(%S.-)\nProduct:%s+(%S.-)\n", function(v,p)
277 disktbl[d]["vendor"] = v
278 disktbl[d]["model"] = p
279 end)
280 end)
281 return disktbl
285 -- return table {["device"] }. {["size"],["vendor"],["model"], ["used"]}
286 function _get_block_devices(mtab, vg, raid, ttype)
287 local disks = _get_physical_disks()
288 for d in pairs(mtab) do
289 local d1=string.match(d, "(%S+)%d")
290 if d1 then
291 for d2 in pairs(disks) do
292 if d1 == d2 then disks[d1]["used"] = "fs" end
296 for m in pairs(raid) do
297 for d1 in string.gmatch(raid[m].devices, "(%S+)%d") do
298 if d1 then
299 for d2 in pairs(disks) do
300 if d1 == d2 then disks[d1]["used"] = "raid" end
306 for v in pairs(vg) do
307 for d1 in string.gmatch(vg[v].pvs, "(%S+)%d") do
308 if d1 then
309 for d2 in pairs(disks) do
310 if d1 == d2 then disks[d1]["used"] = "lvm" end
316 if ttype == "b" then
317 for m in pairs(raid) do
318 disks[m] = {
319 ["size"] = raid[m].size,
320 ["devices"] = raid[m].devices,
321 ["model"] = raid[m].level
323 for v in pairs(vg) do
324 for d1 in string.gmatch(vg[v].pvs, "(%S+%d+)") do
325 if d1 == m then disks[m]["used"] = "lvm" end
330 return disks
333 -- return physical disks table {["device"] }. {["size"],["vendor"],["model"], ["used"]}
334 function get_disks()
335 local mtab = get_mtab()
336 local vg = get_vg()
337 local raid = get_mdstat()
338 return _get_block_devices(mtab, vg, raid, "d")
342 -- return block device table {["device"] }. {["size"],["vendor"],["model"], ["used"]}
343 function get_block_devices()
344 local mtab = get_mtab()
345 local vg = get_vg()
346 local raid = get_mdstat()
347 return _get_block_devices(mtab, vg, raid, "b")
350 -- parted a disk to 2 partitions: 1.swap and 2.xfs, then mount swap,write to fstab
351 function do_disk(disk)
352 local success = "<font color=green><strong>成功</strong></font><br>"
353 local fstr = myexec("sudo parted "..disk.." p")
354 local disksize = string.match(fstr, "\nDisk%s+"..disk..":%s+(%S+)\n")
355 print("<br>disksize: "..disksize)
356 if not disksize then ui_message_err("Not get disk size") return end
357 local cmd = {
358 ["label"] = "sudo parted -s "..disk.." mklabel msdos",
359 ["swap"] = "sudo parted -s "..disk.." mkpart primary linux-swap 0 512",
360 ["xfs"] = "sudo parted -s "..disk.." mkpart primary xfs 512 "..disksize
362 local err,ret
363 local conf = disk.."1\tswap\tswap\tdefaults\t0\t0\n"
365 print("<br>正在为磁盘 "..disk.."分区")
366 myexec("sudo swapoff "..disk.."1")
367 err, ret = myexec(cmd.label)
368 if ret ~= 0 then ui_message_err(err) return nil end
369 err, ret = myexec(cmd.swap)
370 if ret ~= 0 then ui_message_err(err) return nil end
371 err, ret = myexec(cmd.xfs)
372 if ret ~= 0 then ui_message_err(err) return nil else print(success) end
374 file_gsub("/etc/fstab", "\n"..disk.."1.-\n", "\n")
375 err, ret = mywrite("/etc/fstab", myread("/etc/fstab")..conf)
376 myexec("sudo mkswap "..disk.."1 && sudo swapon "..disk.."1")
377 return true
381 -- @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
382 -- ############## SAMBA Utilities #################
383 -- @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
384 smbshare = {}
385 smbshare.config = "/etc/samba/smb.conf"
386 smbshare.version = "# Generated by smbshare util.\n# Author: kang, 2008-09-26\n# e-mail: kkmm99@gmail.com\n"
388 -- return a table from smb.conf: {share,} = {name = value,}
389 function smbshare.get()
390 local t = myread(smbshare.config)
391 t = string.gsub(t, "\n%s*#[^\n]+", "\n")
392 t = string.gsub(t, "\n%s*;[^\n]+", "\n")
393 t = string.gsub(t, "\n+", "\n") --remove multi lines to one line
394 t = string.gsub(t, "%[", "\n%[") -- make an tag "\n\n" at every end of a share
395 t = string.gsub(t, "$", "\n\n"); -- make sure there is a tag at end of file
397 tb={}
398 string.gsub(t, "%[(.-)%]%s*\n(.-\n)\n", function(sh, p)
399 tb[sh] = {}
400 string.gsub(p, "%s*(.-)%s*=%s*(.-)%s*\n", function(n,v)
401 tb[sh][n] = v
402 end)
403 end)
404 return tb
407 -- write the table to smb.conf
408 function smbshare.put(tb)
409 smbconf = smbshare.version.."[global]\n"
410 for n, v in pairs(tb.global) do
411 smbconf = smbconf.."\t"..n.." = "..v.."\n"
414 for s,k in pairs(tb) do
415 if s ~= "global" then
416 smbconf = smbconf.."["..s.."]\n"
417 for n, v in pairs(tb[s]) do
418 smbconf = smbconf.."\t"..n.." = "..v.."\n"
422 mywrite(smbshare.config, smbconf)
425 -- return a template share table
426 function smbshare.new()
427 return {["path"] = "/tmp",
428 ["comment"] = "no comment",
429 ["writable"] = yes,
430 ["create mask"] = 666,
431 ["directory mask"] = 777,
432 ["readlist"] = "",
433 ["writelist"] = ""
437 -- ADD or set a share, and write to smb.conf
438 function smbshare.set(share, path, readlist, writelist, comment)
439 local conftable = smbshare.get()
440 local tb = smbshare.new()
442 tb["path"] = path
443 tb["readlist"] = ","..readlist
444 tb["writelist"] = ","..writelist
445 tb["comment"] = comment
446 conftable[share] = tb
447 smbshare.put(conftable)
450 -- REMOVE a share from smb.conf
451 function smbshare.remove(share)
452 local conftable = smbshare.get()
453 local t = {}
454 for s, v in pairs(conftable) do
455 if s ~= share then t[s] = v end
457 smbshare.put(t)
460 -- return a local user table: {user,} = {uid,gid,comment,home,shell}
461 function get_local_user()
462 local fstr = myread("/etc/passwd")
463 local tbl = {}
464 string.gsub(fstr, "[%^\n](%S+):%S+:(%d+):(%d+):(.-):(%S+):([^\n]+)",
465 function(u,uid,gid,c,h,s)
466 if tonumber(uid) >= 1000 then
467 tbl[u] = {["uid"] = uid, ["gid"] = gid, ["comment"] = c, ["home"] = h, ["shell"] = s }
469 end)
470 return tbl
472 -- return a samba user table: {user = uid, }
473 function get_samba_user()
474 local fstr = myexec("sudo cat /etc/samba/private/smbpasswd")
475 local tbl = {}
476 string.gsub(fstr, "([%w_]+):(%d+)[^\n]+", function(u,uid) tbl[u] = uid end)
477 return tbl
479 -- smbshare.set("a new share", "/root/seconf", "nouser", "nogroup", "ok, comment")
480 -- smbshare.remove("a new share")