GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_os.cc Lines: 93 196 47.4 %
Date: 2019-02-01 22:03:38 Branches: 17 86 19.8 %

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 "env-inl.h"
23
#include "string_bytes.h"
24
#include "util.h"
25
26
#include <array>
27
#include <errno.h>
28
#include <string.h>
29
30
#ifdef __MINGW32__
31
# include <io.h>
32
#endif  // __MINGW32__
33
34
#ifdef __POSIX__
35
# include <limits.h>        // PATH_MAX on Solaris.
36
# include <netdb.h>         // MAXHOSTNAMELEN on Solaris.
37
# include <unistd.h>        // gethostname, sysconf
38
# include <sys/param.h>     // MAXHOSTNAMELEN on Linux and the BSDs.
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::FunctionCallbackInfo;
55
using v8::Int32;
56
using v8::Integer;
57
using v8::Isolate;
58
using v8::Local;
59
using v8::MaybeLocal;
60
using v8::Null;
61
using v8::Number;
62
using v8::Object;
63
using v8::String;
64
using v8::Value;
65
66
67
static void GetHostname(const FunctionCallbackInfo<Value>& args) {
68
  Environment* env = Environment::GetCurrent(args);
69
  char buf[MAXHOSTNAMELEN + 1];
70
  size_t size = sizeof(buf);
71
  int r = uv_os_gethostname(buf, &size);
72
73
  if (r != 0) {
74
    CHECK_GE(args.Length(), 1);
75
    env->CollectUVExceptionInfo(args[args.Length() - 1], r,
76
                                "uv_os_gethostname");
77
    return args.GetReturnValue().SetUndefined();
78
  }
79
80
  args.GetReturnValue().Set(OneByteString(env->isolate(), buf));
81
}
82
83
84
2
static void GetOSType(const FunctionCallbackInfo<Value>& args) {
85
2
  Environment* env = Environment::GetCurrent(args);
86
  uv_utsname_t info;
87
2
  int err = uv_os_uname(&info);
88
89
2
  if (err != 0) {
90
    CHECK_GE(args.Length(), 1);
91
    env->CollectUVExceptionInfo(args[args.Length() - 1], err, "uv_os_uname");
92
2
    return args.GetReturnValue().SetUndefined();
93
  }
94
95
6
  args.GetReturnValue().Set(OneByteString(env->isolate(), info.sysname));
96
}
97
98
99
static void GetOSRelease(const FunctionCallbackInfo<Value>& args) {
100
  Environment* env = Environment::GetCurrent(args);
101
  uv_utsname_t info;
102
  int err = uv_os_uname(&info);
103
104
  if (err != 0) {
105
    CHECK_GE(args.Length(), 1);
106
    env->CollectUVExceptionInfo(args[args.Length() - 1], err, "uv_os_uname");
107
    return args.GetReturnValue().SetUndefined();
108
  }
109
110
  args.GetReturnValue().Set(OneByteString(env->isolate(), info.release));
111
}
112
113
114
59
static void GetCPUInfo(const FunctionCallbackInfo<Value>& args) {
115
59
  Environment* env = Environment::GetCurrent(args);
116
59
  Isolate* isolate = env->isolate();
117
118
  uv_cpu_info_t* cpu_infos;
119
  int count;
120
121
59
  int err = uv_cpu_info(&cpu_infos, &count);
122
59
  if (err)
123
59
    return;
124
125
  // It's faster to create an array packed with all the data and
126
  // assemble them into objects in JS than to call Object::Set() repeatedly
127
  // The array is in the format
128
  // [model, speed, (5 entries of cpu_times), model2, speed2, ...]
129
59
  std::vector<Local<Value>> result(count * 7);
130
531
  for (int i = 0; i < count; i++) {
131
472
    uv_cpu_info_t* ci = cpu_infos + i;
132
944
    result[i * 7] = OneByteString(isolate, ci->model);
133
944
    result[i * 7 + 1] = Number::New(isolate, ci->speed);
134
944
    result[i * 7 + 2] = Number::New(isolate, ci->cpu_times.user);
135
944
    result[i * 7 + 3] = Number::New(isolate, ci->cpu_times.nice);
136
944
    result[i * 7 + 4] = Number::New(isolate, ci->cpu_times.sys);
137
944
    result[i * 7 + 5] = Number::New(isolate, ci->cpu_times.idle);
138
944
    result[i * 7 + 6] = Number::New(isolate, ci->cpu_times.irq);
139
  }
140
141
59
  uv_free_cpu_info(cpu_infos, count);
142
177
  args.GetReturnValue().Set(Array::New(isolate, result.data(), result.size()));
143
}
144
145
146
static void GetFreeMemory(const FunctionCallbackInfo<Value>& args) {
147
  double amount = uv_get_free_memory();
148
  if (amount < 0)
149
    return;
150
  args.GetReturnValue().Set(amount);
151
}
152
153
154
58
static void GetTotalMemory(const FunctionCallbackInfo<Value>& args) {
155
58
  double amount = uv_get_total_memory();
156
58
  if (amount < 0)
157
58
    return;
158
116
  args.GetReturnValue().Set(amount);
159
}
160
161
162
static void GetUptime(const FunctionCallbackInfo<Value>& args) {
163
  double uptime;
164
  int err = uv_uptime(&uptime);
165
  if (err == 0)
166
    args.GetReturnValue().Set(uptime);
167
}
168
169
170
static void GetLoadAvg(const FunctionCallbackInfo<Value>& args) {
171
  CHECK(args[0]->IsFloat64Array());
172
  Local<Float64Array> array = args[0].As<Float64Array>();
173
  CHECK_EQ(array->Length(), 3);
174
  Local<ArrayBuffer> ab = array->Buffer();
175
  double* loadavg = static_cast<double*>(ab->GetContents().Data());
176
  uv_loadavg(loadavg);
177
}
178
179
180
59
static void GetInterfaceAddresses(const FunctionCallbackInfo<Value>& args) {
181
59
  Environment* env = Environment::GetCurrent(args);
182
59
  Isolate* isolate = env->isolate();
183
  uv_interface_address_t* interfaces;
184
  int count, i;
185
  char ip[INET6_ADDRSTRLEN];
186
  char netmask[INET6_ADDRSTRLEN];
187
  std::array<char, 18> mac;
188
  Local<String> name, family;
189
190
59
  int err = uv_interface_addresses(&interfaces, &count);
191
192
59
  if (err == UV_ENOSYS)
193
    return args.GetReturnValue().SetUndefined();
194
195
59
  if (err) {
196
    CHECK_GE(args.Length(), 1);
197
    env->CollectUVExceptionInfo(args[args.Length() - 1], errno,
198
                                "uv_interface_addresses");
199
    return args.GetReturnValue().SetUndefined();
200
  }
201
202
59
  Local<Value> no_scope_id = Integer::New(isolate, -1);
203
59
  std::vector<Local<Value>> result(count * 7);
204
413
  for (i = 0; i < count; i++) {
205
354
    const char* const raw_name = interfaces[i].name;
206
207
    // Use UTF-8 on both Windows and Unixes (While it may be true that UNIX
208
    // systems are somewhat encoding-agnostic here, it’s more than reasonable
209
    // to assume UTF8 as the default as well. It’s what people will expect if
210
    // they name the interface from any input that uses UTF-8, which should be
211
    // the most frequent case by far these days.)
212
    name = String::NewFromUtf8(isolate, raw_name,
213
708
        v8::NewStringType::kNormal).ToLocalChecked();
214
215
    snprintf(mac.data(),
216
             mac.size(),
217
             "%02x:%02x:%02x:%02x:%02x:%02x",
218
354
             static_cast<unsigned char>(interfaces[i].phys_addr[0]),
219
354
             static_cast<unsigned char>(interfaces[i].phys_addr[1]),
220
354
             static_cast<unsigned char>(interfaces[i].phys_addr[2]),
221
354
             static_cast<unsigned char>(interfaces[i].phys_addr[3]),
222
354
             static_cast<unsigned char>(interfaces[i].phys_addr[4]),
223
2124
             static_cast<unsigned char>(interfaces[i].phys_addr[5]));
224
225
354
    if (interfaces[i].address.address4.sin_family == AF_INET) {
226
177
      uv_ip4_name(&interfaces[i].address.address4, ip, sizeof(ip));
227
177
      uv_ip4_name(&interfaces[i].netmask.netmask4, netmask, sizeof(netmask));
228
177
      family = env->ipv4_string();
229
177
    } else if (interfaces[i].address.address4.sin_family == AF_INET6) {
230
177
      uv_ip6_name(&interfaces[i].address.address6, ip, sizeof(ip));
231
177
      uv_ip6_name(&interfaces[i].netmask.netmask6, netmask, sizeof(netmask));
232
177
      family = env->ipv6_string();
233
    } else {
234
      strncpy(ip, "<unknown sa family>", INET6_ADDRSTRLEN);
235
      family = env->unknown_string();
236
    }
237
238
708
    result[i * 7] = name;
239
708
    result[i * 7 + 1] = OneByteString(isolate, ip);
240
708
    result[i * 7 + 2] = OneByteString(isolate, netmask);
241
708
    result[i * 7 + 3] = family;
242
708
    result[i * 7 + 4] = FIXED_ONE_BYTE_STRING(isolate, mac);
243
354
    result[i * 7 + 5] =
244
708
      interfaces[i].is_internal ? True(isolate) : False(isolate);
245
354
    if (interfaces[i].address.address4.sin_family == AF_INET6) {
246
177
      uint32_t scopeid = interfaces[i].address.address6.sin6_scope_id;
247
354
      result[i * 7 + 6] = Integer::NewFromUnsigned(isolate, scopeid);
248
    } else {
249
177
      result[i * 7 + 6] = no_scope_id;
250
    }
251
  }
252
253
59
  uv_free_interface_addresses(interfaces, count);
254
177
  args.GetReturnValue().Set(Array::New(isolate, result.data(), result.size()));
255
}
256
257
258
83
static void GetHomeDirectory(const FunctionCallbackInfo<Value>& args) {
259
83
  Environment* env = Environment::GetCurrent(args);
260
  char buf[PATH_MAX];
261
262
83
  size_t len = sizeof(buf);
263
83
  const int err = uv_os_homedir(buf, &len);
264
265
83
  if (err) {
266
    CHECK_GE(args.Length(), 1);
267
    env->CollectUVExceptionInfo(args[args.Length() - 1], err, "uv_os_homedir");
268
83
    return args.GetReturnValue().SetUndefined();
269
  }
270
271
  Local<String> home = String::NewFromUtf8(env->isolate(),
272
                                           buf,
273
                                           v8::NewStringType::kNormal,
274
166
                                           len).ToLocalChecked();
275
166
  args.GetReturnValue().Set(home);
276
}
277
278
279
static void GetUserInfo(const FunctionCallbackInfo<Value>& args) {
280
  Environment* env = Environment::GetCurrent(args);
281
  uv_passwd_t pwd;
282
  enum encoding encoding;
283
284
  if (args[0]->IsObject()) {
285
    Local<Object> options = args[0].As<Object>();
286
    MaybeLocal<Value> maybe_encoding = options->Get(env->context(),
287
                                                    env->encoding_string());
288
    if (maybe_encoding.IsEmpty())
289
      return;
290
291
    Local<Value> encoding_opt = maybe_encoding.ToLocalChecked();
292
    encoding = ParseEncoding(env->isolate(), encoding_opt, UTF8);
293
  } else {
294
    encoding = UTF8;
295
  }
296
297
  const int err = uv_os_get_passwd(&pwd);
298
299
  if (err) {
300
    CHECK_GE(args.Length(), 2);
301
    env->CollectUVExceptionInfo(args[args.Length() - 1], err,
302
                                "uv_os_get_passwd");
303
    return args.GetReturnValue().SetUndefined();
304
  }
305
306
  OnScopeLeave free_passwd([&]() { uv_os_free_passwd(&pwd); });
307
308
  Local<Value> error;
309
310
  Local<Value> uid = Number::New(env->isolate(), pwd.uid);
311
  Local<Value> gid = Number::New(env->isolate(), pwd.gid);
312
  MaybeLocal<Value> username = StringBytes::Encode(env->isolate(),
313
                                                   pwd.username,
314
                                                   encoding,
315
                                                   &error);
316
  MaybeLocal<Value> homedir = StringBytes::Encode(env->isolate(),
317
                                                  pwd.homedir,
318
                                                  encoding,
319
                                                  &error);
320
  MaybeLocal<Value> shell;
321
322
  if (pwd.shell == nullptr)
323
    shell = Null(env->isolate());
324
  else
325
    shell = StringBytes::Encode(env->isolate(), pwd.shell, encoding, &error);
326
327
  if (username.IsEmpty() || homedir.IsEmpty() || shell.IsEmpty()) {
328
    CHECK(!error.IsEmpty());
329
    env->isolate()->ThrowException(error);
330
    return;
331
  }
332
333
  Local<Object> entry = Object::New(env->isolate());
334
335
  entry->Set(env->context(), env->uid_string(), uid).FromJust();
336
  entry->Set(env->context(), env->gid_string(), gid).FromJust();
337
  entry->Set(env->context(),
338
             env->username_string(),
339
             username.ToLocalChecked()).FromJust();
340
  entry->Set(env->context(),
341
             env->homedir_string(),
342
             homedir.ToLocalChecked()).FromJust();
343
  entry->Set(env->context(),
344
             env->shell_string(),
345
             shell.ToLocalChecked()).FromJust();
346
347
  args.GetReturnValue().Set(entry);
348
}
349
350
351
static void SetPriority(const FunctionCallbackInfo<Value>& args) {
352
  Environment* env = Environment::GetCurrent(args);
353
354
  CHECK_EQ(args.Length(), 3);
355
  CHECK(args[0]->IsInt32());
356
  CHECK(args[1]->IsInt32());
357
358
  const int pid = args[0].As<Int32>()->Value();
359
  const int priority = args[1].As<Int32>()->Value();
360
  const int err = uv_os_setpriority(pid, priority);
361
362
  if (err) {
363
    CHECK(args[2]->IsObject());
364
    env->CollectUVExceptionInfo(args[2], err, "uv_os_setpriority");
365
  }
366
367
  args.GetReturnValue().Set(err);
368
}
369
370
371
static void GetPriority(const FunctionCallbackInfo<Value>& args) {
372
  Environment* env = Environment::GetCurrent(args);
373
374
  CHECK_EQ(args.Length(), 2);
375
  CHECK(args[0]->IsInt32());
376
377
  const int pid = args[0].As<Int32>()->Value();
378
  int priority;
379
  const int err = uv_os_getpriority(pid, &priority);
380
381
  if (err) {
382
    CHECK(args[1]->IsObject());
383
    env->CollectUVExceptionInfo(args[1], err, "uv_os_getpriority");
384
    return;
385
  }
386
387
  args.GetReturnValue().Set(priority);
388
}
389
390
391
150
void Initialize(Local<Object> target,
392
                Local<Value> unused,
393
                Local<Context> context,
394
                void* priv) {
395
150
  Environment* env = Environment::GetCurrent(context);
396
150
  env->SetMethod(target, "getHostname", GetHostname);
397
150
  env->SetMethod(target, "getLoadAvg", GetLoadAvg);
398
150
  env->SetMethod(target, "getUptime", GetUptime);
399
150
  env->SetMethod(target, "getTotalMem", GetTotalMemory);
400
150
  env->SetMethod(target, "getFreeMem", GetFreeMemory);
401
150
  env->SetMethod(target, "getCPUs", GetCPUInfo);
402
150
  env->SetMethod(target, "getOSType", GetOSType);
403
150
  env->SetMethod(target, "getOSRelease", GetOSRelease);
404
150
  env->SetMethod(target, "getInterfaceAddresses", GetInterfaceAddresses);
405
150
  env->SetMethod(target, "getHomeDirectory", GetHomeDirectory);
406
150
  env->SetMethod(target, "getUserInfo", GetUserInfo);
407
150
  env->SetMethod(target, "setPriority", SetPriority);
408
150
  env->SetMethod(target, "getPriority", GetPriority);
409
  target->Set(env->context(),
410
              FIXED_ONE_BYTE_STRING(env->isolate(), "isBigEndian"),
411
750
              Boolean::New(env->isolate(), IsBigEndian())).FromJust();
412
150
}
413
414
}  // namespace os
415
}  // namespace node
416
417
164
NODE_MODULE_CONTEXT_AWARE_INTERNAL(os, node::os::Initialize)