commit: bd6c19ef913c397e39e091e201c0cef65f0e20bf
parent 25c0414efc8e2f0f9b0e88996136602e28365c6c
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Sat, 12 Mar 2022 03:57:37 +0100
bin/id: Add support for -G
Diffstat:
| M | bin/id.c | 74 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| M | test-bin/id | 11 | +++++++++++ | 
2 files changed, 85 insertions(+), 0 deletions(-)
diff --git a/bin/id.c b/bin/id.c
@@ -16,6 +16,65 @@
 bool name_flag = false;
 
 static int
+simple_list_groups(struct passwd *pw)
+{
+	int ngroups   = (int)sysconf(_SC_NGROUPS_MAX) + 1;
+	gid_t *groups = malloc(sizeof(gid_t) * ngroups);
+	if(groups == NULL)
+	{
+		perror("groups malloc");
+		return 1;
+	}
+
+	// getgrouplist(3) BSD extension might not be in all Unixes
+	int grls = getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
+	for(int i = 0; i < ngroups; i++)
+	{
+		if(name_flag)
+		{
+			struct group *lgr = getgrgid(groups[i]);
+			if(lgr == NULL)
+			{
+				goto failure;
+			}
+
+			int sep = ' ';
+			if(i == ngroups - 1)
+			{
+				sep = '\n';
+			}
+
+			int ret = printf("%s%c", lgr->gr_name, sep);
+			if(ret < 0)
+			{
+				goto failure;
+			}
+		}
+		else
+		{
+			int sep = ' ';
+			if(i == ngroups - 1)
+			{
+				sep = '\n';
+			}
+
+			int ret = printf("%u%c", groups[i], sep);
+			if(ret < 0)
+			{
+				goto failure;
+			}
+		}
+	}
+
+	free(groups);
+	return 0;
+
+failure:
+	free(groups);
+	return 1;
+}
+
+static int
 list_groups(struct passwd *pw)
 {
 	int ngroups   = (int)sysconf(_SC_NGROUPS_MAX) + 1;
@@ -253,6 +312,21 @@ main(int argc, char *argv[])
 	struct passwd *epw = getpwuid(euid);
 	// can return NULL (ie. without /etc/passwd)
 
+	if(G_flag)
+	{
+		if(!real_flag)
+		{
+			pw = epw;
+		}
+
+		if(pw != NULL && simple_list_groups(pw) != 0)
+		{
+			goto failure;
+		}
+
+		return 0;
+	}
+
 	ret = print_uid("uid", pw, uid);
 	if(ret < 0)
 	{
diff --git a/test-bin/id b/test-bin/id
@@ -45,6 +45,16 @@ user_body() {
 	atf_check -o "inline:$(id -unr)\n" ../bin/id -unr
 }
 
+atf_test_case groups
+groups_body() {
+	# sadly GNU coreutils' id(1) sorts it's grouplist
+
+	atf_check -o not-empty ../bin/id -G
+	atf_check -o not-empty ../bin/id -Gr
+	atf_check -o not-empty ../bin/id -Gn
+	atf_check -o not-empty ../bin/id -Gnr
+}
+
 atf_test_case noetc
 noetc_body() {
 	bwrap_args="--bind / / --bind /var/empty /etc"
@@ -80,6 +90,7 @@ atf_init_test_cases() {
 	atf_add_test_case names
 	atf_add_test_case group
 	atf_add_test_case user
+	atf_add_test_case groups
 
 	atf_add_test_case noetc
 }