#include <sys/types.h>
#include <grp.h>
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include "test.h"
int getgrgid_r(gid_t, struct group *, char *, size_t, struct group **);
char fail[] = "fail";
pthread_cond_t done;
volatile int done_count;
pthread_mutex_t display;
pthread_mutex_t display2;
static void *
test(void *arg)
{
gid_t gid = *(gid_t *)arg;
gid_t ogid;
struct group grpbuf;
struct group *grp;
char **p;
char buffer[5000];
char buf[2048];
char *cpy[128];
int i;
int count1, count2;
char *s;
char *oname;
char *opasswd;
size_t len;
CHECKr(pthread_mutex_lock(&display));
grpbuf.gr_name = fail;
printf("gid %d\n", gid);
CHECKr(getgrgid_r(gid, &grpbuf, buffer, sizeof(buffer), &grp));
ASSERT(grp->gr_name != fail);
ASSERT(grp->gr_gid == gid);
s = buf;
len = sizeof(buf);
strlcpy(oname = s, grp->gr_name, len);
len -= 1 + strlen(s);
s += 1 + strlen(s);
strlcpy(opasswd = s, grp->gr_passwd, len);
len -= 1 + strlen(s);
s += 1 + strlen(s);
ogid = grp->gr_gid;
for (i = 0, p = grp->gr_mem; *p; p++) {
strlcpy(cpy[i] = s, *p, len);
i++;
len -= 1 + strlen(s);
s += 1 + strlen(s);
}
cpy[i] = NULL;
#if 0
printf("now: %s:%s:%d:", grp->gr_name, grp->gr_passwd, grp->gr_gid);
for (p = grp->gr_mem; *p; p++)
printf("%s%s", *p, *(p+1) == NULL ? "": ",");
printf("\n");
#endif
#ifdef DEBUG
printf("buf = \"");
for (i = 0; i < s - buf; i++)
if (buf[i] == '\0') printf("\\0");
else printf("%c", buf[i]);
printf("\"\n");
#endif
done_count++;
CHECKr(pthread_cond_signal(&done));
CHECKr(pthread_mutex_unlock(&display));
CHECKr(pthread_mutex_lock(&display2));
count1 = 0;
printf("before: %s:%s:%d:", oname, opasswd, ogid);
for (p = cpy; *p; p++) {
count1++;
printf("%s%s", *p, *(p+1) == NULL ? "": ",");
}
printf("\n");
count2 = 0;
printf("after: %s:%s:%d:", grp->gr_name, grp->gr_passwd, grp->gr_gid);
for (p = grp->gr_mem; *p; p++) {
count2++;
printf("%s%s", *p, *(p+1) == NULL ? "": ",");
}
printf("\n");
CHECKr(pthread_mutex_unlock(&display2));
if (count1 != count2)
return "gr_mem length changed";
for (i = 0; i < count1; i++)
if (strcmp(cpy[i], grp->gr_mem[i]) != 0)
return "gr_mem list changed";
if (strcmp(grp->gr_name, oname) != 0)
return "gr_name changed";
if (strcmp(grp->gr_passwd, opasswd) != 0)
return "gr_passwd changed";
if (grp->gr_gid != ogid)
return "gr_gid changed";
return NULL;
}
#define NGRPS 5
int
main(int argc, char *argv[])
{
pthread_t thread[NGRPS];
int gid;
int failed;
void *result;
CHECKr(pthread_mutex_init(&display, NULL));
CHECKr(pthread_mutex_init(&display2, NULL));
CHECKr(pthread_cond_init(&done, NULL));
done_count = 0;
pthread_mutex_lock(&display);
pthread_mutex_lock(&display2);
for (gid = 0; gid < NGRPS; gid++) {
int *n = (int *)malloc(sizeof(int));
*n = gid;
CHECKr(pthread_create(&thread[gid], NULL, test, (void *)n));
}
while (done_count < NGRPS)
pthread_cond_wait(&done, &display);
CHECKr(pthread_mutex_unlock(&display2));
failed = 0;
for (gid = 0; gid < NGRPS; gid++) {
CHECKr(pthread_join(thread[gid], &result));
if (result != NULL) {
fprintf(stderr, "gid %d: %s\n", gid, (char *)result);
failed++;
}
}
if (!failed) {
SUCCEED;
} else {
exit(1);
}
}