Skip to content

Instantly share code, notes, and snippets.

@ry
Forked from ThisIsMissEm/gist:421870
Created June 2, 2010 03:22
Show Gist options
  • Save ry/421874 to your computer and use it in GitHub Desktop.
Save ry/421874 to your computer and use it in GitHub Desktop.
// Copyright 2009 Ryan Dahl <ry@tinyclouds.org>
#include <v8.h>
#include <node.h>
#include <node_os.h>
#include <sys/types.h>
#include <sys/time.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <pwd.h> /* getpwuid() */
#include <grp.h> /* getgrgid() */
namespace node {
using namespace v8;
// User
static Persistent<String> username_symbol;
static Persistent<String> password_symbol;
static Persistent<String> uid_symbol;
static Persistent<String> gid_symbol;
static Persistent<String> class_symbol;
static Persistent<String> dir_symbol;
static Persistent<String> shell_symbol;
static Persistent<String> change_symbol;
static Persistent<String> expire_symbol;
static Persistent<String> gecos_symbol;
static Persistent<String> fields_symbol;
// Group
// static Persistent<String> name_symbol;
// static Persistent<String> members_symbol;
// Buffer for getpwnam_r(), getgrpam_r(); keep this scoped at file-level rather
// than method-level to avoid excess stack usage.
static char getbuf[1024];
/*-----------------------------------------------
Constructs a JS::Object from a *passwd
-----------------------------------------------*/
Local<Object> BuildUserObject(struct passwd *u) {
HandleScope scope;
if (username_symbol.IsEmpty()) {
username_symbol = NODE_PSYMBOL("username");
password_symbol = NODE_PSYMBOL("password");
uid_symbol = NODE_PSYMBOL("uid");
gid_symbol = NODE_PSYMBOL("gid");
class_symbol = NODE_PSYMBOL("class");
gecos_symbol = NODE_PSYMBOL("gecos");
dir_symbol = NODE_PSYMBOL("dir");
shell_symbol = NODE_PSYMBOL("shell");
change_symbol = NODE_PSYMBOL("change");
expire_symbol = NODE_PSYMBOL("expire");
}
Local<Object> user = Object::New();
user->Set(username_symbol, String::New(u->pw_name));
user->Set(password_symbol, String::New(u->pw_passwd));
user->Set(uid_symbol, Integer::New(u->pw_uid));
user->Set(gid_symbol, Integer::New(u->pw_gid));
user->Set(class_symbol, String::New(u->pw_class));
user->Set(gecos_symbol, String::New(u->pw_gecos));
user->Set(dir_symbol, String::New(u->pw_dir));
user->Set(shell_symbol, String::New(u->pw_shell));
user->Set(change_symbol, Undefined()); //atldate(u->pw_change/1000));
user->Set(expire_symbol, Undefined());
return scope.Close(user);
}
struct custom_request {
int type; // 0 is with uid, 1 is with uname
int uid;
void *cb;
struct passwd result;
char name[1];
};
static int EIO_AfterGetUser(eio_req *req) {
}
static int EIO_GetUser(eio_req *req) {
struct custom_request *creq = (struct custom_request *)(req->data);
struct passwd pwd, *pwdp = NULL;
int err;
if(creq->type == 0){
if ((err = getpwuid_r(creq->uid, &pwd, getbuf, sizeof(getbuf), &pwdp)) || pwdp == NULL) {
req->errorno = errno;
}
memcpy(&creq->result, pwdp, sizeof(struct passwd));
} else {
if ((err = getpwnam_r(creq->uname, &pwd, getbuf, sizeof(getbuf), &pwdp)) ||
pwdp == NULL) {
req->errorno = errno;
}
memcpy(&creq->result, pwdp, sizeof(struct passwd));
}
return 0;
}
static Handle<Value> GetUser(const Arguments& args) {
HandleScope scope;
if ( args.Length() < 1) {
return THROW_BAD_ARGS;
}
if (args[1]->IsFunction()) {
if (args[0]->IsInt32()) {
struct custom_request *creq = (struct custom_request *)calloc(1, sizeof(struct custom_request));
creq->uid = args[0]->Int32Value();
creq->type = 0;
} else {
String::Utf8Value pwnam(args[0]->ToString());
struct custom_request *creq = (struct custom_request *)calloc(1, sizeof(struct custom_request)+pwnam->length()+1);
strcpy(creq->name, *pwnam);
creq->type = 1;
}
if (!creq) {
V8::LowMemoryNotification();
return ThrowException(Exception::Error(
String::New("Could not allocate enough memory")));
}
creq->cb = cb_persist(args[1]);
//ASYNC_CUSTOM_CALL(blocking_func, callback, data);
ASYNC_CUSTOM_CALL(EIO_GetUser, EIO_AfterGetUser, creq);
return Undefined();
} else {
struct passwd pwd, *pwdp = NULL;
int err;
if (args[0]->IsInt32()) {
if ((err = getpwuid_r(args[0]->Int32Value(), &pwd, getbuf, sizeof(getbuf), &pwdp)) ||
pwdp == NULL) {
return ThrowException(ErrnoException(errno, "getpwuid_r"));
}
} else {
String::Utf8Value pwnam(args[0]->ToString());
if ((err = getpwnam_r(*pwnam, &pwd, getbuf, sizeof(getbuf), &pwdp)) ||
pwdp == NULL) {
return ThrowException(ErrnoException(errno, "getpwnam_r"));
}
}
return scope.Close(BuildUserObject(*&pwdp));
}
}
/*
Local<Object> BuildGroupObject(struct group *g) {
HandleScope scope;
if (name_symbol.IsEmpty()) {
name_symbol = NODE_PSYMBOL("name");
password_symbol = NODE_PSYMBOL("password");
gid_symbol = NODE_PSYMBOL("gid");
members_symbol = NODE_PSYMBOL("members");
}
Local<Object> group = Object::New();
group->Set(name_symbol, String::New(g->gr_name));
group->Set(password_symbol, String::New(g->gr_passwd));
group->Set(gid_symbol, Integer::New(g->gr_gid));
// group->Set(members_symbol, String::New(g->gr_mem[1]));
return scope.Close(group);
}
static Handle<Value> GetGroup(const Arguments& args) {
HandleScope scope;
if ( args.Length() < 1) {
return THROW_BAD_ARGS;
}
if (args[1]->IsFunction()) {
// Handle with EIO_CUSTOM
return Undefined();
} else {
if (args[0]->IsString()) {
String::Utf8Value grpnam(args[0]->ToString());
struct group grp, *grpp = NULL;
int err;
if ((err = getgrnam_r(*grpnam, &grp, getbuf, sizeof(getbuf), &grpp)) ||
grpp == NULL) {
return ThrowException(ErrnoException(errno, "getgrnam_r"));
}
//uid = (pwdp->pw_uid);
return scope.Close(BuildGroupObject(*&grpp));
} else {
return Undefined();
}
}
}
*/
void Os::Initialize(Handle<Object> target) {
HandleScope scope;
NODE_SET_METHOD(target, "getUser", GetUser);
// NODE_SET_METHOD(target, "getGroup", GetGroup);
}
} // end namespace node
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment