1#!/usr/bin/env @PYTHON@
2
3# Copyright (C) 2021 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
23VERSION = "@VERSION@"
24
25#some constants from MFSCommunication.h
26CLTOMA_CSERV_LIST = (PROTO_BASE+500)
27MATOCL_CSERV_LIST = (PROTO_BASE+501)
28CLTOAN_CHART_DATA = (PROTO_BASE+506)
29ANTOCL_CHART_DATA = (PROTO_BASE+507)
30CLTOMA_SESSION_LIST = (PROTO_BASE+508)
31MATOCL_SESSION_LIST = (PROTO_BASE+509)
32CLTOMA_INFO = (PROTO_BASE+510)
33MATOCL_INFO = (PROTO_BASE+511)
34CLTOMA_FSTEST_INFO = (PROTO_BASE+512)
35MATOCL_FSTEST_INFO = (PROTO_BASE+513)
36CLTOMA_CHUNKSTEST_INFO = (PROTO_BASE+514)
37MATOCL_CHUNKSTEST_INFO = (PROTO_BASE+515)
38CLTOMA_CHUNKS_MATRIX = (PROTO_BASE+516)
39MATOCL_CHUNKS_MATRIX = (PROTO_BASE+517)
40CLTOMA_QUOTA_INFO = (PROTO_BASE+518)
41MATOCL_QUOTA_INFO = (PROTO_BASE+519)
42CLTOMA_EXPORTS_INFO = (PROTO_BASE+520)
43MATOCL_EXPORTS_INFO = (PROTO_BASE+521)
44CLTOMA_MLOG_LIST = (PROTO_BASE+522)
45MATOCL_MLOG_LIST = (PROTO_BASE+523)
46CLTOMA_CSSERV_COMMAND = (PROTO_BASE+524)
47MATOCL_CSSERV_COMMAND = (PROTO_BASE+525)
48CLTOMA_SESSION_COMMAND = (PROTO_BASE+526)
49MATOCL_SESSION_COMMAND = (PROTO_BASE+527)
50CLTOMA_MEMORY_INFO = (PROTO_BASE+528)
51MATOCL_MEMORY_INFO = (PROTO_BASE+529)
52CLTOMA_LIST_OPEN_FILES = (PROTO_BASE+532)
53MATOCL_LIST_OPEN_FILES = (PROTO_BASE+533)
54CLTOMA_LIST_ACQUIRED_LOCKS = (PROTO_BASE+534)
55MATOCL_LIST_ACQUIRED_LOCKS = (PROTO_BASE+535)
56CLTOMA_MASS_RESOLVE_PATHS = (PROTO_BASE+536)
57MATOCL_MASS_RESOLVE_PATHS = (PROTO_BASE+537)
58CLTOMA_SCLASS_INFO = (PROTO_BASE+542)
59MATOCL_SCLASS_INFO = (PROTO_BASE+543)
60CLTOMA_MISSING_CHUNKS = (PROTO_BASE+544)
61MATOCL_MISSING_CHUNKS = (PROTO_BASE+545)
62
63CLTOCS_HDD_LIST = (PROTO_BASE+600)
64CSTOCL_HDD_LIST = (PROTO_BASE+601)
65
66MFS_MESSAGE = 1
67
68FEATURE_EXPORT_UMASK = 0
69FEATURE_EXPORT_DISABLES = 1
70
71MASKORGROUP = 4
72
73MFS_CSSERV_COMMAND_REMOVE = 0
74MFS_CSSERV_COMMAND_BACKTOWORK = 1
75MFS_CSSERV_COMMAND_MAINTENANCEON = 2
76MFS_CSSERV_COMMAND_MAINTENANCEOFF = 3
77MFS_CSSERV_COMMAND_TMPREMOVE = 4
78
79MFS_SESSION_COMMAND_REMOVE = 0
80
81STATUS_OK = 0
82ERROR_NOTFOUND = 41
83ERROR_ACTIVE = 42
84
85STATE_DUMMY = 0
86STATE_LEADER = 1
87STATE_ELECT = 2
88STATE_FOLLOWER = 3
89STATE_USURPER = 4
90
91UNRESOLVED = "(unresolved)"
92
93import socket
94import struct
95import time
96import sys
97import traceback
98import os
99import subprocess
100import codecs
101import json
102
103cgimode = 1 if 'GATEWAY_INTERFACE' in os.environ else 0
104
105try:
106	xrange
107except NameError:
108	xrange = range
109
110def myunicode(x):
111	if sys.version_info[0]<3:
112		return unicode(x)
113	else:
114		return str(x)
115
116#parse parameters and auxilinary functions
117if cgimode:
118	# in CGI mode set default output encoding to utf-8 (our html page encoding)
119	if sys.version_info[0]<3:
120		sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
121	elif sys.version_info[1]<7:
122		sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach())
123	else:
124		sys.stdout.reconfigure(encoding='utf-8')
125
126	try:
127		import urllib.parse as xurllib
128	except ImportError:
129		import urllib as xurllib
130	import cgi
131	import cgitb
132
133	cgitb.enable()
134
135	fields = cgi.FieldStorage()
136
137	try:
138		if "masterhost" in fields:
139			masterhost = fields.getvalue("masterhost")
140		else:
141			masterhost = '@DEFAULT_MASTERNAME@'
142	except Exception:
143		masterhost = '@DEFAULT_MASTERNAME@'
144	try:
145		masterport = int(fields.getvalue("masterport"))
146	except Exception:
147		masterport = @DEFAULT_MASTER_CLIENT_PORT@
148	try:
149		mastercontrolport = int(fields.getvalue("mastercontrolport"))
150	except Exception:
151		try:
152			mastercontrolport = int(fields.getvalue("masterport"))-2
153		except Exception:
154			mastercontrolport = @DEFAULT_MASTER_CONTROL_PORT@
155	try:
156		if "mastername" in fields:
157			mastername = fields.getvalue("mastername")
158		else:
159			mastername = 'MooseFS'
160	except Exception:
161		mastername = 'MooseFS'
162
163#	thsep = ''
164#	html_thsep = ''
165
166	def htmlentities(str):
167		return str.replace('&','&amp;').replace('<','&lt;').replace('>','&gt;').replace("'",'&apos;').replace('"','&quot;')
168
169	def urlescape(str):
170		return xurllib.quote_plus(str)
171
172	def resolve(strip):
173		try:
174			return (socket.gethostbyaddr(strip))[0]
175		except Exception:
176			return UNRESOLVED
177
178	def createlink(update):
179		c = []
180		for k in fields:
181			if k not in update:
182				c.append("%s=%s" % (k,urlescape(fields.getvalue(k))))
183		for k,v in update.items():
184			if v!="":
185				c.append("%s=%s" % (k,urlescape(v)))
186		return "mfs.cgi?%s" % ("&amp;".join(c))
187
188	def createjslink(update):
189		c = []
190		for k in fields:
191			if k not in update:
192				c.append("%s=%s" % (k,urlescape(fields.getvalue(k))))
193		for k,v in update.items():
194			if v!="":
195				c.append("%s=%s" % (k,urlescape(v)))
196		return "mfs.cgi?%s" % ("&".join(c))
197
198	def createorderlink(prefix,columnid):
199		ordername = "%sorder" % prefix
200		revname = "%srev" % prefix
201		try:
202			orderval = int(fields.getvalue(ordername))
203		except Exception:
204			orderval = 0
205		try:
206			revval = int(fields.getvalue(revname))
207		except Exception:
208			revval = 0
209		return createlink({revname:"1"}) if orderval==columnid and revval==0 else createlink({ordername:str(columnid),revname:"0"})
210
211	def createinputs(ignorefields):
212		for k in fields:
213			if k not in ignorefields:
214				yield """<input type="hidden" name="%s" value="%s">""" % (k,htmlentities(fields.getvalue(k)))
215		return
216
217else: # CLI mode
218	import getopt
219
220	masterhost = '@DEFAULT_MASTERNAME@'
221	masterport = @DEFAULT_MASTER_CLIENT_PORT@
222	mastercontrolport = @DEFAULT_MASTER_CONTROL_PORT@
223	mastername = 'MooseFS'
224	frameset = -1
225	plaintextseparator = "\t"
226	forceplaintext = 0
227	colormode = 0
228	donotresolve = 0
229	sectionset = []
230	sectionsubset = []
231	clicommands = []
232
233# order and data parameters
234	IMorder = 0
235	IMrev = 0
236	MForder = 0
237	MFrev = 0
238	CSorder = 0
239	CSrev = 0
240	MBorder = 0
241	MBrev = 0
242	HDorder = 0
243	HDrev = 0
244	HDperiod = 0
245	HDtime = 0
246	HDaddrname = 1
247	EXorder = 0
248	EXrev = 0
249	MSorder = 0
250	MSrev = 0
251	SCorder = 0
252	SCrev = 0
253	OForder = 0
254	OFrev = 0
255	OFsessionid = 0
256	ALorder = 0
257	ALrev = 0
258	ALinode = 0
259	MOorder = 0
260	MOrev = 0
261	MOdata = 0
262	QUorder = 0
263	QUrev = 0
264	MCrange = 0
265	MCcount = 25
266	MCchdata = []
267	CCrange = 0
268	CCcount = 25
269	CCchdata = []
270	INmatrix = 0
271
272	mcchartslist = [
273			('ucpu',0,0,'User cpu usage'),
274			('scpu',1,0,'System cpu usage'),
275			('delete',2,1,'Number of chunk deletions'),
276			('replicate',3,1,'Number of chunk replications'),
277			('statfs',4,1,'Number of statfs operations'),
278			('getattr',5,1,'Number of getattr operations'),
279			('setattr',6,1,'Number of setattr operations'),
280			('lookup',7,1,'Number of lookup operations'),
281			('mkdir',8,1,'Number of mkdir operations'),
282			('rmdir',9,1,'Number of rmdir operations'),
283			('symlink',10,1,'Number of symlink operations'),
284			('readlink',11,1,'Number of readlink operations'),
285			('mknod',12,1,'Number of mknod operations'),
286			('unlink',13,1,'Number of unlink operations'),
287			('rename',14,1,'Number of rename operations'),
288			('link',15,1,'Number of link operations'),
289			('readdir',16,1,'Number of readdir operations'),
290			('open',17,1,'Number of open operations'),
291			('read',18,1,'Number of read operations'),
292			('write',19,1,'Number of write operations'),
293			('memoryrss',20,2,'Resident memory usage'),
294			('prcvd',21,1,'Received packets'),
295			('psent',22,1,'Sent packets'),
296			('brcvd',23,1,'Received bytes'),
297			('bsent',24,1,'Sent bytes'),
298			('memoryvirt',25,2,'Virtual memory usage'),
299			('usedspace',26,2,'RAW disk space usage'),
300			('totalspace',27,2,'RAW disk space connected'),
301			('create',28,1,'Number of chunk creation attempts'),
302			('change',29,1,'Number of chunk internal operation attempts'),
303			('delete_ok',30,1,'Number of successful chunk deletions'),
304			('delete_err',31,1,'Number of unsuccessful chunk deletions'),
305			('replicate_ok',32,1,'Number of successful chunk replications'),
306			('replicate_err',33,1,'Number of unsuccessful chunk replications'),
307			('create_ok',34,1,'Number of successful chunk creations'),
308			('create_err',35,1,'Number of unsuccessful chunk creations'),
309			('change_ok',36,1,'Number of successful chunk internal operations'),
310			('change_err',37,1,'Number of unsuccessful chunk internal operations'),
311			('cpu',100,0,'Cpu usage (total sys+user)')
312	]
313	mcchartsabr = {
314			'delete':['del'],
315			'replicate':['rep','repl'],
316			'memoryrss':['memrss','rmem','mem'],
317			'memoryvirt':['memvirt','vmem']
318	}
319
320	ccchartslist = [
321			('ucpu',0,0,'User cpu usage'),
322			('scpu',1,0,'System cpu usage'),
323			('masterin',2,1,'Data received from master'),
324			('masterout',3,1,'Data sent to master'),
325			('csrepin',4,1,'Data received by replicator'),
326			('csrepout',5,1,'Data sent by replicator'),
327			('csservin',6,1,'Data received by csserv'),
328			('csservout',7,1,'Data sent by csserv'),
329			('hdrbytesr',8,5,'Bytes read (headers)'),
330			('hdrbytesw',9,5,'Bytes written (headers)'),
331			('hdrllopr',10,1,'Low level reads (headers)'),
332			('hdrllopw',11,1,'Low level writes (headers)'),
333			('databytesr',12,5,'Bytes read (data)'),
334			('databytesw',13,5,'Bytes written (data)'),
335			('datallopr',14,1,'Low level reads (data)'),
336			('datallopw',15,1,'Low level writes (data)'),
337			('hlopr',16,1,'High level reads'),
338			('hlopw',17,1,'High level writes'),
339			('rtime',18,4,'Read time'),
340			('wtime',19,4,'Write time'),
341			('repl',20,1,'Replicate chunk ops'),
342			('create',21,1,'Create chunk ops'),
343			('delete',22,1,'Delete chunk ops'),
344			('version',23,1,'Set version ops'),
345			('duplicate',24,1,'Duplicate ops'),
346			('truncate',25,1,'Truncate ops'),
347			('duptrunc',26,1,'Duptrunc (duplicate+truncate) ops'),
348			('test',27,1,'Test chunk ops'),
349			('load',28,3,'Server load'),
350			('memoryrss',29,2,'Resident memory usage'),
351			('memoryvirt',30,2,'Virtual memory usage'),
352			('movels',31,1,'Low speed move ops'),
353			('movehs',32,1,'High speed move ops'),
354			('cpu',100,0,'Cpu usage (total sys+user)')
355	]
356	ccchartsabr = {
357			'memoryrss':['memrss','rmem','mem'],
358			'memoryvirt':['memvirt','vmem']
359	}
360
361	mccharts = {}
362	cccharts = {}
363	for name,no,mode,desc in mcchartslist:
364		mccharts[name] = (no,mode,desc)
365	for name,abrlist in mcchartsabr.items():
366		for abr in abrlist:
367			mccharts[abr] = mccharts[name]
368	for name,no,mode,desc in ccchartslist:
369		cccharts[name] = (no,mode,desc)
370	for name,abrlist in ccchartsabr.items():
371		for abr in abrlist:
372			cccharts[abr] = cccharts[name]
373
374	lastsval = ''
375	lastorder = None
376	lastrev = 0
377	lastid = 0
378	lastmode = None
379	try:
380		opts,args = getopt.getopt(sys.argv[1:],"hvH:P:S:C:f:ps:no:rm:i:a:b:c:d:28")
381	except Exception:
382		opts = [('-h',None)]
383	for opt,val in opts:
384		if val==None:
385			val=""
386		if opt=='-h':
387			print("usage:")
388			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|RS|SC|OF|AL|MO|QU|MC|CC) [-s separator] [-o order_id [-r]] [-m mode_id] [i id] [-a count] [-b chart_data_columns] [-c count] [-d chart_data_columns]" % sys.argv[0])
389			print("\t%s [-hpn28] [-H master_host] [-P master_port] [-f 0..3] -C(RC/ip/port|BW/ip/port|M[01]/ip/port|RS/sessionid)" % sys.argv[0])
390			print("\t%s -v" % sys.argv[0])
391			print("\ncommon:\n")
392			print("\t-h : print this message and exit")
393			print("\t-v : print version number and exit")
394			print("\t-p : force plain text format on tty devices")
395			print("\t-s separator : field separator to use in plain text format on tty devices (forces -p)")
396			print("\t-2 : force 256-color terminal color codes")
397			print("\t-8 : force 8-color terminal color codes")
398			print("\t-H master_host : master address (default: @DEFAULT_MASTERNAME@)")
399			print("\t-P master_port : master client port (default: @DEFAULT_MASTER_CLIENT_PORT@)")
400			print("\t-n : do not resolve ip addresses (default when output device is not tty)")
401			print("\t-f frame charset number : set frame charset to be displayed as table frames in ttymode")
402			print("\t\t-f0 : use simple ascii frames '+','-','|' (default for non utf-8 encodings)")
403			if (sys.stdout.encoding=='UTF-8' or sys.stdout.encoding=='utf-8'):
404				if sys.version_info[0]<3:
405					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")
406					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")
407					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)")
408				else:
409					print("\t\t-f1 : use utf-8 frames: \u250f\u2533\u2513\u2523\u254b\u252b\u2517\u253b\u251b\u2501\u2503\u2578\u2579\u257a\u257b")
410					print("\t\t-f2 : use utf-8 frames: \u250c\u252c\u2510\u251c\u253c\u2524\u2514\u2534\u2518\u2500\u2502\u2574\u2575\u2576\u2577")
411					print("\t\t-f3 : use utf-8 frames: \u2554\u2566\u2557\u2560\u256c\u2563\u255a\u2569\u255d\u2550\u2551 (default for utf-8 encodings)")
412			else:
413				print("\t\t-f1 : use utf-8 frames (thick single)")
414				print("\t\t-f2 : use utf-8 frames (thin single)")
415				print("\t\t-f3 : use utf-8 frames (double - default for utf-8 encodings)")
416			print("\nmonitoring:\n")
417			print("\t-S data set : defines data set to be displayed")
418			print("\t\t-SIN : show full master info")
419			print("\t\t-SIM : show only masters states")
420			print("\t\t-SLI : show only licence info")
421			print("\t\t-SIG : show only general master (leader) info")
422			print("\t\t-SMU : show only master memory usage")
423			print("\t\t-SIC : show only chunks info (goal/copies matrices)")
424			print("\t\t-SIL : show only loop info (with messages)")
425			print("\t\t-SMF : show only missing chunks/files")
426			print("\t\t-SCS : show connected chunk servers")
427			print("\t\t-SMB : show connected metadata backup servers")
428			print("\t\t-SHD : show hdd data")
429			print("\t\t-SEX : show exports")
430			print("\t\t-SMS : show active mounts")
431			print("\t\t-SRS : show resources (storage classes,open files,acquired locks)")
432			print("\t\t-SSC : show storage classes")
433			print("\t\t-SOF : show only open files")
434			print("\t\t-SAL : show only acquired locks")
435			print("\t\t-SMO : show operation counters")
436			print("\t\t-SQU : show quota info")
437			print("\t\t-SMC : show master charts data")
438			print("\t\t-SCC : show chunkserver charts data")
439			print("\t-o order_id : sort data by column specified by 'order id' (depends on data set)")
440			print("\t-r : reverse order")
441			print("\t-m mode_id : show data specified by 'mode id' (depends on data set)")
442			print("\t-i id : sessionid for -SOF or inode for -SAL")
443			print("\t-a count : how many master chart entries should be shown")
444			print("\t-b chart_data_columns : define master chart columns")
445			print("\t-c count : how many chunkserver chart entries should be shown")
446			print("\t-d chart_data_columns : define chunkserver chart columns (prefix with '+' for raw data, prefix with 'ip:[port:]' for server choice)")
447			print("\t\tmaster charts columns:")
448			for name,no,mode,desc in mcchartslist:
449				if name in mcchartsabr:
450					name = "%s,%s" % (name,",".join(mcchartsabr[name]))
451				print("\t\t\t%s - %s" % (name,desc))
452			print("\t\tchunkserver chart columns:")
453			for name,no,mode,desc in ccchartslist:
454				if name in ccchartsabr:
455					name = "%s,%s" % (name,",".join(ccchartsabr[name]))
456				print("\t\t\t%s - %s" % (name,desc))
457			print("\ncommands:\n")
458			print("\t-C command : perform particular command")
459			print("\t\t-CRC/ip/port : remove given chunkserver from list of active chunkservers")
460			print("\t\t-CBW/ip/port : send given chunkserver back to work (from grace state)")
461			print("\t\t-CM1/ip/port : switch given chunkserver to maintenance mode")
462			print("\t\t-CM0/ip/port : switch given chunkserver to standard mode (from maintenance mode)")
463			print("\t\t-CRS/sessionid : remove given session")
464			os._exit(0)
465		elif opt=='-v':
466			print("version: %s" % VERSION)
467			os._exit(0)
468		elif opt=='-2':
469			colormode = 2
470		elif opt=='-8':
471			colormode = 1
472		elif opt=='-p':
473			forceplaintext = 1
474		elif opt=='-s':
475			plaintextseparator = val
476			forceplaintext = 1
477		elif opt=='-n':
478			donotresolve = 1
479		elif opt=='-f':
480			frameset = int(val)
481		elif opt=='-H':
482			masterhost = val
483		elif opt=='-P':
484			masterport = int(val)
485		elif opt=='-S':
486			lastsval = val
487			if 'IN' in val:
488				sectionset.append("IN")
489				sectionsubset.append("IM")
490				sectionsubset.append("LI")
491				sectionsubset.append("IG")
492				sectionsubset.append("MU")
493				sectionsubset.append("IC")
494				sectionsubset.append("IL")
495				sectionsubset.append("MF")
496				if lastmode!=None:
497					INmatrix = lastmode
498				if lastorder!=None:
499					IMorder = lastorder
500				if lastrev:
501					IMrev = 1
502			if 'IM' in val:
503				sectionset.append("IN")
504				sectionsubset.append("IM")
505				if lastorder!=None:
506					IMorder = lastorder
507				if lastrev:
508					IMrev = 1
509			if 'LI' in val:
510				sectionset.append("IN")
511				sectionsubset.append("LI")
512			if 'IG' in val:
513				sectionset.append("IN")
514				sectionsubset.append("IG")
515			if 'MU' in val:
516				sectionset.append("IN")
517				sectionsubset.append("MU")
518			if 'IC' in val:
519				sectionset.append("IN")
520				sectionsubset.append("IC")
521				if lastmode!=None:
522					INmatrix = lastmode
523			if 'IL' in val:
524				sectionset.append("IN")
525				sectionsubset.append("IL")
526			if 'MF' in val:
527				sectionset.append("IN")
528				sectionsubset.append("MF")
529				if lastorder!=None:
530					MForder = lastorder
531				if lastrev:
532					MFrev = 1
533			if 'CS' in val:
534				sectionset.append("CS")
535				sectionsubset.append("CS")
536				if lastorder!=None:
537					CSorder = lastorder
538				if lastrev:
539					CSrev = 1
540			if 'MB' in val:
541				sectionset.append("CS")
542				sectionsubset.append("MB")
543				if lastorder!=None:
544					MBorder = lastorder
545				if lastrev:
546					MBrev = 1
547			if 'HD' in val:
548				sectionset.append("HD")
549				if lastorder!=None:
550					HDorder = lastorder
551				if lastrev:
552					HDrev = 1
553				if lastmode!=None:
554					if lastmode>=0 and lastmode<6:
555						HDperiod,HDtime = divmod(lastmode,2)
556			if 'EX' in val:
557				sectionset.append("EX")
558				if lastorder!=None:
559					EXorder = lastorder
560				if lastrev:
561					EXrev = 1
562			if 'MS' in val:
563				sectionset.append("MS")
564				if lastorder!=None:
565					MSorder = lastorder
566				if lastrev:
567					MSrev = 1
568			if 'MO' in val:
569				sectionset.append("MO")
570				if lastorder!=None:
571					MOorder = lastorder
572				if lastrev:
573					MOrev = 1
574				if lastmode!=None:
575					MOdata = lastmode
576			if 'RS' in val:
577				sectionset.append("RS")
578				sectionsubset.append("SC")
579				sectionsubset.append("OF")
580				sectionsubset.append("AL")
581			if 'SC' in val:
582				sectionset.append("RS")
583				sectionsubset.append("SC")
584				if lastorder!=None:
585					SCorder = lastorder
586				if lastrev:
587					SCrev = 1
588			if 'OF' in val:
589				sectionset.append("RS")
590				sectionsubset.append("OF")
591				if lastorder!=None:
592					OForder = lastorder
593				if lastrev:
594					OFrev = 1
595				if lastid:
596					OFsessionid = lastid
597			if 'AL' in val:
598				sectionset.append("RS")
599				sectionsubset.append("AL")
600				if lastorder!=None:
601					ALorder = lastorder
602				if lastrev:
603					ALrev = 1
604				if lastid:
605					ALinode = lastid
606			if 'QU' in val:
607				sectionset.append("QU")
608				if lastorder!=None:
609					QUorder = lastorder
610				if lastrev:
611					QUrev = 1
612			if 'MC' in val:
613				sectionset.append("MC")
614				if lastmode!=None:
615					MCrange = lastmode
616			if 'CC' in val:
617				sectionset.append("CC")
618				if lastmode!=None:
619					CCrange = lastmode
620			lastorder = None
621			lastrev = 0
622			lastmode = None
623		elif opt=='-o':
624			if 'IM' in lastsval:
625				IMorder = int(val)
626			if 'MF' in lastsval:
627				MForder = int(val)
628			if 'CS' in lastsval:
629				CSorder = int(val)
630			if 'MB' in lastsval:
631				MBorder = int(val)
632			if 'HD' in lastsval:
633				HDorder = int(val)
634			if 'EX' in lastsval:
635				EXorder = int(val)
636			if 'MS' in lastsval:
637				MSorder = int(val)
638			if 'MO' in lastsval:
639				MOorder = int(val)
640			if 'SC' in lastsval:
641				SCorder = int(val)
642			if 'OF' in lastsval:
643				OForder = int(val)
644			if 'AL' in lastsval:
645				ALorder = int(val)
646			if 'QU' in lastsval:
647				QUorder = int(val)
648			if lastsval=='':
649				lastorder = int(val)
650		elif opt=='-r':
651			if 'IM' in lastsval:
652				IMrev = 1
653			if 'MF' in lastsval:
654				MFrev = 1
655			if 'CS' in lastsval:
656				CSrev = 1
657			if 'MB' in lastsval:
658				MBrev = 1
659			if 'HD' in lastsval:
660				HDrev = 1
661			if 'EX' in lastsval:
662				EXrev = 1
663			if 'MS' in lastsval:
664				MSrev = 1
665			if 'MO' in lastsval:
666				MOrev = 1
667			if 'SC' in lastsval:
668				SCrev = 1
669			if 'OF' in lastsval:
670				OFrev = 1
671			if 'AL' in lastsval:
672				ALrev = 1
673			if 'QU' in lastsval:
674				QUrev = 1
675			if lastsval=='':
676				lastrev = 1
677		elif opt=='-m':
678			if 'HD' in lastsval:
679				d = int(val)
680				if d>=0 and d<6:
681					HDperiod,HDtime = divmod(d,2)
682			if 'MO' in lastsval:
683				MOdata = int(val)
684			if 'IN' in lastsval or 'IC' in lastsval:
685				INmatrix = int(val)
686			if 'MC' in lastsval:
687				MCrange = int(val)
688			if 'CC' in lastsval:
689				CCrange = int(val)
690			if lastsval=='':
691				lastmode = int(val)
692		elif opt=='-i':
693			if 'OF' in lastsval:
694				OFsessionid = int(val)
695			if 'AL' in lastsval:
696				ALinode = int(val)
697			if lastsval=='':
698				lastid = int(val)
699		elif opt=='-a':
700			MCcount = int(val)
701		elif opt=='-b':
702			for x in val.split(','):
703				x = x.strip()
704				if ':' in x:
705					xs = x.split(':')
706					if len(xs)==2:
707						chhost = xs[0]
708						chport = 9421
709						x = xs[1]
710					elif len(xs)==3:
711						chhost = xs[0]
712						chport = int(xs[1])
713						x = xs[2]
714					else:
715						print("Unknown chart name: %s" % x)
716						os._exit(0)
717				else:
718					chhost = None
719					chport = None
720				if x[0]=='+':
721					x = x[1:]
722					rawmode = 1
723				else:
724					rawmode = 0
725				if x in mccharts:
726					MCchdata.append((chhost,chport,mccharts[x][0],mccharts[x][1],mccharts[x][2],rawmode))
727				else:
728					print("Unknown master chart name: %s" % x)
729					os._exit(0)
730		elif opt=='-c':
731			CCcount = int(val)
732		elif opt=='-d':
733			for x in val.split(','):
734				x = x.strip()
735				if ':' in x:
736					xs = x.split(':')
737					if len(xs)==2:
738						chhost = xs[0]
739						chport = 9422
740						x = xs[1]
741					elif len(xs)==3:
742						chhost = xs[0]
743						chport = int(xs[1])
744						x = xs[2]
745					else:
746						print("Unknown chart name: %s" % x)
747						os._exit(0)
748				else:
749					chhost = None
750					chport = None
751				if x[0]=='+':
752					x = x[1:]
753					rawmode = 1
754				else:
755					rawmode = 0
756				if x in cccharts:
757					if chhost==None or chport==None:
758						print("in chunkserver chart data server ip/host must be specified")
759						os._exit(0)
760					CCchdata.append((chhost,chport,cccharts[x][0],cccharts[x][1],cccharts[x][2],rawmode))
761				else:
762					print("Unknown chunkserver chart name: %s" % x)
763					os._exit(0)
764		elif opt=='-C':
765			clicommands.append(val)
766
767	if sectionset==[] and clicommands==[]:
768		print("Specify data to be shown (option -S) or command (option -C). Use '-h' for help.")
769		os._exit(0)
770
771	ttymode = 1 if forceplaintext==0 and os.isatty(1) else 0
772	if ttymode:
773		try:
774			import curses
775			curses.setupterm()
776			if curses.tigetnum("colors")>=256:
777				colors256 = 1
778			else:
779				colors256 = 0
780		except Exception:
781			colors256 = 1 if 'TERM' in os.environ and '256color' in os.environ['TERM'] else 0
782		# colors: 0 - white,1 - red,2 - orange,3 - yellow,4 - green,5 - cyan,6 - blue,7 - violet,8 - gray
783		CSI="\x1B["
784		if colors256:
785			ttyreset=CSI+"0m"
786			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"]
787		else:
788			ttysetred=CSI+"31m"
789			ttysetyellow=CSI+"33m"
790			ttysetgreen=CSI+"32m"
791			ttysetcyan=CSI+"36m"
792			ttysetblue=CSI+"34m"
793			ttysetmagenta=CSI+"35m"
794			ttyreset=CSI+"0m"
795			# no orange - use red, no gray - use white
796			colorcode=[ttysetred,ttysetred,ttysetyellow,ttysetgreen,ttysetcyan,ttysetblue,ttysetmagenta,""]
797	else:
798		colorcode=["","","","","","","",""]
799
800	if ttymode and (sys.stdout.encoding=='UTF-8' or sys.stdout.encoding=='utf-8'):
801		if frameset>=0 and frameset<=3:
802			tabbleframes=frameset
803		else:
804			tabbleframes=0
805	else:
806		tabbleframes=0
807
808	# terminal encoding mambo jumbo (mainly replace unicode chars that can't be printed with '?' instead of throwing exception)
809	term_encoding = sys.stdout.encoding
810	if term_encoding==None:
811		term_encoding = 'utf-8'
812	if sys.version_info[0]<3:
813		sys.stdout = codecs.getwriter(term_encoding)(sys.stdout,'replace')
814		sys.stdout.encoding = term_encoding
815	elif sys.version_info[1]<7:
816		sys.stdout = codecs.getwriter(term_encoding)(sys.stdout.detach(),'replace')
817		sys.stdout.encoding = term_encoding
818	else:
819		sys.stdout.reconfigure(errors='replace')
820
821	# lines prepared for JSON output (force utf-8):
822	#if sys.version_info[0]<3:
823	#	sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
824	#elif sys.version_info[1]<7:
825	#	sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach())
826	#else:
827	#	sys.stdout.reconfigure(encoding='utf-8')
828
829	# frames:
830	#  +-----+-----+-----+-----+
831	#  |     |     |     |     |
832	#  |     |     |     |  |  |
833	#  |  +- | -+- | -+  |  +- |
834	#  |  |  |  |  |  |  |  |  |
835	#  |     |     |     |     |
836	#  +-----+-----+-----+-----+
837	#  |     |     |     |     |
838	#  |  |  |  |  |  |  |  |  |
839	#  | -+- | -+  |  +- | -+- |
840	#  |  |  |  |  |     |     |
841	#  |     |     |     |     |
842	#  +-----+-----+-----+-----+
843	#  |     |     |     |     |
844	#  |  |  |     |  |  |     |
845	#  | -+  | -+- |  +  | -+  |
846	#  |     |     |  |  |     |
847	#  |     |     |     |     |
848	#  +-----+-----+-----+-----+
849	#  |     |     |     |     |
850	#  |  |  |     |     |     |
851	#  |  +  |  +- |  +  |  +  |
852	#  |     |     |  |  |     |
853	#  |     |     |     |     |
854	#  +-----+-----+-----+-----+
855	#
856
857	class Tabble:
858		Needseparator = 0
859		def __init__(self,title,ccnt,defattr=""):
860			if tabbleframes==1:
861				if sys.version_info[0]<3:
862					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', ' ']
863				else:
864					self.frames = ['\u250f', '\u2533', '\u2513', '\u2523', '\u254b', '\u252b', '\u2517', '\u253b', '\u251b', '\u2501', '\u2503', '\u2578', '\u2579', '\u257a', '\u257b', ' ']
865			elif tabbleframes==2:
866				if sys.version_info[0]<3:
867					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', ' ']
868				else:
869					self.frames = ['\u250c', '\u252c', '\u2510', '\u251c', '\u253c', '\u2524', '\u2514', '\u2534', '\u2518', '\u2500', '\u2502', '\u2574', '\u2575', '\u2576', '\u2577', ' ']
870			elif tabbleframes==3:
871				if sys.version_info[0]<3:
872					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', ' ']
873				else:
874					self.frames = ['\u2554', '\u2566', '\u2557', '\u2560', '\u256c', '\u2563', '\u255a', '\u2569', '\u255d', '\u2550', '\u2551', ' ', '\u2551', ' ', '\u2551', ' ']
875			else:
876				self.frames = ['+','+','+','+','+','+','+','+','+','-','|',' ','|',' ','|',' ']
877			self.title = title
878			self.ccnt = ccnt
879			self.head = []
880			self.body = []
881			self.defattrs = []
882			self.cwidth = []
883			for _ in range(ccnt):
884				self.defattrs.append(defattr)
885				self.cwidth.append(0)
886		def combineattr(self,attr,defattr):
887			attrcolor = ""
888			for c in ("0","1","2","3","4","5","6","7","8"):
889				if c in defattr:
890					attrcolor = c
891			for c in ("0","1","2","3","4","5","6","7","8"):
892				if c in attr:
893					attrcolor = c
894			attrjust = ""
895			for c in ("l","L","r","R","c","C"):
896				if c in defattr:
897					attrjust = c
898			for c in ("l","L","r","R","c","C"):
899				if c in attr:
900					attrjust = c
901			return attrcolor+attrjust
902		def header(self,*rowdata):
903			ccnt = 0
904			for celldata in rowdata:
905				if type(celldata)==tuple:
906					if len(celldata)==3:
907						ccnt+=celldata[2]
908					else:
909						if celldata[0]!=None:
910							cstr = myunicode(celldata[0])
911							if len(cstr) > self.cwidth[ccnt]:
912								self.cwidth[ccnt] = len(cstr)
913						ccnt+=1
914				else:
915					if celldata!=None:
916						cstr = myunicode(celldata)
917						if len(cstr) > self.cwidth[ccnt]:
918							self.cwidth[ccnt] = len(cstr)
919					ccnt+=1
920			if ccnt != self.ccnt:
921				raise IndexError
922			self.head.append(rowdata)
923		def defattr(self,*rowdata):
924			if len(rowdata) != self.ccnt:
925				raise IndexError
926			self.defattrs = rowdata
927		def append(self,*rowdata):
928			ccnt = 0
929			rdata = []
930			for celldata in rowdata:
931				if type(celldata)==tuple:
932					if celldata[0]!=None:
933						cstr = myunicode(celldata[0])
934					else:
935						cstr = ""
936					if len(celldata)==3:
937						rdata.append((cstr,self.combineattr(celldata[1],self.defattrs[ccnt]),celldata[2]))
938						ccnt+=celldata[2]
939					else:
940						if len(cstr) > self.cwidth[ccnt]:
941							self.cwidth[ccnt] = len(cstr)
942						if len(celldata)==2:
943							rdata.append((cstr,self.combineattr(celldata[1],self.defattrs[ccnt])))
944						else:
945							rdata.append((cstr,self.defattrs[ccnt]))
946						ccnt+=1
947				else:
948					if celldata!=None:
949						cstr = myunicode(celldata)
950						if len(cstr) > self.cwidth[ccnt]:
951							self.cwidth[ccnt] = len(cstr)
952						rdata.append((cstr,self.defattrs[ccnt]))
953					else:
954						rdata.append(celldata)
955					ccnt+=1
956			if ccnt != self.ccnt:
957				raise IndexError
958			self.body.append(rdata)
959		def attrdata(self,cstr,cattr,cwidth):
960			retstr = ""
961			if "1" in cattr:
962				retstr += colorcode[0]
963				needreset = 1
964			elif "2" in cattr:
965				retstr += colorcode[1]
966				needreset = 1
967			elif "3" in cattr:
968				retstr += colorcode[2]
969				needreset = 1
970			elif "4" in cattr:
971				retstr += colorcode[3]
972				needreset = 1
973			elif "5" in cattr:
974				retstr += colorcode[4]
975				needreset = 1
976			elif "6" in cattr:
977				retstr += colorcode[5]
978				needreset = 1
979			elif "7" in cattr:
980				retstr += colorcode[6]
981				needreset = 1
982			elif "8" in cattr:
983				retstr += colorcode[7]
984				needreset = 1
985			else:
986				needreset = 0
987			if cstr=="--":
988				retstr += " "+"-"*cwidth+" "
989			elif cstr=="---":
990				retstr += "-"*(cwidth+2)
991			elif "L" in cattr or "l" in cattr:
992				retstr += " "+cstr.ljust(cwidth)+" "
993			elif "R" in cattr or "r" in cattr:
994				retstr += " "+cstr.rjust(cwidth)+" "
995			else:
996				retstr += " "+cstr.center(cwidth)+" "
997			if needreset:
998				retstr += ttyreset
999			return retstr
1000		def lines(self):
1001			outstrtab = []
1002			if ttymode:
1003				tabdata = []
1004				# upper frame
1005				tabdata.append((("---","",self.ccnt),))
1006				# title
1007				tabdata.append(((self.title,"",self.ccnt),))
1008				# header
1009				if len(self.head)>0:
1010					tabdata.append((("---","",self.ccnt),))
1011					tabdata.extend(self.head)
1012				# head and data separator
1013				tabdata.append((("---","",self.ccnt),))
1014				# data
1015				if len(self.body)==0:
1016					tabdata.append((("no data","",self.ccnt),))
1017				else:
1018					tabdata.extend(self.body)
1019				# bottom frame
1020				tabdata.append((("---","",self.ccnt),))
1021				# check col-spaned headers and adjust column widths if necessary
1022				for rowdata in tabdata:
1023					ccnt = 0
1024					for celldata in rowdata:
1025						if type(celldata)==tuple and len(celldata)==3 and celldata[0]!=None:
1026							cstr = myunicode(celldata[0])
1027							clen = len(cstr)
1028							cwidth = sum(self.cwidth[ccnt:ccnt+celldata[2]])+3*(celldata[2]-1)
1029							if clen > cwidth:
1030								add = clen - cwidth
1031								adddm = divmod(add,celldata[2])
1032								cadd = adddm[0]
1033								if adddm[1]>0:
1034									cadd+=1
1035								for i in range(celldata[2]):
1036									self.cwidth[ccnt+i] += cadd
1037							ccnt += celldata[2]
1038						else:
1039							ccnt += 1
1040				separators = []
1041				# before tab - no separators
1042				seplist = []
1043				for i in range(self.ccnt+1):
1044					seplist.append(0)
1045				separators.append(seplist)
1046				for rowdata in tabdata:
1047					seplist = [1]
1048					for celldata in rowdata:
1049						if type(celldata)==tuple and len(celldata)==3:
1050							for i in range(celldata[2]-1):
1051								seplist.append(1 if celldata[0]=='---' else 0)
1052						seplist.append(1)
1053					separators.append(seplist)
1054				# after tab - no separators
1055				seplist = []
1056				for i in range(self.ccnt+1):
1057					seplist.append(0)
1058				separators.append(seplist)
1059				# add upper and lower separators:
1060				updownsep = [[a*2 + b for (a,b) in zip(x,y)] for (x,y) in zip(separators[2:],separators[:-2])]
1061				# create tabble
1062				for (rowdata,sepdata) in zip(tabdata,updownsep):
1063	#				print rowdata,sepdata
1064					ccnt = 0
1065					line = ""
1066					nsep = 0 #self.frames[10]
1067					for celldata in rowdata:
1068						cpos = ccnt
1069						cattr = ""
1070						if type(celldata)==tuple:
1071							if celldata[1]!=None:
1072								cattr = celldata[1]
1073							if len(celldata)==3:
1074								cwidth = sum(self.cwidth[ccnt:ccnt+celldata[2]])+3*(celldata[2]-1)
1075								ccnt+=celldata[2]
1076							else:
1077								cwidth = self.cwidth[ccnt]
1078								ccnt+=1
1079							cstr = celldata[0]
1080						else:
1081							cstr = celldata
1082							cwidth = self.cwidth[ccnt]
1083							ccnt+=1
1084						if cstr==None:
1085							cstr = ""
1086						cstr = myunicode(cstr)
1087						if cstr=="---":
1088							if nsep==0:
1089								line += self.frames[(13,6,0,3)[sepdata[cpos]]]
1090								#line += self.frames[(15,6,0,3)[sepdata[cpos]]]
1091							else:
1092								line += self.frames[(9,7,1,4)[sepdata[cpos]]]
1093							nsep = 1 #self.frames[4]
1094							for ci in range(cpos,ccnt-1):
1095								line += self.frames[9]*(self.cwidth[ci]+2)
1096								line += self.frames[(9,7,1,4)[sepdata[ci+1]]]
1097							line += self.frames[9]*(self.cwidth[ccnt-1]+2)
1098						else:
1099							if nsep==0:
1100								line += self.frames[(15,12,14,10)[sepdata[cpos]]]
1101								#line += self.frames[(15,10,10,10)[sepdata[cpos]]]
1102							else:
1103								line += self.frames[(11,8,2,5)[sepdata[cpos]]]
1104								#line += self.frames[(15,8,2,5)[sepdata[cpos]]]
1105							nsep = 0
1106							line += self.attrdata(cstr,cattr,cwidth)
1107					if nsep==0:
1108						line += self.frames[(15,12,14,10)[sepdata[ccnt]]]
1109						#line += self.frames[(15,10,10,10)[sepdata[ccnt]]]
1110					else:
1111						line += self.frames[(11,8,2,5)[sepdata[ccnt]]]
1112						#line += self.frames[(15,8,2,5)[sepdata[ccnt]]]
1113					outstrtab.append(line)
1114			else:
1115				for rowdata in self.body:
1116					row = []
1117					for celldata in rowdata:
1118						if type(celldata)==tuple:
1119							cstr = myunicode(celldata[0])
1120						elif celldata!=None:
1121							cstr = myunicode(celldata)
1122						else:
1123							cstr = ""
1124						row.append(cstr)
1125					outstrtab.append("%s:%s%s" % (self.title,plaintextseparator,plaintextseparator.join(row)))
1126			return outstrtab
1127		def __str__(self):
1128			if Tabble.Needseparator:
1129				sep = "\n"
1130			else:
1131				sep = ""
1132				Tabble.Needseparator = 1
1133			return sep+("\n".join(self.lines()))
1134
1135	#x = Tabble("Test title",4)
1136	#x.header("column1","column2","column3","column4")
1137	#x.append("t1","t2","very long entry","test")
1138	#x.append(("r","r3"),("l","l2"),"also long entry","test")
1139	#print x
1140	#
1141	#x = Tabble("Very long tabble title",2)
1142	#x.defattr("l","r")
1143	#x.append("key","value")
1144	#x.append("other key",123)
1145	#y = []
1146	#y.append(("first","1"))
1147	#y.append(("second","4"))
1148	#x.append(*y)
1149	#print x
1150	#
1151	#x = Tabble("Tabble with complicated header",15,"r")
1152	#x.header(("","",4),("I/O stats last min","",8),("","",3))
1153	#x.header(("info","",4),("---","",8),("space","",3))
1154	#x.header(("","",4),("transfer","",2),("max time","",3),("# of ops","",3),("","",3))
1155	#x.header(("---","",15))
1156	#x.header("IP path","chunks","last error","status","read","write","read","write","fsync","read","write","fsync","used","total","used %")
1157	#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%")
1158	#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%")
1159	#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%")
1160	#x.append("192.168.1.211:9422:/mnt/hd5/",49128,"no errors",("marked for removal","4"),"-","-","-","-","-","-","-","-","501 GiB","1.3 TiB","36.46%")
1161	##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%")
1162	##x.append("192.168.1.211:9422:/mnt/hd5/",49128,"no errors",("marked for removal","4"),("","-",8),"501 GiB","1.3 TiB","36.46%")
1163	#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%")
1164	#print x
1165	#
1166	#x = Tabble("Colors",1,"r")
1167	#x.append(("white","0"))
1168	#x.append(("red","1"))
1169	#x.append(("orange","2"))
1170	#x.append(("yellow","3"))
1171	#x.append(("green","4"))
1172	#x.append(("cyan","5"))
1173	#x.append(("blue","6"))
1174	#x.append(("magenta","7"))
1175	#x.append(("gray","8"))
1176	#print x
1177	#
1178	#x = Tabble("Adjustments",1)
1179	#x.append(("left","l"))
1180	#x.append(("right","r"))
1181	#x.append(("center","c"))
1182	#print x
1183	#
1184	#x = Tabble("Special entries",3)
1185	#x.defattr("l","r","r")
1186	#x.header("entry","effect","extra column")
1187	#x.append("-- ","--","")
1188	#x.append("--- ","---","")
1189	#x.append("('--','',2)",('--','',2))
1190	#x.append("('','',2)",('','',2))
1191	#x.append("('---','',2)",('---','',2))
1192	#x.append("('red','1')",('red','1'),'')
1193	#x.append("('orange','2')",('orange','2'),'')
1194	#x.append("('yellow','3')",('yellow','3'),'')
1195	#x.append("('green','4')",('green','4'),'')
1196	#x.append("('cyan','5')",('cyan','5'),'')
1197	#x.append("('blue','6')",('blue','6'),'')
1198	#x.append("('magenta','7')",('magenta','7'),'')
1199	#x.append("('gray','8')",('gray','8'),'')
1200	#x.append(('---','',3))
1201	#x.append("('left','l',2)",('left','l',2))
1202	#x.append("('right','r',2)",('right','r',2))
1203	#x.append("('center','c',2)",('center','c',2))
1204	#print x
1205
1206	def resolve(strip):
1207		if donotresolve:
1208			return strip
1209		try:
1210			return (socket.gethostbyaddr(strip))[0]
1211		except Exception:
1212			return strip
1213
1214
1215
1216
1217
1218
1219# common auxilinary functions
1220
1221def getmasteraddresses():
1222	m = []
1223	for mhost in masterhost.replace(';',' ').replace(',',' ').split():
1224		try:
1225			for i in socket.getaddrinfo(mhost,masterport,socket.AF_INET,socket.SOCK_STREAM,socket.SOL_TCP):
1226				if i[0]==socket.AF_INET and i[1]==socket.SOCK_STREAM and i[2]==socket.SOL_TCP:
1227					m.append(i[4])
1228		except Exception:
1229			pass
1230	return m
1231
1232#def mysend(socket,msg):
1233#	totalsent = 0
1234#	while totalsent < len(msg):
1235#		sent = socket.send(msg[totalsent:])
1236#		if sent == 0:
1237#			raise RuntimeError("socket connection broken")
1238#		totalsent = totalsent + sent
1239
1240#def myrecv(socket,leng):
1241#	if sys.version_info[0]<3:
1242#		msg = ''
1243#	else:
1244#		msg = bytes(0)
1245#	while len(msg) < leng:
1246#		chunk = socket.recv(leng-len(msg))
1247#		if len(chunk) == 0:
1248#			raise RuntimeError("socket connection broken")
1249#		msg = msg + chunk
1250#	return msg
1251
1252def disablesmask_to_string(disables_mask):
1253	cmds = ["chown","chmod","symlink","mkfifo","mkdev","mksock","mkdir","unlink","rmdir","rename","move","link","create","readdir","read","write","truncate","setlength","appendchunks","snapshot","settrash","setsclass","seteattr","setxattr","setfacl"]
1254	l = []
1255	m = 1
1256	for cmd in cmds:
1257		if disables_mask & m:
1258			l.append(cmd)
1259		m <<= 1
1260	return ",".join(l)
1261
1262def state_name(stateid):
1263	if stateid==STATE_DUMMY:
1264		return "DUMMY"
1265	elif stateid==STATE_USURPER:
1266		return "USURPER"
1267	elif stateid==STATE_FOLLOWER:
1268		return "FOLLOWER"
1269	elif stateid==STATE_ELECT:
1270		return "ELECT"
1271	elif stateid==STATE_LEADER:
1272		return "LEADER"
1273	else:
1274		return "???"
1275
1276def state_color(stateid,sync):
1277	if stateid==STATE_DUMMY:
1278		return 8
1279	elif stateid==STATE_FOLLOWER or stateid==STATE_USURPER:
1280		if sync:
1281			return 5
1282		else:
1283			return 6
1284	elif stateid==STATE_ELECT:
1285		return 3
1286	elif stateid==STATE_LEADER:
1287		return 4
1288	else:
1289		return 1
1290
1291def decimal_number(number,sep=' '):
1292	parts = []
1293	while number>=1000:
1294		number,rest = divmod(number,1000)
1295		parts.append("%03u" % rest)
1296	parts.append(str(number))
1297	parts.reverse()
1298	return sep.join(parts)
1299
1300def humanize_number(number,sep='',suff='B'):
1301	number*=100
1302	scale=0
1303	while number>=99950:
1304		number = number//1024
1305		scale+=1
1306	if number<995 and scale>0:
1307		b = (number+5)//10
1308		nstr = "%u.%u" % divmod(b,10)
1309	else:
1310		b = (number+50)//100
1311		nstr = "%u" % b
1312	if scale>0:
1313		return "%s%s%si%s" % (nstr,sep,"-KMGTPEZY"[scale],suff)
1314	else:
1315		return "%s%s%s" % (nstr,sep,suff)
1316
1317def timeduration_to_shortstr(timeduration):
1318	for l,s in ((86400,'d'),(3600,'h'),(60,'m'),(0,'s')):
1319		if timeduration>=l:
1320			if l>0:
1321				n = float(timeduration)/float(l)
1322			else:
1323				n = float(timeduration)
1324			rn = round(n,1)
1325			if n==round(n,0):
1326				return "%.0f%s" % (n,s)
1327			else:
1328				return "%s%.1f%s" % (("~" if n!=rn else ""),rn,s)
1329	return "???"
1330
1331def timeduration_to_fullstr(timeduration):
1332	if timeduration>=86400:
1333		days,dayseconds = divmod(timeduration,86400)
1334		daysstr = "%u day%s, " % (days,("s" if days!=1 else ""))
1335	else:
1336		dayseconds = timeduration
1337		daysstr = ""
1338	hours,hourseconds = divmod(dayseconds,3600)
1339	minutes,seconds = divmod(hourseconds,60)
1340	if seconds==round(seconds,0):
1341		return "%u second%s (%s%u:%02u:%02u)" % (timeduration,("" if timeduration==1 else "s"),daysstr,hours,minutes,seconds)
1342	else:
1343		seconds,fracsec = divmod(seconds,1)
1344		return "%.3f seconds (%s%u:%02u:%02u.%03u)" % (timeduration,daysstr,hours,minutes,seconds,round(1000*fracsec,0))
1345
1346def label_id_to_char(id):
1347	return chr(ord('A')+id)
1348
1349def labelmask_to_str(labelmask):
1350	str = ""
1351	m = 1
1352	for i in xrange(26):
1353		if labelmask & m:
1354			str += label_id_to_char(i)
1355		m <<= 1
1356	return str
1357
1358def labelmasks_to_str(labelmasks):
1359	if labelmasks[0]==0:
1360		return "*"
1361	r = []
1362	for labelmask in labelmasks:
1363		if labelmask==0:
1364			break
1365		r.append(labelmask_to_str(labelmask))
1366	return "+".join(r)
1367
1368
1369def print_exception():
1370	exc_type, exc_value, exc_traceback = sys.exc_info()
1371	try:
1372		if cgimode:
1373			print("""<table class="FR" cellspacing="0">""")
1374			print("""<tr><th>Oops!</th></tr>""")
1375			print("""<tr><td align="left"><b>An error has occurred. Check your MooseFS configuration and network connections. If you decide to seek support because of this error, please include the following traceback:</b>""")
1376			print("""<pre>""")
1377			print(traceback.format_exc().strip())
1378			print("""</pre></td></tr>""")
1379			print("""</table>""")
1380		elif ttymode:
1381			tab = Tabble("Exception Traceback",4)
1382			tab.header("file","line","in","text")
1383			tab.defattr("l","r","l","l")
1384			for d in traceback.extract_tb(exc_traceback):
1385				tab.append(d[0],d[1],d[2],repr(d[3]))
1386			tab.append(("---","",4))
1387			tab.append(("Error","c",4))
1388			tab.append(("---","",4))
1389			for d in traceback.format_exception_only(exc_type, exc_value):
1390				tab.append((repr(d.strip()),"",4))
1391			print("%s%s%s" % (colorcode[1],tab,ttyreset))
1392		else:
1393			print("""---------------------------------------------------------------- error -----------------------------------------------------------------""")
1394			print(traceback.format_exc().strip())
1395			print("""----------------------------------------------------------------------------------------------------------------------------------------""")
1396	except Exception:
1397		print(traceback.format_exc().strip())
1398
1399def version_convert(version):
1400	if version>=(2,0,0):
1401		return ((version[0],version[1],version[2]//2),version[2]&1)
1402	elif version>=(1,7,0):
1403		return (version,1)
1404	elif version>(0,0,0):
1405		return (version,0)
1406	else:
1407		return (version,-1)
1408
1409def version_str_and_sort(version):
1410	version,pro = version_convert(version)
1411	strver = "%u.%u.%u" % version
1412	sortver = "%05u_%03u_%03u" % version
1413	if pro==1:
1414		strver += " PRO"
1415		sortver += "_2"
1416	elif pro==0:
1417		sortver += "_1"
1418	else:
1419		sortver += "_0"
1420	return (strver,sortver)
1421
1422class MFSConn:
1423	def __init__(self,host,port):
1424		self.host = host
1425		self.port = port
1426		self.socket = None
1427		self.connect()
1428	def __del__(self):
1429		try:
1430			if self.socket:
1431				self.socket.close()
1432#				print "connection closed with: %s:%u" % (self.host,self.port)
1433			self.socket = None
1434		except AttributeError:
1435			pass
1436	def connect(self):
1437		cnt = 0
1438		while self.socket == None and cnt<3:
1439			self.socket = socket.socket()
1440			self.socket.settimeout(1)
1441			try:
1442				self.socket.connect((self.host,self.port))
1443			except Exception:
1444				self.socket.close()
1445				self.socket = None
1446				cnt += 1
1447		if self.socket==None:
1448			self.socket = socket.socket()
1449			self.socket.settimeout(1)
1450			self.socket.connect((self.host,self.port))
1451#		else:
1452#			print "connected to: %s:%u" % (self.host,self.port)
1453	def close(self):
1454		if self.socket:
1455			self.socket.close()
1456			self.socket = None
1457	def mysend(self,msg):
1458		if self.socket == None:
1459			self.connect()
1460		totalsent = 0
1461		while totalsent < len(msg):
1462			sent = self.socket.send(msg[totalsent:])
1463			if sent == 0:
1464				raise RuntimeError("socket connection broken")
1465			totalsent = totalsent + sent
1466	def myrecv(self,leng):
1467		if sys.version_info[0]<3:
1468			msg = ''
1469		else:
1470			msg = bytes(0)
1471		while len(msg) < leng:
1472			chunk = self.socket.recv(leng-len(msg))
1473			if len(chunk) == 0:
1474				raise RuntimeError("socket connection broken")
1475			msg = msg + chunk
1476		return msg
1477	def command(self,cmdout,cmdin,dataout=None):
1478		if dataout:
1479			l = len(dataout)
1480			msg = struct.pack(">LL",cmdout,l) + dataout
1481		else:
1482			msg = struct.pack(">LL",cmdout,0)
1483		cmdok = 0
1484		errcnt = 0
1485		while cmdok==0:
1486			try:
1487				self.mysend(msg)
1488				header = self.myrecv(8)
1489				cmd,length = struct.unpack(">LL",header)
1490				if cmd==cmdin:
1491					datain = self.myrecv(length)
1492					cmdok = 1
1493				else:
1494					raise RuntimeError("MFS communication error - bad answer")
1495			except Exception:
1496				if errcnt<3:
1497					self.close()
1498					self.connect()
1499					errcnt+=1
1500				else:
1501					raise RuntimeError("MFS communication error")
1502		return datain,length
1503
1504class Master(MFSConn):
1505	def __init__(self,host,port):
1506		MFSConn.__init__(self,host,port)
1507		self.version = (0,0,0)
1508		self.pro = -1
1509		self.featuremask = 0
1510	def set_version(self,version):
1511		self.version,self.pro = version_convert(version)
1512		if self.version>=(3,0,72):
1513			self.featuremask |= (1<<FEATURE_EXPORT_UMASK)
1514		if self.version>=(3,0,112):
1515			self.featuremask |= (1<<FEATURE_EXPORT_DISABLES)
1516	def version_at_least(self,v1,v2,v3):
1517		return (self.version>=(v1,v2,v3))
1518	def version_less_than(self,v1,v2,v3):
1519		return (self.version<(v1,v2,v3))
1520	def version_is(self,v1,v2,v3):
1521		return (self.version==(v1,v2,v3))
1522	def version_unknown(self):
1523		return (self.version==(0,0,0))
1524	def is_pro(self):
1525		return self.pro
1526	def has_feature(self,featureid):
1527		return True if (self.featuremask & (1<<featureid)) else False
1528	def sort_ver(self):
1529		sortver = "%05u_%03u_%03u" % self.version
1530		if self.pro==1:
1531			sortver += "_2"
1532		elif self.pro==0:
1533			sortver += "_1"
1534		else:
1535			sortver += "_0"
1536		return sortver
1537
1538class ExportsEntry:
1539	def __init__(self,fip1,fip2,fip3,fip4,tip1,tip2,tip3,tip4,path,meta,v1,v2,v3,exportflags,sesflags,umaskval,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime,disables):
1540		self.ipfrom = (fip1,fip2,fip3,fip4)
1541		self.ipto = (tip1,tip2,tip3,tip4)
1542		self.version = (v1,v2,v3)
1543		self.stripfrom = "%u.%u.%u.%u" % (fip1,fip2,fip3,fip4)
1544		self.sortipfrom = "%03u_%03u_%03u_%03u" % (fip1,fip2,fip3,fip4)
1545		self.stripto = "%u.%u.%u.%u" % (tip1,tip2,tip3,tip4)
1546		self.sortipto = "%03u_%03u_%03u_%03u" % (tip1,tip2,tip3,tip4)
1547		self.strver,self.sortver = version_str_and_sort((v1,v2,v3))
1548		self.meta = meta
1549		self.path = path
1550		self.exportflags = exportflags
1551		self.sesflags = sesflags
1552		self.umaskval = umaskval
1553		self.rootuid = rootuid
1554		self.rootgid = rootgid
1555		self.mapalluid = mapalluid
1556		self.mapallgid = mapallgid
1557		self.mingoal = mingoal
1558		self.maxgoal = maxgoal
1559		self.mintrashtime = mintrashtime
1560		self.maxtrashtime = maxtrashtime
1561		self.disables = disables
1562
1563
1564class Session:
1565	def __init__(self,sessionid,ip1,ip2,ip3,ip4,info,openfiles,nsocks,expire,v1,v2,v3,meta,path,sesflags,umaskval,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime,disables,stats_c,stats_l):
1566		self.ip = (ip1,ip2,ip3,ip4)
1567		self.version = (v1,v2,v3)
1568		self.strip = "%u.%u.%u.%u" % (ip1,ip2,ip3,ip4)
1569		self.sortip = "%03u_%03u_%03u_%03u" % (ip1,ip2,ip3,ip4)
1570		self.strver,self.sortver = version_str_and_sort((v1,v2,v3))
1571		self.host = resolve(self.strip)
1572		self.sessionid = sessionid
1573		self.info = info
1574		self.openfiles = openfiles
1575		self.nsocks = nsocks
1576		self.expire = expire
1577		self.meta = meta
1578		self.path = path
1579		self.sesflags = sesflags
1580		self.umaskval = umaskval
1581		self.rootuid = rootuid
1582		self.rootgid = rootgid
1583		self.mapalluid = mapalluid
1584		self.mapallgid = mapallgid
1585		self.mingoal = mingoal
1586		self.maxgoal = maxgoal
1587		self.mintrashtime = mintrashtime
1588		self.maxtrashtime = maxtrashtime
1589		self.disables = disables
1590		self.stats_c = stats_c
1591		self.stats_l = stats_l
1592
1593
1594class ChunkServer:
1595	def __init__(self,ip1,ip2,ip3,ip4,port,csid,v1,v2,v3,flags,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime,labels,mfrstatus):
1596		self.ip = (ip1,ip2,ip3,ip4)
1597		self.version = (v1,v2,v3)
1598		self.strip = "%u.%u.%u.%u" % (ip1,ip2,ip3,ip4)
1599		self.sortip = "%03u_%03u_%03u_%03u" % (ip1,ip2,ip3,ip4)
1600		self.strver,self.sortver = version_str_and_sort((v1,v2,v3))
1601		self.host = resolve(self.strip)
1602		self.port = port
1603		self.csid = csid
1604		self.flags = flags
1605		self.used = used
1606		self.total = total
1607		self.chunks = chunks
1608		self.tdused = tdused
1609		self.tdtotal = tdtotal
1610		self.tdchunks = tdchunks
1611		self.errcnt = errcnt
1612		self.load = load
1613		self.gracetime = gracetime
1614		self.labels = labels
1615		self.mfrstatus = mfrstatus
1616
1617
1618class DataProvider:
1619	def __init__(self,masterconn):
1620		self.masterconn = masterconn
1621		self.sessions = None
1622		self.chunkservers = None
1623		self.exports = None
1624	def get_exports(self):
1625		if self.exports==None:
1626			self.exports=[]
1627			if self.masterconn.has_feature(FEATURE_EXPORT_DISABLES):
1628				data,length = masterconn.command(CLTOMA_EXPORTS_INFO,MATOCL_EXPORTS_INFO,struct.pack(">B",3))
1629			elif self.masterconn.has_feature(FEATURE_EXPORT_UMASK):
1630				data,length = masterconn.command(CLTOMA_EXPORTS_INFO,MATOCL_EXPORTS_INFO,struct.pack(">B",2))
1631			elif self.masterconn.version_at_least(1,6,26):
1632				data,length = masterconn.command(CLTOMA_EXPORTS_INFO,MATOCL_EXPORTS_INFO,struct.pack(">B",1))
1633			else:
1634				data,length = masterconn.command(CLTOMA_EXPORTS_INFO,MATOCL_EXPORTS_INFO)
1635			pos = 0
1636			while pos<length:
1637				fip1,fip2,fip3,fip4,tip1,tip2,tip3,tip4,pleng = struct.unpack(">BBBBBBBBL",data[pos:pos+12])
1638				pos+=12
1639				path = data[pos:pos+pleng]
1640				path = path.decode('utf-8','replace')
1641				pos+=pleng
1642				if self.masterconn.has_feature(FEATURE_EXPORT_DISABLES):
1643					v1,v2,v3,exportflags,sesflags,umaskval,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime,disables = struct.unpack(">HBBBBHLLLLBBLLL",data[pos:pos+38])
1644					pos+=38
1645					if mingoal<=1 and maxgoal>=9:
1646						mingoal = None
1647						maxgoal = None
1648					if mintrashtime==0 and maxtrashtime==0xFFFFFFFF:
1649						mintrashtime = None
1650						maxtrashtime = None
1651				elif self.masterconn.has_feature(FEATURE_EXPORT_UMASK):
1652					v1,v2,v3,exportflags,sesflags,umaskval,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime = struct.unpack(">HBBBBHLLLLBBLL",data[pos:pos+34])
1653					pos+=34
1654					disables = 0
1655					if mingoal<=1 and maxgoal>=9:
1656						mingoal = None
1657						maxgoal = None
1658					if mintrashtime==0 and maxtrashtime==0xFFFFFFFF:
1659						mintrashtime = None
1660						maxtrashtime = None
1661				elif self.masterconn.version_at_least(1,6,26):
1662					v1,v2,v3,exportflags,sesflags,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime = struct.unpack(">HBBBBLLLLBBLL",data[pos:pos+32])
1663					pos+=32
1664					disables = 0
1665					if mingoal<=1 and maxgoal>=9:
1666						mingoal = None
1667						maxgoal = None
1668					if mintrashtime==0 and maxtrashtime==0xFFFFFFFF:
1669						mintrashtime = None
1670						maxtrashtime = None
1671					umaskval = None
1672				else:
1673					v1,v2,v3,exportflags,sesflags,rootuid,rootgid,mapalluid,mapallgid = struct.unpack(">HBBBBLLLL",data[pos:pos+22])
1674					pos+=22
1675					disables = 0
1676					mingoal = None
1677					maxgoal = None
1678					mintrashtime = None
1679					maxtrashtime = None
1680					umaskval = None
1681				if path=='.':
1682					meta = 1
1683					umaskval = None
1684					disables = 0
1685				else:
1686					meta = 0
1687				expent = ExportsEntry(fip1,fip2,fip3,fip4,tip1,tip2,tip3,tip4,path,meta,v1,v2,v3,exportflags,sesflags,umaskval,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime,disables)
1688				self.exports.append(expent)
1689		return self.exports
1690	def get_sessions(self):
1691		if self.sessions==None:
1692			self.sessions=[]
1693			if self.masterconn.has_feature(FEATURE_EXPORT_DISABLES):
1694				data,length = self.masterconn.command(CLTOMA_SESSION_LIST,MATOCL_SESSION_LIST,struct.pack(">B",4))
1695			elif self.masterconn.has_feature(FEATURE_EXPORT_UMASK):
1696				data,length = self.masterconn.command(CLTOMA_SESSION_LIST,MATOCL_SESSION_LIST,struct.pack(">B",3))
1697			elif self.masterconn.version_at_least(1,7,8):
1698				data,length = self.masterconn.command(CLTOMA_SESSION_LIST,MATOCL_SESSION_LIST,struct.pack(">B",2))
1699			elif self.masterconn.version_at_least(1,6,26):
1700				data,length = self.masterconn.command(CLTOMA_SESSION_LIST,MATOCL_SESSION_LIST,struct.pack(">B",1))
1701			else:
1702				data,length = self.masterconn.command(CLTOMA_SESSION_LIST,MATOCL_SESSION_LIST)
1703			if self.masterconn.version_less_than(1,6,21):
1704				statscnt = 16
1705				pos = 0
1706			elif self.masterconn.version_is(1,6,21):
1707				statscnt = 21
1708				pos = 0
1709			else:
1710				statscnt = struct.unpack(">H",data[0:2])[0]
1711				pos = 2
1712			while pos<length:
1713				if self.masterconn.version_at_least(1,7,8):
1714					sessionid,ip1,ip2,ip3,ip4,v1,v2,v3,openfiles,nsocks,expire,ileng = struct.unpack(">LBBBBHBBLBLL",data[pos:pos+25])
1715					pos+=25
1716				else:
1717					sessionid,ip1,ip2,ip3,ip4,v1,v2,v3,ileng = struct.unpack(">LBBBBHBBL",data[pos:pos+16])
1718					pos+=16
1719					openfiles = 0
1720					nsocks = 1
1721					expire = 0
1722				info = data[pos:pos+ileng]
1723				pos+=ileng
1724				pleng = struct.unpack(">L",data[pos:pos+4])[0]
1725				pos+=4
1726				path = data[pos:pos+pleng]
1727				pos+=pleng
1728				info = info.decode('utf-8','replace')
1729				path = path.decode('utf-8','replace')
1730				if self.masterconn.has_feature(FEATURE_EXPORT_DISABLES):
1731					sesflags,umaskval,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime,disables = struct.unpack(">BHLLLLBBLLL",data[pos:pos+33])
1732					pos+=33
1733					if mingoal<=1 and maxgoal>=9:
1734						mingoal = None
1735						maxgoal = None
1736					if mintrashtime==0 and maxtrashtime==0xFFFFFFFF:
1737						mintrashtime = None
1738						maxtrashtime = None
1739				elif self.masterconn.has_feature(FEATURE_EXPORT_UMASK):
1740					sesflags,umaskval,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime = struct.unpack(">BHLLLLBBLL",data[pos:pos+29])
1741					pos+=29
1742					disables = 0
1743					if mingoal<=1 and maxgoal>=9:
1744						mingoal = None
1745						maxgoal = None
1746					if mintrashtime==0 and maxtrashtime==0xFFFFFFFF:
1747						mintrashtime = None
1748						maxtrashtime = None
1749				elif self.masterconn.version_at_least(1,6,26):
1750					sesflags,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime = struct.unpack(">BLLLLBBLL",data[pos:pos+27])
1751					pos+=27
1752					disables = 0
1753					if mingoal<=1 and maxgoal>=9:
1754						mingoal = None
1755						maxgoal = None
1756					if mintrashtime==0 and maxtrashtime==0xFFFFFFFF:
1757						mintrashtime = None
1758						maxtrashtime = None
1759					umaskval = None
1760				else:
1761					sesflags,rootuid,rootgid,mapalluid,mapallgid = struct.unpack(">BLLLL",data[pos:pos+17])
1762					pos+=17
1763					disables = 0
1764					mingoal = None
1765					maxgoal = None
1766					mintrashtime = None
1767					maxtrashtime = None
1768					umaskval = None
1769				if statscnt<16:
1770					stats_c = struct.unpack(">"+"L"*statscnt,data[pos:pos+4*statscnt])+(0,)*(16-statscnt)
1771					pos+=statscnt*4
1772					stats_l = struct.unpack(">"+"L"*statscnt,data[pos:pos+4*statscnt])+(0,)*(16-statscnt)
1773					pos+=statscnt*4
1774				else:
1775					stats_c = struct.unpack(">LLLLLLLLLLLLLLLL",data[pos:pos+64])
1776					pos+=statscnt*4
1777					stats_l = struct.unpack(">LLLLLLLLLLLLLLLL",data[pos:pos+64])
1778					pos+=statscnt*4
1779				if path=='.':
1780					meta=1
1781				else:
1782					meta=0
1783				ses = Session(sessionid,ip1,ip2,ip3,ip4,info,openfiles,nsocks,expire,v1,v2,v3,meta,path,sesflags,umaskval,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime,disables,stats_c,stats_l)
1784				self.sessions.append(ses)
1785		return self.sessions
1786	def get_chunkservers(self):
1787		if self.chunkservers==None:
1788			self.chunkservers=[]
1789			data,length = masterconn.command(CLTOMA_CSERV_LIST,MATOCL_CSERV_LIST)
1790			if masterconn.version_at_least(3,0,38) and (length%69)==0:
1791				n = length//69
1792				for i in range(n):
1793					d = data[i*69:(i+1)*69]
1794					flags,v1,v2,v3,ip1,ip2,ip3,ip4,port,csid,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime,labels,mfrstatus = struct.unpack(">BBBBBBBBHHQQLQQLLLLLB",d)
1795					cs = ChunkServer(ip1,ip2,ip3,ip4,port,csid,v1,v2,v3,flags,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime,labels,mfrstatus)
1796					self.chunkservers.append(cs)
1797			elif masterconn.version_at_least(2,1,0) and (length%68)==0:
1798				n = length//68
1799				for i in range(n):
1800					d = data[i*68:(i+1)*68]
1801					flags,v1,v2,v3,ip1,ip2,ip3,ip4,port,csid,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime,labels = struct.unpack(">BBBBBBBBHHQQLQQLLLLL",d)
1802					cs = ChunkServer(ip1,ip2,ip3,ip4,port,csid,v1,v2,v3,flags,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime,labels,None)
1803					self.chunkservers.append(cs)
1804			elif masterconn.version_at_least(1,7,25) and masterconn.version_less_than(2,1,0) and (length%64)==0:
1805				n = length//64
1806				for i in range(n):
1807					d = data[i*64:(i+1)*64]
1808					flags,v1,v2,v3,ip1,ip2,ip3,ip4,port,csid,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime = struct.unpack(">BBBBBBBBHHQQLQQLLLL",d)
1809					cs = ChunkServer(ip1,ip2,ip3,ip4,port,csid,v1,v2,v3,flags,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime,None,None)
1810					self.chunkservers.append(cs)
1811			elif masterconn.version_at_least(1,6,28) and masterconn.version_less_than(1,7,25) and (length%62)==0:
1812				n = length//62
1813				for i in range(n):
1814					d = data[i*62:(i+1)*62]
1815					disconnected,v1,v2,v3,ip1,ip2,ip3,ip4,port,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime = struct.unpack(">BBBBBBBBHQQLQQLLLL",d)
1816					cs = ChunkServer(ip1,ip2,ip3,ip4,port,csid,v1,v2,v3,1 if disconnected else 0,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime,None,None)
1817					self.chunkservers.append(cs)
1818			elif masterconn.version_less_than(1,6,28) and (length%54)==0:
1819				n = length//54
1820				for i in range(n):
1821					d = data[i*54:(i+1)*54]
1822					disconnected,v1,v2,v3,ip1,ip2,ip3,ip4,port,used,total,chunks,tdused,tdtotal,tdchunks,errcnt = struct.unpack(">BBBBBBBBHQQLQQLL",d)
1823					cs = ChunkServer(ip1,ip2,ip3,ip4,port,None,v1,v2,v3,1 if disconnected else 0,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,None,None,None,None)
1824					self.chunkservers.append(cs)
1825		return self.chunkservers
1826
1827
1828def resolve_inodes_paths(masterconn,inodes):
1829	inodepaths = {}
1830	if len(inodes)>0:
1831		data,length = masterconn.command(CLTOMA_MASS_RESOLVE_PATHS,MATOCL_MASS_RESOLVE_PATHS,struct.pack(">"+len(inodes)*"L",*inodes))
1832		pos = 0
1833		while pos+8<=length:
1834			inode,psize = struct.unpack(">LL",data[pos:pos+8])
1835			pos+=8
1836			if psize == 0:
1837				if inode not in inodepaths:
1838					inodepaths[inode] = []
1839				inodepaths[inode].append("./META")
1840			elif pos + psize <= length:
1841				while psize>=4:
1842					pleng = struct.unpack(">L",data[pos:pos+4])[0]
1843					pos+=4
1844					psize-=4
1845					path = data[pos:pos+pleng]
1846					pos+=pleng
1847					psize-=pleng
1848					path = path.decode('utf-8','replace')
1849					if inode not in inodepaths:
1850						inodepaths[inode] = []
1851					inodepaths[inode].append(path)
1852				if psize!=0:
1853					raise RuntimeError("MFS packet malformed")
1854		if pos!=length:
1855			raise RuntimeError("MFS packet malformed")
1856	return inodepaths
1857
1858
1859# find leader
1860leaderispro = 0
1861leaderfound = 0
1862leader_exports_checksum = None
1863leader_usectime = None
1864followerfound = 0
1865electfound = 0
1866leaderconn = None
1867electconn = None
1868electinfo = None
1869elect_exports_checksum = None
1870dataprovider = None
1871leaderinfo = None
1872masterlist = getmasteraddresses()
1873masterlistver = []
1874masterlistinfo = []
1875
1876for mhost,mport in masterlist:
1877	conn = None
1878	version = (0,0,0)
1879	statestr = "???"
1880	statecolor = 1
1881	memusage = 0
1882	syscpu = 0
1883	usercpu = 0
1884	lastsuccessfulstore = 0
1885	lastsaveseconds = 0
1886	lastsavestatus = 0
1887	metaversion = 0
1888	exports_checksum = None
1889	usectime = None
1890	chlogtime = 0
1891	try:
1892		conn = Master(mhost,mport)
1893		try:
1894			data,length = conn.command(CLTOMA_INFO,MATOCL_INFO)
1895			if length==52:
1896				version = (1,4,0)
1897				conn.set_version(version)
1898				if leaderfound==0:
1899					leaderconn = conn
1900					leaderinfo = data
1901					leaderfound = 1
1902				statestr = "OLD MASTER (LEADER ONLY)"
1903				statecolor = 0
1904			elif length==60:
1905				version = (1,5,0)
1906				conn.set_version(version)
1907				if leaderfound==0:
1908					leaderconn = conn
1909					leaderinfo = data
1910					leaderfound = 1
1911				statestr = "OLD MASTER (LEADER ONLY)"
1912				statecolor = 0
1913			elif length==68 or length==76 or length==101:
1914				version = struct.unpack(">HBB",data[:4])
1915				conn.set_version(version)
1916				if leaderfound==0 and version<(1,7,0):
1917					leaderconn = conn
1918					leaderinfo = data
1919					leaderfound = 1
1920				if length==76:
1921					memusage = struct.unpack(">Q",data[4:12])[0]
1922				if length==101:
1923					memusage,syscpu,usercpu = struct.unpack(">QQQ",data[4:28])
1924					syscpu/=10000000.0
1925					usercpu/=10000000.0
1926					lastsuccessfulstore,lastsaveseconds,lastsavestatus = struct.unpack(">LLB",data[92:101])
1927				if version<(1,7,0):
1928					statestr = "OLD MASTER (LEADER ONLY)"
1929					statecolor = 0
1930				else:
1931					statestr = "UPGRADE THIS UNIT !!!"
1932					statecolor = 2
1933			elif length==121 or length==129 or length==137 or length==149:
1934				offset = 8 if (length==137 or length==149) else 0
1935				version = struct.unpack(">HBB",data[:4])
1936				conn.set_version(version)
1937				memusage,syscpu,usercpu = struct.unpack(">QQQ",data[4:28])
1938				syscpu/=10000000.0
1939				usercpu/=10000000.0
1940				lastsuccessfulstore,lastsaveseconds,lastsavestatus = struct.unpack(">LLB",data[offset+92:offset+101])
1941				if conn.version_at_least(2,0,14):
1942					lastsaveseconds = lastsaveseconds / 1000.0
1943				workingstate,nextstate,stablestate,sync,leaderip,changetime,metaversion = struct.unpack(">BBBBLLQ",data[offset+101:offset+121])
1944				if length>=129:
1945					exports_checksum = struct.unpack(">Q",data[offset+121:offset+129])[0]
1946				if length==149:
1947					usectime,chlogtime = struct.unpack(">QL",data[length-12:length])
1948				if workingstate==0xFF and nextstate==0xFF and stablestate==0xFF and sync==0xFF:
1949					if leaderfound==0:
1950						leaderconn = conn
1951						leaderinfo = data
1952						leaderfound = 1
1953						leader_exports_checksum = exports_checksum
1954						leader_usectime = usectime
1955					statestr = "-"
1956					statecolor = 0
1957				elif stablestate==0 or workingstate!=nextstate:
1958					statestr = "transition %s -> %s" % (state_name(workingstate),state_name(nextstate))
1959					statecolor = 8
1960				else:
1961					statestr = state_name(workingstate)
1962					statecolor = state_color(workingstate,sync)
1963					if workingstate==STATE_FOLLOWER or workingstate==STATE_USURPER:
1964						if sync==0:
1965							statestr += " (DESYNC)"
1966						followerfound = 1
1967						followerconn = conn
1968						followerinfo = data
1969						follower_exports_checksum = exports_checksum
1970					if workingstate==STATE_ELECT and electfound==0:
1971						electfound = 1
1972						electconn = conn
1973						electinfo = data
1974						elect_exports_checksum = exports_checksum
1975					if workingstate==STATE_LEADER and leaderfound==0:
1976						leaderispro = 1
1977						leaderconn = conn
1978						leaderinfo = data
1979						leaderfound = 1
1980						leader_exports_checksum = exports_checksum
1981						leader_usectime = usectime
1982		except Exception:
1983			statestr = "BUSY"
1984			statecolor = 7
1985	except Exception:
1986		statestr = "DEAD"
1987	try:
1988		iptab = tuple(map(int,mhost.split('.')))
1989		strip = "%u.%u.%u.%u" % iptab
1990		sortip = "%03u_%03u_%03u_%03u" % iptab
1991	except Exception:
1992		strip = mhost
1993		sortip = mhost
1994	strver,sortver = version_str_and_sort(version)
1995	if conn and conn!=leaderconn and conn!=electconn:
1996		del conn
1997	masterlistver.append((mhost,mport,version))
1998	masterlistinfo.append((sortip,strip,sortver,strver,statestr,statecolor,metaversion,memusage,syscpu,usercpu,lastsuccessfulstore,lastsaveseconds,lastsavestatus,exports_checksum,usectime,chlogtime))
1999
2000if leaderfound:
2001	masterconn = leaderconn
2002	masterinfo = leaderinfo
2003	masterispro = leaderispro
2004	master_exports_checksum = leader_exports_checksum
2005elif electfound:
2006	masterconn = electconn
2007	masterinfo = electinfo
2008	masterispro = 1
2009	master_exports_checksum = elect_exports_checksum
2010elif followerfound:
2011	masterconn = followerconn
2012	masterinfo = followerinfo
2013	masterispro = 1
2014	master_exports_checksum = follower_exports_checksum
2015else:
2016	masterconn = None
2017	master_exports_checksum = 0
2018	for sortip,strip,sortver,strver,statestr,statecolor,metaversion,memusage,syscpu,usercpu,lastsuccessfulstore,lastsaveseconds,lastsavestatus,exports_checksum,usectime,chlogtime in masterlistinfo:
2019		if exports_checksum!=None:
2020			master_exports_checksum |= exports_checksum
2021
2022master_minusectime = None
2023master_maxusectime = None
2024if leader_usectime==None or leader_usectime==0:
2025	for sortip,strip,sortver,strver,statestr,statecolor,metaversion,memusage,syscpu,usercpu,lastsuccessfulstore,lastsaveseconds,lastsavestatus,exportschecksum,usectime,chlogtime in masterlistinfo:
2026		if usectime!=None and usectime>0:
2027			if master_minusectime==None or usectime<master_minusectime:
2028				master_minusectime = usectime
2029			if master_maxusectime==None or usectime>master_maxusectime:
2030				master_maxusectime = usectime
2031
2032if leaderfound and masterconn.version_less_than(1,6,10):
2033	if cgimode:
2034		print("Content-Type: text/html; charset=UTF-8")
2035		print("")
2036		print("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">""")
2037		print("""<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">""")
2038		print("""<head>""")
2039		print("""<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />""")
2040		print("""<title>MFS Info (%s)</title>""" % (htmlentities(mastername)))
2041		print("""<link rel="stylesheet" href="mfs.css" type="text/css" />""")
2042		print("""</head>""")
2043		print("""<body>""")
2044		if masterconn.version_unknown():
2045			print("""<h1 align="center">Can't detect MFS master version</h1>""")
2046		else:
2047			print("""<h1 align="center">MFS master version not supported (pre 1.6.10)</h1>""")
2048		print("""</body>""")
2049		print("""</html>""")
2050	else:
2051		if masterconn.version_unknown():
2052			print("""Can't detect MFS master version""")
2053		else:
2054			print("""MFS master version not supported (pre 1.6.10)""")
2055	sys.exit(1)
2056
2057
2058dataprovider = DataProvider(masterconn)
2059
2060# commands
2061if cgimode:
2062	# commands in CGI mode
2063	cmd_success = -1
2064	if "CSremove" in fields:
2065		cmd_success = 0
2066		tracedata = ""
2067		if leaderfound:
2068			try:
2069				serverdata = fields.getvalue("CSremove").split(":")
2070				if len(serverdata)==2:
2071					csip = list(map(int,serverdata[0].split(".")))
2072					csport = int(serverdata[1])
2073					if len(csip)==4:
2074						if masterconn.version_less_than(1,6,28):
2075							data,length = masterconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBH",csip[0],csip[1],csip[2],csip[3],csport))
2076							if length==0:
2077								cmd_success = 1
2078								status = 0
2079						else:
2080							data,length = masterconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_REMOVE,csip[0],csip[1],csip[2],csip[3],csport))
2081							if length==1:
2082								status = (struct.unpack(">B",data))[0]
2083								cmd_success = 1
2084			except Exception:
2085				tracedata = traceback.format_exc()
2086		url = createjslink({"CSremove":""})
2087	elif "CSbacktowork" in fields:
2088		cmd_success = 0
2089		tracedata = ""
2090		if leaderfound and masterconn.version_at_least(1,6,28):
2091			try:
2092				serverdata = fields.getvalue("CSbacktowork").split(":")
2093				if len(serverdata)==2:
2094					csip = list(map(int,serverdata[0].split(".")))
2095					csport = int(serverdata[1])
2096					if len(csip)==4:
2097						data,length = masterconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_BACKTOWORK,csip[0],csip[1],csip[2],csip[3],csport))
2098						if length==1:
2099							status = (struct.unpack(">B",data))[0]
2100							cmd_success = 1
2101			except Exception:
2102				tracedata = traceback.format_exc()
2103		url = createjslink({"CSbacktowork":""})
2104	elif "CSmaintenanceon" in fields:
2105		cmd_success = 0
2106		tracedata = ""
2107		if leaderfound and masterconn.version_at_least(2,0,11):
2108			try:
2109				serverdata = fields.getvalue("CSmaintenanceon").split(":")
2110				if len(serverdata)==2:
2111					csip = list(map(int,serverdata[0].split(".")))
2112					csport = int(serverdata[1])
2113					if len(csip)==4:
2114						data,length = masterconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_MAINTENANCEON,csip[0],csip[1],csip[2],csip[3],csport))
2115						if length==1:
2116							status = (struct.unpack(">B",data))[0]
2117							cmd_success = 1
2118			except Exception:
2119				tracedata = traceback.format_exc()
2120		url = createjslink({"CSmaintenanceon":""})
2121	elif "CSmaintenanceoff" in fields:
2122		cmd_success = 0
2123		tracedata = ""
2124		if leaderfound and masterconn.version_at_least(2,0,11):
2125			try:
2126				serverdata = fields.getvalue("CSmaintenanceoff").split(":")
2127				if len(serverdata)==2:
2128					csip = list(map(int,serverdata[0].split(".")))
2129					csport = int(serverdata[1])
2130					if len(csip)==4:
2131						data,length = masterconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_MAINTENANCEOFF,csip[0],csip[1],csip[2],csip[3],csport))
2132						if length==1:
2133							status = (struct.unpack(">B",data))[0]
2134							cmd_success = 1
2135			except Exception:
2136				tracedata = traceback.format_exc()
2137		url = createjslink({"CSmaintenanceoff":""})
2138	elif "MSremove" in fields:
2139		cmd_success = 0
2140		tracedata = ""
2141		if leaderfound:
2142			try:
2143				sessionid = int(fields.getvalue("MSremove"))
2144				data,length = masterconn.command(CLTOMA_SESSION_COMMAND,MATOCL_SESSION_COMMAND,struct.pack(">BL",MFS_SESSION_COMMAND_REMOVE,sessionid))
2145				if length==1:
2146					status = (struct.unpack(">B",data))[0]
2147					cmd_success = 1
2148			except Exception:
2149				tracedata = traceback.format_exc()
2150		url = createjslink({"MSremove":""})
2151	if cmd_success==1:
2152		print("Status: 302 Found")
2153		print("Location: %s" % url)
2154		print("Content-Type: text/html; charset=UTF-8")
2155		print("")
2156		print("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">""")
2157		print("""<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">""")
2158		print("""<head>""")
2159		print("""<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />""")
2160		print("""<meta http-equiv="Refresh" content="0; url=%s" />""" % url.replace('&','&amp;'))
2161		print("""<title>MFS Info (%s)</title>""" % (htmlentities(mastername)))
2162		print("""<link rel="stylesheet" href="mfs.css" type="text/css" />""")
2163		print("""</head>""")
2164		print("""<body>""")
2165		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)
2166		print("""</body>""")
2167		print("""</html>""")
2168		sys.exit(0)
2169	elif cmd_success==0:
2170		print("Content-Type: text/html; charset=UTF-8")
2171		print("")
2172		print("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">""")
2173		print("""<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">""")
2174		print("""<head>""")
2175		print("""<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />""")
2176		print("""<meta http-equiv="Refresh" content="5; url=%s" />""" % url.replace('&','&amp;'))
2177		print("""<title>MFS Info (%s)</title>""" % (htmlentities(mastername)))
2178		print("""<link rel="stylesheet" href="mfs.css" type="text/css" />""")
2179		print("""</head>""")
2180		print("""<body>""")
2181		print("""<h3 align="center">Can't perform command - wait 5 seconds for refresh</h3>""")
2182		if tracedata:
2183			print("""<hr />""")
2184			print("""<pre>%s</pre>""" % tracedata)
2185		print("""</body>""")
2186		print("""</html>""")
2187		sys.exit(0)
2188else:
2189	if leaderfound:
2190		for cmd in clicommands:
2191			cmddata = cmd.split('/')
2192			if cmddata[0]=='RC':
2193				cmd_success = 0
2194				try:
2195					csip = list(map(int,cmddata[1].split(".")))
2196					csport = int(cmddata[2])
2197					if len(csip)==4:
2198						if masterconn.version_less_than(1,6,28):
2199							data,length = masterconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBH",csip[0],csip[1],csip[2],csip[3],csport))
2200							if length==0:
2201								cmd_success = 1
2202								status = 0
2203						else:
2204							data,length = masterconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_REMOVE,csip[0],csip[1],csip[2],csip[3],csport))
2205							if length==1:
2206								status = (struct.unpack(">B",data))[0]
2207								cmd_success = 1
2208					if cmd_success:
2209						if status==STATUS_OK:
2210							print("Chunkserver %s/%s has been removed" % (cmddata[1],cmddata[2]))
2211						elif status==ERROR_NOTFOUND:
2212							print("Chunkserver %s/%s hasn't been found" % (cmddata[1],cmddata[2]))
2213						elif status==ERROR_ACTIVE:
2214							print("Chunkserver %s/%s can't be removed because is still active" % (cmddata[1],cmddata[2]))
2215						else:
2216							print("Can't remove chunkserver %s/%s (status:%u)" % (cmddata[1],cmddata[2],status))
2217					else:
2218						print("Can't remove chunkserver %s/%s" % (cmddata[1],cmddata[2]))
2219				except Exception:
2220					print_exception()
2221			if cmddata[0]=='BW':
2222				cmd_success = 0
2223				try:
2224					csip = list(map(int,cmddata[1].split(".")))
2225					csport = int(cmddata[2])
2226					if len(csip)==4:
2227						if masterconn.version_at_least(1,6,28):
2228							data,length = masterconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_BACKTOWORK,csip[0],csip[1],csip[2],csip[3],csport))
2229							if length==1:
2230								status = (struct.unpack(">B",data))[0]
2231								cmd_success = 1
2232					if cmd_success:
2233						if status==STATUS_OK:
2234							print("Chunkserver %s/%s has back to work" % (cmddata[1],cmddata[2]))
2235						elif status==ERROR_NOTFOUND:
2236							print("Chunkserver %s/%s hasn't been found" % (cmddata[1],cmddata[2]))
2237						else:
2238							print("Can't turn chunkserver %s/%s back to work (status:%u)" % (cmddata[1],cmddata[2],status))
2239					else:
2240						print("Can't turn chunkserver %s/%s back to work" % (cmddata[1],cmddata[2]))
2241				except Exception:
2242					print_exception()
2243			if cmddata[0]=='M1':
2244				cmd_success = 0
2245				try:
2246					csip = list(map(int,cmddata[1].split(".")))
2247					csport = int(cmddata[2])
2248					if len(csip)==4:
2249						if masterconn.version_at_least(2,0,11):
2250							data,length = masterconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_MAINTENANCEON,csip[0],csip[1],csip[2],csip[3],csport))
2251							if length==1:
2252								status = (struct.unpack(">B",data))[0]
2253								cmd_success = 1
2254					if cmd_success:
2255						if status==STATUS_OK:
2256							print("Chunkserver %s/%s has been switched to maintenance mode" % (cmddata[1],cmddata[2]))
2257						elif status==ERROR_NOTFOUND:
2258							print("Chunkserver %s/%s hasn't been found" % (cmddata[1],cmddata[2]))
2259						else:
2260							print("Can't switch chunkserver %s/%s to maintenance mode (status:%u)" % (cmddata[1],cmddata[2],status))
2261					else:
2262						print("Can't switch chunkserver %s/%s to maintenance mode" % (cmddata[1],cmddata[2]))
2263				except Exception:
2264					print_exception()
2265			if cmddata[0]=='M0':
2266				cmd_success = 0
2267				try:
2268					csip = list(map(int,cmddata[1].split(".")))
2269					csport = int(cmddata[2])
2270					if len(csip)==4:
2271						if masterconn.version_at_least(2,0,11):
2272							data,length = masterconn.command(CLTOMA_CSSERV_COMMAND,MATOCL_CSSERV_COMMAND,struct.pack(">BBBBBH",MFS_CSSERV_COMMAND_MAINTENANCEOFF,csip[0],csip[1],csip[2],csip[3],csport))
2273							if length==1:
2274								status = (struct.unpack(">B",data))[0]
2275								cmd_success = 1
2276					if cmd_success:
2277						if status==STATUS_OK:
2278							print("Chunkserver %s/%s has been switched to standard mode" % (cmddata[1],cmddata[2]))
2279						elif status==ERROR_NOTFOUND:
2280							print("Chunkserver %s/%s hasn't been found" % (cmddata[1],cmddata[2]))
2281						else:
2282							print("Can't switch chunkserver %s/%s to standard mode (status:%u)" % (cmddata[1],cmddata[2],status))
2283					else:
2284						print("Can't switch chunkserver %s/%s to standard mode" % (cmddata[1],cmddata[2]))
2285				except Exception:
2286					print_exception()
2287			if cmddata[0]=='RS':
2288				cmd_success = 0
2289				try:
2290					sessionid = int(cmddata[1])
2291					data,length = masterconn.command(CLTOMA_SESSION_COMMAND,MATOCL_SESSION_COMMAND,struct.pack(">BL",MFS_SESSION_COMMAND_REMOVE,sessionid))
2292					if length==1:
2293						status = (struct.unpack(">B",data))[0]
2294						cmd_success = 1
2295					if cmd_success:
2296						if status==STATUS_OK:
2297							print("Session %u has been removed" % (sessionid))
2298						elif status==ERROR_NOTFOUND:
2299							print("Session %u hasn't been found" % (sessionid))
2300						elif status==ERROR_ACTIVE:
2301							print("Session %u can't be removed because is still active" % (sessionid))
2302						else:
2303							print("Can't remove session %u (status:%u)" % (sessionid,status))
2304					else:
2305						print("Can't remove session %u" % (sessionid))
2306				except Exception:
2307					print_exception()
2308	elif len(clicommands)>0:
2309		print("Can't perform any operation because there is no leading master")
2310
2311if cgimode:
2312	if "sections" in fields:
2313		sectionstr = fields.getvalue("sections")
2314		sectionset = set(sectionstr.split("|"))
2315	else:
2316		sectionset = set(("IN",))
2317	if "subsections" in fields:
2318		subsectionstr = fields.getvalue("subsections")
2319		sectionsubset = set(subsectionstr.split("|"))
2320	else:
2321		sectionsubset = ["IM","LI","IG","MU","IC","IL","MF","CS","MB","SC","OF","AL"] # used only in climode - in cgimode turn on all subsections
2322
2323	if leaderfound:
2324		if masterconn.version_less_than(1,7,0):
2325			sectiondef={
2326				"IN":"Info",
2327				"CS":"Servers",
2328				"HD":"Disks",
2329				"EX":"Exports",
2330				"MS":"Mounts",
2331				"MO":"Operations",
2332				"MC":"Master Charts",
2333				"CC":"Server Charts"
2334			}
2335			sectionorder=["IN","CS","HD","EX","MS","MO","MC","CC"]
2336		elif masterconn.version_less_than(2,1,0):
2337			sectiondef={
2338				"IN":"Info",
2339				"CS":"Servers",
2340				"HD":"Disks",
2341				"EX":"Exports",
2342				"MS":"Mounts",
2343				"MO":"Operations",
2344				"QU":"Quotas",
2345				"MC":"Master Charts",
2346				"CC":"Server Charts"
2347			}
2348			sectionorder=["IN","CS","HD","EX","MS","MO","QU","MC","CC"]
2349		else:
2350			sectiondef={
2351				"IN":"Info",
2352				"CS":"Servers",
2353				"HD":"Disks",
2354				"EX":"Exports",
2355				"MS":"Mounts",
2356				"MO":"Operations",
2357				"RS":"Resources",
2358				"QU":"Quotas",
2359				"MC":"Master Charts",
2360				"CC":"Server Charts"
2361			}
2362			sectionorder=["IN","CS","HD","EX","MS","MO","RS","QU","MC","CC"]
2363	elif electfound:
2364		sectiondef = {
2365			"IN":"Info",
2366			"CS":"Servers",
2367			"HD":"Disks",
2368			"EX":"Exports",
2369			"QU":"Quotas",
2370			"MC":"Master Charts",
2371			"CC":"Server Charts"
2372		}
2373		sectionorder=["IN","CS","HD","EX","QU","MC","CC"]
2374	elif followerfound:
2375		sectiondef = {
2376			"IN":"Info",
2377			"MC":"Master Charts"
2378		}
2379		sectionorder=["IN","MC"]
2380	else:
2381		sectiondef = {
2382			"IN":"Info"
2383		}
2384		sectionorder=["IN"]
2385
2386	print("Content-Type: text/html; charset=UTF-8")
2387	print("")
2388	# print """<!-- Put IE into quirks mode -->
2389	print("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">""")
2390	print("""<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">""")
2391	print("""<head>""")
2392	print("""<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />""")
2393	print("""<title>MFS Info (%s)</title>""" % (htmlentities(mastername)))
2394	print("""<link rel="stylesheet" href="mfs.css" type="text/css" />""")
2395	print("""<script src="acidtab.js" type="text/javascript"></script>""")
2396	print("""</head>""")
2397	print("""<body>""")
2398
2399	#MENUBAR
2400	print("""<div id="header">""")
2401	print("""<table class="HDR" cellpadding="0" cellspacing="0" border="0">""")
2402	print("""<tr>""")
2403	print("""<td class="LOGO"><a href="http://moosefs.com"><img src="logomini.png" alt="logo" style="border:0;width:100px;height:47px" /></a></td>""")
2404	print("""<td class="MENU"><table class="MENU" cellspacing="0">""")
2405	print("""<tr>""")
2406	last="U"
2407	for k in sectionorder:
2408		if k==sectionorder[-1]:
2409			last = "L%s" % last
2410		if k in sectionset:
2411			if len(sectionset)<=1:
2412				print("""<td class="%sS">%s &#8722;</td>""" % (last,sectiondef[k]))
2413			else:
2414				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]))})))
2415			last="S"
2416		else:
2417			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]))})))
2418			last="U"
2419	print("""</tr>""")
2420	print("""</table></td>""")
2421	print("""<td class="FILLER" style="white-space:nowrap;">""")
2422	print("""CGI version: %s ; python: %u.%u<br />""" % (VERSION,sys.version_info[0],sys.version_info[1]))
2423	print("""date: %s""" % time.strftime("%Y-%m-%d %H:%M:%S %Z",time.localtime(time.time())))
2424	print("""</td>""")
2425	print("""</tr>""")
2426	print("""</table>""")
2427	print("""</div>""")
2428
2429	#print """<div id="footer">
2430	#Moose File System by Jakub Kruszona-Zawadzki
2431	#</div>
2432	#"""
2433
2434	print("""<div id="container">""")
2435
2436if leaderfound==0:
2437	if cgimode:
2438		out = []
2439		out.append("""<table class="FR" cellspacing="0">""")
2440		if len(masterlist)==0:
2441			out.append("""	<tr>""")
2442			out.append("""		<td align="center">""")
2443			out.append("""			<span class="ERROR">Can't find masters (resolve given name) !!!</span><br />""")
2444			out.append("""			<form method="GET">""")
2445			out.append("""				Input your DNS master name: <input type="text" name="masterhost" value="%s" size="100">""" % (masterhost))
2446			for i in createinputs(["masterhost"]):
2447				out.append("""				%s""" % (i))
2448			out.append("""				<input type="submit" value="Try it !!!">""")
2449			out.append("""			</form>""")
2450			out.append("""		</td>""")
2451			out.append("""	</tr>""")
2452		elif electfound:
2453			out.append("""	<tr>""")
2454			out.append("""		<td align="center">""")
2455			out.append("""			<span class="ERROR">Leader master server not found, but there is an elect, so make sure that all chunkservers are running - elect should become a leader soon</span><br />""")
2456			out.append("""		</td>""")
2457			out.append("""	</tr>""")
2458		else:
2459			out.append("""	<tr>""")
2460			out.append("""		<td align="center">""")
2461			out.append("""			<span class="ERROR">Can't find working masters !!!</span><br />""")
2462			out.append("""			<form method="GET">""")
2463			out.append("""				Input your DNS master name: <input type="text" name="masterhost" value="%s" size="100"><br />""" % (masterhost))
2464			out.append("""				Input your master-client port number: <input type="text" name="masterport" value="%u" size="5"><br />""" % (masterport))
2465			out.append("""				Input your master-control port number: <input type="text" name="mastercontrolport" value="%u" size="5"><br />""" % (mastercontrolport))
2466			for i in createinputs(["masterhost","masterport","mastercontrolport"]):
2467				out.append("""				%s""" % (i))
2468			out.append("""				<input type="submit" value="Try it !!!">""")
2469			out.append("""			</form>""")
2470			out.append("""		</td>""")
2471			out.append("""	</tr>""")
2472		out.append("""</table>""")
2473		print("\n".join(out))
2474	else:
2475		if len(masterlist)==0:
2476			print("""Can't find masters (resolve '%s') !!!""" % (masterhost))
2477		elif electfound:
2478			print("Leader master server not found, but there is an elect, so make sure that all chunkservers are running - elect should become a leader soon")
2479		else:
2480			print("Working master servers not found !!! - maybe you are using wrong port number or wrong dns name")
2481	if not cgimode:
2482		Tabble.Needseparator=1
2483
2484if not cgimode:
2485	if leaderfound:
2486		if masterconn.version_less_than(1,7,0):
2487			allowedsections = ["IN","CS","HD","EX","MS","MO","MC","CC"]
2488		elif masterconn.version_less_than(2,1,0):
2489			allowedsections = ["IN","CS","HD","EX","MS","MO","QU","MC","CC"]
2490		else:
2491			allowedsections = ["IN","CS","HD","EX","MS","MO","RS","QU","MC","CC"]
2492	elif electfound:
2493		allowedsections = ["IN","CS","HD","EX","QU","MC","CC"]
2494	elif followerfound:
2495		allowedsections = ["IN","MC"]
2496	elif len(masterlist)>0:
2497		allowedsections = ["IN"]
2498	else:
2499		sys.exit(1)
2500
2501	filtered_sectionset = []
2502	for section in sectionset:
2503		if section in allowedsections:
2504			filtered_sectionset.append(section)
2505		else:
2506			print("""section '%s' not allowed""" % section)
2507	sectionset = filtered_sectionset
2508
2509# parse cgi parameters
2510if cgimode:
2511	try:
2512		INmatrix = int(fields.getvalue("INmatrix"))
2513	except Exception:
2514		INmatrix = 0
2515	try:
2516		IMorder = int(fields.getvalue("IMorder"))
2517	except Exception:
2518		IMorder = 0
2519	try:
2520		IMrev = int(fields.getvalue("IMrev"))
2521	except Exception:
2522		IMrev = 0
2523	try:
2524		MForder = int(fields.getvalue("MForder"))
2525	except Exception:
2526		MForder = 0
2527	try:
2528		MFrev = int(fields.getvalue("MFrev"))
2529	except Exception:
2530		MFrev = 0
2531	try:
2532		MFlimit = int(fields.getvalue("MFlimit"))
2533	except Exception:
2534		MFlimit = 100
2535	try:
2536		CSorder = int(fields.getvalue("CSorder"))
2537	except Exception:
2538		CSorder = 0
2539	try:
2540		CSrev = int(fields.getvalue("CSrev"))
2541	except Exception:
2542		CSrev = 0
2543	try:
2544		MBorder = int(fields.getvalue("MBorder"))
2545	except Exception:
2546		MBorder = 0
2547	try:
2548		MBrev = int(fields.getvalue("MBrev"))
2549	except Exception:
2550		MBrev = 0
2551	try:
2552		HDorder = int(fields.getvalue("HDorder"))
2553	except Exception:
2554		HDorder = 0
2555	try:
2556		HDrev = int(fields.getvalue("HDrev"))
2557	except Exception:
2558		HDrev = 0
2559	try:
2560		HDperiod = int(fields.getvalue("HDperiod"))
2561	except Exception:
2562		HDperiod = 0
2563	try:
2564		HDtime = int(fields.getvalue("HDtime"))
2565	except Exception:
2566		HDtime = 0
2567	try:
2568		HDaddrname = int(fields.getvalue("HDaddrname"))
2569	except Exception:
2570		HDaddrname = 0
2571	try:
2572		EXorder = int(fields.getvalue("EXorder"))
2573	except Exception:
2574		EXorder = 0
2575	try:
2576		EXrev = int(fields.getvalue("EXrev"))
2577	except Exception:
2578		EXrev = 0
2579	try:
2580		MSorder = int(fields.getvalue("MSorder"))
2581	except Exception:
2582		MSorder = 0
2583	try:
2584		MSrev = int(fields.getvalue("MSrev"))
2585	except Exception:
2586		MSrev = 0
2587	try:
2588		MOorder = int(fields.getvalue("MOorder"))
2589	except Exception:
2590		MOorder = 0
2591	try:
2592		MOrev = int(fields.getvalue("MOrev"))
2593	except Exception:
2594		MOrev = 0
2595	try:
2596		MOdata = int(fields.getvalue("MOdata"))
2597	except Exception:
2598		MOdata = 0
2599	try:
2600		SCorder = int(fields.getvalue("SCorder"))
2601	except Exception:
2602		SCorder = 0
2603	try:
2604		SCrev = int(fields.getvalue("SCrev"))
2605	except Exception:
2606		SCrev = 0
2607	try:
2608		OForder = int(fields.getvalue("OForder"))
2609	except Exception:
2610		OForder = 0
2611	try:
2612		OFrev = int(fields.getvalue("OFrev"))
2613	except Exception:
2614		OFrev = 0
2615	try:
2616		OFsessionid = int(fields.getvalue("OFsessionid"))
2617	except Exception:
2618		OFsessionid = 0
2619	try:
2620		ALorder = int(fields.getvalue("ALorder"))
2621	except Exception:
2622		ALorder = 0
2623	try:
2624		ALrev = int(fields.getvalue("ALrev"))
2625	except Exception:
2626		ALrev = 0
2627	try:
2628		ALinode = int(fields.getvalue("ALinode"))
2629	except Exception:
2630		ALinode = 0
2631	try:
2632		QUorder = int(fields.getvalue("QUorder"))
2633	except Exception:
2634		QUorder = 0
2635	try:
2636		QUrev = int(fields.getvalue("QUrev"))
2637	except Exception:
2638		QUrev = 0
2639	try:
2640		if "MCdata" in fields:
2641			MCdata = fields.getvalue("MCdata")
2642		else:
2643			MCdata = ""
2644	except Exception:
2645		MCdata = ""
2646	try:
2647		if "CCdata" in fields:
2648			CCdata = fields.getvalue("CCdata")
2649		else:
2650			CCdata = ""
2651	except Exception:
2652		CCdata = ""
2653else:
2654	# fix order id's
2655	if CSorder>=2:
2656		CSorder+=1
2657	if leaderfound and masterconn.version_less_than(1,7,25) and CSorder>=4:
2658		CSorder+=1
2659	if leaderfound and masterconn.version_less_than(1,6,28) and CSorder>=5:
2660		CSorder+=1
2661	if CSorder>=6 and CSorder<=9:
2662		CSorder+=4
2663	elif CSorder>=10 and CSorder<=13:
2664		CSorder+=10
2665
2666	if MBorder>=2:
2667		MBorder+=1
2668
2669	if HDorder>=13 and HDorder<=15:
2670		HDorder+=7
2671
2672	if leaderfound and masterconn.version_less_than(1,7,0) and EXorder>=10:
2673		EXorder+=1
2674
2675	if MSorder>=3:
2676		MSorder+=1
2677	if leaderfound and masterconn.version_less_than(1,7,0) and MSorder>=10:
2678		MSorder+=1
2679	if MSorder==0:
2680		MSorder=2
2681
2682	if MOorder==2:
2683		MOorder = 3
2684	elif MOorder>=3 and MOorder<=18:
2685		MOorder += 97
2686	elif MOorder==19:
2687		MOorder = 150
2688	elif MOorder!=1:
2689		MOorder = 0
2690
2691	if QUorder>=2 and QUorder<=6:
2692		QUorder += 8
2693	elif QUorder>=7 and QUorder<=10:
2694		QUorder += 14
2695	elif QUorder>=11 and QUorder<=22:
2696		QUorder = (lambda x: x[0]+x[1]*10)(divmod(QUorder-11,3))+31
2697	elif QUorder<1 or QUorder>22:
2698		QUorder = 0
2699
2700
2701if "IN" in sectionset:
2702	if cgimode and MFS_MESSAGE:
2703		out = []
2704		out.append("""<table class="FR" cellspacing="0">""")
2705		out.append("""<tr><th>Notice</th></tr>""")
2706		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="https://moosefs.com/products/">https://moosefs.com/products/</a></td></tr>""")
2707		out.append("""</table>""")
2708		print("\n".join(out))
2709
2710	if "IM" in sectionsubset and len(masterlistinfo)>0:
2711		try:
2712			if cgimode:
2713				out = []
2714				out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsmasters" cellspacing="0">""")
2715				out.append("""	<tr><th colspan="13">Metadata Servers (masters)</th></tr>""")
2716				out.append("""	<tr>""")
2717				out.append("""		<th class="acid_tab_enumerate">#</th>""")
2718				out.append("""		<th>ip</th>""")
2719				out.append("""		<th>version</th>""")
2720				out.append("""		<th>state</th>""")
2721				out.append("""		<th>local time</th>""")
2722				out.append("""		<th>metadata version</th>""")
2723				out.append("""		<th>metadata delay</th>""")
2724				out.append("""		<th>RAM used</th>""")
2725				out.append("""		<th>CPU used</th>""")
2726				out.append("""		<th>last successful metadata save</th>""")
2727				out.append("""		<th>last metadata save duration</th>""")
2728				out.append("""		<th>last metadata save status</th>""")
2729				out.append("""		<th>exports checksum</th>""")
2730				out.append("""	</tr>""")
2731			elif ttymode:
2732				tab = Tabble("Metadata Servers",12,"r")
2733				tab.header("ip","version","state","local time","metadata version","metadata delay","RAM used","CPU used","last meta save","last save duration","last save status","exports checksum")
2734			else:
2735				tab = Tabble("metadata servers",12)
2736			masterstab = []
2737			for sortip,strip,sortver,strver,statestr,statecolor,metaversion,memusage,syscpu,usercpu,lastsuccessfulstore,lastsaveseconds,lastsavestatus,exports_checksum,usectime,chlogtime in masterlistinfo:
2738				if IMorder==1:
2739					sf = sortip
2740				elif IMorder==2:
2741					sf = sortver
2742				elif IMorder==3:
2743					sf = statecolor
2744				elif IMorder==4:
2745					sf = usectime if usectime!=None else 0
2746				elif IMorder==5:
2747					sf = metaversion
2748				elif IMorder==6:
2749					sf = chlogtime if chlogtime!=None else 0
2750				elif IMorder==7:
2751					sf = memusage
2752				elif IMorder==8:
2753					sf = syscpu+usercpu
2754				elif IMorder==9:
2755					sf = lastsuccessfulstore
2756				elif IMorder==10:
2757					sf = lastsaveseconds
2758				elif IMorder==11:
2759					sf = lastsavestatus
2760				elif IMorder==12:
2761					sf = exports_checksum
2762				else:
2763					sf = 0
2764				masterstab.append((sf,sortip,strip,sortver,strver,statestr,statecolor,metaversion,memusage,syscpu,usercpu,lastsuccessfulstore,lastsaveseconds,lastsavestatus,exports_checksum,usectime,chlogtime))
2765
2766			masterstab.sort()
2767			if IMrev:
2768				masterstab.reverse()
2769
2770			for sf,sortip,strip,sortver,strver,statestr,statecolor,metaversion,memusage,syscpu,usercpu,lastsuccessfulstore,lastsaveseconds,lastsavestatus,exports_checksum,usectime,chlogtime in masterstab:
2771				if usectime==None or usectime==0:
2772					secdelta = None
2773				else:
2774					secdelta = 0.0
2775					if leader_usectime==None or leader_usectime==0:
2776						if master_maxusectime!=None and master_minusectime!=None:
2777							secdelta = (master_maxusectime - master_minusectime) / 1000000.0
2778					else:
2779						if leader_usectime > usectime:
2780							secdelta = (leader_usectime - usectime) / 1000000.0
2781						else:
2782							secdelta = (usectime - leader_usectime) / 1000000.0
2783				if chlogtime==None or chlogtime==0 or leader_usectime==None or leader_usectime==0:
2784					metadelay = None
2785				else:
2786					metadelay = leader_usectime/1000000.0 - chlogtime
2787					if metadelay>1.0:
2788						metadelay-=1.0
2789					else:
2790						metadelay=0.0
2791				if cgimode:
2792					if masterconn!=None and masterconn.is_pro() and not strver.endswith(" PRO"):
2793						verclass = "BADVERSION"
2794					elif masterconn!=None and masterconn.sort_ver() > sortver:
2795						verclass = "LOWERVERSION"
2796					elif masterconn!=None and masterconn.sort_ver() < sortver:
2797						verclass = "HIGHERVERSION"
2798					else:
2799						verclass = "OKVERSION"
2800					out.append("""	<tr>""")
2801					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))
2802					out.append("""		<td align="center"><span class="STATECOLOR%u">%s</span></td>""" % (statecolor,statestr))
2803					if secdelta==None:
2804						out.append("""		<td align="center">-</td>""")
2805					else:
2806						out.append("""		<td align="center"><span class="%s">%s</span></td>""" % (("ERROR" if secdelta>2.0 else "WARNING" if secdelta>1.0 else "SUCCESS" if secdelta>0.0 else "DEFINED"),time.asctime(time.localtime(usectime//1000000))))
2807					out.append("""		<td align="right">%s</td>""" % (decimal_number(metaversion)))
2808					if metadelay==None:
2809						out.append("""		<td align="right">-</td>""")
2810					else:
2811						out.append("""		<td align="right"><span class="%s">%.0f s</span></td>""" % (("SUCCESS" if metadelay<1.0 else "WARNING" if metadelay<6.0 else "ERROR"),metadelay))
2812					if memusage>0:
2813						out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(memusage),humanize_number(memusage,"&nbsp;")))
2814					else:
2815						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>""")
2816					if syscpu>0 or usercpu>0:
2817						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))
2818					else:
2819						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>""")
2820					if lastsuccessfulstore>0:
2821						out.append("""		<td align="center">%s</td>""" % time.asctime(time.localtime(lastsuccessfulstore)))
2822						out.append("""		<td align="center"><a style="cursor:default" title="%s">%s</a></td>""" % (timeduration_to_fullstr(lastsaveseconds),timeduration_to_shortstr(lastsaveseconds)))
2823					else:
2824						out.append("""		<td align="center">-</td><td align="center">-</td>""")
2825					if lastsuccessfulstore>0 or lastsavestatus>0:
2826						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))
2827					else:
2828						out.append("""		<td align="center">-</td>""")
2829					if exports_checksum!=None:
2830						out.append("""		<td align="center"><span class="%s">%016X</span></td>""" % (("ERROR" if exports_checksum != master_exports_checksum else "SUCCESS"),exports_checksum))
2831					else:
2832						out.append("""		<td align="center">-</td>""")
2833					out.append("""	</tr>""")
2834				else:
2835					clist = [strip,strver,(statestr,"c%u" % statecolor)]
2836					if secdelta==None:
2837						clist.append("not available")
2838					else:
2839						if ttymode:
2840							clist.append((time.asctime(time.localtime(usectime//1000000)),("1" if secdelta>2.0 else "3" if secdelta>1.0 else "4" if secdelta>0.0 else "0")))
2841						else:
2842							clist.append("%.6lf" % (usectime/1000000.0))
2843					clist.append(decimal_number(metaversion))
2844					if metadelay==None:
2845						clist.append("not available")
2846					else:
2847						if ttymode:
2848							clist.append((("%.0f s" % metadelay),("4" if metadelay<1.0 else "3" if metadelay<6.0 else "1")))
2849						else:
2850							clist.append(int(metadelay))
2851					if memusage>0:
2852						if ttymode:
2853							clist.append(humanize_number(memusage," "))
2854						else:
2855							clist.append(memusage)
2856					else:
2857						clist.append("not available")
2858					if syscpu>0 or usercpu>0:
2859						if ttymode:
2860							clist.append("all:%.2f%% sys:%.2f%% user:%.2f%%" % (syscpu+usercpu,syscpu,usercpu))
2861						else:
2862							clist.append("all:%.7f%% sys:%.7f%% user:%.7f%%" % (syscpu+usercpu,syscpu,usercpu))
2863					else:
2864						clist.append("not available")
2865					if lastsuccessfulstore>0:
2866						if ttymode:
2867							clist.append(time.asctime(time.localtime(lastsuccessfulstore)))
2868							clist.append(timeduration_to_shortstr(lastsaveseconds))
2869						else:
2870							clist.append(lastsuccessfulstore)
2871							clist.append("%.3f" % lastsaveseconds)
2872					else:
2873						clist.append("-")
2874						clist.append("-")
2875					if lastsuccessfulstore>0 or lastsavestatus>0:
2876						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"))
2877					else:
2878						clist.append("-")
2879					if exports_checksum!=None:
2880						clist.append((("%016X" % exports_checksum),("1" if exports_checksum != master_exports_checksum else "4")))
2881					else:
2882						clist.append("-")
2883					tab.append(*clist)
2884
2885			if len(masterstab)==0:
2886				if cgimode:
2887					out.append("""	<tr><td colspan="10">Servers not found !!! - check your DNS</td></tr>""")
2888				else:
2889					tab.append(("""Servers not found !!! - check your DNS""","c",9))
2890
2891			if cgimode:
2892				out.append("""</table>""")
2893				print("\n".join(out))
2894			else:
2895				print(myunicode(tab))
2896		except Exception:
2897			print_exception()
2898
2899
2900	if "IG" in sectionsubset and masterconn!=None:
2901		try:
2902			length = len(masterinfo)
2903			if length==68:
2904				v1,v2,v3,total,avail,trspace,trfiles,respace,refiles,nodes,dirs,files,chunks,allcopies,tdcopies = struct.unpack(">HBBQQQLQLLLLLLL",masterinfo)
2905				strver,sortver = version_str_and_sort((v1,v2,v3))
2906				if cgimode:
2907					out = []
2908					out.append("""<table class="FR" cellspacing="0">""")
2909					out.append("""	<tr><th colspan="13">Info</th></tr>""")
2910					out.append("""	<tr>""")
2911					out.append("""		<th>version</th>""")
2912					out.append("""		<th>total space</th>""")
2913					out.append("""		<th>avail space</th>""")
2914					out.append("""		<th>trash space</th>""")
2915					out.append("""		<th>trash files</th>""")
2916					out.append("""		<th>sustained space</th>""")
2917					out.append("""		<th>sustained files</th>""")
2918					out.append("""		<th>all fs objects</th>""")
2919					out.append("""		<th>directories</th>""")
2920					out.append("""		<th>files</th>""")
2921					out.append("""		<th>chunks</th>""")
2922					out.append("""		<th><a style="cursor:default" title="chunks from 'regular' hdd space and 'marked for removal' hdd space">all chunk copies</a></th>""")
2923					out.append("""		<th><a style="cursor:default" title="only chunks from 'regular' hdd space">regular chunk copies</a></th>""")
2924					out.append("""	</tr>""")
2925					out.append("""	<tr>""")
2926					out.append("""		<td align="center">%s</td>""" % strver)
2927					out.append("""		<td align="right"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(total),humanize_number(total,"&nbsp;")))
2928					out.append("""		<td align="right"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(avail),humanize_number(avail,"&nbsp;")))
2929					out.append("""		<td align="right"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(trspace),humanize_number(trspace,"&nbsp;")))
2930					out.append("""		<td align="right">%u</td>""" % trfiles)
2931					out.append("""		<td align="right"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(respace),humanize_number(respace,"&nbsp;")))
2932					out.append("""		<td align="right">%u</td>""" % refiles)
2933					out.append("""		<td align="right">%u</td>""" % nodes)
2934					out.append("""		<td align="right">%u</td>""" % dirs)
2935					out.append("""		<td align="right">%u</td>""" % files)
2936					out.append("""		<td align="right">%u</td>""" % chunks)
2937					out.append("""		<td align="right">%u</td>""" % allcopies)
2938					out.append("""		<td align="right">%u</td>""" % tdcopies)
2939					out.append("""	</tr>""")
2940					out.append("""</table>""")
2941					print("\n".join(out))
2942				else:
2943					if ttymode:
2944						tab = Tabble("Master Info",2)
2945					else:
2946						tab = Tabble("master info",2)
2947					tab.defattr("l","r")
2948					tab.append("master version",strver)
2949					if ttymode:
2950						tab.append("total space",humanize_number(total," "))
2951						tab.append("avail space",humanize_number(avail," "))
2952						tab.append("trash space",humanize_number(trspace," "))
2953					else:
2954						tab.append("total space",total)
2955						tab.append("avail space",avail)
2956						tab.append("trash space",trspace)
2957					tab.append("trash files",trfiles)
2958					if ttymode:
2959						tab.append("sustained space",humanize_number(respace," "))
2960					else:
2961						tab.append("sustained space",respace)
2962					tab.append("sustained files",refiles)
2963					tab.append("all fs objects",nodes)
2964					tab.append("directories",dirs)
2965					tab.append("files",files)
2966					tab.append("chunks",chunks)
2967					tab.append("all chunk copies",allcopies)
2968					tab.append("regular chunk copies",tdcopies)
2969					print(myunicode(tab))
2970			elif length==76:
2971				v1,v2,v3,memusage,total,avail,trspace,trfiles,respace,refiles,nodes,dirs,files,chunks,allcopies,tdcopies = struct.unpack(">HBBQQQQLQLLLLLLL",masterinfo)
2972				strver,sortver = version_str_and_sort((v1,v2,v3))
2973				if cgimode:
2974					out = []
2975					out.append("""<table class="FR" cellspacing="0">""")
2976					out.append("""	<tr><th colspan="14">Info</th></tr>""")
2977					out.append("""	<tr>""")
2978					out.append("""		<th>version</th>""")
2979					out.append("""		<th>RAM used</th>""")
2980					out.append("""		<th>total space</th>""")
2981					out.append("""		<th>avail space</th>""")
2982					out.append("""		<th>trash space</th>""")
2983					out.append("""		<th>trash files</th>""")
2984					out.append("""		<th>sustained space</th>""")
2985					out.append("""		<th>sustained files</th>""")
2986					out.append("""		<th>all fs objects</th>""")
2987					out.append("""		<th>directories</th>""")
2988					out.append("""		<th>files</th>""")
2989					out.append("""		<th>chunks</th>""")
2990					out.append("""		<th><a style="cursor:default" title="chunks from 'regular' hdd space and 'marked for removal' hdd space">all chunk copies</a></th>""")
2991					out.append("""		<th><a style="cursor:default" title="only chunks from 'regular' hdd space">regular chunk copies</a></th>""")
2992					out.append("""	</tr>""")
2993					out.append("""	<tr>""")
2994					out.append("""		<td align="center">%s</td>""" % strver)
2995					if memusage>0:
2996						out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(memusage),humanize_number(memusage,"&nbsp;")))
2997					else:
2998						out.append("""		<td align="center"><a style="cursor:default" title="obtaining memory usage is not supported by your OS">not available</td>""")
2999					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(total),humanize_number(total,"&nbsp;")))
3000					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(avail),humanize_number(avail,"&nbsp;")))
3001					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(trspace),humanize_number(trspace,"&nbsp;")))
3002					out.append("""		<td align="center">%u</td>""" % trfiles)
3003					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(respace),humanize_number(respace,"&nbsp;")))
3004					out.append("""		<td align="center">%u</td>""" % refiles)
3005					out.append("""		<td align="center">%u</td>""" % nodes)
3006					out.append("""		<td align="center">%u</td>""" % dirs)
3007					out.append("""		<td align="center">%u</td>""" % files)
3008					out.append("""		<td align="center">%u</td>""" % chunks)
3009					out.append("""		<td align="center">%u</td>""" % allcopies)
3010					out.append("""		<td align="center">%u</td>""" % tdcopies)
3011					out.append("""	</tr>""")
3012					out.append("""</table>""")
3013					print("\n".join(out))
3014				else:
3015					if ttymode:
3016						tab = Tabble("Master Info",2)
3017					else:
3018						tab = Tabble("master info",2)
3019					tab.defattr("l","r")
3020					tab.append("master version",strver)
3021					if memusage>0:
3022						if ttymode:
3023							tab.append("RAM used",humanize_number(memusage," "))
3024						else:
3025							tab.append("RAM used",memusage)
3026					else:
3027						tab.append("RAM used","not available")
3028					if ttymode:
3029						tab.append("total space",humanize_number(total," "))
3030						tab.append("avail space",humanize_number(avail," "))
3031						tab.append("trash space",humanize_number(trspace," "))
3032					else:
3033						tab.append("total space",total)
3034						tab.append("avail space",avail)
3035						tab.append("trash space",trspace)
3036					tab.append("trash files",trfiles)
3037					if ttymode:
3038						tab.append("sustained space",humanize_number(respace," "))
3039					else:
3040						tab.append("sustained space",respace)
3041					tab.append("sustained files",refiles)
3042					tab.append("all fs objects",nodes)
3043					tab.append("directories",dirs)
3044					tab.append("files",files)
3045					tab.append("chunks",chunks)
3046					tab.append("all chunk copies",allcopies)
3047					tab.append("regular chunk copies",tdcopies)
3048					print(myunicode(tab))
3049			elif length==101 or length==121 or length==129 or length==137 or length==149:
3050				if length>=137:
3051					v1,v2,v3,memusage,syscpu,usercpu,totalspace,availspace,freespace,trspace,trfiles,respace,refiles,nodes,dirs,files,chunks,allcopies,tdcopies,lastsuccessfulstore,lastsaveseconds,lastsavestatus = struct.unpack(">HBBQQQQQQQLQLLLLLLLLLB",masterinfo[:109])
3052				else:
3053					v1,v2,v3,memusage,syscpu,usercpu,totalspace,availspace,trspace,trfiles,respace,refiles,nodes,dirs,files,chunks,allcopies,tdcopies,lastsuccessfulstore,lastsaveseconds,lastsavestatus = struct.unpack(">HBBQQQQQQLQLLLLLLLLLB",masterinfo[:101])
3054					freespace = None
3055				strver,sortver = version_str_and_sort((v1,v2,v3))
3056				syscpu/=10000000.0
3057				usercpu/=10000000.0
3058				if masterconn.version_at_least(2,0,14):
3059					lastsaveseconds = lastsaveseconds / 1000.0
3060				if cgimode:
3061					out = []
3062					if length==101:
3063						out.append("""<table class="FR" cellspacing="0">""")
3064						out.append("""	<tr><th colspan="6">General Info</th></tr>""")
3065						out.append("""	<tr>""")
3066						out.append("""		<th>version</th>""")
3067						out.append("""		<th>RAM used</th>""")
3068						out.append("""		<th>CPU used</th>""")
3069						out.append("""		<th>last successful metadata save</th>""")
3070						out.append("""		<th>last metadata save duration</th>""")
3071						out.append("""		<th>last metadata save status</th>""")
3072						out.append("""	</tr>""")
3073						out.append("""	<tr>""")
3074						out.append("""		<td align="center">%s</td>""" % strver)
3075						if memusage>0:
3076							out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(memusage),humanize_number(memusage,"&nbsp;")))
3077						else:
3078							out.append("""		<td align="center"><a style="cursor:default" title="obtaining memory usage is not supported by your OS">not available</td>""")
3079						if syscpu>0 or usercpu>0:
3080							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))
3081						else:
3082							out.append("""		<td align="center"><a style="cursor:default" title="obtaining cpu usage is not supported by your OS">not available</td>""")
3083						if lastsuccessfulstore>0:
3084							out.append("""		<td align="center">%s</td>""" % time.asctime(time.localtime(lastsuccessfulstore)))
3085							out.append("""		<td align="center"><a style="cursor:default" title="%s">%s</a></td>""" % (timeduration_to_fullstr(lastsaveseconds),timeduration_to_shortstr(lastsaveseconds)))
3086						else:
3087							out.append("""		<td align="center">-</td><td align="center">-</td>""")
3088						if lastsuccessfulstore>0 or lastsavestatus>0:
3089							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))
3090						else:
3091							out.append("""		<td align="center">-</td>""")
3092						out.append("""	</tr>""")
3093						out.append("""</table>""")
3094					out.append("""<table class="FR" cellspacing="0">""")
3095					out.append("""	<tr><th colspan="%u">Metadata Info</th></tr>""" % (12 if freespace==None else 13))
3096					out.append("""	<tr>""")
3097					out.append("""		<th>total space</th>""")
3098					out.append("""		<th>avail space</th>""")
3099					if freespace!=None:
3100						out.append("""		<th>free space</th>""")
3101					out.append("""		<th>trash space</th>""")
3102					out.append("""		<th>trash files</th>""")
3103					out.append("""		<th>sustained space</th>""")
3104					out.append("""		<th>sustained files</th>""")
3105					out.append("""		<th>all fs objects</th>""")
3106					out.append("""		<th>directories</th>""")
3107					out.append("""		<th>files</th>""")
3108					out.append("""		<th>chunks</th>""")
3109					out.append("""		<th><a style="cursor:default" title="chunks from 'regular' hdd space and 'marked for removal' hdd space">all chunk copies</a></th>""")
3110					out.append("""		<th><a style="cursor:default" title="only chunks from 'regular' hdd space">regular chunk copies</a></th>""")
3111					out.append("""	</tr>""")
3112					out.append("""	<tr>""")
3113					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(totalspace),humanize_number(totalspace,"&nbsp;")))
3114					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(availspace),humanize_number(availspace,"&nbsp;")))
3115					if freespace!=None:
3116						out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(freespace),humanize_number(freespace,"&nbsp;")))
3117					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(trspace),humanize_number(trspace,"&nbsp;")))
3118					out.append("""		<td align="center">%u</td>""" % trfiles)
3119					out.append("""		<td align="center"><a style="cursor:default" title="%s B">%s</a></td>""" % (decimal_number(respace),humanize_number(respace,"&nbsp;")))
3120					out.append("""		<td align="center">%u</td>""" % refiles)
3121					out.append("""		<td align="center">%u</td>""" % nodes)
3122					out.append("""		<td align="center">%u</td>""" % dirs)
3123					out.append("""		<td align="center">%u</td>""" % files)
3124					out.append("""		<td align="center">%u</td>""" % chunks)
3125					out.append("""		<td align="center">%u</td>""" % allcopies)
3126					out.append("""		<td align="center">%u</td>""" % tdcopies)
3127					out.append("""	</tr>""")
3128					out.append("""</table>""")
3129					print("\n".join(out))
3130				else:
3131					if ttymode:
3132						tab = Tabble("Master Info",2)
3133					else:
3134						tab = Tabble("master info",2)
3135					tab.defattr("l","r")
3136					tab.append("master version",strver)
3137					if memusage>0:
3138						if ttymode:
3139							tab.append("RAM used",humanize_number(memusage," "))
3140						else:
3141							tab.append("RAM used",memusage)
3142					else:
3143						tab.append("RAM used","not available")
3144					if syscpu>0 or usercpu>0:
3145						if ttymode:
3146							tab.append("CPU used","%.2f%%" % (syscpu+usercpu))
3147							tab.append("CPU used (system)","%.2f%%" % (syscpu))
3148							tab.append("CPU used (user)","%.2f%%" % (usercpu))
3149						else:
3150							tab.append("CPU used (system)","%.9f" % (syscpu/100.0))
3151							tab.append("CPU used (user)","%.9f" % (usercpu/100.0))
3152					else:
3153						tab.append("CPU used","not available")
3154					if ttymode:
3155						tab.append("total space",humanize_number(totalspace," "))
3156						tab.append("avail space",humanize_number(availspace," "))
3157						if freespace!=None:
3158							tab.append("free space",humanize_number(freespace," "))
3159						tab.append("trash space",humanize_number(trspace," "))
3160					else:
3161						tab.append("total space",totalspace)
3162						tab.append("avail space",availspace)
3163						if freespace!=None:
3164							tab.append("free space",freespace)
3165						tab.append("trash space",trspace)
3166					tab.append("trash files",trfiles)
3167					if ttymode:
3168						tab.append("sustained space",humanize_number(respace," "))
3169					else:
3170						tab.append("sustained space",respace)
3171					tab.append("sustained files",refiles)
3172					tab.append("all fs objects",nodes)
3173					tab.append("directories",dirs)
3174					tab.append("files",files)
3175					tab.append("chunks",chunks)
3176					tab.append("all chunk copies",allcopies)
3177					tab.append("regular chunk copies",tdcopies)
3178					if lastsuccessfulstore>0:
3179						if ttymode:
3180							tab.append("last successful store",time.asctime(time.localtime(lastsuccessfulstore)))
3181							tab.append("last save duration",timeduration_to_shortstr(lastsaveseconds))
3182						else:
3183							tab.append("last successful store",lastsuccessfulstore)
3184							tab.append("last save duration","%.3f" % lastsaveseconds)
3185					else:
3186						tab.append("last successful store","-")
3187						tab.append("last save duration","-")
3188					if lastsuccessfulstore>0 or lastsavestatus>0:
3189						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"))
3190					else:
3191						tab.append("last save status","-")
3192					print(myunicode(tab))
3193			else:
3194				if cgimode:
3195					out = []
3196					out.append("""<table class="FR" cellspacing="0">""")
3197					out.append("""	<tr><td align="left">unrecognized answer from MFSmaster</td></tr>""")
3198					out.append("""</table>""")
3199					print("\n".join(out))
3200				else:
3201					print("unrecognized answer from MFSmaster")
3202		except Exception:
3203			print_exception()
3204
3205	if "MU" in sectionsubset and masterconn!=None and masterconn.version_at_least(1,7,16):
3206		try:
3207			data,length = masterconn.command(CLTOMA_MEMORY_INFO,MATOCL_MEMORY_INFO)
3208			if length>=176 and length%16==0:
3209				memusage = struct.unpack(">QQQQQQQQQQQQQQQQQQQQQQ",data[:176])
3210				memlabels = ["chunk hash","chunks","cs lists","edge hash","edges","node hash","nodes","deleted nodes","chunk tabs","symlinks","quota"]
3211				abrlabels = ["c.h.","c.","c.l.","e.h.","e.","n.h.","n.","d.n.","c.t.","s.","q."]
3212				totalused = 0
3213				totalallocated = 0
3214				for i in xrange(11):
3215					totalused += memusage[1+i*2]
3216					totalallocated += memusage[i*2]
3217				if cgimode:
3218					out = []
3219					out.append("""<table class="FR" cellspacing="0">""")
3220					out.append("""	<tr><th colspan="%d">Memory usage detailed info</th></tr>""" % (len(memlabels)+2))
3221					out.append("""	<tr><th></th>""")
3222					for i in xrange(11):
3223						out.append("""		<th>%s</th>""" % memlabels[i])
3224					out.append("""	<th>total</th></tr>""")
3225					out.append("""	<tr><th align="center">used</th>""")
3226					for i in xrange(11):
3227						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;")))
3228					out.append("""	<td align="center"><a style="cursor:default" title="%s B">%s</a></td></tr>""" % (decimal_number(totalused),humanize_number(totalused,"&nbsp;")))
3229					out.append("""	<tr><th align="center">allocated</th>""")
3230					for i in xrange(11):
3231						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;")))
3232					out.append("""	<td align="center"><a style="cursor:default" title="%s B">%s</a></td></tr>""" % (decimal_number(totalallocated),humanize_number(totalallocated,"&nbsp;")))
3233					out.append("""	<tr><th align="center">utilization</th>""")
3234					for i in xrange(11):
3235						if memusage[i*2]:
3236							percent = "%.2f %%" % (100.0 * memusage[1+i*2] / memusage[i*2])
3237						else:
3238							percent = "-"
3239						out.append("""		<td align="center">%s</td>""" % percent)
3240					if totalallocated:
3241						percent = "%.2f %%" % (100.0 * totalused / totalallocated)
3242					else:
3243						percent = "-"
3244					out.append("""	<td align="center">%s</td></tr>""" % percent)
3245					if totalallocated>0:
3246						out.append("""	<tr><th align="center">distribution</th>""")
3247						for i in xrange(11):
3248							tpercent = "%.2f %%" % (100.0 * memusage[i*2] / totalallocated)
3249							out.append("""		<td align="center">%s</td>""" % tpercent)
3250						out.append("""	<td>-</td></tr>""")
3251						out.append("""  <tr><th align="center">distribution bar</th>""")
3252						out.append("""		<td colspan="%d" class="NOPADDING">""" % (len(memlabels)+1))
3253						out.append("""			<table width="100%" cellspacing="0" style="border:0px;" id="bar"><tr>""")
3254						memdistribution = []
3255						other = 0.0
3256						for i,(label,abr) in enumerate(zip(memlabels,abrlabels)):
3257							tpercent = (100.0 * memusage[i*2] / totalallocated)
3258							if tpercent>1.0:
3259								memdistribution.append((tpercent,label,abr))
3260							else:
3261								other+=tpercent
3262						memdistribution.sort()
3263						memdistribution.reverse()
3264						if other>0:
3265							memdistribution.append((other,None,None))
3266						cl = "FIRST"
3267						labels = []
3268						tooltips = []
3269						for i,(percent,label,abr) in enumerate(memdistribution):
3270							if label:
3271								if percent>10.0:
3272									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))
3273								elif percent>3.0:
3274									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))
3275								else:
3276									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,"#"))
3277								labels.append(label)
3278								tooltips.append("%s (%.2f %%)" % (label,percent))
3279							else:
3280								out.append("""				<td style="width:%.2f%%;" class="MEMDISTOTHER MEMDIST%s"></td>""" % (percent,cl))
3281								labels.append("others")
3282								tooltips.append("other memory segments (%.2f %%)" % (percent))
3283							cl = "MID"
3284						out.append("""			</tr></table>""")
3285						out.append("""<script type="text/javascript">""")
3286						out.append("""<!--//--><![CDATA[//><!--""")
3287						out.append("""	var bar_labels = [%s];""" % ",".join(map(repr,labels)))
3288						out.append("""	var bar_tooltips = [%s];""" % ",".join(map(repr,tooltips)))
3289						out.append("""//--><!]]>""")
3290						out.append("""</script>""")
3291						out.append("""<script type="text/javascript">
3292<!--//--><![CDATA[//><!--
3293	function bar_refresh() {
3294		var b = document.getElementById("bar");
3295		var i,j,x;
3296		if (b) {
3297			var x = b.getElementsByTagName("td");
3298			for (i=0 ; i<x.length ; i++) {
3299				x[i].innerHTML = "";
3300			}
3301			for (i=0 ; i<x.length ; i++) {
3302				var width = x[i].clientWidth;
3303				var label = bar_labels[i];
3304				var tooltip = bar_tooltips[i];
3305				x[i].innerHTML = "<a title='" + tooltip + "'>" + label + "</a>";
3306				if (width<x[i].clientWidth) {
3307					x[i].innerHTML = "<a title='" + tooltip + "'>&#8230;</a>";
3308					if (width<x[i].clientWidth) {
3309						x[i].innerHTML = "<a title='" + tooltip + "'>&#8226;</a>";
3310						if (width<x[i].clientWidth) {
3311							x[i].innerHTML = "<a title='" + tooltip + "'>.</a>";
3312							if (width<x[i].clientWidth) {
3313								x[i].innerHTML = "";
3314							}
3315						}
3316					} else {
3317						for (j=1 ; j<bar_labels[i].length-1 ; j++) {
3318							x[i].innerHTML = "<a title='" + tooltip + "'>"+label.substring(0,j) + "&#8230;</a>";
3319							if (width<x[i].clientWidth) {
3320								break;
3321							}
3322						}
3323						x[i].innerHTML = "<a title='" + tooltip + "'>" + label.substring(0,j-1) + "&#8230;</a>";
3324					}
3325				}
3326			}
3327		}
3328	}
3329
3330	function bar_add_event(obj,type,fn) {
3331		if (obj.addEventListener) {
3332			obj.addEventListener(type, fn, false);
3333		} else if (obj.attachEvent) {
3334			obj.attachEvent('on'+type, fn);
3335		}
3336	}
3337
3338	bar_add_event(window,"load",bar_refresh);
3339	bar_add_event(window,"resize",bar_refresh);
3340//--><!]]>
3341</script>""")
3342						out.append("""		</td>""")
3343						out.append("""	</tr>""")
3344					out.append("""</table>""")
3345					print("\n".join(out))
3346				else:
3347					if ttymode:
3348						tab = Tabble("Memory Usage Detailed Info",5)
3349						tab.defattr("l","r","r","r","r")
3350						tab.header("object name","memory used","memory allocated","utilization percent","percent of total allocated memory")
3351					else:
3352						tab = Tabble("memory usage detailed info",3)
3353						tab.defattr("l","r","r")
3354						tab.header("object name","memory used","memory allocated")
3355					for i in xrange(11):
3356						if ttymode:
3357							if memusage[i*2]>0:
3358								upercent = "%.2f %%" % (100.0 * memusage[1+i*2] / memusage[i*2])
3359							else:
3360								upercent = "-"
3361							if totalallocated:
3362								tpercent = "%.2f %%" % (100.0 * memusage[i*2] / totalallocated)
3363							else:
3364								tpercent = "-"
3365							tab.append(memlabels[i],humanize_number(memusage[1+i*2]," "),humanize_number(memusage[i*2]," "),upercent,tpercent)
3366						else:
3367							tab.append(memlabels[i],memusage[1+i*2],memusage[i*2])
3368					if ttymode:
3369						tab.append(("---","",5))
3370						percent = 100.0 * totalused / totalallocated
3371						tab.append("total",humanize_number(totalused," "),humanize_number(totalallocated," "),"%.2f %%" % percent,"-")
3372					print(myunicode(tab))
3373		except Exception:
3374			print_exception()
3375
3376	if "IC" in sectionsubset and leaderfound:
3377		try:
3378			if masterconn.version_less_than(1,7,0):
3379				data,length = masterconn.command(CLTOMA_CHUNKS_MATRIX,MATOCL_CHUNKS_MATRIX,struct.pack(">B",0))
3380				if length==484:
3381					matrix = []
3382					matrix.append([])
3383					for i in range(11):
3384						matrix[0].append(list(struct.unpack(">LLLLLLLLLLL",data[i*44:i*44+44])))
3385					data,length = masterconn.command(CLTOMA_CHUNKS_MATRIX,MATOCL_CHUNKS_MATRIX,struct.pack(">B",1))
3386					if length==484:
3387						matrix.append([])
3388						for i in range(11):
3389							matrix[1].append(list(struct.unpack(">LLLLLLLLLLL",data[i*44:i*44+44])))
3390				progressstatus = 0
3391			else:
3392				data,length = masterconn.command(CLTOMA_CHUNKS_MATRIX,MATOCL_CHUNKS_MATRIX)
3393				if length==969:
3394					progressstatus = struct.unpack(">B",data[0:1])[0]
3395					matrix = ([],[])
3396					for x in range(2):
3397						for i in range(11):
3398							matrix[x].append(list(struct.unpack(">LLLLLLLLLLL",data[1+x*484+i*44:45+x*484+i*44])))
3399			progressstr = "disconnections" if (progressstatus==1) else "connections" if (progressstatus==2) else "connections and disconnections"
3400			if len(matrix)==2:
3401				if cgimode:
3402					out = []
3403					out.append("""<table class="acid_tab acid_tab_storageid_mfsmatrix" cellspacing="0" id="mfsmatrix">""")
3404					out.append("""	<tr><th colspan="13">""")
3405					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>""")
3406					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>""")
3407					out.append("""	</th></tr>""")
3408					if progressstatus>0:
3409						out.append("""<tr><th colspan="13"><span class="ERROR">Warning: counters may not be valid - %s in progress</span></th></tr>""" % progressstr)
3410					out.append("""	<tr>""")
3411					out.append("""		<th rowspan="2" class="PERC4 acid_tab_skip">goal</th>""")
3412					out.append("""		<th colspan="12" class="PERC96 acid_tab_skip">valid copies</th>""")
3413					out.append("""	</tr>""")
3414					out.append("""	<tr>""")
3415					out.append("""		<th class="PERC8 acid_tab_skip">0</th>""")
3416					out.append("""		<th class="PERC8 acid_tab_skip">1</th>""")
3417					out.append("""		<th class="PERC8 acid_tab_skip">2</th>""")
3418					out.append("""		<th class="PERC8 acid_tab_skip">3</th>""")
3419					out.append("""		<th class="PERC8 acid_tab_skip">4</th>""")
3420					out.append("""		<th class="PERC8 acid_tab_skip">5</th>""")
3421					out.append("""		<th class="PERC8 acid_tab_skip">6</th>""")
3422					out.append("""		<th class="PERC8 acid_tab_skip">7</th>""")
3423					out.append("""		<th class="PERC8 acid_tab_skip">8</th>""")
3424					out.append("""		<th class="PERC8 acid_tab_skip">9</th>""")
3425					out.append("""		<th class="PERC8 acid_tab_skip">10+</th>""")
3426					out.append("""		<th class="PERC8 acid_tab_skip">all</th>""")
3427					out.append("""	</tr>""")
3428				elif ttymode:
3429					if INmatrix==0:
3430						tab = Tabble("All chunks state matrix",13,"r")
3431					else:
3432						tab = Tabble("Regular chunks state matrix",13,"r")
3433					if progressstatus>0:
3434						tab.header(("Warning: counters may not be valid - %s in progress" % progressstr,"1c",13))
3435						tab.header(("---","",13))
3436					tab.header("",("valid copies","",12))
3437					tab.header("goal",("---","",12))
3438					tab.header("","    0    ","    1    ","    2    ","    3    ","    4    ","    5    ","    6    ","    7    ","    8    ","    9    ","   10+   ","   all   ")
3439				else:
3440					out = []
3441					if INmatrix==0:
3442						mtypeprefix=("all chunks matrix:%s" % plaintextseparator)
3443					else:
3444						mtypeprefix=("regular chunks matrix:%s" % plaintextseparator)
3445				classsum = []
3446				classsum.append(7*[0])
3447				classsum.append(7*[0])
3448				sumlist = []
3449				sumlist.append(11*[0])
3450				sumlist.append(11*[0])
3451				for goal in range(11):
3452					if cgimode:
3453						out.append("""	<tr>""")
3454						if goal==10:
3455							out.append("""		<th align="center" class="acid_tab_skip">10+</th>""")
3456						else:
3457							out.append("""		<th align="center" class="acid_tab_skip">%u</th>""" % goal)
3458					else:
3459						if goal==10:
3460							clist = ["10+"]
3461						else:
3462							clist = [goal]
3463					for vc in range(11):
3464						if goal==0:
3465							if vc==0:
3466								cl = "DELETEREADY"
3467								clidx = 6
3468							else:
3469								cl = "DELETEPENDING"
3470								clidx = 5
3471						elif vc==0:
3472							cl = "MISSING"
3473							clidx = 0
3474						elif vc>goal:
3475							cl = "OVERGOAL"
3476							clidx = 4
3477						elif vc<goal:
3478							if vc==1:
3479								cl = "ENDANGERED"
3480								clidx = 1
3481							else:
3482								cl = "UNDERGOAL"
3483								clidx = 2
3484						else:
3485							cl = "NORMAL"
3486							clidx = 3
3487						classsum[0][clidx]+=matrix[0][goal][vc]
3488						classsum[1][clidx]+=matrix[1][goal][vc]
3489						if cgimode:
3490							out.append("""		<td align="right" class="acid_tab_skip">""")
3491							if matrix[0][goal][vc]>0:
3492								out.append("""			<span class="%s matrix_vis0">%u</span>""" % (cl,matrix[0][goal][vc]))
3493							if matrix[1][goal][vc]>0:
3494								out.append("""			<span class="%s matrix_vis1">%u</span>""" % (cl,matrix[1][goal][vc]))
3495							out.append("""		</td>""")
3496						elif ttymode:
3497							if matrix[INmatrix][goal][vc]>0:
3498								clist.append((matrix[INmatrix][goal][vc],"1234678"[clidx]))
3499							else:
3500								clist.append("-")
3501						else:
3502							if matrix[INmatrix][goal][vc]>0:
3503								out.append("""%sgoal/copies/chunks:%s%u%s%u%s%u""" % (mtypeprefix,plaintextseparator,goal,plaintextseparator,vc,plaintextseparator,matrix[INmatrix][goal][vc]))
3504					if cgimode:
3505						if goal==0:
3506							out.append("""		<td align="right" class="acid_tab_skip">""")
3507							out.append("""			<span class="IGNORE matrix_vis0">%u</span>""" % sum(matrix[0][goal]))
3508							out.append("""			<span class="IGNORE matrix_vis1">%u</span>""" % sum(matrix[1][goal]))
3509							out.append("""		</td>""")
3510						else:
3511							out.append("""		<td align="right" class="acid_tab_skip">""")
3512							out.append("""			<span class="matrix_vis0">%u</span>""" % sum(matrix[0][goal]))
3513							out.append("""			<span class="matrix_vis1">%u</span>""" % sum(matrix[1][goal]))
3514							out.append("""		</td>""")
3515						out.append("""	</tr>""")
3516					elif ttymode:
3517						clist.append(sum(matrix[INmatrix][goal]))
3518						tab.append(*clist)
3519					if goal>0:
3520						sumlist[0] = [ a + b for (a,b) in zip(sumlist[0],matrix[0][goal])]
3521						sumlist[1] = [ a + b for (a,b) in zip(sumlist[1],matrix[1][goal])]
3522				if cgimode:
3523					out.append("""	<tr>""")
3524					out.append("""		<th align="center" class="acid_tab_skip">all 1+</th>""")
3525					for vc in range(11):
3526						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]))
3527					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])))
3528					out.append("""	</tr>""")
3529					out.append("""	<tr><th align="center" class="acid_tab_skip">colors</th><td colspan="12" class="acid_tab_skip">""")
3530					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>")
3531					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>")
3532					out.append("""	</td></tr>""")
3533					out.append("""</table>""")
3534					print("\n".join(out))
3535				elif ttymode:
3536					clist = ["all 1+"]
3537					for vc in range(11):
3538						clist.append(sumlist[INmatrix][vc])
3539					clist.append(sum(sumlist[INmatrix]))
3540					tab.append(*clist)
3541					tab.append(("---","",13))
3542					#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))
3543					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))
3544#							out.append("chunkclass missing: %s%u%s" % (colorcode[0],classsum[0],ttyreset))
3545#							out.append("chunkclass endangered: %s%u%s" % (colorcode[1],classsum[1],ttyreset))
3546#							out.append("chunkclass undergoal: %s%u%s" % (colorcode[2],classsum[2],ttyreset))
3547#							out.append("chunkclass stable: %s%u%s" % (colorcode[3],classsum[3],ttyreset))
3548#							out.append("chunkclass overgoal: %s%u%s" % (colorcode[4],classsum[4],ttyreset))
3549#							out.append("chunkclass pending deletion: %s%u%s" % (colorcode[5],classsum[5],ttyreset))
3550#							out.append("chunkclass to be removed: %s%u%s" % (colorcode[6],classsum[6],ttyreset))
3551					print(myunicode(tab))
3552				else:
3553					out.append("%schunkclass missing:%s%u" % (mtypeprefix,plaintextseparator,classsum[INmatrix][0]))
3554					out.append("%schunkclass endangered:%s%u" % (mtypeprefix,plaintextseparator,classsum[INmatrix][1]))
3555					out.append("%schunkclass undergoal:%s%u" % (mtypeprefix,plaintextseparator,classsum[INmatrix][2]))
3556					out.append("%schunkclass stable:%s%u" % (mtypeprefix,plaintextseparator,classsum[INmatrix][3]))
3557					out.append("%schunkclass overgoal:%s%u" % (mtypeprefix,plaintextseparator,classsum[INmatrix][4]))
3558					out.append("%schunkclass pending deletion:%s%u" % (mtypeprefix,plaintextseparator,classsum[INmatrix][5]))
3559					out.append("%schunkclass to be removed:%s%u" % (mtypeprefix,plaintextseparator,classsum[INmatrix][6]))
3560					print("\n".join(out))
3561		except Exception:
3562			print_exception()
3563
3564	if "IL" in sectionsubset and leaderfound:
3565		try:
3566			data,length = masterconn.command(CLTOMA_CHUNKSTEST_INFO,MATOCL_CHUNKSTEST_INFO)
3567			if length==52:
3568				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)
3569				if cgimode:
3570					out = []
3571					out.append("""<table class="FR" cellspacing="0">""")
3572					out.append("""	<tr><th colspan="8">Chunk operations info</th></tr>""")
3573					out.append("""	<tr>""")
3574					out.append("""		<th colspan="2">loop time</th>""")
3575					out.append("""		<th colspan="4">deletions</th>""")
3576					out.append("""		<th colspan="2">replications</th>""")
3577					out.append("""	</tr>""")
3578					out.append("""	<tr>""")
3579					out.append("""		<th>start</th>""")
3580					out.append("""		<th>end</th>""")
3581					out.append("""		<th>invalid</th>""")
3582					out.append("""		<th>unused</th>""")
3583					out.append("""		<th>disk clean</th>""")
3584					out.append("""		<th>over goal</th>""")
3585					out.append("""		<th>under goal</th>""")
3586					out.append("""		<th>rebalance</th>""")
3587					out.append("""	</tr>""")
3588					if loopstart>0:
3589						out.append("""	<tr>""")
3590						out.append("""		<td align="center">%s</td>""" % (time.asctime(time.localtime(loopstart)),))
3591						out.append("""		<td align="center">%s</td>""" % (time.asctime(time.localtime(loopend)),))
3592						out.append("""		<td align="right">%u/%u</td>""" % (del_invalid,del_invalid+ndel_invalid))
3593						out.append("""		<td align="right">%u/%u</td>""" % (del_unused,del_unused+ndel_unused))
3594						out.append("""		<td align="right">%u/%u</td>""" % (del_dclean,del_dclean+ndel_dclean))
3595						out.append("""		<td align="right">%u/%u</td>""" % (del_ogoal,del_ogoal+ndel_ogoal))
3596						out.append("""		<td align="right">%u/%u</td>""" % (rep_ugoal,rep_ugoal+nrep_ugoal))
3597						out.append("""		<td align="right">%u</td>""" % rebalnce)
3598						out.append("""	</tr>""")
3599					else:
3600						out.append("""	<tr>""")
3601						out.append("""		<td colspan="8" align="center">no data</td>""")
3602						out.append("""	</tr>""")
3603					out.append("""</table>""")
3604					print("\n".join(out))
3605				elif ttymode:
3606					tab = Tabble("Chunk operations info",8,"r")
3607					tab.header(("loop time","",2),("deletions","",4),("replications","",2))
3608					tab.header(("---","",8))
3609					tab.header("start","end","invalid","unused","disk clean","over goal","under goal","rebalance")
3610					if loopstart>0:
3611						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)
3612					else:
3613						tab.append(("no data","c",8))
3614					print(myunicode(tab))
3615				else:
3616					out = []
3617					if loopstart>0:
3618						out.append("""chunk loop%sstart:%s%u""" % (plaintextseparator,plaintextseparator,loopstart))
3619						out.append("""chunk loop%send:%s%u""" % (plaintextseparator,plaintextseparator,loopend))
3620						out.append("""chunk loop%sdeletions%sinvalid:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_invalid,del_invalid+ndel_invalid))
3621						out.append("""chunk loop%sdeletions%sunused:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_unused,del_unused+ndel_unused))
3622						out.append("""chunk loop%sdeletions%sdisk clean:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_dclean,del_dclean+ndel_dclean))
3623						out.append("""chunk loop%sdeletions%sover goal:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_ogoal,del_ogoal+ndel_ogoal))
3624						out.append("""chunk loop%sreplications%sunder goal:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,rep_ugoal,rep_ugoal+nrep_ugoal))
3625						out.append("""chunk loop%sreplications%srebalance:%s%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,rebalnce))
3626					else:
3627						out.append("""chunk loop%sno data""" % plaintextseparator)
3628					print("\n".join(out))
3629			elif length==60:
3630				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)
3631				if cgimode:
3632					out = []
3633					out.append("""<table class="FR" cellspacing="0">""")
3634					out.append("""	<tr><th colspan="10">Chunk operations info</th></tr>""")
3635					out.append("""	<tr>""")
3636					out.append("""		<th colspan="2">loop time</th>""")
3637					out.append("""		<th colspan="4">deletions</th>""")
3638					out.append("""		<th colspan="2">replications</th>""")
3639					out.append("""		<th colspan="2">locked</th>""")
3640					out.append("""	</tr>""")
3641					out.append("""	<tr>""")
3642					out.append("""		<th>start</th>""")
3643					out.append("""		<th>end</th>""")
3644					out.append("""		<th>invalid</th>""")
3645					out.append("""		<th>unused</th>""")
3646					out.append("""		<th>disk clean</th>""")
3647					out.append("""		<th>over goal</th>""")
3648					out.append("""		<th>under goal</th>""")
3649					out.append("""		<th>rebalance</th>""")
3650					out.append("""		<th>unused</th>""")
3651					out.append("""		<th>used</th>""")
3652					out.append("""	</tr>""")
3653					if loopstart>0:
3654						out.append("""	<tr>""")
3655						out.append("""		<td align="center">%s</td>""" % (time.asctime(time.localtime(loopstart)),))
3656						out.append("""		<td align="center">%s</td>""" % (time.asctime(time.localtime(loopend)),))
3657						out.append("""		<td align="right">%u/%u</td>""" % (del_invalid,del_invalid+ndel_invalid))
3658						out.append("""		<td align="right">%u/%u</td>""" % (del_unused,del_unused+ndel_unused))
3659						out.append("""		<td align="right">%u/%u</td>""" % (del_dclean,del_dclean+ndel_dclean))
3660						out.append("""		<td align="right">%u/%u</td>""" % (del_ogoal,del_ogoal+ndel_ogoal))
3661						out.append("""		<td align="right">%u/%u</td>""" % (rep_ugoal,rep_ugoal+nrep_ugoal))
3662						out.append("""		<td align="right">%u</td>""" % rebalnce)
3663						out.append("""		<td align="right">%u</td>""" % locked_unused)
3664						out.append("""		<td align="right">%u</td>""" % locked_used)
3665						out.append("""	</tr>""")
3666					else:
3667						out.append("""	<tr>""")
3668						out.append("""		<td colspan="10" align="center">no data</td>""")
3669						out.append("""	</tr>""")
3670					out.append("""</table>""")
3671					print("\n".join(out))
3672				elif ttymode:
3673					tab = Tabble("Chunk operations info",10,"r")
3674					tab.header(("loop time","",2),("deletions","",4),("replications","",2),("locked","",2))
3675					tab.header(("---","",10))
3676					tab.header("start","end","invalid","unused","disk clean","over goal","under goal","rebalance","unused","used")
3677					if loopstart>0:
3678						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)
3679					else:
3680						tab.append(("no data","c",10))
3681					print(myunicode(tab))
3682				else:
3683					out = []
3684					if loopstart>0:
3685						out.append("""chunk loop%sstart:%s%u""" % (plaintextseparator,plaintextseparator,loopstart))
3686						out.append("""chunk loop%send:%s%u""" % (plaintextseparator,plaintextseparator,loopend))
3687						out.append("""chunk loop%sdeletions%sinvalid:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_invalid,del_invalid+ndel_invalid))
3688						out.append("""chunk loop%sdeletions%sunused:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_unused,del_unused+ndel_unused))
3689						out.append("""chunk loop%sdeletions%sdisk clean:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_dclean,del_dclean+ndel_dclean))
3690						out.append("""chunk loop%sdeletions%sover goal:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_ogoal,del_ogoal+ndel_ogoal))
3691						out.append("""chunk loop%sreplications%sunder goal:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,rep_ugoal,rep_ugoal+nrep_ugoal))
3692						out.append("""chunk loop%sreplications%srebalance:%s%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,rebalnce))
3693						out.append("""chunk loop%slocked%sunused:%s%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,locked_unused))
3694						out.append("""chunk loop%slocked%sused:%s%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,locked_used))
3695					else:
3696						out.append("""chunk loop%sno data""" % plaintextseparator)
3697					print("\n".join(out))
3698			elif length==72:
3699				loopstart,loopend,del_invalid,ndel_invalid,del_unused,ndel_unused,del_dclean,ndel_dclean,del_ogoal,ndel_ogoal,rep_ugoal,nrep_ugoal,rep_wlab,nrep_wlab,rebalnce,labels_dont_match,locked_unused,locked_used = struct.unpack(">LLLLLLLLLLLLLLLLLL",data)
3700				if cgimode:
3701					out = []
3702					out.append("""<table class="FR" cellspacing="0">""")
3703					out.append("""	<tr><th colspan="11">Chunk operations info</th></tr>""")
3704					out.append("""	<tr>""")
3705					out.append("""		<th colspan="2">loop time</th>""")
3706					out.append("""		<th colspan="4">deletions</th>""")
3707					out.append("""		<th colspan="3">replications</th>""")
3708					out.append("""		<th colspan="2">locked</th>""")
3709					out.append("""	</tr>""")
3710					out.append("""	<tr>""")
3711					out.append("""		<th>start</th>""")
3712					out.append("""		<th>end</th>""")
3713					out.append("""		<th>invalid</th>""")
3714					out.append("""		<th>unused</th>""")
3715					out.append("""		<th>disk clean</th>""")
3716					out.append("""		<th>over goal</th>""")
3717					out.append("""		<th>under goal</th>""")
3718					out.append("""		<th>wrong labels</th>""")
3719					out.append("""		<th>rebalance</th>""")
3720					out.append("""		<th>unused</th>""")
3721					out.append("""		<th>used</th>""")
3722					out.append("""	</tr>""")
3723					if loopstart>0:
3724						out.append("""	<tr>""")
3725						out.append("""		<td align="center">%s</td>""" % (time.asctime(time.localtime(loopstart)),))
3726						out.append("""		<td align="center">%s</td>""" % (time.asctime(time.localtime(loopend)),))
3727						out.append("""		<td align="right">%u/%u</td>""" % (del_invalid,del_invalid+ndel_invalid))
3728						out.append("""		<td align="right">%u/%u</td>""" % (del_unused,del_unused+ndel_unused))
3729						out.append("""		<td align="right">%u/%u</td>""" % (del_dclean,del_dclean+ndel_dclean))
3730						out.append("""		<td align="right">%u/%u</td>""" % (del_ogoal,del_ogoal+ndel_ogoal))
3731						out.append("""		<td align="right">%u/%u</td>""" % (rep_ugoal,rep_ugoal+nrep_ugoal))
3732						out.append("""		<td align="right">%u/%u/%u</td>""" % (rep_wlab,labels_dont_match,rep_wlab+nrep_wlab+labels_dont_match))
3733						out.append("""		<td align="right">%u</td>""" % rebalnce)
3734						out.append("""		<td align="right">%u</td>""" % locked_unused)
3735						out.append("""		<td align="right">%u</td>""" % locked_used)
3736						out.append("""	</tr>""")
3737					else:
3738						out.append("""	<tr>""")
3739						out.append("""		<td colspan="11" align="center">no data</td>""")
3740						out.append("""	</tr>""")
3741					out.append("""</table>""")
3742					print("\n".join(out))
3743				elif ttymode:
3744					tab = Tabble("Chunk operations info",11,"r")
3745					tab.header(("loop time","",2),("deletions","",4),("replications","",3),("locked","",2))
3746					tab.header(("---","",11))
3747					tab.header("start","end","invalid","unused","disk clean","over goal","under goal","wrong labels","rebalance","unused","used")
3748					if loopstart>0:
3749						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),"%u/%u/%u" % (rep_wlab,labels_dont_match,rep_wlab+nrep_wlab+labels_dont_match),rebalnce,locked_unused,locked_used)
3750					else:
3751						tab.append(("no data","c",11))
3752					print(myunicode(tab))
3753				else:
3754					out = []
3755					if loopstart>0:
3756						out.append("""chunk loop%sstart:%s%u""" % (plaintextseparator,plaintextseparator,loopstart))
3757						out.append("""chunk loop%send:%s%u""" % (plaintextseparator,plaintextseparator,loopend))
3758						out.append("""chunk loop%sdeletions%sinvalid:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_invalid,del_invalid+ndel_invalid))
3759						out.append("""chunk loop%sdeletions%sunused:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_unused,del_unused+ndel_unused))
3760						out.append("""chunk loop%sdeletions%sdisk clean:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_dclean,del_dclean+ndel_dclean))
3761						out.append("""chunk loop%sdeletions%sover goal:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,del_ogoal,del_ogoal+ndel_ogoal))
3762						out.append("""chunk loop%sreplications%sunder goal:%s%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,rep_ugoal,rep_ugoal+nrep_ugoal))
3763						out.append("""chunk loop%sreplications%swrong labels:%s%u/%u/%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,rep_wlab,labels_dont_match,rep_wlab+nrep_wlab+labels_dont_match))
3764						out.append("""chunk loop%sreplications%srebalance:%s%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,rebalnce))
3765						out.append("""chunk loop%slocked%sunused:%s%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,locked_unused))
3766						out.append("""chunk loop%slocked%sused:%s%u""" % (plaintextseparator,plaintextseparator,plaintextseparator,locked_used))
3767					else:
3768						out.append("""chunk loop%sno data""" % plaintextseparator)
3769					print("\n".join(out))
3770		except Exception:
3771			print_exception()
3772
3773		try:
3774			if (masterconn.version_at_least(2,0,66) and masterconn.version_less_than(3,0,0)) or masterconn.version_at_least(3,0,19):
3775				data,length = masterconn.command(CLTOMA_FSTEST_INFO,MATOCL_FSTEST_INFO,struct.pack(">B",0))
3776				pver = 1
3777			else:
3778				data,length = masterconn.command(CLTOMA_FSTEST_INFO,MATOCL_FSTEST_INFO)
3779				pver = 0
3780			if length>=(36 + pver*8):
3781				if pver==1:
3782					loopstart,loopend,files,ugfiles,mfiles,mtfiles,msfiles,chunks,ugchunks,mchunks,msgbuffleng = struct.unpack(">LLLLLLLLLLL",data[:44])
3783					datastr = data[44:].decode('utf-8','replace')
3784				else:
3785					loopstart,loopend,files,ugfiles,mfiles,chunks,ugchunks,mchunks,msgbuffleng = struct.unpack(">LLLLLLLLL",data[:36])
3786					datastr = data[36:].decode('utf-8','replace')
3787				if cgimode:
3788					out = []
3789					out.append("""<table class="FR" cellspacing="0">""")
3790					out.append("""	<tr><th colspan="%u">Filesystem check info</th></tr>""" % (8 if pver==0 else 10))
3791					out.append("""	<tr>""")
3792					out.append("""		<th>check loop start time</th>""")
3793					out.append("""		<th>check loop end time</th>""")
3794					out.append("""		<th>files</th>""")
3795					out.append("""		<th>under-goal files</th>""")
3796					out.append("""		<th>missing files</th>""")
3797					if pver==1:
3798						out.append("""		<th>missing trash files</th>""")
3799						out.append("""		<th>missing sustained files</th>""")
3800					out.append("""		<th>chunks</th>""")
3801					out.append("""		<th>under-goal chunks</th>""")
3802					out.append("""		<th>missing chunks</th>""")
3803					out.append("""	</tr>""")
3804					if loopstart>0:
3805						out.append("""	<tr>""")
3806						out.append("""		<td align="center">%s</td>""" % (time.asctime(time.localtime(loopstart)),))
3807						out.append("""		<td align="center">%s</td>""" % (time.asctime(time.localtime(loopend)),))
3808						out.append("""		<td align="right">%u</td>""" % files)
3809						out.append("""		<td align="right">%u</td>""" % ugfiles)
3810						out.append("""		<td align="right">%u</td>""" % mfiles)
3811						if pver==1:
3812							out.append("""		<td align="right">%u</td>""" % mtfiles)
3813							out.append("""		<td align="right">%u</td>""" % msfiles)
3814						out.append("""		<td align="right">%u</td>""" % chunks)
3815						out.append("""		<td align="right">%u</td>""" % ugchunks)
3816						out.append("""		<td align="right">%u</td>""" % mchunks)
3817						out.append("""	</tr>""")
3818						if msgbuffleng>0:
3819							if msgbuffleng==100000:
3820								out.append("""	<tr><th colspan="8">Important messages (first 100k):</th></tr>""")
3821							else:
3822								out.append("""	<tr><th colspan="8">Important messages:</th></tr>""")
3823							out.append("""	<tr>""")
3824							out.append("""		<td colspan="8" align="left"><pre>%s</pre></td>""" % (datastr.replace("&","&amp;").replace(">","&gt;").replace("<","&lt;")))
3825							out.append("""	</tr>""")
3826					else:
3827						out.append("""	<tr>""")
3828						out.append("""		<td colspan="%u" align="center">no data</td>""" % (8 if pver==0 else 10))
3829						out.append("""	</tr>""")
3830					out.append("""</table>""")
3831					print("\n".join(out))
3832				elif ttymode:
3833					if pver==1:
3834						tab = Tabble("Filesystem check info",10,"r")
3835						tabwidth = 10
3836						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")
3837					else:
3838						tab = Tabble("Filesystem check info",8,"r")
3839						tabwidth = 8
3840						tab.header("check loop start time","check loop end time","files","under-goal files","missing files","chunks","under-goal chunks","missing chunks")
3841					if loopstart>0:
3842						if pver==1:
3843							tab.append((time.asctime(time.localtime(loopstart)),"c"),(time.asctime(time.localtime(loopend)),"c"),files,ugfiles,mfiles,mtfiles,msfiles,chunks,ugchunks,mchunks)
3844						else:
3845							tab.append((time.asctime(time.localtime(loopstart)),"c"),(time.asctime(time.localtime(loopend)),"c"),files,ugfiles,mfiles,chunks,ugchunks,mchunks)
3846						if msgbuffleng>0:
3847							tab.append(("---","",tabwidth))
3848							if msgbuffleng==100000:
3849								tab.append(("Important messages (first 100k):","c",tabwidth))
3850							else:
3851								tab.append(("Important messages:","c",tabwidth))
3852							tab.append(("---","",tabwidth))
3853							for line in datastr.strip().split("\n"):
3854								tab.append((line.strip(),"l",tabwidth))
3855					else:
3856						tab.append(("no data","c",tabwidth))
3857					print(myunicode(tab))
3858				else:
3859					out = []
3860					if loopstart>0:
3861						out.append("""check loop%sstart:%s%u""" % (plaintextseparator,plaintextseparator,loopstart))
3862						out.append("""check loop%send:%s%u""" % (plaintextseparator,plaintextseparator,loopend))
3863						out.append("""check loop%sfiles:%s%u""" % (plaintextseparator,plaintextseparator,files))
3864						out.append("""check loop%sunder-goal files:%s%u""" % (plaintextseparator,plaintextseparator,ugfiles))
3865						out.append("""check loop%smissing files:%s%u""" % (plaintextseparator,plaintextseparator,mfiles))
3866						if pver==1:
3867							out.append("""check loop%smissing trash files:%s%u""" % (plaintextseparator,plaintextseparator,mtfiles))
3868							out.append("""check loop%smissing sustained files:%s%u""" % (plaintextseparator,plaintextseparator,msfiles))
3869						out.append("""check loop%schunks:%s%u""" % (plaintextseparator,plaintextseparator,chunks))
3870						out.append("""check loop%sunder-goal chunks:%s%u""" % (plaintextseparator,plaintextseparator,ugchunks))
3871						out.append("""check loop%smissing chunks:%s%u""" % (plaintextseparator,plaintextseparator,mchunks))
3872						if msgbuffleng>0:
3873							for line in datastr.strip().split("\n"):
3874								out.append("check loop%simportant messages:%s%s" % (plaintextseparator,plaintextseparator,line.strip()))
3875					else:
3876						out.append("""check loop: no data""")
3877					print("\n".join(out))
3878		except Exception:
3879			print_exception()
3880
3881	if "MF" in sectionsubset and leaderfound and ((masterconn.version_at_least(2,0,66) and masterconn.version_less_than(3,0,0)) or masterconn.version_at_least(3,0,19)):
3882		try:
3883			inodes = set()
3884			missingchunks = []
3885			if ((masterconn.version_at_least(2,0,71) and masterconn.version_less_than(3,0,0)) or masterconn.version_at_least(3,0,25)):
3886				data,length = masterconn.command(CLTOMA_MISSING_CHUNKS,MATOCL_MISSING_CHUNKS,struct.pack(">B",1))
3887				if length%17==0:
3888					n = length//17
3889					for x in xrange(n):
3890						chunkid,inode,indx,mtype = struct.unpack(">QLLB",data[x*17:x*17+17])
3891						inodes.add(inode)
3892						missingchunks.append((chunkid,inode,indx,mtype))
3893				mode = 1
3894			else:
3895				data,length = masterconn.command(CLTOMA_MISSING_CHUNKS,MATOCL_MISSING_CHUNKS)
3896				if length%16==0:
3897					n = length//16
3898					for x in xrange(n):
3899						chunkid,inode,indx = struct.unpack(">QLL",data[x*16:x*16+16])
3900						inodes.add(inode)
3901						missingchunks.append((chunkid,inode,indx,None))
3902				mode = 0
3903			inodepaths = resolve_inodes_paths(masterconn,inodes)
3904			mcdata = []
3905			mccnt = 0
3906			for chunkid,inode,indx,mtype in missingchunks:
3907				if inode in inodepaths:
3908					paths = inodepaths[inode]
3909					mccnt += len(paths)
3910				else:
3911					paths = []
3912					mccnt += 1
3913				sf = paths
3914				if MForder==1:
3915					sf = paths
3916				elif MForder==2:
3917					sf = inode
3918				elif MForder==3:
3919					sf = indx
3920				elif MForder==4:
3921					sf = chunkid
3922				elif MForder==5:
3923					sf = mtype
3924				mcdata.append((sf,paths,inode,indx,chunkid,mtype))
3925			mcdata.sort()
3926			if MFrev:
3927				mcdata.reverse()
3928			if cgimode:
3929				out = []
3930				if mccnt>0:
3931					out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_missingfiles" cellspacing="0">""")
3932					if MFlimit>0 and mccnt>MFlimit:
3933						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"})))
3934					else:
3935						out.append("""	<tr><th colspan="%u">Missing files (gathered by previous file-loop)</th></tr>""" % (6 if mode==1 else 5))
3936					out.append("""	<tr>""")
3937					out.append("""		<th rowspan="2" class="acid_tab_enumerate">#</th>""")
3938					out.append("""		<th rowspan="2">paths</th>""")
3939					out.append("""		<th rowspan="2">inode</th>""")
3940					out.append("""		<th rowspan="2">index</th>""")
3941					out.append("""		<th rowspan="2">chunk&nbsp;id</th>""")
3942					if mode==1:
3943						out.append("""		<th rowspan="2">type&nbsp;of&nbsp;missing&nbsp;chunk</th>""")
3944					out.append("""	</tr>""")
3945			elif ttymode:
3946				if mode==1:
3947					tab = Tabble("Missing Files/Chunks (gathered by previous file-loop)",5)
3948					tab.header("path","inode","index","chunk id","type of missing chunk")
3949					tab.defattr("l","r","r","r","r")
3950				else:
3951					tab = Tabble("Missing Files/Chunks (gathered by previous file-loop)",4)
3952					tab.header("path","inode","index","chunk id")
3953					tab.defattr("l","r","r","r")
3954			else:
3955				tab = Tabble("missing files",(5 if mode==1 else 4))
3956			missingcount = 0
3957			for sf,paths,inode,indx,chunkid,mtype in mcdata:
3958				if mtype==0:
3959					mtypestr = "NO COPY"
3960				elif mtype==1:
3961					mtypestr = "INVALID COPIES"
3962				elif mtype==2:
3963					mtypestr = "WRONG VERSIONS"
3964				else:
3965					mtypestr = "OTHER"
3966				if cgimode:
3967					if mccnt>0:
3968						if len(paths)==0:
3969							if missingcount<MFlimit or MFlimit==0:
3970								out.append("""	<tr>""")
3971								out.append("""		<td align="right"></td>""")
3972								out.append("""		<td align="left"> * unknown path * (deleted file)</td>""")
3973								out.append("""		<td align="right">%u</td>""" % inode)
3974								out.append("""		<td align="right">%u</td>""" % indx)
3975								out.append("""		<td align="right">%016X</td>""" % chunkid)
3976								if mode==1:
3977									out.append("""		<td align="right">%s</td>""" % mtypestr)
3978								out.append("""	</tr>""")
3979							missingcount += 1
3980						else:
3981							for path in paths:
3982								if missingcount<MFlimit or MFlimit==0:
3983									out.append("""	<tr>""")
3984									out.append("""		<td align="right"></td>""")
3985									out.append("""		<td align="left">%s</td>""" % path)
3986									out.append("""		<td align="right">%u</td>""" % inode)
3987									out.append("""		<td align="right">%u</td>""" % indx)
3988									out.append("""		<td align="right">%016X</td>""" % chunkid)
3989									if mode==1:
3990										out.append("""		<td align="right">%s</td>""" % mtypestr)
3991									out.append("""	</tr>""")
3992								missingcount += 1
3993				else:
3994					if len(paths)==0:
3995						dline = [" * unknown path * (deleted file)",inode,indx,"%016X" % chunkid]
3996						if mode==1:
3997							dline.append(mtypestr)
3998						tab.append(*dline)
3999					else:
4000						for path in paths:
4001							dline = [path,inode,indx,"%016X" % chunkid]
4002							if mode==1:
4003								dline.append(mtypestr)
4004							tab.append(*dline)
4005			if cgimode:
4006				if mccnt>0:
4007					out.append("""</table>""")
4008				print("\n".join(out))
4009			else:
4010				print(myunicode(tab))
4011		except Exception:
4012			print_exception()
4013
4014if "CS" in sectionset:
4015	if "CS" in sectionsubset:
4016		try:
4017			if cgimode:
4018				out = []
4019				out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfscs" cellspacing="0">""")
4020				if masterconn.version_at_least(3,0,38):
4021					out.append("""	<tr><th colspan="19">Chunk Servers</th></tr>""")
4022				elif masterconn.version_at_least(2,1,0):
4023					out.append("""	<tr><th colspan="18">Chunk Servers</th></tr>""")
4024				elif masterconn.version_at_least(2,0,11):
4025					out.append("""	<tr><th colspan="17">Chunk Servers</th></tr>""")
4026				elif masterconn.version_at_least(1,7,25):
4027					out.append("""	<tr><th colspan="16">Chunk Servers</th></tr>""")
4028				elif masterconn.version_at_least(1,6,28):
4029					out.append("""	<tr><th colspan="15">Chunk Servers</th></tr>""")
4030				else:
4031					out.append("""	<tr><th colspan="14">Chunk Servers</th></tr>""")
4032				out.append("""	<tr>""")
4033				out.append("""		<th rowspan="2" class="acid_tab_enumerate">#</th>""")
4034				out.append("""		<th rowspan="2">host</th>""")
4035				out.append("""		<th rowspan="2">ip</th>""")
4036				out.append("""		<th rowspan="2">port</th>""")
4037				if masterconn.version_at_least(1,7,25):
4038					out.append("""		<th rowspan="2">id</th>""")
4039				if masterconn.version_at_least(2,1,0):
4040					out.append("""		<th rowspan="2">labels</th>""")
4041				out.append("""		<th rowspan="2">version</th>""")
4042				if masterconn.version_at_least(1,6,28):
4043					out.append("""		<th rowspan="2">load</th>""")
4044				if masterconn.version_at_least(2,0,11):
4045					out.append("""		<th rowspan="2">maintenance</th>""")
4046				out.append("""		<th colspan="4">'regular' hdd space</th>""")
4047				if masterconn.version_at_least(3,0,38):
4048					out.append("""		<th colspan="5">'marked for removal' hdd space</th>""")
4049				else:
4050					out.append("""		<th colspan="4">'marked for removal' hdd space</th>""")
4051				out.append("""	</tr>""")
4052				out.append("""	<tr>""")
4053				out.append("""		<th>chunks</th>""")
4054				out.append("""		<th>used</th>""")
4055				out.append("""		<th>total</th>""")
4056				out.append("""		<th class="PROGBAR">% used</th>""")
4057				if masterconn.version_at_least(3,0,38):
4058					out.append("""		<th>status</th>""")
4059				out.append("""		<th>chunks</th>""")
4060				out.append("""		<th>used</th>""")
4061				out.append("""		<th>total</th>""")
4062				out.append("""		<th class="PROGBAR">% used</th>""")
4063				out.append("""	</tr>""")
4064			elif ttymode:
4065				if masterconn.version_at_least(3,0,38):
4066					tab = Tabble("Chunk Servers",16,"r")
4067					tab.header("","","","","","","",("'regular' hdd space","",4),("'marked for removal' hdd space","",5))
4068					tab.header("ip/host","port","id","labels","version","load","maintenance",("---","",9))
4069					tab.header("","","","","","","","chunks","used","total","% used","status","chunks","used","total","% used")
4070				elif masterconn.version_at_least(2,1,0):
4071					tab = Tabble("Chunk Servers",15,"r")
4072					tab.header("","","","","","","",("'regular' hdd space","",4),("'marked for removal' hdd space","",4))
4073					tab.header("ip/host","port","id","labels","version","load","maintenance",("---","",8))
4074					tab.header("","","","","","","","chunks","used","total","% used","chunks","used","total","% used")
4075				elif masterconn.version_at_least(2,0,11):
4076					tab = Tabble("Chunk Servers",14,"r")
4077					tab.header("","","","","","",("'regular' hdd space","",4),("'marked for removal' hdd space","",4))
4078					tab.header("ip/host","port","id","version","load","maintenance",("---","",8))
4079					tab.header("","","","","","","chunks","used","total","% used","chunks","used","total","% used")
4080				elif masterconn.version_at_least(1,7,25):
4081					tab = Tabble("Chunk Servers",13,"r")
4082					tab.header("","","","","",("'regular' hdd space","",4),("'marked for removal' hdd space","",4))
4083					tab.header("ip/host","port","id","version","load",("---","",8))
4084					tab.header("","","","","","chunks","used","total","% used","chunks","used","total","% used")
4085				elif masterconn.version_at_least(1,6,28):
4086					tab = Tabble("Chunk Servers",12,"r")
4087					tab.header("","","","",("'regular' hdd space","",4),("'marked for removal' hdd space","",4))
4088					tab.header("ip/host","port","version","load",("---","",8))
4089					tab.header("","","","","chunks","used","total","% used","chunks","used","total","% used")
4090				else:
4091					tab = Tabble("Chunk Servers",11,"r")
4092					tab.header("","","",("'regular' hdd space","",4),("'marked for removal' hdd space","",4))
4093					tab.header("ip/host","port","version",("---","",8))
4094					tab.header("","","","chunks","used","total","% used","chunks","used","total","% used")
4095			else:
4096				if masterconn.version_at_least(3,0,38):
4097					tab = Tabble("chunk servers",14)
4098				elif masterconn.version_at_least(2,1,0):
4099					tab = Tabble("chunk servers",13)
4100				elif masterconn.version_at_least(2,0,11):
4101					tab = Tabble("chunk servers",12)
4102				elif masterconn.version_at_least(1,7,25):
4103					tab = Tabble("chunk servers",11)
4104				elif masterconn.version_at_least(1,6,28):
4105					tab = Tabble("chunk servers",10)
4106				else:
4107					tab = Tabble("chunk servers",9)
4108			servers = []
4109			dservers = []
4110			usedsum = 0
4111			totalsum = 0
4112			for cs in dataprovider.get_chunkservers():
4113				if cs.total>0:
4114					usedsum+=cs.used
4115					totalsum+=cs.total
4116				if CSorder==1:
4117					sf = cs.host
4118				elif CSorder==2 or CSorder==0:
4119					sf = cs.sortip
4120				elif CSorder==3:
4121					sf = cs.port
4122				elif CSorder==4:
4123					sf = cs.csid
4124				elif CSorder==5:
4125					sf = cs.sortver
4126				elif CSorder==6:
4127					sf = (cs.gracetime,cs.load)
4128				elif CSorder==10:
4129					sf = cs.chunks
4130				elif CSorder==11:
4131					sf = cs.used
4132				elif CSorder==12:
4133					sf = cs.total
4134				elif CSorder==13:
4135					if cs.total>0:
4136						sf = (1.0*cs.used)/cs.total
4137					else:
4138						sf = 0
4139				elif CSorder==20:
4140					sf = cs.tdchunks
4141				elif CSorder==21:
4142					sf = cs.tdused
4143				elif CSorder==22:
4144					sf = cs.tdtotal
4145				elif CSorder==23:
4146					if cs.tdtotal>0:
4147						sf = (1.0*cs.tdused)/cs.tdtotal
4148					else:
4149						sf = 0
4150				else:
4151					sf = 0
4152				if (cs.flags&1)==0:
4153					servers.append((sf,cs.host,cs.sortip,cs.strip,cs.port,cs.csid,cs.sortver,cs.strver,cs.flags,cs.used,cs.total,cs.chunks,cs.tdused,cs.tdtotal,cs.tdchunks,cs.errcnt,cs.load,cs.gracetime,cs.labels,cs.mfrstatus))
4154				else:
4155					dservers.append((sf,cs.host,cs.sortip,cs.strip,cs.port,cs.csid,cs.flags))
4156			servers.sort()
4157			dservers.sort()
4158			if CSrev:
4159				servers.reverse()
4160				dservers.reverse()
4161			if totalsum>0:
4162				avgpercent = (usedsum*100.0)/totalsum
4163			else:
4164				avgpercent = 0
4165			for sf,host,sortip,strip,port,csid,sortver,strver,flags,used,total,chunks,tdused,tdtotal,tdchunks,errcnt,load,gracetime,labels,mfrstatus in servers:
4166				if cgimode:
4167					if masterconn.is_pro() and not strver.endswith(" PRO"):
4168						verclass = "BADVERSION"
4169					elif masterconn.sort_ver() > sortver:
4170						verclass = "LOWERVERSION"
4171					elif masterconn.sort_ver() < sortver:
4172						verclass = "HIGHERVERSION"
4173					else:
4174						verclass = "OKVERSION"
4175					if masterconn.version_at_least(2,0,11) and leaderfound:
4176						if (flags&2)==0:
4177							mmstr = "OFF"
4178							mm = "switch on"
4179							mmurl = createlink({"CSmaintenanceon":("%s:%u" % (strip,port))})
4180							cl = None
4181						elif (flags&4)==0:
4182							mmstr = "ON"
4183							mm = "switch off"
4184							mmurl = createlink({"CSmaintenanceoff":("%s:%u" % (strip,port))})
4185							cl = "MAINTAINREADY"
4186						else:
4187							mmstr = "ON (TEMP)"
4188							mm = "switch off"
4189							mmurl = createlink({"CSmaintenanceoff":("%s:%u" % (strip,port))})
4190							cl = "MAINTAINREADY"
4191					else:
4192						cl = None
4193					out.append("""	<tr>""")
4194					out.append("""		<td align="right"></td>""")
4195					if cl:
4196						out.append("""		<td align="left"><span class="%s">%s</span></td>""" % (cl,host))
4197						out.append("""		<td align="center"><span class="sortkey">%s </span><span class="%s">%s</span></td>""" % (sortip,cl,strip))
4198						out.append("""		<td align="center"><span class="%s">%u</span></td>""" % (cl,port))
4199						if masterconn.version_at_least(1,7,25):
4200							out.append("""		<td align="center"><span class="%s">%u</span></td>""" % (cl,csid))
4201					else:
4202						out.append("""		<td align="left">%s</td>""" % (host))
4203						out.append("""		<td align="center"><span class="sortkey">%s </span>%s</td>""" % (sortip,strip))
4204						out.append("""		<td align="center">%u</td>""" % (port))
4205						if masterconn.version_at_least(1,7,25):
4206							out.append("""		<td align="center">%u</td>""" % (csid))
4207					if masterconn.version_at_least(2,1,0):
4208						if labels==0:
4209							labelstr = "-"
4210						else:
4211							labelstab = []
4212							for bit,char in enumerate(map(chr,range(ord('A'),ord('Z')+1))):
4213								if labels & (1<<bit):
4214									labelstab.append(char)
4215							labelstr = ",".join(labelstab)
4216						out.append("""		<td align="left">%s</td>""" % labelstr)
4217					out.append("""		<td align="center"><span class="sortkey">%s </span><span class="%s">%s</span></td>""" % (sortver,verclass,strver))
4218					if masterconn.version_at_least(1,6,28):
4219						if gracetime>=0x80000000:
4220							if gracetime>=0xC0000000:
4221								out.append("""		<td align="right"><a style="cursor:default" title="server in heavy load state"><span class="GRACETIME">&lt;%u&gt;</span></a></td>""" % (load))
4222							else:
4223								out.append("""		<td align="right"><a style="cursor:default" title="internal rebalance in progress"><span class="GRACETIME">(%u)</span></a></td>""" % (load))
4224						elif gracetime>0:
4225							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))
4226						else:
4227							out.append("""		<td align="right">%u</td>""" % (load))
4228					if masterconn.version_at_least(2,0,11):
4229						if leaderfound:
4230							out.append("""		<td align="center">%s : <a href="%s">%s</a></td>""" % (mmstr,mmurl,mm))
4231						else:
4232							out.append("""		<td align="center">not available</td>""")
4233					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;")))
4234					if (total>0):
4235						usedpercent = (used*100.0)/total
4236						if usedpercent<avgpercent:
4237							diffstr = "&#8722;%.4f" % (avgpercent-usedpercent)
4238						else:
4239							diffstr = "+%.4f" % (usedpercent-avgpercent)
4240						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))
4241					else:
4242						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>""")
4243					if masterconn.version_at_least(3,0,38):
4244						if tdchunks==0 or leaderfound==0:
4245							out.append("""		<td align="center">-</td>""")
4246						elif mfrstatus==1:
4247							out.append("""		<td align="center"><a style="cursor:default" title="disks can not be safely removed - please wait"><span class="NOTICE">NOT&nbsp;READY</span></a></td>""")
4248						elif mfrstatus==2:
4249							out.append("""		<td align="center"><a style="cursor:default" title="all disks marked for removal can be safely removed"><span class="OK">READY</span></a></td>""")
4250						else:
4251							out.append("""		<td align="center"><a style="cursor:default" title="wait for chunk loop finish to stabilize state">PENDING</a></td>""")
4252					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;")))
4253					if (tdtotal>0):
4254						usedpercent = (tdused*100.0)/tdtotal
4255						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))
4256					else:
4257						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>""")
4258					out.append("""	</tr>""")
4259				elif ttymode:
4260					if total>0:
4261						regperc = "%.2f%%" % ((used*100.0)/total)
4262					else:
4263						regperc = "-"
4264					if tdtotal>0:
4265						tdperc = "%.2f%%" % ((tdused*100.0)/tdtotal)
4266					else:
4267						tdperc = "-"
4268					data = [host,port]
4269					if masterconn.version_at_least(1,7,25):
4270						data.append(csid)
4271					if masterconn.version_at_least(2,1,0):
4272						if labels==0xFFFFFFFF or labels==0:
4273							labelstr = "-"
4274						else:
4275							labelstab = []
4276							for bit,char in enumerate(map(chr,range(ord('A'),ord('Z')+1))):
4277								if labels & (1<<bit):
4278									labelstab.append(char)
4279							labelstr = ",".join(labelstab)
4280						data.append(labelstr)
4281					data.append(strver)
4282					if masterconn.version_at_least(1,6,28):
4283						if gracetime>=0x80000000:
4284							if gracetime>=0xC0000000:
4285								data.append("<%u>" % load)
4286							else:
4287								data.append("(%u)" % load)
4288						elif gracetime>0:
4289							data.append("[%u]" % load)
4290						else:
4291							data.append(load)
4292					if masterconn.version_at_least(2,0,11):
4293						if leaderfound==0:
4294							data.append("not available")
4295						elif (flags&2)==0:
4296							data.append("off")
4297						elif (flags&4)==0:
4298							data.append("on")
4299						else:
4300							data.append("on (temp)")
4301					data.extend([chunks,humanize_number(used," "),humanize_number(total," "),regperc])
4302					if masterconn.version_at_least(3,0,38):
4303						if tdchunks==0 or leaderfound==0:
4304							data.append("-")
4305						elif mfrstatus==1:
4306							data.append(("NOT READY",'3'))
4307						elif mfrstatus==2:
4308							data.append(("READY",'4'))
4309						else:
4310							data.append("PENDING")
4311					data.extend([tdchunks,humanize_number(tdused," "),humanize_number(tdtotal," "),tdperc])
4312					tab.append(*data)
4313				else:
4314					data = [host,port]
4315					if masterconn.version_at_least(1,7,25):
4316						data.append(csid)
4317					if masterconn.version_at_least(2,1,0):
4318						if labels==0xFFFFFFFF or labels==0:
4319							labelstr = "-"
4320						else:
4321							labelstab = []
4322							for bit,char in enumerate(map(chr,range(ord('A'),ord('Z')+1))):
4323								if labels & (1<<bit):
4324									labelstab.append(char)
4325							labelstr = ",".join(labelstab)
4326						data.append(labelstr)
4327					data.append(strver)
4328					if masterconn.version_at_least(1,6,28):
4329						if gracetime>=0x80000000:
4330							if gracetime>=0xC0000000:
4331								data.append("<%u>" % load)
4332							else:
4333								data.append("(%u)" % load)
4334						elif gracetime>0:
4335							data.append("[%u]" % load)
4336						else:
4337							data.append(load)
4338					if masterconn.version_at_least(2,0,11):
4339						if leaderfound==0:
4340							data.append("-")
4341						elif (flags&2)==0:
4342							data.append("maintenance_off")
4343						elif (flags&4)==0:
4344							data.append("maintenance_on")
4345						else:
4346							data.append("maintenance_tmp_on")
4347					data.extend([chunks,used,total])
4348					if masterconn.version_at_least(3,0,38):
4349						if tdchunks==0 or leaderfound==0:
4350							data.append("-")
4351						elif mfrstatus==1:
4352							data.append("NOT READY")
4353						elif mfrstatus==2:
4354							data.append("READY")
4355						else:
4356							data.append("PENDING")
4357					data.extend([tdchunks,tdused,tdtotal])
4358					tab.append(*data)
4359			if len(dservers)>0:
4360				if cgimode:
4361					out.append("""</table>""")
4362					out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsdiscs" cellspacing="0">""")
4363					if masterconn.version_at_least(2,0,11):
4364						out.append("""	<tr><th colspan="7">Disconnected Chunk Servers</th></tr>""")
4365					elif masterconn.version_at_least(1,7,25):
4366						out.append("""	<tr><th colspan="6">Disconnected Chunk Servers</th></tr>""")
4367					else:
4368						out.append("""	<tr><th colspan="5">Disconnected Chunk Servers</th></tr>""")
4369					out.append("""	<tr>""")
4370					out.append("""		<th class="acid_tab_enumerate">#</th>""")
4371					out.append("""		<th>host</th>""")
4372					out.append("""		<th>ip</th>""")
4373					out.append("""		<th>port</th>""")
4374					if masterconn.version_at_least(1,7,25):
4375						out.append("""		<th>id</th>""")
4376					if masterconn.version_at_least(2,0,11):
4377						out.append("""		<th>maintenance</th>""")
4378					if leaderfound:
4379						out.append("""		<th class="acid_tab_skip">remove</th>""")
4380					else:
4381						out.append("""		<th class="acid_tab_skip">temporarily remove</th>""")
4382					out.append("""	</tr>""")
4383				elif ttymode:
4384					if masterconn.version_at_least(3,0,38):
4385						tab.append(("---","",16))
4386						tab.append(("disconnected servers","1c",16))
4387						tab.append(("---","",16))
4388						tab.append(("ip/host","c"),("port","c"),("id","r"),("maintenance","c"),("change maintenance command","c",6),("remove command","c",6))
4389						tab.append(("---","",16))
4390					elif masterconn.version_at_least(2,1,0):
4391						tab.append(("---","",15))
4392						tab.append(("disconnected servers","1c",15))
4393						tab.append(("---","",15))
4394						tab.append(("ip/host","c"),("port","c"),("id","r"),("maintenance","c"),("change maintenance command","c",5),("remove command","c",6))
4395						tab.append(("---","",15))
4396					elif masterconn.version_at_least(2,0,11):
4397						tab.append(("---","",14))
4398						tab.append(("disconnected servers","1c",14))
4399						tab.append(("---","",14))
4400						tab.append(("ip/host","c"),("port","c"),("id","r"),("maintenance","c"),("change maintenance command","c",5),("remove command","c",5))
4401						tab.append(("---","",14))
4402					elif masterconn.version_at_least(1,7,25):
4403						tab.append(("---","",13))
4404						tab.append(("disconnected servers","1c",13))
4405						tab.append(("---","",13))
4406						tab.append(("ip/host","c"),("port","c"),("id","r"),("remove command","c",10))
4407						tab.append(("---","",13))
4408					elif masterconn.version_at_least(1,6,28):
4409						tab.append(("---","",12))
4410						tab.append(("disconnected servers","1c",12))
4411						tab.append(("---","",12))
4412						tab.append(("ip/host","c"),("port","c"),("remove command","c",10))
4413						tab.append(("---","",12))
4414					else:
4415						tab.append(("---","",11))
4416						tab.append(("disconnected servers","1c",11))
4417						tab.append(("---","",11))
4418						tab.append(("ip/host","c"),("port","c"),("remove command","c",9))
4419						tab.append(("---","",11))
4420				else:
4421					print(myunicode(tab))
4422					print("")
4423					if masterconn.version_at_least(2,0,11):
4424						tab = Tabble("Disconnected chunk servers",4)
4425					elif masterconn.version_at_least(1,7,25):
4426						tab = Tabble("Disconnected chunk servers",3)
4427					else:
4428						tab = Tabble("Disconnected chunk servers",2)
4429			for sf,host,sortip,strip,port,csid,flags in dservers:
4430				if cgimode:
4431					out.append("""	<tr>""")
4432					if masterconn.version_at_least(2,0,11):
4433						if leaderfound==0:
4434							cl = "DISCONNECTED"
4435						elif (flags&2)==0:
4436							mmstr = "OFF"
4437							mm = "switch on"
4438							mmurl = createlink({"CSmaintenanceon":("%s:%u" % (strip,port))})
4439							cl = "DISCONNECTED"
4440						elif (flags&4)==0:
4441							mmstr = "ON"
4442							mm = "switch off"
4443							mmurl = createlink({"CSmaintenanceoff":("%s:%u" % (strip,port))})
4444							cl = "MAINTAINED"
4445						else:
4446							mmstr = "ON (temp)"
4447							mm = "switch off"
4448							mmurl = createlink({"CSmaintenanceoff":("%s:%u" % (strip,port))})
4449							cl = "TMPMAINTAINED"
4450						out.append("""		<td align="right"></td><td align="left"><span class="%s">%s</span></td>""" % (cl,host))
4451						out.append("""		<td align="center"><span class="sortkey">%s </span><span class="%s">%s</span></td>""" % (sortip,cl,strip))
4452						out.append("""		<td align="center"><span class="%s">%u</span></td>""" % (cl,port))
4453						if masterconn.version_at_least(1,7,25):
4454							out.append("""		<td align="right"><span class="%s">%u</span></td>""" % (cl,csid))
4455						if leaderfound:
4456							out.append("""		<td align="center"><span class="%s">%s : <a href="%s">%s</a></span></td>""" % (cl,mmstr,mmurl,mm))
4457						else:
4458							out.append("""		<td align="center"><span class="%s">not available</td>""" % cl)
4459						if leaderfound:
4460							out.append("""		<td align="center"><a href="%s">click to remove</a></td>""" % (createlink({"CSremove":("%s:%u" % (strip,port))})))
4461						elif masterconn.version_at_least(3,0,67):
4462							out.append("""		<td align="center"><a href="%s">click to temporarily remove</a></td>""" % (createlink({"CStmpremove":("%s:%u" % (strip,port))})))
4463						else:
4464							out.append("""		<td align="center">not available</td>""")
4465					else:
4466						out.append("""		<td align="right"></td><td align="left"><span class="DISCONNECTED">%s</span></td>""" % (host))
4467						out.append("""		<td align="center"><span class="sortkey">%s </span><span class="DISCONNECTED">%s</span></td>""" % (sortip,strip))
4468						out.append("""		<td align="center"><span class="DISCONNECTED">%u</span></td>""" % (port))
4469						if masterconn.version_at_least(1,7,25):
4470							out.append("""		<td align="right"><span class="DISCONNECTED">%u</span></td>""" % (csid))
4471						if leaderfound:
4472							out.append("""		<td align="center"><a href="%s">click to remove</a></td>""" % (createlink({"CSremove":("%s:%u" % (strip,port))})))
4473						else:
4474							out.append("""		<td align="center">not available</td>""")
4475					out.append("""	</tr>""")
4476				elif ttymode:
4477					data = [host,port]
4478					if masterconn.version_at_least(1,7,25):
4479						data.append(csid)
4480					if masterconn.version_at_least(2,0,11):
4481						if leaderfound==0:
4482							mm = "-"
4483							mmcmd = "not available"
4484						elif (flags&2)==0:
4485							mm = "off"
4486							mmcmd = "%s -H %s -P %u -CM1/%s/%s" % (sys.argv[0],masterhost,masterport,strip,port)
4487						elif (flags&4)==0:
4488							mm = "on"
4489							mmcmd = "%s -H %s -P %u -CM0/%s/%s" % (sys.argv[0],masterhost,masterport,strip,port)
4490						else:
4491							mm = "on (temp)"
4492							mmcmd = "%s -H %s -P %u -CM0/%s/%s" % (sys.argv[0],masterhost,masterport,strip,port)
4493						data.append(mm)
4494						if masterconn.version_at_least(3,0,38):
4495							data.append((mmcmd,"l",6))
4496						else:
4497							data.append((mmcmd,"l",5))
4498						if leaderfound:
4499							rmcmd = "%s -H %s -P %u -CRC/%s/%s" % (sys.argv[0],masterhost,masterport,strip,port)
4500						elif masterconn.version_at_least(3,0,67):
4501							rmcmd = "%s -H %s -P %u -CTR/%s/%s" % (sys.argv[0],masterhost,masterport,strip,port)
4502						else:
4503							rmcmd = "not available"
4504						if masterconn.version_at_least(2,1,0):
4505							data.append((rmcmd,"l",6))
4506						else:
4507							data.append((rmcmd,"l",5))
4508					else:
4509						if leaderfound:
4510							rmcmd = "%s -H %s -P %u -CRC/%s/%s" % (sys.argv[0],masterhost,masterport,strip,port)
4511						else:
4512							rmcmd = "not available"
4513						if masterconn.version_at_least(1,6,28):
4514							data.append((rmcmd,"l",10))
4515						else:
4516							data.append((rmcmd,"l",9))
4517					tab.append(*data)
4518				else:
4519					if masterconn.version_at_least(2,0,11):
4520						if leaderfound==0:
4521							mm = "-"
4522						elif (flags&2)==0:
4523							mm = "maintenance_off"
4524						elif (flags&4)==0:
4525							mm = "maintenance_on"
4526						else:
4527							mm = "maintenance_temp_on"
4528						tab.append(host,port,csid,mm)
4529					elif masterconn.version_at_least(1,7,25):
4530						tab.append(host,port,csid)
4531					else:
4532						tab.append(host,port)
4533			if cgimode:
4534				out.append("""</table>""")
4535				print("\n".join(out))
4536			else:
4537				print(myunicode(tab))
4538		except Exception:
4539			print_exception()
4540
4541	if "MB" in sectionsubset and leaderfound:
4542		try:
4543			if cgimode:
4544				out = []
4545				out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsmbl" cellspacing="0">""")
4546				out.append("""	<tr><th colspan="4">Metadata Backup Loggers</th></tr>""")
4547				out.append("""	<tr>""")
4548				out.append("""		<th class="acid_tab_enumerate">#</th>""")
4549				out.append("""		<th>host</th>""")
4550				out.append("""		<th>ip</th>""")
4551				out.append("""		<th>version</th>""")
4552				out.append("""	</tr>""")
4553			elif ttymode:
4554				tab = Tabble("Metadata Backup Loggers",2,"r")
4555				tab.header("ip/host","version")
4556			else:
4557				tab = Tabble("metadata backup loggers",2)
4558			data,length = masterconn.command(CLTOMA_MLOG_LIST,MATOCL_MLOG_LIST)
4559			if (length%8)==0:
4560				n = length//8
4561				servers = []
4562				for i in range(n):
4563					d = data[i*8:(i+1)*8]
4564					v1,v2,v3,ip1,ip2,ip3,ip4 = struct.unpack(">HBBBBBB",d)
4565					strip = "%u.%u.%u.%u" % (ip1,ip2,ip3,ip4)
4566					host = resolve(strip)
4567					sortip = "%03u_%03u_%03u_%03u" % (ip1,ip2,ip3,ip4)
4568					strver,sortver = version_str_and_sort((v1,v2,v3))
4569					sf = (ip1,ip2,ip3,ip4)
4570					if MBorder==1:
4571						sf = host
4572					elif MBorder==2:
4573						sf = sortip
4574					elif MBorder==3:
4575						sf = sortver
4576					servers.append((sf,host,sortip,strip,sortver,strver))
4577				servers.sort()
4578				if MBrev:
4579					servers.reverse()
4580				for sf,host,sortip,strip,sortver,strver in servers:
4581					if cgimode:
4582						if masterconn.is_pro() and not strver.endswith(" PRO"):
4583							verclass = "BADVERSION"
4584						elif masterconn.sort_ver() > sortver:
4585							verclass = "LOWERVERSION"
4586						elif masterconn.sort_ver() < sortver:
4587							verclass = "HIGHERVERSION"
4588						else:
4589							verclass = "OKVERSION"
4590						out.append("""	<tr>""")
4591						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))
4592						out.append("""	</tr>""")
4593					else:
4594						tab.append(host,strver)
4595			if cgimode:
4596				out.append("""</table>""")
4597				print("\n".join(out))
4598			else:
4599				print(myunicode(tab))
4600		except Exception:
4601			print_exception()
4602
4603if "HD" in sectionset:
4604	try:
4605		# get cs list
4606		hostlist = []
4607		for cs in dataprovider.get_chunkservers():
4608			if (cs.flags&1)==0:
4609				hostlist.append((cs.ip,cs.port,cs.version,cs.mfrstatus))
4610
4611		# get hdd lists one by one
4612		hdd = []
4613		shdd = []
4614		for (ip1,ip2,ip3,ip4),port,version,mfrstatus in hostlist:
4615#		for v1,v2,v3,ip1,ip2,ip3,ip4,port in hostlist:
4616			hostip = "%u.%u.%u.%u" % (ip1,ip2,ip3,ip4)
4617			hostkey = "%s:%u" % (hostip,port)
4618			hoststr = resolve(hostip)
4619			if port>0:
4620				if version<=(1,6,8):
4621					hdd.append((None,hostkey,"0","version too old","version too old",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],[0,0,0],[0,0,0]))
4622				else:
4623					conn = MFSConn(hostip,port)
4624					data,length = conn.command(CLTOCS_HDD_LIST,CSTOCL_HDD_LIST)
4625					while length>0:
4626						entrysize = struct.unpack(">H",data[:2])[0]
4627						entry = data[2:2+entrysize]
4628						data = data[2+entrysize:]
4629						length -= 2+entrysize
4630						if sys.version_info[0]<3:
4631							plen = ord(entry[0])
4632						else:
4633							plen = entry[0]
4634						hddpath = entry[1:plen+1]
4635						hddpath = hddpath.decode('utf-8','replace')
4636						hostpath = "%s:%u:%s" % (hoststr,port,hddpath)
4637						ippath = "%s:%u:%s" % (hostip,port,hddpath)
4638						sortippath = "%03u.%03u.%03u.%03u:%05u:%s" % (ip1,ip2,ip3,ip4,port,hddpath)
4639						flags,errchunkid,errtime,used,total,chunkscnt = struct.unpack(">BQLQQL",entry[plen+1:plen+34])
4640						rbytes = [0,0,0]
4641						wbytes = [0,0,0]
4642						usecreadsum = [0,0,0]
4643						usecwritesum = [0,0,0]
4644						usecfsyncsum = [0,0,0]
4645						rops = [0,0,0]
4646						wops = [0,0,0]
4647						fsyncops = [0,0,0]
4648						usecreadmax = [0,0,0]
4649						usecwritemax = [0,0,0]
4650						usecfsyncmax = [0,0,0]
4651						if entrysize==plen+34+144:
4652							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])
4653							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])
4654							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])
4655#								if HDperiod==0:
4656#									rbytes,wbytes,usecreadsum,usecwritesum,rops,wops,usecreadmax,usecwritemax = struct.unpack(">QQQQLLLL",entry[plen+34:plen+34+48])
4657#								elif HDperiod==1:
4658#									rbytes,wbytes,usecreadsum,usecwritesum,rops,wops,usecreadmax,usecwritemax = struct.unpack(">QQQQLLLL",entry[plen+34+48:plen+34+96])
4659#								elif HDperiod==2:
4660#									rbytes,wbytes,usecreadsum,usecwritesum,rops,wops,usecreadmax,usecwritemax = struct.unpack(">QQQQLLLL",entry[plen+34+96:plen+34+144])
4661						elif entrysize==plen+34+192:
4662							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])
4663							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])
4664							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])
4665#								if HDperiod==0:
4666#									rbytes,wbytes,usecreadsum,usecwritesum,usecfsyncsum,rops,wops,fsyncops,usecreadmax,usecwritemax,usecfsyncmax = struct.unpack(">QQQQQLLLLLL",entry[plen+34:plen+34+64])
4667#								elif HDperiod==1:
4668#									rbytes,wbytes,usecreadsum,usecwritesum,usecfsyncsum,rops,wops,fsyncops,usecreadmax,usecwritemax,usecfsyncmax = struct.unpack(">QQQQQLLLLLL",entry[plen+34+64:plen+34+128])
4669#								elif HDperiod==2:
4670#									rbytes,wbytes,usecreadsum,usecwritesum,usecfsyncsum,rops,wops,fsyncops,usecreadmax,usecwritemax,usecfsyncmax = struct.unpack(">QQQQQLLLLLL",entry[plen+34+128:plen+34+192])
4671						rbw = [0,0,0]
4672						wbw = [0,0,0]
4673						usecreadavg = [0,0,0]
4674						usecwriteavg = [0,0,0]
4675						usecfsyncavg = [0,0,0]
4676						for i in range(3):
4677							if usecreadsum[i]>0:
4678								rbw[i] = rbytes[i]*1000000//usecreadsum[i]
4679							if usecwritesum[i]+usecfsyncsum[i]>0:
4680								wbw[i] = wbytes[i]*1000000//(usecwritesum[i]+usecfsyncsum[i])
4681							if rops[i]>0:
4682								usecreadavg[i] = usecreadsum[i]//rops[i]
4683							if wops[i]>0:
4684								usecwriteavg[i] = usecwritesum[i]//wops[i]
4685							if fsyncops[i]>0:
4686								usecfsyncavg[i] = usecfsyncsum[i]//fsyncops[i]
4687						sf = sortippath
4688						if HDorder==1:
4689							sf = sortippath
4690						elif HDorder==2:
4691							sf = chunkscnt
4692						elif HDorder==3:
4693							sf = errtime
4694						elif HDorder==4:
4695							sf = -flags
4696						elif HDorder==5:
4697							sf = rbw[HDperiod]
4698						elif HDorder==6:
4699							sf = wbw[HDperiod]
4700						elif HDorder==7:
4701							if HDtime==1:
4702								sf = usecreadavg[HDperiod]
4703							else:
4704								sf = usecreadmax[HDperiod]
4705						elif HDorder==8:
4706							if HDtime==1:
4707								sf = usecwriteavg[HDperiod]
4708							else:
4709								sf = usecwritemax[HDperiod]
4710						elif HDorder==9:
4711							if HDtime==1:
4712								sf = usecfsyncavg[HDperiod]
4713							else:
4714								sf = usecfsyncmax[HDperiod]
4715						elif HDorder==10:
4716							sf = rops[HDperiod]
4717						elif HDorder==11:
4718							sf = wops[HDperiod]
4719						elif HDorder==12:
4720							sf = fsyncops[HDperiod]
4721						elif HDorder==20:
4722							if flags&4==0:
4723								sf = used
4724							else:
4725								sf = 0
4726						elif HDorder==21:
4727							if flags&4==0:
4728								sf = total
4729							else:
4730								sf = 0
4731						elif HDorder==22:
4732							if flags&4==0 and total>0:
4733								sf = (1.0*used)/total
4734							else:
4735								sf = 0
4736						if flags&4 and not cgimode and ttymode:
4737							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,mfrstatus))
4738						else:
4739							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,mfrstatus))
4740
4741		if len(hdd)>0 or len(shdd)>0:
4742			if cgimode:
4743				out = []
4744				out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfshdd" cellspacing="0" id="mfshdd">""")
4745				out.append("""	<tr><th colspan="16">Disks</th></tr>""")
4746				out.append("""	<tr>""")
4747				out.append("""		<th rowspan="3" class="acid_tab_enumerate">#</th>""")
4748				out.append("""		<th colspan="4" rowspan="2">""")
4749				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>""")
4750				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>""")
4751				out.append("""		</th>""")
4752				out.append("""		<th colspan="8">""")
4753				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>""")
4754				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>""")
4755				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>""")
4756				out.append("""		</th>""")
4757#				if HDperiod==2:
4758#					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"})))
4759#				elif HDperiod==1:
4760#					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"})))
4761#				else:
4762#					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"})))
4763				out.append("""		<th colspan="3" rowspan="2">space</th>""")
4764				out.append("""	</tr>""")
4765				out.append("""	<tr>""")
4766				out.append("""		<th colspan="2"><a style="cursor:default" title="average data transfer speed">transfer</a></th>""")
4767				out.append("""		<th colspan="3">""")
4768				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>""")
4769				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>""")
4770				out.append("""		</th>""")
4771#				if HDtime==1:
4772#					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"})))
4773#				else:
4774#					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"})))
4775				out.append("""		<th colspan="3"><a style="cursor:default" title="number of chunk block operations / chunk fsyncs"># of ops</a></th>""")
4776				out.append("""	</tr>""")
4777				out.append("""	<tr>""")
4778				out.append("""		<th class="acid_tab_level_1"><span class="hddaddrname_vis0">IP</span><span class="hddaddrname_vis1">name</span> path</th>""")
4779				out.append("""		<th>chunks</th>""")
4780				out.append("""		<th>last error</th>""")
4781				out.append("""		<th>status</th>""")
4782				out.append("""		<th class="acid_tab_level_1">read</th>""")
4783				out.append("""		<th class="acid_tab_level_1">write</th>""")
4784				out.append("""		<th class="acid_tab_level_2">read</th>""")
4785				out.append("""		<th class="acid_tab_level_2">write</th>""")
4786				out.append("""		<th class="acid_tab_level_2">fsync</th>""")
4787				out.append("""		<th class="acid_tab_level_1">read</th>""")
4788				out.append("""		<th class="acid_tab_level_1">write</th>""")
4789				out.append("""		<th class="acid_tab_level_1">fsync</th>""")
4790				out.append("""		<th>used</th>""")
4791				out.append("""		<th>total</th>""")
4792				out.append("""		<th class="SMPROGBAR">% used</th>""")
4793				#out.append("""		<th><a href="%s">chunks</a></th>""" % (createorderlink("HD",2)))
4794				#out.append("""		<th><a href="%s">last error</a></th>""" % (createorderlink("HD",3)))
4795				#out.append("""		<th><a href="%s">status</a></th>""" % (createorderlink("HD",4)))
4796				#out.append("""		<th><a href="%s">read</a></th>""" % (createorderlink("HD",5)))
4797				#out.append("""		<th><a href="%s">write</a></th>""" % (createorderlink("HD",6)))
4798				#out.append("""		<th><a href="%s">read</a></th>""" % (createorderlink("HD",7)))
4799				#out.append("""		<th><a href="%s">write</a></th>""" % (createorderlink("HD",8)))
4800				#out.append("""		<th><a href="%s">fsync</a></th>""" % (createorderlink("HD",9)))
4801				#out.append("""		<th><a href="%s">read</a></th>""" % (createorderlink("HD",10)))
4802				#out.append("""		<th><a href="%s">write</a></th>""" % (createorderlink("HD",11)))
4803				#out.append("""		<th><a href="%s">fsync</a></th>""" % (createorderlink("HD",12)))
4804				#out.append("""		<th><a href="%s">used</a></th>""" % (createorderlink("HD",20)))
4805				#out.append("""		<th><a href="%s">total</a></th>""" % (createorderlink("HD",21)))
4806				#out.append("""		<th class="SMPROGBAR"><a href="%s">used (%%)</a></th>""" % (createorderlink("HD",22)))
4807				out.append("""	</tr>""")
4808			elif ttymode:
4809				tab = Tabble("Disks",15,"r")
4810				tab.header(("","",4),("I/O stats last %s" % ("day" if HDperiod==2 else "hour" if HDperiod==1 else "min"),"",8),("","",3))
4811				tab.header(("info","",4),("---","",8),("space","",3))
4812				tab.header(("","",4),("transfer","",2),("%s time" % ("avg" if HDtime==1 else "max"),"",3),("# of ops","",3),("","",3))
4813				tab.header(("---","",15))
4814				if len(hdd)>0 or len(shdd)==0:
4815					tab.header("IP path","chunks","last error","status","read","write","read","write","fsync","read","write","fsync","used","total","used %")
4816					lscanning = 0
4817				else:
4818					tab.header("IP path","chunks","last error","status","read","write","read","write","fsync","read","write","fsync",("progress","c",3))
4819					lscanning = 1
4820			else:
4821				tab = Tabble("disks",14)
4822			hdd.sort()
4823			shdd.sort()
4824			if HDrev:
4825				hdd.reverse()
4826				shdd.reverse()
4827			usedsum = {}
4828			totalsum = {}
4829			hostavg = {}
4830			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,mfrstatus in hdd+shdd:
4831				if hostkey not in usedsum:
4832					usedsum[hostkey]=0
4833					totalsum[hostkey]=0
4834					hostavg[hostkey]=0
4835				if flags&4==0 and total>0:
4836					usedsum[hostkey]+=used
4837					totalsum[hostkey]+=total
4838					if totalsum[hostkey]>0:
4839						hostavg[hostkey] = (usedsum[hostkey] * 100.0) / totalsum[hostkey]
4840			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,mfrstatus in hdd+shdd:
4841				statuslist = []
4842				if (flags&8):
4843					statuslist.append('invalid')
4844				if (flags&2) and (flags&4)==0 and (flags&8)==0:
4845					statuslist.append('damaged')
4846				if flags&1:
4847					if mfrstatus==1:
4848						statuslist.append('marked for removal (not ready)')
4849					elif mfrstatus==2:
4850						statuslist.append('marked for removal (ready)')
4851					else:
4852						statuslist.append('marked for removal')
4853				if flags&4:
4854					statuslist.append('scanning')
4855				if flags==0:
4856					statuslist.append('ok')
4857				status = ", ".join(statuslist)
4858				if errtime==0 and errchunkid==0:
4859					lerror = 'no errors'
4860				else:
4861					if cgimode:
4862						errtimetuple = time.localtime(errtime)
4863						lerror = '<a style="cursor:default" title="%s on chunk: %016X">%s</a>' % (time.strftime("%Y-%m-%d %H:%M:%S",errtimetuple),errchunkid,time.strftime("%Y-%m-%d %H:%M",errtimetuple))
4864					elif ttymode:
4865						errtimetuple = time.localtime(errtime)
4866						lerror = time.strftime("%Y-%m-%d %H:%M",errtimetuple)
4867					else:
4868						lerror = errtime
4869				if cgimode:
4870					out.append("""	<tr>""")
4871					out.append("""		<td align="right"></td>""")
4872					out.append("""		<td align="left"><span class="hddaddrname_vis0"><span class="sortkey">%s </span>%s</span><span class="hddaddrname_vis1">%s</span></td>""" % (htmlentities(sortippath),htmlentities(ippath),htmlentities(hostpath)))
4873					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))
4874					validdata = [1,1,1]
4875					for i in range(3):
4876						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:
4877							validdata[i] = 0
4878					# rbw
4879					out.append("""		<td align="right">""")
4880					for i in range(3):
4881						out.append("""			<span class="hddperiod_vis%u">""" % i)
4882						if validdata[i]:
4883							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;")))
4884						else:
4885							out.append("""				<span class="sortkey">-1 </span>-""")
4886						out.append("""			</span>""")
4887					out.append("""		</td>""")
4888					# wbw
4889					out.append("""		<td align="right">""")
4890					for i in range(3):
4891						out.append("""			<span class="hddperiod_vis%u">""" % i)
4892						if validdata[i]:
4893							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;")))
4894						else:
4895							out.append("""				<span class="sortkey">-1 </span>-""")
4896						out.append("""			</span>""")
4897					out.append("""		</td>""")
4898					# readtime
4899					out.append("""		<td align="right">""")
4900					for i in range(3):
4901						out.append("""			<span class="hddperiod_vis%u">""" % i)
4902						if validdata[i]:
4903							out.append("""				<span class="hddtime_vis0">%u us</span>""" % usecreadmax[i])
4904							out.append("""				<span class="hddtime_vis1">%u us</span>""" % usecreadavg[i])
4905						else:
4906							out.append("""				<span><span class="sortkey">-1 </span>-</span>""")
4907						out.append("""			</span>""")
4908					out.append("""		</td>""")
4909					# writetime
4910					out.append("""		<td align="right">""")
4911					for i in range(3):
4912						out.append("""			<span class="hddperiod_vis%u">""" % i)
4913						if validdata[i]:
4914							out.append("""				<span class="hddtime_vis0">%u us</span>""" % usecwritemax[i])
4915							out.append("""				<span class="hddtime_vis1">%u us</span>""" % usecwriteavg[i])
4916						else:
4917							out.append("""				<span><span class="sortkey">-1 </span>-</span>""")
4918						out.append("""			</span>""")
4919					out.append("""		</td>""")
4920					# fsynctime
4921					out.append("""		<td align="right">""")
4922					for i in range(3):
4923						out.append("""			<span class="hddperiod_vis%u">""" % i)
4924						if validdata[i]:
4925							out.append("""				<span class="hddtime_vis0">%u us</span>""" % usecfsyncmax[i])
4926							out.append("""				<span class="hddtime_vis1">%u us</span>""" % usecfsyncavg[i])
4927						else:
4928							out.append("""				<span><span class="sortkey">-1 </span>-</span>""")
4929						out.append("""			</span>""")
4930					out.append("""		</td>""")
4931					# rops
4932					out.append("""		<td align="right">""")
4933					for i in range(3):
4934						out.append("""			<span class="hddperiod_vis%u">""" % i)
4935						if validdata[i]:
4936							if rops[i]>0:
4937								bsize = rbytes[i]/rops[i]
4938							else:
4939								bsize = 0
4940							out.append("""				<a style="cursor:default" title="average block size: %u B">%u</a>""" % (bsize,rops[i]))
4941						else:
4942							out.append("""				<span class="sortkey">-1 </span>-""")
4943						out.append("""			</span>""")
4944					out.append("""		</td>""")
4945					# wops
4946					out.append("""		<td align="right">""")
4947					for i in range(3):
4948						out.append("""			<span class="hddperiod_vis%u">""" % i)
4949						if validdata[i]:
4950							if wops[i]>0:
4951								bsize = wbytes[i]/wops[i]
4952							else:
4953								bsize = 0
4954							out.append("""				<a style="cursor:default" title="average block size: %u B">%u</a>""" % (bsize,wops[i]))
4955						else:
4956							out.append("""				<span class="sortkey">-1 </span>-""")
4957						out.append("""			</span>""")
4958					out.append("""		</td>""")
4959					# fsyncops
4960					out.append("""		<td align="right">""")
4961					for i in range(3):
4962						out.append("""			<span class="hddperiod_vis%u">""" % i)
4963						if validdata[i]:
4964							out.append("""				%u""" % (fsyncops[i]))
4965						else:
4966							out.append("""				<span class="sortkey">-1 </span>-""")
4967						out.append("""			</span>""")
4968					out.append("""		</td>""")
4969#					if rbw==0 and wbw==0 and rtime==0 and wtime==0 and rops==0 and wops==0:
4970#						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>""")
4971#					else:
4972#						if rops>0:
4973#							rbsize = rbytes/rops
4974#						else:
4975#							rbsize = 0
4976#						if wops>0:
4977#							wbsize = wbytes/wops
4978#						else:
4979#							wbsize = 0
4980#						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;")))
4981#						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))
4982					if flags&4:
4983						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))
4984					else:
4985						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;")))
4986						if total>0:
4987							usedpercent = (used*100.0)/total
4988							avgpercent = hostavg[hostkey]
4989							if usedpercent<avgpercent:
4990								diffstr = "&#8722;%.4f" % (avgpercent-usedpercent)
4991							else:
4992								diffstr = "+%.4f" % (usedpercent-avgpercent)
4993							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))
4994						else:
4995							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>""")
4996					out.append("""	</tr>""")
4997				elif ttymode:
4998					rtime = usecreadmax[HDperiod] if HDtime==0 else usecreadavg[HDperiod]
4999					wtime = usecwritemax[HDperiod] if HDtime==0 else usecwriteavg[HDperiod]
5000					fsynctime = usecfsyncmax[HDperiod] if HDtime==0 else usecfsyncavg[HDperiod]
5001					ldata = [ippath,chunkscnt,lerror,status]
5002					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:
5003						ldata.extend(("-","-","-","-","-","-","-","-"))
5004					else:
5005						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]))
5006					if flags&4:
5007						if lscanning==0:
5008							lscanning=1
5009							tab.append(("---","",15))
5010							tab.append("IP path","chunks","last error","status","read","write","read","write","fsync","read","write","fsync",("progress","c",3))
5011							tab.append(("---","",15))
5012						ldata.append(("%.0f%%" % used,"r",3))
5013					else:
5014						if total>0:
5015							perc = "%.2f%%" % ((used*100.0)/total)
5016						else:
5017							perc = "-"
5018						ldata.extend((humanize_number(used," "),humanize_number(total," "),perc))
5019					tab.append(*ldata)
5020				else:
5021					rtime = usecreadmax[HDperiod] if HDtime==0 else usecreadavg[HDperiod]
5022					wtime = usecwritemax[HDperiod] if HDtime==0 else usecwriteavg[HDperiod]
5023					fsynctime = usecfsyncmax[HDperiod] if HDtime==0 else usecfsyncavg[HDperiod]
5024					ldata = [ippath,chunkscnt,lerror,status]
5025					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:
5026						ldata.extend(("-","-","-","-","-","-","-","-"))
5027					else:
5028						ldata.extend((rbw[HDperiod],wbw[HDperiod],rtime,wtime,fsynctime,rops[HDperiod],wops[HDperiod],fsyncops[HDperiod]))
5029					if flags&4:
5030						ldata.extend(("progress:",used))
5031					else:
5032						ldata.extend((used,total))
5033					tab.append(*ldata)
5034			if cgimode:
5035				out.append("""</table>""")
5036				print("\n".join(out))
5037			else:
5038				print(myunicode(tab))
5039	except Exception:
5040		print_exception()
5041
5042if "EX" in sectionset:
5043	try:
5044		if cgimode:
5045			out = []
5046			out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsexports" cellspacing="0">""")
5047			out.append("""	<tr><th colspan="%u">Exports</th></tr>""" % (21 if masterconn.has_feature(FEATURE_EXPORT_DISABLES) else 20 if masterconn.has_feature(FEATURE_EXPORT_UMASK) else 19 if masterconn.version_at_least(1,7,0) else 18 if masterconn.version_at_least(1,6,26) else 14))
5048			out.append("""	<tr>""")
5049			out.append("""		<th rowspan="2" class="acid_tab_enumerate">#</th>""")
5050			out.append("""		<th colspan="2">ip&nbsp;range</th>""")
5051#			out.append("""		<th rowspan="2"><a href="%s">path</a></th>""" % (createorderlink("EX",3)))
5052#			out.append("""		<th rowspan="2"><a href="%s">minversion</a></th>""" % (createorderlink("EX",4)))
5053#			out.append("""		<th rowspan="2"><a href="%s">alldirs</a></th>""" % (createorderlink("EX",5)))
5054#			out.append("""		<th rowspan="2"><a href="%s">password</a></th>""" % (createorderlink("EX",6)))
5055#			out.append("""		<th rowspan="2"><a href="%s">ro/rw</a></th>""" % (createorderlink("EX",7)))
5056#			out.append("""		<th rowspan="2"><a href="%s">restricted&nbsp;ip</a></th>""" % (createorderlink("EX",8)))
5057#			out.append("""		<th rowspan="2"><a href="%s">ignore&nbsp;gid</a></th>""" % (createorderlink("EX",9)))
5058			out.append("""		<th rowspan="2">path</th>""")
5059			out.append("""		<th rowspan="2">minversion</th>""")
5060			out.append("""		<th rowspan="2">alldirs</th>""")
5061			out.append("""		<th rowspan="2">password</th>""")
5062			out.append("""		<th rowspan="2">ro/rw</th>""")
5063			out.append("""		<th rowspan="2">restricted&nbsp;ip</th>""")
5064			out.append("""		<th rowspan="2">ignore&nbsp;gid</th>""")
5065			if masterconn.version_at_least(1,7,0):
5066#				out.append("""		<th rowspan="2"><a href="%s">can&nbsp;change&nbsp;quota</a></th>""" % (createorderlink("EX",10)))
5067				out.append("""		<th rowspan="2">admin</th>""")
5068			out.append("""		<th colspan="2">map&nbsp;root</th>""")
5069			out.append("""		<th colspan="2">map&nbsp;users</th>""")
5070			if masterconn.version_at_least(1,6,26):
5071				out.append("""		<th colspan="2">goal&nbsp;limit</th>""")
5072				out.append("""		<th colspan="2">trashtime&nbsp;limit</th>""")
5073			if masterconn.has_feature(FEATURE_EXPORT_UMASK):
5074				out.append("""		<th rowspan="2">global&nbsp;umask</th>""")
5075			if masterconn.has_feature(FEATURE_EXPORT_DISABLES):
5076				out.append("""		<th rowspan="2">disables&nbsp;mask</th>""")
5077			out.append("""	</tr>""")
5078			out.append("""	<tr>""")
5079#			out.append("""		<th><a href="%s">from</a></th>""" % (createorderlink("EX",1)))
5080#			out.append("""		<th><a href="%s">to</a></th>""" % (createorderlink("EX",2)))
5081#			out.append("""		<th><a href="%s">uid</a></th>""" % (createorderlink("EX",11)))
5082#			out.append("""		<th><a href="%s">gid</a></th>""" % (createorderlink("EX",12)))
5083#			out.append("""		<th><a href="%s">uid</a></th>""" % (createorderlink("EX",13)))
5084#			out.append("""		<th><a href="%s">gid</a></th>""" % (createorderlink("EX",14)))
5085			out.append("""		<th>from</th>""")
5086			out.append("""		<th>to</th>""")
5087			out.append("""		<th>uid</th>""")
5088			out.append("""		<th>gid</th>""")
5089			out.append("""		<th>uid</th>""")
5090			out.append("""		<th>gid</th>""")
5091			if masterconn.version_at_least(1,6,26):
5092#				out.append("""		<th><a href="%s">min</a></th>""" % (createorderlink("EX",15)))
5093#				out.append("""		<th><a href="%s">max</a></th>""" % (createorderlink("EX",16)))
5094#				out.append("""		<th><a href="%s">min</a></th>""" % (createorderlink("EX",17)))
5095#				out.append("""		<th><a href="%s">max</a></th>""" % (createorderlink("EX",18)))
5096				out.append("""		<th>min</th>""")
5097				out.append("""		<th>max</th>""")
5098				out.append("""		<th>min</th>""")
5099				out.append("""		<th>max</th>""")
5100			out.append("""	</tr>""")
5101		elif ttymode:
5102			tab = Tabble("Exports",(20 if masterconn.has_feature(FEATURE_EXPORT_DISABLES) else 19 if masterconn.has_feature(FEATURE_EXPORT_UMASK) else 18 if masterconn.version_at_least(1,7,0) else 17 if masterconn.version_at_least(1,6,26) else 13))
5103
5104			dline = ["r","r","l","c","c","c","c","c","c"]
5105			if masterconn.version_at_least(1,7,0):
5106				dline.append("c")
5107			dline.extend(("r","r","r","r"))
5108			if masterconn.version_at_least(1,6,26):
5109				dline.extend(("r","r","r","r"))
5110			if masterconn.has_feature(FEATURE_EXPORT_UMASK):
5111				dline.append("c")
5112			if masterconn.has_feature(FEATURE_EXPORT_DISABLES):
5113				dline.append("c")
5114			tab.defattr(*dline)
5115
5116			dline = [("ip range","",2),"","","","","","",""]
5117			if masterconn.version_at_least(1,7,0):
5118				dline.append("")
5119			dline.extend((("map root","",2),("map users","",2)))
5120			if masterconn.version_at_least(1,6,26):
5121				dline.extend((("goal limit","",2),("trashtime limit","",2)))
5122			if masterconn.has_feature(FEATURE_EXPORT_UMASK):
5123				dline.append("")
5124			if masterconn.has_feature(FEATURE_EXPORT_DISABLES):
5125				dline.append("")
5126			tab.header(*dline)
5127
5128			dline = [("---","",2),"path","minversion","alldirs","password","ro/rw","restrict ip","ignore gid"]
5129			if masterconn.version_at_least(1,7,0):
5130				dline.append("admin")
5131			if masterconn.version_at_least(1,6,26):
5132				dline.append(("---","",8))
5133			else:
5134				dline.append(("---","",4))
5135			if masterconn.has_feature(FEATURE_EXPORT_UMASK):
5136				dline.append("global umask")
5137			if masterconn.has_feature(FEATURE_EXPORT_DISABLES):
5138				dline.append("disables mask")
5139			tab.header(*dline)
5140
5141			dline = ["from","to","","","","","","",""]
5142			if masterconn.version_at_least(1,7,0):
5143				dline.append("")
5144			dline.extend(("uid","gid","uid","gid"))
5145			if masterconn.version_at_least(1,6,26):
5146				dline.extend(("min","max","min","max"))
5147			if masterconn.has_feature(FEATURE_EXPORT_UMASK):
5148				dline.append("")
5149			if masterconn.has_feature(FEATURE_EXPORT_DISABLES):
5150				dline.append("")
5151			tab.header(*dline)
5152
5153		else:
5154			tab = Tabble("exports",(20 if masterconn.has_feature(FEATURE_EXPORT_DISABLES) else 19 if masterconn.has_feature(FEATURE_EXPORT_UMASK) else 18 if masterconn.version_at_least(1,7,0) else 17 if masterconn.version_at_least(1,6,26) else 13))
5155		servers = []
5156		for expe in dataprovider.get_exports():
5157			sf = expe.ipfrom + expe.ipto
5158			if EXorder==1:
5159				sf = expe.sortipfrom
5160			elif EXorder==2:
5161				sf = expe.sortipto
5162			elif EXorder==3:
5163				sf = expe.path
5164			elif EXorder==4:
5165				sf = expe.sortver
5166			elif EXorder==5:
5167				if expe.meta:
5168					sf = None
5169				else:
5170					sf = expe.exportflags&1
5171			elif EXorder==6:
5172				sf = expe.exportflags&2
5173			elif EXorder==7:
5174				sf = expe.sesflags&1
5175			elif EXorder==8:
5176				sf = 2-(expe.sesflags&2)
5177			elif EXorder==9:
5178				if expe.meta:
5179					sf = None
5180				else:
5181					sf = expe.sesflags&4
5182			elif EXorder==10:
5183				if expe.meta:
5184					sf = None
5185				else:
5186					sf = expe.sesflags&8
5187			elif EXorder==11:
5188				if expe.meta:
5189					sf = None
5190				else:
5191					sf = expe.rootuid
5192			elif EXorder==12:
5193				if expe.meta:
5194					sf = None
5195				else:
5196					sf = expe.rootgid
5197			elif EXorder==13:
5198				if expe.meta or (expe.sesflags&16)==0:
5199					sf = None
5200				else:
5201					sf = expe.mapalluid
5202			elif EXorder==14:
5203				if expe.meta or (expe.sesflags&16)==0:
5204					sf = None
5205				else:
5206					sf = expe.mapalguid
5207			elif EXorder==15:
5208				sf = expe.mingoal
5209			elif EXorder==16:
5210				sf = expe.maxgoal
5211			elif EXorder==17:
5212				sf = expe.mintrashtime
5213			elif EXorder==18:
5214				sf = expe.maxtrashtime
5215			elif EXorder==19:
5216				sf = expe.umaskval
5217			elif EXorder==20:
5218				sf = expe.disables
5219			servers.append((sf,expe.sortipfrom,expe.stripfrom,expe.sortipto,expe.stripto,expe.path,expe.meta,expe.sortver,expe.strver,expe.exportflags,expe.sesflags,expe.umaskval,expe.rootuid,expe.rootgid,expe.mapalluid,expe.mapallgid,expe.mingoal,expe.maxgoal,expe.mintrashtime,expe.maxtrashtime,expe.disables))
5220		servers.sort()
5221		if EXrev:
5222			servers.reverse()
5223		for sf,sortipfrom,ipfrom,sortipto,ipto,path,meta,sortver,strver,exportflags,sesflags,umaskval,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime,disables in servers:
5224			if cgimode:
5225				out.append("""	<tr>""")
5226				out.append("""		<td align="right"></td>""")
5227				out.append("""		<td align="center"><span class="sortkey">%s </span>%s</td>""" % (sortipfrom,ipfrom))
5228				out.append("""		<td align="center"><span class="sortkey">%s </span>%s</td>""" % (sortipto,ipto))
5229				out.append("""		<td align="left">%s</td>""" % (".&nbsp;(META)" if meta else htmlentities(path)))
5230				out.append("""		<td align="center"><span class="sortkey">%s </span>%s</td>""" % (sortver,strver))
5231				out.append("""		<td align="center">%s</td>""" % ("-" if meta else "yes" if exportflags&1 else "no"))
5232				out.append("""		<td align="center">%s</td>""" % ("yes" if exportflags&2 else "no"))
5233				out.append("""		<td align="center">%s</td>""" % ("ro" if sesflags&1 else "rw"))
5234				out.append("""		<td align="center">%s</td>""" % ("no" if sesflags&2 else "yes"))
5235				out.append("""		<td align="center">%s</td>""" % ("-" if meta else "yes" if sesflags&4 else "no"))
5236				if masterconn.version_at_least(1,7,0):
5237					out.append("""		<td align="center">%s</td>""" % ("-" if meta else "yes" if sesflags&8 else "no"))
5238				if meta:
5239					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5240					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5241				else:
5242					out.append("""		<td align="right">%u</td>""" % rootuid)
5243					out.append("""		<td align="right">%u</td>""" % rootgid)
5244				if meta or (sesflags&16)==0:
5245					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5246					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5247				else:
5248					out.append("""		<td align="right">%u</td>""" % mapalluid)
5249					out.append("""		<td align="right">%u</td>""" % mapallgid)
5250				if masterconn.version_at_least(1,6,26):
5251					if mingoal!=None and maxgoal!=None:
5252						out.append("""		<td align="right">%u</td>""" % mingoal)
5253						out.append("""		<td align="right">%u</td>""" % maxgoal)
5254					else:
5255						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5256						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5257					if mintrashtime!=None and maxtrashtime!=None:
5258						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)))
5259						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)))
5260					else:
5261						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5262						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5263				if masterconn.has_feature(FEATURE_EXPORT_UMASK):
5264					if umaskval==None:
5265						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5266					else:
5267						out.append("""		<td align="center">%03o</td>""" % umaskval)
5268				if masterconn.has_feature(FEATURE_EXPORT_DISABLES):
5269					out.append("""		<td align="center"><span class="sortkey">%u </span><a style="cursor:default" title="%s">%08X</a></td>""" % (disables,disablesmask_to_string(disables),disables))
5270				out.append("""	</tr>""")
5271			elif ttymode:
5272				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"]
5273				if masterconn.version_at_least(1,7,0):
5274					dline.append("-" if meta else "yes" if sesflags&8 else "no")
5275				if meta:
5276					dline.extend(("-","-"))
5277				else:
5278					dline.extend((rootuid,rootgid))
5279				if meta or (sesflags&16)==0:
5280					dline.extend(("-","-"))
5281				else:
5282					dline.extend((mapalluid,mapallgid))
5283				if masterconn.version_at_least(1,6,26):
5284					if mingoal!=None and maxgoal!=None:
5285						dline.extend((mingoal,maxgoal))
5286					else:
5287						dline.extend(("-","-"))
5288					if mintrashtime!=None and maxtrashtime!=None:
5289						dline.extend((timeduration_to_shortstr(mintrashtime),timeduration_to_shortstr(maxtrashtime)))
5290					else:
5291						dline.extend(("-","-"))
5292				if masterconn.has_feature(FEATURE_EXPORT_UMASK):
5293					if umaskval==None:
5294						dline.append("-")
5295					else:
5296						dline.append("%03o" % umaskval)
5297				if masterconn.has_feature(FEATURE_EXPORT_DISABLES):
5298					dline.append("%08X (%s)" % (disables,disablesmask_to_string(disables)))
5299				tab.append(*dline)
5300			else:
5301				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"]
5302				if masterconn.version_at_least(1,7,0):
5303					dline.append("-" if meta else "yes" if sesflags&8 else "no")
5304				if meta:
5305					dline.extend(("-","-"))
5306				else:
5307					dline.extend((rootuid,rootgid))
5308				if meta or (sesflags&16)==0:
5309					dline.extend(("-","-"))
5310				else:
5311					dline.extend((mapalluid,mapallgid))
5312				if masterconn.version_at_least(1,6,26):
5313					if mingoal!=None and maxgoal!=None:
5314						dline.extend((mingoal,maxgoal))
5315					else:
5316						dline.extend(("-","-"))
5317					if mintrashtime!=None and maxtrashtime!=None:
5318						dline.extend((mintrashtime,maxtrashtime))
5319					else:
5320						dline.extend(("-","-"))
5321				if masterconn.has_feature(FEATURE_EXPORT_UMASK):
5322					if umaskval==None:
5323						dline.append("-")
5324					else:
5325						dline.append("%03o" % umaskval)
5326				if masterconn.has_feature(FEATURE_EXPORT_DISABLES):
5327					dline.append("%08X" % disables)
5328				tab.append(*dline)
5329		if cgimode:
5330			out.append("""</table>""")
5331			print("\n".join(out))
5332		else:
5333			print(myunicode(tab))
5334	except Exception:
5335		print_exception()
5336
5337if "MS" in sectionset and leaderfound:
5338	try:
5339		if cgimode:
5340			out = []
5341			out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsmounts" cellspacing="0">""")
5342			out.append("""	<tr><th colspan="%u">Active mounts (parameters)</th></tr>""" % (23 if masterconn.has_feature(FEATURE_EXPORT_DISABLES) else 22 if masterconn.has_feature(FEATURE_EXPORT_UMASK) else 21 if masterconn.version_at_least(1,7,8) else 19 if masterconn.version_at_least(1,7,0) else 18 if masterconn.version_at_least(1,6,26) else 14))
5343			out.append("""	<tr>""")
5344			out.append("""		<th rowspan="2" class="acid_tab_enumerate">#</th>""")
5345#			out.append("""		<th rowspan="2"><a href="%s">session&nbsp;id</a></th>""" % (createorderlink("MS",1)))
5346#			out.append("""		<th rowspan="2"><a href="%s">host</a></th>""" % (createorderlink("MS",2)))
5347#			out.append("""		<th rowspan="2"><a href="%s">ip</a></th>""" % (createorderlink("MS",3)))
5348#			out.append("""		<th rowspan="2"><a href="%s">mount&nbsp;point</a></th>""" % (createorderlink("MS",4)))
5349#			out.append("""		<th rowspan="2"><a href="%s">version</a></th>""" % (createorderlink("MS",5)))
5350#			out.append("""		<th rowspan="2"><a href="%s">root&nbsp;dir</a></th>""" % (createorderlink("MS",6)))
5351#			out.append("""		<th rowspan="2"><a href="%s">ro/rw</a></th>""" % (createorderlink("MS",7)))
5352#			out.append("""		<th rowspan="2"><a href="%s">restricted&nbsp;ip</a></th>""" % (createorderlink("MS",8)))
5353#			out.append("""		<th rowspan="2"><a href="%s">ignore&nbsp;gid</a></th>""" % (createorderlink("MS",9)))
5354			out.append("""		<th rowspan="2">session&nbsp;id</th>""")
5355			out.append("""		<th rowspan="2">host</th>""")
5356			out.append("""		<th rowspan="2">ip</th>""")
5357			out.append("""		<th rowspan="2">mount&nbsp;point</th>""")
5358			if masterconn.version_at_least(1,7,8):
5359				out.append("""		<th rowspan="2">open files</th>""")
5360				out.append("""		<th rowspan="2"># of connections</th>""")
5361			out.append("""		<th rowspan="2">version</th>""")
5362			out.append("""		<th rowspan="2">root&nbsp;dir</th>""")
5363			out.append("""		<th rowspan="2">ro/rw</th>""")
5364			out.append("""		<th rowspan="2">restricted&nbsp;ip</th>""")
5365			out.append("""		<th rowspan="2">ignore&nbsp;gid</th>""")
5366			if masterconn.version_at_least(1,7,0):
5367#				out.append("""		<th rowspan="2"><a href="%s">can&nbsp;change&nbsp;quota</a></th>""" % (createorderlink("MS",10)))
5368				out.append("""		<th rowspan="2">admin</th>""")
5369			out.append("""		<th colspan="2">map&nbsp;root</th>""")
5370			out.append("""		<th colspan="2">map&nbsp;users</th>""")
5371			if masterconn.version_at_least(1,6,26):
5372				out.append("""		<th colspan="2">goal&nbsp;limits</th>""")
5373				out.append("""		<th colspan="2">trashtime&nbsp;limits</th>""")
5374			if masterconn.has_feature(FEATURE_EXPORT_UMASK):
5375				out.append("""		<th rowspan="2">global umask</th>""")
5376			if masterconn.has_feature(FEATURE_EXPORT_DISABLES):
5377				out.append("""		<th rowspan="2">disables mask</th>""")
5378			out.append("""	</tr>""")
5379			out.append("""	<tr>""")
5380#			out.append("""		<th><a href="%s">uid</a></th>""" % (createorderlink("MS",11)))
5381#			out.append("""		<th><a href="%s">gid</a></th>""" % (createorderlink("MS",12)))
5382#			out.append("""		<th><a href="%s">uid</a></th>""" % (createorderlink("MS",13)))
5383#			out.append("""		<th><a href="%s">gid</a></th>""" % (createorderlink("MS",14)))
5384			out.append("""		<th>uid</th>""")
5385			out.append("""		<th>gid</th>""")
5386			out.append("""		<th>uid</th>""")
5387			out.append("""		<th>gid</th>""")
5388			if masterconn.version_at_least(1,6,26):
5389#				out.append("""		<th><a href="%s">min</a></th>""" % (createorderlink("MS",15)))
5390#				out.append("""		<th><a href="%s">max</a></th>""" % (createorderlink("MS",16)))
5391#				out.append("""		<th><a href="%s">min</a></th>""" % (createorderlink("MS",17)))
5392#				out.append("""		<th><a href="%s">max</a></th>""" % (createorderlink("MS",18)))
5393				out.append("""		<th>min</th>""")
5394				out.append("""		<th>max</th>""")
5395				out.append("""		<th>min</th>""")
5396				out.append("""		<th>max</th>""")
5397			out.append("""	</tr>""")
5398		elif ttymode:
5399			tab = Tabble("Active mounts (parameters)",(21 if masterconn.has_feature(FEATURE_EXPORT_DISABLES) else 20 if masterconn.has_feature(FEATURE_EXPORT_UMASK) else 19 if masterconn.version_at_least(1,7,8) else 17 if masterconn.version_at_least(1,7,0) else 16 if masterconn.version_at_least(1,6,26) else 12))
5400
5401			dline = ["r","r","l"]
5402			if masterconn.version_at_least(1,7,8):
5403				dline.extend(("r","r"))
5404			dline.extend(("r","l","c","c","c"))
5405			if masterconn.version_at_least(1,7,0):
5406				dline.append("c")
5407			dline.extend(("r","r","r","r"))
5408			if masterconn.version_at_least(1,6,26):
5409				dline.extend(("r","r","r","r"))
5410			if masterconn.has_feature(FEATURE_EXPORT_UMASK):
5411				dline.append("c")
5412			if masterconn.has_feature(FEATURE_EXPORT_DISABLES):
5413				dline.append("c")
5414			tab.defattr(*dline)
5415
5416			dline = ["","","","","","","",""]
5417			if masterconn.version_at_least(1,7,0):
5418				if masterconn.version_at_least(1,7,8):
5419					dline.extend(("",""))
5420				dline.append("")
5421			dline.extend((("map root","",2),("map users","",2)))
5422			if masterconn.version_at_least(1,6,26):
5423				dline.extend((("goal limit","",2),("trashtime limit","",2)))
5424			if masterconn.has_feature(FEATURE_EXPORT_UMASK):
5425				dline.append("")
5426			if masterconn.has_feature(FEATURE_EXPORT_DISABLES):
5427				dline.append("")
5428			tab.header(*dline)
5429
5430			dline = ["session id","ip/host","mount point"]
5431			if masterconn.version_at_least(1,7,8):
5432				dline.extend(("open files","# of connections"))
5433			dline.extend(("version","root dir","ro/rw","restrict ip","ignore gid"))
5434			if masterconn.version_at_least(1,7,0):
5435				dline.append("admin")
5436			if masterconn.version_at_least(1,6,26):
5437				dline.append(("---","",8))
5438			else:
5439				dline.append(("---","",4))
5440			if masterconn.has_feature(FEATURE_EXPORT_UMASK):
5441				dline.append("global umask")
5442			if masterconn.has_feature(FEATURE_EXPORT_DISABLES):
5443				dline.append("disables mask")
5444			tab.header(*dline)
5445
5446			dline = ["","","","","","","",""]
5447			if masterconn.version_at_least(1,7,0):
5448				if masterconn.version_at_least(1,7,8):
5449					dline.extend(("",""))
5450				dline.append("")
5451			dline.extend(("uid","gid","uid","gid"))
5452			if masterconn.version_at_least(1,6,26):
5453				dline.extend(("min","max","min","max"))
5454			if masterconn.has_feature(FEATURE_EXPORT_UMASK):
5455				dline.append("")
5456			if masterconn.has_feature(FEATURE_EXPORT_DISABLES):
5457				dline.append("")
5458			tab.header(*dline)
5459		else:
5460			tab = Tabble("active mounts, parameters",(21 if masterconn.has_feature(FEATURE_EXPORT_DISABLES) else 20 if masterconn.has_feature(FEATURE_EXPORT_UMASK) else 19 if masterconn.version_at_least(1,7,8) else 17 if masterconn.version_at_least(1,7,0) else 16 if masterconn.version_at_least(1,6,26) else 12))
5461
5462		servers = []
5463		dservers = []
5464		for ses in dataprovider.get_sessions():
5465			sf = ses.sortip
5466			if MSorder==1:
5467				sf = ses.sessionid
5468			elif MSorder==2:
5469				sf = ses.host
5470			elif MSorder==3:
5471				sf = ses.sortip
5472			elif MSorder==4:
5473				sf = ses.info
5474			elif MSorder==5:
5475				sf = ses.openfiles
5476			elif MSorder==6:
5477				if ses.nsocks>0:
5478					sf = ses.nsocks
5479				else:
5480					sf = ses.expire
5481			elif MSorder==7:
5482				sf = ses.sortver
5483			elif MSorder==8:
5484				sf = ses.path
5485			elif MSorder==9:
5486				sf = ses.sesflags&1
5487			elif MSorder==10:
5488				sf = 2-(ses.sesflags&2)
5489			elif MSorder==11:
5490				if ses.meta:
5491					sf = None
5492				else:
5493					sf = ses.sesflags&4
5494			elif MSorder==12:
5495				if ses.meta:
5496					sf = None
5497				else:
5498					sf = ses.sesflags&8
5499			elif MSorder==13:
5500				if ses.meta:
5501					sf = None
5502				else:
5503					sf = ses.rootuid
5504			elif MSorder==14:
5505				if ses.meta:
5506					sf = None
5507				else:
5508					sf = ses.rootgid
5509			elif MSorder==15:
5510				if ses.meta or (ses.sesflags&16)==0:
5511					sf = None
5512				else:
5513					sf = ses.mapalluid
5514			elif MSorder==16:
5515				if ses.meta or (ses.sesflags&16)==0:
5516					sf = None
5517				else:
5518					sf = ses.mapallgid
5519			elif MSorder==17:
5520				sf = ses.mingoal
5521			elif MSorder==18:
5522				sf = ses.maxgoal
5523			elif MSorder==19:
5524				sf = ses.mintrashtime
5525			elif MSorder==20:
5526				sf = ses.maxtrashtime
5527			elif MSorder==21:
5528				sf = ses.umaskval
5529			elif MSorder==22:
5530				sf = ses.disables
5531			if ses.nsocks>0:
5532				servers.append((sf,ses.sessionid,ses.host,ses.sortip,ses.strip,ses.info,ses.openfiles,ses.nsocks,ses.sortver,ses.strver,ses.meta,ses.path,ses.sesflags,ses.umaskval,ses.rootuid,ses.rootgid,ses.mapalluid,ses.mapallgid,ses.mingoal,ses.maxgoal,ses.mintrashtime,ses.maxtrashtime,ses.disables))
5533			else:
5534				dservers.append((sf,ses.sessionid,ses.host,ses.sortip,ses.strip,ses.info,ses.openfiles,ses.expire))
5535		servers.sort()
5536		dservers.sort()
5537		if MSrev:
5538			servers.reverse()
5539			dservers.reverse()
5540		for sf,sessionid,host,sortipnum,ipnum,info,openfiles,nsocks,sortver,strver,meta,path,sesflags,umaskval,rootuid,rootgid,mapalluid,mapallgid,mingoal,maxgoal,mintrashtime,maxtrashtime,disables in servers:
5541			if cgimode:
5542				if masterconn.is_pro() and not strver.endswith(" PRO"):
5543					verclass = "BADVERSION"
5544				elif masterconn.sort_ver() > sortver:
5545					verclass = "LOWERVERSION"
5546				elif masterconn.sort_ver() < sortver:
5547					verclass = "HIGHERVERSION"
5548				else:
5549					verclass = "OKVERSION"
5550				out.append("""	<tr>""")
5551				out.append("""		<td align="right"></td>""")
5552				out.append("""		<td align="center">%u</td>""" % sessionid)
5553				out.append("""		<td align="left">%s</td>""" % host)
5554				out.append("""		<td align="center"><span class="sortkey">%s </span>%s</td>""" % (sortipnum,ipnum))
5555				out.append("""		<td align="left">%s</td>""" % htmlentities(info))
5556				if masterconn.version_at_least(1,7,8):
5557					out.append("""		<td align="center">%u</td>""" % openfiles)
5558					out.append("""		<td align="center">%u</td>""" % nsocks)
5559				out.append("""		<td align="center"><span class="sortkey">%s </span><span class="%s">%s</span></td>""" % (sortver,verclass,strver))
5560				out.append("""		<td align="left">%s</td>""" % (".&nbsp;(META)" if meta else htmlentities(path)))
5561				out.append("""		<td align="center">%s</td>""" % ("ro" if sesflags&1 else "rw"))
5562				out.append("""		<td align="center">%s</td>""" % ("no" if sesflags&2 else "yes"))
5563				out.append("""		<td align="center">%s</td>""" % ("-" if meta else "yes" if sesflags&4 else "no"))
5564				if masterconn.version_at_least(1,7,0):
5565					out.append("""		<td align="center">%s</td>""" % ("-" if meta else "yes" if sesflags&8 else "no"))
5566				if meta:
5567					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5568					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5569				else:
5570					out.append("""		<td align="right">%u</td>""" % rootuid)
5571					out.append("""		<td align="right">%u</td>""" % rootgid)
5572				if meta or (sesflags&16)==0:
5573					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5574					out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5575				else:
5576					out.append("""		<td align="right">%u</td>""" % mapalluid)
5577					out.append("""		<td align="right">%u</td>""" % mapallgid)
5578				if masterconn.version_at_least(1,6,26):
5579					if mingoal!=None and maxgoal!=None:
5580						out.append("""		<td align="right">%u</td>""" % mingoal)
5581						out.append("""		<td align="right">%u</td>""" % maxgoal)
5582					else:
5583						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5584						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5585					if mintrashtime!=None and maxtrashtime!=None:
5586						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)))
5587						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)))
5588					else:
5589						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5590						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5591				if masterconn.has_feature(FEATURE_EXPORT_UMASK):
5592					if umaskval==None:
5593						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
5594					else:
5595						out.append("""		<td align="center">%03o</td>""" % umaskval)
5596				if masterconn.has_feature(FEATURE_EXPORT_DISABLES):
5597					out.append("""		<td align="center"><span class="sortkey">%u </span><a style="cursor:default" title="%s">%08X</a></td>""" % (disables,disablesmask_to_string(disables),disables))
5598				out.append("""	</tr>""")
5599			elif ttymode:
5600				dline = [sessionid,host,info]
5601				if masterconn.version_at_least(1,7,8):
5602					dline.extend((openfiles,nsocks))
5603				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"))
5604				if masterconn.version_at_least(1,7,0):
5605					dline.append("-" if meta else "yes" if sesflags&8 else "no")
5606				if meta:
5607					dline.extend(("-","-"))
5608				else:
5609					dline.extend((rootuid,rootgid))
5610				if meta or (sesflags&16)==0:
5611					dline.extend(("-","-"))
5612				else:
5613					dline.extend((mapalluid,mapallgid))
5614				if masterconn.version_at_least(1,6,26):
5615					if mingoal!=None and maxgoal!=None:
5616						dline.extend((mingoal,maxgoal))
5617					else:
5618						dline.extend(("-","-"))
5619					if mintrashtime!=None and maxtrashtime!=None:
5620						dline.extend((timeduration_to_shortstr(mintrashtime),timeduration_to_shortstr(maxtrashtime)))
5621					else:
5622						dline.extend(("-","-"))
5623				if masterconn.has_feature(FEATURE_EXPORT_UMASK):
5624					if umaskval==None:
5625						dline.append("-")
5626					else:
5627						dline.append("%03o" % umaskval)
5628				if masterconn.has_feature(FEATURE_EXPORT_DISABLES):
5629					dline.append("%08X (%s)" % (disables,disablesmask_to_string(disables)))
5630				tab.append(*dline)
5631			else:
5632				dline = [sessionid,host,info]
5633				if masterconn.version_at_least(1,7,8):
5634					dline.extend((openfiles,nsocks))
5635				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"))
5636				if masterconn.version_at_least(1,7,0):
5637					dline.append("-" if meta else "yes" if sesflags&8 else "no")
5638				if meta:
5639					dline.extend(("-","-"))
5640				else:
5641					dline.extend((rootuid,rootgid))
5642				if meta or (sesflags&16)==0:
5643					dline.extend(("-","-"))
5644				else:
5645					dline.extend((mapalluid,mapallgid))
5646				if masterconn.version_at_least(1,6,26):
5647					if mingoal!=None and maxgoal!=None:
5648						dline.extend((mingoal,maxgoal))
5649					else:
5650						dline.extend(("-","-"))
5651					if mintrashtime!=None and maxtrashtime!=None:
5652						dline.extend((mintrashtime,maxtrashtime))
5653					else:
5654						dline.extend(("-","-"))
5655				if masterconn.has_feature(FEATURE_EXPORT_UMASK):
5656					if umaskval==None:
5657						dline.append("-")
5658					else:
5659						dline.append("%03o" % umaskval)
5660				if masterconn.has_feature(FEATURE_EXPORT_DISABLES):
5661					dline.append("%08X" % disables)
5662				tab.append(*dline)
5663		if len(dservers)>0 and masterconn.version_at_least(1,7,8):
5664			if cgimode:
5665				out.append("""</table>""")
5666				out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsmounts" cellspacing="0">""")
5667				out.append("""	<tr><th colspan="8">Inactive mounts (parameters)</th></tr>""")
5668				out.append("""	<tr>""")
5669				out.append("""		<th class="acid_tab_enumerate">#</th>""")
5670				out.append("""		<th>session&nbsp;id</th>""")
5671				out.append("""		<th>host</th>""")
5672				out.append("""		<th>ip</th>""")
5673				out.append("""		<th>mount&nbsp;point</th>""")
5674				out.append("""		<th>open files</th>""")
5675				out.append("""		<th>expires</th>""")
5676				out.append("""		<th>cmd</th>""")
5677				out.append("""	</tr>""")
5678			elif ttymode:
5679				tabcols = (21 if masterconn.has_feature(FEATURE_EXPORT_DISABLES) else 20 if masterconn.has_feature(FEATURE_EXPORT_UMASK) else 19 if masterconn.version_at_least(1,7,8) else 17 if masterconn.version_at_least(1,7,0) else 16 if masterconn.version_at_least(1,6,26) else 12)
5680				tab.append(("---","",tabcols))
5681				tab.append(("Inactive mounts (parameters)","1c",tabcols))
5682				tab.append(("---","",tabcols))
5683				dline = [("session id","c"),("ip/host","c"),("mount point","c"),("open files","c"),("expires","c"),("command to remove","c",tabcols-5)]
5684				tab.append(*dline)
5685				tab.append(("---","",tabcols))
5686			else:
5687				print(myunicode(tab))
5688				print("")
5689				tab = Tabble("inactive mounts, parameters",5)
5690		for sf,sessionid,host,sortipnum,ipnum,info,openfiles,expire in dservers:
5691			if cgimode:
5692				out.append("""	<tr>""")
5693				out.append("""		<td align="right"></td>""")
5694				out.append("""		<td align="center">%u</td>""" % sessionid)
5695				out.append("""		<td align="left">%s</td>""" % host)
5696				out.append("""		<td align="center"><span class="sortkey">%s </span>%s</td>""" % (sortipnum,ipnum))
5697				out.append("""		<td align="left">%s</td>""" % info)
5698				out.append("""		<td align="center">%u</td>""" % openfiles)
5699				out.append("""		<td align="center">%u</td>""" % expire)
5700				out.append("""		<td align="center"><a href="%s">click to remove</a></td>""" % createlink({"MSremove":("%u" % (sessionid))}))
5701				out.append("""	</tr>""")
5702			elif ttymode:
5703				tabcols = (21 if masterconn.has_feature(FEATURE_EXPORT_DISABLES) else 20 if masterconn.has_feature(FEATURE_EXPORT_UMASK) else 19 if masterconn.version_at_least(1,7,8) else 17 if masterconn.version_at_least(1,7,0) else 16 if masterconn.version_at_least(1,6,26) else 12)
5704				dline = [sessionid,host,info,openfiles,expire,("%s -H %s -P %u -CRS/%u" % (sys.argv[0],masterhost,masterport,sessionid),"l",tabcols-5)]
5705				tab.append(*dline)
5706			else:
5707				dline = [sessionid,host,info,openfiles,expire]
5708				tab.append(*dline)
5709		if cgimode:
5710			out.append("""</table>""")
5711			print("\n".join(out))
5712		else:
5713			print(myunicode(tab))
5714	except Exception:
5715		print_exception()
5716
5717if "MO" in sectionset and leaderfound:
5718	try:
5719		if cgimode:
5720			out = []
5721			out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsops" cellspacing="0" id="mfsops">""")
5722#			out.append("""<table class="FR" cellspacing="0">""")
5723			out.append("""	<tr><th colspan="21">Active mounts (operations)</th></tr>""")
5724			out.append("""	<tr>""")
5725			out.append("""		<th rowspan="2" class="acid_tab_enumerate">#</th>""")
5726#			out.append("""		<th rowspan="2"><a href="%s">host</a></th>""" % (createorderlink("MO",1)))
5727#			out.append("""		<th rowspan="2"><a href="%s">ip</a></th>""" % (createorderlink("MO",2)))
5728#			out.append("""		<th rowspan="2"><a href="%s">mount&nbsp;point</a></th>""" % (createorderlink("MO",3)))
5729			out.append("""		<th rowspan="2">host</th>""")
5730			out.append("""		<th rowspan="2">ip</th>""")
5731			out.append("""		<th rowspan="2">mount&nbsp;point</th>""")
5732			out.append("""		<th colspan="17">""")
5733			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>""")
5734			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>""")
5735			out.append("""		</th>""")
5736			out.append("""	</tr>""")
5737			out.append("""	<tr>""")
5738#			out.append("""		<th><a href="%s">statfs</a></th>""" % (createorderlink("MO",100)))
5739#			out.append("""		<th><a href="%s">getattr</a></th>""" % (createorderlink("MO",101)))
5740#			out.append("""		<th><a href="%s">setattr</a></th>""" % (createorderlink("MO",102)))
5741#			out.append("""		<th><a href="%s">lookup</a></th>""" % (createorderlink("MO",103)))
5742#			out.append("""		<th><a href="%s">mkdir</a></th>""" % (createorderlink("MO",104)))
5743#			out.append("""		<th><a href="%s">rmdir</a></th>""" % (createorderlink("MO",105)))
5744#			out.append("""		<th><a href="%s">symlink</a></th>""" % (createorderlink("MO",106)))
5745#			out.append("""		<th><a href="%s">readlink</a></th>""" % (createorderlink("MO",107)))
5746#			out.append("""		<th><a href="%s">mknod</a></th>""" % (createorderlink("MO",108)))
5747#			out.append("""		<th><a href="%s">unlink</a></th>""" % (createorderlink("MO",109)))
5748#			out.append("""		<th><a href="%s">rename</a></th>""" % (createorderlink("MO",110)))
5749#			out.append("""		<th><a href="%s">link</a></th>""" % (createorderlink("MO",111)))
5750#			out.append("""		<th><a href="%s">readdir</a></th>""" % (createorderlink("MO",112)))
5751#			out.append("""		<th><a href="%s">open</a></th>""" % (createorderlink("MO",113)))
5752#			out.append("""		<th><a href="%s">read</a></th>""" % (createorderlink("MO",114)))
5753#			out.append("""		<th><a href="%s">write</a></th>""" % (createorderlink("MO",115)))
5754#			out.append("""		<th><a href="%s">total</a></th>""" % (createorderlink("MO",150)))
5755			out.append("""		<th class="acid_tab_level_1">statfs</th>""")
5756			out.append("""		<th class="acid_tab_level_1">getattr</th>""")
5757			out.append("""		<th class="acid_tab_level_1">setattr</th>""")
5758			out.append("""		<th class="acid_tab_level_1">lookup</th>""")
5759			out.append("""		<th class="acid_tab_level_1">mkdir</th>""")
5760			out.append("""		<th class="acid_tab_level_1">rmdir</th>""")
5761			out.append("""		<th class="acid_tab_level_1">symlink</th>""")
5762			out.append("""		<th class="acid_tab_level_1">readlink</th>""")
5763			out.append("""		<th class="acid_tab_level_1">mknod</th>""")
5764			out.append("""		<th class="acid_tab_level_1">unlink</th>""")
5765			out.append("""		<th class="acid_tab_level_1">rename</th>""")
5766			out.append("""		<th class="acid_tab_level_1">link</th>""")
5767			out.append("""		<th class="acid_tab_level_1">readdir</th>""")
5768			out.append("""		<th class="acid_tab_level_1">open</th>""")
5769			out.append("""		<th class="acid_tab_level_1">read</th>""")
5770			out.append("""		<th class="acid_tab_level_1">write</th>""")
5771			out.append("""		<th class="acid_tab_level_1">total</th>""")
5772			out.append("""	</tr>""")
5773		elif ttymode:
5774			tab = Tabble("Active mounts (operations)",19)
5775			tab.header("","",("operations %s hour" % ("last" if MOdata==0 else "current"),"",17))
5776			tab.header("host/ip","mount point",("---","",17))
5777			tab.header("","","statfs","getattr","setattr","lookup","mkdir","rmdir","symlink","readlink","mknod","unlink","rename","link","readdir","open","read","write","total")
5778			tab.defattr("r","l","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r")
5779		else:
5780			tab = Tabble("active mounts, operations",19)
5781		servers = []
5782		for ses in dataprovider.get_sessions():
5783			sf = ses.sortip
5784			if MOorder==1:
5785				sf = ses.host
5786			elif MOorder==2:
5787				sf = ses.sortip
5788			elif MOorder==3:
5789				sf = ses.info
5790			elif MOorder>=100 and MOorder<=115:
5791				sfmul = -1 if cgimode else 1
5792				if MOdata==0:
5793					sf = sfmul * ses.stats_l[MOorder-100]
5794				else:
5795					sf = sfmul * ses.stats_c[MOorder-100]
5796			elif MOorder==150:
5797				sfmul = -1 if cgimode else 1
5798				if MOdata==0:
5799					sf = sfmul * sum(ses.stats_l)
5800				else:
5801					sf = sfmul * sum(ses.stats_c)
5802			if ses.path!='.':
5803				servers.append((sf,ses.host,ses.sortip,ses.strip,ses.info,ses.stats_c,ses.stats_l))
5804		servers.sort()
5805		if MOrev:
5806			servers.reverse()
5807		for sf,host,sortipnum,ipnum,info,stats_c,stats_l in servers:
5808			if cgimode:
5809				out.append("""	<tr>""")
5810				out.append("""		<td align="right"></td>""")
5811				out.append("""		<td align="left">%s</td>""" % host)
5812				out.append("""		<td align="center"><span class="sortkey">%s</span>%s</td>""" % (sortipnum,ipnum))
5813				out.append("""		<td align="left">%s</td>""" % htmlentities(info))
5814				for st in range(16):
5815					out.append("""		<td align="right">""")
5816					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]))
5817					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]))
5818					out.append("""		</td>""")
5819				out.append("""		<td align="right">""")
5820				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)))
5821				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)))
5822				out.append("""		</td>""")
5823#					if MOdata==0:
5824#						for st in xrange(16):
5825#							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]))
5826#						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)))
5827#					else:
5828#						for st in xrange(16):
5829#							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]))
5830#						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)))
5831				out.append("""	</tr>""")
5832			else:
5833				ldata = [host,info]
5834				if MOdata==0:
5835					ldata.extend(stats_l)
5836					ldata.append(sum(stats_l))
5837				else:
5838					ldata.extend(stats_c)
5839					ldata.append(sum(stats_c))
5840				tab.append(*ldata)
5841		if cgimode:
5842			out.append("""</table>""")
5843			print("\n".join(out))
5844		else:
5845			print(myunicode(tab))
5846	except Exception:
5847		print_exception()
5848
5849if "RS" in sectionset and leaderfound:
5850
5851	if "SC" in sectionsubset:
5852		try:
5853			if cgimode:
5854				out = []
5855				out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsls" cellspacing="0">""")
5856				out.append("""	<tr><th colspan="22">Storage Classes</th></tr>""")
5857				out.append("""	<tr>""")
5858				out.append("""		<th rowspan="2">id</th>""")
5859				out.append("""		<th rowspan="2">name</th>""")
5860				out.append("""		<th rowspan="2">admin only</th>""")
5861				out.append("""		<th rowspan="2">mode</th>""")
5862				out.append("""		<th colspan="2"># of inodes</th>""")
5863				out.append("""		<th colspan="3"># of standard chunks</th>""")
5864				out.append("""		<th colspan="3"># of archived chunks</th>""")
5865				out.append("""		<th colspan="3">create</th>""")
5866				out.append("""		<th colspan="3">keep</th>""")
5867				out.append("""		<th colspan="4">archive</th>""")
5868				out.append("""	</tr>""")
5869				out.append("""	<tr>""")
5870				out.append("""		<th>files</th>""")
5871				out.append("""		<th>dirs</th>""")
5872				out.append("""		<th>under</th>""")
5873				out.append("""		<th>exact</th>""")
5874				out.append("""		<th>over</th>""")
5875				out.append("""		<th>under</th>""")
5876				out.append("""		<th>exact</th>""")
5877				out.append("""		<th>over</th>""")
5878				out.append("""		<th>can be fulfilled</th>""")
5879				out.append("""		<th>goal</th>""")
5880				out.append("""		<th>labels</th>""")
5881				out.append("""		<th>can be fulfilled</th>""")
5882				out.append("""		<th>goal</th>""")
5883				out.append("""		<th>labels</th>""")
5884				out.append("""		<th>can be fulfilled</th>""")
5885				out.append("""		<th>goal</th>""")
5886				out.append("""		<th>labels</th>""")
5887				out.append("""		<th>delay</th>""")
5888				out.append("""	</tr>""")
5889			elif ttymode:
5890				tab = Tabble("Storage Classes",22,"r")
5891				tab.header("","","","",("# of inodes","",2),("# of standard chunks","",3),("# of archived chunks","",3),("create","",3),("keep","",3),("archive","",4))
5892				tab.header("id","name","admin only","mode",("---","",18))
5893				tab.header("","","","","files","dirs","under","exact","over","under","exact","over","can be fulfilled","goal","labels","can be fulfilled","goal","labels","can be fulfilled","goal","labels","delay")
5894				tab.defattr("r","l","c","c","r","r","r","r","r","r","r","r","c","r","l","c","r","l","c","r","l","r")
5895			else:
5896				tab = Tabble("storage classes",22)
5897			sclasses = []
5898			data,length = masterconn.command(CLTOMA_SCLASS_INFO,MATOCL_SCLASS_INFO)
5899			scount = struct.unpack(">H",data[:2])[0]
5900			pos = 2
5901			while pos < length:
5902				if masterconn.version_at_least(3,0,75):
5903					sclassid,sclassnleng = struct.unpack_from(">BB",data,pos)
5904					pos += 2
5905					sclassname = data[pos:pos+sclassnleng]
5906					sclassname = sclassname.decode('utf-8','replace')
5907					pos += sclassnleng
5908					files,dirs,stdchunks_under,archchunks_under,stdchunks_exact,archchunks_exact,stdchunks_over,archchunks_over,admin_only,mode,arch_delay,create_canbefulfilled,create_labelscnt,keep_canbefulfilled,keep_labelscnt,arch_canbefulfilled,arch_labelscnt = struct.unpack_from(">LLQQQQQQBBHBBBBBB",data,pos)
5909					pos += 18 + 3 * 16
5910					if arch_delay==0:
5911						stdchunks_under += archchunks_under
5912						stdchunks_exact += archchunks_exact
5913						stdchunks_over += archchunks_over
5914						archchunks_under = None
5915						archchunks_exact = None
5916						archchunks_over = None
5917				elif masterconn.version_at_least(3,0,9):
5918					sclassid,files,dirs,stdchunks_under,archchunks_under,stdchunks_exact,archchunks_exact,stdchunks_over,archchunks_over,mode,arch_delay,create_canbefulfilled,create_labelscnt,keep_canbefulfilled,keep_labelscnt,arch_canbefulfilled,arch_labelscnt = struct.unpack_from(">BLLQQQQQQBHBBBBBB",data,pos)
5919					pos += 18 + 3 * 16
5920					admin_only = 0
5921					if sclassid<10:
5922						sclassname = str(sclassid)
5923					else:
5924						sclassname = "sclass_%u" % (sclassid-9)
5925					if arch_delay==0:
5926						stdchunks_under += archchunks_under
5927						stdchunks_exact += archchunks_exact
5928						stdchunks_over += archchunks_over
5929						archchunks_under = None
5930						archchunks_exact = None
5931						archchunks_over = None
5932				else:
5933					sclassid,files,create_canbefulfilled,create_labelscnt = struct.unpack_from(">BLBB",data,pos)
5934					admin_only = 0
5935					if sclassid<10:
5936						sclassname = str(sclassid)
5937					else:
5938						sclassname = "sclass_%u" % (sclassid-9)
5939					dirs = 0
5940					if create_canbefulfilled:
5941						create_canbefulfilled = 3
5942					keep_canbefulfilled = create_canbefulfilled
5943					arch_canbefulfilled = create_canbefulfilled
5944					keep_labelscnt = create_labelscnt
5945					arch_labelscnt = create_labelscnt
5946					mode = 1
5947					arch_delay = 0
5948					stdchunks_under = None
5949					archchunks_under = None
5950					stdchunks_exact = None
5951					archchunks_exact = None
5952					stdchunks_over = None
5953					archchunks_over = None
5954					pos+=7
5955				create_labellist = []
5956				for i in xrange(create_labelscnt):
5957					labelmasks = struct.unpack_from(">"+"L"*MASKORGROUP,data,pos)
5958					pos+=4*MASKORGROUP
5959					matchingservers = struct.unpack_from(">H",data,pos)[0]
5960					pos+=2
5961					create_labellist.append((labelmasks_to_str(labelmasks),matchingservers))
5962				if masterconn.version_at_least(3,0,9):
5963					keep_labellist = []
5964					for i in xrange(keep_labelscnt):
5965						labelmasks = struct.unpack_from(">"+"L"*MASKORGROUP,data,pos)
5966						pos+=4*MASKORGROUP
5967						matchingservers = struct.unpack_from(">H",data,pos)[0]
5968						pos+=2
5969						keep_labellist.append((labelmasks_to_str(labelmasks),matchingservers))
5970					arch_labellist = []
5971					for i in xrange(arch_labelscnt):
5972						labelmasks = struct.unpack_from(">"+"L"*MASKORGROUP,data,pos)
5973						pos+=4*MASKORGROUP
5974						matchingservers = struct.unpack_from(">H",data,pos)[0]
5975						pos+=2
5976						arch_labellist.append((labelmasks_to_str(labelmasks),matchingservers))
5977				else:
5978					keep_labellist = create_labellist
5979					arch_labellist = create_labellist
5980				sf = sclassid
5981				if SCorder==2:
5982					sf = sclassname
5983				elif SCorder==3:
5984					sf = admin_only
5985				elif SCorder==4:
5986					sf = files
5987				elif SCorder==5:
5988					sf = dirs
5989				elif SCorder==6:
5990					sf = stdchunks_under
5991				elif SCorder==7:
5992					sf = stdchunks_exact
5993				elif SCorder==8:
5994					sf = stdchunks_over
5995				elif SCorder==9:
5996					sf = archchunks_under
5997				elif SCorder==10:
5998					sf = archchunks_exact
5999				elif SCorder==11:
6000					sf = archchunks_over
6001				elif SCorder==12:
6002					sf = mode
6003				elif SCorder==13:
6004					sf = create_canbefulfilled
6005				elif SCorder==14:
6006					sf = create_labelscnt
6007				elif SCorder==15:
6008					sf = create_labellist
6009				elif SCorder==16:
6010					sf = keep_canbefulfilled
6011				elif SCorder==17:
6012					sf = keep_labelscnt
6013				elif SCorder==18:
6014					sf = keep_labellist
6015				elif SCorder==19:
6016					sf = arch_canbefulfilled
6017				elif SCorder==20:
6018					sf = arch_labelscnt
6019				elif SCorder==21:
6020					sf = arch_labellist
6021				elif SCorder==22:
6022					sf = arch_delay
6023				sclasses.append((sf,sclassid,sclassname,admin_only,mode,files,dirs,stdchunks_under,stdchunks_exact,stdchunks_over,archchunks_under,archchunks_exact,archchunks_over,create_canbefulfilled,create_labellist,keep_canbefulfilled,keep_labellist,arch_canbefulfilled,arch_labellist,arch_delay))
6024			sclasses.sort()
6025			if SCrev:
6026				sclasses.reverse()
6027			for sf,sclassid,sclassname,admin_only,mode,files,dirs,stdchunks_under,stdchunks_exact,stdchunks_over,archchunks_under,archchunks_exact,archchunks_over,create_canbefulfilled,create_labellist,keep_canbefulfilled,keep_labellist,arch_canbefulfilled,arch_labellist,arch_delay in sclasses:
6028				if cgimode:
6029					allcolor = (0,160,224)
6030					zerocolor = (0,0,128)
6031					out.append("""	<tr>""")
6032					out.append("""		<td align="right">%u</td>""" % sclassid)
6033					out.append("""		<td align="right">%s</td>""" % htmlentities(sclassname))
6034					out.append("""		<td align="right">%s</td>""" % ("YES" if admin_only else "NO"))
6035					out.append("""		<td align="center">%s</td>""" % ("LOOSE" if mode==0 else "STD" if mode==1 else "STRICT"))
6036					out.append("""		<td align="right">%u</td>""" % files)
6037					out.append("""		<td align="right">%u</td>""" % dirs)
6038					if stdchunks_under!=None and stdchunks_exact!=None and stdchunks_over!=None:
6039						out.append("""		<td align="right"><span class="UNDERGOAL">%s</span></td>""" % (("%u" % stdchunks_under) if stdchunks_under>0 else "&nbsp;"))
6040						out.append("""		<td align="right"><span class="NORMAL">%u</span></td>""" % stdchunks_exact)
6041						out.append("""		<td align="right"><span class="OVERGOAL">%s</span></td>""" % (("%u" % stdchunks_over) if stdchunks_over>0 else "&nbsp;"))
6042					else:
6043						out.append("""		<td align="center">-</td>""")
6044						out.append("""		<td align="center">-</td>""")
6045						out.append("""		<td align="center">-</td>""")
6046					if archchunks_under!=None and archchunks_exact!=None and archchunks_over!=None:
6047						out.append("""		<td align="right"><span class="UNDERGOAL">%s</span></td>""" % (("%u" % archchunks_under) if archchunks_under>0 else "&nbsp;"))
6048						out.append("""		<td align="right"><span class="NORMAL">%u</span></td>""" % archchunks_exact)
6049						out.append("""		<td align="right"><span class="OVERGOAL">%s</span></td>""" % (("%u" % archchunks_over) if archchunks_over>0 else "&nbsp;"))
6050					else:
6051						out.append("""		<td align="center">-</td>""")
6052						out.append("""		<td align="center">-</td>""")
6053						out.append("""		<td align="center">-</td>""")
6054					if create_canbefulfilled==3:
6055						out.append("""		<td align="center">YES</td>""")
6056					elif create_canbefulfilled==2:
6057						out.append("""		<td align="center"><span class="WARNING">OVERLOADED</span></td>""")
6058					elif create_canbefulfilled==1:
6059						out.append("""		<td align="center"><span class="WARNING">NO SPACE</span></td>""")
6060					else:
6061						out.append("""		<td align="center"><span class="ERROR">NO</span></td>""")
6062					labelsarr = []
6063					for labelstr,mscount in create_labellist:
6064						if scount==0:
6065							msperc = 0;
6066						else:
6067							msperc = (1.0 * mscount) / scount
6068						perccolor = (int(zerocolor[0]+(allcolor[0]-zerocolor[0])*msperc),int(zerocolor[1]+(allcolor[1]-zerocolor[1])*msperc),int(zerocolor[2]+(allcolor[2]-zerocolor[2])*msperc))
6069						color = "#%02X%02X%02X" % perccolor
6070						labelsarr.append("""<span style="color:%s"><a style="cursor:default" title="%u/%u servers">%s</a></span>""" % (color,mscount,scount,labelstr))
6071					out.append("""		<td align="center">%u</td>""" % (len(labelsarr)))
6072					out.append("""		<td align="center">%s</td>""" % ("&nbsp;,&nbsp;".join(labelsarr)))
6073					if keep_canbefulfilled==3:
6074						out.append("""		<td align="center">YES</td>""")
6075					elif keep_canbefulfilled==2:
6076						out.append("""		<td align="center"><span class="WARNING">OVERLOADED</span></td>""")
6077					elif keep_canbefulfilled==1:
6078						out.append("""		<td align="center"><span class="WARNING">NO SPACE</span></td>""")
6079					else:
6080						out.append("""		<td align="center"><span class="ERROR">NO</span></td>""")
6081					labelsarr = []
6082					for labelstr,mscount in keep_labellist:
6083						if scount==0:
6084							msperc = 0;
6085						else:
6086							msperc = (1.0 * mscount) / scount
6087						perccolor = (int(zerocolor[0]+(allcolor[0]-zerocolor[0])*msperc),int(zerocolor[1]+(allcolor[1]-zerocolor[1])*msperc),int(zerocolor[2]+(allcolor[2]-zerocolor[2])*msperc))
6088						color = "#%02X%02X%02X" % perccolor
6089						labelsarr.append("""<span style="color:%s"><a style="cursor:default" title="%u/%u servers">%s</a></span>""" % (color,mscount,scount,labelstr))
6090					out.append("""		<td align="center">%u</td>""" % (len(labelsarr)))
6091					out.append("""		<td align="center">%s</td>""" % ("&nbsp;,&nbsp;".join(labelsarr)))
6092					if arch_canbefulfilled==3:
6093						out.append("""		<td align="center">YES</td>""")
6094					elif arch_canbefulfilled==2:
6095						out.append("""		<td align="center"><span class="WARNING">OVERLOADED</span></td>""")
6096					elif arch_canbefulfilled==1:
6097						out.append("""		<td align="center"><span class="WARNING">NO SPACE</span></td>""")
6098					else:
6099						out.append("""		<td align="center"><span class="ERROR">NO</span></td>""")
6100					labelsarr = []
6101					for labelstr,mscount in arch_labellist:
6102						msperc = (1.0 * mscount) / scount
6103						perccolor = (int(zerocolor[0]+(allcolor[0]-zerocolor[0])*msperc),int(zerocolor[1]+(allcolor[1]-zerocolor[1])*msperc),int(zerocolor[2]+(allcolor[2]-zerocolor[2])*msperc))
6104						color = "#%02X%02X%02X" % perccolor
6105						labelsarr.append("""<span style="color:%s"><a style="cursor:default" title="%u/%u servers">%s</a></span>""" % (color,mscount,scount,labelstr))
6106					out.append("""		<td align="center">%u</td>""" % (len(labelsarr)))
6107					out.append("""		<td align="center">%s</td>""" % ("&nbsp;,&nbsp;".join(labelsarr)))
6108					if arch_delay>0:
6109						out.append("""		<td align="center">%ud</td>""" % arch_delay)
6110					else:
6111						out.append("""		<td align="center">-</td>""")
6112					out.append("""	</tr>""")
6113				else:
6114					data = [sclassid,sclassname,("YES" if admin_only else "NO"),"LOOSE" if mode==0 else "STD" if mode==1 else "STRICT",files,dirs]
6115					if stdchunks_under!=None and stdchunks_exact!=None and stdchunks_over!=None:
6116						data.append((stdchunks_under,'3') if stdchunks_under>0 else "-")
6117						data.append((stdchunks_exact,'4'))
6118						data.append((stdchunks_over,'5') if stdchunks_over>0 else "-")
6119					else:
6120						data.extend(["-","-","-"])
6121					if archchunks_under!=None and archchunks_exact!=None and archchunks_over!=None:
6122						data.append((archchunks_under,'3') if archchunks_under>0 else "-")
6123						data.append((archchunks_exact,'4'))
6124						data.append((archchunks_over,'5') if archchunks_over>0 else "-")
6125					else:
6126						data.extend(["-","-","-"])
6127					if create_canbefulfilled==3:
6128						data.append(("YES",'4'))
6129					elif create_canbefulfilled==2:
6130						data.append(("OVERLOADED",'3'))
6131					elif create_canbefulfilled==1:
6132						data.append(("NO SPACE",'2'))
6133					else:
6134						data.append(("NO",'1'))
6135					data.append("%u" % len(create_labellist))
6136					data.append("%s" % (" , ".join([x for x,y in create_labellist])))
6137					if keep_canbefulfilled==3:
6138						data.append(("YES",'4'))
6139					elif keep_canbefulfilled==2:
6140						data.append(("OVERLOADED",'3'))
6141					elif keep_canbefulfilled==1:
6142						data.append(("NO SPACE",'2'))
6143					else:
6144						data.append(("NO",'1'))
6145					data.append("%u" % len(keep_labellist))
6146					data.append("%s" % (" , ".join([x for x,y in keep_labellist])))
6147					if arch_canbefulfilled==3:
6148						data.append(("YES",'4'))
6149					elif arch_canbefulfilled==2:
6150						data.append(("OVERLOADED",'3'))
6151					elif arch_canbefulfilled==1:
6152						data.append(("NO SPACE",'2'))
6153					else:
6154						data.append(("NO",'1'))
6155					data.append("%u" % len(arch_labellist))
6156					data.append("%s" % (" , ".join([x for x,y in arch_labellist])))
6157					if arch_delay>0:
6158						data.append("%ud" % arch_delay)
6159					else:
6160						data.append("-")
6161					tab.append(*data)
6162			if cgimode:
6163				out.append("""</table>""")
6164				print("\n".join(out))
6165			else:
6166				print(myunicode(tab))
6167		except Exception:
6168			print_exception()
6169
6170	inodes = set()
6171	if "OF" in sectionsubset:
6172		try:
6173			sessionsdata = {}
6174			for ses in dataprovider.get_sessions():
6175				sessionsdata[ses.sessionid]=(ses.host,ses.sortip,ses.strip,ses.info,ses.openfiles)
6176			if cgimode:
6177				out = []
6178				out.append("""<form action="#"><table class="FR" cellspacing="0"><tr><th>Show open files for: <select name="server" size="1" onchange="document.location.href='%s&OFsessionid='+this.options[this.selectedIndex].value">""" % createjslink({"OFsessionid":""}))
6179				if OFsessionid==0:
6180					out.append("""<option value="0" selected="selected"> select session</option>""")
6181				sessions = list(sessionsdata.keys())
6182				sessions.sort()
6183				for sessionid in sessions:
6184					host,sortipnum,ipnum,info,openfiles = sessionsdata[sessionid]
6185					if OFsessionid==sessionid:
6186						out.append("""<option value="%s" selected="selected">%s: %s:%s (open files: ~%u)</option>""" % (sessionid,sessionid,host,info,openfiles))
6187					else:
6188						out.append("""<option value="%s">%s: %s:%s (open files: ~%u)</option>""" % (sessionid,sessionid,host,info,openfiles))
6189				out.append("""</select></th></tr></table></form>""")
6190				if OFsessionid!=0:
6191					out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsopenfiles" cellspacing="0">""")
6192					out.append("""	<tr><th colspan="7">Open files by client with session id: %u</th></tr>""" % OFsessionid)
6193					out.append("""	<tr>""")
6194					out.append("""		<th rowspan="2" class="acid_tab_enumerate">#</th>""")
6195					out.append("""		<th rowspan="2">session&nbsp;id</th>""")
6196					out.append("""		<th rowspan="2">host</th>""")
6197					out.append("""		<th rowspan="2">ip</th>""")
6198					out.append("""		<th rowspan="2">mount&nbsp;point</th>""")
6199					out.append("""		<th rowspan="2">inode</th>""")
6200					out.append("""		<th rowspan="2">paths</th>""")
6201					out.append("""	</tr>""")
6202			elif ttymode:
6203				tab = Tabble("Open Files",5)
6204				tab.header("session id","ip/host","mount point","inode","path")
6205				tab.defattr("r","r","l","r","l")
6206			else:
6207				tab = Tabble("open file",5)
6208			if cgimode and OFsessionid==0:
6209				ofdata = []
6210			else:
6211				data,length = masterconn.command(CLTOMA_LIST_OPEN_FILES,MATOCL_LIST_OPEN_FILES,struct.pack(">L",OFsessionid))
6212				openfiles = []
6213				if OFsessionid==0:
6214					n = length//8
6215					for x in xrange(n):
6216						sessionid,inode = struct.unpack(">LL",data[x*8:x*8+8])
6217						openfiles.append((sessionid,inode))
6218						inodes.add(inode)
6219				else:
6220					n = length//4
6221					for x in xrange(n):
6222						inode = struct.unpack(">L",data[x*4:x*4+4])[0]
6223						openfiles.append((OFsessionid,inode))
6224						inodes.add(inode)
6225				inodepaths = resolve_inodes_paths(masterconn,inodes)
6226				ofdata = []
6227				for sessionid,inode in openfiles:
6228					if sessionid in sessionsdata:
6229						host,sortipnum,ipnum,info,openfiles = sessionsdata[sessionid]
6230					else:
6231						host = 'unknown'
6232						sortipnum = ''
6233						ipnum = ''
6234						info = 'unknown'
6235					if inode in inodepaths:
6236						paths = inodepaths[inode]
6237					else:
6238						paths = []
6239					sf = sortipnum
6240					if OForder==1:
6241						sf = sessionid
6242					elif OForder==2:
6243						sf = hostip
6244					elif OForder==3:
6245						sf = sortipnum
6246					elif OForder==4:
6247						sf = info
6248					elif OForder==5:
6249						sf = inode
6250					elif OForder==6:
6251						sf = paths
6252					ofdata.append((sf,sessionid,host,sortipnum,ipnum,info,inode,paths))
6253				ofdata.sort()
6254				if OFrev:
6255					ofdata.reverse()
6256			for sf,sessionid,host,sortipnum,ipnum,info,inode,paths in ofdata:
6257				if cgimode:
6258					for path in paths:
6259						out.append("""	<tr>""")
6260						out.append("""		<td align="right"></td>""")
6261						out.append("""		<td align="center">%u</td>""" % sessionid)
6262						out.append("""		<td align="left">%s</td>""" % host)
6263						out.append("""		<td align="center"><span class="sortkey">%s </span>%s</td>""" % (sortipnum,ipnum))
6264						out.append("""		<td align="left">%s</td>""" % htmlentities(info))
6265						out.append("""		<td align="center">%u</td>""" % inode)
6266						out.append("""		<td align="left">%s</td>""" % htmlentities(path))
6267						out.append("""	</tr>""")
6268				else:
6269					if len(paths)==0:
6270						dline = [sessionid,host,info,inode,"unknown"]
6271						tab.append(*dline)
6272					else:
6273						for path in paths:
6274							dline = [sessionid,host,info,inode,path]
6275							tab.append(*dline)
6276			if cgimode:
6277				if OFsessionid!=0:
6278					out.append("""</table>""")
6279				print("\n".join(out))
6280			else:
6281				#print(openfiles)
6282				print(myunicode(tab))
6283		except Exception:
6284			print_exception()
6285
6286	if "AL" in sectionsubset:
6287		try:
6288			sessionsdata = {}
6289			for ses in dataprovider.get_sessions():
6290				sessionsdata[ses.sessionid]=(ses.host,ses.sortip,ses.strip,ses.info,ses.openfiles)
6291			if cgimode:
6292				if ALinode not in inodes:
6293					ALinode = 0
6294				out = []
6295				if len(inodes)>0:
6296					out.append("""<form action="#"><table class="FR" cellspacing="0"><tr><th>Show acquired locks for: <select name="server" size="1" onchange="document.location.href='%s&ALinode='+this.options[this.selectedIndex].value">""" % createjslink({"ALinode":""}))
6297					if ALinode==0:
6298						out.append("""<option value="0" selected="selected"> select inode</option>""")
6299					inodeslist = list(inodes)
6300					inodeslist.sort()
6301					for inode in inodeslist:
6302						if ALinode==inode:
6303							out.append("""<option value="%u" selected="selected">%u</option>""" % (inode,inode))
6304						else:
6305							out.append("""<option value="%u">%u</option>""" % (inode,inode))
6306					out.append("""</select></th></tr></table></form>""")
6307					if ALinode!=0:
6308						out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_acquiredlocks" cellspacing="0">""")
6309						out.append("""	<tr><th colspan="11">Acquired locks for inode: %u</th></tr>""" % ALinode)
6310						out.append("""	<tr>""")
6311						out.append("""		<th rowspan="2" class="acid_tab_enumerate">#</th>""")
6312						out.append("""		<th rowspan="2">session&nbsp;id</th>""")
6313						out.append("""		<th rowspan="2">host</th>""")
6314						out.append("""		<th rowspan="2">ip</th>""")
6315						out.append("""		<th rowspan="2">mount&nbsp;point</th>""")
6316						out.append("""		<th rowspan="2">lock type</th>""")
6317						out.append("""		<th rowspan="2">owner id</th>""")
6318						out.append("""		<th rowspan="2">pid</th>""")
6319						out.append("""		<th rowspan="2">start</th>""")
6320						out.append("""		<th rowspan="2">end</th>""")
6321						out.append("""		<th rowspan="2">r/w</th>""")
6322						out.append("""	</tr>""")
6323			elif ttymode:
6324				tab = Tabble("Acquired Locks",10,"r")
6325				tab.header("inode","session id","ip/host","mount point","lock type","owner","pid","start","end","r/w")
6326			else:
6327				tab = Tabble("acquired locks",10)
6328			if cgimode and ALinode==0:
6329				aldata = []
6330			else:
6331				data,length = masterconn.command(CLTOMA_LIST_ACQUIRED_LOCKS,MATOCL_LIST_ACQUIRED_LOCKS,struct.pack(">L",ALinode))
6332				locks = []
6333				if ALinode==0:
6334					n = length//37
6335					for x in xrange(n):
6336						inode,sessionid,owner,pid,start,end,ctype = struct.unpack(">LLQLQQB",data[x*37:x*37+37])
6337						locks.append((inode,sessionid,owner,pid,start,end,ctype))
6338				else:
6339					n = length//33
6340					for x in xrange(n):
6341						sessionid,owner,pid,start,end,ctype = struct.unpack(">LQLQQB",data[x*33:x*33+33])
6342						locks.append((ALinode,sessionid,owner,pid,start,end,ctype))
6343				aldata = []
6344				for inode,sessionid,owner,pid,start,end,ctype in locks:
6345					if sessionid in sessionsdata:
6346						host,sortipnum,ipnum,info,openfiles = sessionsdata[sessionid]
6347					else:
6348						host = 'unknown'
6349						sortipnum = ''
6350						ipnum = ''
6351						info = 'unknown'
6352					if pid==0 and start==0 and end==0:
6353						locktype = "FLOCK"
6354					else:
6355						locktype = "POSIX"
6356					sf = inode
6357					if ALorder==1:
6358						sf = inode
6359					elif ALorder==2:
6360						sf = sessionid
6361					elif ALorder==3:
6362						sf = hostip
6363					elif ALorder==4:
6364						sf = sortipnum
6365					elif ALorder==5:
6366						sf = info
6367					elif ALorder==6:
6368						sf = locktype
6369					elif ALorder==7:
6370						sf = owner
6371					elif ALorder==8:
6372						sf = pid
6373					elif ALorder==9:
6374						sf = start
6375					elif ALorder==10:
6376						sf = end
6377					elif ALorder==11:
6378						sf = ctype
6379					aldata.append((sf,inode,sessionid,host,sortipnum,ipnum,info,locktype,owner,pid,start,end,ctype))
6380				aldata.sort()
6381				if ALrev:
6382					aldata.reverse()
6383			for sf,inode,sessionid,host,sortipnum,ipnum,info,locktype,owner,pid,start,end,ctype in aldata:
6384				if cgimode:
6385					out.append("""	<tr>""")
6386					out.append("""		<td align="right"></td>""")
6387					out.append("""		<td align="center">%u</td>""" % sessionid)
6388					out.append("""		<td align="left">%s</td>""" % host)
6389					out.append("""		<td align="center"><span class="sortkey">%s </span>%s</td>""" % (sortipnum,ipnum))
6390					out.append("""		<td align="left">%s</td>""" % htmlentities(info))
6391					out.append("""		<td align="center">%s</td>""" % locktype)
6392					out.append("""		<td align="right">%u</td>""" % owner)
6393					if pid==0 and start==0 and end==0:
6394						out.append("""		<td align="right">-1</td>""")
6395						out.append("""		<td align="right">0</td>""")
6396						out.append("""		<td align="right">EOF</td>""")
6397					else:
6398						out.append("""		<td align="right">%u</td>""" % pid)
6399						out.append("""		<td align="right">%u</td>""" % start)
6400						if end > 0x7FFFFFFFFFFFFFFF:
6401							out.append("""		<td align="right">EOF</td>""")
6402						else:
6403							out.append("""		<td align="right">%u</td>""" % end)
6404					out.append("""		<td align="right">%s</td>""" % ("READ(SHARED)" if ctype==1 else "WRITE(EXCLUSIVE)" if ctype==2 else "???"))
6405					out.append("""	</tr>""")
6406				else:
6407					if pid==0 and start==0 and end==0:
6408						pid = "-1"
6409						start = "0"
6410						end = "EOF"
6411					elif end > 0x7FFFFFFFFFFFFFFF:
6412						end = "EOF"
6413					if ctype==1:
6414						ctypestr = "READ(SHARED)"
6415					elif ctype==2:
6416						ctypestr = "WRITE(EXCLUSIVE)"
6417					else:
6418						ctypestr = "???"
6419					dline = [inode,sessionid,host,info,locktype,owner,pid,start,end,ctypestr]
6420					tab.append(*dline)
6421			if cgimode:
6422				if ALinode!=0:
6423					out.append("""</table>""")
6424				print("\n".join(out))
6425			else:
6426#				print(locks)
6427				print(myunicode(tab))
6428		except Exception:
6429			print_exception()
6430
6431if "QU" in sectionset:
6432	try:
6433		if cgimode:
6434			out = []
6435			out.append("""<table class="acid_tab acid_tab_zebra_C1_C2 acid_tab_storageid_mfsquota" cellspacing="0">""")
6436			out.append("""	<tr><th colspan="24">Active quotas</th></tr>""")
6437			out.append("""	<tr>""")
6438			out.append("""		<th rowspan="3" class="acid_tab_enumerate">#</th>""")
6439#			out.append("""		<th rowspan="2"><a href="%s">path</a></th>""" % (createorderlink("QU",11)))
6440#			out.append("""		<th rowspan="2"><a href="%s">exceeded</a></th>""" % (createorderlink("QU",2)))
6441			out.append("""		<th rowspan="3">path</th>""")
6442			out.append("""	<th colspan="6">soft&nbsp;quota</th>""")
6443			out.append("""	<th colspan="4">hard&nbsp;quota</th>""")
6444			out.append("""	<th colspan="12">current&nbsp;values</th>""")
6445			out.append("""	</tr>""")
6446			out.append("""	<tr>""")
6447#			out.append("""		<th><a href="%s">time&nbsp;to&nbsp;expire</a></th>""" % (createorderlink("QU",10)))
6448#			out.append("""		<th><a href="%s">inodes</a></th>""" % (createorderlink("QU",11)))
6449#			out.append("""		<th><a href="%s">length</a></th>""" % (createorderlink("QU",12)))
6450#			out.append("""		<th><a href="%s">size</a></th>""" % (createorderlink("QU",13)))
6451#			out.append("""		<th><a href="%s">real&nbsp;size</a></th>""" % (createorderlink("QU",14)))
6452#			out.append("""		<th><a href="%s">inodes</a></th>""" % (createorderlink("QU",21)))
6453#			out.append("""		<th><a href="%s">length</a></th>""" % (createorderlink("QU",22)))
6454#			out.append("""		<th><a href="%s">size</a></th>""" % (createorderlink("QU",23)))
6455#			out.append("""		<th><a href="%s">real&nbsp;size</a></th>""" % (createorderlink("QU",24)))
6456#			out.append("""		<th><a href="%s">inodes</a></th>""" % (createorderlink("QU",31)))
6457#			out.append("""		<th><a href="%s">length</a></th>""" % (createorderlink("QU",32)))
6458#			out.append("""		<th><a href="%s">size</a></th>""" % (createorderlink("QU",33)))
6459#			out.append("""		<th><a href="%s">real&nbsp;size</a></th>""" % (createorderlink("QU",34)))
6460#			out.append("""		<th>exceeded</th>""")
6461			out.append("""		<th rowspan="2">grace&nbsp;period</th>""")
6462			out.append("""		<th rowspan="2">time&nbsp;to&nbsp;expire</th>""")
6463			out.append("""		<th rowspan="2">inodes</th>""")
6464			out.append("""		<th rowspan="2">length</th>""")
6465			out.append("""		<th rowspan="2">size</th>""")
6466			out.append("""		<th rowspan="2">real&nbsp;size</th>""")
6467			out.append("""		<th rowspan="2">inodes</th>""")
6468			out.append("""		<th rowspan="2">length</th>""")
6469			out.append("""		<th rowspan="2">size</th>""")
6470			out.append("""		<th rowspan="2">real&nbsp;size</th>""")
6471			out.append("""		<th colspan="3">inodes</th>""")
6472			out.append("""		<th colspan="3">length</th>""")
6473			out.append("""		<th colspan="3">size</th>""")
6474			out.append("""		<th colspan="3">real&nbsp;size</th>""")
6475			out.append("""	</tr>""")
6476			out.append("""	<tr>""")
6477			out.append("""		<th>value</th>""")
6478			out.append("""		<th>% soft</th>""")
6479			out.append("""		<th>% hard</th>""")
6480			out.append("""		<th>value</th>""")
6481			out.append("""		<th>% soft</th>""")
6482			out.append("""		<th>% hard</th>""")
6483			out.append("""		<th>value</th>""")
6484			out.append("""		<th>% soft</th>""")
6485			out.append("""		<th>% hard</th>""")
6486			out.append("""		<th>value</th>""")
6487			out.append("""		<th>% soft</th>""")
6488			out.append("""		<th>% hard</th>""")
6489			out.append("""	</tr>""")
6490		elif ttymode:
6491#			tab = Tabble("Active quotas",14)
6492#			tab.header("",("soft quota","",5),("hard quota","",4),("current values","",4))
6493#			tab.header("path",("---","",13))
6494#			tab.header("","time to expire","inodes","length","size","real size","inodes","length","size","real size","inodes","length","size","real size")
6495#			tab.defattr("l","r","r","r","r","r","r","r","r","r","r","r","r","r")
6496			tab = Tabble("Active quotas",23)
6497			tab.header("",("soft quota","",6),("hard quota","",4),("current values","",12))
6498			tab.header("",("---","",22))
6499			tab.header("path","","","","","","","","","","",("inodes","",3),("length","",3),("size","",3),("real size","",3))
6500			tab.header("","grace period","time to expire","inodes","length","size","real size","inodes","length","size","real size",("---","",12))
6501			tab.header("","","","","","","","","","","","value","% soft","% hard","value","% soft","% hard","value","% soft","% hard","value","% soft","% hard")
6502			tab.defattr("l","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r","r")
6503		else:
6504			tab = Tabble("active quotas",16)
6505		data,length = masterconn.command(CLTOMA_QUOTA_INFO,MATOCL_QUOTA_INFO)
6506		if length>=4 and masterconn.version_at_least(1,7,0):
6507			quotas = []
6508			maxperc = 0.0
6509			pos = 0
6510			while pos<length:
6511				inode,pleng = struct.unpack(">LL",data[pos:pos+8])
6512				pos+=8
6513				path = data[pos:pos+pleng]
6514				path = path.decode('utf-8','replace')
6515				pos+=pleng
6516				if masterconn.version_at_least(3,0,9):
6517					graceperiod,exceeded,qflags,timetoblock = struct.unpack(">LBBL",data[pos:pos+10])
6518					pos+=10
6519				else:
6520					exceeded,qflags,timetoblock = struct.unpack(">BBL",data[pos:pos+6])
6521					pos+=6
6522					graceperiod = 0
6523				sinodes,slength,ssize,srealsize = struct.unpack(">LQQQ",data[pos:pos+28])
6524				pos+=28
6525				hinodes,hlength,hsize,hrealsize = struct.unpack(">LQQQ",data[pos:pos+28])
6526				pos+=28
6527				cinodes,clength,csize,crealsize = struct.unpack(">LQQQ",data[pos:pos+28])
6528				pos+=28
6529				if (qflags&1) and sinodes>0:
6530					perc = 100.0*cinodes/sinodes
6531					if perc>maxperc:
6532						maxperc = perc
6533				if (qflags&2) and slength>0:
6534					perc = 100.0*clength/slength
6535					if perc>maxperc:
6536						maxperc = perc
6537				if (qflags&4) and ssize>0:
6538					perc = 100.0*csize/ssize
6539					if perc>maxperc:
6540						maxperc = perc
6541				if (qflags&8) and srealsize>0:
6542					perc = 100.0*crealsize/srealsize
6543					if perc>maxperc:
6544						maxperc = perc
6545				if (qflags&16) and hinodes>0:
6546					perc = 100.0*cinodes/hinodes
6547					if perc>maxperc:
6548						maxperc = perc
6549				if (qflags&32) and hlength>0:
6550					perc = 100.0*clength/hlength
6551					if perc>maxperc:
6552						maxperc = perc
6553				if (qflags&64) and hsize>0:
6554					perc = 100.0*csize/hsize
6555					if perc>maxperc:
6556						maxperc = perc
6557				if (qflags&128) and hrealsize>0:
6558					perc = 100.0*crealsize/hrealsize
6559					if perc>maxperc:
6560						maxperc = perc
6561				sf = path
6562				if QUorder==1:
6563					sf = path
6564				elif QUorder==2:
6565					sf = exceeded
6566				elif QUorder==9:
6567					sf = graceperiod
6568				elif QUorder==10:
6569					sf = timetoblock
6570				elif QUorder==11:
6571					sf = sinodes
6572				elif QUorder==12:
6573					sf = slength
6574				elif QUorder==13:
6575					sf = ssize
6576				elif QUorder==14:
6577					sf = srealsize
6578				elif QUorder==21:
6579					sf = hinodes
6580				elif QUorder==22:
6581					sf = hlength
6582				elif QUorder==23:
6583					sf = hsize
6584				elif QUorder==24:
6585					sf = hrealsize
6586				elif QUorder==31:
6587					sf = cinodes
6588				elif QUorder==32:
6589					sf = clength
6590				elif QUorder==33:
6591					sf = csize
6592				elif QUorder==34:
6593					sf = crealsize
6594				elif QUorder==41:
6595					sf = (-1,0) if (qflags&1)==0 else (1,0) if sinodes==0 else (0,1.0*cinodes/sinodes)
6596				elif QUorder==42:
6597					sf = (-1,0) if (qflags&2)==0 else (1,0) if slength==0 else (0,1.0*clength/slength)
6598				elif QUorder==43:
6599					sf = (-1,0) if (qflags&4)==0 else (1,0) if ssize==0 else (0,1.0*csize/ssize)
6600				elif QUorder==44:
6601					sf = (-1,0) if (qflags&8)==0 else (1,0) if srealsize==0 else (0,1.0*crealsize/srealsize)
6602				elif QUorder==51:
6603					sf = (-1,0) if (qflags&16)==0 else (1,0) if hinodes==0 else (0,1.0*cinodes/hinodes)
6604				elif QUorder==52:
6605					sf = (-1,0) if (qflags&32)==0 else (1,0) if hlength==0 else (0,1.0*clength/hlength)
6606				elif QUorder==53:
6607					sf = (-1,0) if (qflags&64)==0 else (1,0) if hsize==0 else (0,1.0*csize/hsize)
6608				elif QUorder==54:
6609					sf = (-1,0) if (qflags&128)==0 else (1,0) if hrealsize==0 else (0,1.0*crealsize/hrealsize)
6610				quotas.append((sf,path,exceeded,qflags,graceperiod,timetoblock,sinodes,slength,ssize,srealsize,hinodes,hlength,hsize,hrealsize,cinodes,clength,csize,crealsize))
6611			quotas.sort()
6612			if QUrev:
6613				quotas.reverse()
6614			maxperc += 0.01
6615			for sf,path,exceeded,qflags,graceperiod,timetoblock,sinodes,slength,ssize,srealsize,hinodes,hlength,hsize,hrealsize,cinodes,clength,csize,crealsize in quotas:
6616				if cgimode:
6617					out.append("""	<tr>""")
6618					out.append("""		<td align="right"></td>""")
6619					out.append("""		<td align="left">%s</td>""" % htmlentities(path))
6620	#				out.append("""		<td align="center">%s</td>""" % ("yes" if exceeded else "no"))
6621					if graceperiod>0:
6622						out.append("""		<td align="center"><span class="sortkey">%u </span><a style="cursor:default" title="%s">%s</a></td>""" % (graceperiod,timeduration_to_fullstr(graceperiod),timeduration_to_shortstr(graceperiod)))
6623					else:
6624						out.append("""		<td align="center"><span class="sortkey">0 </span>default</td>""")
6625					if timetoblock<0xFFFFFFFF:
6626						if timetoblock>0:
6627	#						days,rest = divmod(timetoblock,86400)
6628	#						hours,rest = divmod(rest,3600)
6629	#						min,sec = divmod(rest,60)
6630	#						if days>0:
6631	#							tbstr = "%ud,&nbsp;%uh&nbsp;%um&nbsp;%us" % (days,hours,min,sec)
6632	#						elif hours>0:
6633	#							tbstr = "%uh&nbsp;%um&nbsp;%us" % (hours,min,sec)
6634	#						elif min>0:
6635	#							tbstr = "%um&nbsp;%us" % (min,sec)
6636	#						else:
6637	#							tbstr = "%us" % sec
6638							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)))
6639						else:
6640							out.append("""		<td align="center"><span class="EXCEEDED"><span class="sortkey">0 </span>expired</span></td>""")
6641					else:
6642						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
6643					if qflags&1:
6644						out.append("""		<td align="right"><span>%u</span></td>""" % (sinodes))
6645					else:
6646						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
6647					if qflags&2:
6648						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;")))
6649					else:
6650						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
6651					if qflags&4:
6652						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;")))
6653					else:
6654						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
6655					if qflags&8:
6656						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;")))
6657					else:
6658						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
6659					if qflags&16:
6660						out.append("""		<td align="right"><span>%u</span></td>""" % (hinodes))
6661					else:
6662						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
6663					if qflags&32:
6664						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;")))
6665					else:
6666						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
6667					if qflags&64:
6668						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;")))
6669					else:
6670						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
6671					if qflags&128:
6672						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;")))
6673					else:
6674						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
6675					out.append("""		<td align="right">%u</td>""" % cinodes)
6676					if qflags&1:
6677						if sinodes>0:
6678							if sinodes>=cinodes:
6679								cl="NOTEXCEEDED"
6680							elif timetoblock>0:
6681								cl="SEXCEEDED"
6682							else:
6683								cl="EXCEEDED"
6684							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*cinodes)/sinodes))
6685						else:
6686							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
6687					else:
6688						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
6689					if qflags&16:
6690						if hinodes>0:
6691							if hinodes>cinodes:
6692								cl="NOTEXCEEDED"
6693							else:
6694								cl="EXCEEDED"
6695							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*cinodes)/hinodes))
6696						else:
6697							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
6698					else:
6699						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
6700					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;")))
6701					if qflags&2:
6702						if slength>0:
6703							if slength>=clength:
6704								cl="NOTEXCEEDED"
6705							elif timetoblock>0:
6706								cl="SEXCEEDED"
6707							else:
6708								cl="EXCEEDED"
6709							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*clength)/slength))
6710						else:
6711							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
6712					else:
6713						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
6714					if qflags&32:
6715						if hlength>0:
6716							if hlength>clength:
6717								cl="NOTEXCEEDED"
6718							else:
6719								cl="EXCEEDED"
6720							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*clength)/hlength))
6721						else:
6722							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
6723					else:
6724						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
6725					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;")))
6726					if qflags&4:
6727						if ssize>0:
6728							if ssize>=csize:
6729								cl="NOTEXCEEDED"
6730							elif timetoblock>0:
6731								cl="SEXCEEDED"
6732							else:
6733								cl="EXCEEDED"
6734							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*csize)/ssize))
6735						else:
6736							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
6737					else:
6738						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
6739					if qflags&64:
6740						if hsize>0:
6741							if hsize>csize:
6742								cl="NOTEXCEEDED"
6743							else:
6744								cl="EXCEEDED"
6745							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*csize)/hsize))
6746						else:
6747							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
6748					else:
6749						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
6750					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;")))
6751					if qflags&8:
6752						if srealsize>0:
6753							if srealsize>=crealsize:
6754								cl="NOTEXCEEDED"
6755							elif timetoblock>0:
6756								cl="SEXCEEDED"
6757							else:
6758								cl="EXCEEDED"
6759							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*crealsize)/srealsize))
6760						else:
6761							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
6762					else:
6763						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
6764					if qflags&128:
6765						if hrealsize>0:
6766							if hrealsize>crealsize:
6767								cl="NOTEXCEEDED"
6768							else:
6769								cl="EXCEEDED"
6770							out.append("""		<td align="right"><span class="%s">%.2f</span></td>""" % (cl,(100.0*crealsize)/hrealsize))
6771						else:
6772							out.append("""		<td align="right"><span class="sortkey">%.2f </span><span class="EXCEEDED">inf</span></td>""" % (maxperc))
6773					else:
6774						out.append("""		<td align="center"><span class="sortkey">-1 </span>-</td>""")
6775					out.append("""	</tr>""")
6776				elif ttymode:
6777					dline = [path] #,"yes" if exceeded else "no"]
6778					if graceperiod>0:
6779						dline.append(timeduration_to_shortstr(graceperiod))
6780					else:
6781						dline.append("default")
6782					if timetoblock<0xFFFFFFFF:
6783						if timetoblock>0:
6784							dline.append((timeduration_to_shortstr(timetoblock),"2"))
6785						else:
6786							dline.append(("expired","1"))
6787					else:
6788						dline.append("-")
6789					if qflags&1:
6790						dline.append(sinodes)
6791					else:
6792						dline.append("-")
6793					if qflags&2:
6794						dline.append(humanize_number(slength," "))
6795					else:
6796						dline.append("-")
6797					if qflags&4:
6798						dline.append(humanize_number(ssize," "))
6799					else:
6800						dline.append("-")
6801					if qflags&8:
6802						dline.append(humanize_number(srealsize," "))
6803					else:
6804						dline.append("-")
6805					if qflags&16:
6806						dline.append(hinodes)
6807					else:
6808						dline.append("-")
6809					if qflags&32:
6810						dline.append(humanize_number(hlength," "))
6811					else:
6812						dline.append("-")
6813					if qflags&64:
6814						dline.append(humanize_number(hsize," "))
6815					else:
6816						dline.append("-")
6817					if qflags&128:
6818						dline.append(humanize_number(hrealsize," "))
6819					else:
6820						dline.append("-")
6821					dline.append(cinodes)
6822					if qflags&1:
6823						if sinodes>0:
6824							dline.append(("%.2f" % ((100.0*cinodes)/sinodes),"4" if sinodes>=cinodes else "2" if timetoblock>0 else "1"))
6825						else:
6826							dline.append(("inf","1"))
6827					else:
6828						dline.append("-")
6829					if qflags&16:
6830						if hinodes>0:
6831							dline.append(("%.2f" % ((100.0*cinodes)/hinodes),"4" if hinodes>cinodes else "1"))
6832						else:
6833							dline.append(("inf","1"))
6834					else:
6835						dline.append("-")
6836					dline.append(humanize_number(clength," "))
6837					if qflags&2:
6838						if slength>0:
6839							dline.append(("%.2f" % ((100.0*clength)/slength),"4" if slength>=clength else "2" if timetoblock>0 else "1"))
6840						else:
6841							dline.append(("inf","1"))
6842					else:
6843						dline.append("-")
6844					if qflags&32:
6845						if hlength>0:
6846							dline.append(("%.2f" % ((100.0*clength)/hlength),"4" if hlength>clength else "1"))
6847						else:
6848							dline.append(("inf","1"))
6849					else:
6850						dline.append("-")
6851					dline.append(humanize_number(csize," "))
6852					if qflags&4:
6853						if ssize>0:
6854							dline.append(("%.2f" % ((100.0*csize)/ssize),"4" if ssize>=csize else "2" if timetoblock>0 else "1"))
6855						else:
6856							dline.append(("inf","1"))
6857					else:
6858						dline.append("-")
6859					if qflags&64:
6860						if hsize>0:
6861							dline.append(("%.2f" % ((100.0*csize)/hsize),"4" if hsize>csize else "1"))
6862						else:
6863							dline.append(("inf","1"))
6864					else:
6865						dline.append("-")
6866					dline.append(humanize_number(crealsize," "))
6867					if qflags&8:
6868						if srealsize>0:
6869							dline.append(("%.2f" % ((100.0*crealsize)/srealsize),"4" if srealsize>=crealsize else "2" if timetoblock>0 else "1"))
6870						else:
6871							dline.append(("inf","1"))
6872					else:
6873						dline.append("-")
6874					if qflags&128:
6875						if hrealsize>0:
6876							dline.append(("%.2f" % ((100.0*crealsize)/hrealsize),"4" if hrealsize>crealsize else "1"))
6877						else:
6878							dline.append(("inf","1"))
6879					else:
6880						dline.append("-")
6881					tab.append(*dline)
6882				else:
6883					dline = [path,"yes" if exceeded else "no"]
6884					if graceperiod>0:
6885						dline.append(graceperiod)
6886					else:
6887						dline.append("default")
6888					if timetoblock<0xFFFFFFFF:
6889						if timetoblock>0:
6890							dline.append(timetoblock)
6891						else:
6892							dline.append("expired")
6893					else:
6894						dline.append("-")
6895					dline.append(sinodes if qflags&1 else "-")
6896					dline.append(slength if qflags&2 else "-")
6897					dline.append(ssize if qflags&4 else "-")
6898					dline.append(srealsize if qflags&8 else "-")
6899					dline.append(hinodes if qflags&16 else "-")
6900					dline.append(hlength if qflags&32 else "-")
6901					dline.append(hsize if qflags&64 else "-")
6902					dline.append(hrealsize if qflags&128 else "-")
6903					dline.extend((cinodes,clength,csize,crealsize))
6904					tab.append(*dline)
6905		if cgimode:
6906			out.append("""</table>""")
6907			print("\n".join(out))
6908		else:
6909			print(myunicode(tab))
6910	except Exception:
6911		print_exception()
6912
6913if "MC" in sectionset:
6914	out = []
6915	try:
6916		if cgimode:
6917			charts = (
6918				(100,'cpu','cpu usage (percent)'),
6919				(101,'memory','memory usage (if available - rss + virt)'),
6920				(102,'space','raw disk space usage (total / used)'),
6921				(103,'dels','chunk deletions per minute (successful/unsuccessful)'),
6922				(104,'repl','chunk replications per minute (successful/unsuccessful)'),
6923				(105,'creat','chunk creations per minute (successful/unsuccessful)'),
6924				(106,'change','chunk internal operations per minute (successful/unsuccessful)'),
6925				(4,'statfs','statfs operations (per minute)'),
6926				(5,'getattr','getattr operations (per minute)'),
6927				(6,'setattr','setattr operations (per minute)'),
6928				(7,'lookup','lookup operations (per minute)'),
6929				(8,'mkdir','mkdir operations (per minute)'),
6930				(9,'rmdir','rmdir operations (per minute)'),
6931				(10,'symlink','symlink operations (per minute)'),
6932				(11,'readlink','readlink operations (per minute)'),
6933				(12,'mknod','mknod operations (per minute)'),
6934				(13,'unlink','unlink operations (per minute)'),
6935				(14,'rename','rename operations (per minute)'),
6936				(15,'link','link operations (per minute)'),
6937				(16,'readdir','readdir operations (per minute)'),
6938				(17,'open','open operations (per minute)'),
6939				(18,'read','read operations (per minute)'),
6940				(19,'write','write operations (per minute)'),
6941				(21,'prcvd','packets received (per second)'),
6942				(22,'psent','packets sent (per second)'),
6943				(23,'brcvd','bits received (per second)'),
6944				(24,'bsent','bits sent (per second)')
6945			)
6946
6947			if MCdata=="" and leaderfound:
6948				MCdata="%s:%u:%u" % (masterconn.host,masterconn.port,1 if masterconn.version_at_least(2,0,0) else 0)
6949			servers = []
6950			mixedservers = 0
6951			if len(masterlistver)>0:
6952				masterlistver.sort()
6953				out.append("""<form action="#"><table class="FR" cellspacing="0"><tr><th>Select: <select name="server" size="1" onchange="document.location.href='%s&MCdata='+this.options[this.selectedIndex].value">""" % createjslink({"MCdata":""}))
6954				entrystr = []
6955				entrydesc = {}
6956				for id,oname,desc in charts:
6957					name = oname.replace(":","")
6958					entrystr.append(name)
6959					entrydesc[name] = desc
6960				for strip,port,version in masterlistver:
6961					nc = 1 if version>=(2,0,0) else 0
6962					if mixedservers==0:
6963						mixedservers = nc+1
6964					if mixedservers!=nc+1:
6965						mixedservers = 3
6966					name = "%s:%u" % (strip,port)
6967					namearg = "%s:%u" % (name,nc)
6968					hostx = resolve(strip)
6969					if hostx==UNRESOLVED:
6970						host = ""
6971					else:
6972						host = " / "+hostx
6973					entrystr.append(namearg)
6974					entrydesc[namearg] = "Server: %s%s%s" % (name,host," *" if (leaderfound and strip==masterconn.host) else "")
6975					servers.append((strip,port,"ma_"+name.replace(".","_").replace(":","_"),entrydesc[namearg],nc))
6976				if MCdata not in entrystr:
6977					out.append("""<option value="" selected="selected"> data type or server</option>""")
6978				for estr in entrystr:
6979					if estr==MCdata:
6980						out.append("""<option value="%s" selected="selected">%s</option>""" % (estr,entrydesc[estr]))
6981					else:
6982						out.append("""<option value="%s">%s</option>""" % (estr,entrydesc[estr]))
6983				out.append("""</select></th></tr></table></form>""")
6984
6985			mchtmp = MCdata.split(":")
6986			if len(mchtmp)==2:
6987				mchtmp = (mchtmp[0],mchtmp[1],0)
6988			if len(mchtmp)==3:
6989				mahost = mchtmp[0]
6990				maport = mchtmp[1]
6991				manc = int(mchtmp[2])
6992
6993				out.append("""<script type="text/javascript">""")
6994				out.append("""<!--//--><![CDATA[//><!--""")
6995				out.append("""	var ma_vids = [%s];""" % ",".join(map(repr,[ x[0] for x in charts ])))
6996				out.append("""	var ma_inames = [%s];""" % ",".join(map(repr,[ x[1] for x in charts ])))
6997				out.append("""	var ma_idesc = [%s];""" % ",".join(map(repr,[ x[2] for x in charts ])))
6998				out.append("""	var ma_host = "%s";""" % mahost)
6999				out.append("""	var ma_port = "%s";""" % maport)
7000				out.append("""	var ma_nc = %u;""" % manc)
7001				out.append("""//--><!]]>""")
7002				out.append("""</script>""")
7003				out.append("""<script type="text/javascript">
7004<!--//--><![CDATA[//><!--
7005	var i,j;
7006	var ma_chartid = [0,0];
7007	var ma_range_up=0;
7008	var ma_range_down=0;
7009	var ma_zoomed = [];
7010	var ma_resizeto;
7011	function ma_refresh() {
7012		var i;
7013		var minutes = Math.floor((new Date()).getTime()/60000);
7014		for (i=0 ; i<ma_inames.length ; i++) {
7015			var name = ma_inames[i];
7016			var vid = ma_vids[i];
7017			var id = vid*10+ma_range_up;
7018			var element = document.getElementById(name);
7019			if (element) {
7020				var url;
7021				if (ma_nc) {
7022					var width = element.scrollWidth;
7023					var height = element.scrollHeight;
7024					url = "chart.cgi?host="+ma_host+"&port="+ma_port+"&id="+id+"&width="+width+"&height="+height+"&antycache="+minutes;
7025				} else {
7026					url = "chart.cgi?host="+ma_host+"&port="+ma_port+"&id="+id+"&antycache="+minutes;
7027				}
7028				if (typeof(element.ma_url)=="undefined" || element.ma_url!=url) {
7029					element.ma_url = url;
7030					element.style.backgroundImage = "url('"+url+"')";
7031				}
7032			}
7033		}
7034		for (i=0 ; i<2 ; i++) {
7035			var vid = ma_vids[ma_chartid[i]];
7036			var id = vid*10+ma_range_down;
7037			var iname = "ma_chart"+i;
7038			var element = document.getElementById(iname);
7039			if (element) {
7040				var url;
7041				if (ma_nc) {
7042					var width = element.scrollWidth;
7043					var height = element.scrollHeight;
7044					url = "chart.cgi?host="+ma_host+"&port="+ma_port+"&id="+id+"&width="+width+"&height="+height+"&antycache="+minutes;
7045				} else {
7046					url = "chart.cgi?host="+ma_host+"&port="+ma_port+"&id="+id+"&antycache="+minutes;
7047				}
7048				if (typeof(element.ma_url)=="undefined" || element.ma_url!=url) {
7049					element.ma_url = url;
7050					element.style.backgroundImage = "url('"+url+"')";
7051				}
7052			}
7053		}
7054	}
7055	function ma_change_up(num) {
7056		ma_range_up = num;
7057		ma_refresh();
7058	}
7059	function ma_change_down(num) {
7060		ma_range_down = num;
7061		ma_refresh();
7062	}
7063	function ma_zoom(element) {
7064		var name = element.id;
7065		if (typeof(ma_zoomed[name])=="undefined") {
7066			ma_zoomed[name]=0;
7067		}
7068		if (ma_zoomed[name]==0) {
7069			ma_zoomed[name]=1;
7070			element.style.height = '220px';
7071		} else if (ma_zoomed[name]==1) {
7072			ma_zoomed[name]=2;
7073			element.style.height = '420px';
7074		} else if (ma_zoomed[name]==2) {
7075			ma_zoomed[name]=3;
7076			element.style.height = '820px';
7077		} else {
7078			ma_zoomed[name]=0;
7079			element.style.height = '120px';
7080		}
7081		ma_refresh();
7082	}
7083	function ma_resized() {
7084		clearTimeout(ma_resizeto);
7085		ma_resizeto = setTimeout(ma_refresh,250);
7086	}
7087	function ma_change_type(id,no) {
7088		var o;
7089		ma_chartid[id]=no;
7090		o = document.getElementById("ma_desc"+id);
7091		o.innerHTML = ma_idesc[no];
7092		ma_refresh();
7093	}
7094	function ma_add_event(obj,type,fn) {
7095		if (obj.addEventListener) {
7096			obj.addEventListener(type, fn, false);
7097		} else if (obj.attachEvent) {
7098			obj.attachEvent('on'+type, fn);
7099		}
7100	}
7101	ma_add_event(window,"load",ma_refresh);
7102	ma_add_event(window,"resize",ma_resized);
7103//--><!]]>
7104</script>""")
7105				out.append("""<table class="FR" cellspacing="0" cellpadding="0">""")
7106				out.append("""	<tr>""")
7107				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_up(0);">short range</a></th>""")
7108				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_up(1);">medium range</a></th>""")
7109				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_up(2);">long range</a></th>""")
7110				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_up(3);">very long range</a></th>""")
7111				out.append("""	</tr>""")
7112				for id,name,desc in charts:
7113					divclass = "CHARTDYNAMIC" if manc else "CHARTSTATIC"
7114					divclick = 'onclick="ma_zoom(this)"' if manc else ""
7115					out.append("""	<tr class="C2">""")
7116					out.append("""		<td colspan="4" style="height:124px;" valign="middle">""")
7117					out.append("""			<div class="%s" id="%s" %s>""" % (divclass,name,divclick))
7118					out.append("""				<span class="CAPTION">%s</span>""" % desc)
7119					out.append("""			</div>""")
7120					out.append("""		</td>""")
7121					out.append("""	</tr>""")
7122				out.append("""</table>""")
7123
7124				out.append("""<form action="#"><table class="FR" cellspacing="0" cellpadding="0">""")
7125				out.append("""	<tr>""")
7126				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_down(0);">short range</a></th>""")
7127				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_down(1);">medium range</a></th>""")
7128				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_down(2);">long range</a></th>""")
7129				out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change_down(3);">very long range</a></th>""")
7130				out.append("""	</tr>""")
7131				for i in range(2):
7132					divclass = "CHARTDYNAMIC" if manc else "CHARTSTATIC"
7133					divclick = 'onclick="ma_zoom(this)"' if manc else ""
7134					out.append("""	<tr class="C2">""")
7135					out.append("""		<td colspan="4" style="height:124px;" valign="middle">""")
7136					out.append("""			<div class="%s" id="ma_chart%u" %s>""" % (divclass,i,divclick))
7137					out.append("""				<span class="CAPTION" id="ma_desc%u">%s</span>""" % (i,charts[0][2]))
7138					out.append("""			</div>""")
7139					out.append("""		</td>""")
7140					out.append("""	</tr>""")
7141					out.append("""	<tr>""")
7142					out.append("""		<th colspan="4">""")
7143					out.append("""			<select name="machart%u" size="1" onchange="ma_change_type(%u,this.options[this.selectedIndex].value)">""" % (i,i))
7144					no = 0
7145					for id,name,desc in charts:
7146						out.append("""				<option value="%u">%s</option>""" % (no,desc))
7147						no += 1
7148					out.append("""		</th>""")
7149					out.append("""	</tr>""")
7150				out.append("""</table></form>""")
7151			elif len(mchtmp)==1 and len(MCdata)>0:
7152				chid = 0
7153				for id,name,desc in charts:
7154					if name==MCdata:
7155						chid = id
7156				if chid==0:
7157					try:
7158						chid = int(MCdata)
7159					except Exception:
7160						pass
7161				if chid>0 and chid<1000:
7162					out.append("""<script type="text/javascript">""")
7163					out.append("""<!--//--><![CDATA[//><!--""")
7164					out.append("""	var ma_vhosts = [%s];""" % ",".join(map(repr,[ x[0] for x in servers ])))
7165					out.append("""	var ma_vports = [%s];""" % ",".join(map(repr,[ x[1] for x in servers ])))
7166					out.append("""	var ma_inames = [%s];""" % ",".join(map(repr,[ x[2] for x in servers ])))
7167					out.append("""	var ma_nc = [%s];""" % ",".join(map(repr,[ x[4] for x in servers ])))
7168					out.append("""	var ma_chid = %u;""" % chid)
7169					out.append("""//--><!]]>""")
7170					out.append("""</script>""")
7171					out.append("""<script type="text/javascript">
7172<!--//--><![CDATA[//><!--
7173	var i,j;
7174	var ma_range=0;
7175	var ma_zoomed = [];
7176	var ma_resizeto;
7177	function ma_refresh() {
7178		var i;
7179		var minutes = Math.floor((new Date()).getTime()/60000);
7180		for (i=0 ; i<ma_inames.length ; i++) {
7181			var name = ma_inames[i];
7182			var vhost = ma_vhosts[i];
7183			var vport = ma_vports[i];
7184			var manc = ma_nc[i];
7185			var id = ma_chid*10+ma_range;
7186			var element = document.getElementById(name);
7187			if (element) {
7188				var url;
7189				if (manc) {
7190					var width = element.scrollWidth;
7191					var height = element.scrollHeight;
7192					url = "chart.cgi?host="+vhost+"&port="+vport+"&id="+id+"&width="+width+"&height="+height+"&antycache="+minutes;
7193				} else {
7194					url = "chart.cgi?host="+vhost+"&port="+vport+"&id="+id+"&antycache="+minutes;
7195				}
7196				if (typeof(element.ma_url)=="undefined" || element.ma_url!=url) {
7197					element.ma_url = url;
7198					element.style.backgroundImage = "url('"+url+"')";
7199				}
7200			}
7201		}
7202	}
7203	function ma_change(num) {
7204		ma_range = num;
7205		ma_refresh();
7206	}
7207	function ma_zoom(element) {
7208		var name = element.id;
7209		if (typeof(ma_zoomed[name])=="undefined") {
7210			ma_zoomed[name]=0;
7211		}
7212		if (ma_zoomed[name]==0) {
7213			ma_zoomed[name]=1;
7214			element.style.height = '220px';
7215		} else if (ma_zoomed[name]==1) {
7216			ma_zoomed[name]=2;
7217			element.style.height = '420px';
7218		} else if (ma_zoomed[name]==2) {
7219			ma_zoomed[name]=3;
7220			element.style.height = '820px';
7221		} else {
7222			ma_zoomed[name]=0;
7223			element.style.height = '120px';
7224		}
7225		ma_refresh();
7226	}
7227	function ma_resized() {
7228		clearTimeout(ma_resizeto);
7229		ma_resizeto = setTimeout(ma_refresh,250);
7230	}
7231	function ma_add_event(obj,type,fn) {
7232		if (obj.addEventListener) {
7233			obj.addEventListener(type, fn, false);
7234		} else if (obj.attachEvent) {
7235			obj.attachEvent('on'+type, fn);
7236		}
7237	}
7238	ma_add_event(window,"load",ma_refresh);
7239	ma_add_event(window,"resize",ma_resized);
7240//--><!]]>
7241</script>""")
7242					out.append("""<table class="FR" cellspacing="0" cellpadding="0">""")
7243					out.append("""	<tr>""")
7244					out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change(0);">short range</a></th>""")
7245					out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change(1);">medium range</a></th>""")
7246					out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change(2);">long range</a></th>""")
7247					out.append("""		<th class="RANGEBAR"><a href="javascript:ma_change(3);">very long range</a></th>""")
7248					out.append("""	</tr>""")
7249					for mahost,maport,name,desc,manc in servers:
7250						divclass = "CHARTDYNAMIC" if manc else "CHARTSTATICMIXED" if mixedservers==3 else "CHARTSTATIC"
7251						divclick = 'onclick="ma_zoom(this)"' if manc else ""
7252						out.append("""	<tr class="C2">""")
7253						out.append("""		<td colspan="4" style="height:124px;" valign="middle">""")
7254						out.append("""			<div class="%s" id="%s" %s>""" % (divclass,name,divclick))
7255						out.append("""				<span class="CAPTION">%s</span>""" % desc)
7256						out.append("""			</div>""")
7257						out.append("""		</td>""")
7258						out.append("""	</tr>""")
7259					out.append("""</table>""")
7260		else:
7261			if masterconn.version_at_least(2,0,15):
7262				if ttymode:
7263					tab = Tabble("Master chart data",len(MCchdata)+1,"r")
7264					hdrstr = ["host/port ->"]
7265					for host,port,no,mode,desc,raw in MCchdata:
7266						if (host==None or port==None):
7267							hdrstr.append("leader")
7268						else:
7269							hdrstr.append("%s:%s" % (host,port))
7270					tab.header(*hdrstr)
7271					tab.header(("---","",len(MCchdata)+1))
7272					hdrstr = ["Time"]
7273					for host,port,no,mode,desc,raw in MCchdata:
7274						if raw:
7275							if (no==0 or no==1 or no==100):
7276								hdrstr.append("%s (+)" % desc)
7277							else:
7278								hdrstr.append("%s (raw)" % desc)
7279						else:
7280							hdrstr.append(desc)
7281					tab.header(*hdrstr)
7282				else:
7283					tab = Tabble("Master chart data",len(MCchdata)+1)
7284				chrange = MCrange
7285				if chrange<0 or chrange>3:
7286					chrange = 0
7287				if MCcount<0 or MCcount>4095:
7288					MCcount = 4095
7289				chrangestep = [60,360,1800,86400][chrange]
7290				series = set()
7291				for host,port,no,mode,desc,raw in MCchdata:
7292					if no==100:
7293						series.add((host,port,0))
7294						series.add((host,port,1))
7295					else:
7296						series.add((host,port,no))
7297				for gpass in (1,2):
7298					MCresult = {}
7299					timestamp = 0
7300					entries = 0
7301					repeat = 0
7302					for host,port,x in series:
7303						if host==None or port==None:
7304							data,length = masterconn.command(CLTOAN_CHART_DATA,ANTOCL_CHART_DATA,struct.pack(">LL",x*10+chrange,MCcount))
7305						else:
7306							conn = MFSConn(host,port)
7307							data,length = conn.command(CLTOAN_CHART_DATA,ANTOCL_CHART_DATA,struct.pack(">LL",x*10+chrange,MCcount))
7308						if length>=8:
7309							ts,e = struct.unpack(">LL",data[:8])
7310							if e*8+8==length and (entries==0 or entries==e):
7311								entries = e
7312								if timestamp==0 or timestamp==ts or gpass==2:
7313									timestamp=ts
7314									MCresult[(host,port,x)] = list(struct.unpack(">"+e*"Q",data[8:]))
7315								else:
7316									repeat = 1
7317									break
7318							else:
7319								MCresult[(host,port,x)]=None
7320						else:
7321							MCresult[(host,port,x)]=None
7322					if repeat:
7323						continue
7324					else:
7325						break
7326				for e in xrange(entries):
7327					ts = timestamp-chrangestep*e
7328					timestring = time.strftime("%Y-%m-%d %H:%M",time.gmtime(ts))
7329					dline = [timestring]
7330					for host,port,no,mode,desc,raw in MCchdata:
7331						if no==100:
7332							datalist1 = MCresult[(host,port,0)]
7333							datalist2 = MCresult[(host,port,1)]
7334							if (datalist1!=None and datalist2!=None and datalist1[e]<((2**64)-1) and datalist2[e]<((2**64)-1)):
7335								data = datalist1[e]+datalist2[e]
7336							else:
7337								data = None
7338						else:
7339							datalist = MCresult[(host,port,no)]
7340							if datalist!=None and datalist[e]<((2**64)-1):
7341								data = datalist[e]
7342							else:
7343								data = None
7344						if data==None:
7345							dline.append("-")
7346						elif mode==0:
7347							cpu = (data/(10000.0*chrangestep))
7348							if raw:
7349								dline.append("%.8f%%" % (cpu))
7350							else:
7351								dline.append("%.2f%%" % (cpu))
7352						elif mode==1:
7353							if raw:
7354								dline.append("%u" % data)
7355							else:
7356								data = float(data)/float(chrangestep)
7357								dline.append("%.3f/s" % data)
7358						elif mode==2:
7359							if raw:
7360								dline.append("%u" % data)
7361							else:
7362								dline.append("%s" % humanize_number(data," "))
7363					tab.append(*dline)
7364			else:
7365				tab = Tabble("Master chart data are not supported in your version of MFS - please upgrade",1,"r")
7366		if cgimode:
7367			print("\n".join(out))
7368		else:
7369			print(myunicode(tab))
7370	except Exception:
7371		print_exception()
7372
7373if "CC" in sectionset:
7374	out = []
7375	try:
7376		if cgimode:
7377			# get cs list
7378			hostlist = []
7379			for cs in dataprovider.get_chunkservers():
7380				if (cs.flags&1)==0:
7381					hostlist.append((cs.ip,cs.port,cs.version))
7382#			data,length = masterconn.command(CLTOMA_CSERV_LIST,MATOCL_CSERV_LIST)
7383#			if masterconn.version_at_least(1,7,25) and (length%64)==0:
7384#				n = length//64
7385#				servers = []
7386#				for i in range(n):
7387#					d = data[i*64:(i+1)*64]
7388#					flags,v1,v2,v3,ip1,ip2,ip3,ip4,port = struct.unpack(">BBBBBBBBH",d[:10])
7389#					if (flags&1)==0:
7390#						hostlist.append(((ip1,ip2,ip3,ip4),port,(v1,v2,v3)))
7391#			elif masterconn.version_at_least(1,6,28) and masterconn.version_less_than(1,7,25) and (length%62)==0:
7392#				n = length//62
7393#				servers = []
7394#				for i in range(n):
7395#					d = data[i*62:(i+1)*62]
7396#					disconnected,v1,v2,v3,ip1,ip2,ip3,ip4,port = struct.unpack(">BBBBBBBBH",d[:10])
7397#					if disconnected==0:
7398#						hostlist.append(((ip1,ip2,ip3,ip4),port,(v1,v2,v3)))
7399#			elif masterconn.version_less_than(1,6,28) and (length%54)==0:
7400#				n = length//54
7401#				servers = []
7402#				for i in range(n):
7403#					d = data[i*54:(i+1)*54]
7404#					disconnected,v1,v2,v3,ip1,ip2,ip3,ip4,port = struct.unpack(">BBBBBBBBH",d[:10])
7405#					if disconnected==0:
7406#						hostlist.append(((ip1,ip2,ip3,ip4),port,(v1,v2,v3)))
7407			charts = (
7408				(100,'cpu','cpu usage (percent)'),
7409				(107,'memory','memory usage (if available - rss + virt)'),
7410				(101,'datain','traffic from clients and other chunkservers (bits/s - main server + replicator)'),
7411				(102,'dataout','traffic to clients and other chunkservers (bits/s - main server + replicator)'),
7412				(103,'bytesr','bytes read - data/other (bytes/s)'),
7413				(104,'bytesw','bytes written - data/other (bytes/s)'),
7414				(2,'masterin','traffic from master (bits/s)'),
7415				(3,'masterout','traffic to master (bits/s)'),
7416				(105,'hddopr','number of low-level read operations per minute'),
7417				(106,'hddopw','number of low-level write operations per minute'),
7418				(16,'hlopr','number of high-level read operations per minute'),
7419				(17,'hlopw','number of high-level write operations per minute'),
7420				(18,'rtime','time of data read operations'),
7421				(19,'wtime','time of data write operations'),
7422				(20,'repl','number of chunk replications per minute'),
7423				(21,'create','number of chunk creations per minute'),
7424				(22,'delete','number of chunk deletions per minute'),
7425				(33,'change','number of chunk internal operations (duplicate,truncate,etc.) per minute'),
7426				(108,'move','number of chunk internal rebalances per minute (low speed + high speed)'),
7427				(28,'load','load - max operations in queue'),
7428			)
7429
7430			servers = []
7431			mixedservers = 0
7432			if len(hostlist)>0:
7433				hostlist.sort()
7434				out.append("""<form action="#"><table class="FR" cellspacing="0"><tr><th>Select: <select name="server" size="1" onchange="document.location.href='%s&CCdata='+this.options[this.selectedIndex].value">""" % createjslink({"CCdata":""}))
7435				entrystr = []
7436				entrydesc = {}
7437				for id,oname,desc in charts:
7438					name = oname.replace(":","")
7439					entrystr.append(name)
7440					entrydesc[name] = desc
7441				for ip,port,version in hostlist:
7442					nc = 1 if version>=(2,0,0) else 0
7443					if mixedservers==0:
7444						mixedservers = nc+1
7445					if mixedservers!=nc+1:
7446						mixedservers = 3
7447					strip = "%u.%u.%u.%u" % ip
7448					name = "%s:%u" % (strip,port)
7449					namearg = "%s:%u" % (name,nc)
7450					hostx = resolve(strip)
7451					if hostx==UNRESOLVED:
7452						host = ""
7453					else:
7454						host = " / "+hostx
7455					entrystr.append(namearg)
7456					entrydesc[namearg] = "Server: %s%s" % (name,host)
7457					servers.append((strip,port,"cs_"+name.replace(".","_").replace(":","_"),entrydesc[namearg],nc))
7458				if CCdata not in entrystr:
7459					out.append("""<option value="" selected="selected"> data type or server</option>""")
7460				for estr in entrystr:
7461					if estr==CCdata:
7462						out.append("""<option value="%s" selected="selected">%s</option>""" % (estr,entrydesc[estr]))
7463					else:
7464						out.append("""<option value="%s">%s</option>""" % (estr,entrydesc[estr]))
7465				out.append("""</select></th></tr></table></form>""")
7466
7467			cchtmp = CCdata.split(":")
7468			if len(cchtmp)==2:
7469				cchtmp = (cchtmp[0],cchtmp[1],0)
7470			if len(cchtmp)==3:
7471				cshost = cchtmp[0]
7472				csport = cchtmp[1]
7473				csnc = int(cchtmp[2])
7474
7475				out.append("""<script type="text/javascript">""")
7476				out.append("""<!--//--><![CDATA[//><!--""")
7477				out.append("""	var cs_vids = [%s];""" % ",".join(map(repr,[ x[0] for x in charts ])))
7478				out.append("""	var cs_inames = [%s];""" % ",".join(map(repr,[ x[1] for x in charts ])))
7479				out.append("""	var cs_idesc = [%s];""" % ",".join(map(repr,[ x[2] for x in charts ])))
7480				out.append("""	var cs_host = "%s";""" % cshost)
7481				out.append("""	var cs_port = "%s";""" % csport)
7482				out.append("""	var cs_nc = %u;""" % csnc)
7483				out.append("""//--><!]]>""")
7484				out.append("""</script>""")
7485				out.append("""<script type="text/javascript">
7486<!--//--><![CDATA[//><!--
7487	var i,j;
7488	var cs_chartid = [0,0];
7489	var cs_range_up=0;
7490	var cs_range_down=0;
7491	var cs_zoomed = [];
7492	var cs_resizeto;
7493	function cs_refresh() {
7494		var i;
7495		var minutes = Math.floor((new Date()).getTime()/60000);
7496		for (i=0 ; i<cs_inames.length ; i++) {
7497			var name = cs_inames[i];
7498			var vid = cs_vids[i];
7499			var id = vid*10+cs_range_up;
7500			var element = document.getElementById(name);
7501			if (element) {
7502				var url;
7503				if (cs_nc) {
7504					var width = element.scrollWidth;
7505					var height = element.scrollHeight;
7506					url = "chart.cgi?host="+cs_host+"&port="+cs_port+"&id="+id+"&width="+width+"&height="+height+"&antycache="+minutes;
7507				} else {
7508					url = "chart.cgi?host="+cs_host+"&port="+cs_port+"&id="+id+"&antycache="+minutes;
7509				}
7510				if (typeof(element.cs_url)=="undefined" || element.cs_url!=url) {
7511					element.cs_url = url;
7512					element.style.backgroundImage = "url('"+url+"')";
7513				}
7514			}
7515		}
7516		for (i=0 ; i<2 ; i++) {
7517			var vid = cs_vids[cs_chartid[i]];
7518			var id = vid*10+cs_range_down;
7519			var iname = "cs_chart"+i;
7520			var element = document.getElementById(iname);
7521			if (element) {
7522				var url;
7523				if (cs_nc) {
7524					var width = element.scrollWidth;
7525					var height = element.scrollHeight;
7526					url = "chart.cgi?host="+cs_host+"&port="+cs_port+"&id="+id+"&width="+width+"&height="+height+"&antycache="+minutes;
7527				} else {
7528					url = "chart.cgi?host="+cs_host+"&port="+cs_port+"&id="+id+"&antycache="+minutes;
7529				}
7530				if (typeof(element.cs_url)=="undefined" || element.cs_url!=url) {
7531					element.cs_url = url;
7532					element.style.backgroundImage = "url('"+url+"')";
7533				}
7534			}
7535		}
7536	}
7537	function cs_change_up(num) {
7538		cs_range_up = num;
7539		cs_refresh();
7540	}
7541	function cs_change_down(num) {
7542		cs_range_down = num;
7543		cs_refresh();
7544	}
7545	function cs_zoom(element) {
7546		var name = element.id;
7547		if (typeof(cs_zoomed[name])=="undefined") {
7548			cs_zoomed[name]=0;
7549		}
7550		if (cs_zoomed[name]==0) {
7551			cs_zoomed[name]=1;
7552			element.style.height = '220px';
7553		} else if (cs_zoomed[name]==1) {
7554			cs_zoomed[name]=2;
7555			element.style.height = '420px';
7556		} else if (cs_zoomed[name]==2) {
7557			cs_zoomed[name]=3;
7558			element.style.height = '820px';
7559		} else {
7560			cs_zoomed[name]=0;
7561			element.style.height = '120px';
7562		}
7563		cs_refresh()
7564	}
7565	function cs_resized() {
7566		clearTimeout(cs_resizeto);
7567		cs_resizeto = setTimeout(cs_refresh,250);
7568	}
7569	function cs_change_type(id,no) {
7570		var o;
7571		cs_chartid[id]=no;
7572		o = document.getElementById("cs_desc"+id);
7573		o.innerHTML = cs_idesc[no];
7574		cs_refresh();
7575	}
7576	function cs_add_event(obj,type,fn) {
7577		if (obj.addEventListener) {
7578			obj.addEventListener(type, fn, false);
7579		} else if (obj.attachEvent) {
7580			obj.attachEvent('on'+type, fn);
7581		}
7582	}
7583	cs_add_event(window,"load",cs_refresh);
7584	cs_add_event(window,"resize",cs_resized);
7585//--><!]]>
7586</script>""")
7587				out.append("""<table class="FR" cellspacing="0" cellpadding="0">""")
7588				out.append("""	<tr>""")
7589				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_up(0);">short range</a></th>""")
7590				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_up(1);">medium range</a></th>""")
7591				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_up(2);">long range</a></th>""")
7592				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_up(3);">very long range</a></th>""")
7593				out.append("""	</tr>""")
7594				for id,name,desc in charts:
7595					divclass = "CHARTDYNAMIC" if csnc else "CHARTSTATIC"
7596					divclick = 'onclick="cs_zoom(this)"' if csnc else ""
7597					out.append("""	<tr class="C2">""")
7598					out.append("""		<td colspan="4" style="height:124px;" valign="middle">""")
7599					out.append("""			<div class="%s" id="%s" %s>""" % (divclass,name,divclick))
7600					out.append("""				<span class="CAPTION">%s</span>""" % desc)
7601					out.append("""			</div>""")
7602					out.append("""		</td>""")
7603					out.append("""	</tr>""")
7604				out.append("""</table>""")
7605
7606				out.append("""<form action="#"><table class="FR" cellspacing="0" cellpadding="0">""")
7607				out.append("""	<tr>""")
7608				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_down(0);">short range</a></th>""")
7609				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_down(1);">medium range</a></th>""")
7610				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_down(2);">long range</a></th>""")
7611				out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change_down(3);">very long range</a></th>""")
7612				out.append("""	</tr>""")
7613				for i in range(2):
7614					divclass = "CHARTDYNAMIC" if csnc else "CHARTSTATIC"
7615					divclick = 'onclick="cs_zoom(this)"' if csnc else ""
7616					out.append("""	<tr class="C2">""")
7617					out.append("""		<td colspan="4" style="height:124px;" valign="middle">""")
7618					out.append("""			<div class="%s" id="cs_chart%u" %s>""" % (divclass,i,divclick))
7619					out.append("""				<span class="CAPTION" id="cs_desc%u">%s</span>""" % (i,charts[0][2]))
7620					out.append("""			</div>""")
7621					out.append("""		</td>""")
7622					out.append("""	</tr>""")
7623					out.append("""	<tr>""")
7624					out.append("""		<th colspan="4">""")
7625					out.append("""			<select name="cschart%u" size="1" onchange="cs_change_type(%u,this.options[this.selectedIndex].value)">""" % (i,i))
7626					no=0
7627					for id,name,desc in charts:
7628						out.append("""				<option value="%u">%s</option>""" % (no,desc))
7629						no+=1
7630					out.append("""		</th>""")
7631					out.append("""	</tr>""")
7632				out.append("""</table></form>""")
7633			elif len(cchtmp)==1 and len(CCdata)>0:
7634				chid = 0
7635				for id,name,desc in charts:
7636					if name==CCdata:
7637						chid = id
7638				if chid==0:
7639					try:
7640						chid = int(CCdata)
7641					except Exception:
7642						pass
7643				if chid>0 and chid<1000:
7644					out.append("""<script type="text/javascript">""")
7645					out.append("""<!--//--><![CDATA[//><!--""")
7646					out.append("""	var i,j;""")
7647					out.append("""	var cs_range=0;""")
7648					out.append("""	var cs_vhosts = [%s];""" % ",".join(map(repr,[ x[0] for x in servers ])))
7649					out.append("""	var cs_vports = [%s];""" % ",".join(map(repr,[ x[1] for x in servers ])))
7650					out.append("""	var cs_inames = [%s];""" % ",".join(map(repr,[ x[2] for x in servers ])))
7651					out.append("""	var cs_nc = [%s];""" % ",".join(map(repr,[ x[4] for x in servers ])))
7652					out.append("""	var cs_chid = %u;""" % chid)
7653					out.append("""//--><!]]>""")
7654					out.append("""</script>""")
7655					out.append("""<script type="text/javascript">
7656<!--//--><![CDATA[//><!--
7657	var i,j;
7658	var cs_range=0;
7659	var cs_zoomed = [];
7660	var cs_resizeto;
7661	function cs_refresh() {
7662		var i;
7663		var minutes = Math.floor((new Date()).getTime()/60000);
7664		for (i=0 ; i<cs_inames.length ; i++) {
7665			var name = cs_inames[i];
7666			var vhost = cs_vhosts[i];
7667			var vport = cs_vports[i];
7668			var csnc = cs_nc[i];
7669			var id = cs_chid*10+cs_range;
7670			var element = document.getElementById(name);
7671			if (element) {
7672				var url;
7673				if (csnc) {
7674					var width = element.scrollWidth;
7675					var height = element.scrollHeight;
7676					url = "chart.cgi?host="+vhost+"&port="+vport+"&id="+id+"&width="+width+"&height="+height+"&antycache="+minutes;
7677				} else {
7678					url = "chart.cgi?host="+vhost+"&port="+vport+"&id="+id+"&antycache="+minutes;
7679				}
7680				if (typeof(element.cs_url)=="undefined" || element.cs_url!=url) {
7681					element.cs_url = url;
7682					element.style.backgroundImage = "url('"+url+"')";
7683				}
7684			}
7685		}
7686	}
7687	function cs_change(num) {
7688		cs_range = num;
7689		cs_refresh();
7690	}
7691	function cs_zoom(element) {
7692		var name = element.id;
7693		if (typeof(cs_zoomed[name])=="undefined") {
7694			cs_zoomed[name]=0;
7695		}
7696		if (cs_zoomed[name]==0) {
7697			cs_zoomed[name]=1;
7698			element.style.height = '220px';
7699		} else if (cs_zoomed[name]==1) {
7700			cs_zoomed[name]=2;
7701			element.style.height = '420px';
7702		} else if (cs_zoomed[name]==2) {
7703			cs_zoomed[name]=3;
7704			element.style.height = '820px';
7705		} else {
7706			cs_zoomed[name]=0;
7707			element.style.height = '120px';
7708		}
7709		cs_refresh();
7710	}
7711	function cs_resized() {
7712		clearTimeout(cs_resizeto);
7713		cs_resizeto = setTimeout(cs_refresh,250);
7714	}
7715	function cs_add_event(obj,type,fn) {
7716		if (obj.addEventListener) {
7717			obj.addEventListener(type, fn, false);
7718		} else if (obj.attachEvent) {
7719			obj.attachEvent('on'+type, fn);
7720		}
7721	}
7722	cs_add_event(window,"load",cs_refresh);
7723	cs_add_event(window,"resize",cs_resized);
7724//--><!]]>
7725</script>""")
7726					out.append("""<table class="FR" cellspacing="0" cellpadding="0">""")
7727					out.append("""	<tr>""")
7728					out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change(0);">short range</a></th>""")
7729					out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change(1);">medium range</a></th>""")
7730					out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change(2);">long range</a></th>""")
7731					out.append("""		<th class="RANGEBAR"><a href="javascript:cs_change(3);">very long range</a></th>""")
7732					out.append("""	</tr>""")
7733					for cshost,csport,name,desc,csnc in servers:
7734						divclass = "CHARTDYNAMIC" if csnc else "CHARTSTATICMIXED" if mixedservers==3 else "CHARTSTATIC"
7735						divclick = 'onclick="cs_zoom(this)"' if csnc else ""
7736						out.append("""	<tr class="C2">""")
7737						out.append("""		<td colspan="4" style="height:124px;" valign="middle">""")
7738						out.append("""			<div class="%s" id="%s" %s>""" % (divclass,name,divclick))
7739						out.append("""				<span class="CAPTION">%s</span>""" % desc)
7740						out.append("""			</div>""")
7741						out.append("""		</td>""")
7742						out.append("""	</tr>""")
7743					out.append("""</table>""")
7744		else:
7745			if masterconn.version_at_least(2,0,15):
7746				if ttymode:
7747					tab = Tabble("Chunkserver chart data",len(CCchdata)+1,"r")
7748					hdrstr = ["host/port ->"]
7749					for host,port,no,mode,desc,raw in CCchdata:
7750						hdrstr.append("%s:%s" % (host,port))
7751					tab.header(*hdrstr)
7752					tab.header(("---","",len(CCchdata)+1))
7753					hdrstr = ["Time"]
7754					for host,port,no,mode,desc,raw in CCchdata:
7755						if raw:
7756							if mode==0:
7757								hdrstr.append("%s (+)" % desc)
7758							else:
7759								hdrstr.append("%s (raw)" % desc)
7760						else:
7761							hdrstr.append(desc)
7762					tab.header(*hdrstr)
7763				else:
7764					tab = Tabble("Chunkserver chart data",len(CCchdata)+1)
7765				chrange = CCrange
7766				if chrange<0 or chrange>3:
7767					chrange = 0
7768				if CCcount<0 or CCcount>4095:
7769					CCcount = 4095
7770				chrangestep = [60,360,1800,86400][chrange]
7771				series = set()
7772				for host,port,no,mode,desc,raw in CCchdata:
7773					if no==100:
7774						series.add((host,port,0))
7775						series.add((host,port,1))
7776					else:
7777						series.add((host,port,no))
7778				for gpass in (1,2):
7779					CCresult = {}
7780					timestamp = 0
7781					entries = 0
7782					repeat = 0
7783					for host,port,x in series:
7784						conn = MFSConn(host,port)
7785						data,length = conn.command(CLTOAN_CHART_DATA,ANTOCL_CHART_DATA,struct.pack(">LL",x*10+chrange,CCcount))
7786						if length>=8:
7787							ts,e = struct.unpack(">LL",data[:8])
7788							if e*8+8==length and (entries==0 or entries==e):
7789								entries = e
7790								if timestamp==0 or timestamp==ts or gpass==2:
7791									timestamp=ts
7792									CCresult[(host,port,x)] = list(struct.unpack(">"+e*"Q",data[8:]))
7793								else:
7794									repeat = 1
7795									break
7796							else:
7797								CCresult[(host,port,x)]=None
7798						else:
7799							CCresult[(host,port,x)]=None
7800					if repeat:
7801						continue
7802					else:
7803						break
7804				for e in xrange(entries):
7805					ts = timestamp-chrangestep*e
7806					timestring = time.strftime("%Y-%m-%d %H:%M",time.gmtime(ts))
7807					dline = [timestring]
7808					for host,port,no,mode,desc,raw in CCchdata:
7809						if no==100:
7810							datalist1 = CCresult[(host,port,0)]
7811							datalist2 = CCresult[(host,port,1)]
7812							if (datalist1!=None and datalist2!=None):
7813								data = datalist1[e]+datalist2[e]
7814							else:
7815								data = None
7816						else:
7817							datalist = CCresult[(host,port,no)]
7818							if datalist!=None:
7819								data = datalist[e]
7820							else:
7821								data = None
7822						if data==None:
7823							dline.append("-")
7824						elif mode==0:
7825							cpu = (data/(10000.0*chrangestep))
7826							if raw:
7827								dline.append("%.8f%%" % (cpu))
7828							else:
7829								dline.append("%.2f%%" % (cpu))
7830						elif mode==1:
7831							if raw:
7832								dline.append("%u" % data)
7833							else:
7834								data = float(data)/float(chrangestep)
7835								dline.append("%.3f/s" % data)
7836						elif mode==2:
7837							if raw:
7838								dline.append("%u" % data)
7839							else:
7840								dline.append("%s" % humanize_number(data," "))
7841						elif mode==3:
7842							dline.append("%u threads" % data)
7843						elif mode==4:
7844							if raw:
7845								dline.append("%u" % data)
7846							else:
7847								data = float(data)/float(chrangestep)
7848								data /= 10000000.0
7849								dline.append("%.2f%%" % (data))
7850						elif mode==5:
7851							if raw:
7852								dline.append("%u" % data)
7853							else:
7854								data = float(data)/float(chrangestep)
7855								dline.append("%.3fMB/s" % (data/(1024.0*1024.0)))
7856					tab.append(*dline)
7857			else:
7858				tab = Tabble("Chunkserver chart data are not supported in your version of MFS - please upgrade",1,"r")
7859		if cgimode:
7860			print("\n".join(out))
7861		else:
7862			print(myunicode(tab))
7863	except Exception:
7864		print_exception()
7865
7866if cgimode:
7867	print("""</div> <!-- end of container -->""")
7868
7869	print("""</body>""")
7870	print("""</html>""")
7871