userspace.py revision 148434217c040ea38dc844384f6ba68d9b325906
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens#! /usr/bin/python2.4
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens#
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# CDDL HEADER START
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens#
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# The contents of this file are subject to the terms of the
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# Common Development and Distribution License (the "License").
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# You may not use this file except in compliance with the License.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens#
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# or http://www.opensolaris.org/os/licensing.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# See the License for the specific language governing permissions
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# and limitations under the License.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens#
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# When distributing Covered Code, include this CDDL HEADER in each
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# If applicable, add the following below this CDDL HEADER, with the
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# fields enclosed by brackets "[]" replaced with your own identifying
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# information: Portions Copyright [yyyy] [name of copyright owner]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens#
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# CDDL HEADER END
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens#
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# Use is subject to license terms.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens#
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens"""This module implements the "zfs userspace" and "zfs groupspace" subcommands.
148434217c040ea38dc844384f6ba68d9b325906Matthew AhrensThe only public interface is the zfs.userspace.do_userspace() function."""
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensimport zfs.util
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensimport zfs.ioctl
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensimport zfs.dataset
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensimport optparse
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensimport sys
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensimport pwd
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensimport grp
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensimport errno
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens_ = zfs.util._
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens# map from property name prefix -> (field name, isgroup)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensprops = {
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens "userused@": ("used", False),
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens "userquota@": ("quota", False),
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens "groupused@": ("used", True),
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens "groupquota@": ("quota", True),
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens}
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensdef skiptype(options, prop):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens """Return True if this property (eg "userquota@") should be skipped."""
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens (field, isgroup) = props[prop]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if field not in options.fields:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens return True
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if isgroup and "posixgroup" not in options.types and \
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens "smbgroup" not in options.types:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens return True
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if not isgroup and "posixuser" not in options.types and \
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens "smbuser" not in options.types:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens return True
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens return False
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensdef updatemax(d, k, v):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens d[k] = max(d.get(k, None), v)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensdef new_entry(options, isgroup, domain, rid):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens """Return a dict("field": value) for this domain (string) + rid (int)"""
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if domain:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens idstr = "%s-%u" % (domain, rid)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens else:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens idstr = "%u" % rid
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens (typename, mapfunc) = {
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens (1, 1): ("SMB Group", lambda id: zfs.ioctl.sid_to_name(id, 0)),
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens (1, 0): ("POSIX Group", lambda id: grp.getgrgid(int(id)).gr_name),
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens (0, 1): ("SMB User", lambda id: zfs.ioctl.sid_to_name(id, 1)),
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens (0, 0): ("POSIX User", lambda id: pwd.getpwuid(int(id)).pw_name)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens }[isgroup, bool(domain)]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if typename.lower().replace(" ", "") not in options.types:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens return None
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens v = dict()
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens v["type"] = typename
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens # python's getpwuid/getgrgid is confused by ephemeral uids
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if not options.noname and rid < 1<<31:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens try:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens v["name"] = mapfunc(idstr)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens except KeyError:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens pass
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if "name" not in v:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens v["name"] = idstr
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if not domain:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens # it's just a number, so pad it with spaces so
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens # that it will sort numerically
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens v["name.sort"] = "%20d" % rid
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens # fill in default values
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens v["used"] = "0"
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens v["used.sort"] = 0
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens v["quota"] = "none"
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens v["quota.sort"] = 0
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens return v
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensdef process_one_raw(acct, maxfieldlen, options, prop, elem):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens """Update the acct and maxfieldlen dicts to incorporate the
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens information from this elem from Dataset.userspace(prop)."""
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens (domain, rid, value) = elem
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens (field, isgroup) = props[prop]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if options.translate and domain:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens try:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens rid = zfs.ioctl.sid_to_id("%s-%u" % (domain, rid),
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens not isgroup)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens domain = None
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens except KeyError:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens pass;
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens key = (isgroup, domain, rid)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens try:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens v = acct[key]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens except KeyError:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens v = new_entry(options, isgroup, domain, rid)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if not v:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens return
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens acct[key] = v
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens # Add our value to an existing value, which may be present if
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens # options.translate is set.
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens value = v[field + ".sort"] = value + v[field + ".sort"]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if options.parsable:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens v[field] = str(value)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens else:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens v[field] = zfs.util.nicenum(value)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens for k in v.keys():
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens # some of the .sort fields are integers, so have no len()
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if isinstance(v[k], str):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens updatemax(maxfieldlen, k, len(v[k]))
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensdef do_userspace():
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens """Implements the "zfs userspace" and "zfs groupspace" subcommands."""
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens def usage(msg=None):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens parser.print_help()
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if msg:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens print
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens parser.exit("zfs: error: " + msg)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens else:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens parser.exit()
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if sys.argv[1] == "userspace":
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens defaulttypes = "posixuser,smbuser"
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens else:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens defaulttypes = "posixgroup,smbgroup"
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens fields = ("type", "name", "used", "quota")
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens ljustfields = ("type", "name")
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens types = ("all", "posixuser", "smbuser", "posixgroup", "smbgroup")
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens u = _("%s [-niHp] [-o field[,...]] [-sS field] ... \n") % sys.argv[1]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens u += _(" [-t type[,...]] <filesystem|snapshot>")
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens parser = optparse.OptionParser(usage=u, prog="zfs")
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens parser.add_option("-n", action="store_true", dest="noname",
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens help=_("Print numeric ID instead of user/group name"))
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens parser.add_option("-i", action="store_true", dest="translate",
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens help=_("translate SID to posix (possibly ephemeral) ID"))
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens parser.add_option("-H", action="store_true", dest="noheaders",
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens help=_("no headers, tab delimited output"))
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens parser.add_option("-p", action="store_true", dest="parsable",
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens help=_("exact (parsable) numeric output"))
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens parser.add_option("-o", dest="fields", metavar="field[,...]",
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens default="type,name,used,quota",
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens help=_("print only these fields (eg type,name,used,quota)"))
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens parser.add_option("-s", dest="sortfields", metavar="field",
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens type="choice", choices=fields, default=list(),
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens action="callback", callback=zfs.util.append_with_opt,
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens help=_("sort field"))
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens parser.add_option("-S", dest="sortfields", metavar="field",
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens type="choice", choices=fields, #-s sets the default
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens action="callback", callback=zfs.util.append_with_opt,
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens help=_("reverse sort field"))
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens parser.add_option("-t", dest="types", metavar="type[,...]",
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens default=defaulttypes,
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens help=_("print only these types (eg posixuser,smbuser,posixgroup,smbgroup,all)"))
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens (options, args) = parser.parse_args(sys.argv[2:])
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if len(args) != 1:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens usage(_("wrong number of arguments"))
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens dsname = args[0]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens options.fields = options.fields.split(",")
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens for f in options.fields:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if f not in fields:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens usage(_("invalid field %s") % f)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens options.types = options.types.split(",")
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens for t in options.types:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if t not in types:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens usage(_("invalid type %s") % t)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if not options.sortfields:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens options.sortfields = [("-s", "type"), ("-s", "name")]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if "all" in options.types:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens options.types = types[1:]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens ds = zfs.dataset.Dataset(dsname, types=("filesystem"))
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if ds.getprop("zoned") and zfs.ioctl.isglobalzone():
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens options.noname = True
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if not ds.getprop("useraccounting"):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens print(_("Initializing accounting information on old filesystem, please wait..."))
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens ds.userspace_upgrade()
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens acct = dict()
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens maxfieldlen = dict()
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens # gather and process accounting information
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens for prop in props.keys():
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if skiptype(options, prop):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens continue;
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens for elem in ds.userspace(prop):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens process_one_raw(acct, maxfieldlen, options, prop, elem)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens # print out headers
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if not options.noheaders:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens line = str()
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens for field in options.fields:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens # make sure the field header will fit
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens updatemax(maxfieldlen, field, len(field))
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if field in ljustfields:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens fmt = "%-*s "
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens else:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens fmt = "%*s "
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens line += fmt % (maxfieldlen[field], field.upper())
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens print(line)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens # custom sorting func
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens def cmpkey(val):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens l = list()
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens for (opt, field) in options.sortfields:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens try:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens n = val[field + ".sort"]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens except KeyError:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens n = val[field]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if opt == "-S":
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens # reverse sorting
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens try:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens n = -n
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens except TypeError:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens # it's a string; decompose it
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens # into an array of integers,
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens # each one the negative of that
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens # character
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens n = [-ord(c) for c in n]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens l.append(n)
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens return l
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens # print out data lines
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens for val in sorted(acct.itervalues(), key=cmpkey):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens line = str()
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens for field in options.fields:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if options.noheaders:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens line += val[field]
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens line += "\t"
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens else:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if field in ljustfields:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens fmt = "%-*s "
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens else:
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens fmt = "%*s "
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens line += fmt % (maxfieldlen[field], val[field])
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens print(line)