diff mbox series

[3/7] Add user/group ID lookup helper functions

Message ID 20210903154848.18705-4-mdoucha@suse.cz
State Superseded
Headers show
Series UID/GID lookup fixes | expand

Commit Message

Martin Doucha Sept. 3, 2021, 3:48 p.m. UTC
Signed-off-by: Martin Doucha <mdoucha@suse.cz>
---
 include/tst_safe_macros.h |   6 +++
 include/tst_uid.h         |  17 +++++++
 lib/tst_uid.c             | 100 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 123 insertions(+)

Comments

Cyril Hrubis Sept. 6, 2021, 12:21 p.m. UTC | #1
Hi!
> diff --git a/lib/tst_uid.c b/lib/tst_uid.c
> index dd719d312..915a5bc34 100644
> --- a/lib/tst_uid.c
> +++ b/lib/tst_uid.c
> @@ -3,8 +3,10 @@
>   * Copyright (c) 2021 Linux Test Project
>   */
>  
> +#define _XOPEN_SOURCE 500
>  #include <sys/types.h>
>  #include <grp.h>
> +#include <pwd.h>
>  #include <errno.h>
>  
>  #define TST_NO_DEFAULT_MAIN
> @@ -36,3 +38,101 @@ gid_t tst_get_free_gid_(const char *file, const int lineno, gid_t skip)
>  	tst_brk_(file, lineno, TBROK, "No free group ID found");
>  	return (gid_t)-1;
>  }
> +
> +struct passwd *safe_getpwent(const char *file, const int lineno)
> +{
> +	struct passwd *ret;
> +
> +	errno = 0;
> +	ret = getpwent();
> +
> +	if (!ret) {
> +		if (errno) {
> +			tst_brk_(file, lineno, TBROK | TERRNO,
> +				"getpwent() failed");
> +		} else {
> +			tst_brk_(file, lineno, TBROK,
> +				"getpwent() failed: end of file");
> +		}

I'm not sure if "no more users in the /etc/passwd" should be reported as
an error.
Martin Doucha Sept. 6, 2021, 12:40 p.m. UTC | #2
On 06. 09. 21 14:21, Cyril Hrubis wrote:
> Hi!
>> +	if (!ret) {
>> +		if (errno) {
>> +			tst_brk_(file, lineno, TBROK | TERRNO,
>> +				"getpwent() failed");
>> +		} else {
>> +			tst_brk_(file, lineno, TBROK,
>> +				"getpwent() failed: end of file");
>> +		}
> 
> I'm not sure if "no more users in the /etc/passwd" should be reported as
> an error.

The alternative would be that pretty much every test that calls
SAFE_GETPWENT() in setup() will need to check for NULL and explicitly
call tst_brk(). I don't see any use for allowing SAFE_GETPWENT() to
return NULL outside cleanup().
diff mbox series

Patch

diff --git a/include/tst_safe_macros.h b/include/tst_safe_macros.h
index 6fd618597..0238a5de7 100644
--- a/include/tst_safe_macros.h
+++ b/include/tst_safe_macros.h
@@ -625,4 +625,10 @@  int safe_sysinfo(const char *file, const int lineno, struct sysinfo *info);
 #define SAFE_SYSINFO(info) \
 	safe_sysinfo(__FILE__, __LINE__, (info))
 
+struct passwd *safe_getpwent(const char *file, const int lineno);
+#define SAFE_GETPWENT() safe_getpwent(__FILE__, __LINE__)
+
+struct group *safe_getgrent(const char *file, const int lineno);
+#define SAFE_GETGRENT() safe_getgrent(__FILE__, __LINE__)
+
 #endif /* SAFE_MACROS_H__ */
diff --git a/include/tst_uid.h b/include/tst_uid.h
index 7135a9cad..a3bacf64a 100644
--- a/include/tst_uid.h
+++ b/include/tst_uid.h
@@ -15,4 +15,21 @@ 
 gid_t tst_get_free_gid_(const char *file, const int lineno, gid_t skip);
 #define tst_get_free_gid(skip) tst_get_free_gid_(__FILE__, __LINE__, (skip))
 
+/*
+ * Get a specific number of unique existing non-root user or group IDs.
+ * Multiple calls will return additional results, if any. Both functions call
+ * SAFE_GETPWENT() and SAFE_GETGRENT() respectively.
+ * Call endpwent()/endgrent() after the last use of these functions.
+ * Call setpwent()/setgrent() to read user/group IDs from the beginning again.
+ */
+int tst_get_uids_(const char *file, const int lineno, unsigned int count,
+	uid_t *buf);
+#define tst_get_uids(count, buf) \
+	tst_get_uids_(__FILE__, __LINE__, (count), (buf))
+
+int tst_get_gids_(const char *file, const int lineno, unsigned int count,
+	gid_t *buf);
+#define tst_get_gids(count, buf) \
+	tst_get_gids_(__FILE__, __LINE__, (count), (buf))
+
 #endif /* TST_UID_H_ */
diff --git a/lib/tst_uid.c b/lib/tst_uid.c
index dd719d312..915a5bc34 100644
--- a/lib/tst_uid.c
+++ b/lib/tst_uid.c
@@ -3,8 +3,10 @@ 
  * Copyright (c) 2021 Linux Test Project
  */
 
+#define _XOPEN_SOURCE 500
 #include <sys/types.h>
 #include <grp.h>
+#include <pwd.h>
 #include <errno.h>
 
 #define TST_NO_DEFAULT_MAIN
@@ -36,3 +38,101 @@  gid_t tst_get_free_gid_(const char *file, const int lineno, gid_t skip)
 	tst_brk_(file, lineno, TBROK, "No free group ID found");
 	return (gid_t)-1;
 }
+
+struct passwd *safe_getpwent(const char *file, const int lineno)
+{
+	struct passwd *ret;
+
+	errno = 0;
+	ret = getpwent();
+
+	if (!ret) {
+		if (errno) {
+			tst_brk_(file, lineno, TBROK | TERRNO,
+				"getpwent() failed");
+		} else {
+			tst_brk_(file, lineno, TBROK,
+				"getpwent() failed: end of file");
+		}
+	}
+
+	return ret;
+}
+
+struct group *safe_getgrent(const char *file, const int lineno)
+{
+	struct group *ret;
+
+	errno = 0;
+	ret = getgrent();
+
+	if (!ret) {
+		if (errno) {
+			tst_brk_(file, lineno, TBROK | TERRNO,
+				"getgrent() failed");
+		} else {
+			tst_brk_(file, lineno, TBROK,
+				"getgrent() failed: end of file");
+		}
+	}
+
+	return ret;
+}
+
+int tst_get_uids_(const char *file, const int lineno, unsigned int count,
+	uid_t *buf)
+{
+	struct passwd *pw;
+	unsigned int i, j;
+
+	for (i = 0; i < count;) {
+		pw = safe_getpwent(file, lineno);
+
+		if (!pw)
+			return -1;
+
+		if (!pw->pw_uid)
+			continue;
+
+		for (j = 0; j < i; j++) {
+			if (buf[j] == pw->pw_uid)
+				break;
+		}
+
+		if (j < i)
+			continue;
+
+		buf[i++] = pw->pw_uid;
+	}
+
+	return 0;
+}
+
+int tst_get_gids_(const char *file, const int lineno, unsigned int count,
+	gid_t *buf)
+{
+	struct group *gr;
+	unsigned int i, j;
+
+	for (i = 0; i < count;) {
+		gr = safe_getgrent(file, lineno);
+
+		if (!gr)
+			return -1;
+
+		if (!gr->gr_gid)
+			continue;
+
+		for (j = 0; j < i; j++) {
+			if (buf[j] == gr->gr_gid)
+				break;
+		}
+
+		if (j < i)
+			continue;
+
+		buf[i++] = gr->gr_gid;
+	}
+
+	return 0;
+}