[SCM] Samba Shared Repository - branch v4-18-stable updated
Jule Anger
janger at samba.org
Wed Mar 1 12:46:51 UTC 2023
The branch, v4-18-stable has been updated
via 746b83bbd89 VERSION: Disable GIT_SNAPSHOT for the 4.18.0rc4 release.
via 5be2d9c542e WHATSNEW: Add release notes for Samba 4.18.0rc4.
via 24a1a469a91 WHATSNEW: add server addresses option
via bca78e31c69 WHATSNEW: SMB Server performance improvements
via b8299405352 lib:util: File descriptor being closed repeatedly.
via 6191dbda193 python:tests: Make sure we delete the OU for movetest
via b925ac8094f python:tests: Add missing result checks for samba_tool.gpo tests
via b7b61025b65 python:tests: Tell dns.resolver to not read /etc/resolv.conf
via 8739c9c72dd python:tests: Fix domain_backup test with Python 3.11
via 9e8cc236bd3 python:tests: Make sure we do not run into issues with already existing users
via bebf313dcb0 python:tests: Use a random machine name for computer_edit.sh test
via 5ce320a06e0 python:tests: Correctly escape $ in computer_edit.sh
via 889839858fe python:tests: Use a random username for contact_edit.sh test
via 074e0c2783a python:tests: Correctly escape $ in contact_edit.sh
via 359095e8ddd python:tests: Use a random username for user_edit.sh tests
via d45706e2653 python:tests: Correctly escape $ in user_edit.sh
via 820970ab5ec testprogs: Use random user names for kpasswd tests
via f15a1413571 testprogs: Use random usernames for export keytab tests
via 67639f6d9ad testprogs: Use random usernames for kinit tests
via b2d0a834149 VERSION: Bump version up to Samba 4.18.0rc4...
from 4c48a250c04 VERSION: Disable GIT_SNAPSHOT for the 4.18.0rc3 release.
https://git.samba.org/?p=samba.git;a=shortlog;h=v4-18-stable
- Log -----------------------------------------------------------------
-----------------------------------------------------------------------
Summary of changes:
VERSION | 2 +-
WHATSNEW.txt | 27 +++++++++++++-
lib/util/util_file.c | 9 ++++-
python/samba/tests/blackbox/netads_dns.py | 4 ++-
python/samba/tests/domain_backup.py | 5 ++-
python/samba/tests/samba_tool/computer_edit.sh | 30 ++++++++--------
python/samba/tests/samba_tool/contact_edit.sh | 28 ++++++++-------
python/samba/tests/samba_tool/gpo.py | 15 ++++++++
python/samba/tests/samba_tool/group.py | 8 ++---
python/samba/tests/samba_tool/user.py | 21 ++++++++---
python/samba/tests/samba_tool/user_edit.sh | 30 ++++++++--------
testprogs/blackbox/test_export_keytab_heimdal.sh | 17 ++++-----
testprogs/blackbox/test_export_keytab_mit.sh | 4 +--
testprogs/blackbox/test_kinit_heimdal.sh | 46 ++++++++++++------------
testprogs/blackbox/test_kinit_mit.sh | 38 ++++++++++----------
testprogs/blackbox/test_kpasswd_mit.sh | 2 +-
16 files changed, 179 insertions(+), 107 deletions(-)
Changeset truncated at 500 lines:
diff --git a/VERSION b/VERSION
index 82827931d07..f08d67023df 100644
--- a/VERSION
+++ b/VERSION
@@ -87,7 +87,7 @@ SAMBA_VERSION_PRE_RELEASE=
# e.g. SAMBA_VERSION_RC_RELEASE=1 #
# -> "3.0.0rc1" #
########################################################
-SAMBA_VERSION_RC_RELEASE=3
+SAMBA_VERSION_RC_RELEASE=4
########################################################
# To mark SVN snapshots this should be set to 'yes' #
diff --git a/WHATSNEW.txt b/WHATSNEW.txt
index a035daeef79..cb386f28fde 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -1,7 +1,7 @@
Release Announcements
=====================
-This is the third release candidate of Samba 4.18. This is *not*
+This is the fourth release candidate of Samba 4.18. This is *not*
intended for production environments and is designed for testing
purposes only. Please report any defects via the Samba bug reporting
system at https://bugzilla.samba.org/.
@@ -16,6 +16,19 @@ UPGRADING
NEW FEATURES/CHANGES
====================
+SMB Server performance improvements
+-----------------------------------
+
+The security improvements in recent releases
+(4.13, 4.14, 4.15, 4.16), mainly as protection against symlink races,
+caused performance regressions for metadata heavy workloads.
+
+While 4.17 already improved the situation quite a lot,
+with 4.18 the locking overhead for contended path based operations
+is reduced by an additional factor of ~ 3 compared to 4.17.
+It means the throughput of open/close
+operations reached the level of 4.12 again.
+
More succinct samba-tool error messages
---------------------------------------
@@ -123,6 +136,18 @@ smb.conf changes
Parameter Name Description Default
-------------- ----------- -------
acl_xattr:security_acl_name New security.NTACL
+ server addresses New
+
+
+CHANGES SINCE 4.18.0rc3
+=======================
+
+o Andreas Schneider <asn at samba.org>
+ * BUG 15308: Avoid that tests fail because other tests didn't do cleanup on
+ failure.
+
+o baixiangcpp <baixiangcpp at gmail.com>
+ * BUG 15311: fd_load() function implicitly closes the fd where it should not.
CHANGES SINCE 4.18.0rc2
diff --git a/lib/util/util_file.c b/lib/util/util_file.c
index af90e4a7621..fa5abadedec 100644
--- a/lib/util/util_file.c
+++ b/lib/util/util_file.c
@@ -175,13 +175,20 @@ _PUBLIC_ char *fd_load(int fd, size_t *psize, size_t maxsize, TALLOC_CTX *mem_ct
size_t size = 0;
size_t chunk = 1024;
int err;
+ int fd_dup;
if (maxsize == 0) {
maxsize = SIZE_MAX;
}
- file = fdopen(fd, "r");
+ fd_dup = dup(fd);
+ if (fd_dup == -1) {
+ return NULL;
+ }
+
+ file = fdopen(fd_dup, "r");
if (file == NULL) {
+ close(fd_dup);
return NULL;
}
diff --git a/python/samba/tests/blackbox/netads_dns.py b/python/samba/tests/blackbox/netads_dns.py
index 0a491504537..e9f945eaef9 100644
--- a/python/samba/tests/blackbox/netads_dns.py
+++ b/python/samba/tests/blackbox/netads_dns.py
@@ -30,7 +30,9 @@ class NetAdsDnsTests(BlackboxTestCase):
def setUp(self):
super(NetAdsDnsTests, self).setUp()
nameserver = os.environ["DC_SERVER_IP"]
- self.resolver = dns.resolver.Resolver()
+ # filename=None will disable reading /etc/resolv.conf. The file might
+ # not exist e.g. on build or CI systems.
+ self.resolver = dns.resolver.Resolver(filename=None)
self.resolver.nameservers = [nameserver]
def parse_output(self, output):
diff --git a/python/samba/tests/domain_backup.py b/python/samba/tests/domain_backup.py
index b890a1030b7..2feef28bcb4 100644
--- a/python/samba/tests/domain_backup.py
+++ b/python/samba/tests/domain_backup.py
@@ -367,7 +367,10 @@ class DomainBackupBase(BlackboxTestCase):
def cleanup_tempdir(self):
for filename in os.listdir(self.tempdir):
filepath = os.path.join(self.tempdir, filename)
- shutil.rmtree(filepath)
+ if os.path.isfile(filepath):
+ os.remove(filepath)
+ elif os.path.isdir(filepath):
+ shutil.rmtree(filepath)
def run_cmd(self, args):
"""Executes a samba-tool backup/restore command"""
diff --git a/python/samba/tests/samba_tool/computer_edit.sh b/python/samba/tests/samba_tool/computer_edit.sh
index 500a00d9a34..da32760de35 100755
--- a/python/samba/tests/samba_tool/computer_edit.sh
+++ b/python/samba/tests/samba_tool/computer_edit.sh
@@ -29,10 +29,12 @@ display_name_con_b64="dGVzdCAHIHN0cmluZwo="
tmpeditor=$(mktemp --suffix .sh -p $SELFTEST_TMPDIR samba-tool-editor-XXXXXXXX)
chmod +x $tmpeditor
+TEST_MACHINE="$(mktemp -u testmachineXXXXXX)"
+
create_test_computer()
{
$PYTHON ${STpath}/source4/scripting/bin/samba-tool \
- computer create testmachine1 \
+ computer create ${TEST_MACHINE} \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
@@ -48,7 +50,7 @@ $SED -i -e 's/userAccountControl: 4098/userAccountControl: 4096/' $computer_ldif
EOF
$PYTHON ${STpath}/source4/scripting/bin/samba-tool \
- computer edit testmachine1 --editor=$tmpeditor \
+ computer edit ${TEST_MACHINE} --editor=$tmpeditor \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
@@ -60,20 +62,20 @@ add_attribute_base64()
#!/usr/bin/env bash
computer_ldif="\$1"
-grep -v '^$' \$computer_ldif > \${computer_ldif}.tmp
+grep -v '^\$' \$computer_ldif > \${computer_ldif}.tmp
echo "displayName:: $display_name_b64" >> \${computer_ldif}.tmp
mv \${computer_ldif}.tmp \$computer_ldif
EOF
$PYTHON ${STpath}/source4/scripting/bin/samba-tool computer edit \
- testmachine1 --editor=$tmpeditor \
+ ${TEST_MACHINE} --editor=$tmpeditor \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
get_attribute_base64()
{
- ${ldbsearch} '(sAMAccountName=testmachine1$)' displayName \
+ ${ldbsearch} "(sAMAccountName=${TEST_MACHINE}\$)" displayName \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
@@ -88,7 +90,7 @@ grep -v '^displayName' \$computer_ldif >> \${computer_ldif}.tmp
mv \${computer_ldif}.tmp \$computer_ldif
EOF
$PYTHON ${STpath}/source4/scripting/bin/samba-tool computer edit \
- testmachine1 --editor=$tmpeditor \
+ ${TEST_MACHINE} --editor=$tmpeditor \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
@@ -100,20 +102,20 @@ add_attribute_base64_control()
#!/usr/bin/env bash
computer_ldif="\$1"
-grep -v '^$' \$computer_ldif > \${computer_ldif}.tmp
+grep -v '^\$' \$computer_ldif > \${computer_ldif}.tmp
echo "displayName:: $display_name_con_b64" >> \${computer_ldif}.tmp
mv \${computer_ldif}.tmp \$computer_ldif
EOF
$PYTHON ${STpath}/source4/scripting/bin/samba-tool computer edit \
- testmachine1 --editor=$tmpeditor \
+ ${TEST_MACHINE} --editor=$tmpeditor \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
get_attribute_base64_control()
{
$PYTHON ${STpath}/source4/scripting/bin/samba-tool computer show \
- testmachine1 --attributes=displayName \
+ ${TEST_MACHINE} --attributes=displayName \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
@@ -121,7 +123,7 @@ get_attribute_force_no_base64()
{
# LDB_FLAG_FORCE_NO_BASE64_LDIF should be used here.
$PYTHON ${STpath}/source4/scripting/bin/samba-tool computer show \
- testmachine1 --attributes=displayName \
+ ${TEST_MACHINE} --attributes=displayName \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
@@ -137,7 +139,7 @@ sed -i -e 's/displayName:: $display_name_con_b64/displayName: $display_name/' \
\$computer_ldif
EOF
$PYTHON ${STpath}/source4/scripting/bin/samba-tool computer edit \
- testmachine1 --editor=$tmpeditor \
+ ${TEST_MACHINE} --editor=$tmpeditor \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
@@ -156,21 +158,21 @@ sed -i -e 's/displayName: $display_name/displayName: $display_name_new/' \
EOF
$PYTHON ${STpath}/source4/scripting/bin/samba-tool computer edit \
- testmachine1 --editor=$tmpeditor \
+ ${TEST_MACHINE} --editor=$tmpeditor \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
get_changed_attribute_force_no_base64()
{
$PYTHON ${STpath}/source4/scripting/bin/samba-tool computer show \
- testmachine1 --attributes=displayName \
+ ${TEST_MACHINE} --attributes=displayName \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
delete_computer()
{
$PYTHON ${STpath}/source4/scripting/bin/samba-tool \
- computer delete testmachine1 \
+ computer delete ${TEST_MACHINE} \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
diff --git a/python/samba/tests/samba_tool/contact_edit.sh b/python/samba/tests/samba_tool/contact_edit.sh
index 3c14ac8de26..d31413dbcd6 100755
--- a/python/samba/tests/samba_tool/contact_edit.sh
+++ b/python/samba/tests/samba_tool/contact_edit.sh
@@ -28,13 +28,15 @@ display_name_new="Renamed Bjoern"
# echo -e "test \a string" | base64
display_name_con_b64="dGVzdCAHIHN0cmluZwo="
+TEST_USER="$(mktemp -u testcontactXXXXXX)"
+
tmpeditor=$(mktemp --suffix .sh -p $SELFTEST_TMPDIR samba-tool-editor-XXXXXXXX)
chmod +x $tmpeditor
create_test_contact()
{
$PYTHON ${STpath}/source4/scripting/bin/samba-tool \
- contact create testcontact1 \
+ contact create ${TEST_USER} \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
@@ -46,20 +48,20 @@ add_attribute_base64()
#!/usr/bin/env bash
contact_ldif="\$1"
-grep -v '^$' \$contact_ldif > \${contact_ldif}.tmp
+grep -v '^\$' \$contact_ldif > \${contact_ldif}.tmp
echo "displayName:: $display_name_b64" >> \${contact_ldif}.tmp
mv \${contact_ldif}.tmp \$contact_ldif
EOF
$PYTHON ${STpath}/source4/scripting/bin/samba-tool contact edit \
- testcontact1 --editor=$tmpeditor \
+ ${TEST_USER} --editor=$tmpeditor \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
get_attribute_base64()
{
- $samba_ldbsearch '(&(objectClass=contact)(name=testcontact1))' \
+ $samba_ldbsearch "(&(objectClass=contact)(name=${TEST_USER}))" \
displayName \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
@@ -75,7 +77,7 @@ grep -v '^displayName' \$contact_ldif >> \${contact_ldif}.tmp
mv \${contact_ldif}.tmp \$contact_ldif
EOF
$PYTHON ${STpath}/source4/scripting/bin/samba-tool contact edit \
- testcontact1 --editor=$tmpeditor \
+ ${TEST_USER} --editor=$tmpeditor \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
@@ -87,20 +89,20 @@ add_attribute_base64_control()
#!/usr/bin/env bash
contact_ldif="\$1"
-grep -v '^$' \$contact_ldif > \${contact_ldif}.tmp
+grep -v '^\$' \$contact_ldif > \${contact_ldif}.tmp
echo "displayName:: $display_name_con_b64" >> \${contact_ldif}.tmp
mv \${contact_ldif}.tmp \$contact_ldif
EOF
$PYTHON ${STpath}/source4/scripting/bin/samba-tool contact edit \
- testcontact1 --editor=$tmpeditor \
+ ${TEST_USER} --editor=$tmpeditor \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
get_attribute_base64_control()
{
$PYTHON ${STpath}/source4/scripting/bin/samba-tool contact show \
- testcontact1 --attributes=displayName \
+ ${TEST_USER} --attributes=displayName \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
@@ -108,7 +110,7 @@ get_attribute_force_no_base64()
{
# LDB_FLAG_FORCE_NO_BASE64_LDIF should be used here.
$PYTHON ${STpath}/source4/scripting/bin/samba-tool contact show \
- testcontact1 --attributes=displayName \
+ ${TEST_USER} --attributes=displayName \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
@@ -124,7 +126,7 @@ sed -i -e 's/displayName:: $display_name_con_b64/displayName: $display_name/' \
\$contact_ldif
EOF
$PYTHON ${STpath}/source4/scripting/bin/samba-tool contact edit \
- testcontact1 --editor=$tmpeditor \
+ ${TEST_USER} --editor=$tmpeditor \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
@@ -143,21 +145,21 @@ sed -i -e 's/displayName: $display_name/displayName: $display_name_new/' \
EOF
$PYTHON ${STpath}/source4/scripting/bin/samba-tool contact edit \
- testcontact1 --editor=$tmpeditor \
+ ${TEST_USER} --editor=$tmpeditor \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
get_changed_attribute_force_no_base64()
{
$PYTHON ${STpath}/source4/scripting/bin/samba-tool contact show \
- testcontact1 --attributes=displayName \
+ ${TEST_USER} --attributes=displayName \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
delete_contact()
{
$PYTHON ${STpath}/source4/scripting/bin/samba-tool \
- contact delete testcontact1 \
+ contact delete ${TEST_USER} \
-H "ldap://$SERVER" "-U$USERNAME" "--password=$PASSWORD"
}
diff --git a/python/samba/tests/samba_tool/gpo.py b/python/samba/tests/samba_tool/gpo.py
index 78ed5d493af..723c8f055cd 100644
--- a/python/samba/tests/samba_tool/gpo.py
+++ b/python/samba/tests/samba_tool/gpo.py
@@ -183,6 +183,9 @@ class GpoCmdTestCase(SambaToolCmdTest):
os.environ["PASSWORD"]),
"--restore-metadata")
+ self.assertCmdSuccess(result, out, err,
+ "Ensure gpo restore successful")
+
gpo_guid = "{%s}" % out.split("{")[1].split("}")[0]
(result, out, err) = self.runsubcmd("gpo", "backup", gpo_guid,
@@ -237,6 +240,9 @@ class GpoCmdTestCase(SambaToolCmdTest):
os.environ["PASSWORD"]),
"--restore-metadata")
+ self.assertCmdSuccess(result, out, err,
+ "Ensure gpo restore successful")
+
gpo_guid = "{%s}" % out.split("{")[1].split("}")[0]
gpo_guid1 = gpo_guid
@@ -259,6 +265,9 @@ class GpoCmdTestCase(SambaToolCmdTest):
os.environ["PASSWORD"]),
"--restore-metadata")
+ self.assertCmdSuccess(result, out, err,
+ "Ensure gpo restore successful")
+
gpo_guid = "{%s}" % out.split("{")[1].split("}")[0]
gpo_guid2 = gpo_guid
@@ -322,6 +331,9 @@ class GpoCmdTestCase(SambaToolCmdTest):
os.environ["PASSWORD"]),
"--restore-metadata")
+ self.assertCmdSuccess(result, out, err,
+ "Ensure gpo restore successful")
+
gpo_guid = "{%s}" % out.split("{")[1].split("}")[0]
gpo_guid1 = gpo_guid
@@ -342,6 +354,9 @@ class GpoCmdTestCase(SambaToolCmdTest):
os.environ["PASSWORD"]),
"--restore-metadata")
+ self.assertCmdSuccess(result, out, err,
+ "Ensure gpo restore successful")
+
gpo_guid = "{%s}" % out.split("{")[1].split("}")[0]
gpo_guid2 = gpo_guid
diff --git a/python/samba/tests/samba_tool/group.py b/python/samba/tests/samba_tool/group.py
index 2542411d74a..3019b7596d2 100644
--- a/python/samba/tests/samba_tool/group.py
+++ b/python/samba/tests/samba_tool/group.py
@@ -336,7 +336,9 @@ class GroupCmdTestCase(SambaToolCmdTest):
def test_move(self):
- full_ou_dn = str(self.samdb.normalize_dn_in_domain("OU=movetest"))
+ full_ou_dn = str(self.samdb.normalize_dn_in_domain("OU=movetest_grp"))
+ self.addCleanup(self.samdb.delete, full_ou_dn, ["tree_delete:1"])
+
(result, out, err) = self.runsubcmd("ou", "add", full_ou_dn)
self.assertCmdSuccess(result, out, err)
self.assertEqual(err, "", "There shouldn't be any error message")
@@ -363,10 +365,6 @@ class GroupCmdTestCase(SambaToolCmdTest):
self.assertIn('Moved group "%s" into "%s"' %
(group["name"], new_dn), out)
- (result, out, err) = self.runsubcmd("ou", "delete", full_ou_dn)
- self.assertCmdSuccess(result, out, err,
- "Failed to delete ou '%s'" % full_ou_dn)
-
def test_show(self):
"""Assert that we can show a group correctly."""
(result, out, err) = self.runsubcmd("group", "show", "Domain Users",
diff --git a/python/samba/tests/samba_tool/user.py b/python/samba/tests/samba_tool/user.py
index 700cb89c968..9b6d19b11cb 100644
--- a/python/samba/tests/samba_tool/user.py
+++ b/python/samba/tests/samba_tool/user.py
@@ -62,6 +62,11 @@ class UserCmdTestCase(SambaToolCmdTest):
self.users.append(self._randomUnixUser({"name": "unixuser3"}))
self.users.append(self._randomUnixUser({"name": "unixuser4"}))
+ # Make sure users don't exist
+ for user in self.users:
+ if self._find_user(user["name"]):
+ self.runsubcmd("user", "delete", user["name"])
+
# setup the 12 users and ensure they are correct
for user in self.users:
(result, out, err) = user["createUserFn"](user)
@@ -703,7 +708,9 @@ sAMAccountName: %s
self.assertGreater(pwd_expires_time, pwd_last_set_time)
def test_move(self):
- full_ou_dn = str(self.samdb.normalize_dn_in_domain("OU=movetest"))
+ full_ou_dn = str(self.samdb.normalize_dn_in_domain("OU=movetest_usr"))
+ self.addCleanup(self.samdb.delete, full_ou_dn, ["tree_delete:1"])
+
(result, out, err) = self.runsubcmd("ou", "add", full_ou_dn)
self.assertCmdSuccess(result, out, err)
self.assertEqual(err, "", "There shouldn't be any error message")
@@ -730,10 +737,6 @@ sAMAccountName: %s
self.assertIn('Moved user "%s" into "%s"' %
(user["name"], new_dn), out)
- (result, out, err) = self.runsubcmd("ou", "delete", full_ou_dn)
- self.assertCmdSuccess(result, out, err,
- "Failed to delete ou '%s'" % full_ou_dn)
-
def test_rename_surname_initials_givenname(self):
"""rename the existing surname and given name and add missing
initials, then remove them, for all users"""
@@ -999,6 +1002,10 @@ sAMAccountName: %s
"gecos": gecos,
"loginShell": u[6],
})
+
+ # Remove user if it already exists
+ if self._find_user(u[0]):
+ self.runsubcmd("user", "delete", u[0])
# check if --rfc2307-from-nss sets the same values as we got from pwd.getpwuid()
(result, out, err) = self.runsubcmd("user", "create", user["name"], user["password"],
"--surname=%s" % user["surname"],
@@ -1023,6 +1030,10 @@ sAMAccountName: %s
--
Samba Shared Repository
More information about the samba-cvs
mailing list