GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_os.cc Lines: 187 215 87.0 %
Date: 2022-09-19 04:21:54 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 <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
40
static void GetHostname(const FunctionCallbackInfo<Value>& args) {
61
40
  Environment* env = Environment::GetCurrent(args);
62
  char buf[UV_MAXHOSTNAMESIZE];
63
40
  size_t size = sizeof(buf);
64
40
  int r = uv_os_gethostname(buf, &size);
65
66
40
  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
120
  args.GetReturnValue().Set(
74
80
      String::NewFromUtf8(env->isolate(), buf).ToLocalChecked());
75
}
76
77
705
static void GetOSInformation(const FunctionCallbackInfo<Value>& args) {
78
705
  Environment* env = Environment::GetCurrent(args);
79
  uv_utsname_t info;
80
705
  int err = uv_os_uname(&info);
81
82
705
  if (err != 0) {
83
    CHECK_GE(args.Length(), 1);
84
    env->CollectUVExceptionInfo(args[args.Length() - 1], err, "uv_os_uname");
85
    return args.GetReturnValue().SetUndefined();
86
  }
87
88
  // [sysname, version, release, machine]
89
  Local<Value> osInformation[] = {
90
705
      String::NewFromUtf8(env->isolate(), info.sysname).ToLocalChecked(),
91
705
      String::NewFromUtf8(env->isolate(), info.version).ToLocalChecked(),
92
705
      String::NewFromUtf8(env->isolate(), info.release).ToLocalChecked(),
93
3525
      String::NewFromUtf8(env->isolate(), info.machine).ToLocalChecked()};
94
95
1410
  args.GetReturnValue().Set(Array::New(env->isolate(),
96
                                       osInformation,
97
                                       arraysize(osInformation)));
98
}
99
100
62
static void GetCPUInfo(const FunctionCallbackInfo<Value>& args) {
101
62
  Environment* env = Environment::GetCurrent(args);
102
62
  Isolate* isolate = env->isolate();
103
104
  uv_cpu_info_t* cpu_infos;
105
  int count;
106
107
62
  int err = uv_cpu_info(&cpu_infos, &count);
108
62
  if (err)
109
    return;
110
111
  // It's faster to create an array packed with all the data and
112
  // assemble them into objects in JS than to call Object::Set() repeatedly
113
  // The array is in the format
114
  // [model, speed, (5 entries of cpu_times), model2, speed2, ...]
115
62
  std::vector<Local<Value>> result;
116
62
  result.reserve(count * 7);
117
5518
  for (int i = 0; i < count; i++) {
118
5456
    uv_cpu_info_t* ci = cpu_infos + i;
119
5456
    result.emplace_back(OneByteString(isolate, ci->model));
120
5456
    result.emplace_back(Number::New(isolate, ci->speed));
121
    result.emplace_back(
122
5456
        Number::New(isolate, static_cast<double>(ci->cpu_times.user)));
123
    result.emplace_back(
124
5456
        Number::New(isolate, static_cast<double>(ci->cpu_times.nice)));
125
    result.emplace_back(
126
5456
        Number::New(isolate, static_cast<double>(ci->cpu_times.sys)));
127
    result.emplace_back(
128
5456
        Number::New(isolate, static_cast<double>(ci->cpu_times.idle)));
129
    result.emplace_back(
130
5456
        Number::New(isolate, static_cast<double>(ci->cpu_times.irq)));
131
  }
132
133
62
  uv_free_cpu_info(cpu_infos, count);
134
124
  args.GetReturnValue().Set(Array::New(isolate, result.data(), result.size()));
135
}
136
137
138
3
static void GetFreeMemory(const FunctionCallbackInfo<Value>& args) {
139
3
  double amount = static_cast<double>(uv_get_free_memory());
140
3
  args.GetReturnValue().Set(amount);
141
3
}
142
143
144
133
static void GetTotalMemory(const FunctionCallbackInfo<Value>& args) {
145
133
  double amount = static_cast<double>(uv_get_total_memory());
146
133
  args.GetReturnValue().Set(amount);
147
133
}
148
149
150
3
static void GetUptime(const FunctionCallbackInfo<Value>& args) {
151
3
  Environment* env = Environment::GetCurrent(args);
152
  double uptime;
153
3
  int err = uv_uptime(&uptime);
154
3
  if (err != 0) {
155
    env->CollectUVExceptionInfo(args[args.Length() - 1], err, "uv_uptime");
156
    return args.GetReturnValue().SetUndefined();
157
  }
158
159
6
  args.GetReturnValue().Set(uptime);
160
}
161
162
163
1
static void GetLoadAvg(const FunctionCallbackInfo<Value>& args) {
164
1
  CHECK(args[0]->IsFloat64Array());
165
2
  Local<Float64Array> array = args[0].As<Float64Array>();
166
1
  CHECK_EQ(array->Length(), 3);
167
1
  Local<ArrayBuffer> ab = array->Buffer();
168
1
  double* loadavg = static_cast<double*>(ab->Data());
169
1
  uv_loadavg(loadavg);
170
1
}
171
172
173
166
static void GetInterfaceAddresses(const FunctionCallbackInfo<Value>& args) {
174
166
  Environment* env = Environment::GetCurrent(args);
175
166
  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
166
  int err = uv_interface_addresses(&interfaces, &count);
184
185
166
  if (err == UV_ENOSYS)
186
    return args.GetReturnValue().SetUndefined();
187
188
166
  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
166
  Local<Value> no_scope_id = Integer::New(isolate, -1);
196
166
  std::vector<Local<Value>> result;
197
166
  result.reserve(count * 7);
198
830
  for (i = 0; i < count; i++) {
199
664
    const char* const raw_name = interfaces[i].name;
200
201
    // Use UTF-8 on both Windows and Unixes (While it may be true that UNIX
202
    // systems are somewhat encoding-agnostic here, it’s more than reasonable
203
    // to assume UTF8 as the default as well. It’s what people will expect if
204
    // they name the interface from any input that uses UTF-8, which should be
205
    // the most frequent case by far these days.)
206
664
    name = String::NewFromUtf8(isolate, raw_name).ToLocalChecked();
207
208
664
    snprintf(mac.data(),
209
             mac.size(),
210
             "%02x:%02x:%02x:%02x:%02x:%02x",
211
664
             static_cast<unsigned char>(interfaces[i].phys_addr[0]),
212
664
             static_cast<unsigned char>(interfaces[i].phys_addr[1]),
213
664
             static_cast<unsigned char>(interfaces[i].phys_addr[2]),
214
664
             static_cast<unsigned char>(interfaces[i].phys_addr[3]),
215
664
             static_cast<unsigned char>(interfaces[i].phys_addr[4]),
216
664
             static_cast<unsigned char>(interfaces[i].phys_addr[5]));
217
218
664
    if (interfaces[i].address.address4.sin_family == AF_INET) {
219
332
      uv_ip4_name(&interfaces[i].address.address4, ip, sizeof(ip));
220
332
      uv_ip4_name(&interfaces[i].netmask.netmask4, netmask, sizeof(netmask));
221
332
      family = env->ipv4_string();
222
332
    } else if (interfaces[i].address.address4.sin_family == AF_INET6) {
223
332
      uv_ip6_name(&interfaces[i].address.address6, ip, sizeof(ip));
224
332
      uv_ip6_name(&interfaces[i].netmask.netmask6, netmask, sizeof(netmask));
225
332
      family = env->ipv6_string();
226
    } else {
227
      strncpy(ip, "<unknown sa family>", INET6_ADDRSTRLEN);
228
      family = env->unknown_string();
229
    }
230
231
664
    result.emplace_back(name);
232
664
    result.emplace_back(OneByteString(isolate, ip));
233
664
    result.emplace_back(OneByteString(isolate, netmask));
234
664
    result.emplace_back(family);
235
664
    result.emplace_back(FIXED_ONE_BYTE_STRING(isolate, mac));
236
    result.emplace_back(
237
1328
        interfaces[i].is_internal ? True(isolate) : False(isolate));
238
664
    if (interfaces[i].address.address4.sin_family == AF_INET6) {
239
332
      uint32_t scopeid = interfaces[i].address.address6.sin6_scope_id;
240
332
      result.emplace_back(Integer::NewFromUnsigned(isolate, scopeid));
241
    } else {
242
332
      result.emplace_back(no_scope_id);
243
    }
244
  }
245
246
166
  uv_free_interface_addresses(interfaces, count);
247
332
  args.GetReturnValue().Set(Array::New(isolate, result.data(), result.size()));
248
}
249
250
251
312
static void GetHomeDirectory(const FunctionCallbackInfo<Value>& args) {
252
312
  Environment* env = Environment::GetCurrent(args);
253
  char buf[PATH_MAX];
254
255
312
  size_t len = sizeof(buf);
256
312
  const int err = uv_os_homedir(buf, &len);
257
258
312
  if (err) {
259
    CHECK_GE(args.Length(), 1);
260
    env->CollectUVExceptionInfo(args[args.Length() - 1], err, "uv_os_homedir");
261
    return args.GetReturnValue().SetUndefined();
262
  }
263
264
312
  Local<String> home = String::NewFromUtf8(env->isolate(),
265
                                           buf,
266
                                           NewStringType::kNormal,
267
624
                                           len).ToLocalChecked();
268
624
  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
3
  if (args[0]->IsObject()) {
278
4
    Local<Object> options = args[0].As<Object>();
279
    MaybeLocal<Value> maybe_encoding = options->Get(env->context(),
280
4
                                                    env->encoding_string());
281
    Local<Value> encoding_opt;
282
2
    if (!maybe_encoding.ToLocal(&encoding_opt))
283
1
        return;
284
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
  auto free_passwd = OnScopeLeave([&]() { 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
2
                                                   pwd.username,
307
                                                   encoding,
308
2
                                                   &error);
309
  MaybeLocal<Value> homedir = StringBytes::Encode(env->isolate(),
310
2
                                                  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
6
  entry->Set(env->context(), env->uid_string(), uid).Check();
329
6
  entry->Set(env->context(), env->gid_string(), gid).Check();
330
2
  entry->Set(env->context(),
331
             env->username_string(),
332
8
             username.ToLocalChecked()).Check();
333
2
  entry->Set(env->context(),
334
             env->homedir_string(),
335
8
             homedir.ToLocalChecked()).Check();
336
2
  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
80
  CHECK(args[0]->IsInt32());
349
80
  CHECK(args[1]->IsInt32());
350
351
160
  const int pid = args[0].As<Int32>()->Value();
352
160
  const int priority = args[1].As<Int32>()->Value();
353
80
  const int err = uv_os_setpriority(pid, priority);
354
355
80
  if (err) {
356
20
    CHECK(args[2]->IsObject());
357
20
    env->CollectUVExceptionInfo(args[2], err, "uv_os_setpriority");
358
  }
359
360
80
  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
60
  CHECK(args[0]->IsInt32());
369
370
120
  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
120
  args.GetReturnValue().Set(priority);
381
}
382
383
384
706
void Initialize(Local<Object> target,
385
                Local<Value> unused,
386
                Local<Context> context,
387
                void* priv) {
388
706
  Environment* env = Environment::GetCurrent(context);
389
706
  SetMethod(context, target, "getHostname", GetHostname);
390
706
  SetMethod(context, target, "getLoadAvg", GetLoadAvg);
391
706
  SetMethod(context, target, "getUptime", GetUptime);
392
706
  SetMethod(context, target, "getTotalMem", GetTotalMemory);
393
706
  SetMethod(context, target, "getFreeMem", GetFreeMemory);
394
706
  SetMethod(context, target, "getCPUs", GetCPUInfo);
395
706
  SetMethod(context, target, "getInterfaceAddresses", GetInterfaceAddresses);
396
706
  SetMethod(context, target, "getHomeDirectory", GetHomeDirectory);
397
706
  SetMethod(context, target, "getUserInfo", GetUserInfo);
398
706
  SetMethod(context, target, "setPriority", SetPriority);
399
706
  SetMethod(context, target, "getPriority", GetPriority);
400
706
  SetMethod(context, target, "getOSInformation", GetOSInformation);
401
  target
402
706
      ->Set(context,
403
            FIXED_ONE_BYTE_STRING(env->isolate(), "isBigEndian"),
404
2118
            Boolean::New(env->isolate(), IsBigEndian()))
405
      .Check();
406
706
}
407
408
5528
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
409
5528
  registry->Register(GetHostname);
410
5528
  registry->Register(GetLoadAvg);
411
5528
  registry->Register(GetUptime);
412
5528
  registry->Register(GetTotalMemory);
413
5528
  registry->Register(GetFreeMemory);
414
5528
  registry->Register(GetCPUInfo);
415
5528
  registry->Register(GetInterfaceAddresses);
416
5528
  registry->Register(GetHomeDirectory);
417
5528
  registry->Register(GetUserInfo);
418
5528
  registry->Register(SetPriority);
419
5528
  registry->Register(GetPriority);
420
5528
  registry->Register(GetOSInformation);
421
5528
}
422
423
}  // namespace os
424
}  // namespace node
425
426
5598
NODE_MODULE_CONTEXT_AWARE_INTERNAL(os, node::os::Initialize)
427
5528
NODE_MODULE_EXTERNAL_REFERENCE(os, node::os::RegisterExternalReferences)