xref: /titanic_44/usr/src/lib/pyzfs/common/allow.py (revision 148434217c040ea38dc844384f6ba68d9b325906)
1*14843421SMatthew Ahrens#! /usr/bin/python2.4
2*14843421SMatthew Ahrens#
3*14843421SMatthew Ahrens# CDDL HEADER START
4*14843421SMatthew Ahrens#
5*14843421SMatthew Ahrens# The contents of this file are subject to the terms of the
6*14843421SMatthew Ahrens# Common Development and Distribution License (the "License").
7*14843421SMatthew Ahrens# You may not use this file except in compliance with the License.
8*14843421SMatthew Ahrens#
9*14843421SMatthew Ahrens# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*14843421SMatthew Ahrens# or http://www.opensolaris.org/os/licensing.
11*14843421SMatthew Ahrens# See the License for the specific language governing permissions
12*14843421SMatthew Ahrens# and limitations under the License.
13*14843421SMatthew Ahrens#
14*14843421SMatthew Ahrens# When distributing Covered Code, include this CDDL HEADER in each
15*14843421SMatthew Ahrens# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*14843421SMatthew Ahrens# If applicable, add the following below this CDDL HEADER, with the
17*14843421SMatthew Ahrens# fields enclosed by brackets "[]" replaced with your own identifying
18*14843421SMatthew Ahrens# information: Portions Copyright [yyyy] [name of copyright owner]
19*14843421SMatthew Ahrens#
20*14843421SMatthew Ahrens# CDDL HEADER END
21*14843421SMatthew Ahrens#
22*14843421SMatthew Ahrens# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23*14843421SMatthew Ahrens# Use is subject to license terms.
24*14843421SMatthew Ahrens#
25*14843421SMatthew Ahrens
26*14843421SMatthew Ahrens"""This module implements the "zfs allow" and "zfs unallow" subcommands.
27*14843421SMatthew AhrensThe only public interface is the zfs.allow.do_allow() function."""
28*14843421SMatthew Ahrens
29*14843421SMatthew Ahrensimport zfs.util
30*14843421SMatthew Ahrensimport zfs.dataset
31*14843421SMatthew Ahrensimport optparse
32*14843421SMatthew Ahrensimport sys
33*14843421SMatthew Ahrensimport pwd
34*14843421SMatthew Ahrensimport grp
35*14843421SMatthew Ahrensimport errno
36*14843421SMatthew Ahrens
37*14843421SMatthew Ahrens_ = zfs.util._
38*14843421SMatthew Ahrens
39*14843421SMatthew Ahrensclass FSPerms(object):
40*14843421SMatthew Ahrens	"""This class represents all the permissions that are set on a
41*14843421SMatthew Ahrens	particular filesystem (not including those inherited)."""
42*14843421SMatthew Ahrens
43*14843421SMatthew Ahrens	__slots__ = "create", "sets", "local", "descend", "ld"
44*14843421SMatthew Ahrens	__repr__ = zfs.util.default_repr
45*14843421SMatthew Ahrens
46*14843421SMatthew Ahrens	def __init__(self, raw):
47*14843421SMatthew Ahrens		"""Create a FSPerms based on the dict of raw permissions
48*14843421SMatthew Ahrens		from zfs.ioctl.get_fsacl()."""
49*14843421SMatthew Ahrens		# set of perms
50*14843421SMatthew Ahrens		self.create = set()
51*14843421SMatthew Ahrens
52*14843421SMatthew Ahrens		# below are { "Ntype name": set(perms) }
53*14843421SMatthew Ahrens		# where N is a number that we just use for sorting,
54*14843421SMatthew Ahrens		# type is "user", "group", "everyone", or "" (for sets)
55*14843421SMatthew Ahrens		# name is a user, group, or set name, or "" (for everyone)
56*14843421SMatthew Ahrens		self.sets = dict()
57*14843421SMatthew Ahrens		self.local = dict()
58*14843421SMatthew Ahrens		self.descend = dict()
59*14843421SMatthew Ahrens		self.ld = dict()
60*14843421SMatthew Ahrens
61*14843421SMatthew Ahrens		# see the comment in dsl_deleg.c for the definition of whokey
62*14843421SMatthew Ahrens		for whokey in raw.keys():
63*14843421SMatthew Ahrens			perms = raw[whokey].keys()
64*14843421SMatthew Ahrens			whotypechr = whokey[0].lower()
65*14843421SMatthew Ahrens			ws = whokey[3:]
66*14843421SMatthew Ahrens			if whotypechr == "c":
67*14843421SMatthew Ahrens				self.create.update(perms)
68*14843421SMatthew Ahrens			elif whotypechr == "s":
69*14843421SMatthew Ahrens				nwho = "1" + ws
70*14843421SMatthew Ahrens				self.sets.setdefault(nwho, set()).update(perms)
71*14843421SMatthew Ahrens			else:
72*14843421SMatthew Ahrens				if whotypechr == "u":
73*14843421SMatthew Ahrens					try:
74*14843421SMatthew Ahrens						name = pwd.getpwuid(int(ws)).pw_name
75*14843421SMatthew Ahrens					except KeyError:
76*14843421SMatthew Ahrens						name = ws
77*14843421SMatthew Ahrens					nwho = "1user " + name
78*14843421SMatthew Ahrens				elif whotypechr == "g":
79*14843421SMatthew Ahrens					try:
80*14843421SMatthew Ahrens						name = grp.getgrgid(int(ws)).gr_name
81*14843421SMatthew Ahrens					except KeyError:
82*14843421SMatthew Ahrens						name = ws
83*14843421SMatthew Ahrens					nwho = "2group " + name
84*14843421SMatthew Ahrens				elif whotypechr == "e":
85*14843421SMatthew Ahrens					nwho = "3everyone"
86*14843421SMatthew Ahrens				else:
87*14843421SMatthew Ahrens					raise ValueError(whotypechr)
88*14843421SMatthew Ahrens
89*14843421SMatthew Ahrens				if whokey[1] == "l":
90*14843421SMatthew Ahrens					d = self.local
91*14843421SMatthew Ahrens				elif whokey[1] == "d":
92*14843421SMatthew Ahrens					d = self.descend
93*14843421SMatthew Ahrens				else:
94*14843421SMatthew Ahrens					raise ValueError(whokey[1])
95*14843421SMatthew Ahrens
96*14843421SMatthew Ahrens				d.setdefault(nwho, set()).update(perms)
97*14843421SMatthew Ahrens
98*14843421SMatthew Ahrens		# Find perms that are in both local and descend, and
99*14843421SMatthew Ahrens		# move them to ld.
100*14843421SMatthew Ahrens		for nwho in self.local:
101*14843421SMatthew Ahrens			if nwho not in self.descend:
102*14843421SMatthew Ahrens				continue
103*14843421SMatthew Ahrens			# note: these are set operations
104*14843421SMatthew Ahrens			self.ld[nwho] = self.local[nwho] & self.descend[nwho]
105*14843421SMatthew Ahrens			self.local[nwho] -= self.ld[nwho]
106*14843421SMatthew Ahrens			self.descend[nwho] -= self.ld[nwho]
107*14843421SMatthew Ahrens
108*14843421SMatthew Ahrens	@staticmethod
109*14843421SMatthew Ahrens	def __ldstr(d, header):
110*14843421SMatthew Ahrens		s = ""
111*14843421SMatthew Ahrens		for (nwho, perms) in sorted(d.items()):
112*14843421SMatthew Ahrens			# local and descend may have entries where perms
113*14843421SMatthew Ahrens			# is an empty set, due to consolidating all
114*14843421SMatthew Ahrens			# permissions into ld
115*14843421SMatthew Ahrens			if perms:
116*14843421SMatthew Ahrens				s += "\t%s %s\n" % \
117*14843421SMatthew Ahrens				    (nwho[1:], ",".join(sorted(perms)))
118*14843421SMatthew Ahrens		if s:
119*14843421SMatthew Ahrens			s = header + s
120*14843421SMatthew Ahrens		return s
121*14843421SMatthew Ahrens
122*14843421SMatthew Ahrens	def __str__(self):
123*14843421SMatthew Ahrens		s = self.__ldstr(self.sets, _("Permission sets:\n"))
124*14843421SMatthew Ahrens
125*14843421SMatthew Ahrens		if self.create:
126*14843421SMatthew Ahrens			s += _("Create time permissions:\n")
127*14843421SMatthew Ahrens			s += "\t%s\n" % ",".join(sorted(self.create))
128*14843421SMatthew Ahrens
129*14843421SMatthew Ahrens		s += self.__ldstr(self.local, _("Local permissions:\n"))
130*14843421SMatthew Ahrens		s += self.__ldstr(self.descend, _("Descendent permissions:\n"))
131*14843421SMatthew Ahrens		s += self.__ldstr(self.ld, _("Local+Descendent permissions:\n"))
132*14843421SMatthew Ahrens		return s.rstrip()
133*14843421SMatthew Ahrens
134*14843421SMatthew Ahrensdef args_to_perms(parser, options, who, perms):
135*14843421SMatthew Ahrens	"""Return a dict of raw perms {"whostr" -> {"perm" -> None}}
136*14843421SMatthew Ahrens	based on the command-line input."""
137*14843421SMatthew Ahrens
138*14843421SMatthew Ahrens	# perms is not set if we are doing a "zfs unallow <who> <fs>" to
139*14843421SMatthew Ahrens	# remove all of someone's permissions
140*14843421SMatthew Ahrens	if perms:
141*14843421SMatthew Ahrens		setperms = dict(((p, None) for p in perms if p[0] == "@"))
142*14843421SMatthew Ahrens		baseperms = dict(((canonicalized_perm(p), None)
143*14843421SMatthew Ahrens		    for p in perms if p[0] != "@"))
144*14843421SMatthew Ahrens	else:
145*14843421SMatthew Ahrens		setperms = None
146*14843421SMatthew Ahrens		baseperms = None
147*14843421SMatthew Ahrens
148*14843421SMatthew Ahrens	d = dict()
149*14843421SMatthew Ahrens
150*14843421SMatthew Ahrens	def storeperm(typechr, inheritchr, arg):
151*14843421SMatthew Ahrens		assert typechr in "ugecs"
152*14843421SMatthew Ahrens		assert inheritchr in "ld-"
153*14843421SMatthew Ahrens
154*14843421SMatthew Ahrens		def mkwhokey(t):
155*14843421SMatthew Ahrens			return "%c%c$%s" % (t, inheritchr, arg)
156*14843421SMatthew Ahrens
157*14843421SMatthew Ahrens		if baseperms or not perms:
158*14843421SMatthew Ahrens			d[mkwhokey(typechr)] = baseperms
159*14843421SMatthew Ahrens		if setperms or not perms:
160*14843421SMatthew Ahrens			d[mkwhokey(typechr.upper())] = setperms
161*14843421SMatthew Ahrens
162*14843421SMatthew Ahrens	def decodeid(w, toidfunc, fmt):
163*14843421SMatthew Ahrens		try:
164*14843421SMatthew Ahrens			return int(w)
165*14843421SMatthew Ahrens		except ValueError:
166*14843421SMatthew Ahrens			try:
167*14843421SMatthew Ahrens				return toidfunc(w)[2]
168*14843421SMatthew Ahrens			except KeyError:
169*14843421SMatthew Ahrens				parser.error(fmt % w)
170*14843421SMatthew Ahrens
171*14843421SMatthew Ahrens	if options.set:
172*14843421SMatthew Ahrens		storeperm("s", "-", who)
173*14843421SMatthew Ahrens	elif options.create:
174*14843421SMatthew Ahrens		storeperm("c", "-", "")
175*14843421SMatthew Ahrens	else:
176*14843421SMatthew Ahrens		for w in who:
177*14843421SMatthew Ahrens			if options.user:
178*14843421SMatthew Ahrens				id = decodeid(w, pwd.getpwnam,
179*14843421SMatthew Ahrens				    _("invalid user %s"))
180*14843421SMatthew Ahrens				typechr = "u"
181*14843421SMatthew Ahrens			elif options.group:
182*14843421SMatthew Ahrens				id = decodeid(w, grp.getgrnam,
183*14843421SMatthew Ahrens				    _("invalid group %s"))
184*14843421SMatthew Ahrens				typechr = "g"
185*14843421SMatthew Ahrens			elif w == "everyone":
186*14843421SMatthew Ahrens				id = ""
187*14843421SMatthew Ahrens				typechr = "e"
188*14843421SMatthew Ahrens			else:
189*14843421SMatthew Ahrens				try:
190*14843421SMatthew Ahrens					id = pwd.getpwnam(w)[2]
191*14843421SMatthew Ahrens					typechr = "u"
192*14843421SMatthew Ahrens				except KeyError:
193*14843421SMatthew Ahrens					try:
194*14843421SMatthew Ahrens						id = grp.getgrnam(w)[2]
195*14843421SMatthew Ahrens						typechr = "g"
196*14843421SMatthew Ahrens					except KeyError:
197*14843421SMatthew Ahrens						parser.error(_("invalid user/group %s") % w)
198*14843421SMatthew Ahrens			if options.local:
199*14843421SMatthew Ahrens				storeperm(typechr, "l", id)
200*14843421SMatthew Ahrens			if options.descend:
201*14843421SMatthew Ahrens				storeperm(typechr, "d", id)
202*14843421SMatthew Ahrens	return d
203*14843421SMatthew Ahrens
204*14843421SMatthew Ahrensperms_subcmd = dict(
205*14843421SMatthew Ahrens    create=_("Must also have the 'mount' ability"),
206*14843421SMatthew Ahrens    destroy=_("Must also have the 'mount' ability"),
207*14843421SMatthew Ahrens    snapshot=_("Must also have the 'mount' ability"),
208*14843421SMatthew Ahrens    rollback=_("Must also have the 'mount' ability"),
209*14843421SMatthew Ahrens    clone=_("""Must also have the 'create' ability and 'mount'
210*14843421SMatthew Ahrens\t\t\t\tability in the origin file system"""),
211*14843421SMatthew Ahrens    promote=_("""Must also have the 'mount'
212*14843421SMatthew Ahrens\t\t\t\tand 'promote' ability in the origin file system"""),
213*14843421SMatthew Ahrens    rename=_("""Must also have the 'mount' and 'create'
214*14843421SMatthew Ahrens\t\t\t\tability in the new parent"""),
215*14843421SMatthew Ahrens    receive=_("Must also have the 'mount' and 'create' ability"),
216*14843421SMatthew Ahrens    allow=_("Must also have the permission that is being\n\t\t\t\tallowed"),
217*14843421SMatthew Ahrens    mount=_("Allows mount/umount of ZFS datasets"),
218*14843421SMatthew Ahrens    share=_("Allows sharing file systems over NFS or SMB\n\t\t\t\tprotocols"),
219*14843421SMatthew Ahrens    send="",
220*14843421SMatthew Ahrens)
221*14843421SMatthew Ahrens
222*14843421SMatthew Ahrensperms_other = dict(
223*14843421SMatthew Ahrens    userprop=_("Allows changing any user property"),
224*14843421SMatthew Ahrens    userquota=_("Allows accessing any userquota@... property"),
225*14843421SMatthew Ahrens    groupquota=_("Allows accessing any groupquota@... property"),
226*14843421SMatthew Ahrens    userused=_("Allows reading any userused@... property"),
227*14843421SMatthew Ahrens    groupused=_("Allows reading any groupused@... property"),
228*14843421SMatthew Ahrens)
229*14843421SMatthew Ahrens
230*14843421SMatthew Ahrensdef hasset(ds, setname):
231*14843421SMatthew Ahrens	"""Return True if the given setname (string) is defined for this
232*14843421SMatthew Ahrens	ds (Dataset)."""
233*14843421SMatthew Ahrens	# It would be nice to cache the result of get_fsacl().
234*14843421SMatthew Ahrens	for raw in ds.get_fsacl().values():
235*14843421SMatthew Ahrens		for whokey in raw.keys():
236*14843421SMatthew Ahrens			if whokey[0].lower() == "s" and whokey[3:] == setname:
237*14843421SMatthew Ahrens				return True
238*14843421SMatthew Ahrens	return False
239*14843421SMatthew Ahrens
240*14843421SMatthew Ahrensdef canonicalized_perm(permname):
241*14843421SMatthew Ahrens	"""Return the canonical name (string) for this permission (string).
242*14843421SMatthew Ahrens	Raises ZFSError if it is not a valid permission."""
243*14843421SMatthew Ahrens	if permname in perms_subcmd.keys() or permname in perms_other.keys():
244*14843421SMatthew Ahrens		return permname
245*14843421SMatthew Ahrens	try:
246*14843421SMatthew Ahrens		return zfs.dataset.getpropobj(permname).name
247*14843421SMatthew Ahrens	except KeyError:
248*14843421SMatthew Ahrens		raise zfs.util.ZFSError(errno.EINVAL, permname,
249*14843421SMatthew Ahrens		    _("invalid permission"))
250*14843421SMatthew Ahrens
251*14843421SMatthew Ahrensdef print_perms():
252*14843421SMatthew Ahrens	"""Print the set of supported permissions."""
253*14843421SMatthew Ahrens	print(_("\nThe following permissions are supported:\n"))
254*14843421SMatthew Ahrens	fmt = "%-16s %-14s\t%s"
255*14843421SMatthew Ahrens	print(fmt % (_("NAME"), _("TYPE"), _("NOTES")))
256*14843421SMatthew Ahrens
257*14843421SMatthew Ahrens	for (name, note) in sorted(perms_subcmd.iteritems()):
258*14843421SMatthew Ahrens		print(fmt % (name, _("subcommand"), note))
259*14843421SMatthew Ahrens
260*14843421SMatthew Ahrens	for (name, note) in sorted(perms_other.iteritems()):
261*14843421SMatthew Ahrens		print(fmt % (name, _("other"), note))
262*14843421SMatthew Ahrens
263*14843421SMatthew Ahrens	for (name, prop) in sorted(zfs.dataset.proptable.iteritems()):
264*14843421SMatthew Ahrens		if prop.visible and prop.delegatable():
265*14843421SMatthew Ahrens			print(fmt % (name, _("property"), ""))
266*14843421SMatthew Ahrens
267*14843421SMatthew Ahrensdef do_allow():
268*14843421SMatthew Ahrens	"""Implementes the "zfs allow" and "zfs unallow" subcommands."""
269*14843421SMatthew Ahrens	un = (sys.argv[1] == "unallow")
270*14843421SMatthew Ahrens
271*14843421SMatthew Ahrens	def usage(msg=None):
272*14843421SMatthew Ahrens		parser.print_help()
273*14843421SMatthew Ahrens		print_perms()
274*14843421SMatthew Ahrens		if msg:
275*14843421SMatthew Ahrens			print
276*14843421SMatthew Ahrens			parser.exit("zfs: error: " + msg)
277*14843421SMatthew Ahrens		else:
278*14843421SMatthew Ahrens			parser.exit()
279*14843421SMatthew Ahrens
280*14843421SMatthew Ahrens	if un:
281*14843421SMatthew Ahrens		u = _("""unallow [-rldug] <"everyone"|user|group>[,...]
282*14843421SMatthew Ahrens	    [<perm|@setname>[,...]] <filesystem|volume>
283*14843421SMatthew Ahrens	unallow [-rld] -e [<perm|@setname>[,...]] <filesystem|volume>
284*14843421SMatthew Ahrens	unallow [-r] -c [<perm|@setname>[,...]] <filesystem|volume>
285*14843421SMatthew Ahrens	unallow [-r] -s @setname [<perm|@setname>[,...]] <filesystem|volume>""")
286*14843421SMatthew Ahrens		verb = _("remove")
287*14843421SMatthew Ahrens		sstr = _("undefine permission set")
288*14843421SMatthew Ahrens	else:
289*14843421SMatthew Ahrens		u = _("""allow <filesystem|volume>
290*14843421SMatthew Ahrens	allow [-ldug] <"everyone"|user|group>[,...] <perm|@setname>[,...]
291*14843421SMatthew Ahrens	    <filesystem|volume>
292*14843421SMatthew Ahrens	allow [-ld] -e <perm|@setname>[,...] <filesystem|volume>
293*14843421SMatthew Ahrens	allow -c <perm|@setname>[,...] <filesystem|volume>
294*14843421SMatthew Ahrens	allow -s @setname <perm|@setname>[,...] <filesystem|volume>""")
295*14843421SMatthew Ahrens		verb = _("set")
296*14843421SMatthew Ahrens		sstr = _("define permission set")
297*14843421SMatthew Ahrens
298*14843421SMatthew Ahrens	parser = optparse.OptionParser(usage=u, prog="zfs")
299*14843421SMatthew Ahrens
300*14843421SMatthew Ahrens	parser.add_option("-l", action="store_true", dest="local",
301*14843421SMatthew Ahrens	    help=_("%s permission locally") % verb)
302*14843421SMatthew Ahrens	parser.add_option("-d", action="store_true", dest="descend",
303*14843421SMatthew Ahrens	    help=_("%s permission for descendents") % verb)
304*14843421SMatthew Ahrens	parser.add_option("-u", action="store_true", dest="user",
305*14843421SMatthew Ahrens	    help=_("%s permission for user") % verb)
306*14843421SMatthew Ahrens	parser.add_option("-g", action="store_true", dest="group",
307*14843421SMatthew Ahrens	    help=_("%s permission for group") % verb)
308*14843421SMatthew Ahrens	parser.add_option("-e", action="store_true", dest="everyone",
309*14843421SMatthew Ahrens	    help=_("%s permission for everyone") % verb)
310*14843421SMatthew Ahrens	parser.add_option("-c", action="store_true", dest="create",
311*14843421SMatthew Ahrens	    help=_("%s create time permissions") % verb)
312*14843421SMatthew Ahrens	parser.add_option("-s", action="store_true", dest="set", help=sstr)
313*14843421SMatthew Ahrens	if un:
314*14843421SMatthew Ahrens		parser.add_option("-r", action="store_true", dest="recursive",
315*14843421SMatthew Ahrens		    help=_("remove permissions recursively"))
316*14843421SMatthew Ahrens
317*14843421SMatthew Ahrens	if len(sys.argv) == 3 and not un:
318*14843421SMatthew Ahrens		# just print the permissions on this fs
319*14843421SMatthew Ahrens
320*14843421SMatthew Ahrens		if sys.argv[2] == "-h":
321*14843421SMatthew Ahrens			# hack to make "zfs allow -h" work
322*14843421SMatthew Ahrens			usage()
323*14843421SMatthew Ahrens		ds = zfs.dataset.Dataset(sys.argv[2])
324*14843421SMatthew Ahrens
325*14843421SMatthew Ahrens		p = dict()
326*14843421SMatthew Ahrens		for (fs, raw) in ds.get_fsacl().items():
327*14843421SMatthew Ahrens			p[fs] = FSPerms(raw)
328*14843421SMatthew Ahrens
329*14843421SMatthew Ahrens		for fs in sorted(p.keys(), reverse=True):
330*14843421SMatthew Ahrens			s = _("---- Permissions on %s ") % fs
331*14843421SMatthew Ahrens			print(s + "-" * (70-len(s)))
332*14843421SMatthew Ahrens			print(p[fs])
333*14843421SMatthew Ahrens		return
334*14843421SMatthew Ahrens
335*14843421SMatthew Ahrens
336*14843421SMatthew Ahrens	(options, args) = parser.parse_args(sys.argv[2:])
337*14843421SMatthew Ahrens
338*14843421SMatthew Ahrens	if sum((bool(options.everyone), bool(options.user),
339*14843421SMatthew Ahrens	    bool(options.group))) > 1:
340*14843421SMatthew Ahrens		parser.error(_("-u, -g, and -e are mutually exclusive"))
341*14843421SMatthew Ahrens
342*14843421SMatthew Ahrens	def mungeargs(expected_len):
343*14843421SMatthew Ahrens		if un and len(args) == expected_len-1:
344*14843421SMatthew Ahrens			return (None, args[expected_len-2])
345*14843421SMatthew Ahrens		elif len(args) == expected_len:
346*14843421SMatthew Ahrens			return (args[expected_len-2].split(","),
347*14843421SMatthew Ahrens			    args[expected_len-1])
348*14843421SMatthew Ahrens		else:
349*14843421SMatthew Ahrens			usage(_("wrong number of parameters"))
350*14843421SMatthew Ahrens
351*14843421SMatthew Ahrens	if options.set:
352*14843421SMatthew Ahrens		if options.local or options.descend or options.user or \
353*14843421SMatthew Ahrens		    options.group or options.everyone or options.create:
354*14843421SMatthew Ahrens			parser.error(_("invalid option combined with -s"))
355*14843421SMatthew Ahrens		if args[0][0] != "@":
356*14843421SMatthew Ahrens			parser.error(_("invalid set name: missing '@' prefix"))
357*14843421SMatthew Ahrens
358*14843421SMatthew Ahrens		(perms, fsname) = mungeargs(3)
359*14843421SMatthew Ahrens		who = args[0]
360*14843421SMatthew Ahrens	elif options.create:
361*14843421SMatthew Ahrens		if options.local or options.descend or options.user or \
362*14843421SMatthew Ahrens		    options.group or options.everyone or options.set:
363*14843421SMatthew Ahrens			parser.error(_("invalid option combined with -c"))
364*14843421SMatthew Ahrens
365*14843421SMatthew Ahrens		(perms, fsname) = mungeargs(2)
366*14843421SMatthew Ahrens		who = None
367*14843421SMatthew Ahrens	elif options.everyone:
368*14843421SMatthew Ahrens		if options.user or options.group or \
369*14843421SMatthew Ahrens		    options.create or options.set:
370*14843421SMatthew Ahrens			parser.error(_("invalid option combined with -e"))
371*14843421SMatthew Ahrens
372*14843421SMatthew Ahrens		(perms, fsname) = mungeargs(2)
373*14843421SMatthew Ahrens		who = ["everyone"]
374*14843421SMatthew Ahrens	else:
375*14843421SMatthew Ahrens		(perms, fsname) = mungeargs(3)
376*14843421SMatthew Ahrens		who = args[0].split(",")
377*14843421SMatthew Ahrens
378*14843421SMatthew Ahrens	if not options.local and not options.descend:
379*14843421SMatthew Ahrens		options.local = True
380*14843421SMatthew Ahrens		options.descend = True
381*14843421SMatthew Ahrens
382*14843421SMatthew Ahrens	d = args_to_perms(parser, options, who, perms)
383*14843421SMatthew Ahrens
384*14843421SMatthew Ahrens	ds = zfs.dataset.Dataset(fsname, snaps=False)
385*14843421SMatthew Ahrens
386*14843421SMatthew Ahrens	if not un and perms:
387*14843421SMatthew Ahrens		for p in perms:
388*14843421SMatthew Ahrens			if p[0] == "@" and not hasset(ds, p):
389*14843421SMatthew Ahrens				parser.error(_("set %s is not defined") % p)
390*14843421SMatthew Ahrens
391*14843421SMatthew Ahrens	ds.set_fsacl(un, d)
392*14843421SMatthew Ahrens	if un and options.recursive:
393*14843421SMatthew Ahrens		for child in ds.descendents():
394*14843421SMatthew Ahrens			child.set_fsacl(un, d)
395