GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_os.cc Lines: 187 215 87.0 %
Date: 2022-09-07 04:19:57 Branches: 44 98 44.9 %

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


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