diff --git a/doc/services/portability/posix/option_groups/index.rst b/doc/services/portability/posix/option_groups/index.rst index 87a9d50caab9..a50d4de72800 100644 --- a/doc/services/portability/posix/option_groups/index.rst +++ b/doc/services/portability/posix/option_groups/index.rst @@ -539,6 +539,38 @@ Enable this option group with :kconfig:option:`CONFIG_POSIX_SPIN_LOCKS`. pthread_spin_trylock(),yes pthread_spin_unlock(),yes +.. _posix_option_group_system_database_r: + +POSIX_SYSTEM_DATABASE_R ++++++++++++++++++++++++ + +Enable this option group with :kconfig:option:`CONFIG_POSIX_SYSTEM_DATABASE_R`. + +.. csv-table:: POSIX_SYSTEM_DATABASE_R + :header: API, Supported + :widths: 50,10 + + getgrgid_r(),yes + getgrnam_r(),yes + getpwnam_r(),yes + getpwuid_r(),yes + +.. _posix_option_group_system_database: + +POSIX_SYSTEM_DATABASE ++++++++++++++++++++++ + +Enable this option group with :kconfig:option:`CONFIG_POSIX_SYSTEM_DATABASE`. + +.. csv-table:: POSIX_SYSTEM_DATABASE + :header: API, Supported + :widths: 50,10 + + getgrgid(),yes + getgrnam(),yes + getpwnam(),yes + getpwuid(),yes + .. _posix_option_group_threads_base: POSIX_THREADS_BASE diff --git a/include/zephyr/posix/grp.h b/include/zephyr/posix/grp.h index 3f5616c34e1b..15f3f4b8f34e 100644 --- a/include/zephyr/posix/grp.h +++ b/include/zephyr/posix/grp.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2024 Meta Platforms + * Copyright (c) 2024 Tenstorrent AI ULC * * SPDX-License-Identifier: Apache-2.0 */ @@ -24,9 +25,18 @@ struct group { char **gr_mem; }; +#if defined(_XOPEN_SOURCE) +void endgrent(void); +struct group *getgrent(void); +#endif +struct group *getgrgid(gid_t gid); +int getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize, struct group **result); +struct group *getgrnam(const char *name); int getgrnam_r(const char *name, struct group *grp, char *buffer, size_t bufsize, struct group **result); -int getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize, struct group **result); +#if defined(_XOPEN_SOURCE) +void setgrent(void); +#endif #ifdef __cplusplus } diff --git a/include/zephyr/posix/pwd.h b/include/zephyr/posix/pwd.h index 3557b20ab979..76cf1918dcd1 100644 --- a/include/zephyr/posix/pwd.h +++ b/include/zephyr/posix/pwd.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2024 Meta Platforms + * Copyright (c) 2024 Tenstorrent AI ULC * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,9 +26,18 @@ struct passwd { char *pw_shell; }; -int getpwnam_r(const char *nam, struct passwd *pwd, char *buffer, size_t bufsize, +#if defined(_XOPEN_SOURCE) +void endpwent(void); +struct passwd *getpwent(void); +#endif +struct passwd *getpwnam(const char *name); +int getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result); +struct passwd *getpwuid(uid_t uid); int getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result); +#if defined(_XOPEN_SOURCE) +void setpwent(void); +#endif #ifdef __cplusplus } diff --git a/include/zephyr/posix/sys/sysconf.h b/include/zephyr/posix/sys/sysconf.h index 67bf84bfb755..cb8d0ae61ea5 100644 --- a/include/zephyr/posix/sys/sysconf.h +++ b/include/zephyr/posix/sys/sysconf.h @@ -264,8 +264,8 @@ enum { #define __z_posix_sysconf_SC_XOPEN_UUCP (-1L) #define __z_posix_sysconf_SC_XOPEN_VERSION _XOPEN_VERSION #define __z_posix_sysconf_SC_CLK_TCK (100L) -#define __z_posix_sysconf_SC_GETGR_R_SIZE_MAX (0L) -#define __z_posix_sysconf_SC_GETPW_R_SIZE_MAX (0L) +#define __z_posix_sysconf_SC_GETGR_R_SIZE_MAX CONFIG_POSIX_GETGR_R_SIZE_MAX +#define __z_posix_sysconf_SC_GETPW_R_SIZE_MAX CONFIG_POSIX_GETPW_R_SIZE_MAX #define __z_posix_sysconf_SC_AIO_LISTIO_MAX AIO_LISTIO_MAX #define __z_posix_sysconf_SC_AIO_MAX AIO_MAX #define __z_posix_sysconf_SC_AIO_PRIO_DELTA_MAX AIO_PRIO_DELTA_MAX diff --git a/lib/posix/options/CMakeLists.txt b/lib/posix/options/CMakeLists.txt index b6e9d0bad4e2..24be697822cb 100644 --- a/lib/posix/options/CMakeLists.txt +++ b/lib/posix/options/CMakeLists.txt @@ -121,6 +121,20 @@ if (NOT CONFIG_TC_PROVIDES_POSIX_SPIN_LOCKS) zephyr_library_sources_ifdef(CONFIG_POSIX_SPIN_LOCKS spinlock.c) endif() +if (NOT CONFIG_TC_PROVIDES_POSIX_SYSTEM_DATABASE) + zephyr_library_sources_ifdef(CONFIG_POSIX_SYSTEM_DATABASE + system_database_priv.c + system_database.c + ) +endif() + +if (NOT CONFIG_TC_PROVIDES_POSIX_SYSTEM_DATABASE_R) + zephyr_library_sources_ifdef(CONFIG_POSIX_SYSTEM_DATABASE_R + system_database_priv.c + system_database_r.c + ) +endif() + if (NOT CONFIG_TC_PROVIDES_POSIX_TIMERS) zephyr_library_sources_ifdef(CONFIG_POSIX_TIMERS clock.c @@ -146,11 +160,9 @@ if (NOT CONFIG_TC_PROVIDES_POSIX_THREADS) # We have opted to use POSIX_THREADS here to match the Option name. zephyr_library_sources_ifdef(CONFIG_POSIX_THREADS cond.c - grp.c key.c mutex.c pthread.c - pwd.c ) endif() diff --git a/lib/posix/options/Kconfig b/lib/posix/options/Kconfig index c7e60d9e3238..7fa3cd5705de 100644 --- a/lib/posix/options/Kconfig +++ b/lib/posix/options/Kconfig @@ -28,6 +28,8 @@ rsource "Kconfig.semaphore" rsource "Kconfig.signal" rsource "Kconfig.spinlock" rsource "Kconfig.sync_io" +rsource "Kconfig.system_database" +rsource "Kconfig.system_database_r" rsource "Kconfig.timer" rsource "Kconfig.xsi" diff --git a/lib/posix/options/Kconfig.system_database b/lib/posix/options/Kconfig.system_database new file mode 100644 index 000000000000..5b6c3b505784 --- /dev/null +++ b/lib/posix/options/Kconfig.system_database @@ -0,0 +1,13 @@ +# Copyright (c) 2024 Tenstorrent AI ULC +# +# SPDX-License-Identifier: Apache-2.0 + +config POSIX_SYSTEM_DATABASE + bool "POSIX System Database" + select POSIX_SYSTEM_DATABASE_R + help + Select 'y' here, and the system will support getgrgid(), getgrnam(), getpwnam(), and + getpwuid(). + + For more information, please see + https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_subprofiles.html diff --git a/lib/posix/options/Kconfig.system_database_r b/lib/posix/options/Kconfig.system_database_r new file mode 100644 index 000000000000..166141c45e97 --- /dev/null +++ b/lib/posix/options/Kconfig.system_database_r @@ -0,0 +1,42 @@ +# Copyright (c) 2024 Tenstorrent AI ULC +# +# SPDX-License-Identifier: Apache-2.0 + +config POSIX_SYSTEM_DATABASE_R + bool "POSIX System Database" + help + Select 'y' here, and the system will support getgrgid_r(), getgrnam_r(), getpwnam_r(), and + getpwuid_r(). + + For more information, please see + https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_subprofiles.html + +config POSIX_GETGR_R_SIZE_MAX + int "Initial size of getgrgid_r() and getgrnam_r() data buffers" + default 96 + help + This option sets the maximum size of the buffer for getgrgid_r() and getgrnam_r(). + + The default size is derived from the formula below. Note, that the home directory and + shell fields are not based on PATH_MAX, which can be excessively large. + + _POSIX_LOGIN_NAME_MAX + 1 + + sizeof(void *) + + sizeof("4294967295") + 1 + + 2 * (_POSIX_NAME_MAX + 1 + sizeof(void *)) + + sizeof(void *) + +config POSIX_GETPW_R_SIZE_MAX + int "Initial size of getpwnam_r() and getpwuid_r() data buffers" + default 64 + help + This option sets the maximum size of the buffer for getpwnam_r() and getpwuid_r(). + + The default size is derived from the formula below. Note, that the home directory and + shell fields are not based on PATH_MAX, which can be excessively large. + + _POSIX_LOGIN_NAME_MAX + 1 + + sizeof("4294967295") + 1 + + sizeof("4294967295") + 1 + + _POSIX_NAME_MAX + 1 + + _POSIX_NAME_MAX + 1 diff --git a/lib/posix/options/grp.c b/lib/posix/options/grp.c deleted file mode 100644 index 32c840e10164..000000000000 --- a/lib/posix/options/grp.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2024 Meta Platforms - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#include -#include - -#ifdef CONFIG_POSIX_THREAD_SAFE_FUNCTIONS - -int getgrnam_r(const char *name, struct group *grp, char *buffer, size_t bufsize, - struct group **result) -{ - ARG_UNUSED(name); - ARG_UNUSED(grp); - ARG_UNUSED(buffer); - ARG_UNUSED(bufsize); - ARG_UNUSED(result); - - return ENOSYS; -} - -int getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize, struct group **result) -{ - ARG_UNUSED(gid); - ARG_UNUSED(grp); - ARG_UNUSED(buffer); - ARG_UNUSED(bufsize); - ARG_UNUSED(result); - - return ENOSYS; -} - -#endif /* CONFIG_POSIX_THREAD_SAFE_FUNCTIONS */ diff --git a/lib/posix/options/pwd.c b/lib/posix/options/pwd.c deleted file mode 100644 index f806767f3df9..000000000000 --- a/lib/posix/options/pwd.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2024 Meta Platforms - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#include -#include - -#ifdef CONFIG_POSIX_THREAD_SAFE_FUNCTIONS - -int getpwnam_r(const char *nam, struct passwd *pwd, char *buffer, size_t bufsize, - struct passwd **result) -{ - ARG_UNUSED(nam); - ARG_UNUSED(pwd); - ARG_UNUSED(buffer); - ARG_UNUSED(bufsize); - ARG_UNUSED(result); - - return ENOSYS; -} - -int getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result) -{ - ARG_UNUSED(uid); - ARG_UNUSED(pwd); - ARG_UNUSED(buffer); - ARG_UNUSED(bufsize); - ARG_UNUSED(result); - - return ENOSYS; -} - -#endif /* CONFIG_POSIX_THREAD_SAFE_FUNCTIONS */ diff --git a/lib/posix/options/system_database.c b/lib/posix/options/system_database.c new file mode 100644 index 000000000000..dc64779b6ba3 --- /dev/null +++ b/lib/posix/options/system_database.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2024 Tenstorrent AI ULC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "system_database_priv.h" + +#include +#include +#include + +#include +#include +#include + +static char gr_line_buf[CONFIG_POSIX_GETGR_R_SIZE_MAX]; +static char pw_line_buf[CONFIG_POSIX_GETPW_R_SIZE_MAX]; + +static struct group gr; +static struct passwd pw; + +struct group *getgrgid(gid_t gid) +{ + int ret; + struct group *result; + + ret = __getgr_r(NULL, gid, &gr, gr_line_buf, sizeof(gr_line_buf), &result); + if (ret != 0) { + errno = ret; + return NULL; + } + + return result; +} + +struct group *getgrnam(const char *name) +{ + int ret; + struct group *result; + + if (name == NULL) { + return NULL; + } + + ret = __getgr_r(name, -1, &gr, gr_line_buf, sizeof(gr_line_buf), &result); + if (ret != 0) { + errno = ret; + return NULL; + } + + return result; +} + +struct passwd *getpwnam(const char *name) +{ + int ret; + struct passwd *result; + + if (name == NULL) { + return NULL; + } + + ret = __getpw_r(name, -1, &pw, pw_line_buf, sizeof(pw_line_buf), &result); + if (ret != 0) { + errno = ret; + return NULL; + } + + return result; +} + +struct passwd *getpwuid(uid_t uid) +{ + int ret; + struct passwd *result; + + ret = __getpw_r(NULL, uid, &pw, pw_line_buf, sizeof(pw_line_buf), &result); + if (ret != 0) { + errno = ret; + return NULL; + } + + return result; +} diff --git a/lib/posix/options/system_database_priv.c b/lib/posix/options/system_database_priv.c new file mode 100644 index 000000000000..1ab265d759db --- /dev/null +++ b/lib/posix/options/system_database_priv.c @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2024 Tenstorrent AI ULC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include +#include + +static int count(const char *s, char c) +{ + int count; + + for (count = 0; *s != '\0'; ++s) { + count += (*s == c) ? 1 : 0; + } + + return count; +} + +int __getgr_r(const char *name, gid_t gid, struct group *grp, char *buffer, size_t bufsize, + struct group **result) +{ + int ret; + int nmemb; + FILE *file; + + if (((name == NULL) && (gid == (gid_t)-1)) || (grp == NULL) || (buffer == NULL) || + (result == NULL)) { + if (result != NULL) { + *result = NULL; + } + return EINVAL; + } + + /* + * Originally, this checked for a bufsize of 0, but newlib will return NULL from fgets when + * bufsize is < 2 + */ + if (bufsize < 2) { + return ERANGE; + } + + file = fopen("/etc/group", "r"); + if (file == NULL) { + return EIO; + } + + while (fgets(buffer, bufsize, file) != NULL) { + char *p = buffer; + char *q; + + if (*p == '\0') { + goto close_erange; + } + + if (*p == '\n') { + continue; + } + + /* name */ + q = strchr(p, ':'); + if (q == NULL) { + goto close_erange; + } + *q = '\0'; + if ((name != NULL) && (strcmp(p, name) != 0)) { + continue; + } + grp->gr_name = p; + p = q + 1; + + /* password */ + q = strchr(p, ':'); + if (q == NULL) { + goto close_erange; + } + *q = '\0'; + p = q + 1; + + /* gid */ + q = strchr(p, ':'); + if (q == NULL) { + goto close_erange; + } + *q = '\0'; + if ((name == NULL) && (atoi(p) != gid)) { + continue; + } + grp->gr_gid = atoi(p); + p = q + 1; + + /* members */ + q = strchr(p, '\n'); + if (q == NULL) { + goto close_erange; + } + *q = '\0'; + + /* count members */ + int min_size; + + nmemb = (p == q) ? 0 : 1 + count(p, ','); + min_size = (q - buffer + 1 + nmemb * sizeof(char *)) + 32; + if (bufsize < min_size) { + goto close_erange; + } + + /* set up member array inside of buffer */ + grp->gr_mem = (char **)(q + 1); + grp->gr_mem = (char **)ROUND_UP((uintptr_t)grp->gr_mem, 16); + grp->gr_mem[nmemb] = NULL; + + for (int i = 0; i < nmemb; ++i) { + char *x = strchr(p, ','); + + grp->gr_mem[i] = p; + if (x == NULL) { + break; + } + *x = '\0'; + p = x + 1; + } + + /* group found \o/ */ + *result = grp; + ret = 0; + goto close_ret; + } + + /* group not found :( )*/ + ret = 0; + *result = NULL; + goto close_ret; + +close_erange: + ret = ERANGE; + +close_ret: + fclose(file); + return ret; +} + +int __getpw_r(const char *name, uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, + struct passwd **result) +{ + int ret; + FILE *file; + + if (((name == NULL) && (uid == (uid_t)-1)) || (pwd == NULL) || (buffer == NULL) || + (result == NULL)) { + if (result != NULL) { + *result = NULL; + } + return EINVAL; + } + + /* + * Originally, this checked for a bufsize of 0, but newlib will return NULL from fgets when + * bufsize is < 2 + */ + if (bufsize < 2) { + return ERANGE; + } + + file = fopen("/etc/passwd", "r"); + if (file == NULL) { + return EIO; + } + + while (fgets(buffer, bufsize, file) != NULL) { + char *p = buffer; + char *q; + + if (*p == '\0') { + goto close_erange; + } + + if (*p == '\n') { + continue; + } + + /* name */ + q = strchr(p, ':'); + if (q == NULL) { + goto close_erange; + } + *q = '\0'; + if ((name != NULL) && (strcmp(p, name) != 0)) { + continue; + } + pwd->pw_name = p; + p = q + 1; + + /* password */ + q = strchr(p, ':'); + if (q == NULL) { + goto close_erange; + } + *q = '\0'; + p = q + 1; + + /* uid */ + q = strchr(p, ':'); + if (q == NULL) { + goto close_erange; + } + *q = '\0'; + if ((name == NULL) && (atoi(p) != uid)) { + continue; + } + pwd->pw_uid = atoi(p); + p = q + 1; + + /* gid */ + q = strchr(p, ':'); + if (q == NULL) { + goto close_erange; + } + *q = '\0'; + pwd->pw_gid = atoi(p); + p = q + 1; + + /* gecos */ + q = strchr(p, ':'); + if (q == NULL) { + goto close_erange; + } + *q = '\0'; + p = q + 1; + + /* dir */ + q = strchr(p, ':'); + if (q == NULL) { + goto close_erange; + } + *q = '\0'; + pwd->pw_dir = p; + p = q + 1; + + /* shell */ + q = strchr(p, '\n'); + if (q == NULL) { + goto close_erange; + } + *q = '\0'; + pwd->pw_shell = p; + + /* user found \o/ */ + *result = pwd; + ret = 0; + goto close_ret; + } + + /* user not found :( )*/ + ret = 0; + *result = NULL; + goto close_ret; + +close_erange: + ret = ERANGE; + +close_ret: + fclose(file); + return ret; +} diff --git a/lib/posix/options/system_database_priv.h b/lib/posix/options/system_database_priv.h new file mode 100644 index 000000000000..9ec79d58882a --- /dev/null +++ b/lib/posix/options/system_database_priv.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2024 Tenstorrent AI ULC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include + +int __getgr_r(const char *name, gid_t gid, struct group *grp, char *buffer, size_t bufsize, + struct group **result); +int __getpw_r(const char *name, uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, + struct passwd **result); diff --git a/lib/posix/options/system_database_r.c b/lib/posix/options/system_database_r.c new file mode 100644 index 000000000000..3e98143dd7b8 --- /dev/null +++ b/lib/posix/options/system_database_r.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 Tenstorrent AI ULC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "system_database_priv.h" + +#include +#include +#include +#include + +#include +#include +#include + +int getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t bufsize, + struct passwd **result) +{ + return __getpw_r(name, -1, pwd, buffer, bufsize, result); +} + +int getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result) +{ + return __getpw_r(NULL, uid, pwd, buffer, bufsize, result); +} + +int getgrnam_r(const char *name, struct group *grp, char *buffer, size_t bufsize, + struct group **result) +{ + return __getgr_r(name, -1, grp, buffer, bufsize, result); +} + +int getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize, struct group **result) +{ + return __getgr_r(NULL, gid, grp, buffer, bufsize, result); +} diff --git a/tests/posix/common/src/grp.c b/tests/posix/common/src/grp.c deleted file mode 100644 index 1fce1433bff8..000000000000 --- a/tests/posix/common/src/grp.c +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2024 Meta Platforms - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -#include - -ZTEST(grp, test_grp_stubs) -{ - zassert_equal(getgrnam_r(NULL, NULL, NULL, 42, NULL), ENOSYS); - zassert_equal(getgrgid_r(42, NULL, NULL, 42, NULL), ENOSYS); -} - -ZTEST_SUITE(grp, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/common/src/pwd.c b/tests/posix/common/src/pwd.c deleted file mode 100644 index dd473569f0d3..000000000000 --- a/tests/posix/common/src/pwd.c +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2024 Meta Platforms - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -#include - -ZTEST(pwd, test_pwd_stubs) -{ - zassert_equal(getpwnam_r(NULL, NULL, NULL, 42, NULL), ENOSYS); - zassert_equal(getpwuid_r(42, NULL, NULL, 42, NULL), ENOSYS); -} - -ZTEST_SUITE(pwd, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/posix/fs/src/main.c b/tests/posix/fs/src/main.c index 6a124d253732..9c59073c2282 100644 --- a/tests/posix/fs/src/main.c +++ b/tests/posix/fs/src/main.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include "test_fs.h" ZTEST_SUITE(posix_fs_test, NULL, test_mount, NULL, NULL, test_unmount); diff --git a/tests/posix/system_database/CMakeLists.txt b/tests/posix/system_database/CMakeLists.txt new file mode 100644 index 000000000000..37d08f6a3b93 --- /dev/null +++ b/tests/posix/system_database/CMakeLists.txt @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(posix_system_database) + +target_sources(app PRIVATE + src/main.c + ../system_database_r/src/fs.c +) + +target_compile_options(app PRIVATE -U_POSIX_C_SOURCE -D_POSIX_C_SOURCE=200809L) diff --git a/tests/posix/system_database/app.overlay b/tests/posix/system_database/app.overlay new file mode 100644 index 000000000000..87ae21b1e647 --- /dev/null +++ b/tests/posix/system_database/app.overlay @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + ramdisk0 { + compatible = "zephyr,ram-disk"; + disk-name = "RAM"; + sector-size = <512>; + sector-count = <160>; + }; +}; diff --git a/tests/posix/system_database/prj.conf b/tests/posix/system_database/prj.conf new file mode 100644 index 000000000000..bf6eff4369b6 --- /dev/null +++ b/tests/posix/system_database/prj.conf @@ -0,0 +1,8 @@ +CONFIG_POSIX_API=y +CONFIG_ZTEST=y + +CONFIG_POSIX_AEP_CHOICE_BASE=y +CONFIG_POSIX_SYSTEM_DATABASE=y +CONFIG_FAT_FILESYSTEM_ELM=y + +CONFIG_MAIN_STACK_SIZE=4096 diff --git a/tests/posix/system_database/src/main.c b/tests/posix/system_database/src/main.c new file mode 100644 index 000000000000..1a5968b27117 --- /dev/null +++ b/tests/posix/system_database/src/main.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2024 Tenstorrent AI ULC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +ZTEST(posix_system_database, test_getpwnam) +{ + struct passwd *result; + + { + /* degenerate cases */ + errno = 0; + zexpect_is_null(getpwnam(NULL)); + zexpect_equal(errno, 0); + + /* user is not found in /etc/passwd */ + errno = 0; + zexpect_is_null(getpwnam("nobody")); + zexpect_equal(errno, 0, "expected errno to be zero, not %d", errno); + } + + result = getpwnam("root"); + zassert_not_null(result, "getpwnam(\"root\") failed: %d", errno); + zexpect_str_equal(result->pw_name, "root"); + zexpect_equal(result->pw_uid, 0); + zexpect_equal(result->pw_gid, 0); + zexpect_str_equal(result->pw_dir, "/root"); + zexpect_str_equal(result->pw_shell, "/bin/sh"); + + result = getpwnam("user"); + zassert_not_null(result, "getpwnam(\"user\") failed: %d", errno); + zexpect_str_equal(result->pw_name, "user"); + zexpect_equal(result->pw_uid, 1000); + zexpect_equal(result->pw_gid, 1000); + zexpect_str_equal(result->pw_dir, "/home/user"); + zexpect_str_equal(result->pw_shell, "/bin/sh"); +} + +ZTEST(posix_system_database, test_getpwuid) +{ + struct passwd *result; + + { + /* degenerate cases */ + + /* user is not found in /etc/passwd */ + errno = 0; + zexpect_is_null(getpwuid(1001)); + zexpect_equal(errno, 0, "expected errno to be zero, not %d", errno); + } + + result = getpwuid(0); + zassert_not_null(result, "getpwuid(0) failed: %d", errno); + zexpect_str_equal(result->pw_name, "root"); + zexpect_equal(result->pw_uid, 0); + zexpect_equal(result->pw_gid, 0); + zexpect_str_equal(result->pw_dir, "/root"); + zexpect_str_equal(result->pw_shell, "/bin/sh"); + + result = getpwuid(1000); + zassert_not_null(result, "getpwuid(0) failed: %d", errno); + zexpect_str_equal(result->pw_name, "user"); + zexpect_equal(result->pw_uid, 1000); + zexpect_equal(result->pw_gid, 1000); + zexpect_str_equal(result->pw_dir, "/home/user"); + zexpect_str_equal(result->pw_shell, "/bin/sh"); +} + +static const char *const members[] = { + "staff", + "admin", +}; + +ZTEST(posix_system_database, test_getgrnam) +{ + struct group *result; + + { + /* degenerate cases */ + errno = 0; + zexpect_is_null(getgrnam(NULL)); + zexpect_equal(errno, 0, "expected errno to be zero, not %d", errno); + + /* group is not found in /etc/group */ + errno = 0; + zexpect_is_null(getgrnam("nobody")); + zexpect_equal(errno, 0, "expected errno to be zero, not %d", errno); + } + + result = getgrnam("root"); + zassert_not_null(result, "getgrnam(\"root\") failed: %d", errno); + zexpect_str_equal(result->gr_name, "root"); + zexpect_equal(result->gr_gid, 0); + zexpect_equal(result->gr_mem[0], NULL); + + result = getgrnam("user"); + zassert_not_null(result, "getgrnam(\"user\") failed: %d", errno); + zexpect_str_equal(result->gr_name, "user"); + zexpect_equal(result->gr_gid, 1000); + ARRAY_FOR_EACH(members, i) { + zexpect_str_equal(result->gr_mem[i], members[i], + "members[%d] (%s) does not match gr.gr_mem[%d] (%s)", i, + members[i], i, result->gr_mem[i]); + } + zexpect_equal(result->gr_mem[2], NULL); +} + +ZTEST(posix_system_database, test_getgrgid) +{ + struct group *result; + + { + /* degenerate cases */ + + /* group is not found in /etc/group */ + errno = 0; + zexpect_is_null(getgrgid(1001)); + zexpect_equal(errno, 0, "expected errno to be zero, not %d", errno); + } + + result = getgrgid(0); + zassert_not_null(result, "getgrgid(0) failed: %d", errno); + zexpect_str_equal(result->gr_name, "root"); + zexpect_equal(result->gr_gid, 0); + zexpect_equal(result->gr_mem[0], NULL); + + result = getgrgid(1000); + zassert_not_null(result, "getgrgid(1000) failed: %d", errno); + zexpect_str_equal(result->gr_name, "user"); + zexpect_equal(result->gr_gid, 1000); + ARRAY_FOR_EACH(members, i) { + zexpect_str_equal(result->gr_mem[i], members[i], + "members[%d] (%s) does not match gr.gr_mem[%d] (%s)", i, + members[i], i, result->gr_mem[i]); + } + zexpect_equal(result->gr_mem[2], NULL); +} + +void *setup(void); +void teardown(void *arg); + +ZTEST_SUITE(posix_system_database, NULL, setup, NULL, NULL, teardown); diff --git a/tests/posix/system_database/testcase.yaml b/tests/posix/system_database/testcase.yaml new file mode 100644 index 000000000000..2b1cab6b031b --- /dev/null +++ b/tests/posix/system_database/testcase.yaml @@ -0,0 +1,25 @@ +common: + filter: not CONFIG_NATIVE_LIBC + tags: + - posix + - posix_system_database + # 1 tier0 platform per supported architecture + platform_key: + - arch + - simulation + min_flash: 64 + min_ram: 32 +tests: + portability.posix.posix_system_database: {} + portability.posix.posix_system_database.minimal: + extra_configs: + - CONFIG_MINIMAL_LIBC=y + portability.posix.posix_system_database.newlib: + filter: TOOLCHAIN_HAS_NEWLIB == 1 + extra_configs: + - CONFIG_NEWLIB_LIBC=y + portability.posix.posix_system_database.picolibc: + tags: picolibc + filter: CONFIG_PICOLIBC_SUPPORTED + extra_configs: + - CONFIG_PICOLIBC=y diff --git a/tests/posix/system_database_r/CMakeLists.txt b/tests/posix/system_database_r/CMakeLists.txt new file mode 100644 index 000000000000..e38c61e48946 --- /dev/null +++ b/tests/posix/system_database_r/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(posix_system_database_r) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) + +target_compile_options(app PRIVATE -U_POSIX_C_SOURCE -D_POSIX_C_SOURCE=200809L) diff --git a/tests/posix/system_database_r/app.overlay b/tests/posix/system_database_r/app.overlay new file mode 100644 index 000000000000..87ae21b1e647 --- /dev/null +++ b/tests/posix/system_database_r/app.overlay @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + ramdisk0 { + compatible = "zephyr,ram-disk"; + disk-name = "RAM"; + sector-size = <512>; + sector-count = <160>; + }; +}; diff --git a/tests/posix/system_database_r/prj.conf b/tests/posix/system_database_r/prj.conf new file mode 100644 index 000000000000..47f9fbb4e5b0 --- /dev/null +++ b/tests/posix/system_database_r/prj.conf @@ -0,0 +1,8 @@ +CONFIG_POSIX_API=y +CONFIG_ZTEST=y + +CONFIG_POSIX_AEP_CHOICE_BASE=y +CONFIG_POSIX_SYSTEM_DATABASE_R=y +CONFIG_FAT_FILESYSTEM_ELM=y + +CONFIG_MAIN_STACK_SIZE=4096 diff --git a/tests/posix/system_database_r/src/fs.c b/tests/posix/system_database_r/src/fs.c new file mode 100644 index 000000000000..9cf220f52c0b --- /dev/null +++ b/tests/posix/system_database_r/src/fs.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2024 Tenstorrent AI ULC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include + +static FATFS _fs; + +static struct fs_mount_t _mnt = { + .type = FS_FATFS, + .mnt_point = "/", + .fs_data = &_fs, +}; + +struct _entry { + const char *const name; + const char *const data; +}; + +static const struct _entry _data[] = { + {.name = "/etc/passwd", + .data = "user:x:1000:1000:user:/home/user:/bin/sh\nroot:x:0:0:root:/root:/bin/sh\n"}, + {.name = "/etc/group", .data = "user:x:1000:staff,admin\nroot:x:0:\n"}, +}; + +void *setup(void) +{ + int ret; + + memset(&_fs, 0, sizeof(_fs)); + + ret = fs_mount(&_mnt); + zassert_ok(ret, "mount failed: %d", ret); + + ret = fs_mkdir("/etc"); + zassert_ok(ret, "mkdir failed: %d", ret); + + ARRAY_FOR_EACH_PTR(_data, entry) { + int len; + struct fs_file_t zfp; + + fs_file_t_init(&zfp); + + ret = fs_open(&zfp, entry->name, FS_O_CREATE | FS_O_RDWR | FS_O_TRUNC); + zassert_true(ret >= 0, "open failed: %d", ret); + + len = strlen(entry->data); + ret = fs_write(&zfp, entry->data, len); + zassert_equal(ret, len, "%s returned %d instead of %d", "write", ret, len); + + ret = fs_close(&zfp); + zassert_ok(ret, "%s returned %d instead of %d", "close", ret, len); + }; + + return &_mnt; +} + +void teardown(void *arg) +{ + struct fs_mount_t *const mnt = arg; + + (void)fs_unmount(mnt); +} diff --git a/tests/posix/system_database_r/src/main.c b/tests/posix/system_database_r/src/main.c new file mode 100644 index 000000000000..9efea6c463aa --- /dev/null +++ b/tests/posix/system_database_r/src/main.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2024 Tenstorrent AI ULC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +static char buf[CONFIG_POSIX_GETGR_R_SIZE_MAX]; + +ZTEST(posix_system_database_r, test_getpwnam_r) +{ + struct passwd pwd; + struct passwd *result; + + { + /* degenerate cases */ + zexpect_not_ok(getpwnam_r(NULL, NULL, NULL, 0, NULL)); + zexpect_not_ok(getpwnam_r(NULL, NULL, NULL, 0, &result)); + zexpect_not_ok(getpwnam_r(NULL, NULL, NULL, sizeof(buf), NULL)); + zexpect_not_ok(getpwnam_r(NULL, NULL, NULL, sizeof(buf), &result)); + zexpect_not_ok(getpwnam_r(NULL, NULL, buf, 0, NULL)); + zexpect_not_ok(getpwnam_r(NULL, NULL, buf, 0, &result)); + zexpect_not_ok(getpwnam_r(NULL, NULL, buf, sizeof(buf), NULL)); + zexpect_not_ok(getpwnam_r(NULL, NULL, buf, sizeof(buf), &result)); + zexpect_not_ok(getpwnam_r(NULL, &pwd, NULL, 0, NULL)); + zexpect_not_ok(getpwnam_r(NULL, &pwd, NULL, 0, &result)); + zexpect_not_ok(getpwnam_r(NULL, &pwd, NULL, sizeof(buf), NULL)); + zexpect_not_ok(getpwnam_r(NULL, &pwd, NULL, sizeof(buf), &result)); + zexpect_not_ok(getpwnam_r(NULL, &pwd, buf, 0, NULL)); + zexpect_not_ok(getpwnam_r(NULL, &pwd, buf, 0, &result)); + zexpect_not_ok(getpwnam_r(NULL, &pwd, buf, sizeof(buf), NULL)); + zexpect_not_ok(getpwnam_r(NULL, &pwd, buf, sizeof(buf), &result)); + zexpect_not_ok(getpwnam_r("root", NULL, NULL, 0, NULL)); + zexpect_not_ok(getpwnam_r("root", NULL, NULL, 0, &result)); + zexpect_not_ok(getpwnam_r("root", NULL, NULL, sizeof(buf), NULL)); + zexpect_not_ok(getpwnam_r("root", NULL, NULL, sizeof(buf), &result)); + zexpect_not_ok(getpwnam_r("root", NULL, buf, 0, NULL)); + zexpect_not_ok(getpwnam_r("root", NULL, buf, 0, &result)); + zexpect_not_ok(getpwnam_r("root", NULL, buf, sizeof(buf), NULL)); + zexpect_not_ok(getpwnam_r("root", NULL, buf, sizeof(buf), &result)); + zexpect_not_ok(getpwnam_r("root", &pwd, NULL, 0, NULL)); + zexpect_not_ok(getpwnam_r("root", &pwd, NULL, 0, &result)); + zexpect_not_ok(getpwnam_r("root", &pwd, NULL, sizeof(buf), NULL)); + zexpect_not_ok(getpwnam_r("root", &pwd, NULL, sizeof(buf), &result)); + zexpect_not_ok(getpwnam_r("root", &pwd, buf, 0, NULL)); + zexpect_not_ok(getpwnam_r("root", &pwd, buf, 0, &result)); + zexpect_not_ok(getpwnam_r("root", &pwd, buf, sizeof(buf), NULL)); + + /* buffer is not large enough */ + zexpect_equal(getpwnam_r("root", &pwd, buf, 1, &result), ERANGE); + + /* user is not found in /etc/passwd */ + result = (struct passwd *)0x42; + zexpect_ok(getpwnam_r("nobody", &pwd, buf, sizeof(buf), &result)); + zexpect_equal(result, NULL); + } + + zexpect_ok(getpwnam_r("root", &pwd, buf, sizeof(buf), &result)); + zexpect_equal(result, &pwd); + zexpect_str_equal(pwd.pw_name, "root"); + zexpect_equal(pwd.pw_uid, 0); + zexpect_equal(pwd.pw_gid, 0); + zexpect_str_equal(pwd.pw_dir, "/root"); + zexpect_str_equal(pwd.pw_shell, "/bin/sh"); + + zexpect_ok(getpwnam_r("user", &pwd, buf, sizeof(buf), &result)); + zexpect_equal(result, &pwd); + zexpect_str_equal(pwd.pw_name, "user"); + zexpect_equal(pwd.pw_uid, 1000); + zexpect_equal(pwd.pw_gid, 1000); + zexpect_str_equal(pwd.pw_dir, "/home/user"); + zexpect_str_equal(pwd.pw_shell, "/bin/sh"); +} + +ZTEST(posix_system_database_r, test_getpwuid_r) +{ + struct passwd pwd; + struct passwd *result; + + { + /* degenerate cases */ + zexpect_not_ok(getpwuid_r(-1, NULL, NULL, 0, NULL)); + zexpect_not_ok(getpwuid_r(-1, NULL, NULL, 0, &result)); + zexpect_not_ok(getpwuid_r(-1, NULL, NULL, sizeof(buf), NULL)); + zexpect_not_ok(getpwuid_r(-1, NULL, NULL, sizeof(buf), &result)); + zexpect_not_ok(getpwuid_r(-1, NULL, buf, 0, NULL)); + zexpect_not_ok(getpwuid_r(-1, NULL, buf, 0, &result)); + zexpect_not_ok(getpwuid_r(-1, NULL, buf, sizeof(buf), NULL)); + zexpect_not_ok(getpwuid_r(-1, NULL, buf, sizeof(buf), &result)); + zexpect_not_ok(getpwuid_r(-1, &pwd, NULL, 0, NULL)); + zexpect_not_ok(getpwuid_r(-1, &pwd, NULL, 0, &result)); + zexpect_not_ok(getpwuid_r(-1, &pwd, NULL, sizeof(buf), NULL)); + zexpect_not_ok(getpwuid_r(-1, &pwd, NULL, sizeof(buf), &result)); + zexpect_not_ok(getpwuid_r(-1, &pwd, buf, 0, NULL)); + zexpect_not_ok(getpwuid_r(-1, &pwd, buf, 0, &result)); + zexpect_not_ok(getpwuid_r(-1, &pwd, buf, sizeof(buf), NULL)); + zexpect_not_ok(getpwuid_r(-1, &pwd, buf, sizeof(buf), &result)); + zexpect_not_ok(getpwuid_r(0, NULL, NULL, 0, NULL)); + zexpect_not_ok(getpwuid_r(0, NULL, NULL, 0, &result)); + zexpect_not_ok(getpwuid_r(0, NULL, NULL, sizeof(buf), NULL)); + zexpect_not_ok(getpwuid_r(0, NULL, NULL, sizeof(buf), &result)); + zexpect_not_ok(getpwuid_r(0, NULL, buf, 0, NULL)); + zexpect_not_ok(getpwuid_r(0, NULL, buf, 0, &result)); + zexpect_not_ok(getpwuid_r(0, NULL, buf, sizeof(buf), NULL)); + zexpect_not_ok(getpwuid_r(0, NULL, buf, sizeof(buf), &result)); + zexpect_not_ok(getpwuid_r(0, &pwd, NULL, 0, NULL)); + zexpect_not_ok(getpwuid_r(0, &pwd, NULL, 0, &result)); + zexpect_not_ok(getpwuid_r(0, &pwd, NULL, sizeof(buf), NULL)); + zexpect_not_ok(getpwuid_r(0, &pwd, NULL, sizeof(buf), &result)); + zexpect_not_ok(getpwuid_r(0, &pwd, buf, 0, NULL)); + zexpect_not_ok(getpwuid_r(0, &pwd, buf, 0, &result)); + zexpect_not_ok(getpwuid_r(0, &pwd, buf, sizeof(buf), NULL)); + + /* buffer is not large enough */ + zexpect_equal(getpwuid_r(0, &pwd, buf, 1, &result), ERANGE); + + /* user is not found in /etc/passwd */ + result = (struct passwd *)0x42; + zexpect_ok(getpwuid_r(1001, &pwd, buf, sizeof(buf), &result)); + zexpect_equal(result, NULL); + } + + zexpect_ok(getpwuid_r(0, &pwd, buf, sizeof(buf), &result)); + zexpect_equal(result, &pwd); + zexpect_str_equal(pwd.pw_name, "root"); + zexpect_equal(pwd.pw_uid, 0); + zexpect_equal(pwd.pw_gid, 0); + zexpect_str_equal(pwd.pw_dir, "/root"); + zexpect_str_equal(pwd.pw_shell, "/bin/sh"); + + zexpect_ok(getpwuid_r(1000, &pwd, buf, sizeof(buf), &result)); + zexpect_equal(result, &pwd); + zexpect_str_equal(pwd.pw_name, "user"); + zexpect_equal(pwd.pw_uid, 1000); + zexpect_equal(pwd.pw_gid, 1000); + zexpect_str_equal(pwd.pw_dir, "/home/user"); + zexpect_str_equal(pwd.pw_shell, "/bin/sh"); +} + +static const char *const members[] = { + "staff", + "admin", +}; + +ZTEST(posix_system_database_r, test_getgrnam_r) +{ + struct group grp; + struct group *result; + + { + /* degenerate cases */ + zexpect_not_ok(getgrnam_r(NULL, NULL, NULL, 0, NULL)); + zexpect_not_ok(getgrnam_r(NULL, NULL, NULL, 0, &result)); + zexpect_not_ok(getgrnam_r(NULL, NULL, NULL, sizeof(buf), NULL)); + zexpect_not_ok(getgrnam_r(NULL, NULL, NULL, sizeof(buf), &result)); + zexpect_not_ok(getgrnam_r(NULL, NULL, buf, 0, NULL)); + zexpect_not_ok(getgrnam_r(NULL, NULL, buf, 0, &result)); + zexpect_not_ok(getgrnam_r(NULL, NULL, buf, sizeof(buf), NULL)); + zexpect_not_ok(getgrnam_r(NULL, NULL, buf, sizeof(buf), &result)); + zexpect_not_ok(getgrnam_r(NULL, &grp, NULL, 0, NULL)); + zexpect_not_ok(getgrnam_r(NULL, &grp, NULL, 0, &result)); + zexpect_not_ok(getgrnam_r(NULL, &grp, NULL, sizeof(buf), NULL)); + zexpect_not_ok(getgrnam_r(NULL, &grp, NULL, sizeof(buf), &result)); + zexpect_not_ok(getgrnam_r(NULL, &grp, buf, 0, NULL)); + zexpect_not_ok(getgrnam_r(NULL, &grp, buf, 0, &result)); + zexpect_not_ok(getgrnam_r(NULL, &grp, buf, sizeof(buf), NULL)); + zexpect_not_ok(getgrnam_r(NULL, &grp, buf, sizeof(buf), &result)); + zexpect_not_ok(getgrnam_r("root", NULL, NULL, 0, NULL)); + zexpect_not_ok(getgrnam_r("root", NULL, NULL, 0, &result)); + zexpect_not_ok(getgrnam_r("root", NULL, NULL, sizeof(buf), NULL)); + zexpect_not_ok(getgrnam_r("root", NULL, NULL, sizeof(buf), &result)); + zexpect_not_ok(getgrnam_r("root", NULL, buf, 0, NULL)); + zexpect_not_ok(getgrnam_r("root", NULL, buf, 0, &result)); + zexpect_not_ok(getgrnam_r("root", NULL, buf, sizeof(buf), NULL)); + zexpect_not_ok(getgrnam_r("root", NULL, buf, sizeof(buf), &result)); + zexpect_not_ok(getgrnam_r("root", &grp, NULL, 0, NULL)); + zexpect_not_ok(getgrnam_r("root", &grp, NULL, 0, &result)); + zexpect_not_ok(getgrnam_r("root", &grp, NULL, sizeof(buf), NULL)); + zexpect_not_ok(getgrnam_r("root", &grp, NULL, sizeof(buf), &result)); + zexpect_not_ok(getgrnam_r("root", &grp, buf, 0, NULL)); + zexpect_not_ok(getgrnam_r("root", &grp, buf, 0, &result)); + zexpect_not_ok(getgrnam_r("root", &grp, buf, sizeof(buf), NULL)); + + /* buffer is not large enough */ + zexpect_equal(getgrnam_r("root", &grp, buf, 1, &result), ERANGE); + + /* group is not found in /etc/group */ + result = (struct group *)0x42; + zexpect_ok(getgrnam_r("nobody", &grp, buf, sizeof(buf), &result)); + zexpect_equal(result, NULL); + } + + zexpect_ok(getgrnam_r("root", &grp, buf, sizeof(buf), &result)); + zexpect_equal(result, &grp); + zexpect_str_equal(grp.gr_name, "root"); + zexpect_equal(grp.gr_gid, 0); + zassert_within((uintptr_t)grp.gr_mem, (uintptr_t)buf, sizeof(buf)); + zexpect_equal(grp.gr_mem[0], NULL); + + zexpect_ok(getgrnam_r("user", &grp, buf, sizeof(buf), &result)); + zexpect_equal(result, &grp); + zexpect_str_equal(grp.gr_name, "user"); + zexpect_equal(grp.gr_gid, 1000); + zassert_within((uintptr_t)grp.gr_mem, (uintptr_t)buf, sizeof(buf)); + ARRAY_FOR_EACH(members, i) { + zexpect_str_equal(grp.gr_mem[i], members[i], + "members[%d] (%s) does not match gr.gr_mem[%d] (%s)", i, + members[i], i, grp.gr_mem[i]); + } + zexpect_equal(grp.gr_mem[2], NULL); +} + +ZTEST(posix_system_database_r, test_getgrgid_r) +{ + struct group grp; + struct group *result; + + { + /* degenerate cases */ + zexpect_not_ok(getgrgid_r(-1, NULL, NULL, 0, NULL)); + zexpect_not_ok(getgrgid_r(-1, NULL, NULL, 0, &result)); + zexpect_not_ok(getgrgid_r(-1, NULL, NULL, sizeof(buf), NULL)); + zexpect_not_ok(getgrgid_r(-1, NULL, NULL, sizeof(buf), &result)); + zexpect_not_ok(getgrgid_r(-1, NULL, buf, 0, NULL)); + zexpect_not_ok(getgrgid_r(-1, NULL, buf, 0, &result)); + zexpect_not_ok(getgrgid_r(-1, NULL, buf, sizeof(buf), NULL)); + zexpect_not_ok(getgrgid_r(-1, NULL, buf, sizeof(buf), &result)); + zexpect_not_ok(getgrgid_r(-1, &grp, NULL, 0, NULL)); + zexpect_not_ok(getgrgid_r(-1, &grp, NULL, 0, &result)); + zexpect_not_ok(getgrgid_r(-1, &grp, NULL, sizeof(buf), NULL)); + zexpect_not_ok(getgrgid_r(-1, &grp, NULL, sizeof(buf), &result)); + zexpect_not_ok(getgrgid_r(-1, &grp, buf, 0, NULL)); + zexpect_not_ok(getgrgid_r(-1, &grp, buf, 0, &result)); + zexpect_not_ok(getgrgid_r(-1, &grp, buf, sizeof(buf), NULL)); + zexpect_not_ok(getgrgid_r(-1, &grp, buf, sizeof(buf), &result)); + zexpect_not_ok(getgrgid_r(0, NULL, NULL, 0, NULL)); + zexpect_not_ok(getgrgid_r(0, NULL, NULL, 0, &result)); + zexpect_not_ok(getgrgid_r(0, NULL, NULL, sizeof(buf), NULL)); + zexpect_not_ok(getgrgid_r(0, NULL, NULL, sizeof(buf), &result)); + zexpect_not_ok(getgrgid_r(0, NULL, buf, 0, NULL)); + zexpect_not_ok(getgrgid_r(0, NULL, buf, 0, &result)); + zexpect_not_ok(getgrgid_r(0, NULL, buf, sizeof(buf), NULL)); + zexpect_not_ok(getgrgid_r(0, NULL, buf, sizeof(buf), &result)); + zexpect_not_ok(getgrgid_r(0, &grp, NULL, 0, NULL)); + zexpect_not_ok(getgrgid_r(0, &grp, NULL, 0, &result)); + zexpect_not_ok(getgrgid_r(0, &grp, NULL, sizeof(buf), NULL)); + zexpect_not_ok(getgrgid_r(0, &grp, NULL, sizeof(buf), &result)); + zexpect_not_ok(getgrgid_r(0, &grp, buf, 0, NULL)); + zexpect_not_ok(getgrgid_r(0, &grp, buf, 0, &result)); + zexpect_not_ok(getgrgid_r(0, &grp, buf, sizeof(buf), NULL)); + + /* buffer is not large enough */ + zexpect_equal(getgrgid_r(0, &grp, buf, 1, &result), ERANGE); + + /* group is not found in /etc/group */ + result = (struct group *)0x42; + zexpect_ok(getgrgid_r(1001, &grp, buf, sizeof(buf), &result)); + zexpect_equal(result, NULL); + } + + zexpect_ok(getgrgid_r(0, &grp, buf, sizeof(buf), &result)); + zexpect_equal(result, &grp); + zexpect_str_equal(grp.gr_name, "root"); + zexpect_equal(grp.gr_gid, 0); + zassert_within((uintptr_t)grp.gr_mem, (uintptr_t)buf, sizeof(buf)); + zexpect_equal(grp.gr_mem[0], NULL); + + zexpect_ok(getgrgid_r(1000, &grp, buf, sizeof(buf), &result)); + zexpect_equal(result, &grp); + zexpect_str_equal(grp.gr_name, "user"); + zexpect_equal(grp.gr_gid, 1000); + zassert_within((uintptr_t)grp.gr_mem, (uintptr_t)buf, sizeof(buf)); + ARRAY_FOR_EACH(members, i) { + zexpect_str_equal(grp.gr_mem[i], members[i], + "members[%d] (%s) does not match gr.gr_mem[%d] (%s)", i, + members[i], i, grp.gr_mem[i]); + } + zexpect_equal(grp.gr_mem[2], NULL); +} + +void *setup(void); +void teardown(void *arg); + +ZTEST_SUITE(posix_system_database_r, NULL, setup, NULL, NULL, teardown); diff --git a/tests/posix/system_database_r/testcase.yaml b/tests/posix/system_database_r/testcase.yaml new file mode 100644 index 000000000000..553e593058b2 --- /dev/null +++ b/tests/posix/system_database_r/testcase.yaml @@ -0,0 +1,25 @@ +common: + filter: not CONFIG_NATIVE_LIBC + tags: + - posix + - posix_system_database_r + # 1 tier0 platform per supported architecture + platform_key: + - arch + - simulation + min_flash: 64 + min_ram: 32 +tests: + portability.posix.posix_system_database_r: {} + portability.posix.posix_system_database_r.minimal: + extra_configs: + - CONFIG_MINIMAL_LIBC=y + portability.posix.posix_system_database_r.newlib: + filter: TOOLCHAIN_HAS_NEWLIB == 1 + extra_configs: + - CONFIG_NEWLIB_LIBC=y + portability.posix.posix_system_database_r.picolibc: + tags: picolibc + filter: CONFIG_PICOLIBC_SUPPORTED + extra_configs: + - CONFIG_PICOLIBC=y