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


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