xref: /openbsd-src/regress/lib/libpthread/group/group.c (revision 8500990981f885cbe5e6a4958549cacc238b5ae6)
1 /*	$OpenBSD: group.c,v 1.5 2003/07/31 21:48:04 deraadt 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 
44 	/* Acquire lock for running first part. */
45 	CHECKr(pthread_mutex_lock(&display));
46 
47 	/* Store magic name to test for non-alteration */
48 	grpbuf.gr_name = fail;
49 
50 	/* Call getgrgid_r() */
51 	printf("gid %d\n", gid);
52 	CHECKr(getgrgid_r(gid, &grpbuf, buffer, sizeof(buffer), &grp));
53 
54 	/* Test for non-alteration of group structure */
55 	ASSERT(grp->gr_name != fail);
56 
57 	/* We must get the right group */
58 	ASSERT(grp->gr_gid == gid);
59 
60 	s = buf;	/* Keep our private buffer on the stack */
61 
62 	/* copy gr_name */
63 	strcpy(oname = s, grp->gr_name);
64 	s += 1 + strlen(s);
65 
66 	/* copy gr_passwd */
67 	strcpy(opasswd = s, grp->gr_passwd);
68 	s += 1 + strlen(s);
69 
70 	/* copy gr_gid */
71 	ogid = grp->gr_gid;
72 
73 	/* copy gr_mem */
74 	for (i = 0, p = grp->gr_mem; *p; p++) {
75 		strcpy(cpy[i] = s, *p); i++;
76 		s += 1 + strlen(s);
77 	}
78 	cpy[i] = NULL;
79 
80 #if 0
81 	printf("now:    %s:%s:%d:", grp->gr_name, grp->gr_passwd, grp->gr_gid);
82 	for (p = grp->gr_mem; *p; p++)
83 		printf("%s%s", *p, *(p+1) == NULL ? "": ",");
84 	printf("\n");
85 #endif
86 
87 #ifdef DEBUG /* debugging this program */
88 	printf("buf = \"");
89 	for (i = 0; i < s - buf; i++)
90 		if (buf[i] == '\0')	printf("\\0");
91 		else printf("%c", buf[i]);
92 	printf("\"\n");
93 #endif
94 
95 	/* Inform main that we have finished */
96 	done_count++;
97 	CHECKr(pthread_cond_signal(&done));
98 
99 	/* Allow other threads to run first part */
100 	CHECKr(pthread_mutex_unlock(&display));
101 
102 	/* Acquire lock for the second part */
103 	CHECKr(pthread_mutex_lock(&display2));
104 
105 	count1 = 0;
106 	printf("before: %s:%s:%d:", oname, opasswd, ogid);
107 	for (p = cpy; *p; p++)  {
108 		count1++;
109 		printf("%s%s", *p, *(p+1) == NULL ? "": ",");
110 	}
111 	printf("\n");
112 
113 	count2 = 0;
114 	printf("after:  %s:%s:%d:", grp->gr_name, grp->gr_passwd, grp->gr_gid);
115 	for (p = grp->gr_mem; *p; p++)  {
116 		count2++;
117 		printf("%s%s", *p, *(p+1) == NULL ? "": ",");
118 	}
119 	printf("\n");
120 
121 	CHECKr(pthread_mutex_unlock(&display2));
122 
123 	if (count1 != count2)
124 		return "gr_mem length changed";
125 	for (i = 0; i < count1; i++)
126 		if (strcmp(cpy[i], grp->gr_mem[i]) != 0)
127 			return "gr_mem list changed";
128 	if (strcmp(grp->gr_name, oname) != 0)
129 		return "gr_name changed";
130 	if (strcmp(grp->gr_passwd, opasswd) != 0)
131 		return "gr_passwd changed";
132 	if (grp->gr_gid != ogid)
133 		return "gr_gid changed";
134 	return NULL;
135 }
136 
137 
138 #define NGRPS	5
139 int
140 main(int argc, char *argv[])
141 {
142 	pthread_t thread[NGRPS];
143 	int gid;
144 	int failed;
145 	void *result;
146 
147 	CHECKr(pthread_mutex_init(&display, NULL));
148 	CHECKr(pthread_mutex_init(&display2, NULL));
149 
150 	CHECKr(pthread_cond_init(&done, NULL));
151 	done_count = 0;
152 
153 	pthread_mutex_lock(&display);
154 	pthread_mutex_lock(&display2);
155 
156 	/* Get separate threads to do a group open separately */
157 	for (gid = 0; gid < NGRPS; gid++) {
158 		int *n = (int *)malloc(sizeof(int));
159 		*n = gid;
160 
161 		CHECKr(pthread_create(&thread[gid], NULL, test, (void *)n));
162 	}
163 
164 	/* Allow all threads to run their first part */
165 	while (done_count < NGRPS)
166 		pthread_cond_wait(&done, &display);
167 
168 	/* Allow each thread to run the 2nd part of its test */
169 	CHECKr(pthread_mutex_unlock(&display2));
170 
171 	/* Wait for each thread to terminate, collecting results. */
172 	failed = 0;
173 	for (gid = 0; gid < NGRPS; gid++) {
174 		CHECKr(pthread_join(thread[gid], &result));
175 		if (result != NULL) {
176 			fprintf(stderr, "gid %d: %s\n", gid, (char *)result);
177 			failed++;
178 		}
179 	}
180 
181 	if (!failed) {
182 		SUCCEED;
183 	} else {
184 		exit(1);
185 	}
186 }
187