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: 174 201 86.6 %
Date: 2019-01-07 12:15:22 Branches: 45 88 51.1 %

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_internals.h"
23
#include "string_bytes.h"
24
25
#include <array>
26
#include <errno.h>
27
#include <string.h>
28
29
#ifdef __MINGW32__
30
# include <io.h>
31
#endif  // __MINGW32__
32
33
#ifdef __POSIX__
34
# include <limits.h>        // PATH_MAX on Solaris.
35
# include <netdb.h>         // MAXHOSTNAMELEN on Solaris.
36
# include <unistd.h>        // gethostname, sysconf
37
# include <sys/param.h>     // MAXHOSTNAMELEN on Linux and the BSDs.
38
# include <sys/utsname.h>
39
#endif  // __POSIX__
40
41
// Add Windows fallback.
42
#ifndef MAXHOSTNAMELEN
43
# define MAXHOSTNAMELEN 256
44
#endif  // MAXHOSTNAMELEN
45
46
namespace node {
47
namespace os {
48
49
using v8::Array;
50
using v8::ArrayBuffer;
51
using v8::Boolean;
52
using v8::Context;
53
using v8::Float64Array;
54
using v8::Function;
55
using v8::FunctionCallbackInfo;
56
using v8::Int32;
57
using v8::Integer;
58
using v8::Isolate;
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
3
  size_t size = sizeof(buf);
72
3
  int r = uv_os_gethostname(buf, &size);
73
74
3
  if (r != 0) {
75
    CHECK_GE(args.Length(), 1);
76
    env->CollectUVExceptionInfo(args[args.Length() - 1], r,
77
                                "uv_os_gethostname");
78
3
    return args.GetReturnValue().SetUndefined();
79
  }
80
81
9
  args.GetReturnValue().Set(OneByteString(env->isolate(), buf));
82
}
83
84
85
7
static void GetOSType(const FunctionCallbackInfo<Value>& args) {
86
7
  Environment* env = Environment::GetCurrent(args);
87
  const char* rval;
88
89
#ifdef __POSIX__
90
  struct utsname info;
91
7
  if (uname(&info) < 0) {
92
    CHECK_GE(args.Length(), 1);
93
    env->CollectExceptionInfo(args[args.Length() - 1], errno, "uname");
94
7
    return args.GetReturnValue().SetUndefined();
95
  }
96
7
  rval = info.sysname;
97
#else  // __MINGW32__
98
  rval = "Windows_NT";
99
#endif  // __POSIX__
100
101
21
  args.GetReturnValue().Set(OneByteString(env->isolate(), rval));
102
}
103
104
105
4
static void GetOSRelease(const FunctionCallbackInfo<Value>& args) {
106
4
  Environment* env = Environment::GetCurrent(args);
107
  const char* rval;
108
109
#ifdef __POSIX__
110
  struct utsname info;
111
4
  if (uname(&info) < 0) {
112
    CHECK_GE(args.Length(), 1);
113
    env->CollectExceptionInfo(args[args.Length() - 1], errno, "uname");
114
4
    return args.GetReturnValue().SetUndefined();
115
  }
116
# ifdef _AIX
117
  char release[256];
118
  snprintf(release, sizeof(release),
119
           "%s.%s", info.version, info.release);
120
  rval = release;
121
# else
122
4
  rval = info.release;
123
# endif
124
#else  // Windows
125
  char release[256];
126
  OSVERSIONINFOW info;
127
128
  info.dwOSVersionInfoSize = sizeof(info);
129
130
  // Don't complain that GetVersionEx is deprecated; there is no alternative.
131
  #pragma warning(suppress : 4996)
132
  if (GetVersionExW(&info) == 0)
133
    return;
134
135
  snprintf(release,
136
           sizeof(release),
137
           "%d.%d.%d",
138
           static_cast<int>(info.dwMajorVersion),
139
           static_cast<int>(info.dwMinorVersion),
140
           static_cast<int>(info.dwBuildNumber));
141
  rval = release;
142
#endif  // __POSIX__
143
144
12
  args.GetReturnValue().Set(OneByteString(env->isolate(), rval));
145
}
146
147
148
2990
static void GetCPUInfo(const FunctionCallbackInfo<Value>& args) {
149
2990
  Environment* env = Environment::GetCurrent(args);
150
2991
  Isolate* isolate = env->isolate();
151
152
  uv_cpu_info_t* cpu_infos;
153
  int count;
154
155
2991
  int err = uv_cpu_info(&cpu_infos, &count);
156
2991
  if (err)
157
2991
    return;
158
159
  // It's faster to create an array packed with all the data and
160
  // assemble them into objects in JS than to call Object::Set() repeatedly
161
  // The array is in the format
162
  // [model, speed, (5 entries of cpu_times), model2, speed2, ...]
163
2991
  std::vector<Local<Value>> result(count * 7);
164
26919
  for (int i = 0; i < count; i++) {
165
23928
    uv_cpu_info_t* ci = cpu_infos + i;
166
47856
    result[i * 7] = OneByteString(isolate, ci->model);
167
47856
    result[i * 7 + 1] = Number::New(isolate, ci->speed);
168
47856
    result[i * 7 + 2] = Number::New(isolate, ci->cpu_times.user);
169
47856
    result[i * 7 + 3] = Number::New(isolate, ci->cpu_times.nice);
170
47856
    result[i * 7 + 4] = Number::New(isolate, ci->cpu_times.sys);
171
47856
    result[i * 7 + 5] = Number::New(isolate, ci->cpu_times.idle);
172
47856
    result[i * 7 + 6] = Number::New(isolate, ci->cpu_times.irq);
173
  }
174
175
2991
  uv_free_cpu_info(cpu_infos, count);
176
8973
  args.GetReturnValue().Set(Array::New(isolate, result.data(), result.size()));
177
}
178
179
180
3
static void GetFreeMemory(const FunctionCallbackInfo<Value>& args) {
181
3
  double amount = uv_get_free_memory();
182
3
  if (amount < 0)
183
3
    return;
184
6
  args.GetReturnValue().Set(amount);
185
}
186
187
188
2989
static void GetTotalMemory(const FunctionCallbackInfo<Value>& args) {
189
2989
  double amount = uv_get_total_memory();
190
2989
  if (amount < 0)
191
2990
    return;
192
5979
  args.GetReturnValue().Set(amount);
193
}
194
195
196
3
static void GetUptime(const FunctionCallbackInfo<Value>& args) {
197
  double uptime;
198
3
  int err = uv_uptime(&uptime);
199
3
  if (err == 0)
200
9
    args.GetReturnValue().Set(uptime);
201
3
}
202
203
204
1
static void GetLoadAvg(const FunctionCallbackInfo<Value>& args) {
205
2
  CHECK(args[0]->IsFloat64Array());
206
2
  Local<Float64Array> array = args[0].As<Float64Array>();
207
1
  CHECK_EQ(array->Length(), 3);
208
1
  Local<ArrayBuffer> ab = array->Buffer();
209
1
  double* loadavg = static_cast<double*>(ab->GetContents().Data());
210
1
  uv_loadavg(loadavg);
211
1
}
212
213
214
2992
static void GetInterfaceAddresses(const FunctionCallbackInfo<Value>& args) {
215
2992
  Environment* env = Environment::GetCurrent(args);
216
  uv_interface_address_t* interfaces;
217
  int count, i;
218
  char ip[INET6_ADDRSTRLEN];
219
  char netmask[INET6_ADDRSTRLEN];
220
  std::array<char, 18> mac;
221
  Local<Object> ret, o;
222
  Local<String> name, family;
223
  Local<Array> ifarr;
224
225
2993
  int err = uv_interface_addresses(&interfaces, &count);
226
227
2993
  ret = Object::New(env->isolate());
228
229
2992
  if (err == UV_ENOSYS) {
230
    return args.GetReturnValue().Set(ret);
231
2992
  } else if (err) {
232
    CHECK_GE(args.Length(), 1);
233
    env->CollectUVExceptionInfo(args[args.Length() - 1], errno,
234
                                "uv_interface_addresses");
235
    return args.GetReturnValue().SetUndefined();
236
  }
237
238
20950
  for (i = 0; i < count; i++) {
239
17957
    const char* const raw_name = interfaces[i].name;
240
241
    // Use UTF-8 on both Windows and Unixes (While it may be true that UNIX
242
    // systems are somewhat encoding-agnostic here, it’s more than reasonable
243
    // to assume UTF8 as the default as well. It’s what people will expect if
244
    // they name the interface from any input that uses UTF-8, which should be
245
    // the most frequent case by far these days.)
246
    name = String::NewFromUtf8(env->isolate(), raw_name,
247
35915
        v8::NewStringType::kNormal).ToLocalChecked();
248
249
53873
    if (ret->Has(env->context(), name).FromJust()) {
250
      ifarr = Local<Array>::Cast(ret->Get(env->context(),
251
26936
                                          name).ToLocalChecked());
252
    } else {
253
8979
      ifarr = Array::New(env->isolate());
254
26935
      ret->Set(env->context(), name, ifarr).FromJust();
255
    }
256
257
    snprintf(mac.data(),
258
             mac.size(),
259
             "%02x:%02x:%02x:%02x:%02x:%02x",
260
17956
             static_cast<unsigned char>(interfaces[i].phys_addr[0]),
261
17956
             static_cast<unsigned char>(interfaces[i].phys_addr[1]),
262
17956
             static_cast<unsigned char>(interfaces[i].phys_addr[2]),
263
17956
             static_cast<unsigned char>(interfaces[i].phys_addr[3]),
264
17956
             static_cast<unsigned char>(interfaces[i].phys_addr[4]),
265
107736
             static_cast<unsigned char>(interfaces[i].phys_addr[5]));
266
267
17957
    if (interfaces[i].address.address4.sin_family == AF_INET) {
268
8979
      uv_ip4_name(&interfaces[i].address.address4, ip, sizeof(ip));
269
8976
      uv_ip4_name(&interfaces[i].netmask.netmask4, netmask, sizeof(netmask));
270
8978
      family = env->ipv4_string();
271
8978
    } else if (interfaces[i].address.address4.sin_family == AF_INET6) {
272
8978
      uv_ip6_name(&interfaces[i].address.address6, ip, sizeof(ip));
273
8979
      uv_ip6_name(&interfaces[i].netmask.netmask6, netmask, sizeof(netmask));
274
8979
      family = env->ipv6_string();
275
    } else {
276
      strncpy(ip, "<unknown sa family>", INET6_ADDRSTRLEN);
277
      family = env->unknown_string();
278
    }
279
280
17958
    o = Object::New(env->isolate());
281
    o->Set(env->context(),
282
           env->address_string(),
283
89788
           OneByteString(env->isolate(), ip)).FromJust();
284
    o->Set(env->context(),
285
           env->netmask_string(),
286
89789
           OneByteString(env->isolate(), netmask)).FromJust();
287
    o->Set(env->context(),
288
71830
           env->family_string(), family).FromJust();
289
    o->Set(env->context(),
290
           env->mac_string(),
291
89788
           FIXED_ONE_BYTE_STRING(env->isolate(), mac)).FromJust();
292
293
17957
    if (interfaces[i].address.address4.sin_family == AF_INET6) {
294
8979
      uint32_t scopeid = interfaces[i].address.address6.sin6_scope_id;
295
      o->Set(env->context(), env->scopeid_string(),
296
44895
             Integer::NewFromUnsigned(env->isolate(), scopeid)).FromJust();
297
    }
298
299
17957
    const bool internal = interfaces[i].is_internal;
300
    o->Set(env->context(), env->internal_string(),
301
101759
           internal ? True(env->isolate()) : False(env->isolate())).FromJust();
302
303
53874
    ifarr->Set(env->context(), ifarr->Length(), o).FromJust();
304
  }
305
306
2993
  uv_free_interface_addresses(interfaces, count);
307
5986
  args.GetReturnValue().Set(ret);
308
}
309
310
311
110
static void GetHomeDirectory(const FunctionCallbackInfo<Value>& args) {
312
110
  Environment* env = Environment::GetCurrent(args);
313
  char buf[PATH_MAX];
314
315
110
  size_t len = sizeof(buf);
316
110
  const int err = uv_os_homedir(buf, &len);
317
318
110
  if (err) {
319
    CHECK_GE(args.Length(), 1);
320
    env->CollectUVExceptionInfo(args[args.Length() - 1], err, "uv_os_homedir");
321
110
    return args.GetReturnValue().SetUndefined();
322
  }
323
324
  Local<String> home = String::NewFromUtf8(env->isolate(),
325
                                           buf,
326
                                           v8::NewStringType::kNormal,
327
220
                                           len).ToLocalChecked();
328
220
  args.GetReturnValue().Set(home);
329
}
330
331
332
3
static void GetUserInfo(const FunctionCallbackInfo<Value>& args) {
333
3
  Environment* env = Environment::GetCurrent(args);
334
  uv_passwd_t pwd;
335
  enum encoding encoding;
336
337
6
  if (args[0]->IsObject()) {
338
4
    Local<Object> options = args[0].As<Object>();
339
    MaybeLocal<Value> maybe_encoding = options->Get(env->context(),
340
6
                                                    env->encoding_string());
341
2
    if (maybe_encoding.IsEmpty())
342
1
      return;
343
344
1
    Local<Value> encoding_opt = maybe_encoding.ToLocalChecked();
345
1
    encoding = ParseEncoding(env->isolate(), encoding_opt, UTF8);
346
  } else {
347
1
    encoding = UTF8;
348
  }
349
350
2
  const int err = uv_os_get_passwd(&pwd);
351
352
2
  if (err) {
353
    CHECK_GE(args.Length(), 2);
354
    env->CollectUVExceptionInfo(args[args.Length() - 1], err,
355
                                "uv_os_get_passwd");
356
    return args.GetReturnValue().SetUndefined();
357
  }
358
359
4
  OnScopeLeave free_passwd([&]() { uv_os_free_passwd(&pwd); });
360
361
  Local<Value> error;
362
363
2
  Local<Value> uid = Number::New(env->isolate(), pwd.uid);
364
2
  Local<Value> gid = Number::New(env->isolate(), pwd.gid);
365
  MaybeLocal<Value> username = StringBytes::Encode(env->isolate(),
366
                                                   pwd.username,
367
                                                   encoding,
368
2
                                                   &error);
369
  MaybeLocal<Value> homedir = StringBytes::Encode(env->isolate(),
370
                                                  pwd.homedir,
371
                                                  encoding,
372
2
                                                  &error);
373
  MaybeLocal<Value> shell;
374
375
2
  if (pwd.shell == nullptr)
376
    shell = Null(env->isolate());
377
  else
378
2
    shell = StringBytes::Encode(env->isolate(), pwd.shell, encoding, &error);
379
380


6
  if (username.IsEmpty() || homedir.IsEmpty() || shell.IsEmpty()) {
381
    CHECK(!error.IsEmpty());
382
    env->isolate()->ThrowException(error);
383
    return;
384
  }
385
386
2
  Local<Object> entry = Object::New(env->isolate());
387
388
8
  entry->Set(env->context(), env->uid_string(), uid).FromJust();
389
8
  entry->Set(env->context(), env->gid_string(), gid).FromJust();
390
  entry->Set(env->context(),
391
             env->username_string(),
392
8
             username.ToLocalChecked()).FromJust();
393
  entry->Set(env->context(),
394
             env->homedir_string(),
395
8
             homedir.ToLocalChecked()).FromJust();
396
  entry->Set(env->context(),
397
             env->shell_string(),
398
8
             shell.ToLocalChecked()).FromJust();
399
400
4
  args.GetReturnValue().Set(entry);
401
}
402
403
404
80
static void SetPriority(const FunctionCallbackInfo<Value>& args) {
405
80
  Environment* env = Environment::GetCurrent(args);
406
407
80
  CHECK_EQ(args.Length(), 3);
408
160
  CHECK(args[0]->IsInt32());
409
160
  CHECK(args[1]->IsInt32());
410
411
240
  const int pid = args[0].As<Int32>()->Value();
412
240
  const int priority = args[1].As<Int32>()->Value();
413
80
  const int err = uv_os_setpriority(pid, priority);
414
415
80
  if (err) {
416
40
    CHECK(args[2]->IsObject());
417
20
    env->CollectUVExceptionInfo(args[2], err, "uv_os_setpriority");
418
  }
419
420
160
  args.GetReturnValue().Set(err);
421
80
}
422
423
424
60
static void GetPriority(const FunctionCallbackInfo<Value>& args) {
425
60
  Environment* env = Environment::GetCurrent(args);
426
427
60
  CHECK_EQ(args.Length(), 2);
428
120
  CHECK(args[0]->IsInt32());
429
430
180
  const int pid = args[0].As<Int32>()->Value();
431
  int priority;
432
60
  const int err = uv_os_getpriority(pid, &priority);
433
434
60
  if (err) {
435
    CHECK(args[1]->IsObject());
436
    env->CollectUVExceptionInfo(args[1], err, "uv_os_getpriority");
437
    return;
438
  }
439
440
180
  args.GetReturnValue().Set(priority);
441
}
442
443
444
3090
void Initialize(Local<Object> target,
445
                Local<Value> unused,
446
                Local<Context> context,
447
                void* priv) {
448
3090
  Environment* env = Environment::GetCurrent(context);
449
3090
  env->SetMethod(target, "getHostname", GetHostname);
450
3090
  env->SetMethod(target, "getLoadAvg", GetLoadAvg);
451
3090
  env->SetMethod(target, "getUptime", GetUptime);
452
3090
  env->SetMethod(target, "getTotalMem", GetTotalMemory);
453
3090
  env->SetMethod(target, "getFreeMem", GetFreeMemory);
454
3090
  env->SetMethod(target, "getCPUs", GetCPUInfo);
455
3090
  env->SetMethod(target, "getOSType", GetOSType);
456
3090
  env->SetMethod(target, "getOSRelease", GetOSRelease);
457
3090
  env->SetMethod(target, "getInterfaceAddresses", GetInterfaceAddresses);
458
3090
  env->SetMethod(target, "getHomeDirectory", GetHomeDirectory);
459
3090
  env->SetMethod(target, "getUserInfo", GetUserInfo);
460
3090
  env->SetMethod(target, "setPriority", SetPriority);
461
3090
  env->SetMethod(target, "getPriority", GetPriority);
462
  target->Set(env->context(),
463
              FIXED_ONE_BYTE_STRING(env->isolate(), "isBigEndian"),
464
15450
              Boolean::New(env->isolate(), IsBigEndian())).FromJust();
465
3090
}
466
467
}  // namespace os
468
}  // namespace node
469
470
3596
NODE_MODULE_CONTEXT_AWARE_INTERNAL(os, node::os::Initialize)