summaryrefslogtreecommitdiff
path: root/common/attr
blob: 3ebba682c894f6f85f12189f675c61c5ec24e45f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
##/bin/bash
# SPDX-License-Identifier: GPL-2.0+
# Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
#
# common extended attribute and ACL support

# filesystems that want to test maximum supported acl counts need to
# add support in here
_acl_get_max()
{
	case $FSTYP in
	xfs)
		# CRC format filesystems have much larger ACL counts. The actual
		# number is into the thousands, but testing that meany takes too
		# long, so just test well past the old limit of 25.
		$XFS_INFO_PROG $TEST_DIR | _filter_mkfs > /dev/null 2> $tmp.info
		. $tmp.info
		rm $tmp.info
		if [ $_fs_has_crcs -eq 0 ]; then
			echo 25
		else
			echo 5461
		fi
		;;
	jfs)
		echo 8191
		;;
	f2fs)
		# If noinline_xattr is enabled, max xattr size should be:
		# (4096 - 24) - (24 + 4) = 4044
		# then ACL_MAX_ENTRIES should be:
		# (4044 - (4 + 4 * 4)) / 8 + 4 = 507
		_fs_options $TEST_DEV | grep "noinline_xattr" >/dev/null 2>&1
		if [ $? -eq 0 ]; then
			echo 507
		else
			# If inline_xattr is enabled, max xattr size should be:
			# (4096 - 24 + 200) - (24 + 4) = 4244
			# then ACL_MAX_ENTRIES should be:
			# (4244 - (4 + 4 * 4)) / 8 + 4 = 532
			_fs_options $TEST_DEV | grep "inline_xattr" >/dev/null 2>&1
			if [ $? -eq 0 ]; then
				echo 532
			else
				echo 507
			fi
		fi
		;;
	bcachefs)
		echo 251
		;;
	*)
		echo 0
		;;
	esac
}

_require_acl_get_max()
{
	if [ $(_acl_get_max) -eq 0 ]; then
		_notrun "$FSTYP does not define maximum ACL count"
	fi
}

# pick three unused user/group ids, store them as $acl[1-3]
#
_acl_setup_ids()
{
    eval `(_cat_passwd; _cat_group) | awk -F: '
      { ids[$3]=1 }
      END {
        j=1
        for(i=1; i<1000000 && j<=3;i++){
          if (! (i in ids)) {
	     printf "acl%d=%d;", j, i;
	     j++
          }
        }
      }'`
}

# filter for the acl ids selected above
#
_acl_filter_id()
{
    sed \
       -e "s/u:$acl1/u:id1/" \
       -e "s/u:$acl2/u:id2/" \
       -e "s/u:$acl3/u:id3/" \
       -e "s/g:$acl1/g:id1/" \
       -e "s/g:$acl2/g:id2/" \
       -e "s/g:$acl3/g:id3/" \
       -e "s/ $acl1 / id1 /" \
       -e "s/ $acl2 / id2 /" \
       -e "s/ $acl3 / id3 /"
}

_getfacl_filter_id()
{
    sed \
       -e "s/user:$acl1/user:id1/" \
       -e "s/user:$acl2/user:id2/" \
       -e "s/user:$acl3/user:id3/" \
       -e "s/group:$acl1/group:id1/" \
       -e "s/group:$acl2/group:id2/" \
       -e "s/group:$acl3/group:id3/" \
       -e "s/: $acl1/: id1/" \
       -e "s/: $acl2/: id2/" \
       -e "s/: $acl3/: id3/"
}

# filtered ls
#
_acl_ls()
{
    _ls_l -n $* | awk '{ print $1, $3, $4, $NF }' | _acl_filter_id
}

# create an ACL with n ACEs in it
#
_create_n_aces()
{
    let n=$1-4
    acl='u::rwx,g::rwx,o::rwx,m::rwx' # 4 ace acl start
    while [ $n -ne 0 ]; do
	acl="$acl,u:$n:rwx"
	let n=$n-1
    done
    echo $acl
}

# filter user ace names to user ids
#
_filter_aces()
{
    tmp_file=`mktemp /tmp/ace.XXXXXX`

    (_cat_passwd; _cat_group) > $tmp_file

    $AWK_PROG -v tmpfile=$tmp_file '
	BEGIN {
	    FS=":"
	    while ( getline <tmpfile > 0 ) {
		idlist[$1] = $3
	    }
	}
	/^user/ { if ($2 in idlist) sub($2, idlist[$2]); print; next}
	/^u/ { if ($2 in idlist) sub($2, idlist[$2]); print; next}
	/^default:user/ { if ($3 in idlist) sub($3, idlist[$3]); print; next}
	{print}
    '
    rm -f $tmp_file
}

_filter_aces_notypes()
{
    tr '\[' '\012' | tr ']' '\012' | tr ',' '\012' | _filter_aces|\
    sed -e 's/u:/user:/' -e 's/g:/group:/' -e 's/o:/other:/' -e 's/m:/mask:/'
}

_require_acls()
{
    [ -n "$CHACL_PROG" ] || _notrun "chacl command not found"

    #
    # Test if chacl is able to set an ACL on a file.  On really old kernels
    # the system calls might not be implemented at all, but the more common
    # case is that the tested filesystem simply doesn't support ACLs.
    #
    touch $TEST_DIR/syscalltest
    chacl 'u::rw-,g::---,o::---' $TEST_DIR/syscalltest > $TEST_DIR/syscalltest.out 2>&1
    cat $TEST_DIR/syscalltest.out >> $seqres.full

    if grep -q 'Function not implemented' $TEST_DIR/syscalltest.out; then
      _notrun "kernel does not support ACLs"
    fi
    if grep -q 'Operation not supported' $TEST_DIR/syscalltest.out; then
      _notrun "ACLs not supported by this filesystem type: $FSTYP"
    fi

    rm -f $TEST_DIR/syscalltest.out
}

_list_acl()
{
    file=$1

    ls -dD $file | _acl_filter_id
}

_require_attrs()
{
	local args
	local nsp

	if [ $# -eq 0 ]; then
		args="user"
	else
	  	args="$*"
	fi

	[ -n "$ATTR_PROG" ] || _notrun "attr command not found"
	[ -n "$GETFATTR_PROG" ] || _notrun "getfattr command not found"
	[ -n "$SETFATTR_PROG" ] || _notrun "setfattr command not found"

	for nsp in $args; do
		#
		# Test if chacl is able to write an attribute on the target
		# filesystems.  On really old kernels the system calls might
		# not be implemented at all, but the more common case is that
		# the tested filesystem simply doesn't support attributes.
		# Note that we can't simply list attributes as various security
		# modules generate synthetic attributes not actually stored on
		# disk.
		#
		touch $TEST_DIR/syscalltest
		$SETFATTR_PROG -n "$nsp.xfstests" -v "attr" $TEST_DIR/syscalltest > $TEST_DIR/syscalltest.out 2>&1
		cat $TEST_DIR/syscalltest.out >> $seqres.full

		if grep -q 'Function not implemented' $TEST_DIR/syscalltest.out; then
			_notrun "kernel does not support attrs"
		fi
		if grep -q 'Operation not supported' $TEST_DIR/syscalltest.out; then
			_notrun "attr namespace $nsp not supported by this filesystem type: $FSTYP"
		fi

		rm -f $TEST_DIR/syscalltest.out
	done
}

_require_attr_v1()
{
	_scratch_mkfs_xfs_supported -i attr=1 >/dev/null 2>&1 \
		|| _notrun "attr v1 not supported on $SCRATCH_DEV"
}

# check if we support the noattr2 mount option
_require_noattr2()
{
	_scratch_mkfs_xfs > /dev/null 2>&1 \
		|| _fail "_scratch_mkfs_xfs failed on $SCRATCH_DEV"
	_try_scratch_mount -o noattr2 > /dev/null 2>&1 \
		|| _notrun "noattr2 mount option not supported on $SCRATCH_DEV"
	_scratch_unmount
}

# getfattr -R returns info in readdir order which varies from fs to fs.
# This sorts the output by filename
_sort_getfattr_output()
{
    awk '{a[FNR]=$0}END{n = asort(a); for(i=1; i <= n; i++) print a[i]"\n"}' RS=''
}

# Previously, when getfattr dumps values of all extended attributes, it prints
# empty attr as 'user.name', but new getfattr (since attr-2.4.48) prints it as
# 'user.name=""'. Filter out the ending '=""' so that both old and new getfattr
# pints the same output.
#
# Note: This function returns the getfattr command result.
_getfattr()
{
	$GETFATTR_PROG "$@" | sed -e 's/=\"\"//'
	return ${PIPESTATUS[0]}
}

# make sure this script returns success
/bin/true