1#!@PYTHON@
2
3# Copyright (C) 2016 Jakub Kruszona-Zawadzki, Core Technology Sp. z o.o.
4#
5# This file is part of MooseFS.
6#
7# MooseFS is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, version 2 (only).
10#
11# MooseFS is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with MooseFS; if not, write to the Free Software
18# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA
19# or visit http://www.gnu.org/licenses/gpl-2.0.html
20
21PROTO_BASE = @PROTO_BASE@
22
23#some constants from MFSCommunication.h
24CLTOMA_CSERV_LIST = (PROTO_BASE+500)
25MATOCL_CSERV_LIST = (PROTO_BASE+501)
26CLTOCS_HDD_LIST_V1 = (PROTO_BASE+502)
27CSTOCL_HDD_LIST_V1 = (PROTO_BASE+503)
28CLTOMA_SESSION_LIST = (PROTO_BASE+508)
29MATOCL_SESSION_LIST = (PROTO_BASE+509)
30CLTOMA_INFO = (PROTO_BASE+510)
31MATOCL_INFO = (PROTO_BASE+511)
32CLTOMA_FSTEST_INFO = (PROTO_BASE+512)
33MATOCL_FSTEST_INFO = (PROTO_BASE+513)
34CLTOMA_CHUNKSTEST_INFO = (PROTO_BASE+514)
35MATOCL_CHUNKSTEST_INFO = (PROTO_BASE+515)
36CLTOMA_CHUNKS_MATRIX = (PROTO_BASE+516)
37MATOCL_CHUNKS_MATRIX = (PROTO_BASE+517)
38CLTOMA_QUOTA_INFO = (PROTO_BASE+518)
39MATOCL_QUOTA_INFO = (PROTO_BASE+519)
40CLTOMA_EXPORTS_INFO = (PROTO_BASE+520)
41MATOCL_EXPORTS_INFO = (PROTO_BASE+521)
42CLTOMA_MLOG_LIST = (PROTO_BASE+522)
43MATOCL_MLOG_LIST = (PROTO_BASE+523)
44CLTOMA_CSSERV_COMMAND = (PROTO_BASE+524)
45MATOCL_CSSERV_COMMAND = (PROTO_BASE+525)
46CLTOMA_SESSION_COMMAND = (PROTO_BASE+526)
47MATOCL_SESSION_COMMAND = (PROTO_BASE+527)
48CLTOMA_MEMORY_INFO = (PROTO_BASE+528)
49MATOCL_MEMORY_INFO = (PROTO_BASE+529)
50CLTOMA_MASS_RESOLVE_PATHS = (PROTO_BASE+536)
51MATOCL_MASS_RESOLVE_PATHS = (PROTO_BASE+537)
52CLTOMA_MISSING_CHUNKS = (PROTO_BASE+544)
53MATOCL_MISSING_CHUNKS = (PROTO_BASE+545)
54
55CLTOCS_HDD_LIST_V2 = (PROTO_BASE+600)
56CSTOCL_HDD_LIST_V2 = (PROTO_BASE+601)
57
58MFS_MESSAGE = 1
59
60MFS_CSSERV_COMMAND_REMOVE = 0
61MFS_CSSERV_COMMAND_BACKTOWORK = 1
62MFS_CSSERV_COMMAND_MAINTENANCEON = 2
63MFS_CSSERV_COMMAND_MAINTENANCEOFF = 3
64
65MFS_SESSION_COMMAND_REMOVE = 0
66
67STATUS_OK = 0
68ERROR_NOTFOUND = 41
69ERROR_ACTIVE = 42
70
71STATE_DUMMY = 0
72STATE_LEADER = 1
73STATE_ELECT = 2
74STATE_FOLLOWER = 3
75STATE_USURPER = 4
76
77UNRESOLVED = "(unresolved)"
78
79import socket
80import struct
81import time
82import sys
83import traceback
84import os
85import subprocess
86
87cgimode = 1 if 'GATEWAY_INTERFACE' in os.environ else 0
88
89try:
90	xrange
91except NameError:
92	xrange = range
93
94#parse parameters and auxilinary functions
95if cgimode:
96	try:
97		import urllib.parse as xurllib
98	except ImportError:
99		import urllib as xurllib
100	import cgi
101	import cgitb
102
103	cgitb.enable()
104
105	fields = cgi.FieldStorage()
106
107	try:
108		if "masterhost" in fields:
109			masterhost = fields.getvalue("masterhost")
110		else:
111			masterhost = '@DEFAULT_MASTERNAME@'
112	except Exception:
113		masterhost = '@DEFAULT_MASTERNAME@'
114	try:
115		masterport = int(fields.getvalue("masterport"))
116	except Exception:
117		masterport = @DEFAULT_MASTER_CLIENT_PORT@
118	try:
119		mastercontrolport = int(fields.getvalue("mastercontrolport"))
120	except Exception:
121		try:
122			mastercontrolport = int(fields.getvalue("masterport"))-2
123		except Exception:
124			mastercontrolport = @DEFAULT_MASTER_CONTROL_PORT@
125	try:
126		if "mastername" in fields:
127			mastername = fields.getvalue("mastername")
128		else:
129			mastername = 'MooseFS'
130	except Exception:
131		mastername = 'MooseFS'
132
133#	thsep = ''
134#	html_thsep = ''
135
136	def htmlentities(str):
137		return str.replace('&','&amp;').replace('<','&lt;').replace('>','&gt;').replace("'",'&apos;').replace('"','&quot;')
138
139	def urlescape(str):
140		return xurllib.quote_plus(str)
141
142	def resolve(strip):
143		global UNRESOLVED
144		try:
145			return (socket.gethostbyaddr(strip))[0]
146		except Exception:
147			return UNRESOLVED
148
149	def createlink(update):
150		global fields,urlescape
151		c = []
152		for k in fields:
153			if k not in update:
154				c.append("%s=%s" % (k,urlescape(fields.getvalue(k))))
155		for k,v in update.items():
156			if v!="":
157				c.append("%s=%s" % (k,urlescape(v)))
158		return "mfs.cgi?%s" % ("&amp;".join(c))
159
160	def createorderlink(prefix,columnid):
161		global fields,createlink
162		ordername = "%sorder" % prefix
163		revname = "%srev" % prefix
164		try:
165			orderval = int(fields.getvalue(ordername))
166		except Exception:
167			orderval = 0
168		try:
169			revval = int(fields.getvalue(revname))
170		except Exception:
171			revval = 0
172		return createlink({revname:"1"}) if orderval==columnid and revval==0 else createlink({ordername:str(columnid),revname:"0"})
173
174	def createinputs(ignorefields):
175		for k in fields:
176			if k not in ignorefields:
177				yield """<input type="hidden" name="%s" value="%s">""" % (k,htmlentities(fields.getvalue(k)))
178		return
179
180else: # CLI mode
181	import getopt
182
183	masterhost = '@DEFAULT_MASTERNAME@'
184	masterport = @DEFAULT_MASTER_CLIENT_PORT@
185	mastercontrolport = @DEFAULT_MASTER_CONTROL_PORT@
186	mastername = 'MooseFS'
187	frameset = -1
188	plaintextseparator = "\t"
189	forceplaintext = 0
190	colormode = 0
191	donotresolve = 0
192	sectionset = []
193	sectionsubset = []
194	clicommands = []
195
196# order and data parameters
197	IMorder = 0
198	IMrev = 0
199	MForder = 0
200	MFrev = 0
201	CSorder = 0
202	CSrev = 0
203	MBorder = 0
204	MBrev = 0
205	HDorder = 0
206	HDrev = 0
207	HDperiod = 0
208	HDtime = 0
209	HDaddrname = 1
210	EXorder = 0
211	EXrev = 0
212	MSorder = 0
213	MSrev = 0
214	MOorder = 0
215	MOrev = 0
216	MOdata = 0
217	QUorder = 0
218	QUrev = 0
219	INmatrix = 0
220
221	lastsval = ''
222	lastorder = None
223	lastrev = 0
224	lastmode = None
225	try:
226		opts,args = getopt.getopt(sys.argv[1:],"hH:P:S:C:f:ps:no:rm:28")
227	except:
228		opts = [('-h',None)]
229	for opt,val in opts:
230		if opt=='-h':
231			print("usage:")
232			print("\t%s [-hpn28] [-H master_host] [-P master_port] [-f 0..3] -S(IN|IM|LI|IG|MU|IC|IL|MF|CS|MB|HD|EX|MS|MO|QU) [-o order_id [-r]] [-m mode_id]" % sys.argv[0])
233			print("\t%s [-hpn28] [-H master_host] [-P master_port] [-f 0..3] -C(RC/ip/port|BW/ip/port)" % sys.argv[0])
234			print("\ncommon:\n")
235			print("\t-h : print this message")
236			print("\t-p : force plain text format on tty devices")
237			print("\t-s separator : field separator to use in plain text format on tty devices (forces -p)")
238			print("\t-2 : force 256-color terminal color codes")
239			print("\t-8 : force 8-color terminal color codes")
240			print("\t-H master_host : master address (default: @DEFAULT_MASTERNAME@)")
241			print("\t-P master_port : master client port (default: @DEFAULT_MASTER_CLIENT_PORT@)")
242			print("\t-n : do not resolve ip adresses (default when output device is not tty)")
243			print("\t-f frame charset number : set frame charset to be displayed as table frames in ttymode")
244			print("\t\t-f0 : use simple ascii frames '+','-','|' (default for non utf-8 encodings)")
245			if sys.stdout.encoding=='UTF-8':
246				if sys.version_info[0]<3:
247					print("\t\t-f1 : use utf-8 frames: \xe2\x94\x8f\xe2\x94\xb3\xe2\x94\x93\xe2\x94\xa3\xe2\x95\x8b\xe2\x94\xab\xe2\x94\x97\xe2\x94\xbb\xe2\x94\x9b\xe2\x94\x81\xe2\x94\x83\xe2\x95\xb8\xe2\x95\xb9\xe2\x95\xba\xe2\x95\xbb")
248					print("\t\t-f2 : use utf-8 frames: \xe2\x94\x8c\xe2\x94\xac\xe2\x94\x90\xe2\x94\x9c\xe2\x94\xbc\xe2\x94\xa4\xe2\x94\x94\xe2\x94\xb4\xe2\x94\x98\xe2\x94\x80\xe2\x94\x82\xe2\x95\xb4\xe2\x95\xb5\xe2\x95\xb6\xe2\x95\xb7")
249					print("\t\t-f3 : use utf-8 frames: \xe2\x95\x94\xe2\x95\xa6\xe2\x95\x97\xe2\x95\xa0\xe2\x95\xac\xe2\x95\xa3\xe2\x95\x9a\xe2\x95\xa9\xe2\x95\x9d\xe2\x95\x90\xe2\x95\x91 (default for utf-8 encodings)")
250				else:
251					print("\t\t-f1 : use utf-8 frames: \u250f\u2533\u2513\u2523\u254b\u252b\u2517\u253b\u251b\u2501\u2503\u2578\u2579\u257a\u257b")
252					print("\t\t-f2 : use utf-8 frames: \u250c\u252c\u2510\u251c\u253c\u2524\u2514\u2534\u2518\u2500\u2502\u2574\u2575\u2576\u2577")
253					print("\t\t-f3 : use utf-8 frames: \u2554\u2566\u2557\u2560\u256c\u2563\u255a\u2569\u255d\u2550\u2551 (default for utf-8 encodings)")
254			else:
255				print("\t\t-f1 : use utf-8 frames (thick single)")
256				print("\t\t-f2 : use utf-8 frames (thin single)")
257				print("\t\t-f3 : use utf-8 frames (double - default for utf-8 encodings)")
258			print("\nmonitoring:\n")
259			print("\t-S data set : defines data set to be displayed")
260			print("\t\t-SIN : show full master info")
261			print("\t\t-SIM : show only masters states")
262			print("\t\t-SLI : show only licence info")
263			print("\t\t-SIG : show only general master (leader) info")
264			print("\t\t-SMU : show only master memory usage")
265			print("\t\t-SIC : show only chunks info (goal/copies matrices)")
266			print("\t\t-SIL : show only loop info (with messages)")
267			print("\t\t-SMF : show only missing chunks/files")
268			print("\t\t-SCS : show connected chunk servers")
269			print("\t\t-SMB : show connected metadata backup servers")
270			print("\t\t-SHD : show hdd data")
271			print("\t\t-SEX : show exports")
272			print("\t\t-SMS : show active mounts")
273			print("\t\t-SMO : show operation counters")
274			print("\t\t-SQU : show quota info")
275			print("\t-o order_id : sort data by column specified by 'order id' (depends on data set)")
276			print("\t-r : reverse order")
277			print("\t-m mode_id : show data specified by 'mode id' (depends on data set)")
278			print("\ncommands:\n")
279			print("\t-C command : perform particular command")
280			print("\t\t-CRC/ip/port : remove given chunkserver from list of active chunkservers")
281			print("\t\t-CBW/ip/port : send given chunkserver back to work (from grace state)")
282			print("\t\t-CM1/ip/port : switch given chunkserver to maintenance mode")
283			print("\t\t-CM0/ip/port : switch given chunkserver to standard mode (from maintenance mode)")
284			print("\t\t-CRS/sessionid : remove given session")
285			os._exit(0)
286		elif opt=='-2':
287			colormode = 2
288		elif opt=='-8':
289			colormode = 1
290		elif opt=='-p':
291			forceplaintext = 1
292		elif opt=='-s':
293			plaintextseparator = val
294			forceplaintext = 1
295		elif opt=='-n':
296			donotresolve = 1
297		elif opt=='-f':
298			frameset = int(val)
299		elif opt=='-H':
300			masterhost = val
301		elif opt=='-P':
302			masterport = int(val)
303		elif opt=='-S':
304			lastsval = val
305			if 'IN' in val:
306				sectionset.append("IN")
307				sectionsubset.append("IM")
308				sectionsubset.append("LI")
309				sectionsubset.append("IG")
310				sectionsubset.append("MU")
311				sectionsubset.append("IC")
312				sectionsubset.append("IL")
313				sectionsubset.append("MF")
314				if lastmode!=None:
315					INmatrix = lastmode
316				if lastorder!=None:
317					IMorder = lastorder
318				if lastrev:
319					IMrev = 1
320			if 'IM' in val:
321				sectionset.append("IN")
322				sectionsubset.append("IM")
323				if lastorder!=None:
324					IMorder = lastorder
325				if lastrev:
326					IMrev = 1
327			if 'LI' in val:
328				sectionset.append("IN")
329				sectionsubset.append("LI")
330			if 'IG' in val:
331				sectionset.append("IN")
332				sectionsubset.append("IG")
333			if 'MU' in val:
334				sectionset.append("IN")
335				sectionsubset.append("MU")
336			if 'IC' in val:
337				sectionset.append("IN")
338				sectionsubset.append("IC")
339				if lastmode!=None:
340					INmatrix = lastmode
341			if 'IL' in val:
342				sectionset.append("IN")
343				sectionsubset.append("IL")
344			if 'MF' in val:
345				sectionset.append("IN")
346				sectionsubset.append("MF")
347				if lastorder!=None:
348					MForder = lastorder
349				if lastrev:
350					MFrev = 1
351			if 'CS' in val:
352				sectionset.append("CS")
353				sectionsubset.append("CS")
354				if lastorder!=None:
355					CSorder = lastorder
356				if lastrev:
357					CSrev = 1
358			if 'MB' in val:
359				sectionset.append("CS")
360				sectionsubset.append("MB")
361				if lastorder!=None:
362					MBorder = lastorder
363				if lastrev:
364					MBrev = 1
365			if 'HD' in val:
366				sectionset.append("HD")
367				if lastorder!=None:
368					HDorder = lastorder
369				if lastrev:
370					HDrev = 1
371				if lastmode!=None:
372					if lastmode>=0 and lastmode<6:
373						HDperiod,HDtime = divmod(lastmode,2)
374			if 'EX' in val:
375				sectionset.append("EX")
376				if lastorder!=None:
377					EXorder = lastorder
378				if lastrev:
379					EXrev = 1
380			if 'MS' in val:
381				sectionset.append("MS")
382				if lastorder!=None:
383					MSorder = lastorder
384				if lastrev:
385					MSrev = 1
386			if 'MO' in val:
387				sectionset.append("MO")
388				if lastorder!=None:
389					MOorder = lastorder
390				if lastrev:
391					MOrev = 1
392				if lastmode!=None:
393					MOdata = lastmode
394			if 'QU' in val:
395				sectionset.append("QU")
396				if lastorder!=None:
397					QUorder = lastorder
398				if lastrev:
399					QUrev = 1
400			lastorder = None
401			lastrev = 0
402			lastmode = None
403		elif opt=='-o':
404			if 'IM' in lastsval:
405				IMorder = int(val)
406			if 'MF' in lastsval:
407				MForder = int(val)
408			if 'CS' in lastsval:
409				CSorder = int(val)
410			if 'MB' in lastsval:
411				MBorder = int(val)
412			if 'HD' in lastsval:
413				HDorder = int(val)
414			if 'EX' in lastsval:
415				EXorder = int(val)
416			if 'MS' in lastsval:
417				MSorder = int(val)
418			if 'MO' in lastsval:
419				MOorder = int(val)
420			if 'QU' in lastsval:
421				QUorder = int(val)
422			if lastsval=='':
423				lastorder = int(val)
424		elif opt=='-r':
425			if 'IM' in lastsval:
426				IMrev = 1
427			if 'MF' in lastsval:
428				MFrev = 1
429			if 'CS' in lastsval:
430				CSrev = 1
431			if 'MB' in lastsval:
432				MBrev = 1
433			if 'HD' in lastsval:
434				HDrev = 1
435			if 'EX' in lastsval:
436				EXrev = 1
437			if 'MS' in lastsval:
438				MSrev = 1
439			if 'MO' in lastsval:
440				MOrev = 1
441			if 'QU' in lastsval:
442				QUrev = 1
443			if lastsval=='':
444				lastrev = 1
445		elif opt=='-m':
446			if 'HD' in lastsval:
447				d = int(val)
448				if d>=0 and d<6:
449					HDperiod,HDtime = divmod(d,2)
450			if 'MO' in lastsval:
451				MOdata = int(val)
452			if 'IN' in lastsval or 'IC' in lastsval:
453				INmatrix = int(val)
454			if lastsval=='':
455				lastmode = int(val)
456		elif opt=='-C':
457			clicommands.append(val)
458
459	if sectionset==[] and clicommands==[]:
460		print("Specify data to be shown (option -S) or command (option -C). Use '-h' for help.")
461		os._exit(0)
462
463	ttymode = 1 if forceplaintext==0 and os.isatty(1) else 0
464	if ttymode:
465		try:
466			import curses
467			curses.setupterm()
468			if curses.tigetnum("colors")>=256:
469				colors256 = 1
470			else:
471				colors256 = 0
472		except Exception:
473			colors256 = 1 if 'TERM' in os.environ and '256color' in os.environ['TERM'] else 0
474		# colors: 0 - white,1 - red,2 - orange,3 - yellow,4 - green,5 - cyan,6 - blue,7 - violet,8 - gray
475		CSI="\x1B["
476		if colors256:
477			ttyreset=CSI+"0m"
478			colorcode=[CSI+"38;5;196m",CSI+"38;5;208m",CSI+"38;5;226m",CSI+"38;5;34m",CSI+"38;5;30m",CSI+"38;5;19m",CSI+"38;5;55m",CSI+"38;5;244m"]
479		else:
480			ttysetred=CSI+"31m"
481			ttysetyellow=CSI+"33m"
482			ttysetgreen=CSI+"32m"
483			ttysetcyan=CSI+"36m"
484			ttysetblue=CSI+"34m"
485			ttysetmagenta=CSI+"35m"
486			ttyreset=CSI+"0m"
487			# no orange - use red, no gray - use white
488			colorcode=[ttysetred,ttysetred,ttysetyellow,ttysetgreen,ttysetcyan,ttysetblue,ttysetmagenta,""]
489	else:
490		colorcode=["","","","","","","",""]
491
492	if ttymode and sys.stdout.encoding=='UTF-8':
493		if frameset>=0 and frameset<=3:
494			tabbleframes=frameset
495		else:
496			tabbleframes=0
497	else:
498		tabbleframes=0
499
500	# frames:
501	#  +-----+-----+-----+-----+
502	#  |     |     |     |     |
503	#  |     |     |     |  |  |
504	#  |  +- | -+- | -+  |  +- |
505	#  |  |  |  |  |  |  |  |  |
506	#  |     |     |     |     |
507	#  +-----+-----+-----+-----+
508	#  |     |     |     |     |
509	#  |  |  |  |  |  |  |  |  |
510	#  | -+- | -+  |  +- | -+- |
511	#  |  |  |  |  |     |     |
512	#  |     |     |     |     |
513	#  +-----+-----+-----+-----+
514	#  |     |     |     |     |
515	#  |  |  |     |  |  |     |
516	#  | -+  | -+- |  +  | -+  |
517	#  |     |     |  |  |     |
518	#  |     |     |     |     |
519	#  +-----+-----+-----+-----+
520	#  |     |     |     |     |
521	#  |  |  |     |     |     |
522	#  |  +  |  +- |  +  |  +  |
523	#  |     |     |  |  |     |
524	#  |     |     |     |     |
525	#  +-----+-----+-----+-----+
526	#
527
528	class Tabble:
529		def __init__(self,title,ccnt,defattr=""):
530			if tabbleframes==1:
531				if sys.version_info[0]<3:
532					self.frames = ['\xe2\x94\x8f', '\xe2\x94\xb3', '\xe2\x94\x93', '\xe2\x94\xa3', '\xe2\x95\x8b', '\xe2\x94\xab', '\xe2\x94\x97', '\xe2\x94\xbb', '\xe2\x94\x9b', '\xe2\x94\x81', '\xe2\x94\x83', '\xe2\x95\xb8', '\xe2\x95\xb9', '\xe2\x95\xba', '\xe2\x95\xbb', ' ']
533				else:
534					self.frames = ['\u250f', '\u2533', '\u2513', '\u2523', '\u254b', '\u252b', '\u2517', '\u253b', '\u251b', '\u2501', '\u2503', '\u2578', '\u2579', '\u257a', '\u257b', ' ']
535			elif tabbleframes==2:
536				if sys.version_info[0]<3:
537					self.frames = ['\xe2\x94\x8c', '\xe2\x94\xac', '\xe2\x94\x90', '\xe2\x94\x9c', '\xe2\x94\xbc', '\xe2\x94\xa4', '\xe2\x94\x94', '\xe2\x94\xb4', '\xe2\x94\x98', '\xe2\x94\x80', '\xe2\x94\x82', '\xe2\x95\xb4', '\xe2\x95\xb5', '\xe2\x95\xb6', '\xe2\x95\xb7', ' ']
538				else:
539					self.frames = ['\u250c', '\u252c', '\u2510', '\u251c', '\u253c', '\u2524', '\u2514', '\u2534', '\u2518', '\u2500', '\u2502', '\u2574', '\u2575', '\u2576', '\u2577', ' ']
540			elif tabbleframes==3:
541				if sys.version_info[0]<3:
542					self.frames = ['\xe2\x95\x94', '\xe2\x95\xa6', '\xe2\x95\x97', '\xe2\x95\xa0', '\xe2\x95\xac', '\xe2\x95\xa3', '\xe2\x95\x9a', '\xe2\x95\xa9', '\xe2\x95\x9d', '\xe2\x95\x90', '\xe2\x95\x91', ' ', '\xe2\x95\x91', ' ', '\xe2\x95\x91', ' ']
543				else:
544					self.frames = ['\u2554', '\u2566', '\u2557', '\u2560', '\u256c', '\u2563', '\u255a', '\u2569', '\u255d', '\u2550', '\u2551', ' ', '\u2551', ' ', '\u2551', ' ']
545			else:
546				self.frames = ['+','+','+','+','+','+','+','+','+','-','|',' ','|',' ','|',' ']
547			self.title = title
548			self.ccnt = ccnt
549			self.head = []
550			self.body = []
551			self.defattrs = []
552			self.cwidth = []
553			for i in range(ccnt):
554				self.defattrs.append(defattr)
555				self.cwidth.append(0)
556		def combineattr(self,attr,defattr):
557			attrcolor = ""
558			for c in ("0","1","2","3","4","5","6","7","8"):
559				if c in defattr:
560					attrcolor = c
561			for c in ("0","1","2","3","4","5","6","7","8"):
562				if c in attr:
563					attrcolor = c
564			attrjust = ""
565			for c in ("l","L","r","R","c","C"):
566				if c in defattr:
567					attrjust = c
568			for c in ("l","L","r","R","c","C"):
569				if c in attr:
570					attrjust = c
571			return attrcolor+attrjust
572		def header(self,*rowdata):
573			ccnt = 0
574			for celldata in rowdata:
575				if type(celldata)==tuple:
576					if len(celldata)==3:
577						ccnt+=celldata[2]
578					else:
579						if celldata[0]!=None:
580							cstr = str(celldata[0])
581							if len(cstr) > self.cwidth[ccnt]:
582								self.cwidth[ccnt] = len(cstr)
583						ccnt+=1
584				else:
585					if celldata!=None:
586						cstr = str(celldata)
587						if len(cstr) > self.cwidth[ccnt]:
588							self.cwidth[ccnt] = len(cstr)
589					ccnt+=1
590			if ccnt != self.ccnt:
591				raise IndexError
592			self.head.append(rowdata)
593		def defattr(self,*rowdata):
594			if len(rowdata) != self.ccnt:
595				raise IndexError
596			self.defattrs = rowdata
597		def append(self,*rowdata):
598			ccnt = 0
599			rdata = []
600			for celldata in rowdata:
601				if type(celldata)==tuple:
602					if celldata[0]!=None:
603						cstr = str(celldata[0])
604					else:
605						cstr = ""
606					if len(celldata)==3:
607						rdata.append((cstr,self.combineattr(celldata[1],self.defattrs[ccnt]),celldata[2]))
608						ccnt+=celldata[2]
609					else:
610						if len(cstr) > self.cwidth[ccnt]:
611							self.cwidth[ccnt] = len(cstr)
612						if len(celldata)==2:
613							rdata.append((cstr,self.combineattr(celldata[1],self.defattrs[ccnt])))
614						else:
615							rdata.append((cstr,self.defattrs[ccnt]))
616						ccnt+=1
617				else:
618					if celldata!=None:
619						cstr = str(celldata)
620						if len(cstr) > self.cwidth[ccnt]:
621							self.cwidth[ccnt] = len(cstr)
622						rdata.append((cstr,self.defattrs[ccnt]))
623					else:
624						rdata.append(celldata)
625					ccnt+=1
626			if ccnt != self.ccnt:
627				raise IndexError
628			self.body.append(rdata)
629		def attrdata(self,cstr,cattr,cwidth):
630			retstr = ""
631			if "1" in cattr:
632				retstr += colorcode[0]
633				needreset = 1
634			elif "2" in cattr:
635				retstr += colorcode[1]
636				needreset = 1
637			elif "3" in cattr:
638				retstr += colorcode[2]
639				needreset = 1
640			elif "4" in cattr:
641				retstr += colorcode[3]
642				needreset = 1
643			elif "5" in cattr:
644				retstr += colorcode[4]
645				needreset = 1
646			elif "6" in cattr:
647				retstr += colorcode[5]
648				needreset = 1
649			elif "7" in cattr:
650				retstr += colorcode[6]
651				needreset = 1
652			elif "8" in cattr:
653				retstr += colorcode[7]
654				needreset = 1
655			else:
656				needreset = 0
657			if cstr=="--":
658				retstr += " "+"-"*cwidth+" "
659			elif cstr=="---":
660				retstr += "-"*(cwidth+2)
661			elif "L" in cattr or "l" in cattr:
662				retstr += " "+cstr.ljust(cwidth)+" "
663			elif "R" in cattr or "r" in cattr:
664				retstr += " "+cstr.rjust(cwidth)+" "
665			else:
666				retstr += " "+cstr.center(cwidth)+" "
667			if needreset:
668				retstr += ttyreset
669			return retstr
670		def lines(self):
671			outstrtab = []
672			if ttymode:
673				tabdata = []
674				# upper frame
675				tabdata.append((("---","",self.ccnt),))
676				# title
677				tabdata.append(((self.title,"",self.ccnt),))
678				# header
679				if len(self.head)>0:
680					tabdata.append((("---","",self.ccnt),))
681					tabdata.extend(self.head)
682				# head and data separator
683				tabdata.append((("---","",self.ccnt),))
684				# data
685				if len(self.body)==0:
686					tabdata.append((("no data","",self.ccnt),))
687				else:
688					tabdata.extend(self.body)
689				# bottom frame
690				tabdata.append((("---","",self.ccnt),))
691				# check col-spaned headers and adjust column widths if necessary
692				for rowdata in tabdata:
693					ccnt = 0
694					for celldata in rowdata:
695						if type(celldata)==tuple and len(celldata)==3 and celldata[0]!=None:
696							cstr = str(celldata[0])
697							clen = len(cstr)
698							cwidth = sum(self.cwidth[ccnt:ccnt+celldata[2]])+3*(celldata[2]-1)
699							if clen > cwidth:
700								add = clen - cwidth
701								adddm = divmod(add,celldata[2])
702								cadd = adddm[0]
703								if adddm[1]>0:
704									cadd+=1
705								for i in range(celldata[2]):
706									self.cwidth[ccnt+i] += cadd
707							ccnt += celldata[2]
708						else:
709							ccnt += 1
710				separators = []
711				# before tab - no separators
712				seplist = []
713				for i in range(self.ccnt+1):
714					seplist.append(0)
715				separators.append(seplist)
716				for rowdata in tabdata:
717					seplist = [1]
718					for celldata in rowdata:
719						if type(celldata)==tuple and len(celldata)==3:
720							for i in range(celldata[2]-1):
721								seplist.append(1 if celldata[0]=='---' else 0)
722						seplist.append(1)
723					separators.append(seplist)
724				# after tab - no separators
725				seplist = []
726				for i in range(self.ccnt+1):
727					seplist.append(0)
728				separators.append(seplist)
729				# add upper and lower separators:
730				updownsep = [[a*2 + b for (a,b) in zip(x,y)] for (x,y) in zip(separators[2:],separators[:-2])]
731				# create tabble
732				for (rowdata,sepdata) in zip(tabdata,updownsep):
733	#				print rowdata,sepdata
734					ccnt = 0
735					line = ""
736					nsep = 0 #self.frames[10]
737					for celldata in rowdata:
738						cpos = ccnt
739						cattr = ""
740						if type(celldata)==tuple:
741							if celldata[1]!=None:
742								cattr = celldata[1]
743							if len(celldata)==3:
744								cwidth = sum(self.cwidth[ccnt:ccnt+celldata[2]])+3*(celldata[2]-1)
745								ccnt+=celldata[2]
746							else:
747								cwidth = self.cwidth[ccnt]
748								ccnt+=1
749							cstr = celldata[0]
750						else:
751							cstr = celldata
752							cwidth = self.cwidth[ccnt]
753							ccnt+=1
754						if cstr==None:
755							cstr = ""
756						if type(cstr)!=str:
757							cstr = str(cstr)
758						if cstr=="---":
759							if nsep==0:
760								line += self.frames[(13,6,0,3)[sepdata[cpos]]]
761								#line += self.frames[(15,6,0,3)[sepdata[cpos]]]
762							else:
763								line += self.frames[(9,7,1,4)[sepdata[cpos]]]
764							nsep = 1 #self.frames[4]
765							for ci in range(cpos,ccnt-1):
766								line += self.frames[9]*(self.cwidth[ci]+2)
767								line += self.frames[(9,7,1,4)[sepdata[ci+1]]]
768							line += self.frames[9]*(self.cwidth[ccnt-1]+2)
769						else:
770							if nsep==0:
771								line += self.frames[(15,12,14,10)[sepdata[cpos]]]
772								#line += self.frames[(15,10,10,10)[sepdata[cpos]]]
773							else:
774								line += self.frames[(11,8,2,5)[sepdata[cpos]]]
775								#line += self.frames[(15,8,2,5)[sepdata[cpos]]]
776							nsep = 0
777							line += self.attrdata(cstr,cattr,cwidth)
778					if nsep==0:
779						line += self.frames[(15,12,14,10)[sepdata[ccnt]]]
780						#line += self.frames[(15,10,10,10)[sepdata[ccnt]]]
781					else:
782						line += self.frames[(11,8,2,5)[sepdata[ccnt]]]
783						#line += self.frames[(15,8,2,5)[sepdata[ccnt]]]
784					outstrtab.append(line)
785			else:
786				for rowdata in self.body:
787					row = []
788					for celldata in rowdata:
789						if type(celldata)==tuple:
790							cstr = str(celldata[0])
791						elif celldata!=None:
792							cstr = str(celldata)
793						else:
794							cstr = ""
795						row.append(cstr)
796					outstrtab.append("%s:%s%s" % (self.title,plaintextseparator,plaintextseparator.join(row)))
797			return outstrtab
798		def __str__(self):
799			return "\n".join(self.lines())
800
801	#x = Tabble("Test title",4)
802	#x.header("column1","column2","column3","column4")
803	#x.append("t1","t2","very long entry","test")
804	#x.append(("r","r3"),("l","l2"),"also long entry","test")
805	#print x
806	#
807	#x = Tabble("Very long tabble title",2)
808	#x.defattr("l","r")
809	#x.append("key","value")
810	#x.append("other key",123)
811	#y = []
812	#y.append(("first","1"))
813	#y.append(("second","4"))
814	#x.append(*y)
815	#print x
816	#
817	#x = Tabble("Tabble with complicated header",15,"r")
818	#x.header(("","",4),("I/O stats last min","",8),("","",3))
819	#x.header(("info","",4),("---","",8),("space","",3))
820	#x.header(("","",4),("transfer","",2),("max time","",3),("# of ops","",3),("","",3))
821	#x.header(("---","",15))
822	#x.header("IP path","chunks","last error","status","read","write","read","write","fsync","read","write","fsync","used","total","used %")
823	#x.append("192.168.1.102:9422:/mnt/hd4/",66908,"no errors","ok","19 MiB/s","27 MiB/s","263625 us","43116 us","262545 us",3837,3295,401,"1.0 TiB","1.3 TiB","76.41%")
824	#x.append("192.168.1.102:9422:/mnt/hd5/",67469,"no errors","ok","25 MiB/s","29 MiB/s","340303 us","89168 us","223610 us",2487,2593,366,"1.0 TiB","1.3 TiB","75.93%")
825	#x.append("192.168.1.111:9422:/mnt/hd5/",109345,("2012-10-12 07:27","2"),("damaged","1"),"-","-","-","-","-","-","-","-","1.2 TiB","1.3 TiB","87.18%")
826	#x.append("192.168.1.211:9422:/mnt/hd5/",49128,"no errors",("marked for removal","4"),"-","-","-","-","-","-","-","-","501 GiB","1.3 TiB","36.46%")
827	##x.append("192.168.1.111:9422:/mnt/hd5/",109345,("2012-10-12 07:27","2"),("damaged","1"),("","-",8),"1.2 TiB","1.3 TiB","87.18%")
828	##x.append("192.168.1.211:9422:/mnt/hd5/",49128,"no errors",("marked for removal","4"),("","-",8),"501 GiB","1.3 TiB","36.46%")
829	#x.append("192.168.1.229:9422:/mnt/hd10/","67969","no errors","ok","17 MiB/s","11 MiB/s","417292 us","76333 us","1171903 us","2299","2730","149","1.0 TiB","1.3 TiB","76.61%")
830	#print x
831	#
832	#x = Tabble("Colors",1,"r")
833	#x.append(("white","0"))
834	#x.append(("red","1"))
835	#x.append(("orange","2"))
836	#x.append(("yellow","3"))
837	#x.append(("green","4"))
838	#x.append(("cyan","5"))
839	#x.append(("blue","6"))
840	#x.append(("magenta","7"))
841	#x.append(("gray","8"))
842	#print x
843	#
844	#x = Tabble("Adjustments",1)
845	#x.append(("left","l"))
846	#x.append(("right","r"))
847	#x.append(("center","c"))
848	#print x
849	#
850	#x = Tabble("Special entries",3)
851	#x.defattr("l","r","r")
852	#x.header("entry","effect","extra column")
853	#x.append("-- ","--","")
854	#x.append("--- ","---","")
855	#x.append("('--','',2)",('--','',2))
856	#x.append("('','',2)",('','',2))
857	#x.append("('---','',2)",('---','',2))
858	#x.append("('red','1')",('red','1'),'')
859	#x.append("('orange','2')",('orange','2'),'')
860	#x.append("('yellow','3')",('yellow','3'),'')
861	#x.append("('green','4')",('green','4'),'')
862	#x.append("('cyan','5')",('cyan','5'),'')
863	#x.append("('blue','6')",('blue','6'),'')
864	#x.append("('magenta','7')",('magenta','7'),'')
865	#x.append("('gray','8')",('gray','8'),'')
866	#x.append(('---','',3))
867	#x.append("('left','l',2)",('left','l',2))
868	#x.append("('right','r',2)",('right','r',2))
869	#x.append("('center','c',2)",('center','c',2))
870	#print x
871
872	def resolve(strip):
873		if donotresolve:
874			return strip
875		try:
876			return (socket.gethostbyaddr(strip))[0]
877		except Exception:
878			return strip
879
880
881
882
883
884
885# common auxilinary functions
886
887def getmasteraddresses():
888	m = []
889	try:
890		for i in socket.getaddrinfo(masterhost,masterport,socket.AF_INET,socket.SOCK_STREAM,socket.SOL_TCP):
891			if i[0]==socket.AF_INET and i[1]==socket.SOCK_STREAM and i[2]==socket.SOL_TCP:
892				m.append(i[4])
893	except Exception:
894		pass
895	return m
896
897#def mysend(socket,msg):
898#	totalsent = 0
899#	while totalsent < len(msg):
900#		sent = socket.send(msg[totalsent:])
901#		if sent == 0:
902#			raise RuntimeError("socket connection broken")
903#		totalsent = totalsent + sent
904
905#def myrecv(socket,leng):
906#	if sys.version_info[0]<3:
907#		msg = ''
908#	else:
909#		msg = bytes(0)
910#	while len(msg) < leng:
911#		chunk = socket.recv(leng-len(msg))
912#		if len(chunk) == 0:
913#			raise RuntimeError("socket connection broken")
914#		msg = msg + chunk
915#	return msg
916
917def state_name(stateid):
918	if stateid==STATE_DUMMY:
919		return "DUMMY"
920	elif stateid==STATE_USURPER:
921		return "USURPER"
922	elif stateid==STATE_FOLLOWER:
923		return "FOLLOWER"
924	elif stateid==STATE_ELECT:
925		return "ELECT"
926	elif stateid==STATE_LEADER:
927		return "LEADER"
928	else:
929		return "???"
930
931def state_color(stateid,sync):
932	if stateid==STATE_DUMMY:
933		return 8
934	elif stateid==STATE_FOLLOWER or stateid==STATE_USURPER:
935		if sync:
936			return 5
937		else:
938			return 6
939	elif stateid==STATE_ELECT:
940		return 3
941	elif stateid==STATE_LEADER:
942		return 4
943	else:
944		return 1
945
946def decimal_number(number,sep=' '):
947	parts = []
948	while number>=1000:
949		number,rest = divmod(number,1000)
950		parts.append("%03u" % rest)
951	parts.append(str(number))
952	parts.reverse()
953	return sep.join(parts)
954
955def humanize_number(number,sep='',suff='B'):
956	number*=100
957	scale=0
958	while number>=99950:
959		number = number//1024
960		scale+=1
961	if number<995 and scale>0:
962		b = (number+5)//10
963		nstr = "%u.%u" % divmod(b,10)
964	else:
965		b = (number+50)//100
966		nstr = "%u" % b
967	if scale>0:
968		return "%s%s%si%s" % (nstr,sep,"-KMGTPEZY"[scale],suff)
969	else:
970		return "%s%s%s" % (nstr,sep,suff)
971
972def timeduration_to_shortstr(timeduration):
973	for l,s in ((86400,'d'),(3600,'h'),(60,'m'),(0,'s')):
974		if timeduration>=l:
975			if l>0:
976				n = float(timeduration)/float(l)
977			else:
978				n = float(timeduration)
979			rn = round(n,1)
980			if n==round(n,0):
981				return "%.0f%s" % (n,s)
982			else:
983				return "%s%.1f%s" % (("~" if n!=rn else ""),rn,s)
984	return "???"
985
986def timeduration_to_fullstr(timeduration):
987	if timeduration>=86400:
988		days,dayseconds = divmod(timeduration,86400)
989		daysstr = "%u day%s, " % (days,("s" if days!=1 else ""))
990	else:
991		dayseconds = timeduration
992		daysstr = ""
993	hours,hourseconds = divmod(dayseconds,3600)
994	minutes,seconds = divmod(hourseconds,60)
995	if seconds==round(seconds,0):
996		return "%u second%s (%s%u:%02u:%02u)" % (timeduration,("" if timeduration==1 else "s"),daysstr,hours,minutes,seconds)
997	else:
998		seconds,fracsec = divmod(seconds,1)
999		return "%.3f seconds (%s%u:%02u:%02u.%03u)" % (timeduration,daysstr,hours,minutes,seconds,round(1000*fracsec,0))
1000
1001def print_exception():
1002	exc_type, exc_value, exc_traceback = sys.exc_info()
1003	global cgimode,ttymode
1004	try:
1005		if cgimode:
1006			print("""<table class="FR" cellspacing="0">""")
1007			print("""<tr><td align="left"><pre>""")
1008			print(traceback.format_exc().strip())
1009			print("""</pre></td></tr>""")
1010			print("""</table>""")
1011		elif ttymode:
1012			tab = Tabble("Exception Traceback",4)
1013			tab.header("file","line","in","text")
1014			tab.defattr("l","r","l","l")
1015			for d in traceback.extract_tb(exc_traceback):
1016				tab.append(d[0],d[1],d[2],repr(d[3]))
1017			tab.append(("---","",4))
1018			tab.append(("Error","c",4))
1019			tab.append(("---","",4))
1020			for d in traceback.format_exception_only(exc_type, exc_value):
1021				tab.append((repr(d.strip()),"",4))
1022			print("%s%s%s" % (colorcode[1],tab,ttyreset))
1023		else:
1024			print("""---------------------------------------------------------------- error -----------------------------------------------------------------""")
1025			print(traceback.format_exc().strip())
1026			print("""----------------------------------------------------------------------------------------------------------------------------------------""")
1027	except:
1028		print(traceback.format_exc().strip())
1029
1030def version_convert(version):
1031	if version>=(2,0,0):
1032		return ((version[0],version[1],version[2]//2),version[2]&1)
1033	elif version>=(1,7,0):
1034		return (version,1)
1035	elif version>(0,0,0):
1036		return (version,0)
1037	else:
1038		return (version,-1)
1039
1040def version_str_and_sort(version):
1041	version,pro = version_convert(version)
1042	strver = "%u.%u.%u" % version
1043	sortver = "%05u_%03u_%03u" % version
1044	if pro==1:
1045		strver += " PRO"
1046		sortver += "_2"
1047	elif pro==0:
1048		sortver += "_1"
1049	else:
1050		sortver += "_0"
1051	return (strver,sortver)
1052
1053class MFSConn:
1054	def __init__(self,host,port):
1055		self.host = host
1056		self.port = port
1057		self.socket = None
1058		self.connect()
1059	def __del__(self):
1060		try:
1061			if self.socket:
1062				self.socket.close()
1063#				print "connection closed with: %s:%u" % (self.host,self.port)
1064			self.socket = None
1065		except AttributeError:
1066			pass
1067	def connect(self):
1068		cnt = 0
1069		while self.socket == None and cnt<3:
1070			self.socket = socket.socket()
1071			self.socket.settimeout(1)
1072			try:
1073				self.socket.connect((self.host,self.port))
1074			except Exception:
1075				self.socket.close()
1076				self.socket = None
1077				cnt += 1
1078		if self.socket==None:
1079			self.socket = socket.socket()
1080			self.socket.settimeout(1)
1081			self.socket.connect((self.host,self.port))
1082#		else:
1083#			print "connected to: %s:%u" % (self.host,self.port)
1084	def close(self):
1085		if self.socket:
1086			self.socket.close()
1087			self.socket = None
1088	def mysend(self,msg):
1089		if self.socket == None:
1090			self.connect()
1091		totalsent = 0
1092		while totalsent < len(msg):
1093			sent = self.socket.send(msg[totalsent:])
1094			if sent == 0:
1095				raise RuntimeError("socket connection broken")
1096			totalsent = totalsent + sent
1097	def myrecv(self,leng):
1098		if sys.version_info[0]<3:
1099			msg = ''
1100		else:
1101			msg = bytes(0)
1102		while len(msg) < leng:
1103			chunk = self.socket.recv(leng-len(msg))
1104			if len(chunk) == 0:
1105				raise RuntimeError("socket connection broken")
1106			msg = msg + chunk
1107		return msg
1108	def command(self,cmdout,cmdin,dataout=None):
1109		if dataout:
1110			l = len(dataout)
1111			msg = struct.pack(">LL",cmdout,l) + dataout
1112		else:
1113			msg = struct.pack(">LL",cmdout,0)
1114		cmdok = 0
1115		errcnt = 0
1116		while cmdok==0:
1117			try:
1118				self.mysend(msg)
1119				header = self.myrecv(8)
1120				cmd,length = struct.unpack(">LL",header)
1121				if cmd==cmdin:
1122					datain = self.myrecv(length)
1123					cmdok = 1
1124				else:
1125					raise RuntimeError("MFS communication error - bad answer")
1126			except Exception:
1127				if errcnt<3:
1128					self.close()
1129					self.connect()
1130					errcnt+=1
1131				else:
1132					raise RuntimeError("MFS communication error")
1133		return datain,length
1134
1135class Master(MFSConn):
1136	def __init__(self,host,port):
1137		MFSConn.__init__(self,host,port)
1138		self.version = (0,0,0)
1139		self.pro = -1
1140	def set_version(self,version):
1141		self.version,self.pro = version_convert(version)
1142	def version_at_least(self,v1,v2,v3):
1143		return (self.version>=(v1,v2,v3))
1144	def version_less_than(self,v1,v2,v3):
1145		return (self.version<(v1,v2,v3))
1146	def version_is(self,v1,v2,v3):
1147		return (self.version==(v1,v2,v3))
1148	def version_unknown(self):
1149		return (self.version==(0,0,0))
1150	def is_pro(self):
1151		return self.pro
1152	def sort_ver(self):
1153		sortver = "%05u_%03u_%03u" % self.version
1154		if self.pro==1:
1155			sortver += "_2"
1156		elif self.pro==0:
1157			sortver += "_1"
1158		else:
1159			sortver += "_0"
1160		return sortver
1161
1162
1163def resolve_inodes_paths(leaderconn,inodes):
1164	inodepaths = {}
1165	if len(inodes)>0:
1166		data,length = leaderconn.command(CLTOMA_MASS_RESOLVE_PATHS,MATOCL_MASS_RESOLVE_PATHS,struct.pack(">"+len(inodes)*"L",*inodes))
1167		pos = 0
1168		while pos+8<=length:
1169			inode,psize = struct.unpack(">LL",data[pos:pos+8])
1170			pos+=8
1171			if psize == 0:
1172				if inode not in inodepaths:
1173					inodepaths[inode] = []
1174				inodepaths[inode].append("./META")
1175			elif pos + psize <= length:
1176				while psize>=4:
1177					pleng = struct.unpack(">L",data[pos:pos+4])[0]
1178					pos+=4
1179					psize-=4
1180					path = data[pos:pos+pleng]
1181					pos+=pleng
1182					psize-=pleng
1183					if sys.version_info[0]>=3:
1184						try:
1185							path = path.decode('ascii')
1186						except UnicodeDecodeError:
1187							pass
1188					if inode not in inodepaths:
1189						inodepaths[inode] = []
1190					inodepaths[inode].append(path)
1191				if psize!=0:
1192					raise RuntimeError("MFS packet malformed")
1193		if pos!=length:
1194			raise RuntimeError("MFS packet malformed")
1195	return inodepaths
1196
1197
1198# find leader
1199leaderispro = 0
1200leaderfound = 0
1201followerfound = 0
1202electfound = 0
1203leaderconn = None
1204leaderinfo = None
1205masterlist = getmasteraddresses()
1206masterlistver = []
1207masterlistinfo = []
1208
1209for mhost,mport in masterlist:
1210	conn = None
1211	version = (0,0,0)
1212	statestr = "???"
1213	statecolor = 1
1214	memusage = 0
1215	syscpu = 0
1216	usercpu = 0
1217	lastsuccessfulstore = 0
1218	lastsaveseconds = 0
1219	lastsavestatus = 0
1220	metaversion = 0
1221	try:
1222		conn = Master(mhost,mport)
1223		try:
1224			data,length = conn.command(CLTOMA_INFO,MATOCL_INFO)
1225			if length==52:
1226				version = (1,4,0)
1227				conn.set_version(version)
1228				if leaderfound==0:
1229					leaderconn = conn
1230					leaderinfo = data
1231					leaderfound = 1
1232				statestr = "OLD MASTER (LEADER ONLY)"
1233				statecolor = 0
1234			elif length==60:
1235				version = (1,5,0)
1236				conn.set_version(version)
1237				if leaderfound==0:
1238					leaderconn = conn
1239					leaderinfo = data
1240					leaderfound = 1
1241				statestr = "OLD MASTER (LEADER ONLY)"
1242				statecolor = 0
1243			elif length==68 or length==76 or length==101:
1244				version = struct.unpack(">HBB",data[:4])
1245				conn.set_version(version)
1246				if leaderfound==0:
1247					leaderconn = conn
1248					leaderinfo = data
1249					leaderfound = 1
1250				if length==76:
1251					memusage = struct.unpack(">Q",data[4:12])[0]
1252				if length==101:
1253					memusage,syscpu,usercpu = struct.unpack(">QQQ",data[4:28])
1254					syscpu/=10000000.0
1255					usercpu/=10000000.0
1256					lastsuccessfulstore,lastsaveseconds,lastsavestatus = struct.unpack(">LLB",data[92:101])
1257				if version<(1,7,0):
1258					statestr = "OLD MASTER (LEADER ONLY)"
1259					statecolor = 0
1260				else:
1261					statestr = "UPGRADE THIS UNIT !!!"
1262					statecolor = 2
1263			elif length==121:
1264				version = struct.unpack(">HBB",data[:4])
1265				conn.set_version(version)
1266				memusage,syscpu,usercpu = struct.unpack(">QQQ",data[4:28])
1267				syscpu/=10000000.0
1268				usercpu/=10000000.0
1269				lastsuccessfulstore,lastsaveseconds,lastsavestatus = struct.unpack(">LLB",data[92:101])
1270				if conn.version_at_least(2,0,14):
1271					lastsaveseconds = lastsaveseconds / 1000.0
1272				workingstate,nextstate,stablestate,sync,leaderip,changetime,metaversion = struct.unpack(">BBBBLLQ",data[101:121])
1273				if workingstate==0xFF and nextstate==0xFF and stablestate==0xFF and sync==0xFF:
1274					if leaderfound==0:
1275						leaderconn = conn
1276						leaderinfo = data
1277						leaderfound = 1
1278					statestr = "-"
1279					statecolor = 0
1280				elif stablestate==0 or workingstate!=nextstate:
1281					statestr = "transition %s -> %s" % (state_name(workingstate),state_name(nextstate))
1282					statecolor = 8
1283				else:
1284					statestr = state_name(workingstate)
1285					statecolor = state_color(workingstate,sync)
1286					if workingstate==STATE_FOLLOWER or workingstate==STATE_USURPER:
1287						if sync==0:
1288							statestr += " (DESYNC)"
1289						followerfound = 1
1290					if workingstate==STATE_ELECT:
1291						electfound = 1
1292					if workingstate==STATE_LEADER and leaderfound==0:
1293						leaderispro = 1
1294						leaderconn = conn
1295						leaderinfo = data
1296						leaderfound = 1
1297		except Exception:
1298			statestr = "BUSY"
1299			statecolor = 7
1300	except Exception:
1301		statestr = "DEAD"
1302	try:
1303		iptab = tuple(map(int,mhost.split('.')))
1304		strip = "%u.%u.%u.%u" % iptab
1305		sortip = "%03u_%03u_%03u_%03u" % iptab
1306	except Exception:
1307		strip = mhost
1308		sortip = mhost
1309	strver,sortver = version_str_and_sort(version)
1310	if conn and conn!=leaderconn:
1311		del conn
1312	masterlistver.append((mhost,mport,version))
1313	masterlistinfo.append((sortip,strip,sortver,strver,statestr,statecolor,metaversion,memusage,syscpu,usercpu,lastsuccessfulstore,lastsaveseconds,lastsavestatus))
1314
1315if leaderfound and leaderconn.version_less_than(1,6,10):
1316	if cgimode:
1317		print("Content-Type: text/html; charset=UTF-8")
1318		print("")
1319		print("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">""")
1320		print("""<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">""")
1321		print("""<head>""")
1322		print("""<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />""")
1323		print("""<title>MFS Info (%s)</title>""" % (htmlentities(mastername)))
1324		print("""<link rel="stylesheet" href="mfs.css" type="text/css" />""")
1325		print("""</head>""")
1326		print("""<body>""")
1327		if leaderconn.version_unknown():
1328			print("""<h1 align="center">Can't detect MFS master version</h1>""")
1329		else:
1330			print("""<h1 align="center">MFS master version not supported (pre 1.6.10)</h1>""")
1331		print("""</body>""")
1332		print("""</html>""")
1333	else:
1334		if leaderconn.version_unknown():
1335			print("""Can't detect MFS master version""")
1336		else:
1337			print("""MFS master version not supported (pre 1.6.10)""")
1338	sys.exit(1)
1339
1340
1341
1342
1343# commands
1344if cgimode:
1345	# commands in CGI mode
1346	cmd_success = -1
1347	if "CSremove" in fields:
1348		cmd_success = 0
1349		tracedata = ""
1350		if leaderfound:
1351			try:
1352				serverdata = fields.getvalue("CSremove").split(":")
1353				if len(serverdata)==2:
1354					csip = list(map(int,serverdata[0].split(".")))
1355					csport = int(serverdata[1])
1356					if len(csip)==4:
1357						if leaderconn.version_less_than(1,6,28):
1358							data,length = leaderconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBH",csip[0],csip[1],csip[2],csip[3],csport))
1359							if length==0:
1360								cmd_success = 1
1361								status = 0
1362						else:
1363							data,length = leaderconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_REMOVE,csip[0],csip[1],csip[2],csip[3],csport))
1364							if length==1:
1365								status = (struct.unpack(">B",data))[0]
1366								cmd_success = 1
1367			except Exception:
1368				tracedata = traceback.format_exc()
1369		url = createlink({"CSremove":""})
1370	elif "CSbacktowork" in fields:
1371		cmd_success = 0
1372		tracedata = ""
1373		if leaderfound:
1374			try:
1375				serverdata = fields.getvalue("CSbacktowork").split(":")
1376				if len(serverdata)==2:
1377					csip = list(map(int,serverdata[0].split(".")))
1378					csport = int(serverdata[1])
1379					if len(csip)==4:
1380						if leaderconn.version_at_least(1,6,28):
1381							data,length = leaderconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_BACKTOWORK,csip[0],csip[1],csip[2],csip[3],csport))
1382							if length==1:
1383								status = (struct.unpack(">B",data))[0]
1384								cmd_success = 1
1385			except Exception:
1386				tracedata = traceback.format_exc()
1387		url = createlink({"CSbacktowork":""})
1388	elif "CSmaintenanceon" in fields:
1389		cmd_success = 0
1390		tracedata = ""
1391		if leaderfound:
1392			try:
1393				serverdata = fields.getvalue("CSmaintenanceon").split(":")
1394				if len(serverdata)==2:
1395					csip = list(map(int,serverdata[0].split(".")))
1396					csport = int(serverdata[1])
1397					if len(csip)==4:
1398						if leaderconn.version_at_least(2,0,11):
1399							data,length = leaderconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_MAINTENANCEON,csip[0],csip[1],csip[2],csip[3],csport))
1400							if length==1:
1401								status = (struct.unpack(">B",data))[0]
1402								cmd_success = 1
1403			except Exception:
1404				tracedata = traceback.format_exc()
1405		url = createlink({"CSmaintenanceon":""})
1406	elif "CSmaintenanceoff" in fields:
1407		cmd_success = 0
1408		tracedata = ""
1409		if leaderfound:
1410			try:
1411				serverdata = fields.getvalue("CSmaintenanceoff").split(":")
1412				if len(serverdata)==2:
1413					csip = list(map(int,serverdata[0].split(".")))
1414					csport = int(serverdata[1])
1415					if len(csip)==4:
1416						if leaderconn.version_at_least(2,0,11):
1417							data,length = leaderconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_MAINTENANCEOFF,csip[0],csip[1],csip[2],csip[3],csport))
1418							if length==1:
1419								status = (struct.unpack(">B",data))[0]
1420								cmd_success = 1
1421			except Exception:
1422				tracedata = traceback.format_exc()
1423		url = createlink({"CSmaintenanceoff":""})
1424	elif "MSremove" in fields:
1425		cmd_success = 0
1426		tracedata = ""
1427		if leaderfound:
1428			try:
1429				sessionid = int(fields.getvalue("MSremove"))
1430				data,length = leaderconn.command(CLTOMA_SESSION_COMMAND,MATOCL_SESSION_COMMAND,struct.pack(">BL",MFS_SESSION_COMMAND_REMOVE,sessionid))
1431				if length==1:
1432					status = (struct.unpack(">B",data))[0]
1433					cmd_success = 1
1434			except Exception:
1435				tracedata = traceback.format_exc()
1436		url = createlink({"MSremove":""})
1437	if cmd_success==1:
1438		print("Status: 302 Found")
1439		print("Location: %s" % url.replace("&amp;","&"))
1440		print("Content-Type: text/html; charset=UTF-8")
1441		print("")
1442		print("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">""")
1443		print("""<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">""")
1444		print("""<head>""")
1445		print("""<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />""")
1446		print("""<meta http-equiv="Refresh" content="0; url=%s" />""" % url)
1447		print("""<title>MFS Info (%s)</title>""" % (htmlentities(mastername)))
1448		print("""<link rel="stylesheet" href="mfs.css" type="text/css" />""")
1449		print("""</head>""")
1450		print("""<body>""")
1451		print("""<h1 align="center"><a href="%s">If you see this then it means that redirection didn't work, so click here</a></h1>""" % url)
1452		print("""</body>""")
1453		print("""</html>""")
1454		sys.exit(0)
1455	elif cmd_success==0:
1456		print("Content-Type: text/html; charset=UTF-8")
1457		print("")
1458		print("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">""")
1459		print("""<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">""")
1460		print("""<head>""")
1461		print("""<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />""")
1462		print("""<meta http-equiv="Refresh" content="5; url=%s" />""" % url)
1463		print("""<title>MFS Info (%s)</title>""" % (htmlentities(mastername)))
1464		print("""<link rel="stylesheet" href="mfs.css" type="text/css" />""")
1465		print("""</head>""")
1466		print("""<body>""")
1467		print("""<h3 align="center">Can't perform command - wait 5 seconds for refresh</h3>""")
1468		if tracedata:
1469			print("""<hr />""")
1470			print("""<pre>%s</pre>""" % tracedata)
1471		print("""</body>""")
1472		print("""</html>""")
1473		sys.exit(0)
1474else:
1475	if leaderfound:
1476		for cmd in clicommands:
1477			cmddata = cmd.split('/')
1478			if cmddata[0]=='RC':
1479				cmd_success = 0
1480				try:
1481					csip = list(map(int,cmddata[1].split(".")))
1482					csport = int(cmddata[2])
1483					if len(csip)==4:
1484						if leaderconn.version_less_than(1,6,28):
1485							data,length = leaderconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBH",csip[0],csip[1],csip[2],csip[3],csport))
1486							if length==0:
1487								cmd_success = 1
1488								status = 0
1489						else:
1490							data,length = leaderconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_REMOVE,csip[0],csip[1],csip[2],csip[3],csport))
1491							if length==1:
1492								status = (struct.unpack(">B",data))[0]
1493								cmd_success = 1
1494					if cmd_success:
1495						if status==STATUS_OK:
1496							print("Chunkserver %s/%s has been removed" % (cmddata[1],cmddata[2]))
1497						elif status==ERROR_NOTFOUND:
1498							print("Chunkserver %s/%s hasn't been found" % (cmddata[1],cmddata[2]))
1499						elif status==ERROR_ACTIVE:
1500							print("Chunkserver %s/%s can't be removed because is still active" (cmddata[1],cmddata[2]))
1501						else:
1502							print("Can't remove chunkserver %s/%s (status:%u)" % (cmddata[1],cmddata[2],status))
1503					else:
1504						print("Can't remove chunkserver %s/%s" % (cmddata[1],cmddata[2]))
1505				except Exception:
1506					print_exception()
1507			if cmddata[0]=='BW':
1508				cmd_success = 0
1509				try:
1510					csip = list(map(int,cmddata[1].split(".")))
1511					csport = int(cmddata[2])
1512					if len(csip)==4:
1513						if leaderconn.version_at_least(1,6,28):
1514							data,length = leaderconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_BACKTOWORK,csip[0],csip[1],csip[2],csip[3],csport))
1515							if length==1:
1516								status = (struct.unpack(">B",data))[0]
1517								cmd_success = 1
1518					if cmd_success:
1519						if status==STATUS_OK:
1520							print("Chunkserver %s/%s has back to work" % (cmddata[1],cmddata[2]))
1521						elif status==ERROR_NOTFOUND:
1522							print("Chunkserver %s/%s hasn't been found" % (cmddata[1],cmddata[2]))
1523						else:
1524							print("Can't turn chunkserver %s/%s back to work (status:%u)" % (cmddata[1],cmddata[2],status))
1525					else:
1526						print("Can't turn chunkserver %s/%s back to work" % (cmddata[1],cmddata[2]))
1527				except Exception:
1528					print_exception()
1529			if cmddata[0]=='M1':
1530				cmd_success = 0
1531				try:
1532					csip = list(map(int,cmddata[1].split(".")))
1533					csport = int(cmddata[2])
1534					if len(csip)==4:
1535						if leaderconn.version_at_least(2,0,11):
1536							data,length = leaderconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_MAINTENANCEON,csip[0],csip[1],csip[2],csip[3],csport))
1537							if length==1:
1538								status = (struct.unpack(">B",data))[0]
1539								cmd_success = 1
1540					if cmd_success:
1541						if status==STATUS_OK:
1542							print("Chunkserver %s/%s has been switched to maintenance mode" % (cmddata[1],cmddata[2]))
1543						elif status==ERROR_NOTFOUND:
1544							print("Chunkserver %s/%s hasn't been found" % (cmddata[1],cmddata[2]))
1545						else:
1546							print("Can't switch chunkserver %s/%s to maintenance mode (status:%u)" % (cmddata[1],cmddata[2],status))
1547					else:
1548						print("Can't switch chunkserver %s/%s to maintenance mode" % (cmddata[1],cmddata[2]))
1549				except Exception:
1550					print_exception()
1551			if cmddata[0]=='M0':
1552				cmd_success = 0
1553				try:
1554					csip = list(map(int,cmddata[1].split(".")))
1555					csport = int(cmddata[2])
1556					if len(csip)==4:
1557						if leaderconn.version_at_least(2,0,11):
1558							data,length = leaderconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_MAINTENANCEOFF,csip[0],csip[1],csip[2],csip[3],csport))
1559							if length==1:
1560								status = (struct.unpack(">B",data))[0]
1561								cmd_success = 1
1562					if cmd_success:
1563						if status==STATUS_OK:
1564							print("Chunkserver %s/%s has been switched to standard mode" % (cmddata[1],cmddata[2]))
1565						elif status==ERROR_NOTFOUND:
1566							print("Chunkserver %s/%s hasn't been found" % (cmddata[1],cmddata[2]))
1567						else:
1568							print("Can't switch chunkserver %s/%s to standard mode (status:%u)" % (cmddata[1],cmddata[2],status))
1569					else:
1570						print("Can't switch chunkserver %s/%s to standard mode" % (cmddata[1],cmddata[2]))
1571				except Exception:
1572					print_exception()
1573			if cmddata[0]=='RS':
1574				cmd_success = 0
1575				try:
1576					sessionid = int(cmddata[1])
1577					data,length = leaderconn.command(CLTOMA_SESSION_COMMAND,MATOCL_SESSION_COMMAND,struct.pack(">BL",MFS_SESSION_COMMAND_REMOVE,sessionid))
1578					if length==1:
1579						status = (struct.unpack(">B",data))[0]
1580						cmd_success = 1
1581					if cmd_success:
1582						if status==STATUS_OK:
1583							print("Session %u has been removed" % (sessionid))
1584						elif status==ERROR_NOTFOUND:
1585							print("Session %u hasn't been found" % (sessionid))
1586						elif status==ERROR_ACTIVE:
1587							print("Session %u can't be removed because is still active" % (sessionid))
1588						else:
1589							print("Can't remove session %u (status:%u)" % (sessionid,status))
1590					else:
1591						print("Can't remove session %u" % (sessionid))
1592				except Exception:
1593					print_exception()
1594	elif len(clicommands)>0:
1595		print("Can't perform any operation because there is no leading master")
1596
1597if cgimode:
1598	if "sections" in fields:
1599		sectionstr = fields.getvalue("sections")
1600		sectionset = set(sectionstr.split("|"))
1601	else:
1602		sectionset = set(("IN",))
1603	if "subsections" in fields:
1604		subsectionstr = fields.getvalue("subsections")
1605		sectionsubset = set(subsectionstr.split("|"))
1606	else:
1607		sectionsubset = ["IM","LI","IG","MU","IC","IL","MF","CS","MB"] # used only in climode - in cgimode turn on all subsections
1608
1609	if leaderfound:
1610		if leaderconn.version_less_than(1,7,0):
1611			sectiondef={
1612				"IN":"Info",
1613				"CS":"Servers",
1614				"HD":"Disks",
1615				"EX":"Exports",
1616				"MS":"Mounts",
1617				"MO":"Operations",
1618				"MC":"Master Charts",
1619				"CC":"Server Charts"
1620			}
1621			sectionorder=["IN","CS","HD","EX","MS","MO","MC","CC"];
1622		else:
1623			sectiondef={
1624				"IN":"Info",
1625				"CS":"Servers",
1626				"HD":"Disks",
1627				"EX":"Exports",
1628				"MS":"Mounts",
1629				"MO":"Operations",
1630				"QU":"Quotas",
1631				"MC":"Master Charts",
1632				"CC":"Server Charts"
1633			}
1634			sectionorder=["IN","CS","HD","EX","MS","MO","QU","MC","CC"];
1635	else:
1636		sectiondef = {
1637			"IN":"Info"
1638		}
1639		sectionorder=["IN"];
1640
1641	print("Content-Type: text/html; charset=UTF-8")
1642	print("")
1643	# print """<!-- Put IE into quirks mode -->
1644	print("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">""")
1645	print("""<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">""")
1646	print("""<head>""")
1647	print("""<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />""")
1648	print("""<title>MFS Info (%s)</title>""" % (htmlentities(mastername)))
1649	print("""<link rel="stylesheet" href="mfs.css" type="text/css" />""")
1650	print("""<script src="acidtab.js" type="text/javascript"></script>""")
1651	print("""</head>""")
1652	print("""<body>""")
1653
1654	#MENUBAR
1655	print("""<div id="header">""")
1656	print("""<table class="HDR" cellpadding="0" cellspacing="0" border="0">""")
1657	print("""<tr>""")
1658	print("""<td class="LOGO"><a href="http://www.moosefs.org"><img src="/logomini.png" alt="logo" style="border:0;width:123px;height:47px" /></a></td>""")
1659	print("""<td class="MENU"><table class="MENU" cellspacing="0">""")
1660	print("""<tr>""")
1661	last="U"
1662	for k in sectionorder:
1663		if k==sectionorder[-1]:
1664			last = "L%s" % last
1665		if k in sectionset:
1666			if len(sectionset)<=1:
1667				print("""<td class="%sS">%s &#8722;</td>""" % (last,sectiondef[k]))
1668			else:
1669				print("""<td class="%sS"><a href="%s">%s</a> <a href="%s">&#8722;</a></td>""" % (last,createlink({"sections":k}),sectiondef[k],createlink({"sections":"|".join(sectionset-set([k]))})))
1670			last="S"
1671		else:
1672			print("""<td class="%sU"><a href="%s">%s</a> <a href="%s">+</a></td>""" % (last,createlink({"sections":k}),sectiondef[k],createlink({"sections":"|".join(sectionset|set([k]))})))
1673			last="U"
1674	print("""</tr>""")
1675	print("""</table></td>""")
1676	print("""<td class="FILLER" style="white-space:nowrap;">""")
1677	#print("""<a href="http://jigsaw.w3.org/css-validator/check/referer"><img style="border:0;width:88px;height:31px" src="http://jigsaw.w3.org/css-validator/images/vcss-blue" alt="Valid CSS!" /></a>""")
1678	#print("""<a href="http://validator.w3.org/check?uri=referer"><img style="border:0;width:88px;height:31px" src="http://www.w3.org/Icons/valid-xhtml10-blue" alt="Valid XHTML 1.0 Strict" /></a>""")
1679	print("""</td>""")
1680	print("""</tr>""")
1681	print("""</table>""")
1682	print("""</div>""")
1683
1684	#print """<div id="footer">
1685	#Moose File System by Jakub Kruszona-Zawadzki
1686	#</div>
1687	#"""
1688
1689	print("""<div id="container">""")
1690
1691needseparator = 0
1692
1693if leaderfound==0:
1694	if cgimode:
1695		out = []
1696		out.append("""<table class="FR" cellspacing="0">""")
1697		if len(masterlist)==0:
1698			out.append("""	<tr>""")
1699			out.append("""		<td align="center">""")
1700			out.append("""			<span class="ERROR">Can't find masters (resolve given name) !!!</span><br />""")
1701			out.append("""			<form method="GET">""")
1702			out.append("""				Input your DNS master name: <input type="text" name="masterhost" value="%s" size="100">""" % (masterhost))
1703			for i in createinputs(["masterhost"]):
1704				out.append("""				%s""" % (i))
1705			out.append("""				<input type="submit" value="Try it !!!">""")
1706			out.append("""			</form>""")
1707			out.append("""		</td>""")
1708			out.append("""	</tr>""")
1709		elif electfound:
1710			out.append("""	<tr>""")
1711			out.append("""		<td align="center">""")
1712			out.append("""			<span class="ERROR">Leader master server not found, but there is an elect, so make sure that all chnunkservers are running - elect should became a leader soon</span><br />""")
1713			out.append("""		</td>""")
1714			out.append("""	</tr>""")
1715		elif followerfound:
1716			out.append("""	<tr><td align="center"><span class="ERROR">Leader master server not found !!!</span><br /><button type="button" onclick="document.location.href='%s'">click here to try to resolve this problem</button></td></tr>""" % createlink({"MAsupervisor":"true"}))
1717		else:
1718			out.append("""	<tr>""")
1719			out.append("""		<td align="center">""")
1720			out.append("""			<span class="ERROR">Can't find working masters !!!</span><br />""")
1721			out.append("""			<form method="GET">""")
1722			out.append("""				Input your DNS master name: <input type="text" name="masterhost" value="%s" size="100"><br />""" % (masterhost))
1723			out.append("""				Input your master-client port number: <input type="text" name="masterport" value="%u" size="5"><br />""" % (masterport))
1724			out.append("""				Input your master-control port number: <input type="text" name="mastercontrolport" value="%u" size="5"><br />""" % (mastercontrolport))
1725			for i in createinputs(["masterhost","masterport","mastercontrolport"]):
1726				out.append("""				%s""" % (i))
1727			out.append("""				<input type="submit" value="Try it !!!">""")
1728			out.append("""			</form>""")
1729			out.append("""		</td>""")
1730			out.append("""	</tr>""")
1731		out.append("""</table>""")
1732		print("\n".join(out))
1733	else:
1734		if len(masterlist)==0:
1735			print("""Can't find masters (resolve '%s') !!!""" % (masterhost))
1736		elif electfound:
1737			print("Leader master server not found, but there is an elect, so make sure that all chnunkservers are running - elect should became a leader soon")
1738		elif followerfound:
1739			print("Leader master server not found !!! - maybe you should run 'mfssupervisor -f -x -h %s -p %u'" % (masterhost,mastercontrolport))
1740		else:
1741			print("Working master servers not found !!! - maybe you are using wrong port number or wrong dns name")
1742	needseparator=1
1743	sectionset = set(("IN",))
1744	sectionsubset = ["IM"] # used only in climode - in cgimode turn on all subsections
1745
1746# parse cgi parameters
1747if cgimode:
1748	try:
1749		INmatrix = int(fields.getvalue("INmatrix"))
1750	except Exception:
1751		INmatrix = 0
1752	try:
1753		IMorder = int(fields.getvalue("IMorder"))
1754	except Exception:
1755		IMorder = 0
1756	try:
1757		IMrev = int(fields.getvalue("IMrev"))
1758	except Exception:
1759		IMrev = 0
1760	try:
1761		MForder = int(fields.getvalue("MForder"))
1762	except Exception:
1763		MForder = 0
1764	try:
1765		MFrev = int(fields.getvalue("MFrev"))
1766	except Exception:
1767		MFrev = 0
1768	try:
1769		MFlimit = int(fields.getvalue("MFlimit"))
1770	except Exception:
1771		MFlimit = 100
1772	try:
1773		CSorder = int(fields.getvalue("CSorder"))
1774	except Exception:
1775		CSorder = 0
1776	try:
1777		CSrev = int(fields.getvalue("CSrev"))
1778	except Exception:
1779		CSrev = 0
1780	try:
1781		MBorder = int(fields.getvalue("MBorder"))
1782	except Exception:
1783		MBorder = 0
1784	try:
1785		MBrev = int(fields.getvalue("MBrev"))
1786	except Exception:
1787		MBrev = 0
1788	try:
1789		HDorder = int(fields.getvalue("HDorder"))
1790	except Exception:
1791		HDorder = 0
1792	try:
1793		HDrev = int(fields.getvalue("HDrev"))
1794	except Exception:
1795		HDrev = 0
1796	try:
1797		HDperiod = int(fields.getvalue("HDperiod"))
1798	except Exception:
1799		HDperiod = 0
1800	try:
1801		HDtime = int(fields.getvalue("HDtime"))
1802	except Exception:
1803		HDtime = 0
1804	try:
1805		HDaddrname = int(fields.getvalue("HDaddrname"))
1806	except Exception:
1807		HDaddrname = 0
1808	try:
1809		EXorder = int(fields.getvalue("EXorder"))
1810	except Exception:
1811		EXorder = 0
1812	try:
1813		EXrev = int(fields.getvalue("EXrev"))
1814	except Exception:
1815		EXrev = 0
1816	try:
1817		MSorder = int(fields.getvalue("MSorder"))
1818	except Exception:
1819		MSorder = 0
1820	try:
1821		MSrev = int(fields.getvalue("MSrev"))
1822	except Exception:
1823		MSrev = 0
1824	try:
1825		MOorder = int(fields.getvalue("MOorder"))
1826	except Exception:
1827		MOorder = 0
1828	try:
1829		MOrev = int(fields.getvalue("MOrev"))
1830	except Exception:
1831		MOrev = 0
1832	try:
1833		MOdata = int(fields.getvalue("MOdata"))
1834	except Exception:
1835		MOdata = 0
1836	try:
1837		QUorder = int(fields.getvalue("QUorder"))
1838	except Exception:
1839		QUorder = 0
1840	try:
1841		QUrev = int(fields.getvalue("QUrev"))
1842	except Exception:
1843		QUrev = 0
1844	try:
1845		if "MCdata" in fields:
1846			MCdata = fields.getvalue("MCdata")
1847		else:
1848			MCdata = ""
1849	except Exception:
1850		MCdata = ""
1851	try:
1852		if "CCdata" in fields:
1853			CCdata = fields.getvalue("CCdata")
1854		else:
1855			CCdata = ""
1856	except Exception:
1857		CCdata = ""
1858else:
1859	# fix order id's
1860	if CSorder>=2:
1861		CSorder+=1
1862	if leaderfound and leaderconn.version_less_than(1,7,25) and CSorder>=4:
1863		CSorder+=1
1864	if leaderfound and leaderconn.version_less_than(1,6,28) and CSorder>=5:
1865		CSorder+=1
1866	if CSorder>=6 and CSorder<=9:
1867		CSorder+=4
1868	elif CSorder>=10 and CSorder<=13:
1869		CSorder+=10
1870
1871	if MBorder>=2:
1872		MBorder+=1
1873
1874	if HDorder>=13 and HDorder<=15:
1875		HDorder+=7
1876
1877	if leaderfound and leaderconn.version_less_than(1,7,0) and EXorder>=10:
1878		EXorder+=1
1879
1880	if MSorder>=3:
1881		MSorder+=1
1882	if leaderfound and leaderconn.version_less_than(1,7,0) and MSorder>=10:
1883		MSorder+=1
1884	if MSorder==0:
1885		MSorder=2
1886
1887	if MOorder==2:
1888		MOorder = 3
1889	elif MOorder>=3 and MOorder<=18:
1890		MOorder += 97
1891	elif MOorder==19:
1892		MOorder = 150
1893	elif MOorder!=1:
1894		MOorder = 0
1895
1896	if QUorder>=2 and QUorder<=6:
1897		QUorder += 8
1898	elif QUorder>=7 and QUorder<=10:
1899		QUorder += 14
1900	elif QUorder>=11 and QUorder<=22:
1901		QUorder = (lambda x: x[0]+x[1]*10)(divmod(QUorder-11,3))+31
1902	elif QUorder<1 or QUorder>22:
1903		QUorder = 0
1904
1905
1906if "IN" in sectionset:
1907	if cgimode and MFS_MESSAGE:
1908		if needseparator:
1909			print("""<br/>""")
1910		else:
1911			needseparator=1
1912		out = []
1913		out.append("""<table class="FR" cellspacing="0">""")
1914		out.append("""<tr><th>Notice</th></tr>""")
1915		out.append("""<tr><td>You are currently using GPL version of MooseFS. If you want to find out what great features are available in MooseFS Pro go to <a href="http://moosefs.com/products.html">http://moosefs.com/products.html</a></td></tr>""")
1916		out.append("""</table>""")
1917		print("\n".join(out))
1918
1919	if "IM" in sectionsubset and len(masterlistinfo)>0:
1920		try:
1921			if needseparator:
1922				if cgimode:
1923					print("""<br/>""")
1924				else:
1925					print("")
1926			else:
1927				needseparator=1
1928			if cgimode:
1929				out = []
1930				out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsmasters" cellspacing="0">""")
1931				out.append("""	<tr><th colspan="10">Metadata Servers (masters)</th></tr>""")
1932				out.append("""	<tr>""")
1933				out.append("""		<th class="acid_tab_enumerate">#</th>""")
1934				out.append("""		<th>ip</th>""")
1935				out.append("""		<th>version</th>""")
1936				out.append("""		<th>state</th>""")
1937				out.append("""		<th>metadata version</th>""")
1938				out.append("""		<th>RAM used</th>""")
1939				out.append("""		<th>CPU used</th>""")
1940				out.append("""		<th>last successful metadata save</th>""")
1941				out.append("""		<th>last metadata save duration</th>""")
1942				out.append("""		<th>last metadata save status</th>""")
1943				out.append("""	</tr>""")
1944			elif ttymode:
1945				tab = Tabble("Metadata Servers",9,"r")
1946				tab.header("ip","version","state","metadata version","RAM used","CPU used","last meta save","last save duration","last save status")
1947			else:
1948				tab = Tabble("metadata servers",9)
1949			masterstab = []
1950			for sortip,strip,sortver,strver,statestr,statecolor,metaversion,memusage,syscpu,usercpu,lastsuccessfulstore,lastsaveseconds,lastsavestatus in masterlistinfo:
1951				if IMorder==1:
1952					sf = sortip
1953				elif IMorder==2:
1954					sf = sortver
1955				elif IMorder==3:
1956					sf = statecolor
1957				elif IMorder==4:
1958					sf = metaversion
1959				elif IMorder==5:
1960					sf = memusage
1961				elif IMorder==6:
1962					sf = syscpu+usercpu
1963				elif IMorder==7:
1964					sf = lastsuccessfulstore
1965				elif IMorder==8:
1966					sf = lastsaveseconds
1967				elif IMorder==9:
1968					sf = lastsavestatus
1969				else:
1970					sf = 0
1971				masterstab.append((sf,sortip,strip,sortver,strver,statestr,statecolor,metaversion,memusage,syscpu,usercpu,lastsuccessfulstore,lastsaveseconds,lastsavestatus))
1972
1973			masterstab.sort()
1974			if IMrev:
1975				masterstab.reverse()
1976
1977			for sf,sortip,strip,sortver,strver,statestr,statecolor,metaversion,memusage,syscpu,usercpu,lastsuccessfulstore,lastsaveseconds,lastsavestatus in masterstab:
1978				if cgimode:
1979					if leaderconn!=None and leaderconn.is_pro() and not strver.endswith(" PRO"):
1980						verclass = "BADVERSION"
1981					elif leaderconn!=None and leaderconn.sort_ver() > sortver:
1982						verclass = "LOWERVERSION"
1983					elif leaderconn!=None and leaderconn.sort_ver() < sortver:
1984						verclass = "HIGHERVERSION"
1985					else:
1986						verclass = "OKVERSION"
1987					out.append("""	<tr>""")
1988					out.append("""		<td align="right"></td><td align="center"><span class="sortkey">%s </span>%s</td><td align="center"><span class="sortkey">%s </span><span class="%s">%s</span></td>""" % (sortip,strip,sortver,verclass,strver))
1989					out.append("""		<td align="center"><span class="STATECOLOR%u">%s</span></td>""" % (statecolor,statestr))
1990					out.append("""		<td align="right">%s</td>""" % (decimal_number(metaversion)))
1991					if memusage>0:
1992						out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(memusage),humanize_number(memusage,"&nbsp;")))
1993					else:
1994						out.append("""		<td align="center"><a style="cursor:default" title="obtaining memory usage is not supported by your OS or can't be obtained from server">not available</td>""")
1995					if syscpu>0 or usercpu>0:
1996						out.append("""		<td align="center"><a style="cursor:default" title="all:%.7f%% sys:%.7f%% user:%.7f%%">all:%.2f%%&nbsp;sys:%.2f%%&nbsp;user:%.2f%%</a></td>""" % (syscpu+usercpu,syscpu,usercpu,syscpu+usercpu,syscpu,usercpu))
1997					else:
1998						out.append("""		<td align="center"><a style="cursor:default" title="obtaining cpu usage is not supported by your OS or can't be obtained from server">not available</td>""")
1999					if lastsuccessfulstore>0:
2000						out.append("""		<td align="center">%s</td>""" % time.asctime(time.localtime(lastsuccessfulstore)))
2001						out.append("""		<td align="center"><a style="cursor:default" title="%s">%s</a></td>""" % (timeduration_to_fullstr(lastsaveseconds),timeduration_to_shortstr(lastsaveseconds)))
2002					else:
2003						out.append("""		<td align="center">-</td><td align="center">-</td>""")
2004					if lastsuccessfulstore>0 or lastsavestatus>0:
2005						out.append("""		<td align="center"><span class="%s">%s</span></td>""" % ("SUCCESS" if lastsavestatus==0 or lastsavestatus==1 else "WARNING" if lastsavestatus==2 else "ERROR","Saved in background" if lastsavestatus==0 else "Downloaded from other master" if lastsavestatus==1 else "Saved in foreground" if lastsavestatus==2 else "Unknown status: %u" % lastsavestatus))
2006					else:
2007						out.append("""		<td align="center">-</td>""")
2008					out.append("""	</tr>""")
2009				else:
2010					clist = [strip,strver,(statestr,"c%u" % statecolor),decimal_number(metaversion)]
2011					if memusage>0:
2012						if ttymode:
2013							clist.append(humanize_number(memusage," "))
2014						else:
2015							clist.append(memusage)
2016					else:
2017						clist.append("not available")
2018					if syscpu>0 or usercpu>0:
2019						if ttymode:
2020							clist.append("all:%.2f%% sys:%.2f%% user:%.2f%%" % (syscpu+usercpu,syscpu,usercpu))
2021						else:
2022							clist.append("all:%.7f%% sys:%.7f%% user:%.7f%%" % (syscpu+usercpu,syscpu,usercpu))
2023					else:
2024						clist.append("not available")
2025					if lastsuccessfulstore>0:
2026						if ttymode:
2027							clist.append(time.asctime(time.localtime(lastsuccessfulstore)))
2028							clist.append(timeduration_to_shortstr(lastsaveseconds))
2029						else:
2030							clist.append(lastsuccessfulstore)
2031							clist.append("%.3f" % lastsaveseconds)
2032					else:
2033						clist.append("-")
2034						clist.append("-")
2035					if lastsuccessfulstore>0 or lastsavestatus>0:
2036						clist.append(("Saved in background","4") if lastsavestatus==0 else ("Downloaded from other master","4") if lastsavestatus==1 else ("Saved in foreground","2") if lastsavestatus==2 else ("Unknown status: %u" % lastsavestatus,"1"))
2037					else:
2038						clist.append("-")
2039					tab.append(*clist)
2040
2041			if len(masterstab)==0:
2042				if cgimode:
2043					out.append("""	<tr><td colspan="10">Servers not found !!! - check your DNS</td></tr>""")
2044				else:
2045					tab.append(("""Servers not found !!! - check your DNS""","c",9))
2046
2047			if cgimode:
2048				out.append("""</table>""")
2049			if cgimode:
2050				print("\n".join(out))
2051			else:
2052				print(tab)
2053		except Exception:
2054			print_exception()
2055
2056
2057	if "IG" in sectionsubset:
2058		try:
2059			if needseparator:
2060				if cgimode:
2061					print("""<br/>""")
2062				else:
2063					print("")
2064			else:
2065				needseparator=1
2066			length = len(leaderinfo)
2067			if length==68:
2068				v1,v2,v3,total,avail,trspace,trfiles,respace,refiles,nodes,dirs,files,chunks,allcopies,tdcopies = struct.unpack(">HBBQQQLQLLLLLLL",leaderinfo)
2069				strver,sortver = version_str_and_sort((v1,v2,v3))
2070				if cgimode:
2071					out = []
2072					out.append("""<table class="FR" cellspacing="0">""")
2073					out.append("""	<tr><th colspan="13">Info</th></tr>""")
2074					out.append("""	<tr>""")
2075					out.append("""		<th>version</th>""")
2076					out.append("""		<th>total space</th>""")
2077					out.append("""		<th>avail space</th>""")
2078					out.append("""		<th>trash space</th>""")
2079					out.append("""		<th>trash files</th>""")
2080					out.append("""		<th>sustained space</th>""")
2081					out.append("""		<th>sustained files</th>""")
2082					out.append("""		<th>all fs objects</th>""")
2083					out.append("""		<th>directories</th>""")
2084					out.append("""		<th>files</th>""")
2085					out.append("""		<th>chunks</th>""")
2086					out.append("""		<th><a style="cursor:default" title="chunks from 'regular' hdd space and 'marked for removal' hdd space">all chunk copies</a></th>""")
2087					out.append("""		<th><a style="cursor:default" title="only chunks from 'regular' hdd space">regular chunk copies</a></th>""")
2088					out.append("""	</tr>""")
2089					out.append("""	<tr>""")
2090					out.append("""		<td align="center">%s</td>""" % strver)
2091					out.append("""		<td align="right"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(total),humanize_number(total,"&nbsp;")))
2092					out.append("""		<td align="right"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(avail),humanize_number(avail,"&nbsp;")))
2093					out.append("""		<td align="right"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(trspace),humanize_number(trspace,"&nbsp;")))
2094					out.append("""		<td align="right">%u</td>""" % trfiles)
2095					out.append("""		<td align="right"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(respace),humanize_number(respace,"&nbsp;")))
2096					out.append("""		<td align="right">%u</td>""" % refiles)
2097					out.append("""		<td align="right">%u</td>""" % nodes)
2098					out.append("""		<td align="right">%u</td>""" % dirs)
2099					out.append("""		<td align="right">%u</td>""" % files)
2100					out.append("""		<td align="right">%u</td>""" % chunks)
2101					out.append("""		<td align="right">%u</td>""" % allcopies)
2102					out.append("""		<td align="right">%u</td>""" % tdcopies)
2103					out.append("""	</tr>""")
2104					out.append("""</table>""")
2105					print("\n".join(out))
2106				else:
2107					if ttymode:
2108						tab = Tabble("Master Info",2)
2109					else:
2110						tab = Tabble("master info",2)
2111					tab.defattr("l","r")
2112					tab.append("master version",strver)
2113					if ttymode:
2114						tab.append("total space",humanize_number(total," "))
2115						tab.append("avail space",humanize_number(avail," "))
2116						tab.append("trash space",humanize_number(trspace," "))
2117					else:
2118						tab.append("total space",total)
2119						tab.append("avail space",avail)
2120						tab.append("trash space",trspace)
2121					tab.append("trash files",trfiles)
2122					if ttymode:
2123						tab.append("sustained space",humanize_number(respace," "))
2124					else:
2125						tab.append("sustained space",respace)
2126					tab.append("sustained files",refiles)
2127					tab.append("all fs objects",nodes)
2128					tab.append("directories",dirs)
2129					tab.append("files",files)
2130					tab.append("chunks",chunks)
2131					tab.append("all chunk copies",allcopies)
2132					tab.append("regular chunk copies",tdcopies)
2133					print(tab)
2134			elif length==76:
2135				v1,v2,v3,memusage,total,avail,trspace,trfiles,respace,refiles,nodes,dirs,files,chunks,allcopies,tdcopies = struct.unpack(">HBBQQQQLQLLLLLLL",leaderinfo)
2136				strver,sortver = version_str_and_sort((v1,v2,v3))
2137				if cgimode:
2138					out = []
2139					out.append("""<table class="FR" cellspacing="0">""")
2140					out.append("""	<tr><th colspan="14">Info</th></tr>""")
2141					out.append("""	<tr>""")
2142					out.append("""		<th>version</th>""")
2143					out.append("""		<th>RAM used</th>""")
2144					out.append("""		<th>total space</th>""")
2145					out.append("""		<th>avail space</th>""")
2146					out.append("""		<th>trash space</th>""")
2147					out.append("""		<th>trash files</th>""")
2148					out.append("""		<th>sustained space</th>""")
2149					out.append("""		<th>sustained files</th>""")
2150					out.append("""		<th>all fs objects</th>""")
2151					out.append("""		<th>directories</th>""")
2152					out.append("""		<th>files</th>""")
2153					out.append("""		<th>chunks</th>""")
2154					out.append("""		<th><a style="cursor:default" title="chunks from 'regular' hdd space and 'marked for removal' hdd space">all chunk copies</a></th>""")
2155					out.append("""		<th><a style="cursor:default" title="only chunks from 'regular' hdd space">regular chunk copies</a></th>""")
2156					out.append("""	</tr>""")
2157					out.append("""	<tr>""")
2158					out.append("""		<td align="center">%s</td>""" % strver)
2159					if memusage>0:
2160						out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(memusage),humanize_number(memusage,"&nbsp;")))
2161					else:
2162						out.append("""		<td align="center"><a style="cursor:default" title="obtaining memory usage is not supported by your OS">not available</td>""")
2163					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(total),humanize_number(total,"&nbsp;")))
2164					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(avail),humanize_number(avail,"&nbsp;")))
2165					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(trspace),humanize_number(trspace,"&nbsp;")))
2166					out.append("""		<td align="center">%u</td>""" % trfiles)
2167					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(respace),humanize_number(respace,"&nbsp;")))
2168					out.append("""		<td align="center">%u</td>""" % refiles)
2169					out.append("""		<td align="center">%u</td>""" % nodes)
2170					out.append("""		<td align="center">%u</td>""" % dirs)
2171					out.append("""		<td align="center">%u</td>""" % files)
2172					out.append("""		<td align="center">%u</td>""" % chunks)
2173					out.append("""		<td align="center">%u</td>""" % allcopies)
2174					out.append("""		<td align="center">%u</td>""" % tdcopies)
2175					out.append("""	</tr>""")
2176					out.append("""</table>""")
2177					print("\n".join(out))
2178				else:
2179					if ttymode:
2180						tab = Tabble("Master Info",2)
2181					else:
2182						tab = Tabble("master info",2)
2183					tab.defattr("l","r")
2184					tab.append("master version",strver)
2185					if memusage>0:
2186						if ttymode:
2187							tab.append("RAM used",humanize_number(memusage," "))
2188						else:
2189							tab.append("RAM used",memusage)
2190					else:
2191						tab.append("RAM used","not available")
2192					if ttymode:
2193						tab.append("total space",humanize_number(total," "))
2194						tab.append("avail space",humanize_number(avail," "))
2195						tab.append("trash space",humanize_number(trspace," "))
2196					else:
2197						tab.append("total space",total)
2198						tab.append("avail space",avail)
2199						tab.append("trash space",trspace)
2200					tab.append("trash files",trfiles)
2201					if ttymode:
2202						tab.append("sustained space",humanize_number(respace," "))
2203					else:
2204						tab.append("sustained space",respace)
2205					tab.append("sustained files",refiles)
2206					tab.append("all fs objects",nodes)
2207					tab.append("directories",dirs)
2208					tab.append("files",files)
2209					tab.append("chunks",chunks)
2210					tab.append("all chunk copies",allcopies)
2211					tab.append("regular chunk copies",tdcopies)
2212					print(tab)
2213			elif length==101 or length==121:
2214				v1,v2,v3,memusage,syscpu,usercpu,total,avail,trspace,trfiles,respace,refiles,nodes,dirs,files,chunks,allcopies,tdcopies,lastsuccessfulstore,lastsaveseconds,lastsavestatus = struct.unpack(">HBBQQQQQQLQLLLLLLLLLB",leaderinfo[:101])
2215				strver,sortver = version_str_and_sort((v1,v2,v3))
2216				syscpu/=10000000.0
2217				usercpu/=10000000.0
2218				if leaderconn.version_at_least(2,0,14):
2219					lastsaveseconds = lastsaveseconds / 1000.0
2220				if cgimode:
2221					out = []
2222					if length==101:
2223						out.append("""<table class="FR" cellspacing="0">""")
2224						out.append("""	<tr><th colspan="6">General Info</th></tr>""")
2225						out.append("""	<tr>""")
2226						out.append("""		<th>version</th>""")
2227						out.append("""		<th>RAM used</th>""")
2228						out.append("""		<th>CPU used</th>""")
2229						out.append("""		<th>last successful metadata save</th>""")
2230						out.append("""		<th>last metadata save duration</th>""")
2231						out.append("""		<th>last metadata save status</th>""")
2232						out.append("""	</tr>""")
2233						out.append("""	<tr>""")
2234						out.append("""		<td align="center">%s</td>""" % strver)
2235						if memusage>0:
2236							out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(memusage),humanize_number(memusage,"&nbsp;")))
2237						else:
2238							out.append("""		<td align="center"><a style="cursor:default" title="obtaining memory usage is not supported by your OS">not available</td>""")
2239						if syscpu>0 or usercpu>0:
2240							out.append("""		<td align="center"><a style="cursor:default" title="all:%.7f%% sys:%.7f%% user:%.7f">all:%.2f%%&nbsp;sys:%.2f%%&nbsp;user:%.2f%%</a></td>""" % (syscpu+usercpu,syscpu,usercpu,syscpu+usercpu,syscpu,usercpu))
2241						else:
2242							out.append("""		<td align="center"><a style="cursor:default" title="obtaining cpu usage is not supported by your OS">not available</td>""")
2243						if lastsuccessfulstore>0:
2244							out.append("""		<td align="center">%s</td>""" % time.asctime(time.localtime(lastsuccessfulstore)))
2245							out.append("""		<td align="center"><a style="cursor:default" title="%s">%s</a></td>""" % (timeduration_to_fullstr(lastsaveseconds),timeduration_to_shortstr(lastsaveseconds)))
2246						else:
2247							out.append("""		<td align="center">-</td><td align="center">-</td>""")
2248						if lastsuccessfulstore>0 or lastsavestatus>0:
2249							out.append("""		<td align="center"><span class="%s">%s</span></td>""" % ("SUCCESS" if lastsavestatus==0 else "ERROR","OK" if lastsavestatus==0 else "ERROR (%u)" % lastsavestatus))
2250						else:
2251							out.append("""		<td align="center">-</td>""")
2252						out.append("""	</tr>""")
2253						out.append("""</table>""")
2254						out.append("""<br/>""")
2255					out.append("""<table class="FR" cellspacing="0">""")
2256					out.append("""	<tr><th colspan="12">Metadata Info</th></tr>""")
2257					out.append("""	<tr>""")
2258					out.append("""		<th>total space</th>""")
2259					out.append("""		<th>avail space</th>""")
2260					out.append("""		<th>trash space</th>""")
2261					out.append("""		<th>trash files</th>""")
2262					out.append("""		<th>sustained space</th>""")
2263					out.append("""		<th>sustained files</th>""")
2264					out.append("""		<th>all fs objects</th>""")
2265					out.append("""		<th>directories</th>""")
2266					out.append("""		<th>files</th>""")
2267					out.append("""		<th>chunks</th>""")
2268					out.append("""		<th><a style="cursor:default" title="chunks from 'regular' hdd space and 'marked for removal' hdd space">all chunk copies</a></th>""")
2269					out.append("""		<th><a style="cursor:default" title="only chunks from 'regular' hdd space">regular chunk copies</a></th>""")
2270					out.append("""	</tr>""")
2271					out.append("""	<tr>""")
2272					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(total),humanize_number(total,"&nbsp;")))
2273					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(avail),humanize_number(avail,"&nbsp;")))
2274					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(trspace),humanize_number(trspace,"&nbsp;")))
2275					out.append("""		<td align="center">%u</td>""" % trfiles)
2276					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(respace),humanize_number(respace,"&nbsp;")))
2277					out.append("""		<td align="center">%u</td>""" % refiles)
2278					out.append("""		<td align="center">%u</td>""" % nodes)
2279					out.append("""		<td align="center">%u</td>""" % dirs)
2280					out.append("""		<td align="center">%u</td>""" % files)
2281					out.append("""		<td align="center">%u</td>""" % chunks)
2282					out.append("""		<td align="center">%u</td>""" % allcopies)
2283					out.append("""		<td align="center">%u</td>""" % tdcopies)
2284					out.append("""	</tr>""")
2285					out.append("""</table>""")
2286					print("\n".join(out))
2287				else:
2288					if ttymode:
2289						tab = Tabble("Master Info",2)
2290					else:
2291						tab = Tabble("master info",2)
2292					tab.defattr("l","r")
2293					tab.append("master version",strver)
2294					if memusage>0:
2295						if ttymode:
2296							tab.append("RAM used",humanize_number(memusage," "))
2297						else:
2298							tab.append("RAM used",memusage)
2299					else:
2300						tab.append("RAM used","not available")
2301					if syscpu>0 or usercpu>0:
2302						if ttymode:
2303							tab.append("CPU used","%.2f%%" % (syscpu+usercpu))
2304							tab.append("CPU used (system)","%.2f%%" % (syscpu))
2305							tab.append("CPU used (user)","%.2f%%" % (usercpu))
2306						else:
2307							tab.append("CPU used (system)","%.9f" % (syscpu/100.0))
2308							tab.append("CPU used (user)","%.9f" % (usercpu/100.0))
2309					else:
2310						tab.append("CPU used","not available")
2311					if ttymode:
2312						tab.append("total space",humanize_number(total," "))
2313						tab.append("avail space",humanize_number(avail," "))
2314						tab.append("trash space",humanize_number(trspace," "))
2315					else:
2316						tab.append("total space",total)
2317						tab.append("avail space",avail)
2318						tab.append("trash space",trspace)
2319					tab.append("trash files",trfiles)
2320					if ttymode:
2321						tab.append("sustained space",humanize_number(respace," "))
2322					else:
2323						tab.append("sustained space",respace)
2324					tab.append("sustained files",refiles)
2325					tab.append("all fs objects",nodes)
2326					tab.append("directories",dirs)
2327					tab.append("files",files)
2328					tab.append("chunks",chunks)
2329					tab.append("all chunk copies",allcopies)
2330					tab.append("regular chunk copies",tdcopies)
2331					if lastsuccessfulstore>0:
2332						if ttymode:
2333							tab.append("last successful store",time.asctime(time.localtime(lastsuccessfulstore)))
2334							tab.append("last save duration",timeduration_to_shortstr(lastsaveseconds))
2335						else:
2336							tab.append("last successful store",lastsuccessfulstore)
2337							tab.append("last save duration","%.3f" % lastsaveseconds)
2338					else:
2339						tab.append("last successful store","-")
2340						tab.append("last save duration","-")
2341					if lastsuccessfulstore>0 or lastsavestatus>0:
2342						tab.append("last save status",("Saved in background","4") if lastsavestatus==0 else ("Downloaded from another master","4") if lastsavestatus==1 else ("Saved in foreground","2") if lastsavestatus==2 else ("Unknown status: %u" % lastsavestatus,"1"))
2343					else:
2344						tab.append("last save status","-")
2345					print(tab)
2346			else:
2347				if cgimode:
2348					out = []
2349					out.append("""<table class="FR" cellspacing="0">""")
2350					out.append("""	<tr><td align="left">unrecognized answer from MFSmaster</td></tr>""")
2351					out.append("""</table>""")
2352					print("\n".join(out))
2353				else:
2354					print("unrecognized answer from MFSmaster")
2355		except Exception:
2356			print_exception()
2357
2358	if "MU" in sectionsubset and leaderconn.version_at_least(1,7,16):
2359		if needseparator:
2360			if cgimode:
2361				print("""<br/>""")
2362			else:
2363				print("")
2364		else:
2365			needseparator=1
2366		try:
2367			data,length = leaderconn.command(CLTOMA_MEMORY_INFO,MATOCL_MEMORY_INFO)
2368			if length>=176 and length%16==0:
2369				memusage = struct.unpack(">QQQQQQQQQQQQQQQQQQQQQQ",data[:176])
2370				memlabels = ["chunk hash","chunks","cs lists","edge hash","edges","node hash","nodes","deleted nodes","chunk tabs","symlinks","quota"]
2371				abrlabels = ["c.h.","c.","c.l.","e.h.","e.","n.h.","n.","d.n.","c.t.","s.","q."]
2372				totalused = 0
2373				totalallocated = 0
2374				for i in xrange(11):
2375					totalused += memusage[1+i*2]
2376					totalallocated += memusage[i*2]
2377				if cgimode:
2378					out = []
2379					out.append("""<table class="FR" cellspacing="0">""")
2380					out.append("""	<tr><th colspan="%d">Memory usage detailed info</th></tr>""" % (len(memlabels)+2))
2381					out.append("""	<tr><th></th>""")
2382					for i in xrange(11):
2383						out.append("""		<th>%s</th>""" % memlabels[i])
2384					out.append("""	<th>total</th></tr>""")
2385					out.append("""	<tr><th align="center">used</th>""")
2386					for i in xrange(11):
2387						out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(memusage[1+i*2]),humanize_number(memusage[1+i*2],"&nbsp;")))
2388					out.append("""	<td align="center"><a style="cursor:default" title="%s B">%s</a></td></tr>""" % (decimal_number(totalused),humanize_number(totalused,"&nbsp;")))
2389					out.append("""	<tr><th align="center">allocated</th>""")
2390					for i in xrange(11):
2391						out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(memusage[i*2]),humanize_number(memusage[i*2],"&nbsp;")))
2392					out.append("""	<td align="center"><a style="cursor:default" title="%s B">%s</a></td></tr>""" % (decimal_number(totalallocated),humanize_number(totalallocated,"&nbsp;")))
2393					out.append("""	<tr><th align="center">utilization</th>""")
2394					for i in xrange(11):
2395						if memusage[i*2]:
2396							percent = "%.2f %%" % (100.0 * memusage[1+i*2] / memusage[i*2])
2397						else:
2398							percent = "-"
2399						out.append("""		<td align="center">%s</td>""" % percent)
2400					if totalallocated:
2401						percent = "%.2f %%" % (100.0 * totalused / totalallocated)
2402					else:
2403						percent = "-"
2404					out.append("""	<td align="center">%s</td></tr>""" % percent)
2405					if totalallocated>0:
2406						out.append("""	<tr><th align="center">distribution</th>""")
2407						for i in xrange(11):
2408							tpercent = "%.2f %%" % (100.0 * memusage[i*2] / totalallocated)
2409							out.append("""		<td align="center">%s</td>""" % tpercent)
2410						out.append("""	<td>-</td></tr>""")
2411						out.append("""  <tr><th align="center">distribution bar</th>""")
2412						out.append("""		<td colspan="%d" class="NOPADDING">""" % (len(memlabels)+1))
2413						out.append("""			<table width="100%" cellspacing="0" style="border:0px;" id="bar"><tr>""")
2414						memdistribution = []
2415						other = 0.0
2416						for i,(label,abr) in enumerate(zip(memlabels,abrlabels)):
2417							tpercent = (100.0 * memusage[i*2] / totalallocated)
2418							if tpercent>1.0:
2419								memdistribution.append((tpercent,label,abr))
2420							else:
2421								other+=tpercent
2422						memdistribution.sort()
2423						memdistribution.reverse()
2424						if other>0:
2425							memdistribution.append((other,None,None))
2426						cl = "FIRST"
2427						labels = []
2428						tooltips = []
2429						for i,(percent,label,abr) in enumerate(memdistribution):
2430							if label:
2431								if percent>10.0:
2432									out.append("""				<td style="width:%.2f%%;" class="MEMDIST%d MEMDIST%s" align="center"><a style="cursor:default;" title="%s (%.2f %%)">%s</a></td>""" % (percent,i,cl,label,percent,label))
2433								elif percent>3.0:
2434									out.append("""				<td style="width:%.2f%%;" class="MEMDIST%d MEMDIST%s" align="center"><a style="cursor:default;" title="%s (%.2f %%)">%s</a></td>""" % (percent,i,cl,label,percent,abr))
2435								else:
2436									out.append("""				<td style="width:%.2f%%;" class="MEMDIST%d MEMDIST%s" align="center"><a style="cursor:default;" title="%s (%.2f %%)">%s</a></td>""" % (percent,i,cl,label,percent,"#"))
2437								labels.append(label)
2438								tooltips.append("%s (%.2f %%)" % (label,percent))
2439							else:
2440								out.append("""				<td style="width:%.2f%%;" class="MEMDISTOTHER MEMDIST%s"></td>""" % (percent,cl))
2441								labels.append("others")
2442								tooltips.append("other memory segments (%.2f %%)" % (percent))
2443							cl = "MID"
2444						out.append("""			</tr></table>""")
2445						out.append("""<script type="text/javascript">""")
2446						out.append("""<!--//--><![CDATA[//><!--""")
2447						out.append("""	var bar_labels = [%s];""" % ",".join(map(repr,labels)))
2448						out.append("""	var bar_tooltips = [%s];""" % ",".join(map(repr,tooltips)))
2449						out.append("""//--><!]]>""")
2450						out.append("""</script>""")
2451						out.append("""<script type="text/javascript">
2452<!--//--><![CDATA[//><!--
2453	function bar_refresh() {
2454		var b = document.getElementById("bar");
2455		var i,j,x;
2456		if (b) {
2457			var x = b.getElementsByTagName("td");
2458			for (i=0 ; i<x.length ; i++) {
2459				x[i].innerHTML = "";
2460			}
2461			for (i=0 ; i<x.length ; i++) {
2462				var width = x[i].clientWidth;
2463				var label = bar_labels[i];
2464				var tooltip = bar_tooltips[i];
2465				x[i].innerHTML = "<a title='" + tooltip + "'>" + label + "</a>";
2466				if (width<x[i].clientWidth) {
2467					x[i].innerHTML = "<a title='" + tooltip + "'>&#8230;</a>";
2468					if (width<x[i].clientWidth) {
2469						x[i].innerHTML = "<a title='" + tooltip + "'>&#8226;</a>";
2470						if (width<x[i].clientWidth) {
2471							x[i].innerHTML = "<a title='" + tooltip + "'>.</a>";
2472							if (width<x[i].clientWidth) {
2473								x[i].innerHTML = "";
2474							}
2475						}
2476					} else {
2477						for (j=1 ; j<bar_labels[i].length-1 ; j++) {
2478							x[i].innerHTML = "<a title='" + tooltip + "'>"+label.substring(0,j) + "&#8230;</a>";
2479							if (width<x[i].clientWidth) {
2480								break;
2481							}
2482						}
2483						x[i].innerHTML = "<a title='" + tooltip + "'>" + label.substring(0,j-1) + "&#8230;</a>";
2484					}
2485				}
2486			}
2487		}
2488	}
2489
2490	function bar_add_event(obj,type,fn) {
2491		if (obj.addEventListener) {
2492			obj.addEventListener(type, fn, false);
2493		} else if (obj.attachEvent) {
2494			obj.attachEvent('on'+type, fn);
2495		}
2496	}
2497
2498	bar_add_event(window,"load",bar_refresh);
2499	bar_add_event(window,"resize",bar_refresh);
2500//--><!]]>
2501</script>""")
2502						out.append("""		</td>""")
2503						out.append("""	</tr>""")
2504					out.append("""</table>""")
2505					print("\n".join(out))
2506				else:
2507					if ttymode:
2508						tab = Tabble("Memory Usage Detailed Info",5)
2509						tab.defattr("l","r","r","r","r")
2510						tab.header("object name","memory used","memory allocated","utilization percent","percent of total allocated memory")
2511					else:
2512						tab = Tabble("memory usage detailed info",3)
2513						tab.defattr("l","r","r")
2514						tab.header("object name","memory used","memory allocated")
2515					for i in xrange(11):
2516						if ttymode:
2517							if memusage[i*2]>0:
2518								upercent = "%.2f %%" % (100.0 * memusage[1+i*2] / memusage[i*2])
2519							else:
2520								upercent = "-"
2521							if totalallocated:
2522								tpercent = "%.2f %%" % (100.0 * memusage[i*2] / totalallocated)
2523							else:
2524								tpercent = "-"
2525							tab.append(memlabels[i],humanize_number(memusage[1+i*2]," "),humanize_number(memusage[i*2]," "),upercent,tpercent)
2526						else:
2527							tab.append(memlabels[i],memusage[1+i*2],memusage[i*2])
2528					if ttymode:
2529						tab.append(("---","",5))
2530						percent = 100.0 * totalused / totalallocated
2531						tab.append("total",humanize_number(totalused," "),humanize_number(totalallocated," "),"%.2f %%" % percent,"-")
2532					print(tab)
2533		except Exception:
2534			print_exception()
2535
2536	if "IC" in sectionsubset:
2537		if needseparator:
2538			if cgimode:
2539				print("""<br/>""")
2540			else:
2541				print("")
2542		else:
2543			needseparator=1
2544		try:
2545			if leaderconn.version_less_than(1,7,0):
2546				data,length = leaderconn.command(CLTOMA_CHUNKS_MATRIX,MATOCL_CHUNKS_MATRIX,struct.pack(">B",0))
2547				if length==484:
2548					matrix = []
2549					matrix.append([])
2550					for i in range(11):
2551						matrix[0].append(list(struct.unpack(">LLLLLLLLLLL",data[i*44:i*44+44])))
2552					data,length = leaderconn.command(CLTOMA_CHUNKS_MATRIX,MATOCL_CHUNKS_MATRIX,struct.pack(">B",1))
2553					if length==484:
2554						matrix.append([])
2555						for i in range(11):
2556							matrix[1].append(list(struct.unpack(">LLLLLLLLLLL",data[i*44:i*44+44])))
2557				progressstatus = 0
2558			else:
2559				data,length = leaderconn.command(CLTOMA_CHUNKS_MATRIX,MATOCL_CHUNKS_MATRIX)
2560				if length==969:
2561					progressstatus = struct.unpack(">B",data[0:1])[0]
2562					matrix = ([],[])
2563					for x in range(2):
2564						for i in range(11):
2565							matrix[x].append(list(struct.unpack(">LLLLLLLLLLL",data[1+x*484+i*44:45+x*484+i*44])))
2566			progressstr = "disconnections" if (progressstatus==1) else "connections" if (progressstatus==2) else "connections and disconnections"
2567			if len(matrix)==2:
2568				if cgimode:
2569					out = []
2570					out.append("""<table class="acid_tab acid_tab_storageid_mfsmatrix" cellspacing="0" id="mfsmatrix">""")
2571					out.append("""	<tr><th colspan="13">""")
2572					out.append("""		<span class="matrix_vis0">All chunks state matrix (counts 'regular' hdd space and 'marked for removal' hdd space : <a href="javascript:acid_tab.switchdisplay('mfsmatrix','matrix_vis',1)" class="VISIBLELINK">switch to 'regular'</a>)</span>""")
2573					out.append("""		<span class="matrix_vis1">Regular chunks state matrix (counts only 'regular' hdd space : <a href="javascript:acid_tab.switchdisplay('mfsmatrix','matrix_vis',0)" class="VISIBLELINK">switch to 'all'</a>)</span>""")
2574					out.append("""	</th></tr>""")
2575					if progressstatus>0:
2576						out.append("""<tr><th colspan="13"><span class="ERROR">Warning: counters may not be valid - %s in progress</span></th></tr>""" % progressstr)
2577					out.append("""	<tr>""")
2578					out.append("""		<th rowspan="2" class="PERC4 acid_tab_skip">goal</th>""")
2579					out.append("""		<th colspan="12" class="PERC96 acid_tab_skip">valid copies</th>""")
2580					out.append("""	</tr>""")
2581					out.append("""	<tr>""")
2582					out.append("""		<th class="PERC8 acid_tab_skip">0</th>""")
2583					out.append("""		<th class="PERC8 acid_tab_skip">1</th>""")
2584					out.append("""		<th class="PERC8 acid_tab_skip">2</th>""")
2585					out.append("""		<th class="PERC8 acid_tab_skip">3</th>""")
2586					out.append("""		<th class="PERC8 acid_tab_skip">4</th>""")
2587					out.append("""		<th class="PERC8 acid_tab_skip">5</th>""")
2588					out.append("""		<th class="PERC8 acid_tab_skip">6</th>""")
2589					out.append("""		<th class="PERC8 acid_tab_skip">7</th>""")
2590					out.append("""		<th class="PERC8 acid_tab_skip">8</th>""")
2591					out.append("""		<th class="PERC8 acid_tab_skip">9</th>""")
2592					out.append("""		<th class="PERC8 acid_tab_skip">10+</th>""")
2593					out.append("""		<th class="PERC8 acid_tab_skip">all</th>""")
2594					out.append("""	</tr>""")
2595				elif ttymode:
2596					if INmatrix==0:
2597						tab = Tabble("All chunks state matrix",13,"r")
2598					else:
2599						tab = Tabble("Regular chunks state matrix",13,"r")
2600					if progressstatus>0:
2601						tab.header(("Warning: counters may not be valid - %s in progress" % progressstr,"1c",13))
2602						tab.header(("---","",13))
2603					tab.header("",("valid copies","",12))
2604					tab.header("goal",("---","",12))
2605					tab.header("","    0    ","    1    ","    2    ","    3    ","    4    ","    5    ","    6    ","    7    ","    8    ","    9    ","   10+   ","   all   ")
2606				else:
2607					out = []
2608					if INmatrix==0:
2609						mtypeprefix=("all chunks matrix:%s" % plaintextseparator)
2610					else:
2611						mtypeprefix=("regular chunks matrix:%s" % plaintextseparator)
2612				classsum = []
2613				classsum.append(7*[0])
2614				classsum.append(7*[0])
2615				sumlist = []
2616				sumlist.append(11*[0])
2617				sumlist.append(11*[0])
2618				for goal in range(11):
2619					if cgimode:
2620						out.append("""	<tr>""")
2621						if goal==10:
2622							out.append("""		<th align="center" class="acid_tab_skip">10+</th>""")
2623						else:
2624							out.append("""		<th align="center" class="acid_tab_skip">%u</th>""" % goal)
2625					else:
2626						if goal==10:
2627							clist = ["10+"]
2628						else:
2629							clist = [goal]
2630					for vc in range(11):
2631						if goal==0:
2632							if vc==0:
2633								cl = "DELETEREADY"
2634								clidx = 6
2635							else:
2636								cl = "DELETEPENDING"
2637								clidx = 5
2638						elif vc==0:
2639							cl = "MISSING"
2640							clidx = 0
2641						elif vc>goal:
2642							cl = "OVERGOAL"
2643							clidx = 4
2644						elif vc<goal:
2645							if vc==1:
2646								cl = "ENDANGERED"
2647								clidx = 1
2648							else:
2649								cl = "UNDERGOAL"
2650								clidx = 2
2651						else:
2652							cl = "NORMAL"
2653							clidx = 3
2654						classsum[0][clidx]+=matrix[0][goal][vc]
2655						classsum[1][clidx]+=matrix[1][goal][vc]
2656						if cgimode:
2657							out.append("""		<td align="right" class="acid_tab_skip">""")
2658							if matrix[0][goal][vc]>0:
2659								out.append("""			<span class="%s matrix_vis0">%u</span>""" % (cl,matrix[0][goal][vc]))
2660							if matrix[1][goal][vc]>0:
2661								out.append("""			<span class="%s matrix_vis1">%u</span>""" % (cl,matrix[1][goal][vc]))
2662							out.append("""		</td>""")
2663						elif ttymode:
2664							if matrix[INmatrix][goal][vc]>0:
2665								clist.append((matrix[INmatrix][goal][vc],"1234678"[clidx]))
2666							else:
2667								clist.append("-")
2668						else:
2669							if matrix[INmatrix][goal][vc]>0:
2670								out.append("""%sgoal/copies/chunks:%s%u%s%u%s%u""" % (mtypeprefix,plaintextseparator,goal,plaintextseparator,vc,plaintextseparator,matrix[INmatrix][goal][vc]))
2671					if cgimode:
2672						if goal==0:
2673							out.append("""		<td align="right" class="acid_tab_skip">""")
2674							out.append("""			<span class="IGNORE matrix_vis0">%u</span>""" % sum(matrix[0][goal]))
2675							out.append("""			<span class="IGNORE matrix_vis1">%u</span>""" % sum(matrix[1][goal]))
2676							out.append("""		</td>""")
2677						else:
2678							out.append("""		<td align="right" class="acid_tab_skip">""")
2679							out.append("""			<span class="matrix_vis0">%u</span>""" % sum(matrix[0][goal]))
2680							out.append("""			<span class="matrix_vis1">%u</span>""" % sum(matrix[1][goal]))
2681							out.append("""		</td>""")
2682						out.append("""	</tr>""")
2683					elif ttymode:
2684						clist.append(sum(matrix[INmatrix][goal]))
2685						tab.append(*clist)
2686					if goal>0:
2687						sumlist[0] = [ a + b for (a,b) in zip(sumlist[0],matrix[0][goal])]
2688						sumlist[1] = [ a + b for (a,b) in zip(sumlist[1],matrix[1][goal])]
2689				if cgimode:
2690					out.append("""	<tr>""")
2691					out.append("""		<th align="center" class="acid_tab_skip">all 1+</th>""")
2692					for vc in range(11):
2693						out.append("""		<td align="right" class="acid_tab_skip"><span class="matrix_vis0">%u</span><span class="matrix_vis1">%u</span></td>""" % (sumlist[0][vc],sumlist[1][vc]))
2694					out.append("""		<td align="right" class="acid_tab_skip"><span class="matrix_vis0">%u</span><span class="matrix_vis1">%u</span></td>""" % (sum(sumlist[0]),sum(sumlist[1])))
2695					out.append("""	</tr>""")
2696					out.append("""	<tr><th align="center" class="acid_tab_skip">colors</th><td colspan="12" class="acid_tab_skip">""")
2697					out.append("""		<span class="matrix_vis0">"""+(" / ".join(["""<span class="%sBOX"></span>&nbsp;-&nbsp;%s (<span class="%s">%u</span>)""" % (cl,desc,cl,classsum[0][clidx]) for clidx,cl,desc in [(0,"MISSING","missing"),(1,"ENDANGERED","endangered"),(2,"UNDERGOAL","undergoal"),(3,"NORMAL","stable"),(4,"OVERGOAL","overgoal"),(5,"DELETEPENDING","pending&nbsp;deletion"),(6,"DELETEREADY","ready&nbsp;to&nbsp;be&nbsp;removed")]]))+"</span>")
2698					out.append("""		<span class="matrix_vis1">"""+(" / ".join(["""<span class="%sBOX"></span>&nbsp;-&nbsp;%s (<span class="%s">%u</span>)""" % (cl,desc,cl,classsum[1][clidx]) for clidx,cl,desc in [(0,"MISSING","missing"),(1,"ENDANGERED","endangered"),(2,"UNDERGOAL","undergoal"),(3,"NORMAL","stable"),(4,"OVERGOAL","overgoal"),(5,"DELETEPENDING","pending&nbsp;deletion"),(6,"DELETEREADY","ready&nbsp;to&nbsp;be&nbsp;removed")]]))+"</span>")
2699					out.append("""	</td></tr>""")
2700					out.append("""</table>""")
2701					print("\n".join(out))
2702				elif ttymode:
2703					clist = ["all 1+"]
2704					for vc in range(11):
2705						clist.append(sumlist[INmatrix][vc])
2706					clist.append(sum(sumlist[INmatrix]))
2707					tab.append(*clist)
2708					tab.append(("---","",13))
2709					#tab.append(("missing: %s%u%s / endangered: %s%u%s / undergoal: %s%u%s / stable: %s%u%s / overgoal: %s%u%s / pending deletion: %s%u%s / to be removed: %s%u%s" % (colorcode[0],classsum[0],ttyreset,colorcode[1],classsum[1],ttyreset,colorcode[2],classsum[2],ttyreset,colorcode[3],classsum[3],ttyreset,colorcode[5],classsum[4],ttyreset,colorcode[6],classsum[5],ttyreset,colorcode[7],classsum[6],ttyreset),"c",13))
2710					tab.append(("missing: %u / endangered: %u / undergoal: %u / stable: %u / overgoal: %u / pending deletion: %u / to be removed: %u" % (classsum[INmatrix][0],classsum[INmatrix][1],classsum[INmatrix][2],classsum[INmatrix][3],classsum[INmatrix][4],classsum[INmatrix][5],classsum[INmatrix][6]),"c",13))
2711#							out.append("chunkclass missing: %s%u%s" % (colorcode[0],classsum[0],ttyreset))
2712#							out.append("chunkclass endangered: %s%u%s" % (colorcode[1],classsum[1],ttyreset))
2713#							out.append("chunkclass undergoal: %s%u%s" % (colorcode[2],classsum[2],ttyreset))
2714#							out.append("chunkclass stable: %s%u%s" % (colorcode[3],classsum[3],ttyreset))
2715#							out.append("chunkclass overgoal: %s%u%s" % (colorcode[4],classsum[4],ttyreset))
2716#							out.append("chunkclass pending deletion: %s%u%s" % (colorcode[5],classsum[5],ttyreset))
2717#							out.append("chunkclass to be removed: %s%u%s" % (colorcode[6],classsum[6],ttyreset))
2718					print(tab)
2719				else:
2720					out.append("%schunkclass missing:%s%u" % (mtypeprefix,plaintextseparator,classsum[INmatrix][0]))
2721					out.append("%schunkclass endangered:%s%u" % (mtypeprefix,plaintextseparator,classsum[INmatrix][1]))
2722					out.append("%schunkclass undergoal:%s%u" % (mtypeprefix,plaintextseparator,classsum[INmatrix][2]))
2723					out.append("%schunkclass stable:%s%u" % (mtypeprefix,plaintextseparator,classsum[INmatrix][3]))
2724					out.append("%schunkclass overgoal:%s%u" % (mtypeprefix,plaintextseparator,classsum[INmatrix][4]))
2725					out.append("%schunkclass pending deletion:%s%u" % (mtypeprefix,plaintextseparator,classsum[INmatrix][5]))
2726					out.append("%schunkclass to be removed:%s%u" % (mtypeprefix,plaintextseparator,classsum[INmatrix][6]))
2727					print("\n".join(out))
2728		except Exception:
2729			print_exception()
2730
2731	if "IL" in sectionsubset:
2732		try:
2733			if needseparator:
2734				if cgimode:
2735					print("""<br/>""")
2736				else:
2737					print("")
2738			else:
2739				needseparator=1
2740			data,length = leaderconn.command(CLTOMA_CHUNKSTEST_INFO,MATOCL_CHUNKSTEST_INFO)
2741			if length==52:
2742				loopstart,loopend,del_invalid,ndel_invalid,del_unused,ndel_unused,del_dclean,ndel_dclean,del_ogoal,ndel_ogoal,rep_ugoal,nrep_ugoal,rebalnce = struct.unpack(">LLLLLLLLLLLLL",data)
2743				if cgimode:
2744					out = []
2745					out.append("""<table class="FR" cellspacing="0">""")
2746					out.append("""	<tr><th colspan="8">Chunk operations info</th></tr>""")
2747					out.append("""	<tr>""")
2748					out.append("""		<th colspan="2">loop time</th>""")
2749					out.append("""		<th colspan="4">deletions</th>""")
2750					out.append("""		<th colspan="2">replications</th>""")
2751					out.append("""	</tr>""")
2752					out.append("""	<tr>""")
2753					out.append("""		<th>start</th>""")
2754					out.append("""		<th>end</th>""")
2755					out.append("""		<th>invalid</th>""")
2756					out.append("""		<th>unused</th>""")
2757					out.append("""		<th>disk clean</th>""")
2758					out.append("""		<th>over goal</th>""")
2759					out.append("""		<th>under goal</th>""")
2760					out.append("""		<th>rebalance</th>""")
2761					out.append("""	</tr>""")
2762					if loopstart>0:
2763						out.append("""	<tr>""")
2764						out.append("""		<td align="center">%s</td>""" % (time.asctime(time.localtime(loopstart)),))
2765						out.append("""		<td align="center">%s</td>""" % (time.asctime(time.localtime(loopend)),))
2766						out.append("""		<td align="right">%u/%u</td>""" % (del_invalid,del_invalid+ndel_invalid))
2767						out.append("""		<td align="right">%u/%u</td>""" % (del_unused,del_unused+ndel_unused))
2768						out.append("""		<td align="right">%u/%u</td>""" % (del_dclean,del_dclean+ndel_dclean))
2769						out.append("""		<td align="right">%u/%u</td>""" % (del_ogoal,del_ogoal+ndel_ogoal))
2770						out.append("""		<td align="right">%u/%u</td>""" % (rep_ugoal,rep_ugoal+nrep_ugoal))
2771						out.append("""		<td align="right">%u</td>""" % rebalnce)
2772						out.append("""	</tr>""")
2773					else:
2774						out.append("""	<tr>""")
2775						out.append("""		<td colspan="8" align="center">no data</td>""")
2776						out.append("""	</tr>""")
2777					out.append("""</table>""")
2778					print("\n".join(out))
2779				elif ttymode:
2780					tab = Tabble("Chunk operations info",8,"r")
2781					tab.header(("loop time","",2),("deletions","",4),("replications","",2))
2782					tab.header(("---","",8))
2783					tab.header("start","end","invalid","unused","disk clean","over goal","under goal","rebalance")
2784					if loopstart>0:
2785						tab.append((time.asctime(time.localtime(loopstart)),"c"),(time.asctime(time.localtime(loopend)),"c"),"%u/%u" % (del_invalid,del_invalid+ndel_invalid),"%u/%u" % (del_unused,del_unused+ndel_unused),"%u/%u" % (del_dclean,del_dclean+ndel_dclean),"%u/%u" % (del_ogoal,del_ogoal+ndel_ogoal),"%u/%u" % (rep_ugoal,rep_ugoal+nrep_ugoal),rebalnce)
2786					else:
2787						tab.append(("no data","c",8))
2788					print(tab)
2789				else:
2790					out = []
2791					if loopstart>0:
2792						out.append("""chunk loop%sstart:%s%u""" % (plaintextseparator,plaintextseparator,loopstart))
2793						out.append("""chunk loop%send:%s%u""" % (plaintextseparator,plaintextseparator,loopend))
2794						out.append("""chunk loop%sdeletions%sinvalid:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_invalid,del_invalid+ndel_invalid))
2795						out.append("""chunk loop%sdeletions%sunused:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_unused,del_unused+ndel_unused))
2796						out.append("""chunk loop%sdeletions%sdisk clean:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_dclean,del_dclean+ndel_dclean))
2797						out.append("""chunk loop%sdeletions%sover goal:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_ogoal,del_ogoal+ndel_ogoal))
2798						out.append("""chunk loop%sreplications%sunder goal:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,rep_ugoal,rep_ugoal+nrep_ugoal))
2799						out.append("""chunk loop%sreplications%srebalance:%s%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,rebalnce))
2800					else:
2801						out.append("""chunk loop%sno data""" % plaintextseparator)
2802					print("\n".join(out))
2803			elif length==60:
2804				loopstart,loopend,del_invalid,ndel_invalid,del_unused,ndel_unused,del_dclean,ndel_dclean,del_ogoal,ndel_ogoal,rep_ugoal,nrep_ugoal,rebalnce,locked_unused,locked_used = struct.unpack(">LLLLLLLLLLLLLLL",data)
2805				if cgimode:
2806					out = []
2807					out.append("""<table class="FR" cellspacing="0">""")
2808					out.append("""	<tr><th colspan="10">Chunk operations info</th></tr>""")
2809					out.append("""	<tr>""")
2810					out.append("""		<th colspan="2">loop time</th>""")
2811					out.append("""		<th colspan="4">deletions</th>""")
2812					out.append("""		<th colspan="2">replications</th>""")
2813					out.append("""		<th colspan="2">locked</th>""")
2814					out.append("""	</tr>""")
2815					out.append("""	<tr>""")
2816					out.append("""		<th>start</th>""")
2817					out.append("""		<th>end</th>""")
2818					out.append("""		<th>invalid</th>""")
2819					out.append("""		<th>unused</th>""")
2820					out.append("""		<th>disk clean</th>""")
2821					out.append("""		<th>over goal</th>""")
2822					out.append("""		<th>under goal</th>""")
2823					out.append("""		<th>rebalance</th>""")
2824					out.append("""		<th>unused</th>""")
2825					out.append("""		<th>used</th>""")
2826					out.append("""	</tr>""")
2827					if loopstart>0:
2828						out.append("""	<tr>""")
2829						out.append("""		<td align="center">%s</td>""" % (time.asctime(time.localtime(loopstart)),))
2830						out.append("""		<td align="center">%s</td>""" % (time.asctime(time.localtime(loopend)),))
2831						out.append("""		<td align="right">%u/%u</td>""" % (del_invalid,del_invalid+ndel_invalid))
2832						out.append("""		<td align="right">%u/%u</td>""" % (del_unused,del_unused+ndel_unused))
2833						out.append("""		<td align="right">%u/%u</td>""" % (del_dclean,del_dclean+ndel_dclean))
2834						out.append("""		<td align="right">%u/%u</td>""" % (del_ogoal,del_ogoal+ndel_ogoal))
2835						out.append("""		<td align="right">%u/%u</td>""" % (rep_ugoal,rep_ugoal+nrep_ugoal))
2836						out.append("""		<td align="right">%u</td>""" % rebalnce)
2837						out.append("""		<td align="right">%u</td>""" % locked_unused)
2838						out.append("""		<td align="right">%u</td>""" % locked_used)
2839						out.append("""	</tr>""")
2840					else:
2841						out.append("""	<tr>""")
2842						out.append("""		<td colspan="10" align="center">no data</td>""")
2843						out.append("""	</tr>""")
2844					out.append("""</table>""")
2845					print("\n".join(out))
2846				elif ttymode:
2847					tab = Tabble("Chunk operations info",10,"r")
2848					tab.header(("loop time","",2),("deletions","",4),("replications","",2),("locked","",2))
2849					tab.header(("---","",10))
2850					tab.header("start","end","invalid","unused","disk clean","over goal","under goal","rebalance","unused","used")
2851					if loopstart>0:
2852						tab.append((time.asctime(time.localtime(loopstart)),"c"),(time.asctime(time.localtime(loopend)),"c"),"%u/%u" % (del_invalid,del_invalid+ndel_invalid),"%u/%u" % (del_unused,del_unused+ndel_unused),"%u/%u" % (del_dclean,del_dclean+ndel_dclean),"%u/%u" % (del_ogoal,del_ogoal+ndel_ogoal),"%u/%u" % (rep_ugoal,rep_ugoal+nrep_ugoal),rebalnce,locked_unused,locked_used)
2853					else:
2854						tab.append(("no data","c",10))
2855					print(tab)
2856				else:
2857					out = []
2858					if loopstart>0:
2859						out.append("""chunk loop%sstart:%s%u""" % (plaintextseparator,plaintextseparator,loopstart))
2860						out.append("""chunk loop%send:%s%u""" % (plaintextseparator,plaintextseparator,loopend))
2861						out.append("""chunk loop%sdeletions%sinvalid:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_invalid,del_invalid+ndel_invalid))
2862						out.append("""chunk loop%sdeletions%sunused:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_unused,del_unused+ndel_unused))
2863						out.append("""chunk loop%sdeletions%sdisk clean:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_dclean,del_dclean+ndel_dclean))
2864						out.append("""chunk loop%sdeletions%sover goal:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_ogoal,del_ogoal+ndel_ogoal))
2865						out.append("""chunk loop%sreplications%sunder goal:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,rep_ugoal,rep_ugoal+nrep_ugoal))
2866						out.append("""chunk loop%sreplications%srebalance:%s%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,rebalnce))
2867						out.append("""chunk loop%slocked%sunused:%s%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,locked_unused))
2868						out.append("""chunk loop%slocked%sused:%s%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,locked_used))
2869					else:
2870						out.append("""chunk loop%sno data""" % plaintextseparator)
2871					print("\n".join(out))
2872		except Exception:
2873			print_exception()
2874
2875		try:
2876			if needseparator:
2877				if cgimode:
2878					print("""<br/>""")
2879				else:
2880					print("")
2881			else:
2882				needseparator=1
2883			if (leaderconn.version_at_least(2,0,66) and leaderconn.version_less_than(3,0,0)) or leaderconn.version_at_least(3,0,19):
2884				data,length = leaderconn.command(CLTOMA_FSTEST_INFO,MATOCL_FSTEST_INFO,struct.pack(">B",0))
2885				pver = 1
2886			else:
2887				data,length = leaderconn.command(CLTOMA_FSTEST_INFO,MATOCL_FSTEST_INFO)
2888				pver = 0
2889			if length>=(36 + pver*8):
2890				if pver==1:
2891					loopstart,loopend,files,ugfiles,mfiles,mtfiles,msfiles,chunks,ugchunks,mchunks,msgbuffleng = struct.unpack(">LLLLLLLLLLL",data[:44])
2892					datastr = data[44:].decode('ascii')
2893				else:
2894					loopstart,loopend,files,ugfiles,mfiles,chunks,ugchunks,mchunks,msgbuffleng = struct.unpack(">LLLLLLLLL",data[:36])
2895					datastr = data[36:].decode('ascii')
2896				if cgimode:
2897					out = []
2898					out.append("""<table class="FR" cellspacing="0">""")
2899					out.append("""	<tr><th colspan="%u">Filesystem check info</th></tr>""" % (8 if pver==0 else 10))
2900					out.append("""	<tr>""")
2901					out.append("""		<th>check loop start time</th>""")
2902					out.append("""		<th>check loop end time</th>""")
2903					out.append("""		<th>files</th>""")
2904					out.append("""		<th>under-goal files</th>""")
2905					out.append("""		<th>missing files</th>""")
2906					if pver==1:
2907						out.append("""		<th>missing trash files</th>""")
2908						out.append("""		<th>missing sustained files</th>""")
2909					out.append("""		<th>chunks</th>""")
2910					out.append("""		<th>under-goal chunks</th>""")
2911					out.append("""		<th>missing chunks</th>""")
2912					out.append("""	</tr>""")
2913					if loopstart>0:
2914						out.append("""	<tr>""")
2915						out.append("""		<td align="center">%s</td>""" % (time.asctime(time.localtime(loopstart)),))
2916						out.append("""		<td align="center">%s</td>""" % (time.asctime(time.localtime(loopend)),))
2917						out.append("""		<td align="right">%u</td>""" % files)
2918						out.append("""		<td align="right">%u</td>""" % ugfiles)
2919						out.append("""		<td align="right">%u</td>""" % mfiles)
2920						if pver==1:
2921							out.append("""		<td align="right">%u</td>""" % mtfiles)
2922							out.append("""		<td align="right">%u</td>""" % msfiles)
2923						out.append("""		<td align="right">%u</td>""" % chunks)
2924						out.append("""		<td align="right">%u</td>""" % ugchunks)
2925						out.append("""		<td align="right">%u</td>""" % mchunks)
2926						out.append("""	</tr>""")
2927						if msgbuffleng>0:
2928							if msgbuffleng==100000:
2929								out.append("""	<tr><th colspan="8">Important messages (first 100k):</th></tr>""")
2930							else:
2931								out.append("""	<tr><th colspan="8">Important messages:</th></tr>""")
2932							out.append("""	<tr>""")
2933							out.append("""		<td colspan="8" align="left"><pre>%s</pre></td>""" % (datastr.replace("&","&amp;").replace(">","&gt;").replace("<","&lt;")))
2934							out.append("""	</tr>""")
2935					else:
2936						out.append("""	<tr>""")
2937						out.append("""		<td colspan="%u" align="center">no data</td>""" % (8 if pver==0 else 10))
2938						out.append("""	</tr>""")
2939					out.append("""</table>""")
2940					print("\n".join(out))
2941				elif ttymode:
2942					if pver==1:
2943						tab = Tabble("Filesystem check info",10,"r")
2944						tabwidth = 10
2945						tab.header("check loop start time","check loop end time","files","under-goal files","missing files","missing trash files","missing sustained files","chunks","under-goal chunks","missing chunks")
2946					else:
2947						tab = Tabble("Filesystem check info",8,"r")
2948						tabwidth = 8
2949						tab.header("check loop start time","check loop end time","files","under-goal files","missing files","chunks","under-goal chunks","missing chunks")
2950					if loopstart>0:
2951						if pver==1:
2952							tab.append((time.asctime(time.localtime(loopstart)),"c"),(time.asctime(time.localtime(loopend)),"c"),files,ugfiles,mfiles,mtfiles,msfiles,chunks,ugchunks,mchunks)
2953						else:
2954							tab.append((time.asctime(time.localtime(loopstart)),"c"),(time.asctime(time.localtime(loopend)),"c"),files,ugfiles,mfiles,chunks,ugchunks,mchunks)
2955						if msgbuffleng>0:
2956							tab.append(("---","",tabwidth))
2957							if msgbuffleng==100000:
2958								tab.append(("Important messages (first 100k):","c",tabwidth))
2959							else:
2960								tab.append(("Important messages:","c",tabwidth))
2961							tab.append(("---","",tabwidth))
2962							for line in datastr.strip().split("\n"):
2963								tab.append((line.strip(),"l",tabwidth))
2964					else:
2965						tab.append(("no data","c",tabwidth))
2966					print(tab)
2967				else:
2968					out = []
2969					if loopstart>0:
2970						out.append("""check loop%sstart:%s%u""" % (plaintextseparator,plaintextseparator,loopstart))
2971						out.append("""check loop%send:%s%u""" % (plaintextseparator,plaintextseparator,loopend))
2972						out.append("""check loop%sfiles:%s%u""" % (plaintextseparator,plaintextseparator,files))
2973						out.append("""check loop%sunder-goal files:%s%u""" % (plaintextseparator,plaintextseparator,ugfiles))
2974						out.append("""check loop%smissing files:%s%u""" % (plaintextseparator,plaintextseparator,mfiles))
2975						if pver==1:
2976							out.append("""check loop%smissing trash files:%s%u""" % (plaintextseparator,plaintextseparator,mtfiles))
2977							out.append("""check loop%smissing sustained files:%s%u""" % (plaintextseparator,plaintextseparator,msfiles))
2978						out.append("""check loop%schunks:%s%u""" % (plaintextseparator,plaintextseparator,chunks))
2979						out.append("""check loop%sunder-goal chunks:%s%u""" % (plaintextseparator,plaintextseparator,ugchunks))
2980						out.append("""check loop%smissing chunks:%s%u""" % (plaintextseparator,plaintextseparator,mchunks))
2981						if msgbuffleng>0:
2982							for line in datastr.strip().split("\n"):
2983								out.append("check loop%simportant messages:%s%s" % (plaintextseparator,plaintextseparator,line.strip()))
2984					else:
2985						out.append("""check loop: no data""")
2986					print("\n".join(out))
2987		except Exception:
2988			print_exception()
2989
2990	if "MF" in sectionsubset and ((leaderconn.version_at_least(2,0,66) and leaderconn.version_less_than(3,0,0)) or leaderconn.version_at_least(3,0,19)):
2991		try:
2992			if needseparator:
2993				if cgimode:
2994					print("""<br/>""")
2995				else:
2996					print("")
2997			else:
2998				needseparator=1
2999			inodes = set()
3000			missingchunks = []
3001			if ((leaderconn.version_at_least(2,0,71) and leaderconn.version_less_than(3,0,0)) or leaderconn.version_at_least(3,0,25)):
3002				data,length = leaderconn.command(CLTOMA_MISSING_CHUNKS,MATOCL_MISSING_CHUNKS,struct.pack(">B",1))
3003				if length%17==0:
3004					n = length//17
3005					for x in xrange(n):
3006						chunkid,inode,indx,mtype = struct.unpack(">QLLB",data[x*17:x*17+17])
3007						inodes.add(inode)
3008						missingchunks.append((chunkid,inode,indx,mtype))
3009				mode = 1
3010			else:
3011				data,length = leaderconn.command(CLTOMA_MISSING_CHUNKS,MATOCL_MISSING_CHUNKS)
3012				if length%16==0:
3013					n = length//16
3014					for x in xrange(n):
3015						chunkid,inode,indx = struct.unpack(">QLL",data[x*16:x*16+16])
3016						inodes.add(inode)
3017						missingchunks.append((chunkid,inode,indx,None))
3018				mode = 0
3019			inodepaths = resolve_inodes_paths(leaderconn,inodes)
3020			mcdata = []
3021			mccnt = 0
3022			for chunkid,inode,indx,mtype in missingchunks:
3023				if inode in inodepaths:
3024					paths = inodepaths[inode]
3025					mccnt += len(paths)
3026				else:
3027					paths = []
3028					mccnt += 1
3029				sf = paths
3030				if MForder==1:
3031					sf = paths
3032				elif MForder==2:
3033					sf = inode
3034				elif MForder==3:
3035					sf = indx
3036				elif MForder==4:
3037					sf = chunkid
3038				elif MForder==5:
3039					sf = mtype
3040				mcdata.append((sf,paths,inode,indx,chunkid,mtype))
3041			mcdata.sort()
3042			if MFrev:
3043				mcdata.reverse()
3044			if cgimode:
3045				out = []
3046				if mccnt>0:
3047					out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_missingfiles" cellspacing="0">""")
3048					if MFlimit>0 and mccnt>MFlimit:
3049						out.append("""	<tr><th colspan="%u">Missing files (gathered by previous file-loop) - %u/%u entries - <a href="%s" class="VISIBLELINK">show more</a> - <a href="%s" class="VISIBLELINK">show all</a></th></tr>""" % ((6 if mode==1 else 5),MFlimit,mccnt,createlink({"MFlimit":"%u" % (MFlimit + 100)}),createlink({"MFlimit":"0"})))
3050					else:
3051						out.append("""	<tr><th colspan="%u">Missing files (gathered by previous file-loop)</th></tr>""" % (6 if mode==1 else 5))
3052					out.append("""	<tr>""")
3053					out.append("""		<th rowspan="2" class="acid_tab_enumerate">#</th>""")
3054					out.append("""		<th rowspan="2">paths</th>""")
3055					out.append("""		<th rowspan="2">inode</th>""")
3056					out.append("""		<th rowspan="2">index</th>""")
3057					out.append("""		<th rowspan="2">chunk&nbsp;id</th>""")
3058					if mode==1:
3059						out.append("""		<th rowspan="2">type&nbsp;of&nbsp;missing&nbsp;chunk</th>""")
3060					out.append("""	</tr>""")
3061				else:
3062					needseparator=0
3063			elif ttymode:
3064				if mode==1:
3065					tab = Tabble("Missing Files/Chunks (gathered by previous file-loop)",5)
3066					tab.header("path","inode","index","chunk id","type of missing chunk")
3067					tab.defattr("l","r","r","r","r")
3068				else:
3069					tab = Tabble("Missing Files/Chunks (gathered by previous file-loop)",4)
3070					tab.header("path","inode","index","chunk id")
3071					tab.defattr("l","r","r","r")
3072			else:
3073				tab = Tabble("missing files",(5 if mode==1 else 4))
3074			missingcount = 0
3075			for sf,paths,inode,indx,chunkid,mtype in mcdata:
3076				if mtype==0:
3077					mtypestr = "NO COPY"
3078				elif mtype==1:
3079					mtypestr = "INVALID COPIES"
3080				elif mtype==2:
3081					mtypestr = "WRONG VERSIONS"
3082				else:
3083					mtypestr = "OTHER"
3084				if cgimode:
3085					if mccnt>0:
3086						if len(paths)==0:
3087							if missingcount<MFlimit or MFlimit==0:
3088								out.append("""	<tr>""")
3089								out.append("""		<td align="right"></td>""")
3090								out.append("""		<td align="left"> * unknown path * (deleted file)</td>""")
3091								out.append("""		<td align="right">%u</td>""" % inode)
3092								out.append("""		<td align="right">%u</td>""" % indx)
3093								out.append("""		<td align="right">%016X</td>""" % chunkid)
3094								if mode==1:
3095									out.append("""		<td align="right">%s</td>""" % mtypestr)
3096								out.append("""	</tr>""")
3097							missingcount += 1
3098						else:
3099							for path in paths:
3100								if missingcount<MFlimit or MFlimit==0:
3101									out.append("""	<tr>""")
3102									out.append("""		<td align="right"></td>""")
3103									out.append("""		<td align="left">%s</td>""" % path)
3104									out.append("""		<td align="right">%u</td>""" % inode)
3105									out.append("""		<td align="right">%u</td>""" % indx)
3106									out.append("""		<td align="right">%016X</td>""" % chunkid)
3107									if mode==1:
3108										out.append("""		<td align="right">%s</td>""" % mtypestr)
3109									out.append("""	</tr>""")
3110								missingcount += 1
3111				else:
3112					if len(paths)==0:
3113						dline = [" * unknown path * (deleted file)",inode,indx,chunkid]
3114						if mode==1:
3115							dline.append(mtypestr)
3116						tab.append(*dline)
3117					else:
3118						for path in paths:
3119							dline = [path,inode,indx,chunkid]
3120							if mode==1:
3121								dline.append(mtypestr)
3122							tab.append(*dline)
3123			if cgimode:
3124				if mccnt>0:
3125					out.append("""</table>""")
3126				print("\n".join(out))
3127			else:
3128				print(tab)
3129		except Exception:
3130			print_exception()
3131
3132if "CS" in sectionset:
3133	if "CS" in sectionsubset:
3134		if needseparator:
3135			if cgimode:
3136				print("""<br/>""")
3137			else:
3138				print("")
3139		else:
3140			needseparator=1
3141
3142		try:
3143			if cgimode:
3144				out = []
3145				out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfscs" cellspacing="0">""")
3146				if leaderconn.version_at_least(2,0,11):
3147					out.append("""	<tr><th colspan="17">Chunk Servers</th></tr>""")
3148				elif leaderconn.version_at_least(1,7,25):
3149					out.append("""	<tr><th colspan="16">Chunk Servers</th></tr>""")
3150				elif leaderconn.version_at_least(1,6,28):
3151					out.append("""	<tr><th colspan="15">Chunk Servers</th></tr>""")
3152				else:
3153					out.append("""	<tr><th colspan="14">Chunk Servers</th></tr>""")
3154				out.append("""	<tr>""")
3155				out.append("""		<th rowspan="2" class="acid_tab_enumerate">#</th>""")
3156				out.append("""		<th rowspan="2">host</th>""")
3157				out.append("""		<th rowspan="2">ip</th>""")
3158				out.append("""		<th rowspan="2">port</th>""")
3159				if leaderconn.version_at_least(1,7,25):
3160					out.append("""		<th rowspan="2">id</th>""")
3161				out.append("""		<th rowspan="2">version</th>""")
3162				if leaderconn.version_at_least(1,6,28):
3163					out.append("""		<th rowspan="2">load</th>""")
3164				if leaderconn.version_at_least(2,0,11):
3165					out.append("""		<th rowspan="2">maintenance</th>""")
3166				out.append("""		<th colspan="4">'regular' hdd space</th>""")
3167				out.append("""		<th colspan="4">'marked for removal' hdd space</th>""")
3168				out.append("""	</tr>""")
3169				out.append("""	<tr>""")
3170				out.append("""		<th>chunks</th>""")
3171				out.append("""		<th>used</th>""")
3172				out.append("""		<th>total</th>""")
3173				out.append("""		<th class="PROGBAR">% used</th>""")
3174				out.append("""		<th>chunks</th>""")
3175				out.append("""		<th>used</th>""")
3176				out.append("""		<th>total</th>""")
3177				out.append("""		<th class="PROGBAR">% used</th>""")
3178				out.append("""	</tr>""")
3179			elif ttymode:
3180				if leaderconn.version_at_least(2,0,11):
3181					tab = Tabble("Chunk Servers",14,"r")
3182					tab.header("","","","","","",("'regular' hdd space","",4),("'marked for removal' hdd space","",4))
3183					tab.header("ip/host","port","id","version","load","maintenance",("---","",8))
3184					tab.header("","","","","","","chunks","used","total","% used","chunks","used","total","% used")
3185				elif leaderconn.version_at_least(1,7,25):
3186					tab = Tabble("Chunk Servers",13,"r")
3187					tab.header("","","","","",("'regular' hdd space","",4),("'marked for removal' hdd space","",4))
3188					tab.header("ip/host","port","id","version","load",("---","",8))
3189					tab.header("","","","","","chunks","used","total","% used","chunks","used","total","% used")
3190				elif leaderconn.version_at_least(1,6,28):
3191					tab = Tabble("Chunk Servers",12,"r")
3192					tab.header("","","","",("'regular' hdd space","",4),("'marked for removal' hdd space","",4))
3193					tab.header("ip/host","port","version","load",("---","",8))
3194					tab.header("","","","","chunks","used","total","% used","chunks","used","total","% used")
3195				else:
3196					tab = Tabble("Chunk Servers",11,"r")
3197					tab.header("","","",("'regular' hdd space","",4),("'marked for removal' hdd space","",4))
3198					tab.header("ip/host","port","version",("---","",8))
3199					tab.header("","","","chunks","used","total","% used","chunks","used","total","% used")
3200			else:
3201				if leaderconn.version_at_least(2,0,11):
3202					tab = Tabble("chunk servers",12)
3203				elif leaderconn.version_at_least(1,7,25):
3204					tab = Tabble("chunk servers",11)
3205				elif leaderconn.version_at_least(1,6,28):
3206					tab = Tabble("chunk servers",10)
3207				else:
3208					tab = Tabble("chunk servers",9)
3209			data,length = leaderconn.command(CLTOMA_CSERV_LIST,MATOCL_CSERV_LIST)
3210			if leaderconn.version_at_least(1,7,25) and (length%64)==0:
3211				n = length//64
3212				servers = []
3213				dservers = []
3214				usedsum = 0
3215				totalsum = 0
3216				for i in range(n):
3217					d = data[i*64:(i+1)*64]
3218					flags,v1,v2,v3,ip1,ip2,ip3,ip4,port,csid,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime = struct.unpack(">BBBBBBBBHHQQLQQLLLL",d)
3219					strip = "%u.%u.%u.%u" % (ip1,ip2,ip3,ip4)
3220					sortip = "%03u_%03u_%03u_%03u" % (ip1,ip2,ip3,ip4)
3221					strver,sortver = version_str_and_sort((v1,v2,v3))
3222					host = resolve(strip)
3223					if total>0:
3224						usedsum+=used
3225						totalsum+=total
3226					if CSorder==1:
3227						sf = host
3228					elif CSorder==2 or CSorder==0:
3229						sf = sortip
3230					elif CSorder==3:
3231						sf = port
3232					elif CSorder==4:
3233						sf = csid
3234					elif CSorder==5:
3235						sf = sortver
3236					elif CSorder==6:
3237						sf = (gracetime,load)
3238					elif CSorder==10:
3239						sf = chunks
3240					elif CSorder==11:
3241						sf = used
3242					elif CSorder==12:
3243						sf = total
3244					elif CSorder==13:
3245						if total>0:
3246							sf = (1.0*used)/total
3247						else:
3248							sf = 0
3249					elif CSorder==20:
3250						sf = tdchunks
3251					elif CSorder==21:
3252						sf = tdused
3253					elif CSorder==22:
3254						sf = tdtotal
3255					elif CSorder==23:
3256						if tdtotal>0:
3257							sf = (1.0*tdused)/tdtotal
3258						else:
3259							sf = 0
3260					else:
3261						sf = 0
3262					if (flags&1)==0:
3263						servers.append((sf,host,sortip,strip,port,csid,sortver,strver,flags,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime))
3264					else:
3265						dservers.append((sf,host,sortip,strip,port,csid,flags))
3266				servers.sort()
3267				dservers.sort()
3268				if CSrev:
3269					servers.reverse()
3270					dservers.reverse()
3271				if totalsum>0:
3272					avgpercent = (usedsum*100.0)/totalsum
3273				else:
3274					avgpercent = 0
3275				for sf,host,sortip,strip,port,csid,sortver,strver,flags,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime in servers:
3276					if cgimode:
3277						if leaderconn.is_pro() and not strver.endswith(" PRO"):
3278							verclass = "BADVERSION"
3279						elif leaderconn.sort_ver() > sortver:
3280							verclass = "LOWERVERSION"
3281						elif leaderconn.sort_ver() < sortver:
3282							verclass = "HIGHERVERSION"
3283						else:
3284							verclass = "OKVERSION"
3285						if leaderconn.version_at_least(2,0,11):
3286							if (flags&2)==0:
3287								mm = "switch on"
3288								mmurl = createlink({"CSmaintenanceon":("%s:%u" % (strip,port))})
3289								cl = None
3290							else:
3291								mm = "switch off"
3292								mmurl = createlink({"CSmaintenanceoff":("%s:%u" % (strip,port))})
3293								cl = "MAINTAINREADY"
3294						else:
3295							cl = None
3296						out.append("""	<tr>""")
3297						out.append("""		<td align="right"></td>""")
3298						if cl:
3299							out.append("""		<td align="left"><span class="%s">%s</span></td>""" % (cl,host))
3300							out.append("""		<td align="center"><span class="sortkey">%s </span><span class="%s">%s</span></td>""" % (sortip,cl,strip))
3301							out.append("""		<td align="center"><span class="%s">%u</span></td>""" % (cl,port))
3302							out.append("""		<td align="center"><span class="%s">%u</span></td>""" % (cl,csid))
3303						else:
3304							out.append("""		<td align="left">%s</td>""" % (host))
3305							out.append("""		<td align="center"><span class="sortkey">%s </span>%s</td>""" % (sortip,strip))
3306							out.append("""		<td align="center">%u</td>""" % (port))
3307							out.append("""		<td align="center">%u</td>""" % (csid))
3308						out.append("""		<td align="center"><span class="sortkey">%s </span><span class="%s">%s</span></td>""" % (sortver,verclass,strver))
3309						if gracetime>0:
3310							out.append("""		<td align="right"><a style="cursor:default" title="back after %u seconds" href="%s"><span class="GRACETIME">[%u]</span></a></td>""" % (gracetime,createlink({"CSbacktowork":("%s:%u" % (strip,port))}),load))
3311						else:
3312							out.append("""		<td align="right">%u</td>""" % (load))
3313						if leaderconn.version_at_least(2,0,11):
3314							out.append("""		<td align="center"><a href="%s">%s</a></td>""" % (mmurl,mm))
3315						out.append("""		<td align="right">%u</td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td>""" % (chunks,used,decimal_number(used),humanize_number(used,"&nbsp;"),total,decimal_number(total),humanize_number(total,"&nbsp;")))
3316						if (total>0):
3317							usedpercent = (used*100.0)/total
3318							if usedpercent<avgpercent:
3319								diffstr = "&#8722;%.4f" % (avgpercent-usedpercent)
3320							else:
3321								diffstr = "+%.4f" % (usedpercent-avgpercent)
3322							out.append("""		<td align="center"><span class="sortkey">%.10f </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:%.2f%%;"></div><div class="PROGAVG" style="width:%.2f%%"></div><div class="PROGVALUE"><a style="cursor:default" title="%.4f%% = (avg%s%%)">%.2f</a></div></div></td>""" % (usedpercent,100.0-usedpercent,avgpercent,usedpercent,diffstr,usedpercent))
3323						else:
3324							out.append("""		<td align="center"><span class="sortkey">-1 </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:100%;"></div><div class="PROGVALUE">-</div></div></td>""")
3325						out.append("""		<td align="right">%u</td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td>""" % (tdchunks,tdused,decimal_number(tdused),humanize_number(tdused,"&nbsp;"),tdtotal,decimal_number(tdtotal),humanize_number(tdtotal,"&nbsp;")))
3326						if (tdtotal>0):
3327							usedpercent = (tdused*100.0)/tdtotal
3328							out.append("""		<td align="center"><span class="sortkey">%.10f </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:%.2f%%;"></div><div class="PROGVALUE">%.2f</div></div></td>""" % (usedpercent,100.0-usedpercent,usedpercent))
3329						else:
3330							out.append("""		<td align="center"><span class="sortkey">-1 </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:100%;"></div><div class="PROGVALUE">-</div></div></td>""")
3331						out.append("""	</tr>""")
3332					elif ttymode:
3333						if total>0:
3334							regperc = "%.2f%%" % ((used*100.0)/total)
3335						else:
3336							regperc = "-"
3337						if tdtotal>0:
3338							tdperc = "%.2f%%" % ((tdused*100.0)/tdtotal)
3339						else:
3340							tdperc = "-"
3341						if leaderconn.version_at_least(2,0,11):
3342							if (flags&2)==0:
3343								mm = "off"
3344							else:
3345								mm = "on"
3346							tab.append(host,port,csid,strver,load,mm,chunks,humanize_number(used," "),humanize_number(total," "),regperc,tdchunks,humanize_number(tdused," "),humanize_number(tdtotal," "),tdperc)
3347						else:
3348							tab.append(host,port,csid,strver,load,chunks,humanize_number(used," "),humanize_number(total," "),regperc,tdchunks,humanize_number(tdused," "),humanize_number(tdtotal," "),tdperc)
3349					else:
3350						if leaderconn.version_at_least(2,0,11):
3351							if (flags&2)==0:
3352								mm = "standard_mode"
3353							else:
3354								mm = "maintenance_mode"
3355							tab.append(host,port,csid,strver,load,mm,chunks,used,total,tdchunks,tdused,tdtotal)
3356						else:
3357							tab.append(host,port,csid,strver,load,chunks,used,total,tdchunks,tdused,tdtotal)
3358				if len(dservers)>0:
3359					if cgimode:
3360						out.append("""</table>""")
3361						out.append("""<br/>""")
3362						out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsdiscs" cellspacing="0">""")
3363						if leaderconn.version_at_least(2,0,11):
3364							out.append("""	<tr><th colspan="7">Disconnected Chunk Servers</th></tr>""")
3365						else:
3366							out.append("""	<tr><th colspan="6">Disconnected Chunk Servers</th></tr>""")
3367						out.append("""	<tr>""")
3368						out.append("""		<th class="acid_tab_enumerate">#</th>""")
3369						out.append("""		<th>host</th>""")
3370						out.append("""		<th>ip</th>""")
3371						out.append("""		<th>port</th>""")
3372						out.append("""		<th>id</th>""")
3373						if leaderconn.version_at_least(2,0,11):
3374							out.append("""		<th>maintenance</th>""")
3375						out.append("""		<th class="acid_tab_skip">remove</th>""")
3376						out.append("""	</tr>""")
3377					elif ttymode:
3378						if leaderconn.version_at_least(2,0,11):
3379							tab.append(("---","",14))
3380							tab.append(("disconnected servers","1c",14))
3381							tab.append(("---","",14))
3382							tab.append(("ip/host","c"),("port","c"),("csid","r"),("maintenance","c"),("change maintenance command","c",5),("remove command","c",5))
3383							tab.append(("---","",14))
3384						else:
3385							tab.append(("---","",13))
3386							tab.append(("disconnected servers","1c",13))
3387							tab.append(("---","",13))
3388							tab.append(("ip/host","c"),("port","c"),("csid","r"),("remove command","c",10))
3389							tab.append(("---","",13))
3390					else:
3391						print(tab)
3392						print("")
3393						if leaderconn.version_at_least(2,0,11):
3394							tab = Tabble("Disconnected chunk servers",4)
3395						else:
3396							tab = Tabble("Disconnected chunk servers",3)
3397				for sf,host,sortip,strip,port,csid,flags in dservers:
3398					if cgimode:
3399						out.append("""	<tr>""")
3400						if leaderconn.version_at_least(2,0,11):
3401							if (flags&2)==0:
3402								mm = "switch on"
3403								mmurl = createlink({"CSmaintenanceon":("%s:%u" % (strip,port))})
3404								cl = "DISCONNECTED"
3405							else:
3406								mm = "switch off"
3407								mmurl = createlink({"CSmaintenanceoff":("%s:%u" % (strip,port))})
3408								cl = "MAINTAINED"
3409							out.append("""		<td align="right"></td><td align="left"><span class="%s">%s</span></td>""" % (cl,host))
3410							out.append("""		<td align="center"><span class="sortkey">%s </span><span class="%s">%s</span></td>""" % (sortip,cl,strip))
3411							out.append("""		<td align="center"><span class="%s">%u</span></td>""" % (cl,port))
3412							out.append("""		<td align="right"><span class="%s">%u</span></td>""" % (cl,csid))
3413							out.append("""		<td align="center"><span class="%s"><a href="%s">%s</a></span></td>""" % (cl,mmurl,mm))
3414							out.append("""		<td align="center"><a href="%s">click to remove</a></td>""" % (createlink({"CSremove":("%s:%u" % (strip,port))})))
3415						else:
3416							out.append("""		<td align="right"></td><td align="left"><span class="DISCONNECTED">%s</span></td><td align="center"><span class="sortkey">%s </span><span class="DISCONNECTED">%s</span></td><td align="center"><span class="DISCONNECTED">%u</span></td><td align="right"><span class="DISCONNECTED">%u</span></td><td align="center"><a href="%s">click to remove</a></td>""" % (host,sortip,strip,port,csid,createlink({"CSremove":("%s:%u" % (strip,port))})))
3417						out.append("""	</tr>""")
3418					elif ttymode:
3419						if leaderconn.version_at_least(2,0,11):
3420							if (flags&2)==0:
3421								mm = "off"
3422								mmcmd = "%s -H %s -P %u -CM1/%s/%s" % (sys.argv[0],masterhost,masterport,strip,port)
3423							else:
3424								mm = "on"
3425								mmcmd = "%s -H %s -P %u -CM0/%s/%s" % (sys.argv[0],masterhost,masterport,strip,port)
3426							tab.append(host,port,csid,mm,(mmcmd,"l",5),("%s -H %s -P %u -CRC/%s/%s" % (sys.argv[0],masterhost,masterport,strip,port),"l",5))
3427						else:
3428							tab.append(host,port,csid,("%s -H %s -P %u -CRC/%s/%s" % (sys.argv[0],masterhost,masterport,strip,port),"l",10))
3429					else:
3430						if leaderconn.version_at_least(2,0,11):
3431							if (flags&2)==0:
3432								mm = "standard_mode"
3433							else:
3434								mm = "maintenance_mode"
3435							tab.append(host,port,csid,mm)
3436						else:
3437							tab.append(host,port,csid)
3438			if leaderconn.version_at_least(1,6,28) and leaderconn.version_less_than(1,7,25) and (length%62)==0:
3439				n = length//62
3440				servers = []
3441				dservers = []
3442				usedsum = 0
3443				totalsum = 0
3444				for i in range(n):
3445					d = data[i*62:(i+1)*62]
3446					disconnected,v1,v2,v3,ip1,ip2,ip3,ip4,port,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime = struct.unpack(">BBBBBBBBHQQLQQLLLL",d)
3447					strip = "%u.%u.%u.%u" % (ip1,ip2,ip3,ip4)
3448					sortip = "%03u_%03u_%03u_%03u" % (ip1,ip2,ip3,ip4)
3449					strver,sortver = version_str_and_sort((v1,v2,v3))
3450					host = resolve(strip)
3451					if total>0:
3452						usedsum+=used
3453						totalsum+=total
3454					if CSorder==1:
3455						sf = host
3456					elif CSorder==2 or CSorder==0:
3457						sf = sortip
3458					elif CSorder==3:
3459						sf = port
3460					elif CSorder==5:
3461						sf = sortver
3462					elif CSorder==6:
3463						sf = (gracetime,load)
3464					elif CSorder==10:
3465						sf = chunks
3466					elif CSorder==11:
3467						sf = used
3468					elif CSorder==12:
3469						sf = total
3470					elif CSorder==13:
3471						if total>0:
3472							sf = (1.0*used)/total
3473						else:
3474							sf = 0
3475					elif CSorder==20:
3476						sf = tdchunks
3477					elif CSorder==21:
3478						sf = tdused
3479					elif CSorder==22:
3480						sf = tdtotal
3481					elif CSorder==23:
3482						if tdtotal>0:
3483							sf = (1.0*tdused)/tdtotal
3484						else:
3485							sf = 0
3486					else:
3487						sf = 0
3488					if disconnected==0:
3489						servers.append((sf,host,sortip,strip,port,sortver,strver,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime))
3490					else:
3491						dservers.append((sf,host,sortip,strip,port))
3492				servers.sort()
3493				dservers.sort()
3494				if CSrev:
3495					servers.reverse()
3496					dservers.reverse()
3497				if totalsum>0:
3498					avgpercent = (usedsum*100.0)/totalsum
3499				else:
3500					avgpercent = 0
3501				for sf,host,sortip,strip,port,sortver,strver,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime in servers:
3502					if cgimode:
3503						if leaderconn.is_pro() and not strver.endswith(" PRO"):
3504							verclass = "BADVERSION"
3505						elif leaderconn.sort_ver() > sortver:
3506							verclass = "LOWERVERSION"
3507						elif leaderconn.sort_ver() < sortver:
3508							verclass = "HIGHERVERSION"
3509						else:
3510							verclass = "OKVERSION"
3511						out.append("""	<tr>""")
3512						out.append("""		<td align="right"></td><td align="left">%s</td><td align="center"><span class="sortkey">%s </span>%s</td><td align="center">%u</td><td align="center"><span class="sortkey">%s </span><span class="%s">%s</span></td>""" % (host,sortip,strip,port,sortver,verclass,strver))
3513						if gracetime>0:
3514							out.append("""		<td align="right"><a style="cursor:default" title="back after %u seconds"><span class="GRACETIME">[%u]</span></a></td>""" % (gracetime,load))
3515						else:
3516							out.append("""		<td align="right">%u</td>""" % (load))
3517						out.append("""		<td align="right">%u</td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td>""" % (chunks,used,decimal_number(used),humanize_number(used,"&nbsp;"),total,decimal_number(total),humanize_number(total,"&nbsp;")))
3518						if (total>0):
3519							usedpercent = (used*100.0)/total
3520							if usedpercent<avgpercent:
3521								diffstr = "&#8722;%.4f" % (avgpercent-usedpercent)
3522							else:
3523								diffstr = "+%.4f" % (usedpercent-avgpercent)
3524							out.append("""		<td align="center"><span class="sortkey">%.10f </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:%.2f%%;"></div><div class="PROGAVG" style="width:%.2f%%"></div><div class="PROGVALUE"><a style="cursor:default" title="%.4f%% = (avg%s%%)">%.2f</a></div></div></td>""" % (usedpercent,100.0-usedpercent,avgpercent,usedpercent,diffstr,usedpercent))
3525						else:
3526							out.append("""		<td align="center"><span class="sortkey">-1 </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:100%;"></div><div class="PROGVALUE">-</div></div></td>""")
3527						out.append("""		<td align="right">%u</td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td>""" % (tdchunks,tdused,decimal_number(tdused),humanize_number(tdused,"&nbsp;"),tdtotal,decimal_number(tdtotal),humanize_number(tdtotal,"&nbsp;")))
3528						if (tdtotal>0):
3529							usedpercent = (tdused*100.0)/tdtotal
3530							out.append("""		<td align="center"><span class="sortkey">%.10f </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:%.2f%%;"></div><div class="PROGVALUE">%.2f</div></div></td>""" % (usedpercent,100.0-usedpercent,usedpercent))
3531						else:
3532							out.append("""		<td align="center"><span class="sortkey">-1 </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:100%;"></div><div class="PROGVALUE">-</div></div></td>""")
3533						out.append("""	</tr>""")
3534					elif ttymode:
3535						if total>0:
3536							regperc = "%.2f%%" % ((used*100.0)/total)
3537						else:
3538							regperc = "-"
3539						if tdtotal>0:
3540							tdperc = "%.2f%%" % ((tdused*100.0)/tdtotal)
3541						else:
3542							tdperc = "-"
3543						tab.append(host,port,strver,load,chunks,humanize_number(used," "),humanize_number(total," "),regperc,tdchunks,humanize_number(tdused," "),humanize_number(tdtotal," "),tdperc)
3544					else:
3545						tab.append(host,port,strver,load,chunks,used,total,tdchunks,tdused,tdtotal)
3546				if len(dservers)>0:
3547					if cgimode:
3548						out.append("""</table>""")
3549						out.append("""<br/>""")
3550						out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsdiscs" cellspacing="0">""")
3551						out.append("""	<tr><th colspan="5">Disconnected Chunk Servers</th></tr>""")
3552						out.append("""	<tr>""")
3553						out.append("""		<th class="acid_tab_enumerate">#</th>""")
3554						out.append("""		<th>host</th>""")
3555						out.append("""		<th>ip</th>""")
3556						out.append("""		<th>port</th>""")
3557						out.append("""		<th class="acid_tab_skip">cmd</th>""")
3558						out.append("""	</tr>""")
3559					elif ttymode:
3560						tab.append(("---","",12))
3561						tab.append(("disconnected servers","1c",12))
3562						tab.append(("---","",12))
3563						tab.append(("ip/host","c"),("port","c"),("remove command","c",10))
3564						tab.append(("---","",12))
3565					else:
3566						print(tab)
3567						print("")
3568						tab = Tabble("Disconnected chunk servers",2)
3569				for sf,host,sortip,strip,port in dservers:
3570					if cgimode:
3571						out.append("""	<tr>""")
3572						out.append("""		<td align="right"></td><td align="left"><span class="DISCONNECTED">%s</span></td><td align="center"><span class="sortkey">%s </span><span class="DISCONNECTED">%s</span></td><td align="center"><span class="DISCONNECTED">%u</span></td><td align="center"><a href="%s">click to remove</a></td>""" % (host,sortip,strip,port,createlink({"CSremove":("%s:%u" % (strip,port))})))
3573						out.append("""	</tr>""")
3574					elif ttymode:
3575						tab.append(host,port,("%s -H %s -P %u -CRC/%s/%s" % (sys.argv[0],masterhost,masterport,strip,port),"l",10))
3576					else:
3577						tab.append(host,port)
3578			if leaderconn.version_less_than(1,6,28) and (length%54)==0:
3579				n = length//54
3580				servers = []
3581				dservers = []
3582				usedsum = 0
3583				totalsum = 0
3584				for i in range(n):
3585					d = data[i*54:(i+1)*54]
3586					disconnected,v1,v2,v3,ip1,ip2,ip3,ip4,port,used,total,chunks,tdused,tdtotal,tdchunks,errcnt = struct.unpack(">BBBBBBBBHQQLQQLL",d)
3587					strip = "%u.%u.%u.%u" % (ip1,ip2,ip3,ip4)
3588					sortip = "%03u_%03u_%03u_%03u" % (ip1,ip2,ip3,ip4)
3589					strver,sortver = version_str_and_sort((v1,v2,v3))
3590					host = resolve(strip)
3591					if total>0:
3592						usedsum+=used
3593						totalsum+=total
3594					sf = sortip
3595					if CSorder==1:
3596						sf = host
3597					elif CSorder==2:
3598						sf = sortip
3599					elif CSorder==3:
3600						sf = port
3601					elif CSorder==5:
3602						sf = sortver
3603					elif CSorder==10:
3604						sf = chunks
3605					elif CSorder==11:
3606						sf = used
3607					elif CSorder==12:
3608						sf = total
3609					elif CSorder==13:
3610						if total>0:
3611							sf = (1.0*used)/total
3612						else:
3613							sf = 0
3614					elif CSorder==20:
3615						sf = tdchunks
3616					elif CSorder==21:
3617						sf = tdused
3618					elif CSorder==22:
3619						sf = tdtotal
3620					elif CSorder==23:
3621						if tdtotal>0:
3622							sf = (1.0*tdused)/tdtotal
3623						else:
3624							sf = 0
3625					if disconnected==0:
3626						servers.append((sf,host,sortip,strip,port,sortver,strver,used,total,chunks,tdused,tdtotal,tdchunks,errcnt))
3627					else:
3628						dservers.append((sf,host,sortip,strip,port))
3629				servers.sort()
3630				dservers.sort()
3631				if CSrev:
3632					servers.reverse()
3633					dservers.reverse()
3634				if totalsum>0:
3635					avgpercent = (usedsum*100.0)/totalsum
3636				else:
3637					avgpercent = 0
3638				i = 1
3639				for sf,host,sortip,strip,port,sortver,strver,used,total,chunks,tdused,tdtotal,tdchunks,errcnt in servers:
3640					if cgimode:
3641						if leaderconn.is_pro() and not strver.endswith(" PRO"):
3642							verclass = "BADVERSION"
3643						elif leaderconn.sort_ver() > sortver:
3644							verclass = "LOWERVERSION"
3645						elif leaderconn.sort_ver() < sortver:
3646							verclass = "HIGHERVERSION"
3647						else:
3648							verclass = "OKVERSION"
3649						out.append("""	<tr>""")
3650						out.append("""		<td align="right"></td><td align="left">%s</td><td align="center"><span class="sortkey">%s </span>%s</td><td align="center">%u</td><td align="center"><span class="sortkey">%s </span><span class="%s">%s</span></td>""" % (host,sortip,strip,port,sortver,verclass,strver))
3651						out.append("""		<td align="right">%u</td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td>""" % (chunks,used,decimal_number(used),humanize_number(used,"&nbsp;"),total,decimal_number(total),humanize_number(total,"&nbsp;")))
3652						if (total>0):
3653							usedpercent = (used*100.0)/total
3654							if usedpercent<avgpercent:
3655								diffstr = "&#8722;%.4f" % (avgpercent-usedpercent)
3656							else:
3657								diffstr = "+%.4f" % (usedpercent-avgpercent)
3658							out.append("""		<td align="center"><span class="sortkey">%.10f </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:%.2f%%;"></div><div class="PROGAVG" style="width:%.2f%%"></div><div class="PROGVALUE"><a style="cursor:default" title="%.4f%% = (avg%s%%)">%.2f</a></div></div></td>""" % (usedpercent,100.0-usedpercent,avgpercent,usedpercent,diffstr,usedpercent))
3659						else:
3660							out.append("""		<td align="center"><span class="sortkey">-1 </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:100%;"></div><div class="PROGVALUE">-</div></div></td>""")
3661						out.append("""		<td align="right">%u</td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td>""" % (tdchunks,tdused,decimal_number(tdused),humanize_number(tdused,"&nbsp;"),tdtotal,decimal_number(tdtotal),humanize_number(tdtotal,"&nbsp;")))
3662						if (tdtotal>0):
3663							usedpercent = (tdused*100.0)/tdtotal
3664							out.append("""		<td align="center"><span class="sortkey">%.10f </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:%.2f%%;"></div><div class="PROGVALUE">%.2f</div></div></td>""" % (usedpercent,100.0-usedpercent,usedpercent))
3665						else:
3666							out.append("""		<td align="center"><span class="sortkey">-1 </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:100%;"></div><div class="PROGVALUE">-</div></div></td>""")
3667						out.append("""	</tr>""")
3668						i+=1
3669					elif ttymode:
3670						if total>0:
3671							regperc = "%.2f%%" % ((used*100.0)/total)
3672						else:
3673							regperc = "-"
3674						if tdtotal>0:
3675							tdperc = "%.2f%%" % ((tdused*100.0)/tdtotal)
3676						else:
3677							tdperc = "-"
3678						tab.append(host,port,strver,chunks,humanize_number(used," "),humanize_number(total," "),regperc,tdchunks,humanize_number(tdused," "),humanize_number(tdtotal," "),tdperc)
3679					else:
3680						tab.append(host,port,strver,chunks,used,total,tdchunks,tdused,tdtotal)
3681				if len(dservers)>0:
3682					if cgimode:
3683						out.append("""</table>""")
3684						out.append("""<br/>""")
3685						out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsdiscs" cellspacing="0">""")
3686						out.append("""	<tr><th colspan="5">Disconnected Chunk Servers</th></tr>""")
3687						out.append("""	<tr>""")
3688						out.append("""		<th class="acid_tab_enumerate">#</th>""")
3689						out.append("""		<th>host</th>""")
3690						out.append("""		<th>ip</th>""")
3691						out.append("""		<th>port</th>""")
3692						out.append("""		<th class="acid_tab_skip">cmd</th>""")
3693						out.append("""	</tr>""")
3694					elif ttymode:
3695						tab.append(("---","",11))
3696						tab.append(("disconnected servers","1c",11))
3697						tab.append(("---","",11))
3698						tab.append(("ip/host","c"),("port","c"),("remove command","c",9))
3699						tab.append(("---","",11))
3700					else:
3701						print(tab)
3702						print("")
3703						tab = Tabble("Disconnected chunk servers",2)
3704				for sf,host,sortip,strip,port in dservers:
3705					if cgimode:
3706						out.append("""	<tr>""")
3707						out.append("""		<td align="right"></td><td align="left"><span class="DISCONNECTED">%s</span></td><td align="center"><span class="sortkey">%s </span><span class="DISCONNECTED">%s</span></td><td align="center"><span class="DISCONNECTED">%u</span></td><td align="center"><a href="%s">click to remove</a></td>""" % (host,sortip,strip,port,createlink({"CSremove":("%s:%u" % (strip,port))})))
3708						out.append("""	</tr>""")
3709						i+=1
3710					elif ttymode:
3711						tab.append(host,port,("%s -H %s -P %u -CCR/%s/%s" % (sys.argv[0],masterhost,masterport,strip,port),"l",9))
3712					else:
3713						tab.append(host,port)
3714			if cgimode:
3715				out.append("""</table>""")
3716				print("\n".join(out))
3717			else:
3718				print(tab)
3719		except Exception:
3720			print_exception()
3721
3722	if "MB" in sectionsubset:
3723		if needseparator:
3724			if cgimode:
3725				print("""<br/>""")
3726			else:
3727				print("")
3728		else:
3729			needseparator=1
3730
3731		try:
3732			if cgimode:
3733				out = []
3734				out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsmbl" cellspacing="0">""")
3735				out.append("""	<tr><th colspan="4">Metadata Backup Loggers</th></tr>""")
3736				out.append("""	<tr>""")
3737				out.append("""		<th class="acid_tab_enumerate">#</th>""")
3738				out.append("""		<th>host</th>""")
3739				out.append("""		<th>ip</th>""")
3740				out.append("""		<th>version</th>""")
3741				out.append("""	</tr>""")
3742			elif ttymode:
3743				tab = Tabble("Metadata Backup Loggers",2,"r")
3744				tab.header("ip/host","version")
3745			else:
3746				tab = Tabble("metadata backup loggers",2)
3747			data,length = leaderconn.command(CLTOMA_MLOG_LIST,MATOCL_MLOG_LIST)
3748			if (length%8)==0:
3749				n = length//8
3750				servers = []
3751				for i in range(n):
3752					d = data[i*8:(i+1)*8]
3753					v1,v2,v3,ip1,ip2,ip3,ip4 = struct.unpack(">HBBBBBB",d)
3754					strip = "%u.%u.%u.%u" % (ip1,ip2,ip3,ip4)
3755					host = resolve(strip)
3756					sortip = "%03u_%03u_%03u_%03u" % (ip1,ip2,ip3,ip4)
3757					strver,sortver = version_str_and_sort((v1,v2,v3))
3758					sf = (ip1,ip2,ip3,ip4)
3759					if MBorder==1:
3760						sf = host
3761					elif MBorder==2:
3762						sf = sortip
3763					elif MBorder==3:
3764						sf = sortver
3765					servers.append((sf,host,sortip,strip,sortver,strver))
3766				servers.sort()
3767				if MBrev:
3768					servers.reverse()
3769				for sf,host,sortip,strip,sortver,strver in servers:
3770					if cgimode:
3771						if leaderconn.is_pro() and not strver.endswith(" PRO"):
3772							verclass = "BADVERSION"
3773						elif leaderconn.sort_ver() > sortver:
3774							verclass = "LOWERVERSION"
3775						elif leaderconn.sort_ver() < sortver:
3776							verclass = "HIGHERVERSION"
3777						else:
3778							verclass = "OKVERSION"
3779						out.append("""	<tr>""")
3780						out.append("""		<td align="right"></td><td align="left">%s</td><td align="center"><span class="sortkey">%s </span>%s</td><td align="center"><span class="sortkey">%s </span><span class="%s">%s</span></td>""" % (host,sortip,strip,sortver,verclass,strver))
3781						out.append("""	</tr>""")
3782					else:
3783						tab.append(host,strver)
3784			if cgimode:
3785				out.append("""</table>""")
3786				print("\n".join(out))
3787			else:
3788				print(tab)
3789		except Exception:
3790			print_exception()
3791
3792if "HD" in sectionset:
3793	if needseparator:
3794		if cgimode:
3795			print("""<br/>""")
3796		else:
3797			print("")
3798	else:
3799		needseparator=1
3800
3801	try:
3802		# get cs list
3803		hostlist = []
3804		data,length = leaderconn.command(CLTOMA_CSERV_LIST,MATOCL_CSERV_LIST)
3805		if leaderconn.version_at_least(1,7,25) and (length%64)==0:
3806			n = length//64
3807			servers = []
3808			for i in range(n):
3809				d = data[i*64:(i+1)*64]
3810				flags,v1,v2,v3,ip1,ip2,ip3,ip4,port = struct.unpack(">BBBBBBBBH",d[:10])
3811				if (flags&1)==0:
3812					hostlist.append((v1,v2,v3,ip1,ip2,ip3,ip4,port))
3813		elif leaderconn.version_at_least(1,6,28) and leaderconn.version_less_than(1,7,25) and (length%62)==0:
3814			n = length//62
3815			servers = []
3816			for i in range(n):
3817				d = data[i*62:(i+1)*62]
3818				disconnected,v1,v2,v3,ip1,ip2,ip3,ip4,port = struct.unpack(">BBBBBBBBH",d[:10])
3819				if disconnected==0:
3820					hostlist.append((v1,v2,v3,ip1,ip2,ip3,ip4,port))
3821		elif leaderconn.version_less_than(1,6,28) and (length%54)==0:
3822			n = length//54
3823			servers = []
3824			for i in range(n):
3825				d = data[i*54:(i+1)*54]
3826				disconnected,v1,v2,v3,ip1,ip2,ip3,ip4,port = struct.unpack(">BBBBBBBBH",d[:10])
3827				if disconnected==0:
3828					hostlist.append((v1,v2,v3,ip1,ip2,ip3,ip4,port))
3829
3830		# get hdd lists one by one
3831		hdd = []
3832		shdd = []
3833		for v1,v2,v3,ip1,ip2,ip3,ip4,port in hostlist:
3834			hostip = "%u.%u.%u.%u" % (ip1,ip2,ip3,ip4)
3835			hostkey = "%s:%u" % (hostip,port)
3836			hoststr = resolve(hostip)
3837			if port>0:
3838				if (v1,v2,v3)<=(1,6,8):
3839					conn = MFSConn(hostip,port)
3840					data,length = conn.command(CLTOCS_HDD_LIST_V1,CSTOCL_HDD_LIST_V1)
3841					while length>0:
3842						if sys.version_info[0]<3:
3843							plen = ord(data[0])
3844							hddpath = data[1:plen+1]
3845						else:
3846							plen = data[0]
3847							hddpath = data[1:plen+1]
3848							try:
3849								hddpath = hddpath.decode('ascii')
3850							except UnicodeDecodeError:
3851								pass
3852						hostpath = "%s:%u:%s" % (hoststr,port,hddpath)
3853						ippath = "%s:%u:%s" % (hostip,port,hddpath)
3854						sortippath = "%03u_%03u_%03u_%03u:%05u:%s" % (ip1,ip2,ip3,ip4,port,hddpath)
3855						flags,errchunkid,errtime,used,total,chunkscnt = struct.unpack(">BQLQQL",data[plen+1:plen+34])
3856						length -= plen+34
3857						data = data[plen+34:]
3858						sf = (ip1,ip2,ip3,ip4,port,data[1:plen+1])
3859						if HDorder==1:
3860							sf = (ip1,ip2,ip3,ip4,port,data[1:plen+1])
3861						elif HDorder==2:
3862							sf = chunkscnt
3863						elif HDorder==3:
3864							sf = errtime
3865						elif HDorder==4:
3866							sf = -flags
3867						elif HDorder==20:
3868							sf = used
3869						elif HDorder==21:
3870							sf = total
3871						elif HDorder==22:
3872							if total>0:
3873								sf = (1.0*used)/total
3874							else:
3875								sf = 0
3876						hdd.append((sf,hostkey,sortippath,ippath,hostpath,flags,errchunkid,errtime,used,total,chunkscnt,[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]))
3877				else:
3878					conn = MFSConn(hostip,port)
3879					data,length = conn.command(CLTOCS_HDD_LIST_V2,CSTOCL_HDD_LIST_V2)
3880					while length>0:
3881						entrysize = struct.unpack(">H",data[:2])[0]
3882						entry = data[2:2+entrysize]
3883						data = data[2+entrysize:]
3884						length -= 2+entrysize;
3885						if sys.version_info[0]<3:
3886							plen = ord(entry[0])
3887							hddpath = entry[1:plen+1]
3888						else:
3889							plen = entry[0]
3890							hddpath = entry[1:plen+1]
3891							try:
3892								hddpath = hddpath.decode('ascii')
3893							except UnicodeDecodeError:
3894								pass
3895						hostpath = "%s:%u:%s" % (hoststr,port,hddpath)
3896						ippath = "%s:%u:%s" % (hostip,port,hddpath)
3897						sortippath = "%03u.%03u.%03u.%03u:%05u:%s" % (ip1,ip2,ip3,ip4,port,hddpath)
3898						flags,errchunkid,errtime,used,total,chunkscnt = struct.unpack(">BQLQQL",entry[plen+1:plen+34])
3899						rbytes = [0,0,0]
3900						wbytes = [0,0,0]
3901						usecreadsum = [0,0,0]
3902						usecwritesum = [0,0,0]
3903						usecfsyncsum = [0,0,0]
3904						rops = [0,0,0]
3905						wops = [0,0,0]
3906						fsyncops = [0,0,0]
3907						usecreadmax = [0,0,0]
3908						usecwritemax = [0,0,0]
3909						usecfsyncmax = [0,0,0]
3910						if entrysize==plen+34+144:
3911							rbytes[0],wbytes[0],usecreadsum[0],usecwritesum[0],rops[0],wops[0],usecreadmax[0],usecwritemax[0] = struct.unpack(">QQQQLLLL",entry[plen+34:plen+34+48])
3912							rbytes[1],wbytes[1],usecreadsum[1],usecwritesum[1],rops[1],wops[1],usecreadmax[1],usecwritemax[1] = struct.unpack(">QQQQLLLL",entry[plen+34+48:plen+34+96])
3913							rbytes[2],wbytes[2],usecreadsum[2],usecwritesum[2],rops[2],wops[2],usecreadmax[2],usecwritemax[2] = struct.unpack(">QQQQLLLL",entry[plen+34+96:plen+34+144])
3914#								if HDperiod==0:
3915#									rbytes,wbytes,usecreadsum,usecwritesum,rops,wops,usecreadmax,usecwritemax = struct.unpack(">QQQQLLLL",entry[plen+34:plen+34+48])
3916#								elif HDperiod==1:
3917#									rbytes,wbytes,usecreadsum,usecwritesum,rops,wops,usecreadmax,usecwritemax = struct.unpack(">QQQQLLLL",entry[plen+34+48:plen+34+96])
3918#								elif HDperiod==2:
3919#									rbytes,wbytes,usecreadsum,usecwritesum,rops,wops,usecreadmax,usecwritemax = struct.unpack(">QQQQLLLL",entry[plen+34+96:plen+34+144])
3920						elif entrysize==plen+34+192:
3921							rbytes[0],wbytes[0],usecreadsum[0],usecwritesum[0],usecfsyncsum[0],rops[0],wops[0],fsyncops[0],usecreadmax[0],usecwritemax[0],usecfsyncmax[0] = struct.unpack(">QQQQQLLLLLL",entry[plen+34:plen+34+64])
3922							rbytes[1],wbytes[1],usecreadsum[1],usecwritesum[1],usecfsyncsum[1],rops[1],wops[1],fsyncops[1],usecreadmax[1],usecwritemax[1],usecfsyncmax[1] = struct.unpack(">QQQQQLLLLLL",entry[plen+34+64:plen+34+128])
3923							rbytes[2],wbytes[2],usecreadsum[2],usecwritesum[2],usecfsyncsum[2],rops[2],wops[2],fsyncops[2],usecreadmax[2],usecwritemax[2],usecfsyncmax[2] = struct.unpack(">QQQQQLLLLLL",entry[plen+34+128:plen+34+192])
3924#								if HDperiod==0:
3925#									rbytes,wbytes,usecreadsum,usecwritesum,usecfsyncsum,rops,wops,fsyncops,usecreadmax,usecwritemax,usecfsyncmax = struct.unpack(">QQQQQLLLLLL",entry[plen+34:plen+34+64])
3926#								elif HDperiod==1:
3927#									rbytes,wbytes,usecreadsum,usecwritesum,usecfsyncsum,rops,wops,fsyncops,usecreadmax,usecwritemax,usecfsyncmax = struct.unpack(">QQQQQLLLLLL",entry[plen+34+64:plen+34+128])
3928#								elif HDperiod==2:
3929#									rbytes,wbytes,usecreadsum,usecwritesum,usecfsyncsum,rops,wops,fsyncops,usecreadmax,usecwritemax,usecfsyncmax = struct.unpack(">QQQQQLLLLLL",entry[plen+34+128:plen+34+192])
3930						rbw = [0,0,0]
3931						wbw = [0,0,0]
3932						usecreadavg = [0,0,0]
3933						usecwriteavg = [0,0,0]
3934						usecfsyncavg = [0,0,0]
3935						for i in range(3):
3936							if usecreadsum[i]>0:
3937								rbw[i] = rbytes[i]*1000000//usecreadsum[i]
3938							if usecwritesum[i]+usecfsyncsum[i]>0:
3939								wbw[i] = wbytes[i]*1000000//(usecwritesum[i]+usecfsyncsum[i])
3940							if rops[i]>0:
3941								usecreadavg[i] = usecreadsum[i]//rops[i]
3942							if wops[i]>0:
3943								usecwriteavg[i] = usecwritesum[i]//wops[i]
3944							if fsyncops[i]>0:
3945								usecfsyncavg[i] = usecfsyncsum[i]//fsyncops[i]
3946						sf = sortippath
3947						if HDorder==1:
3948							sf = sortippath
3949						elif HDorder==2:
3950							sf = chunkscnt
3951						elif HDorder==3:
3952							sf = errtime
3953						elif HDorder==4:
3954							sf = -flags
3955						elif HDorder==5:
3956							sf = rbw[HDperiod]
3957						elif HDorder==6:
3958							sf = wbw[HDperiod]
3959						elif HDorder==7:
3960							if HDtime==1:
3961								sf = usecreadavg[HDperiod]
3962							else:
3963								sf = usecreadmax[HDperiod]
3964						elif HDorder==8:
3965							if HDtime==1:
3966								sf = usecwriteavg[HDperiod]
3967							else:
3968								sf = usecwritemax[HDperiod]
3969						elif HDorder==9:
3970							if HDtime==1:
3971								sf = usecfsyncavg[HDperiod]
3972							else:
3973								sf = usecfsyncmax[HDperiod]
3974						elif HDorder==10:
3975							sf = rops[HDperiod]
3976						elif HDorder==11:
3977							sf = wops[HDperiod]
3978						elif HDorder==12:
3979							sf = fsyncops[HDperiod]
3980						elif HDorder==20:
3981							if flags&4==0:
3982								sf = used
3983							else:
3984								sf = 0
3985						elif HDorder==21:
3986							if flags&4==0:
3987								sf = total
3988							else:
3989								sf = 0
3990						elif HDorder==22:
3991							if flags&4==0 and total>0:
3992								sf = (1.0*used)/total
3993							else:
3994								sf = 0
3995						if flags&4 and not cgimode and ttymode:
3996							shdd.append((sf,hostkey,sortippath,ippath,hostpath,flags,errchunkid,errtime,used,total,chunkscnt,rbw,wbw,usecreadavg,usecwriteavg,usecfsyncavg,usecreadmax,usecwritemax,usecfsyncmax,rops,wops,fsyncops,rbytes,wbytes))
3997						else:
3998							hdd.append((sf,hostkey,sortippath,ippath,hostpath,flags,errchunkid,errtime,used,total,chunkscnt,rbw,wbw,usecreadavg,usecwriteavg,usecfsyncavg,usecreadmax,usecwritemax,usecfsyncmax,rops,wops,fsyncops,rbytes,wbytes))
3999
4000		if len(hdd)>0 or len(shdd)>0:
4001			if cgimode:
4002				out = []
4003				out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfshdd" cellspacing="0" id="mfshdd">""")
4004				out.append("""	<tr><th colspan="16">Disks</th></tr>""")
4005				out.append("""	<tr>""")
4006				out.append("""		<th rowspan="3" class="acid_tab_enumerate">#</th>""")
4007				out.append("""		<th colspan="4" rowspan="2">""")
4008				out.append("""			<span class="hddaddrname_vis0">info (<a href="javascript:acid_tab.switchdisplay('mfshdd','hddaddrname_vis',1)" class="VISIBLELINK">switch IP to name</a>)</span>""")
4009				out.append("""			<span class="hddaddrname_vis1">info (<a href="javascript:acid_tab.switchdisplay('mfshdd','hddaddrname_vis',0)" class="VISIBLELINK">switch name to IP</a>)</span>""")
4010				out.append("""		</th>""")
4011				out.append("""		<th colspan="8">""")
4012				out.append("""			<span class="hddperiod_vis0">I/O stats last min (switch to <a href="javascript:acid_tab.switchdisplay('mfshdd','hddperiod_vis',1)" class="VISIBLELINK">hour</a>,<a href="javascript:acid_tab.switchdisplay('mfshdd','hddperiod_vis',2)" class="VISIBLELINK">day</a>)</span>""")
4013				out.append("""			<span class="hddperiod_vis1">I/O stats last hour (switch to <a href="javascript:acid_tab.switchdisplay('mfshdd','hddperiod_vis',0)" class="VISIBLELINK">min</a>,<a href="javascript:acid_tab.switchdisplay('mfshdd','hddperiod_vis',2)" class="VISIBLELINK">day</a>)</span>""")
4014				out.append("""			<span class="hddperiod_vis2">I/O stats last day (switch to <a href="javascript:acid_tab.switchdisplay('mfshdd','hddperiod_vis',0)" class="VISIBLELINK">min</a>,<a href="javascript:acid_tab.switchdisplay('mfshdd','hddperiod_vis',1)" class="VISIBLELINK">hour</a>)</span>""")
4015				out.append("""		</th>""")
4016#				if HDperiod==2:
4017#					out.append("""		<th colspan="8">I/O stats last day (switch to <a href="%s" class="VISIBLELINK">min</a>,<a href="%s" class="VISIBLELINK">hour</a>)</th>""" % (createlink({"HDperiod":"0"}),createlink({"HDperiod":"1"})))
4018#				elif HDperiod==1:
4019#					out.append("""		<th colspan="8">I/O stats last hour (switch to <a href="%s" class="VISIBLELINK">min</a>,<a href="%s" class="VISIBLELINK">day</a>)</th>""" % (createlink({"HDperiod":"0"}),createlink({"HDperiod":"2"})))
4020#				else:
4021#					out.append("""		<th colspan="8">I/O stats last min (switch to <a href="%s" class="VISIBLELINK">hour</a>,<a href="%s" class="VISIBLELINK">day</a>)</th>""" % (createlink({"HDperiod":"1"}),createlink({"HDperiod":"2"})))
4022				out.append("""		<th colspan="3" rowspan="2">space</th>""")
4023				out.append("""	</tr>""")
4024				out.append("""	<tr>""")
4025				out.append("""		<th colspan="2"><a style="cursor:default" title="average data transfer speed">transfer</a></th>""")
4026				out.append("""		<th colspan="3">""")
4027				out.append("""			<span class="hddtime_vis0"><a style="cursor:default" title="max time of read or write one chunk block (up to 64kB)">max time</a> (<a href="javascript:acid_tab.switchdisplay('mfshdd','hddtime_vis',1)" class="VISIBLELINK">switch to avg</a>)</span>""")
4028				out.append("""			<span class="hddtime_vis1"><a style="cursor:default" title="average time of read or write chunk block (up to 64kB)">avg time</a> (<a href="javascript:acid_tab.switchdisplay('mfshdd','hddtime_vis',0)" class="VISIBLELINK">switch to max</a>)</span>""")
4029				out.append("""		</th>""")
4030#				if HDtime==1:
4031#					out.append("""		<th colspan="3"><a style="cursor:default" title="average time of read or write chunk block (up to 64kB)">avg time</a> (<a href="%s" class="VISIBLELINK">switch to max</a>)</th>""" % (createlink({"HDtime":"0"})))
4032#				else:
4033#					out.append("""		<th colspan="3"><a style="cursor:default" title="max time of read or write one chunk block (up to 64kB)">max time</a> (<a href="%s" class="VISIBLELINK">switch to avg</a>)</th>""" % (createlink({"HDtime":"1"})))
4034				out.append("""		<th colspan="3"><a style="cursor:default" title="number of chunk block operations / chunk fsyncs"># of ops</a></th>""")
4035				out.append("""	</tr>""")
4036				out.append("""	<tr>""")
4037				out.append("""		<th class="acid_tab_level_1"><span class="hddaddrname_vis0">IP</span><span class="hddaddrname_vis1">name</span> path</th>""")
4038				out.append("""		<th>chunks</th>""")
4039				out.append("""		<th>last error</th>""")
4040				out.append("""		<th>status</th>""")
4041				out.append("""		<th class="acid_tab_level_1">read</th>""")
4042				out.append("""		<th class="acid_tab_level_1">write</th>""")
4043				out.append("""		<th class="acid_tab_level_2">read</th>""")
4044				out.append("""		<th class="acid_tab_level_2">write</th>""")
4045				out.append("""		<th class="acid_tab_level_2">fsync</th>""")
4046				out.append("""		<th class="acid_tab_level_1">read</th>""")
4047				out.append("""		<th class="acid_tab_level_1">write</th>""")
4048				out.append("""		<th class="acid_tab_level_1">fsync</th>""")
4049				out.append("""		<th>used</th>""")
4050				out.append("""		<th>total</th>""")
4051				out.append("""		<th class="SMPROGBAR">% used</th>""")
4052				#out.append("""		<th><a href="%s">chunks</a></th>""" % (createorderlink("HD",2)))
4053				#out.append("""		<th><a href="%s">last error</a></th>""" % (createorderlink("HD",3)))
4054				#out.append("""		<th><a href="%s">status</a></th>""" % (createorderlink("HD",4)))
4055				#out.append("""		<th><a href="%s">read</a></th>""" % (createorderlink("HD",5)))
4056				#out.append("""		<th><a href="%s">write</a></th>""" % (createorderlink("HD",6)))
4057				#out.append("""		<th><a href="%s">read</a></th>""" % (createorderlink("HD",7)))
4058				#out.append("""		<th><a href="%s">write</a></th>""" % (createorderlink("HD",8)))
4059				#out.append("""		<th><a href="%s">fsync</a></th>""" % (createorderlink("HD",9)))
4060				#out.append("""		<th><a href="%s">read</a></th>""" % (createorderlink("HD",10)))
4061				#out.append("""		<th><a href="%s">write</a></th>""" % (createorderlink("HD",11)))
4062				#out.append("""		<th><a href="%s">fsync</a></th>""" % (createorderlink("HD",12)))
4063				#out.append("""		<th><a href="%s">used</a></th>""" % (createorderlink("HD",20)))
4064				#out.append("""		<th><a href="%s">total</a></th>""" % (createorderlink("HD",21)))
4065				#out.append("""		<th class="SMPROGBAR"><a href="%s">used (%%)</a></th>""" % (createorderlink("HD",22)))
4066				out.append("""	</tr>""")
4067			elif ttymode:
4068				tab = Tabble("Disks",15,"r")
4069				tab.header(("","",4),("I/O stats last %s" % ("day" if HDperiod==2 else "hour" if HDperiod==1 else "min"),"",8),("","",3))
4070				tab.header(("info","",4),("---","",8),("space","",3))
4071				tab.header(("","",4),("transfer","",2),("%s time" % ("avg" if HDtime==1 else "max"),"",3),("# of ops","",3),("","",3))
4072				tab.header(("---","",15))
4073				if len(hdd)>0 or len(shdd)==0:
4074					tab.header("IP path","chunks","last error","status","read","write","read","write","fsync","read","write","fsync","used","total","used %")
4075					lscanning = 0
4076				else:
4077					tab.header("IP path","chunks","last error","status","read","write","read","write","fsync","read","write","fsync",("progress","c",3))
4078					lscanning = 1
4079			else:
4080				tab = Tabble("disks",14)
4081			hdd.sort()
4082			shdd.sort()
4083			if HDrev:
4084				hdd.reverse()
4085				shdd.reverse()
4086			usedsum = {}
4087			totalsum = {}
4088			hostavg = {}
4089			for sf,hostkey,sortippath,ippath,hostpath,flags,errchunkid,errtime,used,total,chunkscnt,rbw,wbw,usecreadavg,usecwriteavg,usecfsyncavg,usecreadmax,usecwritemax,usecfsyncmax,rops,wops,fsyncops,rbytes,wbytes in hdd+shdd:
4090				if hostkey not in usedsum:
4091					usedsum[hostkey]=0
4092					totalsum[hostkey]=0
4093					hostavg[hostkey]=0
4094				if flags&4==0 and total>0:
4095					usedsum[hostkey]+=used
4096					totalsum[hostkey]+=total
4097					if totalsum[hostkey]>0:
4098						hostavg[hostkey] = (usedsum[hostkey] * 100.0) / totalsum[hostkey]
4099			for sf,hostkey,sortippath,ippath,hostpath,flags,errchunkid,errtime,used,total,chunkscnt,rbw,wbw,usecreadavg,usecwriteavg,usecfsyncavg,usecreadmax,usecwritemax,usecfsyncmax,rops,wops,fsyncops,rbytes,wbytes in hdd+shdd:
4100				if flags==1:
4101					status = 'marked for removal'
4102				elif flags==2:
4103					status = 'damaged'
4104				elif flags==3:
4105					status = 'damaged, marked for removal'
4106				elif flags==4 or flags==6:
4107					status = 'scanning'
4108				elif flags==5 or flags==7:
4109					status = 'marked for removal, scanning'
4110				else:
4111					status = 'ok'
4112				if errtime==0 and errchunkid==0:
4113					lerror = 'no errors'
4114				else:
4115					if cgimode:
4116						errtimetuple = time.localtime(errtime)
4117						lerror = '<a style="cursor:default" title="%s on chunk: %u">%s</a>' % (time.strftime("%Y-%m-%d %H:%M:%S",errtimetuple),errchunkid,time.strftime("%Y-%m-%d %H:%M",errtimetuple))
4118					elif ttymode:
4119						errtimetuple = time.localtime(errtime)
4120						lerror = time.strftime("%Y-%m-%d %H:%M",errtimetuple)
4121					else:
4122						lerror = errtime
4123				if cgimode:
4124					out.append("""	<tr>""")
4125					out.append("""		<td align="right"></td>""")
4126					out.append("""		<td align="left"><span class="hddaddrname_vis0"><span class="sortkey">%s </span>%s</span><span class="hddaddrname_vis1">%s</span></td>""" % (sortippath,ippath,hostpath))
4127					out.append("""		<td align="right">%u</td><td align="right"><span class="sortkey">%u </span>%s</td><td align="right">%s</td>""" % (chunkscnt,errtime,lerror,status))
4128					validdata = [1,1,1]
4129					for i in range(3):
4130						if rbw[i]==0 and wbw[i]==0 and usecreadmax[i]==0 and usecwritemax[i]==0 and usecfsyncmax[i]==0 and rops[i]==0 and wops[i]==0:
4131							validdata[i] = 0
4132					# rbw
4133					out.append("""		<td align="right">""")
4134					for i in range(3):
4135						out.append("""			<span class="hddperiod_vis%u">""" % i)
4136						if validdata[i]:
4137							out.append("""				<span class="sortkey">%u </span><a style="cursor:default" title="%s B/s">%s/s</a>""" % (rbw[i],decimal_number(rbw[i]),humanize_number(rbw[i],"&nbsp;")))
4138						else:
4139							out.append("""				<span class="sortkey">-1 </span>-""")
4140						out.append("""			</span>""")
4141					out.append("""		</td>""")
4142					# wbw
4143					out.append("""		<td align="right">""")
4144					for i in range(3):
4145						out.append("""			<span class="hddperiod_vis%u">""" % i)
4146						if validdata[i]:
4147							out.append("""				<span class="sortkey">%u </span><a style="cursor:default" title="%s B/s">%s/s</a>""" % (wbw[i],decimal_number(wbw[i]),humanize_number(wbw[i],"&nbsp;")))
4148						else:
4149							out.append("""				<span class="sortkey">-1 </span>-""")
4150						out.append("""			</span>""")
4151					out.append("""		</td>""")
4152					# readtime
4153					out.append("""		<td align="right">""")
4154					for i in range(3):
4155						out.append("""			<span class="hddperiod_vis%u">""" % i)
4156						if validdata[i]:
4157							out.append("""				<span class="hddtime_vis0">%u us</span>""" % usecreadmax[i])
4158							out.append("""				<span class="hddtime_vis1">%u us</span>""" % usecreadavg[i])
4159						else:
4160							out.append("""				<span><span class="sortkey">-1 </span>-</span>""")
4161						out.append("""			</span>""")
4162					out.append("""		</td>""")
4163					# writetime
4164					out.append("""		<td align="right">""")
4165					for i in range(3):
4166						out.append("""			<span class="hddperiod_vis%u">""" % i)
4167						if validdata[i]:
4168							out.append("""				<span class="hddtime_vis0">%u us</span>""" % usecwritemax[i])
4169							out.append("""				<span class="hddtime_vis1">%u us</span>""" % usecwriteavg[i])
4170						else:
4171							out.append("""				<span><span class="sortkey">-1 </span>-</span>""")
4172						out.append("""			</span>""")
4173					out.append("""		</td>""")
4174					# fsynctime
4175					out.append("""		<td align="right">""")
4176					for i in range(3):
4177						out.append("""			<span class="hddperiod_vis%u">""" % i)
4178						if validdata[i]:
4179							out.append("""				<span class="hddtime_vis0">%u us</span>""" % usecfsyncmax[i])
4180							out.append("""				<span class="hddtime_vis1">%u us</span>""" % usecfsyncavg[i])
4181						else:
4182							out.append("""				<span><span class="sortkey">-1 </span>-</span>""")
4183						out.append("""			</span>""")
4184					out.append("""		</td>""")
4185					# rops
4186					out.append("""		<td align="right">""")
4187					for i in range(3):
4188						out.append("""			<span class="hddperiod_vis%u">""" % i)
4189						if validdata[i]:
4190							if rops[i]>0:
4191								bsize = rbytes[i]/rops[i]
4192							else:
4193								bsize = 0
4194							out.append("""				<a style="cursor:default" title="average block size: %u B">%u</a>""" % (bsize,rops[i]))
4195						else:
4196							out.append("""				<span class="sortkey">-1 </span>-""")
4197						out.append("""			</span>""")
4198					out.append("""		</td>""")
4199					# wops
4200					out.append("""		<td align="right">""")
4201					for i in range(3):
4202						out.append("""			<span class="hddperiod_vis%u">""" % i)
4203						if validdata[i]:
4204							if wops[i]>0:
4205								bsize = wbytes[i]/wops[i]
4206							else:
4207								bsize = 0
4208							out.append("""				<a style="cursor:default" title="average block size: %u B">%u</a>""" % (bsize,wops[i]))
4209						else:
4210							out.append("""				<span class="sortkey">-1 </span>-""")
4211						out.append("""			</span>""")
4212					out.append("""		</td>""")
4213					# fsyncops
4214					out.append("""		<td align="right">""")
4215					for i in range(3):
4216						out.append("""			<span class="hddperiod_vis%u">""" % i)
4217						if validdata[i]:
4218							out.append("""				%u""" % (fsyncops[i]))
4219						else:
4220							out.append("""				<span class="sortkey">-1 </span>-""")
4221						out.append("""			</span>""")
4222					out.append("""		</td>""")
4223#					if rbw==0 and wbw==0 and rtime==0 and wtime==0 and rops==0 and wops==0:
4224#						out.append("""		<td><span class="sortkey">-1 </span>-</td><td><span class="sortkey">-1 </span>-</td><td><span class="sortkey">-1 </span>-</td><td><span class="sortkey">-1 </span>-</td><td><span class="sortkey">-1 </span>-</td><td><span class="sortkey">-1 </span>-</td><td><span class="sortkey">-1 </span>-</td><td><span class="sortkey">-1 </span>-</td>""")
4225#					else:
4226#						if rops>0:
4227#							rbsize = rbytes/rops
4228#						else:
4229#							rbsize = 0
4230#						if wops>0:
4231#							wbsize = wbytes/wops
4232#						else:
4233#							wbsize = 0
4234#						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B/s">%s/s</a></td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s/s</a></td>""" % (rbw,decimal_number(rbw),humanize_number(rbw,"&nbsp;"),wbw,decimal_number(wbw),humanize_number(wbw,"&nbsp;")))
4235#						out.append("""		<td align="right">%u us</td><td align="right">%u us</td><td align="right">%u us</td><td align="right"><a style="cursor:default" title="average block size: %u B">%u</a></td><td align="right"><a style="cursor:default" title="average block size: %u B">%u</a></td><td align="right">%u</td>""" % (rtime,wtime,fsynctime,rbsize,rops,wbsize,wops,fsyncops))
4236					if flags&4:
4237						out.append("""		<td colspan="3" align="right"><span class="sortkey">0 </span><div class="PROGBOX" style="width:200px;"><div class="PROGCOVER" style="width:%.0f%%;"></div><div class="PROGVALUE">%.0f%% scanned</div></div></td>""" % (100.0-used,used))
4238					else:
4239						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td><td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td>""" % (used,decimal_number(used),humanize_number(used,"&nbsp;"),total,decimal_number(total),humanize_number(total,"&nbsp;")))
4240						if total>0:
4241							usedpercent = (used*100.0)/total
4242							avgpercent = hostavg[hostkey]
4243							if usedpercent<avgpercent:
4244								diffstr = "&#8722;%.4f" % (avgpercent-usedpercent)
4245							else:
4246								diffstr = "+%.4f" % (usedpercent-avgpercent)
4247							out.append("""		<td align="center"><span class="sortkey">%.10f </span><div class="PROGBOX" style="width:100px;"><div class="PROGCOVER" style="width:%.2f%%;"></div><div class="PROGAVG" style="width:%.2f%%"></div><div class="PROGVALUE"><a style="cursor:default" title="%.4f%% = (avg%s%%)">%.2f</a></div></div></td>""" % (usedpercent,100.0-usedpercent,avgpercent,usedpercent,diffstr,usedpercent))
4248						else:
4249							out.append("""		<td align="center"><span class="sortkey">-1 </span><div class="PROGBOX" style="width:100px;"><div class="PROGCOVER" style="width:100%;"></div><div class="PROGVALUE">-</div></div></td>""")
4250					out.append("""	</tr>""")
4251				elif ttymode:
4252					rtime = usecreadmax[HDperiod] if HDtime==0 else usecreadavg[HDperiod]
4253					wtime = usecwritemax[HDperiod] if HDtime==0 else usecwriteavg[HDperiod]
4254					fsynctime = usecfsyncmax[HDperiod] if HDtime==0 else usecfsyncavg[HDperiod]
4255					ldata = [ippath,chunkscnt,lerror,status]
4256					if rbw[HDperiod]==0 and wbw[HDperiod]==0 and usecreadmax[HDperiod]==0 and usecwritemax[HDperiod]==0 and usecfsyncmax[HDperiod]==0 and rops[HDperiod]==0 and wops[HDperiod]==0:
4257						ldata.extend(("-","-","-","-","-","-","-","-"))
4258					else:
4259						ldata.extend(("%s/s" % humanize_number(rbw[HDperiod]," "),"%s/s" % humanize_number(wbw[HDperiod]," "),"%u us" % rtime,"%u us" % wtime,"%u us" % fsynctime,rops[HDperiod],wops[HDperiod],fsyncops[HDperiod]))
4260					if flags&4:
4261						if lscanning==0:
4262							lscanning=1
4263							tab.append(("---","",15))
4264							tab.append("IP path","chunks","last error","status","read","write","read","write","fsync","read","write","fsync",("progress","c",3))
4265							tab.append(("---","",15))
4266						ldata.append(("%.0f%%" % used,"r",3))
4267					else:
4268						if total>0:
4269							perc = "%.2f%%" % ((used*100.0)/total)
4270						else:
4271							perc = "-"
4272						ldata.extend((humanize_number(used," "),humanize_number(total," "),perc))
4273					tab.append(*ldata)
4274				else:
4275					rtime = usecreadmax[HDperiod] if HDtime==0 else usecreadavg[HDperiod]
4276					wtime = usecwritemax[HDperiod] if HDtime==0 else usecwriteavg[HDperiod]
4277					fsynctime = usecfsyncmax[HDperiod] if HDtime==0 else usecfsyncavg[HDperiod]
4278					ldata = [ippath,chunkscnt,lerror,status]
4279					if rbw[HDperiod]==0 and wbw[HDperiod]==0 and usecreadmax[HDperiod]==0 and usecwritemax[HDperiod]==0 and usecfsyncmax[HDperiod]==0 and rops[HDperiod]==0 and wops[HDperiod]==0:
4280						ldata.extend(("-","-","-","-","-","-","-","-"))
4281					else:
4282						ldata.extend((rbw[HDperiod],wbw[HDperiod],rtime,wtime,fsynctime,rops[HDperiod],wops[HDperiod],fsyncops[HDperiod]))
4283					if flags&4:
4284						ldata.extend(("progress:",used))
4285					else:
4286						ldata.extend((used,total))
4287					tab.append(*ldata)
4288			if cgimode:
4289				out.append("""</table>""")
4290				print("\n".join(out))
4291			else:
4292				print(tab)
4293	except Exception:
4294		print_exception()
4295
4296if "EX" in sectionset:
4297	if needseparator:
4298		if cgimode:
4299			print("""<br/>""")
4300		else:
4301			print("")
4302	else:
4303		needseparator=1
4304
4305	try:
4306		if cgimode:
4307			out = []
4308			out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsexports" cellspacing="0">""")
4309			out.append("""	<tr><th colspan="%u">Exports</th></tr>""" % (19 if leaderconn.version_at_least(1,7,0) else 18 if leaderconn.version_at_least(1,6,26) else 14))
4310			out.append("""	<tr>""")
4311			out.append("""		<th rowspan="2" class="acid_tab_enumerate">#</th>""")
4312			out.append("""		<th colspan="2">ip&nbsp;range</th>""")
4313#			out.append("""		<th rowspan="2"><a href="%s">path</a></th>""" % (createorderlink("EX",3)))
4314#			out.append("""		<th rowspan="2"><a href="%s">minversion</a></th>""" % (createorderlink("EX",4)))
4315#			out.append("""		<th rowspan="2"><a href="%s">alldirs</a></th>""" % (createorderlink("EX",5)))
4316#			out.append("""		<th rowspan="2"><a href="%s">password</a></th>""" % (createorderlink("EX",6)))
4317#			out.append("""		<th rowspan="2"><a href="%s">ro/rw</a></th>""" % (createorderlink("EX",7)))
4318#			out.append("""		<th rowspan="2"><a href="%s">restricted&nbsp;ip</a></th>""" % (createorderlink("EX",8)))
4319#			out.append("""		<th rowspan="2"><a href="%s">ignore&nbsp;gid</a></th>""" % (createorderlink("EX",9)))
4320			out.append("""		<th rowspan="2">path</th>""")
4321			out.append("""		<th rowspan="2">minversion</th>""")
4322			out.append("""		<th rowspan="2">alldirs</th>""")
4323			out.append("""		<th rowspan="2">password</th>""")
4324			out.append("""		<th rowspan="2">ro/rw</th>""")
4325			out.append("""		<th rowspan="2">restricted&nbsp;ip</th>""")
4326			out.append("""		<th rowspan="2">ignore&nbsp;gid</th>""")
4327			if leaderconn.version_at_least(1,7,0):
4328#				out.append("""		<th rowspan="2"><a href="%s">can&nbsp;change&nbsp;quota</a></th>""" % (createorderlink("EX",10)))
4329				out.append("""		<th rowspan="2">admin</th>""")
4330			out.append("""		<th colspan="2">map&nbsp;root</th>""")
4331			out.append("""		<th colspan="2">map&nbsp;users</th>""")
4332			if leaderconn.version_at_least(1,6,26):
4333				out.append("""		<th colspan="2">goal&nbsp;limit</th>""")
4334				out.append("""		<th colspan="2">trashtime&nbsp;limit</th>""")
4335			out.append("""	</tr>""")
4336			out.append("""	<tr>""")
4337#			out.append("""		<th><a href="%s">from</a></th>""" % (createorderlink("EX",1)))
4338#			out.append("""		<th><a href="%s">to</a></th>""" % (createorderlink("EX",2)))
4339#			out.append("""		<th><a href="%s">uid</a></th>""" % (createorderlink("EX",11)))
4340#			out.append("""		<th><a href="%s">gid</a></th>""" % (createorderlink("EX",12)))
4341#			out.append("""		<th><a href="%s">uid</a></th>""" % (createorderlink("EX",13)))
4342#			out.append("""		<th><a href="%s">gid</a></th>""" % (createorderlink("EX",14)))
4343			out.append("""		<th>from</th>""")
4344			out.append("""		<th>to</th>""")
4345			out.append("""		<th>uid</th>""")
4346			out.append("""		<th>gid</th>""")
4347			out.append("""		<th>uid</th>""")
4348			out.append("""		<th>gid</th>""")
4349			if leaderconn.version_at_least(1,6,26):
4350#				out.append("""		<th><a href="%s">min</a></th>""" % (createorderlink("EX",15)))
4351#				out.append("""		<th><a href="%s">max</a></th>""" % (createorderlink("EX",16)))
4352#				out.append("""		<th><a href="%s">min</a></th>""" % (createorderlink("EX",17)))
4353#				out.append("""		<th><a href="%s">max</a></th>""" % (createorderlink("EX",18)))
4354				out.append("""		<th>min</th>""")
4355				out.append("""		<th>max</th>""")
4356				out.append("""		<th>min</th>""")
4357				out.append("""		<th>max</th>""")
4358			out.append("""	</tr>""")
4359		elif ttymode:
4360			tab = Tabble("Exports",(18 if leaderconn.version_at_least(1,7,0) else 17 if leaderconn.version_at_least(1,6,26) else 13))
4361			dline = ["r","r","l","c","c","c","c","c","c"]
4362			if leaderconn.version_at_least(1,7,0):
4363				dline.append("c")
4364			dline.extend(("r","r","r","r"))
4365			if leaderconn.version_at_least(1,6,26):
4366				dline.extend(("r","r","r","r"))
4367			tab.defattr(*dline)
4368			dline = [("ip range","",2),"","","","","","",""]
4369			if leaderconn.version_at_least(1,7,0):
4370				dline.append("")
4371			dline.extend((("map root","",2),("map users","",2)))
4372			if leaderconn.version_at_least(1,6,26):
4373				dline.extend((("goal limit","",2),("trashtime limit","",2)))
4374			tab.header(*dline)
4375			dline = [("---","",2),"path","minversion","alldirs","password","ro/rw","restrict ip","ignore gid"]
4376			if leaderconn.version_at_least(1,7,0):
4377				dline.append("admin")
4378			if leaderconn.version_at_least(1,6,26):
4379				dline.append(("---","",8))
4380			else:
4381				dline.append(("---","",4))
4382			tab.header(*dline)
4383			dline = ["from","to","","","","","","",""]
4384			if leaderconn.version_at_least(1,7,0):
4385				dline.append("")
4386			dline.extend(("uid","gid","uid","gid"))
4387			if leaderconn.version_at_least(1,6,26):
4388				dline.extend(("min","max","min","max"))
4389			tab.header(*dline)
4390		else:
4391			tab = Tabble("exports",(18 if leaderconn.version_at_least(1,7,0) else 17 if leaderconn.version_at_least(1,6,26) else 13))
4392		if leaderconn.version_at_least(1,6,26):
4393			data,length = leaderconn.command(CLTOMA_EXPORTS_INFO,MATOCL_EXPORTS_INFO,struct.pack(">B",1))
4394		else:
4395			data,length = leaderconn.command(CLTOMA_EXPORTS_INFO,MATOCL_EXPORTS_INFO)
4396		servers = []
4397		pos = 0
4398		while pos<length:
4399			fip1,fip2,fip3,fip4,tip1,tip2,tip3,tip4,pleng = struct.unpack(">BBBBBBBBL",data[pos:pos+12])
4400			ipfrom = "%d.%d.%d.%d" % (fip1,fip2,fip3,fip4)
4401			ipto = "%d.%d.%d.%d" % (tip1,tip2,tip3,tip4)
4402			sortipfrom = "%03d.%03d.%03d.%03d" % (fip1,fip2,fip3,fip4)
4403			sortipto = "%03d.%03d.%03d.%03d" % (tip1,tip2,tip3,tip4)
4404			pos+=12
4405			path = data[pos:pos+pleng]
4406			if sys.version_info[0]>=3:
4407				try:
4408					path = path.decode('ascii')
4409				except UnicodeDecodeError:
4410					pass
4411			pos+=pleng
4412			if leaderconn.version_at_least(1,6,26):
4413				v1,v2,v3,exportflags,sesflags,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime = struct.unpack(">HBBBBLLLLBBLL",data[pos:pos+32])
4414				pos+=32
4415				if mingoal<=1 and maxgoal>=9:
4416					mingoal = None
4417					maxgoal = None
4418				if mintrashtime==0 and maxtrashtime==0xFFFFFFFF:
4419					mintrashtime = None
4420					maxtrashtime = None
4421			else:
4422				v1,v2,v3,exportflags,sesflags,rootuid,rootgid,mapalluid,mapallgid = struct.unpack(">HBBBBLLLL",data[pos:pos+22])
4423				mingoal = None;
4424				maxgoal = None;
4425				mintrashtime = None;
4426				maxtrashtime = None;
4427				pos+=22
4428			strver,sortver = version_str_and_sort((v1,v2,v3))
4429			if path=='.':
4430				meta=1
4431			else:
4432				meta=0
4433			sf = (fip1,fip2,fip3,fip4,tip1,tip2,tip3,tip4)
4434			if EXorder==1:
4435				sf = sortipfrom
4436			elif EXorder==2:
4437				sf = sortipto
4438			elif EXorder==3:
4439				sf = path
4440			elif EXorder==4:
4441				sf = sortver
4442			elif EXorder==5:
4443				if meta:
4444					sf = None
4445				else:
4446					sf = exportflags&1
4447			elif EXorder==6:
4448				sf = exportflags&2
4449			elif EXorder==7:
4450				sf = sesflags&1
4451			elif EXorder==8:
4452				sf = 2-(sesflags&2)
4453			elif EXorder==9:
4454				if meta:
4455					sf = None
4456				else:
4457					sf = sesflags&4
4458			elif EXorder==10:
4459				if meta:
4460					sf = None
4461				else:
4462					sf = sesflags&8
4463			elif EXorder==11:
4464				if meta:
4465					sf = None
4466				else:
4467					sf = rootuid
4468			elif EXorder==12:
4469				if meta:
4470					sf = None
4471				else:
4472					sf = rootgid
4473			elif EXorder==13:
4474				if meta or (sesflags&16)==0:
4475					sf = None
4476				else:
4477					sf = mapalluid
4478			elif EXorder==14:
4479				if meta or (sesflags&16)==0:
4480					sf = None
4481				else:
4482					sf = mapalguid
4483			elif EXorder==15:
4484				sf = mingoal
4485			elif EXorder==16:
4486				sf = maxgoal
4487			elif EXorder==17:
4488				sf = mintrashtime
4489			elif EXorder==18:
4490				sf = maxtrashtime
4491			servers.append((sf,sortipfrom,ipfrom,sortipto,ipto,path,meta,sortver,strver,exportflags,sesflags,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime))
4492		servers.sort()
4493		if EXrev:
4494			servers.reverse()
4495		for sf,sortipfrom,ipfrom,sortipto,ipto,path,meta,sortver,strver,exportflags,sesflags,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime in servers:
4496			if cgimode:
4497				out.append("""	<tr>""")
4498				out.append("""		<td align="right"></td>""")
4499				out.append("""		<td align="center"><span class="sortkey">%s </span>%s</td>""" % (sortipfrom,ipfrom))
4500				out.append("""		<td align="center"><span class="sortkey">%s </span>%s</td>""" % (sortipto,ipto))
4501				out.append("""		<td align="left">%s</td>""" % (".&nbsp;(META)" if meta else path))
4502				out.append("""		<td align="center"><span class="sortkey">%s </span>%s</td>""" % (sortver,strver))
4503				out.append("""		<td align="center">%s</td>""" % ("-" if meta else "yes" if exportflags&1 else "no"))
4504				out.append("""		<td align="center">%s</td>""" % ("yes" if exportflags&2 else "no"))
4505				out.append("""		<td align="center">%s</td>""" % ("ro" if sesflags&1 else "rw"))
4506				out.append("""		<td align="center">%s</td>""" % ("no" if sesflags&2 else "yes"))
4507				out.append("""		<td align="center">%s</td>""" % ("-" if meta else "yes" if sesflags&4 else "no"))
4508				if leaderconn.version_at_least(1,7,0):
4509					out.append("""		<td align="center">%s</td>""" % ("-" if meta else "yes" if sesflags&8 else "no"))
4510				if meta:
4511					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
4512					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
4513				else:
4514					out.append("""		<td align="right">%u</td>""" % rootuid)
4515					out.append("""		<td align="right">%u</td>""" % rootgid)
4516				if meta or (sesflags&16)==0:
4517					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
4518					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
4519				else:
4520					out.append("""		<td align="right">%u</td>""" % mapalluid)
4521					out.append("""		<td align="right">%u</td>""" % mapallgid)
4522				if leaderconn.version_at_least(1,6,26):
4523					if mingoal!=None and maxgoal!=None:
4524						out.append("""		<td align="right">%u</td>""" % mingoal)
4525						out.append("""		<td align="right">%u</td>""" % maxgoal)
4526					else:
4527						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
4528						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
4529					if mintrashtime!=None and maxtrashtime!=None:
4530						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s">%s</a></td>""" % (mintrashtime,timeduration_to_fullstr(mintrashtime),timeduration_to_shortstr(mintrashtime)))
4531						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s">%s</a></td>""" % (maxtrashtime,timeduration_to_fullstr(maxtrashtime),timeduration_to_shortstr(maxtrashtime)))
4532					else:
4533						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
4534						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
4535				out.append("""	</tr>""")
4536			elif ttymode:
4537				dline = [ipfrom,ipto,". (META)" if meta else path,strver,"-" if meta else "yes" if exportflags&1 else "no","yes" if exportflags&2 else "no","ro" if sesflags&1 else "rw","no" if sesflags&2 else "yes","-" if meta else "yes" if sesflags&4 else "no"]
4538				if leaderconn.version_at_least(1,7,0):
4539					dline.append("-" if meta else "yes" if sesflags&8 else "no")
4540				if meta:
4541					dline.extend(("-","-"))
4542				else:
4543					dline.extend((rootuid,rootgid))
4544				if meta or (sesflags&16)==0:
4545					dline.extend(("-","-"))
4546				else:
4547					dline.extend((mapalluid,mapallgid))
4548				if leaderconn.version_at_least(1,6,26):
4549					if mingoal!=None and maxgoal!=None:
4550						dline.extend((mingoal,maxgoal))
4551					else:
4552						dline.extend(("-","-"))
4553					if mintrashtime!=None and maxtrashtime!=None:
4554						dline.extend((timeduration_to_shortstr(mintrashtime),timeduration_to_shortstr(maxtrashtime)))
4555					else:
4556						dline.extend(("-","-"))
4557				tab.append(*dline)
4558			else:
4559				dline = [ipfrom,ipto,". (META)" if meta else path,strver,"-" if meta else "yes" if exportflags&1 else "no","yes" if exportflags&2 else "no","ro" if sesflags&1 else "rw","no" if sesflags&2 else "yes","-" if meta else "yes" if sesflags&4 else "no"]
4560				if leaderconn.version_at_least(1,7,0):
4561					dline.append("-" if meta else "yes" if sesflags&8 else "no")
4562				if meta:
4563					dline.extend(("-","-"))
4564				else:
4565					dline.extend((rootuid,rootgid))
4566				if meta or (sesflags&16)==0:
4567					dline.extend(("-","-"))
4568				else:
4569					dline.extend((mapalluid,mapallgid))
4570				if leaderconn.version_at_least(1,6,26):
4571					if mingoal!=None and maxgoal!=None:
4572						dline.extend((mingoal,maxgoal))
4573					else:
4574						dline.extend(("-","-"))
4575					if mintrashtime!=None and maxtrashtime!=None:
4576						dline.extend((mintrashtime,maxtrashtime))
4577					else:
4578						dline.extend(("-","-"))
4579				tab.append(*dline)
4580		if cgimode:
4581			out.append("""</table>""")
4582			print("\n".join(out))
4583		else:
4584			print(tab)
4585	except Exception:
4586		print_exception()
4587
4588if "MS" in sectionset:
4589	if needseparator:
4590		if cgimode:
4591			print("""<br/>""")
4592		else:
4593			print("")
4594	else:
4595		needseparator=1
4596
4597	try:
4598		if cgimode:
4599			out = []
4600			out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsmounts" cellspacing="0">""")
4601			out.append("""	<tr><th colspan="%u">Active mounts (parameters)</th></tr>""" % (21 if leaderconn.version_at_least(1,7,8) else 19 if leaderconn.version_at_least(1,7,0) else 18 if leaderconn.version_at_least(1,6,26) else 14))
4602			out.append("""	<tr>""")
4603			out.append("""		<th rowspan="2" class="acid_tab_enumerate">#</th>""")
4604#			out.append("""		<th rowspan="2"><a href="%s">session&nbsp;id</a></th>""" % (createorderlink("MS",1)))
4605#			out.append("""		<th rowspan="2"><a href="%s">host</a></th>""" % (createorderlink("MS",2)))
4606#			out.append("""		<th rowspan="2"><a href="%s">ip</a></th>""" % (createorderlink("MS",3)))
4607#			out.append("""		<th rowspan="2"><a href="%s">mount&nbsp;point</a></th>""" % (createorderlink("MS",4)))
4608#			out.append("""		<th rowspan="2"><a href="%s">version</a></th>""" % (createorderlink("MS",5)))
4609#			out.append("""		<th rowspan="2"><a href="%s">root&nbsp;dir</a></th>""" % (createorderlink("MS",6)))
4610#			out.append("""		<th rowspan="2"><a href="%s">ro/rw</a></th>""" % (createorderlink("MS",7)))
4611#			out.append("""		<th rowspan="2"><a href="%s">restricted&nbsp;ip</a></th>""" % (createorderlink("MS",8)))
4612#			out.append("""		<th rowspan="2"><a href="%s">ignore&nbsp;gid</a></th>""" % (createorderlink("MS",9)))
4613			out.append("""		<th rowspan="2">session&nbsp;id</th>""")
4614			out.append("""		<th rowspan="2">host</th>""")
4615			out.append("""		<th rowspan="2">ip</th>""")
4616			out.append("""		<th rowspan="2">mount&nbsp;point</th>""")
4617			if leaderconn.version_at_least(1,7,8):
4618				out.append("""		<th rowspan="2">open files</th>""")
4619				out.append("""		<th rowspan="2"># of connections</th>""")
4620			out.append("""		<th rowspan="2">version</th>""")
4621			out.append("""		<th rowspan="2">root&nbsp;dir</th>""")
4622			out.append("""		<th rowspan="2">ro/rw</th>""")
4623			out.append("""		<th rowspan="2">restricted&nbsp;ip</th>""")
4624			out.append("""		<th rowspan="2">ignore&nbsp;gid</th>""")
4625			if leaderconn.version_at_least(1,7,0):
4626#				out.append("""		<th rowspan="2"><a href="%s">can&nbsp;change&nbsp;quota</a></th>""" % (createorderlink("MS",10)))
4627				out.append("""		<th rowspan="2">admin</th>""")
4628			out.append("""		<th colspan="2">map&nbsp;root</th>""")
4629			out.append("""		<th colspan="2">map&nbsp;users</th>""")
4630			if leaderconn.version_at_least(1,6,26):
4631				out.append("""		<th colspan="2">goal&nbsp;limits</th>""")
4632				out.append("""		<th colspan="2">trashtime&nbsp;limits</th>""")
4633			out.append("""	</tr>""")
4634			out.append("""	<tr>""")
4635#			out.append("""		<th><a href="%s">uid</a></th>""" % (createorderlink("MS",11)))
4636#			out.append("""		<th><a href="%s">gid</a></th>""" % (createorderlink("MS",12)))
4637#			out.append("""		<th><a href="%s">uid</a></th>""" % (createorderlink("MS",13)))
4638#			out.append("""		<th><a href="%s">gid</a></th>""" % (createorderlink("MS",14)))
4639			out.append("""		<th>uid</th>""")
4640			out.append("""		<th>gid</th>""")
4641			out.append("""		<th>uid</th>""")
4642			out.append("""		<th>gid</th>""")
4643			if leaderconn.version_at_least(1,6,26):
4644#				out.append("""		<th><a href="%s">min</a></th>""" % (createorderlink("MS",15)))
4645#				out.append("""		<th><a href="%s">max</a></th>""" % (createorderlink("MS",16)))
4646#				out.append("""		<th><a href="%s">min</a></th>""" % (createorderlink("MS",17)))
4647#				out.append("""		<th><a href="%s">max</a></th>""" % (createorderlink("MS",18)))
4648				out.append("""		<th>min</th>""")
4649				out.append("""		<th>max</th>""")
4650				out.append("""		<th>min</th>""")
4651				out.append("""		<th>max</th>""")
4652			out.append("""	</tr>""")
4653		elif ttymode:
4654			tab = Tabble("Active mounts (parameters)",(19 if leaderconn.version_at_least(1,7,8) else 17 if leaderconn.version_at_least(1,7,0) else 16 if leaderconn.version_at_least(1,6,26) else 12))
4655			dline = ["r","r","l"]
4656			if leaderconn.version_at_least(1,7,8):
4657				dline.extend(("r","r"))
4658			dline.extend(("r","l","c","c","c"))
4659			if leaderconn.version_at_least(1,7,0):
4660				dline.append("c")
4661			dline.extend(("r","r","r","r"))
4662			if leaderconn.version_at_least(1,6,26):
4663				dline.extend(("r","r","r","r"))
4664			tab.defattr(*dline)
4665			dline = ["","","","","","","",""]
4666			if leaderconn.version_at_least(1,7,0):
4667				if leaderconn.version_at_least(1,7,8):
4668					dline.extend(("",""))
4669				dline.append("")
4670			dline.extend((("map root","",2),("map users","",2)))
4671			if leaderconn.version_at_least(1,6,26):
4672				dline.extend((("goal limit","",2),("trashtime limit","",2)))
4673			tab.header(*dline)
4674			dline = ["session id","ip/host","mount point"]
4675			if leaderconn.version_at_least(1,7,8):
4676				dline.extend(("open files","# of connections"))
4677			dline.extend(("version","root dir","ro/rw","restrict ip","ignore gid"))
4678			if leaderconn.version_at_least(1,7,0):
4679				dline.append("admin")
4680			if leaderconn.version_at_least(1,6,26):
4681				dline.append(("---","",8))
4682			else:
4683				dline.append(("---","",4))
4684			tab.header(*dline)
4685			dline = ["","","","","","","",""]
4686			if leaderconn.version_at_least(1,7,0):
4687				if leaderconn.version_at_least(1,7,8):
4688					dline.extend(("",""))
4689				dline.append("")
4690			dline.extend(("uid","gid","uid","gid"))
4691			if leaderconn.version_at_least(1,6,26):
4692				dline.extend(("min","max","min","max"))
4693			tab.header(*dline)
4694		else:
4695			tab = Tabble("active mounts, parameters",(19 if leaderconn.version_at_least(1,7,8) else 17 if leaderconn.version_at_least(1,7,0) else 16 if leaderconn.version_at_least(1,6,26) else 12))
4696		if leaderconn.version_at_least(1,7,8):
4697			data,length = leaderconn.command(CLTOMA_SESSION_LIST,MATOCL_SESSION_LIST,struct.pack(">B",2))
4698		elif leaderconn.version_at_least(1,6,26):
4699			data,length = leaderconn.command(CLTOMA_SESSION_LIST,MATOCL_SESSION_LIST,struct.pack(">B",1))
4700		else:
4701			data,length = leaderconn.command(CLTOMA_SESSION_LIST,MATOCL_SESSION_LIST)
4702		servers = []
4703		dservers = []
4704		if leaderconn.version_less_than(1,6,21):
4705			statscnt = 16
4706			pos = 0
4707		elif leaderconn.version_is(1,6,21):
4708			statscnt = 21
4709			pos = 0
4710		else:
4711			statscnt = struct.unpack(">H",data[0:2])[0]
4712			pos = 2
4713		while pos<length:
4714			if leaderconn.version_at_least(1,7,8):
4715				sessionid,ip1,ip2,ip3,ip4,v1,v2,v3,openfiles,nsocks,expire,ileng = struct.unpack(">LBBBBHBBLBLL",data[pos:pos+25])
4716				pos+=25
4717			else:
4718				sessionid,ip1,ip2,ip3,ip4,v1,v2,v3,ileng = struct.unpack(">LBBBBHBBL",data[pos:pos+16])
4719				pos+=16
4720				openfiles = 0;
4721				nsocks = 1
4722				expire = 0
4723			ipnum = "%u.%u.%u.%u" % (ip1,ip2,ip3,ip4)
4724			sortipnum = "%03u.%03u.%03u.%03u" % (ip1,ip2,ip3,ip4)
4725			strver,sortver = version_str_and_sort((v1,v2,v3))
4726			info = data[pos:pos+ileng]
4727			pos+=ileng
4728			pleng = struct.unpack(">L",data[pos:pos+4])[0]
4729			pos+=4
4730			path = data[pos:pos+pleng]
4731			pos+=pleng
4732			if sys.version_info[0]>=3:
4733				try:
4734					info = info.decode('ascii')
4735				except UnicodeDecodeError:
4736					pass
4737				try:
4738					path = path.decode('ascii')
4739				except UnicodeDecodeError:
4740					pass
4741			if leaderconn.version_at_least(1,6,26):
4742				sesflags,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime = struct.unpack(">BLLLLBBLL",data[pos:pos+27])
4743				pos+=27
4744				if mingoal<=1 and maxgoal>=9:
4745					mingoal = None
4746					maxgoal = None
4747				if mintrashtime==0 and maxtrashtime==0xFFFFFFFF:
4748					mintrashtime = None
4749					maxtrashtime = None
4750			else:
4751				sesflags,rootuid,rootgid,mapalluid,mapallgid = struct.unpack(">BLLLL",data[pos:pos+17])
4752				mingoal = None
4753				maxgoal = None
4754				mintrashtime = None
4755				maxtrashtime = None
4756				pos+=17
4757			pos+=8*statscnt		# skip stats
4758			if path=='.':
4759				meta=1
4760			else:
4761				meta=0
4762			host = resolve(ipnum)
4763#				if path=="":
4764#					path="(empty)"
4765			sf = sortipnum
4766			if MSorder==1:
4767				sf = sessionid
4768			elif MSorder==2:
4769				sf = host
4770			elif MSorder==3:
4771				sf = sortipnum
4772			elif MSorder==4:
4773				sf = info
4774			elif MSorder==5:
4775				sf = openfiles
4776			elif MSorder==6:
4777				if nsocks>0:
4778					sf = nsocks
4779				else:
4780					sf = expire
4781			elif MSorder==7:
4782				sf = sortver
4783			elif MSorder==8:
4784				sf = path
4785			elif MSorder==9:
4786				sf = sesflags&1
4787			elif MSorder==10:
4788				sf = 2-(sesflags&2)
4789			elif MSorder==11:
4790				if meta:
4791					sf = None
4792				else:
4793					sf = sesflags&4
4794			elif MSorder==12:
4795				if meta:
4796					sf = None
4797				else:
4798					sf = sesflags&8
4799			elif MSorder==13:
4800				if meta:
4801					sf = None
4802				else:
4803					sf = rootuid
4804			elif MSorder==14:
4805				if meta:
4806					sf = None
4807				else:
4808					sf = rootgid
4809			elif MSorder==15:
4810				if meta or (sesflags&16)==0:
4811					sf = None
4812				else:
4813					sf = mapalluid
4814			elif MSorder==16:
4815				if meta or (sesflags&16)==0:
4816					sf = None
4817				else:
4818					sf = mapallgid
4819			elif MSorder==17:
4820				sf = mingoal
4821			elif MSorder==18:
4822				sf = maxgoal
4823			elif MSorder==19:
4824				sf = mintrashtime
4825			elif MSorder==20:
4826				sf = maxtrashtime
4827			if nsocks>0:
4828				servers.append((sf,sessionid,host,sortipnum,ipnum,info,openfiles,nsocks,sortver,strver,meta,path,sesflags,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime))
4829			else:
4830				dservers.append((sf,sessionid,host,sortipnum,ipnum,info,openfiles,expire))
4831		servers.sort()
4832		dservers.sort()
4833		if MSrev:
4834			servers.reverse()
4835			dservers.reverse()
4836		for sf,sessionid,host,sortipnum,ipnum,info,openfiles,nsocks,sortver,strver,meta,path,sesflags,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime in servers:
4837			if cgimode:
4838				if leaderconn.is_pro() and not strver.endswith(" PRO"):
4839					verclass = "BADVERSION"
4840				elif leaderconn.sort_ver() > sortver:
4841					verclass = "LOWERVERSION"
4842				elif leaderconn.sort_ver() < sortver:
4843					verclass = "HIGHERVERSION"
4844				else:
4845					verclass = "OKVERSION"
4846				out.append("""	<tr>""")
4847				out.append("""		<td align="right"></td>""")
4848				out.append("""		<td align="center">%u</td>""" % sessionid)
4849				out.append("""		<td align="left">%s</td>""" % host)
4850				out.append("""		<td align="center"><span class="sortkey">%s </span>%s</td>""" % (sortipnum,ipnum))
4851				out.append("""		<td align="left">%s</td>""" % info)
4852				if leaderconn.version_at_least(1,7,8):
4853					out.append("""		<td align="center">%u</td>""" % openfiles)
4854					out.append("""		<td align="center">%u</td>""" % nsocks)
4855				out.append("""		<td align="center"><span class="sortkey">%s </span><span class="%s">%s</span></td>""" % (sortver,verclass,strver))
4856				out.append("""		<td align="left">%s</td>""" % (".&nbsp;(META)" if meta else path))
4857				out.append("""		<td align="center">%s</td>""" % ("ro" if sesflags&1 else "rw"))
4858				out.append("""		<td align="center">%s</td>""" % ("no" if sesflags&2 else "yes"))
4859				out.append("""		<td align="center">%s</td>""" % ("-" if meta else "yes" if sesflags&4 else "no"))
4860				if leaderconn.version_at_least(1,7,0):
4861					out.append("""		<td align="center">%s</td>""" % ("-" if meta else "yes" if sesflags&8 else "no"))
4862				if meta:
4863					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
4864					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
4865				else:
4866					out.append("""		<td align="right">%u</td>""" % rootuid)
4867					out.append("""		<td align="right">%u</td>""" % rootgid)
4868				if meta or (sesflags&16)==0:
4869					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
4870					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
4871				else:
4872					out.append("""		<td align="right">%u</td>""" % mapalluid)
4873					out.append("""		<td align="right">%u</td>""" % mapallgid)
4874				if leaderconn.version_at_least(1,6,26):
4875					if mingoal!=None and maxgoal!=None:
4876						out.append("""		<td align="right">%u</td>""" % mingoal)
4877						out.append("""		<td align="right">%u</td>""" % maxgoal)
4878					else:
4879						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
4880						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
4881					if mintrashtime!=None and maxtrashtime!=None:
4882						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s">%s</a></td>""" % (mintrashtime,timeduration_to_fullstr(mintrashtime),timeduration_to_shortstr(mintrashtime)))
4883						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s">%s</a></td>""" % (maxtrashtime,timeduration_to_fullstr(maxtrashtime),timeduration_to_shortstr(maxtrashtime)))
4884					else:
4885						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
4886						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
4887				out.append("""	</tr>""")
4888			elif ttymode:
4889				dline = [sessionid,host,info]
4890				if leaderconn.version_at_least(1,7,8):
4891					dline.extend((openfiles,nsocks))
4892				dline.extend((strver,".&nbsp;(META)" if meta else path,"ro" if sesflags&1 else "rw","no" if sesflags&2 else "yes","-" if meta else "yes" if sesflags&4 else "no"))
4893				if leaderconn.version_at_least(1,7,0):
4894					dline.append("-" if meta else "yes" if sesflags&8 else "no")
4895				if meta:
4896					dline.extend(("-","-"))
4897				else:
4898					dline.extend((rootuid,rootgid))
4899				if meta or (sesflags&16)==0:
4900					dline.extend(("-","-"))
4901				else:
4902					dline.extend((mapalluid,mapallgid))
4903				if leaderconn.version_at_least(1,6,26):
4904					if mingoal!=None and maxgoal!=None:
4905						dline.extend((mingoal,maxgoal))
4906					else:
4907						dline.extend(("-","-"))
4908					if mintrashtime!=None and maxtrashtime!=None:
4909						dline.extend((timeduration_to_shortstr(mintrashtime),timeduration_to_shortstr(maxtrashtime)))
4910					else:
4911						dline.extend(("-","-"))
4912				tab.append(*dline)
4913			else:
4914				dline = [sessionid,host,info]
4915				if leaderconn.version_at_least(1,7,8):
4916					dline.extend((openfiles,nsocks))
4917				dline.extend((strver,".&nbsp;(META)" if meta else path,"ro" if sesflags&1 else "rw","no" if sesflags&2 else "yes","-" if meta else "yes" if sesflags&4 else "no"))
4918				if leaderconn.version_at_least(1,7,0):
4919					dline.append("-" if meta else "yes" if sesflags&8 else "no")
4920				if meta:
4921					dline.extend(("-","-"))
4922				else:
4923					dline.extend((rootuid,rootgid))
4924				if meta or (sesflags&16)==0:
4925					dline.extend(("-","-"))
4926				else:
4927					dline.extend((mapalluid,mapallgid))
4928				if leaderconn.version_at_least(1,6,26):
4929					if mingoal!=None and maxgoal!=None:
4930						dline.extend((mingoal,maxgoal))
4931					else:
4932						dline.extend(("-","-"))
4933					if mintrashtime!=None and maxtrashtime!=None:
4934						dline.extend((mintrashtime,maxtrashtime))
4935					else:
4936						dline.extend(("-","-"))
4937				tab.append(*dline)
4938		if len(dservers)>0 and leaderconn.version_at_least(1,7,8):
4939			if cgimode:
4940				out.append("""</table>""")
4941				out.append("""<br/>""")
4942				out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsmounts" cellspacing="0">""")
4943				out.append("""	<tr><th colspan="8">Inactive mounts (parameters)</th></tr>""")
4944				out.append("""	<tr>""")
4945				out.append("""		<th class="acid_tab_enumerate">#</th>""")
4946				out.append("""		<th>session&nbsp;id</th>""")
4947				out.append("""		<th>host</th>""")
4948				out.append("""		<th>ip</th>""")
4949				out.append("""		<th>mount&nbsp;point</th>""")
4950				out.append("""		<th>open files</th>""")
4951				out.append("""		<th>expires</th>""")
4952				out.append("""		<th>cmd</th>""")
4953				out.append("""	</tr>""")
4954			elif ttymode:
4955				tabcols = (19 if leaderconn.version_at_least(1,7,8) else 17 if leaderconn.version_at_least(1,7,0) else 16 if leaderconn.version_at_least(1,6,26) else 12)
4956				tab.append(("---","",tabcols))
4957				tab.append(("Inactive mounts (parameters)","1c",tabcols))
4958				tab.append(("---","",tabcols))
4959				dline = [("session id","c"),("ip/host","c"),("mount point","c"),("open files","c"),("expires","c"),("command to remove","c",tabcols-5)]
4960				tab.append(*dline)
4961				tab.append(("---","",tabcols))
4962			else:
4963				print(tab)
4964				print("")
4965				tab = Tabble("inactive mounts, parameters",5)
4966		for sf,sessionid,host,sortipnum,ipnum,info,openfiles,expire in dservers:
4967			if cgimode:
4968				out.append("""	<tr>""")
4969				out.append("""		<td align="right"></td>""")
4970				out.append("""		<td align="center">%u</td>""" % sessionid)
4971				out.append("""		<td align="left">%s</td>""" % host)
4972				out.append("""		<td align="center"><span class="sortkey">%s </span>%s</td>""" % (sortipnum,ipnum))
4973				out.append("""		<td align="left">%s</td>""" % info)
4974				out.append("""		<td align="center">%u</td>""" % openfiles)
4975				out.append("""		<td align="center">%u</td>""" % expire)
4976				out.append("""		<td align="center"><a href="%s">click to remove</a></td>""" % createlink({"MSremove":("%u" % (sessionid))}))
4977				out.append("""	</tr>""")
4978			elif ttymode:
4979				tabcols = (19 if leaderconn.version_at_least(1,7,8) else 17 if leaderconn.version_at_least(1,7,0) else 16 if leaderconn.version_at_least(1,6,26) else 12)
4980				dline = [sessionid,host,info,openfiles,expire,("%s -H %s -P %u -CRS/%u" % (sys.argv[0],masterhost,masterport,sessionid),"l",tabcols-5)]
4981				tab.append(*dline)
4982			else:
4983				dline = [sessionid,host,info,openfiles,expire]
4984				tab.append(*dline)
4985		if cgimode:
4986			out.append("""</table>""")
4987			print("\n".join(out))
4988		else:
4989			print(tab)
4990	except Exception:
4991		print_exception()
4992
4993if "MO" in sectionset:
4994	if needseparator:
4995		if cgimode:
4996			print("""<br/>""")
4997		else:
4998			print("")
4999	else:
5000		needseparator=1
5001
5002	try:
5003		if cgimode:
5004			out = []
5005			out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsops" cellspacing="0" id="mfsops">""")
5006#			out.append("""<table class="FR" cellspacing="0">""")
5007			out.append("""	<tr><th colspan="21">Active mounts (operations)</th></tr>""")
5008			out.append("""	<tr>""")
5009			out.append("""		<th rowspan="2" class="acid_tab_enumerate">#</th>""")
5010#			out.append("""		<th rowspan="2"><a href="%s">host</a></th>""" % (createorderlink("MO",1)))
5011#			out.append("""		<th rowspan="2"><a href="%s">ip</a></th>""" % (createorderlink("MO",2)))
5012#			out.append("""		<th rowspan="2"><a href="%s">mount&nbsp;point</a></th>""" % (createorderlink("MO",3)))
5013			out.append("""		<th rowspan="2">host</th>""")
5014			out.append("""		<th rowspan="2">ip</th>""")
5015			out.append("""		<th rowspan="2">mount&nbsp;point</th>""")
5016			out.append("""		<th colspan="17">""")
5017			out.append("""			<span class="opshour_vis0">operations last hour (<a href="javascript:acid_tab.switchdisplay('mfsops','opshour_vis',1)" class="VISIBLELINK">switch to current</a>)</span>""")
5018			out.append("""			<span class="opshour_vis1">operations current hour (<a href="javascript:acid_tab.switchdisplay('mfsops','opshour_vis',0)" class="VISIBLELINK">switch to last</a>)</span>""")
5019			out.append("""		</th>""")
5020			out.append("""	</tr>""")
5021			out.append("""	<tr>""")
5022#			out.append("""		<th><a href="%s">statfs</a></th>""" % (createorderlink("MO",100)))
5023#			out.append("""		<th><a href="%s">getattr</a></th>""" % (createorderlink("MO",101)))
5024#			out.append("""		<th><a href="%s">setattr</a></th>""" % (createorderlink("MO",102)))
5025#			out.append("""		<th><a href="%s">lookup</a></th>""" % (createorderlink("MO",103)))
5026#			out.append("""		<th><a href="%s">mkdir</a></th>""" % (createorderlink("MO",104)))
5027#			out.append("""		<th><a href="%s">rmdir</a></th>""" % (createorderlink("MO",105)))
5028#			out.append("""		<th><a href="%s">symlink</a></th>""" % (createorderlink("MO",106)))
5029#			out.append("""		<th><a href="%s">readlink</a></th>""" % (createorderlink("MO",107)))
5030#			out.append("""		<th><a href="%s">mknod</a></th>""" % (createorderlink("MO",108)))
5031#			out.append("""		<th><a href="%s">unlink</a></th>""" % (createorderlink("MO",109)))
5032#			out.append("""		<th><a href="%s">rename</a></th>""" % (createorderlink("MO",110)))
5033#			out.append("""		<th><a href="%s">link</a></th>""" % (createorderlink("MO",111)))
5034#			out.append("""		<th><a href="%s">readdir</a></th>""" % (createorderlink("MO",112)))
5035#			out.append("""		<th><a href="%s">open</a></th>""" % (createorderlink("MO",113)))
5036#			out.append("""		<th><a href="%s">read</a></th>""" % (createorderlink("MO",114)))
5037#			out.append("""		<th><a href="%s">write</a></th>""" % (createorderlink("MO",115)))
5038#			out.append("""		<th><a href="%s">total</a></th>""" % (createorderlink("MO",150)))
5039			out.append("""		<th class="acid_tab_level_1">statfs</th>""")
5040			out.append("""		<th class="acid_tab_level_1">getattr</th>""")
5041			out.append("""		<th class="acid_tab_level_1">setattr</th>""")
5042			out.append("""		<th class="acid_tab_level_1">lookup</th>""")
5043			out.append("""		<th class="acid_tab_level_1">mkdir</th>""")
5044			out.append("""		<th class="acid_tab_level_1">rmdir</th>""")
5045			out.append("""		<th class="acid_tab_level_1">symlink</th>""")
5046			out.append("""		<th class="acid_tab_level_1">readlink</th>""")
5047			out.append("""		<th class="acid_tab_level_1">mknod</th>""")
5048			out.append("""		<th class="acid_tab_level_1">unlink</th>""")
5049			out.append("""		<th class="acid_tab_level_1">rename</th>""")
5050			out.append("""		<th class="acid_tab_level_1">link</th>""")
5051			out.append("""		<th class="acid_tab_level_1">readdir</th>""")
5052			out.append("""		<th class="acid_tab_level_1">open</th>""")
5053			out.append("""		<th class="acid_tab_level_1">read</th>""")
5054			out.append("""		<th class="acid_tab_level_1">write</th>""")
5055			out.append("""		<th class="acid_tab_level_1">total</th>""")
5056			out.append("""	</tr>""")
5057		elif ttymode:
5058			tab = Tabble("Active mounts (operations)",19)
5059			tab.header("","",("operations %s hour" % ("last" if MOdata==0 else "current"),"",17))
5060			tab.header("host/ip","mount point",("---","",17))
5061			tab.header("","","statfs","getattr","setattr","lookup","mkdir","rmdir","symlink","readlink","mknod","unlink","rename","link","readdir","open","read","write","total")
5062			tab.defattr("r","l","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r")
5063		else:
5064			tab = Tabble("active mounts, operations",19)
5065		data,length = leaderconn.command(CLTOMA_SESSION_LIST,MATOCL_SESSION_LIST)
5066		servers = []
5067		if leaderconn.version_less_than(1,6,21):
5068			statscnt = 16
5069			pos = 0
5070		elif leaderconn.version_is(1,6,21):
5071			statscnt = 21
5072			pos = 0
5073		else:
5074			statscnt = struct.unpack(">H",data[0:2])[0]
5075			pos = 2
5076		while pos<length:
5077			sessionid,ip1,ip2,ip3,ip4,v1,v2,v3,ileng = struct.unpack(">LBBBBHBBL",data[pos:pos+16])
5078			sortipnum = "%03u.%03u.%03u.%03u" % (ip1,ip2,ip3,ip4)
5079			ipnum = "%u.%u.%u.%u" % (ip1,ip2,ip3,ip4)
5080#				sortver = "$05u.%03u.%03u" % (v1,v2,v3)
5081#				strver = "%u.%u.%u" % (v1,v2,v3)
5082			pos+=16
5083			info = data[pos:pos+ileng]
5084			pos+=ileng
5085			pleng = struct.unpack(">L",data[pos:pos+4])[0]
5086			pos+=4
5087			path = data[pos:pos+pleng]
5088			pos+=pleng
5089			if sys.version_info[0]>=3:
5090				try:
5091					info = info.decode('ascii')
5092				except UnicodeDecodeError:
5093					pass
5094				try:
5095					path = path.decode('ascii')
5096				except UnicodeDecodeError:
5097					pass
5098			# sesflags,rootuid,rootgid,mapalluid,mapallgid = struct.unpack(">BLLLL",data[pos:pos+17])
5099			pos+=17
5100			if statscnt<16:
5101				stats_c = struct.unpack(">"+"L"*statscnt,data[pos:pos+4*statscnt])+(0,)*(16-statscnt)
5102				pos+=statscnt*4
5103				stats_l = struct.unpack(">"+"L"*statscnt,data[pos:pos+4*statscnt])+(0,)*(16-statscnt)
5104				pos+=statscnt*4
5105			else:
5106				stats_c = struct.unpack(">LLLLLLLLLLLLLLLL",data[pos:pos+64])
5107				pos+=statscnt*4
5108				stats_l = struct.unpack(">LLLLLLLLLLLLLLLL",data[pos:pos+64])
5109				pos+=statscnt*4
5110			host = resolve(ipnum)
5111			sf = sortipnum
5112			if MOorder==1:
5113				sf = host
5114			elif MOorder==2:
5115				sf = sortipnum
5116			elif MOorder==3:
5117				sf = info
5118			elif MOorder>=100 and MOorder<=115:
5119				if MOdata==0:
5120					sf = stats_l[MOorder-100]
5121				else:
5122					sf = stats_c[MOorder-100]
5123				if cgimode:
5124					sf = -sf
5125			elif MOorder==150:
5126				if MOdata==0:
5127					sf = sum(stats_l)
5128				else:
5129					sf = sum(stats_c)
5130				if cgimode:
5131					sf = -sf
5132			if path!='.':
5133				servers.append((sf,host,ipnum,info,stats_c,stats_l))
5134		servers.sort()
5135		if MOrev:
5136			servers.reverse()
5137		for sf,host,ipnum,info,stats_c,stats_l in servers:
5138			if cgimode:
5139				out.append("""	<tr>""")
5140				out.append("""		<td align="right"></td>""")
5141				out.append("""		<td align="left">%s</td>""" % host)
5142				out.append("""		<td align="center"><span class="sortkey">%s</span>%s</td>""" % (sortipnum,ipnum))
5143				out.append("""		<td align="left">%s</td>""" % info)
5144				for st in range(16):
5145					out.append("""		<td align="right">""")
5146					out.append("""			<span class="opshour_vis0"><a style="cursor:default" title="current:%u last:%u">%u</a></span>""" % (stats_c[st],stats_l[st],stats_l[st]))
5147					out.append("""			<span class="opshour_vis1"><a style="cursor:default" title="current:%u last:%u">%u</a></span>""" % (stats_c[st],stats_l[st],stats_c[st]))
5148					out.append("""		</td>""")
5149				out.append("""		<td align="right">""")
5150				out.append("""			<span class="opshour_vis0"><a style="cursor:default" title="current:%u last:%u">%u</a></span>""" % (sum(stats_c),sum(stats_l),sum(stats_l)))
5151				out.append("""			<span class="opshour_vis1"><a style="cursor:default" title="current:%u last:%u">%u</a></span>""" % (sum(stats_c),sum(stats_l),sum(stats_c)))
5152				out.append("""		</td>""")
5153#					if MOdata==0:
5154#						for st in xrange(16):
5155#							out.append("""		<td align="right"><a style="cursor:default" title="current:%u last:%u">%u</a></td>""" % (stats_c[st],stats_l[st],stats_l[st]))
5156#						out.append("""		<td align="right"><a style="cursor:default" title="current:%u last:%u">%u</a></td>""" % (sum(stats_c),sum(stats_l),sum(stats_l)))
5157#					else:
5158#						for st in xrange(16):
5159#							out.append("""		<td align="right"><a style="cursor:default" title="current:%u last:%u">%u</a></td>""" % (stats_c[st],stats_l[st],stats_c[st]))
5160#						out.append("""		<td align="right"><a style="cursor:default" title="current:%u last:%u">%u</a></td>""" % (sum(stats_c),sum(stats_l),sum(stats_c)))
5161				out.append("""	</tr>""")
5162			else:
5163				ldata = [host,info]
5164				if MOdata==0:
5165					ldata.extend(stats_l)
5166					ldata.append(sum(stats_l))
5167				else:
5168					ldata.extend(stats_c)
5169					ldata.append(sum(stats_c))
5170				tab.append(*ldata)
5171		if cgimode:
5172			out.append("""</table>""")
5173			print("\n".join(out))
5174		else:
5175			print(tab)
5176	except Exception:
5177		print_exception()
5178
5179if "QU" in sectionset:
5180	if needseparator:
5181		if cgimode:
5182			print("""<br/>""")
5183		else:
5184			print("")
5185	else:
5186		needseparator=1
5187
5188	try:
5189		if cgimode:
5190			out = []
5191			out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsquota" cellspacing="0">""")
5192			out.append("""	<tr><th colspan="23">Active quotas</th></tr>""")
5193			out.append("""	<tr>""")
5194			out.append("""		<th rowspan="3" class="acid_tab_enumerate">#</th>""")
5195#			out.append("""		<th rowspan="2"><a href="%s">path</a></th>""" % (createorderlink("QU",11)))
5196#			out.append("""		<th rowspan="2"><a href="%s">exceeded</a></th>""" % (createorderlink("QU",2)))
5197			out.append("""		<th rowspan="3">path</th>""")
5198			out.append("""	<th colspan="5">soft&nbsp;quota</th>""")
5199			out.append("""	<th colspan="4">hard&nbsp;quota</th>""")
5200			out.append("""	<th colspan="12">current&nbsp;values</th>""")
5201			out.append("""	</tr>""")
5202			out.append("""	<tr>""")
5203#			out.append("""		<th><a href="%s">time&nbsp;to&nbsp;expire</a></th>""" % (createorderlink("QU",10)))
5204#			out.append("""		<th><a href="%s">inodes</a></th>""" % (createorderlink("QU",11)))
5205#			out.append("""		<th><a href="%s">length</a></th>""" % (createorderlink("QU",12)))
5206#			out.append("""		<th><a href="%s">size</a></th>""" % (createorderlink("QU",13)))
5207#			out.append("""		<th><a href="%s">real&nbsp;size</a></th>""" % (createorderlink("QU",14)))
5208#			out.append("""		<th><a href="%s">inodes</a></th>""" % (createorderlink("QU",21)))
5209#			out.append("""		<th><a href="%s">length</a></th>""" % (createorderlink("QU",22)))
5210#			out.append("""		<th><a href="%s">size</a></th>""" % (createorderlink("QU",23)))
5211#			out.append("""		<th><a href="%s">real&nbsp;size</a></th>""" % (createorderlink("QU",24)))
5212#			out.append("""		<th><a href="%s">inodes</a></th>""" % (createorderlink("QU",31)))
5213#			out.append("""		<th><a href="%s">length</a></th>""" % (createorderlink("QU",32)))
5214#			out.append("""		<th><a href="%s">size</a></th>""" % (createorderlink("QU",33)))
5215#			out.append("""		<th><a href="%s">real&nbsp;size</a></th>""" % (createorderlink("QU",34)))
5216#			out.append("""		<th>exceeded</th>""")
5217			out.append("""		<th rowspan="2">time&nbsp;to&nbsp;expire</th>""")
5218			out.append("""		<th rowspan="2">inodes</th>""")
5219			out.append("""		<th rowspan="2">length</th>""")
5220			out.append("""		<th rowspan="2">size</th>""")
5221			out.append("""		<th rowspan="2">real&nbsp;size</th>""")
5222			out.append("""		<th rowspan="2">inodes</th>""")
5223			out.append("""		<th rowspan="2">length</th>""")
5224			out.append("""		<th rowspan="2">size</th>""")
5225			out.append("""		<th rowspan="2">real&nbsp;size</th>""")
5226			out.append("""		<th colspan="3">inodes</th>""")
5227			out.append("""		<th colspan="3">length</th>""")
5228			out.append("""		<th colspan="3">size</th>""")
5229			out.append("""		<th colspan="3">real&nbsp;size</th>""")
5230			out.append("""	</tr>""")
5231			out.append("""	<tr>""")
5232			out.append("""		<th>value</th>""")
5233			out.append("""		<th>% soft</th>""")
5234			out.append("""		<th>% hard</th>""")
5235			out.append("""		<th>value</th>""")
5236			out.append("""		<th>% soft</th>""")
5237			out.append("""		<th>% hard</th>""")
5238			out.append("""		<th>value</th>""")
5239			out.append("""		<th>% soft</th>""")
5240			out.append("""		<th>% hard</th>""")
5241			out.append("""		<th>value</th>""")
5242			out.append("""		<th>% soft</th>""")
5243			out.append("""		<th>% hard</th>""")
5244			out.append("""	</tr>""")
5245		elif ttymode:
5246#			tab = Tabble("Active quotas",14)
5247#			tab.header("",("soft quota","",5),("hard quota","",4),("current values","",4))
5248#			tab.header("path",("---","",13))
5249#			tab.header("","time to expire","inodes","length","size","real size","inodes","length","size","real size","inodes","length","size","real size")
5250#			tab.defattr("l","r","r","r","r","r","r","r","r","r","r","r","r","r")
5251			tab = Tabble("Active quotas",22)
5252			tab.header("",("soft quota","",5),("hard quota","",4),("current values","",12))
5253			tab.header("",("---","",21))
5254			tab.header("path","","","","","","","","","",("inodes","",3),("length","",3),("size","",3),("real size","",3))
5255			tab.header("","time to expire","inodes","length","size","real size","inodes","length","size","real size",("---","",12))
5256			tab.header("","","","","","","","","","","value","% soft","% hard","value","% soft","% hard","value","% soft","% hard","value","% soft","% hard")
5257			tab.defattr("l","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r")
5258		else:
5259			tab = Tabble("active quotas",15)
5260		data,length = leaderconn.command(CLTOMA_QUOTA_INFO,MATOCL_QUOTA_INFO)
5261		if length>=4 and leaderconn.version_at_least(1,7,0):
5262			quotas = []
5263			maxperc = 0.0
5264			pos = 0
5265			while pos<length:
5266				inode,pleng = struct.unpack(">LL",data[pos:pos+8])
5267				pos+=8
5268				path = data[pos:pos+pleng]
5269				if sys.version_info[0]>=3:
5270					try:
5271						path = path.decode('ascii')
5272					except UnicodeDecodeError:
5273						pass
5274				pos+=pleng
5275				exceeded,qflags,timetoblock = struct.unpack(">BBL",data[pos:pos+6])
5276				pos+=6;
5277				sinodes,slength,ssize,srealsize = struct.unpack(">LQQQ",data[pos:pos+28])
5278				pos+=28
5279				hinodes,hlength,hsize,hrealsize = struct.unpack(">LQQQ",data[pos:pos+28])
5280				pos+=28
5281				cinodes,clength,csize,crealsize = struct.unpack(">LQQQ",data[pos:pos+28])
5282				pos+=28
5283				if (qflags&1) and sinodes>0:
5284					perc = 100.0*cinodes/sinodes
5285					if perc>maxperc:
5286						maxperc = perc
5287				if (qflags&2) and slength>0:
5288					perc = 100.0*clength/slength
5289					if perc>maxperc:
5290						maxperc = perc
5291				if (qflags&4) and ssize>0:
5292					perc = 100.0*csize/ssize
5293					if perc>maxperc:
5294						maxperc = perc
5295				if (qflags&8) and srealsize>0:
5296					perc = 100.0*crealsize/srealsize
5297					if perc>maxperc:
5298						maxperc = perc
5299				if (qflags&16) and hinodes>0:
5300					perc = 100.0*cinodes/hinodes
5301					if perc>maxperc:
5302						maxperc = perc
5303				if (qflags&32) and hlength>0:
5304					perc = 100.0*clength/hlength
5305					if perc>maxperc:
5306						maxperc = perc
5307				if (qflags&64) and hsize>0:
5308					perc = 100.0*csize/hsize
5309					if perc>maxperc:
5310						maxperc = perc
5311				if (qflags&128) and hrealsize>0:
5312					perc = 100.0*crealsize/hrealsize
5313					if perc>maxperc:
5314						maxperc = perc
5315				sf = path
5316				if QUorder==1:
5317					sf = path
5318				elif QUorder==2:
5319					sf = exceeded
5320				elif QUorder==10:
5321					sf = timetoblock
5322				elif QUorder==11:
5323					sf = sinodes
5324				elif QUorder==12:
5325					sf = slength
5326				elif QUorder==13:
5327					sf = ssize
5328				elif QUorder==14:
5329					sf = srealsize
5330				elif QUorder==21:
5331					sf = hinodes
5332				elif QUorder==22:
5333					sf = hlength
5334				elif QUorder==23:
5335					sf = hsize
5336				elif QUorder==24:
5337					sf = hrealsize
5338				elif QUorder==31:
5339					sf = cinodes
5340				elif QUorder==32:
5341					sf = clength
5342				elif QUorder==33:
5343					sf = csize
5344				elif QUorder==34:
5345					sf = crealsize
5346				elif QUorder==41:
5347					sf = (-1,0) if (qflags&1)==0 else (1,0) if sinodes==0 else (0,1.0*cinodes/sinodes)
5348				elif QUorder==42:
5349					sf = (-1,0) if (qflags&2)==0 else (1,0) if slength==0 else (0,1.0*clength/slength)
5350				elif QUorder==43:
5351					sf = (-1,0) if (qflags&4)==0 else (1,0) if ssize==0 else (0,1.0*csize/ssize)
5352				elif QUorder==44:
5353					sf = (-1,0) if (qflags&8)==0 else (1,0) if srealsize==0 else (0,1.0*crealsize/srealsize)
5354				elif QUorder==51:
5355					sf = (-1,0) if (qflags&16)==0 else (1,0) if hinodes==0 else (0,1.0*cinodes/hinodes)
5356				elif QUorder==52:
5357					sf = (-1,0) if (qflags&32)==0 else (1,0) if hlength==0 else (0,1.0*clength/hlength)
5358				elif QUorder==53:
5359					sf = (-1,0) if (qflags&64)==0 else (1,0) if hsize==0 else (0,1.0*csize/hsize)
5360				elif QUorder==54:
5361					sf = (-1,0) if (qflags&128)==0 else (1,0) if hrealsize==0 else (0,1.0*crealsize/hrealsize)
5362				quotas.append((sf,path,exceeded,qflags,timetoblock,sinodes,slength,ssize,srealsize,hinodes,hlength,hsize,hrealsize,cinodes,clength,csize,crealsize))
5363			quotas.sort()
5364			if QUrev:
5365				quotas.reverse()
5366			maxperc += 0.01
5367			for sf,path,exceeded,qflags,timetoblock,sinodes,slength,ssize,srealsize,hinodes,hlength,hsize,hrealsize,cinodes,clength,csize,crealsize in quotas:
5368				if cgimode:
5369					out.append("""	<tr>""")
5370					out.append("""		<td align="right"></td>""")
5371					out.append("""		<td align="left">%s</td>""" % path)
5372	#				out.append("""		<td align="center">%s</td>""" % ("yes" if exceeded else "no"))
5373					if timetoblock<0xFFFFFFFF:
5374						if timetoblock>0:
5375	#						days,rest = divmod(timetoblock,86400)
5376	#						hours,rest = divmod(rest,3600)
5377	#						min,sec = divmod(rest,60)
5378	#						if days>0:
5379	#							tbstr = "%ud,&nbsp;%uh&nbsp;%um&nbsp;%us" % (days,hours,min,sec)
5380	#						elif hours>0:
5381	#							tbstr = "%uh&nbsp;%um&nbsp;%us" % (hours,min,sec)
5382	#						elif min>0:
5383	#							tbstr = "%um&nbsp;%us" % (min,sec)
5384	#						else:
5385	#							tbstr = "%us" % sec
5386							out.append("""		<td align="center"><span class="SEXCEEDED"><span class="sortkey">%u </span><a style="cursor:default" title="%s">%s</a></span></td>""" % (timetoblock,timeduration_to_fullstr(timetoblock),timeduration_to_shortstr(timetoblock)))
5387						else:
5388							out.append("""		<td align="center"><span class="EXCEEDED"><span class="sortkey">0 </span>expired</span></td>""")
5389					else:
5390						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5391					if qflags&1:
5392						out.append("""		<td align="right"><span>%u</span></td>""" % (sinodes))
5393					else:
5394						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5395					if qflags&2:
5396						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B"><span>%s</span></a></td>""" % (slength,decimal_number(slength),humanize_number(slength,"&nbsp;")))
5397					else:
5398						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5399					if qflags&4:
5400						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B"><span>%s</span></a></td>""" % (ssize,decimal_number(ssize),humanize_number(ssize,"&nbsp;")))
5401					else:
5402						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5403					if qflags&8:
5404						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B"><span>%s</span></a></td>""" % (srealsize,decimal_number(srealsize),humanize_number(srealsize,"&nbsp;")))
5405					else:
5406						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5407					if qflags&16:
5408						out.append("""		<td align="right"><span>%u</span></td>""" % (hinodes))
5409					else:
5410						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5411					if qflags&32:
5412						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B"><span>%s</span></a></td>""" % (hlength,decimal_number(hlength),humanize_number(hlength,"&nbsp;")))
5413					else:
5414						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5415					if qflags&64:
5416						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B"><span>%s</span></a></td>""" % (hsize,decimal_number(hsize),humanize_number(hsize,"&nbsp;")))
5417					else:
5418						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5419					if qflags&128:
5420						out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B"><span>%s</span></a></td>""" % (hrealsize,decimal_number(hrealsize),humanize_number(hrealsize,"&nbsp;")))
5421					else:
5422						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5423					out.append("""		<td align="right">%u</td>""" % cinodes)
5424					if qflags&1:
5425						if sinodes>0:
5426							if sinodes>=cinodes:
5427								cl="NOTEXCEEDED"
5428							elif timetoblock>0:
5429								cl="SEXCEEDED"
5430							else:
5431								cl="EXCEEDED"
5432							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*cinodes)/sinodes))
5433						else:
5434							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
5435					else:
5436						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5437					if qflags&16:
5438						if hinodes>0:
5439							if hinodes>cinodes:
5440								cl="NOTEXCEEDED"
5441							else:
5442								cl="EXCEEDED"
5443							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*cinodes)/hinodes))
5444						else:
5445							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
5446					else:
5447						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5448					out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td>""" % (clength,decimal_number(clength),humanize_number(clength,"&nbsp;")))
5449					if qflags&2:
5450						if slength>0:
5451							if slength>=clength:
5452								cl="NOTEXCEEDED"
5453							elif timetoblock>0:
5454								cl="SEXCEEDED"
5455							else:
5456								cl="EXCEEDED"
5457							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*clength)/slength))
5458						else:
5459							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
5460					else:
5461						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5462					if qflags&32:
5463						if hlength>0:
5464							if hlength>clength:
5465								cl="NOTEXCEEDED"
5466							else:
5467								cl="EXCEEDED"
5468							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*clength)/hlength))
5469						else:
5470							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
5471					else:
5472						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5473					out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td>""" % (csize,decimal_number(csize),humanize_number(csize,"&nbsp;")))
5474					if qflags&4:
5475						if ssize>0:
5476							if ssize>=csize:
5477								cl="NOTEXCEEDED"
5478							elif timetoblock>0:
5479								cl="SEXCEEDED"
5480							else:
5481								cl="EXCEEDED"
5482							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*csize)/ssize))
5483						else:
5484							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
5485					else:
5486						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5487					if qflags&64:
5488						if hsize>0:
5489							if hsize>csize:
5490								cl="NOTEXCEEDED"
5491							else:
5492								cl="EXCEEDED"
5493							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*csize)/hsize))
5494						else:
5495							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
5496					else:
5497						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5498					out.append("""		<td align="right"><span class="sortkey">%u </span><a style="cursor:default" title="%s B">%s</a></td>""" % (crealsize,decimal_number(crealsize),humanize_number(crealsize,"&nbsp;")))
5499					if qflags&8:
5500						if srealsize>0:
5501							if srealsize>=crealsize:
5502								cl="NOTEXCEEDED"
5503							elif timetoblock>0:
5504								cl="SEXCEEDED"
5505							else:
5506								cl="EXCEEDED"
5507							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*crealsize)/srealsize))
5508						else:
5509							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
5510					else:
5511						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5512					if qflags&128:
5513						if hrealsize>0:
5514							if hrealsize>crealsize:
5515								cl="NOTEXCEEDED"
5516							else:
5517								cl="EXCEEDED"
5518							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*crealsize)/hrealsize))
5519						else:
5520							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
5521					else:
5522						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5523					out.append("""	</tr>""")
5524				elif ttymode:
5525					dline = [path] #,"yes" if exceeded else "no"]
5526					if timetoblock<0xFFFFFFFF:
5527						if timetoblock>0:
5528							dline.append((timeduration_to_shortstr(timetoblock),"2"))
5529						else:
5530							dline.append(("expired","1"))
5531					else:
5532						dline.append("-")
5533					if qflags&1:
5534						dline.append(sinodes)
5535					else:
5536						dline.append("-")
5537					if qflags&2:
5538						dline.append(humanize_number(slength," "))
5539					else:
5540						dline.append("-")
5541					if qflags&4:
5542						dline.append(humanize_number(ssize," "))
5543					else:
5544						dline.append("-")
5545					if qflags&8:
5546						dline.append(humanize_number(srealsize," "))
5547					else:
5548						dline.append("-")
5549					if qflags&16:
5550						dline.append(hinodes)
5551					else:
5552						dline.append("-")
5553					if qflags&32:
5554						dline.append(humanize_number(hlength," "))
5555					else:
5556						dline.append("-")
5557					if qflags&64:
5558						dline.append(humanize_number(hsize," "))
5559					else:
5560						dline.append("-")
5561					if qflags&128:
5562						dline.append(humanize_number(hrealsize," "))
5563					else:
5564						dline.append("-")
5565					dline.append(cinodes)
5566					if qflags&1:
5567						if sinodes>0:
5568							dline.append(("%.2f" % ((100.0*cinodes)/sinodes),"4" if sinodes>=cinodes else "2" if timetoblock>0 else "1"))
5569						else:
5570							dline.append(("inf","1"))
5571					else:
5572						dline.append("-")
5573					if qflags&16:
5574						if hinodes>0:
5575							dline.append(("%.2f" % ((100.0*cinodes)/hinodes),"4" if hinodes>cinodes else "1"))
5576						else:
5577							dline.append(("inf","1"))
5578					else:
5579						dline.append("-")
5580					dline.append(humanize_number(clength," "))
5581					if qflags&2:
5582						if slength>0:
5583							dline.append(("%.2f" % ((100.0*clength)/slength),"4" if slength>=clength else "2" if timetoblock>0 else "1"))
5584						else:
5585							dline.append(("inf","1"))
5586					else:
5587						dline.append("-")
5588					if qflags&32:
5589						if hlength>0:
5590							dline.append(("%.2f" % ((100.0*clength)/hlength),"4" if hlength>clength else "1"))
5591						else:
5592							dline.append(("inf","1"))
5593					else:
5594						dline.append("-")
5595					dline.append(humanize_number(csize," "))
5596					if qflags&4:
5597						if ssize>0:
5598							dline.append(("%.2f" % ((100.0*csize)/ssize),"4" if ssize>=csize else "2" if timetoblock>0 else "1"))
5599						else:
5600							dline.append(("inf","1"))
5601					else:
5602						dline.append("-")
5603					if qflags&64:
5604						if hsize>0:
5605							dline.append(("%.2f" % ((100.0*csize)/hsize),"4" if hsize>csize else "1"))
5606						else:
5607							dline.append(("inf","1"))
5608					else:
5609						dline.append("-")
5610					dline.append(humanize_number(crealsize," "))
5611					if qflags&8:
5612						if srealsize>0:
5613							dline.append(("%.2f" % ((100.0*crealsize)/srealsize),"4" if srealsize>=crealsize else "2" if timetoblock>0 else "1"))
5614						else:
5615							dline.append(("inf","1"))
5616					else:
5617						dline.append("-")
5618					if qflags&128:
5619						if hrealsize>0:
5620							dline.append(("%.2f" % ((100.0*crealsize)/hrealsize),"4" if hrealsize>crealsize else "1"))
5621						else:
5622							dline.append(("inf","1"))
5623					else:
5624						dline.append("-")
5625					tab.append(*dline)
5626				else:
5627					dline = [path,"yes" if exceeded else "no"]
5628					if timetoblock<0xFFFFFFFF:
5629						if timetoblock>0:
5630							dline.append(timetoblock)
5631						else:
5632							dline.append("expired")
5633					else:
5634						dline.append("-")
5635					dline.append(sinodes if qflags&1 else "-")
5636					dline.append(slength if qflags&2 else "-")
5637					dline.append(ssize if qflags&4 else "-")
5638					dline.append(srealsize if qflags&8 else "-")
5639					dline.append(hinodes if qflags&16 else "-")
5640					dline.append(hlength if qflags&32 else "-")
5641					dline.append(hsize if qflags&64 else "-")
5642					dline.append(hrealsize if qflags&128 else "-")
5643					dline.extend((cinodes,clength,csize,crealsize))
5644					tab.append(*dline)
5645		if cgimode:
5646			out.append("""</table>""")
5647			print("\n".join(out))
5648		else:
5649			print(tab)
5650	except Exception:
5651		print_exception()
5652
5653if "MC" in sectionset:
5654	if needseparator:
5655		if cgimode:
5656			print("""<br/>""")
5657		else:
5658			print("")
5659	else:
5660		needseparator=1
5661
5662	out = []
5663
5664	try:
5665		if cgimode:
5666			charts = (
5667				(100,'cpu','cpu usage (percent)'),
5668				(101,'memory','memory usage (if available - rss + virt)'),
5669				(2,'dels','chunk deletions (per minute)'),
5670				(3,'repl','chunk replications (per minute)'),
5671				(4,'stafs','statfs operations (per minute)'),
5672				(5,'getattr','getattr operations (per minute)'),
5673				(6,'setattr','setattr operations (per minute)'),
5674				(7,'lookup','lookup operations (per minute)'),
5675				(8,'mkdir','mkdir operations (per minute)'),
5676				(9,'rmdir','rmdir operations (per minute)'),
5677				(10,'symlink','symlink operations (per minute)'),
5678				(11,'readlink','readlink operations (per minute)'),
5679				(12,'mknod','mknod operations (per minute)'),
5680				(13,'unlink','unlink operations (per minute)'),
5681				(14,'rename','rename operations (per minute)'),
5682				(15,'link','link operations (per minute)'),
5683				(16,'readdir','readdir operations (per minute)'),
5684				(17,'open','open operations (per minute)'),
5685				(18,'read','read operations (per minute)'),
5686				(19,'write','write operations (per minute)'),
5687				(21,'prcvd','packets received (per second)'),
5688				(22,'psent','packets sent (per second)'),
5689				(23,'brcvd','bits received (per second)'),
5690				(24,'bsent','bits sent (per second)')
5691			)
5692
5693			if MCdata=="" and leaderfound:
5694				MCdata="%s:%u:%u" % (leaderconn.host,leaderconn.port,1 if leaderconn.version_at_least(2,0,0) else 0)
5695			servers = []
5696			mixedservers = 0
5697			if len(masterlistver)>0:
5698				masterlistver.sort()
5699				out.append("""<form action="#"><table class="FR" cellspacing="0"><tr><th>Select: <select name="server" size="1" onchange="document.location.href='%s&amp;MCdata='+this.options[this.selectedIndex].value">""" % createlink({"MCdata":""}))
5700				entrystr = []
5701				entrydesc = {}
5702				for id,oname,desc in charts:
5703					name = oname.replace(":","")
5704					entrystr.append(name)
5705					entrydesc[name] = desc
5706				for strip,port,version in masterlistver:
5707					nc = 1 if version>=(2,0,0) else 0
5708					if mixedservers==0:
5709						mixedservers = nc+1
5710					if mixedservers!=nc+1:
5711						mixedservers = 3
5712					name = "%s:%u" % (strip,port)
5713					namearg = "%s:%u" % (name,nc)
5714					hostx = resolve(strip)
5715					if hostx==UNRESOLVED:
5716						host = ""
5717					else:
5718						host = " / "+hostx
5719					entrystr.append(namearg)
5720					entrydesc[namearg] = "Server: %s%s%s" % (name,host," *" if strip==leaderconn.host else "")
5721					servers.append((strip,port,"ma_"+name.replace(".","_").replace(":","_"),entrydesc[namearg],nc))
5722				if MCdata not in entrystr:
5723					out.append("""<option value="" selected="selected"> data type or server</option>""")
5724				for estr in entrystr:
5725					if estr==MCdata:
5726						out.append("""<option value="%s" selected="selected">%s</option>""" % (estr,entrydesc[estr]))
5727					else:
5728						out.append("""<option value="%s">%s</option>""" % (estr,entrydesc[estr]))
5729				out.append("""</select></th></tr></table></form><br/>""")
5730
5731			mchtmp = MCdata.split(":")
5732			if len(mchtmp)==2:
5733				mchtmp = (mchtmp[0],mchtmp[1],0)
5734			if len(mchtmp)==3:
5735				mahost = mchtmp[0]
5736				maport = mchtmp[1]
5737				manc = int(mchtmp[2])
5738
5739				out.append("""<script type="text/javascript">""")
5740				out.append("""<!--//--><![CDATA[//><!--""")
5741				out.append("""	var ma_vids = [%s];""" % ",".join(map(repr,[ x[0] for x in charts ])))
5742				out.append("""	var ma_inames = [%s];""" % ",".join(map(repr,[ x[1] for x in charts ])))
5743				out.append("""	var ma_idesc = [%s];""" % ",".join(map(repr,[ x[2] for x in charts ])))
5744				out.append("""	var ma_host = "%s";""" % mahost)
5745				out.append("""	var ma_port = "%s";""" % maport)
5746				out.append("""	var ma_nc = %u;""" % manc)
5747				out.append("""//--><!]]>""")
5748				out.append("""</script>""")
5749				out.append("""<script type="text/javascript">
5750<!--//--><![CDATA[//><!--
5751	var i,j;
5752	var ma_chartid = [0,0];
5753	var ma_range_up=0;
5754	var ma_range_down=0;
5755	var ma_zoomed = [];
5756	var ma_resizeto;
5757	function ma_refresh() {
5758		var i;
5759		var minutes = Math.floor((new Date()).getTime()/60000);
5760		for (i=0 ; i<ma_inames.length ; i++) {
5761			var name = ma_inames[i];
5762			var vid = ma_vids[i];
5763			var id = vid*10+ma_range_up;
5764			var element = document.getElementById(name);
5765			if (element) {
5766				var url;
5767				if (ma_nc) {
5768					var width = element.scrollWidth;
5769					var height = element.scrollHeight;
5770					url = "/chart.cgi?host="+ma_host+"&amp;port="+ma_port+"&amp;id="+id+"&amp;width="+width+"&amp;height="+height+"&amp;antycache="+minutes;
5771				} else {
5772					url = "/chart.cgi?host="+ma_host+"&amp;port="+ma_port+"&amp;id="+id+"&amp;antycache="+minutes;
5773				}
5774				if (typeof(element.ma_url)=="undefined" || element.ma_url!=url) {
5775					element.ma_url = url;
5776					element.style.backgroundImage = "url('"+url+"')";
5777				}
5778			}
5779		}
5780		for (i=0 ; i<2 ; i++) {
5781			var vid = ma_vids[ma_chartid[i]];
5782			var id = vid*10+ma_range_down;
5783			var iname = "ma_chart"+i;
5784			var element = document.getElementById(iname);
5785			if (element) {
5786				var url;
5787				if (ma_nc) {
5788					var width = element.scrollWidth;
5789					var height = element.scrollHeight;
5790					url = "/chart.cgi?host="+ma_host+"&amp;port="+ma_port+"&amp;id="+id+"&amp;width="+width+"&amp;height="+height+"&amp;antycache="+minutes;
5791				} else {
5792					url = "/chart.cgi?host="+ma_host+"&amp;port="+ma_port+"&amp;id="+id+"&amp;antycache="+minutes;
5793				}
5794				if (typeof(element.ma_url)=="undefined" || element.ma_url!=url) {
5795					element.ma_url = url;
5796					element.style.backgroundImage = "url('"+url+"')";
5797				}
5798			}
5799		}
5800	}
5801	function ma_change_up(num) {
5802		ma_range_up = num;
5803		ma_refresh();
5804	}
5805	function ma_change_down(num) {
5806		ma_range_down = num;
5807		ma_refresh();
5808	}
5809	function ma_zoom(element) {
5810		var name = element.id;
5811		if (typeof(ma_zoomed[name])=="undefined") {
5812			ma_zoomed[name]=0;
5813		}
5814		if (ma_zoomed[name]==0) {
5815			ma_zoomed[name]=1;
5816			element.style.height = '220px';
5817		} else if (ma_zoomed[name]==1) {
5818			ma_zoomed[name]=2;
5819			element.style.height = '420px';
5820		} else if (ma_zoomed[name]==2) {
5821			ma_zoomed[name]=3;
5822			element.style.height = '820px';
5823		} else {
5824			ma_zoomed[name]=0;
5825			element.style.height = '120px';
5826		}
5827		ma_refresh();
5828	}
5829	function ma_resized() {
5830		clearTimeout(ma_resizeto);
5831		ma_resizeto = setTimeout(ma_refresh,250);
5832	}
5833	function ma_change_type(id,no) {
5834		var o;
5835		o = document.getElementById("ma_cell_"+id+"_"+ma_chartid[id]);
5836		o.className="REL";
5837		ma_chartid[id]=no;
5838		o = document.getElementById("ma_cell_"+id+"_"+ma_chartid[id]);
5839		o.className="PR";
5840		o = document.getElementById("ma_desc"+id);
5841		o.innerHTML = ma_idesc[no];
5842		ma_refresh();
5843	}
5844	function ma_add_event(obj,type,fn) {
5845		if (obj.addEventListener) {
5846			obj.addEventListener(type, fn, false);
5847		} else if (obj.attachEvent) {
5848			obj.attachEvent('on'+type, fn);
5849		}
5850	}
5851	ma_add_event(window,"load",ma_refresh);
5852	ma_add_event(window,"resize",ma_resized);
5853//--><!]]>
5854</script>""")
5855				out.append("""<table class="FR" cellspacing="0" cellpadding="0">""")
5856				out.append("""	<tr>""")
5857				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_up(0);">short range</a></th>""")
5858				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_up(1);">medium range</a></th>""")
5859				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_up(2);">long range</a></th>""")
5860				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_up(3);">very long range</a></th>""")
5861				out.append("""	</tr>""")
5862				for id,name,desc in charts:
5863					divclass = "CHARTDYNAMIC" if manc else "CHARTSTATIC"
5864					divclick = 'onclick="ma_zoom(this)"' if manc else ""
5865					out.append("""	<tr class="C2">""")
5866					out.append("""		<td colspan="4" style="height:124px;" valign="middle">""")
5867					out.append("""			<div class="%s" id="%s" %s>""" % (divclass,name,divclick))
5868					out.append("""				<span class="CAPTION">%s</span>""" % desc)
5869					out.append("""			</div>""")
5870					out.append("""		</td>""")
5871					out.append("""	</tr>""")
5872				out.append("""</table>""")
5873				out.append("""<br/>""")
5874
5875				out.append("""<table class="FR" cellspacing="0" cellpadding="0">""")
5876				out.append("""	<tr>""")
5877				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_down(0);">short range</a></th>""")
5878				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_down(1);">medium range</a></th>""")
5879				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_down(2);">long range</a></th>""")
5880				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_down(3);">very long range</a></th>""")
5881				out.append("""	</tr>""")
5882				for i in range(2):
5883					divclass = "CHARTDYNAMIC" if manc else "CHARTSTATIC"
5884					divclick = 'onclick="ma_zoom(this)"' if manc else ""
5885					out.append("""	<tr class="C2">""")
5886					out.append("""		<td colspan="4" style="height:124px;" valign="middle">""")
5887					out.append("""			<div class="%s" id="ma_chart%u" %s>""" % (divclass,i,divclick))
5888					out.append("""				<span class="CAPTION" id="ma_desc%u">%s</span>""" % (i,charts[0][2]))
5889					out.append("""			</div>""")
5890					out.append("""		</td>""")
5891					out.append("""	</tr>""")
5892					out.append("""	<tr>""")
5893					out.append("""		<td colspan="4">""")
5894					out.append("""			<table class="BOTMENU" cellspacing="0">""")
5895					out.append("""				<tr>""")
5896					no=0
5897					cl="PR"
5898					for id,name,desc in charts:
5899						out.append("""					<td align="center" id="ma_cell_%u_%u" class="%s"><a href="javascript:ma_change_type(%u,%u);" title="%s">%s</a></td>""" % (i,no,cl,i,no,desc,name))
5900						cl="REL"
5901						no+=1
5902					out.append("""				</tr>""")
5903					out.append("""			</table>""")
5904					out.append("""		</td>""")
5905					out.append("""	</tr>""")
5906				out.append("""</table>""")
5907			elif len(mchtmp)==1 and len(MCdata)>0:
5908				chid = 0
5909				for id,name,desc in charts:
5910					if name==MCdata:
5911						chid = id
5912				if chid==0:
5913					try:
5914						chid = int(MCdata)
5915					except Exception:
5916						pass
5917				if chid>0 and chid<1000:
5918					out.append("""<script type="text/javascript">""")
5919					out.append("""<!--//--><![CDATA[//><!--""")
5920					out.append("""	var ma_vhosts = [%s];""" % ",".join(map(repr,[ x[0] for x in servers ])))
5921					out.append("""	var ma_vports = [%s];""" % ",".join(map(repr,[ x[1] for x in servers ])))
5922					out.append("""	var ma_inames = [%s];""" % ",".join(map(repr,[ x[2] for x in servers ])))
5923					out.append("""	var ma_nc = [%s];""" % ",".join(map(repr,[ x[4] for x in servers ])))
5924					out.append("""	var ma_chid = %u;""" % chid);
5925					out.append("""//--><!]]>""")
5926					out.append("""</script>""")
5927					out.append("""<script type="text/javascript">
5928<!--//--><![CDATA[//><!--
5929	var i,j;
5930	var ma_range=0;
5931	var ma_zoomed = [];
5932	var ma_resizeto;
5933	function ma_refresh() {
5934		var i;
5935		var minutes = Math.floor((new Date()).getTime()/60000);
5936		for (i=0 ; i<ma_inames.length ; i++) {
5937			var name = ma_inames[i];
5938			var vhost = ma_vhosts[i];
5939			var vport = ma_vports[i];
5940			var manc = ma_nc[i];
5941			var id = ma_chid*10+ma_range;
5942			var element = document.getElementById(name);
5943			if (element) {
5944				var url;
5945				if (manc) {
5946					var width = element.scrollWidth;
5947					var height = element.scrollHeight;
5948					url = "/chart.cgi?host="+vhost+"&amp;port="+vport+"&amp;id="+id+"&amp;width="+width+"&amp;height="+height+"&amp;antycache="+minutes;
5949				} else {
5950					url = "/chart.cgi?host="+vhost+"&amp;port="+vport+"&amp;id="+id+"&amp;antycache="+minutes;
5951				}
5952				if (typeof(element.ma_url)=="undefined" || element.ma_url!=url) {
5953					element.ma_url = url;
5954					element.style.backgroundImage = "url('"+url+"')";
5955				}
5956			}
5957		}
5958	}
5959	function ma_change(num) {
5960		ma_range = num;
5961		ma_refresh();
5962	}
5963	function ma_zoom(element) {
5964		var name = element.id;
5965		if (typeof(ma_zoomed[name])=="undefined") {
5966			ma_zoomed[name]=0;
5967		}
5968		if (ma_zoomed[name]==0) {
5969			ma_zoomed[name]=1;
5970			element.style.height = '220px';
5971		} else if (ma_zoomed[name]==1) {
5972			ma_zoomed[name]=2;
5973			element.style.height = '420px';
5974		} else if (ma_zoomed[name]==2) {
5975			ma_zoomed[name]=3;
5976			element.style.height = '820px';
5977		} else {
5978			ma_zoomed[name]=0;
5979			element.style.height = '120px';
5980		}
5981		ma_refresh();
5982	}
5983	function ma_resized() {
5984		clearTimeout(ma_resizeto);
5985		ma_resizeto = setTimeout(ma_refresh,250);
5986	}
5987	function ma_add_event(obj,type,fn) {
5988		if (obj.addEventListener) {
5989			obj.addEventListener(type, fn, false);
5990		} else if (obj.attachEvent) {
5991			obj.attachEvent('on'+type, fn);
5992		}
5993	}
5994	ma_add_event(window,"load",ma_refresh);
5995	ma_add_event(window,"resize",ma_resized);
5996//--><!]]>
5997</script>""")
5998					out.append("""<table class="FR" cellspacing="0" cellpadding="0">""")
5999					out.append("""	<tr>""")
6000					out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change(0);">short range</a></th>""")
6001					out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change(1);">medium range</a></th>""")
6002					out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change(2);">long range</a></th>""")
6003					out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change(3);">very long range</a></th>""")
6004					out.append("""	</tr>""")
6005					for mahost,maport,name,desc,manc in servers:
6006						divclass = "CHARTDYNAMIC" if manc else "CHARTSTATICMIXED" if mixedservers==3 else "CHARTSTATIC"
6007						divclick = 'onclick="ma_zoom(this)"' if manc else ""
6008						out.append("""	<tr class="C2">""")
6009						out.append("""		<td colspan="4" style="height:124px;" valign="middle">""")
6010						out.append("""			<div class="%s" id="%s" %s>""" % (divclass,name,divclick))
6011						out.append("""				<span class="CAPTION">%s</span>""" % desc)
6012						out.append("""			</div>""")
6013						out.append("""		</td>""")
6014						out.append("""	</tr>""")
6015					out.append("""</table>""")
6016		else:
6017			out.append("""master charts are unavailable in CLI mode""")
6018		print("\n".join(out))
6019	except Exception:
6020		print_exception()
6021
6022if "CC" in sectionset:
6023	if needseparator:
6024		if cgimode:
6025			print("""<br/>""")
6026		else:
6027			print("")
6028	else:
6029		needseparator=1
6030
6031	out = []
6032
6033	try:
6034		if cgimode:
6035			# get cs list
6036			hostlist = []
6037			data,length = leaderconn.command(CLTOMA_CSERV_LIST,MATOCL_CSERV_LIST)
6038			if leaderconn.version_at_least(1,7,25) and (length%64)==0:
6039				n = length//64
6040				servers = []
6041				for i in range(n):
6042					d = data[i*64:(i+1)*64]
6043					flags,v1,v2,v3,ip1,ip2,ip3,ip4,port = struct.unpack(">BBBBBBBBH",d[:10])
6044					if (flags&1)==0:
6045						hostlist.append(((ip1,ip2,ip3,ip4),port,(v1,v2,v3)))
6046			elif leaderconn.version_at_least(1,6,28) and leaderconn.version_less_than(1,7,25) and (length%62)==0:
6047				n = length//62
6048				servers = []
6049				for i in range(n):
6050					d = data[i*62:(i+1)*62]
6051					disconnected,v1,v2,v3,ip1,ip2,ip3,ip4,port = struct.unpack(">BBBBBBBBH",d[:10])
6052					if disconnected==0:
6053						hostlist.append(((ip1,ip2,ip3,ip4),port,(v1,v2,v3)))
6054			elif leaderconn.version_less_than(1,6,28) and (length%54)==0:
6055				n = length//54
6056				servers = []
6057				for i in range(n):
6058					d = data[i*54:(i+1)*54]
6059					disconnected,v1,v2,v3,ip1,ip2,ip3,ip4,port = struct.unpack(">BBBBBBBBH",d[:10])
6060					if disconnected==0:
6061						hostlist.append(((ip1,ip2,ip3,ip4),port,(v1,v2,v3)))
6062			charts = (
6063				(100,'cpu','cpu usage (percent)'),
6064				(107,'memory','memory usage (if available - rss + virt)'),
6065				(101,'datain','traffic from clients and other chunkservers (bits/s - main server + replicator)'),
6066				(102,'dataout','traffic to clients and other chunkservers (bits/s - main server + replicator)'),
6067				(103,'bytesr','bytes read - data/other (bytes/s)'),
6068				(104,'bytesw','bytes written - data/other (bytes/s)'),
6069				(2,'masterin','traffic from master (bits/s)'),
6070				(3,'masterout','traffic to master (bits/s)'),
6071				(105,'hddopr','number of low-level read operations per minute'),
6072				(106,'hddopw','number of low-level write operations per minute'),
6073				(16,'hlopr','number of high-level read operations per minute'),
6074				(17,'hlopw','number of high-level write operations per minute'),
6075				(18,'rtime','time of data read operations'),
6076				(19,'wtime','time of data write operations'),
6077				(20,'repl','number of chunk replications per minute'),
6078				(21,'create','number of chunk creations per minute'),
6079				(22,'delete','number of chunk deletions per minute'),
6080				(28,'load','load - max operations in queue'),
6081			)
6082
6083			servers = []
6084			mixedservers = 0
6085			if len(hostlist)>0:
6086				hostlist.sort()
6087				out.append("""<form action="#"><table class="FR" cellspacing="0"><tr><th>Select: <select name="server" size="1" onchange="document.location.href='%s&amp;CCdata='+this.options[this.selectedIndex].value">""" % createlink({"CCdata":""}))
6088				entrystr = []
6089				entrydesc = {}
6090				for id,oname,desc in charts:
6091					name = oname.replace(":","")
6092					entrystr.append(name)
6093					entrydesc[name] = desc
6094				for ip,port,version in hostlist:
6095					nc = 1 if version>=(2,0,0) else 0
6096					if mixedservers==0:
6097						mixedservers = nc+1
6098					if mixedservers!=nc+1:
6099						mixedservers = 3
6100					strip = "%u.%u.%u.%u" % ip
6101					name = "%s:%u" % (strip,port)
6102					namearg = "%s:%u" % (name,nc)
6103					hostx = resolve(strip)
6104					if hostx==UNRESOLVED:
6105						host = ""
6106					else:
6107						host = " / "+hostx
6108					entrystr.append(namearg)
6109					entrydesc[namearg] = "Server: %s%s" % (name,host)
6110					servers.append((strip,port,"cs_"+name.replace(".","_").replace(":","_"),entrydesc[namearg],nc))
6111				if CCdata not in entrystr:
6112					out.append("""<option value="" selected="selected"> data type or server</option>""")
6113				for estr in entrystr:
6114					if estr==CCdata:
6115						out.append("""<option value="%s" selected="selected">%s</option>""" % (estr,entrydesc[estr]))
6116					else:
6117						out.append("""<option value="%s">%s</option>""" % (estr,entrydesc[estr]))
6118				out.append("""</select></th></tr></table></form><br/>""")
6119
6120			cchtmp = CCdata.split(":")
6121			if len(cchtmp)==2:
6122				cchtmp = (cchtmp[0],cchtmp[1],0)
6123			if len(cchtmp)==3:
6124				cshost = cchtmp[0]
6125				csport = cchtmp[1]
6126				csnc = int(cchtmp[2])
6127
6128				out.append("""<script type="text/javascript">""")
6129				out.append("""<!--//--><![CDATA[//><!--""")
6130				out.append("""	var cs_vids = [%s];""" % ",".join(map(repr,[ x[0] for x in charts ])))
6131				out.append("""	var cs_inames = [%s];""" % ",".join(map(repr,[ x[1] for x in charts ])))
6132				out.append("""	var cs_idesc = [%s];""" % ",".join(map(repr,[ x[2] for x in charts ])))
6133				out.append("""	var cs_host = "%s";""" % cshost)
6134				out.append("""	var cs_port = "%s";""" % csport)
6135				out.append("""	var cs_nc = %u;""" % csnc)
6136				out.append("""//--><!]]>""")
6137				out.append("""</script>""")
6138				out.append("""<script type="text/javascript">
6139<!--//--><![CDATA[//><!--
6140	var i,j;
6141	var cs_chartid = [0,0];
6142	var cs_range_up=0;
6143	var cs_range_down=0;
6144	var cs_zoomed = [];
6145	var cs_resizeto;
6146	function cs_refresh() {
6147		var i;
6148		var minutes = Math.floor((new Date()).getTime()/60000);
6149		for (i=0 ; i<cs_inames.length ; i++) {
6150			var name = cs_inames[i];
6151			var vid = cs_vids[i];
6152			var id = vid*10+cs_range_up;
6153			var element = document.getElementById(name);
6154			if (element) {
6155				var url;
6156				if (cs_nc) {
6157					var width = element.scrollWidth;
6158					var height = element.scrollHeight;
6159					url = "/chart.cgi?host="+cs_host+"&amp;port="+cs_port+"&amp;id="+id+"&amp;width="+width+"&amp;height="+height+"&amp;antycache="+minutes;
6160				} else {
6161					url = "/chart.cgi?host="+cs_host+"&amp;port="+cs_port+"&amp;id="+id+"&amp;antycache="+minutes;
6162				}
6163				if (typeof(element.cs_url)=="undefined" || element.cs_url!=url) {
6164					element.cs_url = url;
6165					element.style.backgroundImage = "url('"+url+"')";
6166				}
6167			}
6168		}
6169		for (i=0 ; i<2 ; i++) {
6170			var vid = cs_vids[cs_chartid[i]];
6171			var id = vid*10+cs_range_down;
6172			var iname = "cs_chart"+i;
6173			var element = document.getElementById(iname);
6174			if (element) {
6175				var url;
6176				if (cs_nc) {
6177					var width = element.scrollWidth;
6178					var height = element.scrollHeight;
6179					url = "/chart.cgi?host="+cs_host+"&amp;port="+cs_port+"&amp;id="+id+"&amp;width="+width+"&amp;height="+height+"&amp;antycache="+minutes;
6180				} else {
6181					url = "/chart.cgi?host="+cs_host+"&amp;port="+cs_port+"&amp;id="+id+"&amp;antycache="+minutes;
6182				}
6183				if (typeof(element.cs_url)=="undefined" || element.cs_url!=url) {
6184					element.cs_url = url;
6185					element.style.backgroundImage = "url('"+url+"')";
6186				}
6187			}
6188		}
6189	}
6190	function cs_change_up(num) {
6191		cs_range_up = num;
6192		cs_refresh();
6193	}
6194	function cs_change_down(num) {
6195		cs_range_down = num;
6196		cs_refresh();
6197	}
6198	function cs_zoom(element) {
6199		var name = element.id;
6200		if (typeof(cs_zoomed[name])=="undefined") {
6201			cs_zoomed[name]=0;
6202		}
6203		if (cs_zoomed[name]==0) {
6204			cs_zoomed[name]=1;
6205			element.style.height = '220px';
6206		} else if (cs_zoomed[name]==1) {
6207			cs_zoomed[name]=2;
6208			element.style.height = '420px';
6209		} else if (cs_zoomed[name]==2) {
6210			cs_zoomed[name]=3;
6211			element.style.height = '820px';
6212		} else {
6213			cs_zoomed[name]=0;
6214			element.style.height = '120px';
6215		}
6216		cs_refresh()
6217	}
6218	function cs_resized() {
6219		clearTimeout(cs_resizeto);
6220		cs_resizeto = setTimeout(cs_refresh,250);
6221	}
6222	function cs_change_type(id,no) {
6223		var o;
6224		o = document.getElementById("cs_cell_"+id+"_"+cs_chartid[id]);
6225		o.className="REL";
6226		cs_chartid[id]=no;
6227		o = document.getElementById("cs_cell_"+id+"_"+cs_chartid[id]);
6228		o.className="PR";
6229		o = document.getElementById("cs_desc"+id);
6230		o.innerHTML = cs_idesc[no];
6231		cs_refresh();
6232	}
6233	function cs_add_event(obj,type,fn) {
6234		if (obj.addEventListener) {
6235			obj.addEventListener(type, fn, false);
6236		} else if (obj.attachEvent) {
6237			obj.attachEvent('on'+type, fn);
6238		}
6239	}
6240	cs_add_event(window,"load",cs_refresh);
6241	cs_add_event(window,"resize",cs_resized);
6242//--><!]]>
6243</script>""")
6244				out.append("""<table class="FR" cellspacing="0" cellpadding="0">""")
6245				out.append("""	<tr>""")
6246				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_up(0);">short range</a></th>""")
6247				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_up(1);">medium range</a></th>""")
6248				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_up(2);">long range</a></th>""")
6249				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_up(3);">very long range</a></th>""")
6250				out.append("""	</tr>""")
6251				for id,name,desc in charts:
6252					divclass = "CHARTDYNAMIC" if csnc else "CHARTSTATIC"
6253					divclick = 'onclick="cs_zoom(this)"' if csnc else ""
6254					out.append("""	<tr class="C2">""")
6255					out.append("""		<td colspan="4" style="height:124px;" valign="middle">""")
6256					out.append("""			<div class="%s" id="%s" %s>""" % (divclass,name,divclick))
6257					out.append("""				<span class="CAPTION">%s</span>""" % desc)
6258					out.append("""			</div>""")
6259					out.append("""		</td>""")
6260					out.append("""	</tr>""")
6261				out.append("""</table>""")
6262				out.append("""<br/>""")
6263
6264				out.append("""<table class="FR" cellspacing="0" cellpadding="0">""")
6265				out.append("""	<tr>""")
6266				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_down(0);">short range</a></th>""")
6267				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_down(1);">medium range</a></th>""")
6268				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_down(2);">long range</a></th>""")
6269				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_down(3);">very long range</a></th>""")
6270				out.append("""	</tr>""")
6271				for i in range(2):
6272					divclass = "CHARTDYNAMIC" if csnc else "CHARTSTATIC"
6273					divclick = 'onclick="cs_zoom(this)"' if csnc else ""
6274					out.append("""	<tr class="C2">""")
6275					out.append("""		<td colspan="4" style="height:124px;" valign="middle">""")
6276					out.append("""			<div class="%s" id="cs_chart%u" %s>""" % (divclass,i,divclick))
6277					out.append("""				<span class="CAPTION" id="cs_desc%u">%s</span>""" % (i,charts[0][2]))
6278					out.append("""			</div>""")
6279					out.append("""		</td>""")
6280					out.append("""	</tr>""")
6281					out.append("""	<tr>""")
6282					out.append("""		<td colspan="4">""")
6283					out.append("""			<table class="BOTMENU" cellspacing="0">""")
6284					out.append("""				<tr>""")
6285					no=0
6286					cl="PR"
6287					for id,name,desc in charts:
6288						out.append("""					<td align="center" id="cs_cell_%u_%u" class="%s"><a href="javascript:cs_change_type(%u,%u);" title="%s">%s</a></td>""" % (i,no,cl,i,no,desc,name))
6289						cl="REL"
6290						no+=1
6291					out.append("""				</tr>""")
6292					out.append("""			</table>""")
6293					out.append("""		</td>""")
6294					out.append("""	</tr>""")
6295				out.append("""</table>""")
6296			elif len(cchtmp)==1 and len(CCdata)>0:
6297				chid = 0
6298				for id,name,desc in charts:
6299					if name==CCdata:
6300						chid = id
6301				if chid==0:
6302					try:
6303						chid = int(CCdata)
6304					except Exception:
6305						pass
6306				if chid>0 and chid<1000:
6307					out.append("""<script type="text/javascript">""")
6308					out.append("""<!--//--><![CDATA[//><!--""")
6309					out.append("""	var i,j;""")
6310					out.append("""	var cs_range=0;""")
6311					out.append("""	var cs_vhosts = [%s];""" % ",".join(map(repr,[ x[0] for x in servers ])))
6312					out.append("""	var cs_vports = [%s];""" % ",".join(map(repr,[ x[1] for x in servers ])))
6313					out.append("""	var cs_inames = [%s];""" % ",".join(map(repr,[ x[2] for x in servers ])))
6314					out.append("""	var cs_nc = [%s];""" % ",".join(map(repr,[ x[4] for x in servers ])))
6315					out.append("""	var cs_chid = %u;""" % chid)
6316					out.append("""//--><!]]>""")
6317					out.append("""</script>""")
6318					out.append("""<script type="text/javascript">
6319<!--//--><![CDATA[//><!--
6320	var i,j;
6321	var cs_range=0;
6322	var cs_zoomed = [];
6323	var cs_resizeto;
6324	function cs_refresh() {
6325		var i;
6326		var minutes = Math.floor((new Date()).getTime()/60000);
6327		for (i=0 ; i<cs_inames.length ; i++) {
6328			var name = cs_inames[i];
6329			var vhost = cs_vhosts[i];
6330			var vport = cs_vports[i];
6331			var csnc = cs_nc[i];
6332			var id = cs_chid*10+cs_range;
6333			var element = document.getElementById(name);
6334			if (element) {
6335				var url;
6336				if (csnc) {
6337					var width = element.scrollWidth;
6338					var height = element.scrollHeight;
6339					url = "/chart.cgi?host="+vhost+"&amp;port="+vport+"&amp;id="+id+"&amp;width="+width+"&amp;height="+height+"&amp;antycache="+minutes;
6340				} else {
6341					url = "/chart.cgi?host="+vhost+"&amp;port="+vport+"&amp;id="+id+"&amp;antycache="+minutes;
6342				}
6343				if (typeof(element.cs_url)=="undefined" || element.cs_url!=url) {
6344					element.cs_url = url;
6345					element.style.backgroundImage = "url('"+url+"')";
6346				}
6347			}
6348		}
6349	}
6350	function cs_change(num) {
6351		cs_range = num;
6352		cs_refresh();
6353	}
6354	function cs_zoom(element) {
6355		var name = element.id;
6356		if (typeof(cs_zoomed[name])=="undefined") {
6357			cs_zoomed[name]=0;
6358		}
6359		if (cs_zoomed[name]==0) {
6360			cs_zoomed[name]=1;
6361			element.style.height = '220px';
6362		} else if (cs_zoomed[name]==1) {
6363			cs_zoomed[name]=2;
6364			element.style.height = '420px';
6365		} else if (cs_zoomed[name]==2) {
6366			cs_zoomed[name]=3;
6367			element.style.height = '820px';
6368		} else {
6369			cs_zoomed[name]=0;
6370			element.style.height = '120px';
6371		}
6372		cs_refresh();
6373	}
6374	function cs_resized() {
6375		clearTimeout(cs_resizeto);
6376		cs_resizeto = setTimeout(cs_refresh,250);
6377	}
6378	function cs_add_event(obj,type,fn) {
6379		if (obj.addEventListener) {
6380			obj.addEventListener(type, fn, false);
6381		} else if (obj.attachEvent) {
6382			obj.attachEvent('on'+type, fn);
6383		}
6384	}
6385	cs_add_event(window,"load",cs_refresh);
6386	cs_add_event(window,"resize",cs_resized);
6387//--><!]]>
6388</script>""")
6389					out.append("""<table class="FR" cellspacing="0" cellpadding="0">""")
6390					out.append("""	<tr>""")
6391					out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change(0);">short range</a></th>""")
6392					out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change(1);">medium range</a></th>""")
6393					out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change(2);">long range</a></th>""")
6394					out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change(3);">very long range</a></th>""")
6395					out.append("""	</tr>""")
6396					for cshost,csport,name,desc,csnc in servers:
6397						divclass = "CHARTDYNAMIC" if csnc else "CHARTSTATICMIXED" if mixedservers==3 else "CHARTSTATIC"
6398						divclick = 'onclick="cs_zoom(this)"' if csnc else ""
6399						out.append("""	<tr class="C2">""")
6400						out.append("""		<td colspan="4" style="height:124px;" valign="middle">""")
6401						out.append("""			<div class="%s" id="%s" %s>""" % (divclass,name,divclick))
6402						out.append("""				<span class="CAPTION">%s</span>""" % desc)
6403						out.append("""			</div>""")
6404						out.append("""		</td>""")
6405						out.append("""	</tr>""")
6406					out.append("""</table>""")
6407		else:
6408			out.append("""chunk server charts are unavailable in CLI mode""")
6409		print("\n".join(out))
6410	except Exception:
6411		print_exception()
6412
6413if cgimode:
6414	print("""</div> <!-- end of container -->""")
6415
6416	print("""</body>""")
6417	print("""</html>""")
6418