9f9230833b50b8271840dc2c12bd1e94d9df7d12Alexander Pyhalov#!@PYTHON@
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#
6d52f363e3b2c0c5da672c5b8c8adec99d345f38Lori Alt# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
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 optparse
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensimport sys
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensimport pwd
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensimport grp
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrensimport errno
e4d060fb4c00d44cd578713eb9a921f594b733b8Sam Falknerimport solaris.misc
842727c2f41f01b380de4f5e787d905702870f23Chris Kirbyimport zfs.util
842727c2f41f01b380de4f5e787d905702870f23Chris Kirbyimport zfs.ioctl
842727c2f41f01b380de4f5e787d905702870f23Chris Kirbyimport zfs.dataset
842727c2f41f01b380de4f5e787d905702870f23Chris Kirbyimport zfs.table
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 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) = {
e4d060fb4c00d44cd578713eb9a921f594b733b8Sam Falkner (1, 1): ("SMB Group", lambda id: solaris.misc.sid_to_name(id, 0)),
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens (1, 0): ("POSIX Group", lambda id: grp.getgrgid(int(id)).gr_name),
e4d060fb4c00d44cd578713eb9a921f594b733b8Sam Falkner (0, 1): ("SMB User", lambda id: solaris.misc.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
842727c2f41f01b380de4f5e787d905702870f23Chris Kirbydef process_one_raw(acct, options, prop, elem):
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby """Update the acct dict 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:
e4d060fb4c00d44cd578713eb9a921f594b733b8Sam Falkner rid = solaris.misc.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
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")
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby rjustfields = ("used", "quota")
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
e4d060fb4c00d44cd578713eb9a921f594b733b8Sam Falkner if ds.getprop("zoned") and solaris.misc.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 # gather and process accounting information
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby # Due to -i, we need to keep a dict, so we can potentially add
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby # together the posix ID and SID's usage. Grr.
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby acct = dict()
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens for prop in props.keys():
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens if skiptype(options, prop):
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens continue;
148434217c040ea38dc844384f6ba68d9b325906Matthew Ahrens for elem in ds.userspace(prop):
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby process_one_raw(acct, options, prop, elem)
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby
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
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby t = zfs.table.Table(options.fields, rjustfields)
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby for val in acct.itervalues():
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby t.addline(cmpkey(val), val)
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby t.printme(not options.noheaders)