GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/node_os.cc Lines: 166 177 93.8 %
Date: 2017-06-14 Branches: 43 66 65.2 %

Line Branch Exec Source
1
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22
#include "node.h"
23
#include "v8.h"
24
#include "env.h"
25
#include "env-inl.h"
26
#include "string_bytes.h"
27
28
#include <errno.h>
29
#include <string.h>
30
31
#ifdef __MINGW32__
32
# include <io.h>
33
#endif  // __MINGW32__
34
35
#ifdef __POSIX__
36
# include <limits.h>        // PATH_MAX on Solaris.
37
# include <netdb.h>         // MAXHOSTNAMELEN on Solaris.
38
# include <unistd.h>        // gethostname, sysconf
39
# include <sys/param.h>     // MAXHOSTNAMELEN on Linux and the BSDs.
40
# include <sys/utsname.h>
41
#endif  // __POSIX__
42
43
// Add Windows fallback.
44
#ifndef MAXHOSTNAMELEN
45
# define MAXHOSTNAMELEN 256
46
#endif  // MAXHOSTNAMELEN
47
48
namespace node {
49
namespace os {
50
51
using v8::Array;
52
using v8::ArrayBuffer;
53
using v8::Boolean;
54
using v8::Context;
55
using v8::Float64Array;
56
using v8::Function;
57
using v8::FunctionCallbackInfo;
58
using v8::Integer;
59
using v8::Local;
60
using v8::MaybeLocal;
61
using v8::Null;
62
using v8::Number;
63
using v8::Object;
64
using v8::String;
65
using v8::Value;
66
67
68
3
static void GetHostname(const FunctionCallbackInfo<Value>& args) {
69
3
  Environment* env = Environment::GetCurrent(args);
70
  char buf[MAXHOSTNAMELEN + 1];
71
72
3
  if (gethostname(buf, sizeof(buf))) {
73
#ifdef __POSIX__
74
    int errorno = errno;
75
#else  // __MINGW32__
76
    int errorno = WSAGetLastError();
77
#endif  // __POSIX__
78
3
    return env->ThrowErrnoException(errorno, "gethostname");
79
  }
80
3
  buf[sizeof(buf) - 1] = '\0';
81
82
9
  args.GetReturnValue().Set(OneByteString(env->isolate(), buf));
83
}
84
85
86
4
static void GetOSType(const FunctionCallbackInfo<Value>& args) {
87
4
  Environment* env = Environment::GetCurrent(args);
88
  const char* rval;
89
90
#ifdef __POSIX__
91
  struct utsname info;
92
4
  if (uname(&info) < 0) {
93
4
    return env->ThrowErrnoException(errno, "uname");
94
  }
95
4
  rval = info.sysname;
96
#else  // __MINGW32__
97
  rval = "Windows_NT";
98
#endif  // __POSIX__
99
100
12
  args.GetReturnValue().Set(OneByteString(env->isolate(), rval));
101
}
102
103
104
3
static void GetOSRelease(const FunctionCallbackInfo<Value>& args) {
105
3
  Environment* env = Environment::GetCurrent(args);
106
  const char* rval;
107
108
#ifdef __POSIX__
109
  struct utsname info;
110
3
  if (uname(&info) < 0) {
111
3
    return env->ThrowErrnoException(errno, "uname");
112
  }
113
# ifdef _AIX
114
  char release[256];
115
  snprintf(release, sizeof(release),
116
           "%s.%s", info.version, info.release);
117
  rval = release;
118
# else
119
3
  rval = info.release;
120
# endif
121
#else  // Windows
122
  char release[256];
123
  OSVERSIONINFOW info;
124
125
  info.dwOSVersionInfoSize = sizeof(info);
126
127
  // Don't complain that GetVersionEx is deprecated; there is no alternative.
128
  #pragma warning(suppress : 4996)
129
  if (GetVersionExW(&info) == 0)
130
    return;
131
132
  snprintf(release,
133
           sizeof(release),
134
           "%d.%d.%d",
135
           static_cast<int>(info.dwMajorVersion),
136
           static_cast<int>(info.dwMinorVersion),
137
           static_cast<int>(info.dwBuildNumber));
138
  rval = release;
139
#endif  // __POSIX__
140
141
9
  args.GetReturnValue().Set(OneByteString(env->isolate(), rval));
142
}
143
144
145
1900
static void GetCPUInfo(const FunctionCallbackInfo<Value>& args) {
146
1900
  Environment* env = Environment::GetCurrent(args);
147
  uv_cpu_info_t* cpu_infos;
148
  int count, i, field_idx;
149
150
1900
  int err = uv_cpu_info(&cpu_infos, &count);
151
1900
  if (err)
152
1900
    return;
153
154
3800
  CHECK(args[0]->IsFunction());
155
3800
  Local<Function> addfn = args[0].As<Function>();
156
157
3800
  CHECK(args[1]->IsFloat64Array());
158
3800
  Local<Float64Array> array = args[1].As<Float64Array>();
159
1900
  CHECK_EQ(array->Length(), 6 * NODE_PUSH_VAL_TO_ARRAY_MAX);
160
1900
  Local<ArrayBuffer> ab = array->Buffer();
161
1900
  double* fields = static_cast<double*>(ab->GetContents().Data());
162
163
3800
  CHECK(args[2]->IsArray());
164
3800
  Local<Array> cpus = args[2].As<Array>();
165
166
17100
  Local<Value> model_argv[NODE_PUSH_VAL_TO_ARRAY_MAX];
167
1900
  int model_idx = 0;
168
169
17100
  for (i = 0, field_idx = 0; i < count; i++) {
170
15200
    uv_cpu_info_t* ci = cpu_infos + i;
171
172
15200
    fields[field_idx++] = ci->speed;
173
15200
    fields[field_idx++] = ci->cpu_times.user;
174
15200
    fields[field_idx++] = ci->cpu_times.nice;
175
15200
    fields[field_idx++] = ci->cpu_times.sys;
176
15200
    fields[field_idx++] = ci->cpu_times.idle;
177
15200
    fields[field_idx++] = ci->cpu_times.irq;
178
30400
    model_argv[model_idx++] = OneByteString(env->isolate(), ci->model);
179
180
15200
    if (model_idx >= NODE_PUSH_VAL_TO_ARRAY_MAX) {
181
5700
      addfn->Call(env->context(), cpus, model_idx, model_argv).ToLocalChecked();
182
1900
      model_idx = 0;
183
1900
      field_idx = 0;
184
    }
185
  }
186
187
1900
  if (model_idx > 0) {
188
    addfn->Call(env->context(), cpus, model_idx, model_argv).ToLocalChecked();
189
  }
190
191
1900
  uv_free_cpu_info(cpu_infos, count);
192
3800
  args.GetReturnValue().Set(cpus);
193
}
194
195
196
1
static void GetFreeMemory(const FunctionCallbackInfo<Value>& args) {
197
1
  double amount = uv_get_free_memory();
198
1
  if (amount < 0)
199
1
    return;
200
2
  args.GetReturnValue().Set(amount);
201
}
202
203
204
1900
static void GetTotalMemory(const FunctionCallbackInfo<Value>& args) {
205
1900
  double amount = uv_get_total_memory();
206
1900
  if (amount < 0)
207
1900
    return;
208
3800
  args.GetReturnValue().Set(amount);
209
}
210
211
212
1
static void GetUptime(const FunctionCallbackInfo<Value>& args) {
213
  double uptime;
214
1
  int err = uv_uptime(&uptime);
215
1
  if (err == 0)
216
3
    args.GetReturnValue().Set(uptime);
217
1
}
218
219
220
1
static void GetLoadAvg(const FunctionCallbackInfo<Value>& args) {
221
2
  CHECK(args[0]->IsFloat64Array());
222
2
  Local<Float64Array> array = args[0].As<Float64Array>();
223
1
  CHECK_EQ(array->Length(), 3);
224
1
  Local<ArrayBuffer> ab = array->Buffer();
225
1
  double* loadavg = static_cast<double*>(ab->GetContents().Data());
226
1
  uv_loadavg(loadavg);
227
1
}
228
229
230
1902
static void GetInterfaceAddresses(const FunctionCallbackInfo<Value>& args) {
231
1902
  Environment* env = Environment::GetCurrent(args);
232
  uv_interface_address_t* interfaces;
233
  int count, i;
234
  char ip[INET6_ADDRSTRLEN];
235
  char netmask[INET6_ADDRSTRLEN];
236
  char mac[18];
237
  Local<Object> ret, o;
238
  Local<String> name, family;
239
  Local<Array> ifarr;
240
241
1902
  int err = uv_interface_addresses(&interfaces, &count);
242
243
1902
  ret = Object::New(env->isolate());
244
245
1902
  if (err == UV_ENOSYS) {
246
    return args.GetReturnValue().Set(ret);
247
1902
  } else if (err) {
248
    return env->ThrowUVException(err, "uv_interface_addresses");
249
  }
250
251
13314
  for (i = 0; i < count; i++) {
252
11412
    const char* const raw_name = interfaces[i].name;
253
254
    // On Windows, the interface name is the UTF8-encoded friendly name and may
255
    // contain non-ASCII characters.  On UNIX, it's just a binary string with
256
    // no particular encoding but we treat it as a one-byte Latin-1 string.
257
#ifdef _WIN32
258
    name = String::NewFromUtf8(env->isolate(), raw_name);
259
#else
260
11412
    name = OneByteString(env->isolate(), raw_name);
261
#endif
262
263
34236
    if (ret->Has(env->context(), name).FromJust()) {
264
11412
      ifarr = Local<Array>::Cast(ret->Get(name));
265
    } else {
266
5706
      ifarr = Array::New(env->isolate());
267
5706
      ret->Set(name, ifarr);
268
    }
269
270
    snprintf(mac,
271
             18,
272
             "%02x:%02x:%02x:%02x:%02x:%02x",
273
11412
             static_cast<unsigned char>(interfaces[i].phys_addr[0]),
274
11412
             static_cast<unsigned char>(interfaces[i].phys_addr[1]),
275
11412
             static_cast<unsigned char>(interfaces[i].phys_addr[2]),
276
11412
             static_cast<unsigned char>(interfaces[i].phys_addr[3]),
277
11412
             static_cast<unsigned char>(interfaces[i].phys_addr[4]),
278
68472
             static_cast<unsigned char>(interfaces[i].phys_addr[5]));
279
280
11412
    if (interfaces[i].address.address4.sin_family == AF_INET) {
281
5706
      uv_ip4_name(&interfaces[i].address.address4, ip, sizeof(ip));
282
5706
      uv_ip4_name(&interfaces[i].netmask.netmask4, netmask, sizeof(netmask));
283
5706
      family = env->ipv4_string();
284
5706
    } else if (interfaces[i].address.address4.sin_family == AF_INET6) {
285
5706
      uv_ip6_name(&interfaces[i].address.address6, ip, sizeof(ip));
286
5706
      uv_ip6_name(&interfaces[i].netmask.netmask6, netmask, sizeof(netmask));
287
5706
      family = env->ipv6_string();
288
    } else {
289
      strncpy(ip, "<unknown sa family>", INET6_ADDRSTRLEN);
290
      family = env->unknown_string();
291
    }
292
293
11412
    o = Object::New(env->isolate());
294
34236
    o->Set(env->address_string(), OneByteString(env->isolate(), ip));
295
34236
    o->Set(env->netmask_string(), OneByteString(env->isolate(), netmask));
296
22824
    o->Set(env->family_string(), family);
297
34236
    o->Set(env->mac_string(), FIXED_ONE_BYTE_STRING(env->isolate(), mac));
298
299
11412
    if (interfaces[i].address.address4.sin_family == AF_INET6) {
300
5706
      uint32_t scopeid = interfaces[i].address.address6.sin6_scope_id;
301
      o->Set(env->scopeid_string(),
302
17118
             Integer::NewFromUnsigned(env->isolate(), scopeid));
303
    }
304
305
11412
    const bool internal = interfaces[i].is_internal;
306
    o->Set(env->internal_string(),
307
41844
           internal ? True(env->isolate()) : False(env->isolate()));
308
309
22824
    ifarr->Set(ifarr->Length(), o);
310
  }
311
312
1902
  uv_free_interface_addresses(interfaces, count);
313
3804
  args.GetReturnValue().Set(ret);
314
}
315
316
317
66
static void GetHomeDirectory(const FunctionCallbackInfo<Value>& args) {
318
66
  Environment* env = Environment::GetCurrent(args);
319
  char buf[PATH_MAX];
320
321
66
  size_t len = sizeof(buf);
322
66
  const int err = uv_os_homedir(buf, &len);
323
324
66
  if (err) {
325
66
    return env->ThrowUVException(err, "uv_os_homedir");
326
  }
327
328
  Local<String> home = String::NewFromUtf8(env->isolate(),
329
                                           buf,
330
                                           String::kNormalString,
331
66
                                           len);
332
132
  args.GetReturnValue().Set(home);
333
}
334
335
336
3
static void GetUserInfo(const FunctionCallbackInfo<Value>& args) {
337
3
  Environment* env = Environment::GetCurrent(args);
338
  uv_passwd_t pwd;
339
  enum encoding encoding;
340
341
6
  if (args[0]->IsObject()) {
342
4
    Local<Object> options = args[0].As<Object>();
343
    MaybeLocal<Value> maybe_encoding = options->Get(env->context(),
344
6
                                                    env->encoding_string());
345
2
    if (maybe_encoding.IsEmpty())
346
1
      return;
347
348
1
    Local<Value> encoding_opt = maybe_encoding.ToLocalChecked();
349
1
    encoding = ParseEncoding(env->isolate(), encoding_opt, UTF8);
350
  } else {
351
1
    encoding = UTF8;
352
  }
353
354
2
  const int err = uv_os_get_passwd(&pwd);
355
356
2
  if (err) {
357
    return env->ThrowUVException(err, "uv_os_get_passwd");
358
  }
359
360
  Local<Value> error;
361
362
2
  Local<Value> uid = Number::New(env->isolate(), pwd.uid);
363
2
  Local<Value> gid = Number::New(env->isolate(), pwd.gid);
364
  MaybeLocal<Value> username = StringBytes::Encode(env->isolate(),
365
                                                   pwd.username,
366
                                                   encoding,
367
2
                                                   &error);
368
  MaybeLocal<Value> homedir = StringBytes::Encode(env->isolate(),
369
                                                  pwd.homedir,
370
                                                  encoding,
371
2
                                                  &error);
372
  MaybeLocal<Value> shell;
373
374
2
  if (pwd.shell == NULL)
375
    shell = Null(env->isolate());
376
  else
377
2
    shell = StringBytes::Encode(env->isolate(), pwd.shell, encoding, &error);
378
379
2
  uv_os_free_passwd(&pwd);
380
381
2
  if (username.IsEmpty()) {
382
    // TODO(addaleax): Use `error` itself here.
383
    return env->ThrowUVException(UV_EINVAL,
384
                                 "uv_os_get_passwd",
385
                                 "Invalid character encoding for username");
386
  }
387
388
2
  if (homedir.IsEmpty()) {
389
    // TODO(addaleax): Use `error` itself here.
390
    return env->ThrowUVException(UV_EINVAL,
391
                                 "uv_os_get_passwd",
392
                                 "Invalid character encoding for homedir");
393
  }
394
395
2
  if (shell.IsEmpty()) {
396
    // TODO(addaleax): Use `error` itself here.
397
    return env->ThrowUVException(UV_EINVAL,
398
                                 "uv_os_get_passwd",
399
                                 "Invalid character encoding for shell");
400
  }
401
402
2
  Local<Object> entry = Object::New(env->isolate());
403
404
4
  entry->Set(env->uid_string(), uid);
405
4
  entry->Set(env->gid_string(), gid);
406
4
  entry->Set(env->username_string(), username.ToLocalChecked());
407
4
  entry->Set(env->homedir_string(), homedir.ToLocalChecked());
408
4
  entry->Set(env->shell_string(), shell.ToLocalChecked());
409
410
4
  args.GetReturnValue().Set(entry);
411
}
412
413
414
1968
void Initialize(Local<Object> target,
415
                Local<Value> unused,
416
                Local<Context> context) {
417
1968
  Environment* env = Environment::GetCurrent(context);
418
1968
  env->SetMethod(target, "getHostname", GetHostname);
419
1968
  env->SetMethod(target, "getLoadAvg", GetLoadAvg);
420
1968
  env->SetMethod(target, "getUptime", GetUptime);
421
1968
  env->SetMethod(target, "getTotalMem", GetTotalMemory);
422
1968
  env->SetMethod(target, "getFreeMem", GetFreeMemory);
423
1968
  env->SetMethod(target, "getCPUs", GetCPUInfo);
424
1968
  env->SetMethod(target, "getOSType", GetOSType);
425
1968
  env->SetMethod(target, "getOSRelease", GetOSRelease);
426
1968
  env->SetMethod(target, "getInterfaceAddresses", GetInterfaceAddresses);
427
1968
  env->SetMethod(target, "getHomeDirectory", GetHomeDirectory);
428
1968
  env->SetMethod(target, "getUserInfo", GetUserInfo);
429
  target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "isBigEndian"),
430
5904
              Boolean::New(env->isolate(), IsBigEndian()));
431
1968
}
432
433
}  // namespace os
434
}  // namespace node
435
436
2441
NODE_MODULE_CONTEXT_AWARE_BUILTIN(os, node::os::Initialize)