Skip to content

Commit d6e56fd

Browse files
committedApr 12, 2016
os: add userInfo() method
os.userInfo() calls libuv's uv_os_get_passwd() function. It returns an object containing the current effective user's username, uid, gid, shell, and home directory. On Windows, the uid and gid are -1, and the shell is null. Refs: #5582 PR-URL: #6104 Reviewed-By: James M Snell <[email protected]>
1 parent aba035f commit d6e56fd

File tree

5 files changed

+114
-0
lines changed

5 files changed

+114
-0
lines changed
 

‎doc/api/os.markdown

+16
Original file line numberDiff line numberDiff line change
@@ -182,5 +182,21 @@ on OS X and `'Windows_NT'` on Windows.
182182

183183
Returns the system uptime in seconds.
184184

185+
## os.userInfo([options])
186+
187+
* `options` {Object}
188+
* `encoding` {String} Character encoding used to interpret resulting strings.
189+
If `encoding` is set to `'buffer'`, the `username`, `shell`, and `homedir`
190+
values will be `Buffer` instances. (Default: 'utf8')
191+
192+
Returns a subset of the password file entry for the current effective user. The
193+
returned object includes the `username`, `uid`, `gid`, `shell`, and `homedir`.
194+
On Windows, the `uid` and `gid` fields are `-1`, and `shell` is `null`.
195+
196+
The value of `homedir` returned by `userInfo()` comes directly from the
197+
operating system. This differs from the result of `os.homedir()`, which queries
198+
several environment variables for the home directory before falling back to the
199+
operating system response.
200+
185201
[`process.arch`]: process.html#process_process_arch
186202
[`process.platform`]: process.html#process_process_platform

‎lib/os.js

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ exports.type = binding.getOSType;
1414
exports.release = binding.getOSRelease;
1515
exports.networkInterfaces = binding.getInterfaceAddresses;
1616
exports.homedir = binding.getHomeDirectory;
17+
exports.userInfo = binding.getUserInfo;
1718

1819

1920
exports.arch = function() {

‎src/env.h

+4
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ namespace node {
9494
V(exchange_string, "exchange") \
9595
V(idle_string, "idle") \
9696
V(irq_string, "irq") \
97+
V(encoding_string, "encoding") \
9798
V(enter_string, "enter") \
9899
V(env_pairs_string, "envPairs") \
99100
V(env_string, "env") \
@@ -121,6 +122,7 @@ namespace node {
121122
V(handle_string, "handle") \
122123
V(heap_total_string, "heapTotal") \
123124
V(heap_used_string, "heapUsed") \
125+
V(homedir_string, "homedir") \
124126
V(hostmaster_string, "hostmaster") \
125127
V(ignore_string, "ignore") \
126128
V(immediate_callback_string, "_immediateCallback") \
@@ -206,6 +208,7 @@ namespace node {
206208
V(service_string, "service") \
207209
V(servername_string, "servername") \
208210
V(session_id_string, "sessionId") \
211+
V(shell_string, "shell") \
209212
V(signal_string, "signal") \
210213
V(size_string, "size") \
211214
V(sni_context_err_string, "Invalid SNI context") \
@@ -235,6 +238,7 @@ namespace node {
235238
V(uid_string, "uid") \
236239
V(unknown_string, "<unknown>") \
237240
V(user_string, "user") \
241+
V(username_string, "username") \
238242
V(uv_string, "uv") \
239243
V(valid_from_string, "valid_from") \
240244
V(valid_to_string, "valid_to") \

‎src/node_os.cc

+69
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "v8.h"
33
#include "env.h"
44
#include "env-inl.h"
5+
#include "string_bytes.h"
56

67
#include <errno.h>
78
#include <string.h>
@@ -32,6 +33,7 @@ using v8::Context;
3233
using v8::FunctionCallbackInfo;
3334
using v8::Integer;
3435
using v8::Local;
36+
using v8::Null;
3537
using v8::Number;
3638
using v8::Object;
3739
using v8::String;
@@ -290,6 +292,72 @@ static void GetHomeDirectory(const FunctionCallbackInfo<Value>& args) {
290292
}
291293

292294

295+
static void GetUserInfo(const FunctionCallbackInfo<Value>& args) {
296+
Environment* env = Environment::GetCurrent(args);
297+
uv_passwd_t pwd;
298+
enum encoding encoding;
299+
300+
if (args[0]->IsObject()) {
301+
Local<Object> options = args[0].As<Object>();
302+
Local<Value> encoding_opt = options->Get(env->encoding_string());
303+
encoding = ParseEncoding(env->isolate(), encoding_opt, UTF8);
304+
} else {
305+
encoding = UTF8;
306+
}
307+
308+
const int err = uv_os_get_passwd(&pwd);
309+
310+
if (err) {
311+
return env->ThrowUVException(err, "uv_os_get_passwd");
312+
}
313+
314+
Local<Value> uid = Number::New(env->isolate(), pwd.uid);
315+
Local<Value> gid = Number::New(env->isolate(), pwd.gid);
316+
Local<Value> username = StringBytes::Encode(env->isolate(),
317+
pwd.username,
318+
encoding);
319+
Local<Value> homedir = StringBytes::Encode(env->isolate(),
320+
pwd.homedir,
321+
encoding);
322+
Local<Value> shell;
323+
324+
if (pwd.shell == NULL)
325+
shell = Null(env->isolate());
326+
else
327+
shell = StringBytes::Encode(env->isolate(), pwd.shell, encoding);
328+
329+
uv_os_free_passwd(&pwd);
330+
331+
if (username.IsEmpty()) {
332+
return env->ThrowUVException(UV_EINVAL,
333+
"uv_os_get_passwd",
334+
"Invalid character encoding for username");
335+
}
336+
337+
if (homedir.IsEmpty()) {
338+
return env->ThrowUVException(UV_EINVAL,
339+
"uv_os_get_passwd",
340+
"Invalid character encoding for homedir");
341+
}
342+
343+
if (shell.IsEmpty()) {
344+
return env->ThrowUVException(UV_EINVAL,
345+
"uv_os_get_passwd",
346+
"Invalid character encoding for shell");
347+
}
348+
349+
Local<Object> entry = Object::New(env->isolate());
350+
351+
entry->Set(env->uid_string(), uid);
352+
entry->Set(env->gid_string(), gid);
353+
entry->Set(env->username_string(), username);
354+
entry->Set(env->homedir_string(), homedir);
355+
entry->Set(env->shell_string(), shell);
356+
357+
args.GetReturnValue().Set(entry);
358+
}
359+
360+
293361
void Initialize(Local<Object> target,
294362
Local<Value> unused,
295363
Local<Context> context) {
@@ -304,6 +372,7 @@ void Initialize(Local<Object> target,
304372
env->SetMethod(target, "getOSRelease", GetOSRelease);
305373
env->SetMethod(target, "getInterfaceAddresses", GetInterfaceAddresses);
306374
env->SetMethod(target, "getHomeDirectory", GetHomeDirectory);
375+
env->SetMethod(target, "getUserInfo", GetUserInfo);
307376
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "isBigEndian"),
308377
Boolean::New(env->isolate(), IsBigEndian()));
309378
}

‎test/parallel/test-os.js

+24
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,27 @@ if (common.isWindows && process.env.USERPROFILE) {
125125
assert.ok(os.homedir().indexOf(path.sep) !== -1);
126126
process.env.HOME = home;
127127
}
128+
129+
const pwd = os.userInfo();
130+
const pwdBuf = os.userInfo({ encoding: 'buffer' });
131+
132+
if (common.isWindows) {
133+
assert.strictEqual(pwd.uid, -1);
134+
assert.strictEqual(pwd.gid, -1);
135+
assert.strictEqual(pwd.shell, null);
136+
assert.strictEqual(pwdBuf.uid, -1);
137+
assert.strictEqual(pwdBuf.gid, -1);
138+
assert.strictEqual(pwdBuf.shell, null);
139+
} else {
140+
assert.strictEqual(typeof pwd.uid, 'number');
141+
assert.strictEqual(typeof pwd.gid, 'number');
142+
assert.notStrictEqual(pwd.shell.indexOf(path.sep), -1);
143+
assert.strictEqual(pwd.uid, pwdBuf.uid);
144+
assert.strictEqual(pwd.gid, pwdBuf.gid);
145+
assert.strictEqual(pwd.shell, pwdBuf.shell.toString('utf8'));
146+
}
147+
148+
assert.strictEqual(typeof pwd.username, 'string');
149+
assert.notStrictEqual(pwd.homedir.indexOf(path.sep), -1);
150+
assert.strictEqual(pwd.username, pwdBuf.username.toString('utf8'));
151+
assert.strictEqual(pwd.homedir, pwdBuf.homedir.toString('utf8'));

0 commit comments

Comments
 (0)
Please sign in to comment.