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: 172 201 85.6 %
Date: 2020-06-24 22:13:30 Branches: 40 78 51.3 %

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


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