xref: /openbsd/regress/lib/libpthread/group/group.c (revision 09467b48)
1 /*	$OpenBSD: group.c,v 1.6 2005/10/30 23:59:43 fgsch Exp $	*/
2 
3 /* David Leonard <d@openbsd.org>, 2001. Public Domain. */
4 
5 /*
6  * Test getgrgid_r() across multiple threads to see if the members list changes.
7  */
8 
9 #include <sys/types.h>
10 #include <grp.h>
11 #include <pthread.h>
12 #include <unistd.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include "test.h"
16 
17 int	getgrgid_r(gid_t, struct group *, char *, size_t, struct group **);
18 
19 char fail[] = "fail";
20 
21 pthread_cond_t done;
22 volatile int done_count;
23 
24 pthread_mutex_t display;
25 pthread_mutex_t display2;
26 
27 static void *
28 test(void *arg)
29 {
30 	gid_t gid = *(gid_t *)arg;
31 	gid_t ogid;
32 	struct group grpbuf;
33 	struct group *grp;
34 	char **p;
35 	char buffer[5000];
36 	char buf[2048];
37 	char *cpy[128];
38 	int i;
39 	int count1, count2;
40 	char *s;
41 	char *oname;
42 	char *opasswd;
43 	size_t len;
44 
45 	/* Acquire lock for running first part. */
46 	CHECKr(pthread_mutex_lock(&display));
47 
48 	/* Store magic name to test for non-alteration */
49 	grpbuf.gr_name = fail;
50 
51 	/* Call getgrgid_r() */
52 	printf("gid %d\n", gid);
53 	CHECKr(getgrgid_r(gid, &grpbuf, buffer, sizeof(buffer), &grp));
54 
55 	/* Test for non-alteration of group structure */
56 	ASSERT(grp->gr_name != fail);
57 
58 	/* We must get the right group */
59 	ASSERT(grp->gr_gid == gid);
60 
61 	s = buf;	/* Keep our private buffer on the stack */
62 	len = sizeof(buf);
63 
64 	/* copy gr_name */
65 	strlcpy(oname = s, grp->gr_name, len);
66 	len -= 1 + strlen(s);
67 	s += 1 + strlen(s);
68 
69 	/* copy gr_passwd */
70 	strlcpy(opasswd = s, grp->gr_passwd, len);
71 	len -= 1 + strlen(s);
72 	s += 1 + strlen(s);
73 
74 	/* copy gr_gid */
75 	ogid = grp->gr_gid;
76 
77 	/* copy gr_mem */
78 	for (i = 0, p = grp->gr_mem; *p; p++) {
79 		strlcpy(cpy[i] = s, *p, len);
80 		i++;
81 		len -= 1 + strlen(s);
82 		s += 1 + strlen(s);
83 	}
84 	cpy[i] = NULL;
85 
86 #if 0
87 	printf("now:    %s:%s:%d:", grp->gr_name, grp->gr_passwd, grp->gr_gid);
88 	for (p = grp->gr_mem; *p; p++)
89 		printf("%s%s", *p, *(p+1) == NULL ? "": ",");
90 	printf("\n");
91 #endif
92 
93 #ifdef DEBUG /* debugging this program */
94 	printf("buf = \"");
95 	for (i = 0; i < s - buf; i++)
96 		if (buf[i] == '\0')	printf("\\0");
97 		else printf("%c", buf[i]);
98 	printf("\"\n");
99 #endif
100 
101 	/* Inform main that we have finished */
102 	done_count++;
103 	CHECKr(pthread_cond_signal(&done));
104 
105 	/* Allow other threads to run first part */
106 	CHECKr(pthread_mutex_unlock(&display));
107 
108 	/* Acquire lock for the second part */
109 	CHECKr(pthread_mutex_lock(&display2));
110 
111 	count1 = 0;
112 	printf("before: %s:%s:%d:", oname, opasswd, ogid);
113 	for (p = cpy; *p; p++)  {
114 		count1++;
115 		printf("%s%s", *p, *(p+1) == NULL ? "": ",");
116 	}
117 	printf("\n");
118 
119 	count2 = 0;
120 	printf("after:  %s:%s:%d:", grp->gr_name, grp->gr_passwd, grp->gr_gid);
121 	for (p = grp->gr_mem; *p; p++)  {
122 		count2++;
123 		printf("%s%s", *p, *(p+1) == NULL ? "": ",");
124 	}
125 	printf("\n");
126 
127 	CHECKr(pthread_mutex_unlock(&display2));
128 
129 	if (count1 != count2)
130 		return "gr_mem length changed";
131 	for (i = 0; i < count1; i++)
132 		if (strcmp(cpy[i], grp->gr_mem[i]) != 0)
133 			return "gr_mem list changed";
134 	if (strcmp(grp->gr_name, oname) != 0)
135 		return "gr_name changed";
136 	if (strcmp(grp->gr_passwd, opasswd) != 0)
137 		return "gr_passwd changed";
138 	if (grp->gr_gid != ogid)
139 		return "gr_gid changed";
140 	return NULL;
141 }
142 
143 
144 #define NGRPS	5
145 int
146 main(int argc, char *argv[])
147 {
148 	pthread_t thread[NGRPS];
149 	int gid;
150 	int failed;
151 	void *result;
152 
153 	CHECKr(pthread_mutex_init(&display, NULL));
154 	CHECKr(pthread_mutex_init(&display2, NULL));
155 
156 	CHECKr(pthread_cond_init(&done, NULL));
157 	done_count = 0;
158 
159 	pthread_mutex_lock(&display);
160 	pthread_mutex_lock(&display2);
161 
162 	/* Get separate threads to do a group open separately */
163 	for (gid = 0; gid < NGRPS; gid++) {
164 		int *n = (int *)malloc(sizeof(int));
165 		*n = gid;
166 
167 		CHECKr(pthread_create(&thread[gid], NULL, test, (void *)n));
168 	}
169 
170 	/* Allow all threads to run their first part */
171 	while (done_count < NGRPS)
172 		pthread_cond_wait(&done, &display);
173 
174 	/* Allow each thread to run the 2nd part of its test */
175 	CHECKr(pthread_mutex_unlock(&display2));
176 
177 	/* Wait for each thread to terminate, collecting results. */
178 	failed = 0;
179 	for (gid = 0; gid < NGRPS; gid++) {
180 		CHECKr(pthread_join(thread[gid], &result));
181 		if (result != NULL) {
182 			fprintf(stderr, "gid %d: %s\n", gid, (char *)result);
183 			failed++;
184 		}
185 	}
186 
187 	if (!failed) {
188 		SUCCEED;
189 	} else {
190 		exit(1);
191 	}
192 }
193