static int hadoop_group_info_fetch_nonreentrant( struct hadoop_group_info *ginfo, gid_t gid) { struct group *group; int i, num_users = 0; char **g; do { errno = 0; group = getgrgid(gid); } while ((!group) && (errno == EINTR)); if (!group) { return getgrgid_error_translate(errno); } ginfo->group.gr_name = strdup(group->gr_name); if (!ginfo->group.gr_name) { hadoop_group_info_clear(ginfo); return ENOMEM; } ginfo->group.gr_passwd = strdup(group->gr_passwd); if (!ginfo->group.gr_passwd) { hadoop_group_info_clear(ginfo); return ENOMEM; } ginfo->group.gr_gid = group->gr_gid; if (group->gr_mem) { for (g = group->gr_mem, num_users = 0; *g; g++) { num_users++; } } ginfo->group.gr_mem = calloc(num_users + 1, sizeof(char *)); if (!ginfo->group.gr_mem) { hadoop_group_info_clear(ginfo); return ENOMEM; } for (i = 0; i < num_users; i++) { ginfo->group.gr_mem[i] = strdup(group->gr_mem[i]); if (!ginfo->group.gr_mem[i]) { hadoop_group_info_clear(ginfo); return ENOMEM; } } return 0; }
void hadoop_group_info_free(struct hadoop_group_info *ginfo) { if (!ginfo->buf_sz) { hadoop_group_info_clear(ginfo); } else { free(ginfo->buf); } free(ginfo); }
int hadoop_group_info_fetch(struct hadoop_group_info *ginfo, gid_t gid) { int ret; hadoop_group_info_clear(ginfo); if (!ginfo->buf_sz) { static pthread_mutex_t g_getgrnam_lock = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&g_getgrnam_lock); ret = hadoop_group_info_fetch_nonreentrant(ginfo, gid); pthread_mutex_unlock(&g_getgrnam_lock); return ret; } else { return hadoop_group_info_fetch_reentrant(ginfo, gid); } }
int hadoop_group_info_fetch(struct hadoop_group_info *ginfo, gid_t gid) { struct group *group; int ret; size_t buf_sz; char *nbuf; hadoop_group_info_clear(ginfo); for (;;) { // On success, the following call returns 0 and group is set to non-NULL. group = NULL; ret = getgrgid_r(gid, &ginfo->group, ginfo->buf, ginfo->buf_sz, &group); switch(ret) { case 0: if (!group) { // Not found. return ENOENT; } // Found. return 0; case EINTR: // EINTR: a signal was handled and this thread was allowed to continue. break; case ERANGE: // ERANGE: the buffer was not big enough. if (ginfo->buf_sz == MAX_GROUP_BUFFER_SIZE) { // Already tried with the max size. return ENOMEM; } buf_sz = ginfo->buf_sz * 2; if (buf_sz > MAX_GROUP_BUFFER_SIZE) { buf_sz = MAX_GROUP_BUFFER_SIZE; } nbuf = realloc(ginfo->buf, buf_sz); if (!nbuf) { return ENOMEM; } ginfo->buf = nbuf; ginfo->buf_sz = buf_sz; break; default: // Lookup failed. return getgrgid_error_translate(ret); } } }