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