#include <grp.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "idmap.h"
struct idMap_s {
struct idElement * byId;
int numEntries;
};
typedef struct idMap_s * idMap;
struct idElement {
long int id;
char * name;
};
typedef void * (*iterFn)(void);
typedef int (*infoFn)(void * item, struct idElement * el);
static idMap uidMap = NULL;
static idMap gidMap = NULL;
static int idCmp(const void * a, const void * b) {
const struct idElement * one = a;
const struct idElement * two = b;
if (one->id < two->id)
return -1;
else if (one->id > two->id)
return 1;
return 0;
}
static idMap readmap(iterFn fn, infoFn info) {
idMap map;
int alloced;
void * res;
struct idElement * newEntries;
map = malloc(sizeof(*map));
if (!map) {
return NULL;
}
alloced = 5;
map->byId = malloc(sizeof(*map->byId) * alloced);
if (!map->byId) {
free(map);
return NULL;
}
map->numEntries = 0;
while ((res = fn())) {
if (map->numEntries == alloced) {
alloced += 5;
newEntries = realloc(map->byId,
sizeof(*map->byId) * alloced);
if (!newEntries) {
/* FIXME: this doesn't free the id names */
free(map->byId);
free(map);
return NULL;
}
map->byId = newEntries;
}
if (info(res, map->byId + map->numEntries++)) {
/* FIXME: this doesn't free the id names */
free(map->byId);
free(map);
return NULL;
}
}
map->byId = realloc(map->byId,
sizeof(*map->byId) * map->numEntries);
qsort(map->byId, map->numEntries, sizeof(*map->byId), idCmp);
return map;
}
static int pwInfo(struct passwd * pw, struct idElement * el) {
el->id = pw->pw_uid;
el->name = strdup(pw->pw_name);
return el->name == NULL;
}
static int grInfo(struct group * gr, struct idElement * el) {
el->id = gr->gr_gid;
el->name = strdup(gr->gr_name);
return el->name == NULL;
}
idMap readUIDmap(void) {
idMap result;
result = readmap((void *) getpwent, (void *) pwInfo);
endpwent();
return result;
}
idMap readGIDmap(void) {
idMap result;
result = readmap((void *) getgrent, (void *) grInfo);
endgrent();
return result;
}
char * idSearchByUid(long int id) {
struct idElement el = { id, NULL };
struct idElement * match;
match = bsearch(&el, uidMap->byId, uidMap->numEntries,
sizeof(*uidMap->byId), idCmp);
if (match) return match->name; else return NULL;
}
char * idSearchByGid(long int id) {
struct idElement el = { id, NULL };
struct idElement * match;
match = bsearch(&el, gidMap->byId, gidMap->numEntries,
sizeof(*gidMap->byId), idCmp);
if (match) return match->name; else return NULL;
}
int idInit(void) {
if (!(uidMap = readUIDmap())) return 1;
if (!(gidMap = readGIDmap())) return 1;
return 0;
}