def output_format(file, windows=False, archive=None): if file[T_TYPE] == 'X': return '--- TRUNCATED ---' name = to_utf8(file[T_NAME]) if archive: name += u' \u25bb ' + archive if windows: out = u' {}{}{}{}'.format( u'{:<10}'.format(file_timestamp(file[T_TIMESTAMP])), u'{:<3}'.format(file[T_TYPE]), u'{:<11}'.format(size_human_readable(file[T_SIZE])), u'{:<40}'.format(name)) else: out = u' {}{}{}{}{}{}{}'.format( u'{:<10}'.format(file_timestamp(file[T_TIMESTAMP])), u'{:<3}'.format(file[T_TYPE]), u'{:<5}'.format(file[T_UID]), u'{:<5}'.format(file[T_GID]), u' {:06o} '.format(file[T_MODE]), u'{:<11}'.format(size_human_readable(file[T_SIZE])), u'{:<40}'.format(name)) if archive: out=Color(out, 'yellow') elif file[T_TYPE] == 'D': out=Color(out, 'lightyellow') elif 'U' in file[T_SPEC]: out=Color(out, 'lightred') elif 'G' in file[T_SPEC]: out=Color(out, 'red') elif file[T_TYPE] == 'B': out=Color(out, 'grey') elif file[T_TYPE] == 'C': out=Color(out, 'grey') elif file[T_TYPE] == 'F': out=Color(out, 'cyan') elif file[T_TYPE] == 'S': out=Color(out, 'magenta') elif file[T_TYPE] == 'L': out=Color(out, 'grey') elif not file[T_SIZE]: out=Color(out, 'darkgrey') elif 'E' in file[T_SPEC]: out=Color(out, 'lightgreen') elif 'W' in file[T_SPEC] and not windows: out=Color(out, 'blue') return out
def print_psinfo(fout, families, socktypes, data, colinfo, sections=[], wide=False): keys = ('id', 'key', 'PROPERTY', 'VAR', 'TYPE') sorter = lambda x, y: -1 if (x in keys and y not in keys) else (1 if ( y in keys and not x in keys) else cmp(x, y)) parts = [] for pid, info in data.iteritems(): if sections is not None: infosecs = {'general': []} for prop, value in info.iteritems(): if type(value) not in (list, dict): infosecs['general'].append({ 'PROPERTY': prop, 'VALUE': '{:3}%'.format(int(value)) if ('_percent' in prop) else value }) else: if prop == 'environ': maxvar = max(len(x) for x in value.iterkeys()) maxval = max(len(x) for x in value.itervalues()) infosecs[prop] = [{ 'VAR': x, 'VALUE': y } for x, y in value.iteritems()] continue elif prop == 'connections': newvalue = [] for connection in value: newvalue.append({ 'status': connection['status'], 'raddr': ':'.join([str(x) for x in connection['raddr']]), 'laddr': ':'.join([str(x) for x in connection['laddr']]), 'family': families[connection['family']], 'type': socktypes[connection['type']], }) infosecs[prop] = newvalue continue elif prop == 'memory_maps': filtered = ('path', 'rss', 'size') elif prop == 'memory_info': infosecs[prop] = [{ 'TYPE': item['KEY'], 'SIZE': size_human_readable(item['VALUE']) } for item in value] continue else: filtered = None infosecs[prop] = [{ k: v for k, v in item.iteritems() if filtered is None or k in filtered } for item in (value if type(value) == list else [value])] if sections: for section in sections: section = section.lower() if section in infosecs: labels = sorted(infosecs[section][0], cmp=sorter) parts.append( TruncateToTerm( Table(infosecs[section], labels, Color(section.upper(), 'yellow')))) else: for section, table in infosecs.iteritems(): labels = sorted(table[0], cmp=sorter) parts.append( TruncateToTerm( Table(table, labels, Color(section.upper(), 'yellow')))) fout(MultiPart(parts)) else: outcols = ['pid'] + [ x for x in ('cpu_percent', 'memory_percent', 'username', 'exe', 'name', 'cmdline') if x in colinfo ] info['pid'] = pid columns = gen_columns(info, colinfo) fout(gen_output_line(columns, outcols, info, wide) + '\n')
class ls(PupyModule): """ list system files """ is_module = False dependencies = ['pupyutils.basic_cmds', 'scandir'] @classmethod def init_argparse(cls): cls.arg_parser = PupyArgumentParser(prog="ls", description=cls.__doc__) cls.arg_parser.add_argument('-d', '--dir', action='store_false', default=True, help='do not list directories') sort = cls.arg_parser.add_mutually_exclusive_group() sort.add_argument( '-L', '--limit', type=int, default=1024, help='List no more than this amount of files (server side), ' 'to not to stuck on huge dirs. Default: 1024') sort.add_argument('-s', '--size', dest='sort', action='store_const', const=T_SIZE, help='sort by size') sort.add_argument('-t', '--time', dest='sort', action='store_const', const=T_TIMESTAMP, help='sort by time') cls.arg_parser.add_argument('-r', '--reverse', action='store_true', default=False, help='reverse sort order') cls.arg_parser.add_argument('path', type=str, nargs='?', help='path of a specific file', completer=remote_path_completer) def run(self, args): try: ls = self.client.remote('pupyutils.basic_cmds', 'ls') results = ls(args.path, args.dir, args.limit) except Exception, e: self.error(' '.join(x for x in e.args if type(x) in (str, unicode))) return # results = obtain(results) windows = self.client.is_windows() if not results: return total_cnt = 0 files_size = 0 files_cnt = 0 dirs_cnt = 0 for r in results: if T_FILES in r: self.log(r[T_PATH] + ':') if not args.sort: dirs = [] files = [] truncated = 0 for x in r[T_FILES]: if T_TRUNCATED in x: truncated = x[T_TRUNCATED] total_cnt += truncated elif x[T_TYPE] == 'D': dirs.append(x) total_cnt += 1 dirs_cnt += 1 else: files.append(x) files_size += x[T_SIZE] total_cnt += 1 files_cnt += 1 for f in sorted(dirs, key=lambda x: to_utf8(x.get(T_NAME)), reverse=args.reverse): self.log(output_format(f, windows)) for f in sorted(files, key=lambda x: to_utf8(x.get(T_NAME)), reverse=args.reverse): self.log(output_format(f, windows)) if truncated: self.warning( 'Folder is too big. Not listed: {} (-L {})'.format( truncated, args.limit)) self.info( 'Summary (observed): Files: {} Dirs: {} Total: {}'. format( '{}+'.format(files_cnt) if files_cnt else '??', '{}+'.format(dirs_cnt) if dirs_cnt else '??', total_cnt)) else: self.info( 'Summary: Files: {} (size: {}) Dirs: {} Total: {}'. format(files_cnt, size_human_readable(files_size), dirs_cnt, total_cnt)) else: truncated = False for f in sorted(r[T_FILES], key=lambda x: x.get(args.sort), reverse=args.reverse): if T_TRUNCATED in f: truncated = True continue self.log(output_format(f, windows)) if truncated: self.log('--- TRUNCATED ---') elif T_FILE in r: self.log(output_format(r[T_FILE], windows)) else: self.error('Old format. Update pupyutils.basic_cmds') return
class FStat(PupyModule): '''Show a bit more info about file path. ACLs/Caps/Owner for now''' dependencies = { 'all': ['pupyutils.basic_cmds', 'fsutils', 'fsutils_ext'], 'windows': ['junctions', 'ntfs_streams', 'pupwinutils.security'], 'linux': ['xattr', 'posix1e', 'prctl', '_prctl'] } @classmethod def init_argparse(cls): cls.arg_parser = PupyArgumentParser(prog='stat', description=cls.__doc__) cls.arg_parser.add_argument( '-v', '--verbose', action='store_true', default=False, help='Print more information (certificates for example)') cls.arg_parser.add_argument('path', type=str, nargs=REMAINDER, help='path of a specific file', completer=remote_path_completer) def run(self, args): getfilesec = self.client.remote('fsutils_ext', 'getfilesec') path = ' '.join(args.path) try: sec = getfilesec(path) except Exception, e: self.error(' '.join(x for x in e.args if type(x) in (str, unicode))) return ctime, atime, mtime, size, owner, group, header, mode, extra = sec owner_id, owner_name, owner_domain = owner group_id, group_name, group_domain = group default = { 'Created': file_timestamp(ctime, time=True), 'Accessed': file_timestamp(atime, time=True), 'Modified': file_timestamp(mtime, time=True), 'Size': '{} ({})'.format(size_human_readable(size), size), 'Owner': '{}{} ({})'.format(owner_domain + '\\' if owner_domain else '', owner_name, owner_id), 'Group': '{}{} ({})'.format(group_domain + '\\' if group_domain else '', group_name, group_id), 'Mode': mode, } infos = [] infos.append( Table([{ 'Property': p, 'Value': default[p] } for p in ('Created', 'Accessed', 'Modified', 'Size', 'Owner', 'Group', 'Mode')], ['Property', 'Value'], legend=False)) oneliners = [] certificates = None for extra, values in extra.iteritems(): if extra == 'Certificates': certificates = [ load_cert_string(cert, FORMAT_DER).as_text() for cert in values ] elif isinstance(values, dict): records = [{ 'KEY': k.decode('utf-8'), 'VALUE': v.decode('utf-8') if isinstance(v, str) else str(v) } for k, v in values.iteritems()] infos.append(Table(records, ['KEY', 'VALUE'], caption=extra)) elif isinstance(values, (list, tuple)): if all( isinstance(value, (list, tuple)) and len(value) == 2 for value in values): infos.append( List('{}: {}'.format(key, value) for key, value in values)) else: infos.append(List(values, caption=extra)) elif isinstance(values, int): oneliners.append('{}: {}'.format(extra, values)) elif '\n' in values: infos.append(Line(extra + ':', values)) else: oneliners.append(extra + ': ' + values) if args.verbose: magic = '' if header: with Magic() as libmagic: magic = libmagic.id_buffer(header) if magic: oneliners.append('Magic: {}'.format(magic)) if certificates: infos.extend(certificates) if oneliners: infos.append(List(oneliners, caption='Other')) self.log(MultiPart(infos))
def run(self, args): ok = False if self.client.is_posix(): tier1 = ('network', 'fuse', 'dm', 'block', 'vm') mounts = self.client.remote('mount', 'mounts') getuid = self.client.remote('os', 'getuid') getgid = self.client.remote('os', 'getgid') mountinfo = mounts() uid = getuid() gid = getgid() option_colors = { 'rw': 'yellow', 'nosuid': 'grey', 'nodev': 'grey', 'noexec': 'lightgreen', 'uid': { '0': 'green', str(uid): 'red' }, 'gid': { '0': 'green', str(gid): 'red' }, 'ro': 'green', 'user_id': { '0': 'green', str(uid): 'red' }, 'group_id': { '0': 'green', str(gid): 'red' }, 'allow_other': 'yellow', 'xattr': 'yellow', 'acl': 'yellow', 'username': '******', 'domain': 'red', 'forceuid': 'yellow', 'forcegid': 'yellow', 'addr': 'red', 'unix': 'red' } def colorize_option(option): if len(option) > 1: k, v = option else: k = option[0] v = None color = option_colors.get(k) if color: if type(color) == dict: if v in color: return colorize('='.join([x for x in [k, v] if x]), color.get(v)) else: return '='.join([x for x in [k, v] if x]) else: return colorize('='.join([x for x in [k, v] if x]), color) else: return '='.join([x for x in [k, v] if x]) output = [] for fstype in mountinfo.iterkeys(): if fstype in tier1: continue output.append('{}:'.format(colorize(fstype, 'yellow'))) dst_max = max([len(x['dst']) for x in mountinfo[fstype]]) fsname_max = max([len(x['fsname']) for x in mountinfo[fstype]]) free_max = max([ len(x['hfree']) if x['total'] else 0 for x in mountinfo[fstype] ]) for info in mountinfo[fstype]: fmt = '{{:<{}}} {{:<{}}} {{:>{}}} {{}}'.format( dst_max, fsname_max, (free_max + 3 + 4) if free_max else 0) output.append( fmt.format( info['dst'], info['fsname'], (colorize( ('{{:>3}}% ({{:>{}}})'.format(free_max) ).format(info['pused'], info['hfree']), 'white' if info['pused'] < 90 else 'yellow')) if info['total'] else '', ','.join([ colorize_option(option) for option in info['options'] ]))) output.append('') for fstype in tier1: if not fstype in mountinfo: continue src_max = max([len(x['src']) for x in mountinfo[fstype]]) dst_max = max([len(x['dst']) for x in mountinfo[fstype]]) fsname_max = max([len(x['fsname']) for x in mountinfo[fstype]]) free_max = max([ len(x['hfree']) if x['total'] else 0 for x in mountinfo[fstype] ]) output.append('{}:'.format(colorize(fstype, 'green'))) for info in mountinfo[fstype]: fmt = '{{:<{}}} {{:<{}}} {{:<{}}} {{:>{}}} {{}}'.format( dst_max, src_max, fsname_max, (free_max + 3 + 4) if free_max else 0) output.append( fmt.format( info['dst'], info['src'], info['fsname'], (colorize( ('{{:>3}}% ({{:>{}}})'.format(free_max) ).format(info['pused'], info['hfree']), 'white' if info['pused'] < 90 else 'yellow')) if info['total'] else '', ','.join([ colorize_option(option) for option in info['options'] ]))) output.append('') self.log('\n'.join(output)) ok = True elif self.client.is_windows(): try: list_drives = self.client.remote('pupwinutils.drives', 'list_drives') self.log(list_drives()) ok = True except: self.warning('WMI failed') pass if not ok: list_drives = self.client.remote('pupyps', 'drives') drives = list_drives() formatted_drives = [] for drive in drives: formatted_drives.append({ 'DEV': drive['device'], 'MP': drive['mountpoint'], 'FS': drive['fstype'], 'OPTS': drive['opts'], 'USED': ('{}% ({}/{})'.format( drive['percent'], size_human_readable(drive['used']), size_human_readable(drive['total']))) if ('used' in drive and 'total' in drive) else '?' }) self.log( Table(formatted_drives, ['DEV', 'MP', 'FS', 'OPTS', 'USED']))
def run(self, args): if self.client.is_posix(): tier1 = ('network', 'fuse', 'dm', 'block', 'vm') mounts = self.client.remote('mount', 'mounts') getuid = self.client.remote('os', 'getuid') getgid = self.client.remote('os', 'getgid') mountinfo = mounts() uid = getuid() gid = getgid() option_colors = { 'rw': 'yellow', 'nosuid': 'grey', 'nodev': 'grey', 'noexec': 'lightgreen', 'uid': { '0': 'green', str(uid): 'red' }, 'gid': { '0': 'green', str(gid): 'red' }, 'ro': 'green', 'user_id': { '0': 'green', str(uid): 'red' }, 'group_id': { '0': 'green', str(gid): 'red' }, 'allow_other': 'yellow', 'xattr': 'yellow', 'acl': 'yellow', 'username': '******', 'domain': 'red', 'forceuid': 'yellow', 'forcegid': 'yellow', 'addr': 'red', 'unix': 'red' } def colorize_option(option): if len(option) > 1: k, v = option else: k = option[0] v = None color = option_colors.get(k) if color: if type(color) == dict: if v in color: return colorize('='.join([x for x in [k, v] if x]), color.get(v)) else: return '='.join([x for x in [k, v] if x]) else: return colorize('='.join([x for x in [k, v] if x]), color) else: return '='.join([x for x in [k, v] if x]) output = [] for fstype in mountinfo.iterkeys(): if fstype in tier1: continue output.append('{}:'.format(colorize(fstype, 'yellow'))) dst_max = max([len(x['dst']) for x in mountinfo[fstype]]) fsname_max = max([len(x['fsname']) for x in mountinfo[fstype]]) free_max = max([ len(x['hfree']) if x['total'] else 0 for x in mountinfo[fstype] ]) for info in mountinfo[fstype]: fmt = '{{:<{}}} {{:<{}}} {{:>{}}} {{}}'.format( dst_max, fsname_max, (free_max + 3 + 4) if free_max else 0) output.append( fmt.format( info['dst'], info['fsname'], (colorize( ('{{:>3}}% ({{:>{}}})'.format(free_max) ).format(info['pused'], info['hfree']), 'white' if info['pused'] < 90 else 'yellow')) if info['total'] else '', ','.join([ colorize_option(option) for option in info['options'] ]))) output.append('') for fstype in tier1: if fstype not in mountinfo: continue src_max = max([len(x['src']) for x in mountinfo[fstype]]) dst_max = max([len(x['dst']) for x in mountinfo[fstype]]) fsname_max = max([len(x['fsname']) for x in mountinfo[fstype]]) free_max = max([ len(x['hfree']) if x['total'] else 0 for x in mountinfo[fstype] ]) output.append('{}:'.format(colorize(fstype, 'green'))) for info in mountinfo[fstype]: fmt = '{{:<{}}} {{:<{}}} {{:<{}}} {{:>{}}} {{}}'.format( dst_max, src_max, fsname_max, (free_max + 3 + 4) if free_max else 0) output.append( fmt.format( info['dst'], info['src'], info['fsname'], (colorize( ('{{:>3}}% ({{:>{}}})'.format(free_max) ).format(info['pused'], info['hfree']), 'white' if info['pused'] < 90 else 'yellow')) if info['total'] else '', ','.join([ colorize_option(option) for option in info['options'] ]))) output.append('') self.log('\n'.join(output)) elif self.client.is_windows(): list_drives = self.client.remote('pupyps', 'drives') EnumNetResources = self.client.remote('netresources', 'EnumNetResources') drives = list_drives() formatted_drives = [] parts = [] for drive in drives: formatted_drives.append({ 'MP': drive['mountpoint'], 'FS': drive['fstype'], 'OPTS': drive['opts'], 'USED': ('{}% ({}/{})'.format( drive['percent'], size_human_readable(drive['used']), size_human_readable(drive['total']))) if ('used' in drive and 'total' in drive) else '?' }) parts.append(Table(formatted_drives, ['MP', 'FS', 'OPTS', 'USED'])) providers = {} net_resources = EnumNetResources() for resource in net_resources: if resource['provider'] not in providers: providers[resource['provider']] = [] if 'used' in resource: resource['used'] = '{}% ({}/{})'.format( resource['percent'], size_human_readable(resource['used']), size_human_readable(resource['total'])) else: resource['used'] = '?' providers[resource['provider']].append( dict((k, v) for k, v in resource.iteritems() if k not in ('usage', 'provider', 'scope'))) for provider, records in providers.iteritems(): parts.append( Table(records, ['remote', 'local', 'type', 'used'], caption=provider)) self.log(MultiPart(parts))
def output_format(file, windows=False, archive=None, time=False, uid_len=0, gid_len=0): if file[T_TYPE] == 'X': return '--- TRUNCATED ---' name = to_str(file[T_NAME]) if archive: name += u' \u25bb ' + archive timestamp_field = u'{:<18}' if time else u'{:<10}' if windows: out = u' {}{}{}{}{}{}'.format( timestamp_field.format(file_timestamp(file[T_TIMESTAMP], time)), u'{:<2}'.format(file[T_TYPE] + ('+' if file[T_HAS_XATTR] else '')), to_str(file[T_UID]).rjust(uid_len + 1) + u' ' if uid_len else u'', to_str(file[T_GID]).rjust(gid_len + 1) + u' ' if gid_len else u'', u'{:>9}'.format(size_human_readable(file[T_SIZE])), u' {:<40}'.format(name)) else: if not uid_len: uid_len = 5 if not gid_len: gid_len = 5 out = u' {}{}{}{}{}{}{}'.format( timestamp_field.format(file_timestamp(file[T_TIMESTAMP], time)), u'{:<2}'.format(file[T_TYPE] + ('+' if file[T_HAS_XATTR] else '')), to_str(file[T_UID]).rjust(uid_len + 1) + ' ', to_str(file[T_GID]).rjust(gid_len + 1) + ' ', u'{:04o} '.format(file[T_MODE] & 0o7777), u'{:>9}'.format(size_human_readable(file[T_SIZE])), u' {:<40}'.format(name)) if archive: out = Color(out, 'yellow') elif file[T_TYPE] == 'D': out = Color(out, 'lightyellow') elif 'U' in file[T_SPEC]: out = Color(out, 'lightred') elif 'G' in file[T_SPEC]: out = Color(out, 'red') elif file[T_TYPE] == 'B': out = Color(out, 'grey') elif file[T_TYPE] == 'C': out = Color(out, 'grey') elif file[T_TYPE] == 'F': out = Color(out, 'cyan') elif file[T_TYPE] == 'S': out = Color(out, 'magenta') elif file[T_TYPE] == 'L': out = Color(out, 'grey') elif not file[T_SIZE]: out = Color(out, 'darkgrey') elif 'W' in file[T_SPEC] and not windows: out = Color(out, 'blue') elif file[T_HAS_XATTR]: out = Color(out, 'lightmagenta') elif 'E' in file[T_SPEC]: out = Color(out, 'lightgreen') return out
class ls(PupyModule): """ list system files """ is_module = False dependencies = ['pupyutils.basic_cmds'] @classmethod def init_argparse(cls): cls.arg_parser = PupyArgumentParser(prog="ls", description=cls.__doc__) cls.arg_parser.add_argument('-d', '--dir', action='store_false', default=True, help='do not list directories') cls.arg_parser.add_argument('-u', '--userinfo', action='store_true', help='show uid info') cls.arg_parser.add_argument('-g', '--groupinfo', action='store_true', help='show gid info') sort = cls.arg_parser.add_mutually_exclusive_group() sort.add_argument( '-L', '--limit', type=int, default=1024, help='List no more than this amount of files (server side), ' 'to not to stuck on huge dirs. Default: 1024') sort.add_argument('-A', '--archive', action='store_true', help='list archives (tar/zip)') sort.add_argument('-s', '--size', dest='sort', action='store_const', const=T_SIZE, help='sort by size') sort.add_argument('-t', '--time', dest='sort', action='store_const', const=T_TIMESTAMP, help='sort by time') cls.arg_parser.add_argument('-r', '--reverse', action='store_true', default=False, help='reverse sort order') cls.arg_parser.add_argument('path', type=str, nargs=REMAINDER, help='path of a specific file', completer=remote_path_completer) def run(self, args): try: ls = self.client.remote('pupyutils.basic_cmds', 'ls') path = ' '.join(args.path) results = ls(path, args.dir, args.limit, args.archive, args.userinfo or args.groupinfo) except Exception, e: self.error(' '.join(x for x in e.args if type(x) in (str, unicode))) return # results = obtain(results) windows = self.client.is_windows() if not results: return total_cnt = 0 files_size = 0 files_cnt = 0 dirs_cnt = 0 show_time = args.sort == T_TIMESTAMP for r in results: uid_len = 0 gid_len = 0 if T_FILES in r: archive = None is_windows = windows if args.userinfo or args.groupinfo: for x in r[T_FILES]: if args.userinfo: uid = x.get(T_UID, '?') if type(uid) == int: uid = str(uid) if elen(uid) > uid_len: uid_len = elen(uid) if args.groupinfo: gid = x.get(T_GID, '?') if type(gid) == int: gid = str(gid) if elen(gid) > gid_len: gid_len = elen(gid) if T_ZIPFILE in r: self.log(Color('ZIP: ' + r[T_ZIPFILE] + ':', 'lightred')) is_windows = True elif T_TARFILE in r: self.log(Color('TAR: ' + r[T_TARFILE] + ':', 'lightred')) is_windows = False elif T_PATH in r: self.log(r[T_PATH] + ':') if not args.sort: dirs = [] files = [] truncated = 0 for x in r[T_FILES] or []: if T_TRUNCATED in x: truncated = x[T_TRUNCATED] total_cnt += truncated elif x[T_TYPE] == 'D': dirs.append(x) total_cnt += 1 dirs_cnt += 1 else: files.append(x) files_size += x[T_SIZE] total_cnt += 1 files_cnt += 1 for f in sorted(dirs, key=lambda x: to_str(x.get(T_NAME)), reverse=args.reverse): self.log( output_format(f, is_windows, time=show_time, uid_len=uid_len, gid_len=gid_len)) for f in sorted(files, key=lambda x: to_str(x.get(T_NAME)), reverse=args.reverse): self.log( output_format(f, is_windows, time=show_time, uid_len=uid_len, gid_len=gid_len)) if truncated: self.warning( 'Folder is too big. Not listed: {} (-L {})'.format( truncated, args.limit)) self.info( 'Summary (observed): Files: {} Dirs: {} Total: {}'. format( '{}+'.format(files_cnt) if files_cnt else '??', '{}+'.format(dirs_cnt) if dirs_cnt else '??', total_cnt)) else: self.info( 'Summary: Files: {} (size: {}) Dirs: {} Total: {}'. format(files_cnt, size_human_readable(files_size), dirs_cnt, total_cnt)) else: truncated = False for f in sorted(r[T_FILES], key=lambda x: x.get(args.sort), reverse=args.reverse): if T_TRUNCATED in f: truncated = True continue self.log( output_format(f, is_windows, time=show_time, uid_len=uid_len, gid_len=gid_len)) if truncated: self.log('--- TRUNCATED ---') elif T_FILE in r: is_windows = windows archive = '' if T_ZIPFILE in r: archive = 'ZIP' is_windows = True elif T_TARFILE in r: archive = 'TAR' is_windows = False if args.userinfo: uid = r[T_FILE][T_UID] if type(uid) == int: uid = str(uid) uid_len = elen(uid) if args.groupinfo: gid = r[T_FILE][T_GID] if type(gid) == int: gid = str(gid) gid_len = elen(gid) self.log( output_format(r[T_FILE], is_windows, archive, show_time, uid_len=uid_len, gid_len=gid_len)) else: self.error('Old format. Update pupyutils.basic_cmds') return
class FStat(PupyModule): '''Show a bit more info about file path. ACLs/Caps/Owner for now''' dependencies = { 'all': ['pupyutils', 'fsutils', 'fsutils_ext'], 'windows': ['junctions', 'ntfs_streams'], 'linux': ['xattr', 'posix1e', 'prctl', '_prctl'] } @classmethod def init_argparse(cls): cls.arg_parser = PupyArgumentParser(prog='stat', description=cls.__doc__) cls.arg_parser.add_argument('path', type=str, nargs=REMAINDER, help='path of a specific file', completer=remote_path_completer) def run(self, args): getfilesec = self.client.remote('fsutils_ext', 'getfilesec') path = ' '.join(args.path) try: sec = getfilesec(path) except Exception, e: self.error(' '.join(x for x in e.args if type(x) in (str, unicode))) return ctime, atime, mtime, size, owner, group, header, mode, extra = sec owner_id, owner_name, owner_domain = owner group_id, group_name, group_domain = group magic = '' if header: with Magic() as libmagic: magic = libmagic.id_buffer(header) default = { 'Created': file_timestamp(ctime, time=True), 'Accessed': file_timestamp(atime, time=True), 'Modified': file_timestamp(mtime, time=True), 'Size': '{} ({})'.format(size_human_readable(size), size), 'Owner': '{}{} ({})'.format(owner_domain + '\\' if owner_domain else '', owner_name, owner_id), 'Group': '{}{} ({})'.format(group_domain + '\\' if group_domain else '', group_name, group_id), 'Mode': mode, } infos = [] infos.append( Table([{ 'Property': p, 'Value': default[p] } for p in ('Created', 'Accessed', 'Modified', 'Size', 'Owner', 'Group', 'Mode')], ['Property', 'Value'], legend=False)) if magic: infos.append('Magic: {}'.format(magic)) for extra, values in extra.iteritems(): if type(values) in (list, tuple): infos.append(List(values, caption=extra)) else: infos.append(Line(extra + ':', values)) self.log(MultiPart(infos))