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: 175 202 86.6 %
Date: 2019-09-26 22:31:05 Branches: 43 86 50.0 %

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
25
#ifdef __MINGW32__
26
# include <io.h>
27
#endif  // __MINGW32__
28
29
#ifdef __POSIX__
30
# include <unistd.h>        // gethostname, sysconf
31
# include <climits>         // PATH_MAX on Solaris.
32
#endif  // __POSIX__
33
34
#include <array>
35
#include <cerrno>
36
#include <cstring>
37
38
namespace node {
39
namespace os {
40
41
using v8::Array;
42
using v8::ArrayBuffer;
43
using v8::Boolean;
44
using v8::Context;
45
using v8::Float64Array;
46
using v8::FunctionCallbackInfo;
47
using v8::Int32;
48
using v8::Integer;
49
using v8::Isolate;
50
using v8::Local;
51
using v8::MaybeLocal;
52
using v8::NewStringType;
53
using v8::Null;
54
using v8::Number;
55
using v8::Object;
56
using v8::String;
57
using v8::Value;
58
59
60
18
static void GetHostname(const FunctionCallbackInfo<Value>& args) {
61
18
  Environment* env = Environment::GetCurrent(args);
62
  char buf[UV_MAXHOSTNAMESIZE];
63
18
  size_t size = sizeof(buf);
64
18
  int r = uv_os_gethostname(buf, &size);
65
66
18
  if (r != 0) {
67
    CHECK_GE(args.Length(), 1);
68
    env->CollectUVExceptionInfo(args[args.Length() - 1], r,
69
                                "uv_os_gethostname");
70
18
    return args.GetReturnValue().SetUndefined();
71
  }
72
73
  args.GetReturnValue().Set(
74
18
      String::NewFromUtf8(env->isolate(), buf, NewStringType::kNormal)
75
54
          .ToLocalChecked());
76
}
77
78
79
27
static void GetOSType(const FunctionCallbackInfo<Value>& args) {
80
27
  Environment* env = Environment::GetCurrent(args);
81
  uv_utsname_t info;
82
27
  int err = uv_os_uname(&info);
83
84
27
  if (err != 0) {
85
    CHECK_GE(args.Length(), 1);
86
    env->CollectUVExceptionInfo(args[args.Length() - 1], err, "uv_os_uname");
87
27
    return args.GetReturnValue().SetUndefined();
88
  }
89
90
  args.GetReturnValue().Set(
91
27
      String::NewFromUtf8(env->isolate(), info.sysname, NewStringType::kNormal)
92
81
          .ToLocalChecked());
93
}
94
95
96
19
static void GetOSRelease(const FunctionCallbackInfo<Value>& args) {
97
19
  Environment* env = Environment::GetCurrent(args);
98
  uv_utsname_t info;
99
19
  int err = uv_os_uname(&info);
100
101
19
  if (err != 0) {
102
    CHECK_GE(args.Length(), 1);
103
    env->CollectUVExceptionInfo(args[args.Length() - 1], err, "uv_os_uname");
104
19
    return args.GetReturnValue().SetUndefined();
105
  }
106
107
  args.GetReturnValue().Set(
108
19
      String::NewFromUtf8(env->isolate(), info.release, NewStringType::kNormal)
109
57
          .ToLocalChecked());
110
}
111
112
113
3437
static void GetCPUInfo(const FunctionCallbackInfo<Value>& args) {
114
3437
  Environment* env = Environment::GetCurrent(args);
115
3437
  Isolate* isolate = env->isolate();
116
117
  uv_cpu_info_t* cpu_infos;
118
  int count;
119
120
3437
  int err = uv_cpu_info(&cpu_infos, &count);
121
3437
  if (err)
122
3437
    return;
123
124
  // It's faster to create an array packed with all the data and
125
  // assemble them into objects in JS than to call Object::Set() repeatedly
126
  // The array is in the format
127
  // [model, speed, (5 entries of cpu_times), model2, speed2, ...]
128
3437
  std::vector<Local<Value>> result(count * 7);
129
30933
  for (int i = 0, j = 0; i < count; i++) {
130
27496
    uv_cpu_info_t* ci = cpu_infos + i;
131
54992
    result[j++] = OneByteString(isolate, ci->model);
132
54992
    result[j++] = Number::New(isolate, ci->speed);
133
54992
    result[j++] = Number::New(isolate, ci->cpu_times.user);
134
54992
    result[j++] = Number::New(isolate, ci->cpu_times.nice);
135
54992
    result[j++] = Number::New(isolate, ci->cpu_times.sys);
136
54992
    result[j++] = Number::New(isolate, ci->cpu_times.idle);
137
54992
    result[j++] = Number::New(isolate, ci->cpu_times.irq);
138
  }
139
140
3437
  uv_free_cpu_info(cpu_infos, count);
141
10311
  args.GetReturnValue().Set(Array::New(isolate, result.data(), result.size()));
142
}
143
144
145
3
static void GetFreeMemory(const FunctionCallbackInfo<Value>& args) {
146
3
  double amount = uv_get_free_memory();
147
3
  if (amount < 0)
148
3
    return;
149
6
  args.GetReturnValue().Set(amount);
150
}
151
152
153
3429
static void GetTotalMemory(const FunctionCallbackInfo<Value>& args) {
154
3429
  double amount = uv_get_total_memory();
155
3429
  if (amount < 0)
156
3429
    return;
157
6858
  args.GetReturnValue().Set(amount);
158
}
159
160
161
3
static void GetUptime(const FunctionCallbackInfo<Value>& args) {
162
  double uptime;
163
3
  int err = uv_uptime(&uptime);
164
3
  if (err == 0)
165
9
    args.GetReturnValue().Set(uptime);
166
3
}
167
168
169
2
static void GetLoadAvg(const FunctionCallbackInfo<Value>& args) {
170
4
  CHECK(args[0]->IsFloat64Array());
171
4
  Local<Float64Array> array = args[0].As<Float64Array>();
172
2
  CHECK_EQ(array->Length(), 3);
173
2
  Local<ArrayBuffer> ab = array->Buffer();
174
2
  double* loadavg = static_cast<double*>(ab->GetContents().Data());
175
2
  uv_loadavg(loadavg);
176
2
}
177
178
179
3433
static void GetInterfaceAddresses(const FunctionCallbackInfo<Value>& args) {
180
3433
  Environment* env = Environment::GetCurrent(args);
181
3433
  Isolate* isolate = env->isolate();
182
  uv_interface_address_t* interfaces;
183
  int count, i;
184
  char ip[INET6_ADDRSTRLEN];
185
  char netmask[INET6_ADDRSTRLEN];
186
  std::array<char, 18> mac;
187
  Local<String> name, family;
188
189
3433
  int err = uv_interface_addresses(&interfaces, &count);
190
191
3433
  if (err == UV_ENOSYS)
192
    return args.GetReturnValue().SetUndefined();
193
194
3433
  if (err) {
195
    CHECK_GE(args.Length(), 1);
196
    env->CollectUVExceptionInfo(args[args.Length() - 1], errno,
197
                                "uv_interface_addresses");
198
    return args.GetReturnValue().SetUndefined();
199
  }
200
201
3433
  Local<Value> no_scope_id = Integer::New(isolate, -1);
202
3433
  std::vector<Local<Value>> result(count * 7);
203
24031
  for (i = 0; i < count; i++) {
204
20598
    const char* const raw_name = interfaces[i].name;
205
206
    // Use UTF-8 on both Windows and Unixes (While it may be true that UNIX
207
    // systems are somewhat encoding-agnostic here, it’s more than reasonable
208
    // to assume UTF8 as the default as well. It’s what people will expect if
209
    // they name the interface from any input that uses UTF-8, which should be
210
    // the most frequent case by far these days.)
211
    name = String::NewFromUtf8(isolate, raw_name,
212
41196
        v8::NewStringType::kNormal).ToLocalChecked();
213
214
    snprintf(mac.data(),
215
             mac.size(),
216
             "%02x:%02x:%02x:%02x:%02x:%02x",
217
20598
             static_cast<unsigned char>(interfaces[i].phys_addr[0]),
218
20598
             static_cast<unsigned char>(interfaces[i].phys_addr[1]),
219
20598
             static_cast<unsigned char>(interfaces[i].phys_addr[2]),
220
20598
             static_cast<unsigned char>(interfaces[i].phys_addr[3]),
221
20598
             static_cast<unsigned char>(interfaces[i].phys_addr[4]),
222
123588
             static_cast<unsigned char>(interfaces[i].phys_addr[5]));
223
224
20598
    if (interfaces[i].address.address4.sin_family == AF_INET) {
225
10299
      uv_ip4_name(&interfaces[i].address.address4, ip, sizeof(ip));
226
10299
      uv_ip4_name(&interfaces[i].netmask.netmask4, netmask, sizeof(netmask));
227
10299
      family = env->ipv4_string();
228
10299
    } else if (interfaces[i].address.address4.sin_family == AF_INET6) {
229
10299
      uv_ip6_name(&interfaces[i].address.address6, ip, sizeof(ip));
230
10298
      uv_ip6_name(&interfaces[i].netmask.netmask6, netmask, sizeof(netmask));
231
10298
      family = env->ipv6_string();
232
    } else {
233
      strncpy(ip, "<unknown sa family>", INET6_ADDRSTRLEN);
234
      family = env->unknown_string();
235
    }
236
237
41194
    result[i * 7] = name;
238
41195
    result[i * 7 + 1] = OneByteString(isolate, ip);
239
41196
    result[i * 7 + 2] = OneByteString(isolate, netmask);
240
41196
    result[i * 7 + 3] = family;
241
41196
    result[i * 7 + 4] = FIXED_ONE_BYTE_STRING(isolate, mac);
242
20598
    result[i * 7 + 5] =
243
41194
      interfaces[i].is_internal ? True(isolate) : False(isolate);
244
20597
    if (interfaces[i].address.address4.sin_family == AF_INET6) {
245
10299
      uint32_t scopeid = interfaces[i].address.address6.sin6_scope_id;
246
20598
      result[i * 7 + 6] = Integer::NewFromUnsigned(isolate, scopeid);
247
    } else {
248
10298
      result[i * 7 + 6] = no_scope_id;
249
    }
250
  }
251
252
3433
  uv_free_interface_addresses(interfaces, count);
253
10299
  args.GetReturnValue().Set(Array::New(isolate, result.data(), result.size()));
254
}
255
256
257
273
static void GetHomeDirectory(const FunctionCallbackInfo<Value>& args) {
258
273
  Environment* env = Environment::GetCurrent(args);
259
  char buf[PATH_MAX];
260
261
273
  size_t len = sizeof(buf);
262
273
  const int err = uv_os_homedir(buf, &len);
263
264
273
  if (err) {
265
    CHECK_GE(args.Length(), 1);
266
    env->CollectUVExceptionInfo(args[args.Length() - 1], err, "uv_os_homedir");
267
273
    return args.GetReturnValue().SetUndefined();
268
  }
269
270
  Local<String> home = String::NewFromUtf8(env->isolate(),
271
                                           buf,
272
                                           v8::NewStringType::kNormal,
273
546
                                           len).ToLocalChecked();
274
546
  args.GetReturnValue().Set(home);
275
}
276
277
278
3
static void GetUserInfo(const FunctionCallbackInfo<Value>& args) {
279
3
  Environment* env = Environment::GetCurrent(args);
280
  uv_passwd_t pwd;
281
  enum encoding encoding;
282
283
6
  if (args[0]->IsObject()) {
284
4
    Local<Object> options = args[0].As<Object>();
285
    MaybeLocal<Value> maybe_encoding = options->Get(env->context(),
286
6
                                                    env->encoding_string());
287
2
    if (maybe_encoding.IsEmpty())
288
1
      return;
289
290
1
    Local<Value> encoding_opt = maybe_encoding.ToLocalChecked();
291
1
    encoding = ParseEncoding(env->isolate(), encoding_opt, UTF8);
292
  } else {
293
1
    encoding = UTF8;
294
  }
295
296
2
  const int err = uv_os_get_passwd(&pwd);
297
298
2
  if (err) {
299
    CHECK_GE(args.Length(), 2);
300
    env->CollectUVExceptionInfo(args[args.Length() - 1], err,
301
                                "uv_os_get_passwd");
302
    return args.GetReturnValue().SetUndefined();
303
  }
304
305
4
  OnScopeLeave free_passwd([&]() { uv_os_free_passwd(&pwd); });
306
307
  Local<Value> error;
308
309
2
  Local<Value> uid = Number::New(env->isolate(), pwd.uid);
310
2
  Local<Value> gid = Number::New(env->isolate(), pwd.gid);
311
  MaybeLocal<Value> username = StringBytes::Encode(env->isolate(),
312
                                                   pwd.username,
313
                                                   encoding,
314
2
                                                   &error);
315
  MaybeLocal<Value> homedir = StringBytes::Encode(env->isolate(),
316
                                                  pwd.homedir,
317
                                                  encoding,
318
2
                                                  &error);
319
  MaybeLocal<Value> shell;
320
321
2
  if (pwd.shell == nullptr)
322
    shell = Null(env->isolate());
323
  else
324
2
    shell = StringBytes::Encode(env->isolate(), pwd.shell, encoding, &error);
325
326


6
  if (username.IsEmpty() || homedir.IsEmpty() || shell.IsEmpty()) {
327
    CHECK(!error.IsEmpty());
328
    env->isolate()->ThrowException(error);
329
    return;
330
  }
331
332
2
  Local<Object> entry = Object::New(env->isolate());
333
334
8
  entry->Set(env->context(), env->uid_string(), uid).Check();
335
8
  entry->Set(env->context(), env->gid_string(), gid).Check();
336
  entry->Set(env->context(),
337
             env->username_string(),
338
8
             username.ToLocalChecked()).Check();
339
  entry->Set(env->context(),
340
             env->homedir_string(),
341
8
             homedir.ToLocalChecked()).Check();
342
  entry->Set(env->context(),
343
             env->shell_string(),
344
8
             shell.ToLocalChecked()).Check();
345
346
4
  args.GetReturnValue().Set(entry);
347
}
348
349
350
80
static void SetPriority(const FunctionCallbackInfo<Value>& args) {
351
80
  Environment* env = Environment::GetCurrent(args);
352
353
80
  CHECK_EQ(args.Length(), 3);
354
160
  CHECK(args[0]->IsInt32());
355
160
  CHECK(args[1]->IsInt32());
356
357
240
  const int pid = args[0].As<Int32>()->Value();
358
240
  const int priority = args[1].As<Int32>()->Value();
359
80
  const int err = uv_os_setpriority(pid, priority);
360
361
80
  if (err) {
362
40
    CHECK(args[2]->IsObject());
363
20
    env->CollectUVExceptionInfo(args[2], err, "uv_os_setpriority");
364
  }
365
366
160
  args.GetReturnValue().Set(err);
367
80
}
368
369
370
60
static void GetPriority(const FunctionCallbackInfo<Value>& args) {
371
60
  Environment* env = Environment::GetCurrent(args);
372
373
60
  CHECK_EQ(args.Length(), 2);
374
120
  CHECK(args[0]->IsInt32());
375
376
180
  const int pid = args[0].As<Int32>()->Value();
377
  int priority;
378
60
  const int err = uv_os_getpriority(pid, &priority);
379
380
60
  if (err) {
381
    CHECK(args[1]->IsObject());
382
    env->CollectUVExceptionInfo(args[1], err, "uv_os_getpriority");
383
    return;
384
  }
385
386
180
  args.GetReturnValue().Set(priority);
387
}
388
389
390
3559
void Initialize(Local<Object> target,
391
                Local<Value> unused,
392
                Local<Context> context,
393
                void* priv) {
394
3559
  Environment* env = Environment::GetCurrent(context);
395
3559
  env->SetMethod(target, "getHostname", GetHostname);
396
3559
  env->SetMethod(target, "getLoadAvg", GetLoadAvg);
397
3559
  env->SetMethod(target, "getUptime", GetUptime);
398
3559
  env->SetMethod(target, "getTotalMem", GetTotalMemory);
399
3559
  env->SetMethod(target, "getFreeMem", GetFreeMemory);
400
3559
  env->SetMethod(target, "getCPUs", GetCPUInfo);
401
3559
  env->SetMethod(target, "getOSType", GetOSType);
402
3559
  env->SetMethod(target, "getOSRelease", GetOSRelease);
403
3559
  env->SetMethod(target, "getInterfaceAddresses", GetInterfaceAddresses);
404
3559
  env->SetMethod(target, "getHomeDirectory", GetHomeDirectory);
405
3559
  env->SetMethod(target, "getUserInfo", GetUserInfo);
406
3559
  env->SetMethod(target, "setPriority", SetPriority);
407
3559
  env->SetMethod(target, "getPriority", GetPriority);
408
  target->Set(env->context(),
409
              FIXED_ONE_BYTE_STRING(env->isolate(), "isBigEndian"),
410
17795
              Boolean::New(env->isolate(), IsBigEndian())).Check();
411
3559
}
412
413
}  // namespace os
414
}  // namespace node
415
416
4953
NODE_MODULE_CONTEXT_AWARE_INTERNAL(os, node::os::Initialize)