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