xref: /third_party/node/deps/uv/src/unix/ibmi.c (revision 1cb0ef41)
1/* Copyright libuv project contributors. All rights reserved.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to
5 * deal in the Software without restriction, including without limitation the
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 * IN THE SOFTWARE.
20 */
21
22#include "uv.h"
23#include "internal.h"
24
25#include <stdio.h>
26#include <stdint.h>
27#include <stdlib.h>
28#include <string.h>
29#include <errno.h>
30
31#include <sys/types.h>
32#include <sys/socket.h>
33#include <sys/ioctl.h>
34#include <net/if.h>
35#include <netinet/in.h>
36#include <arpa/inet.h>
37
38#include <sys/time.h>
39#include <unistd.h>
40#include <fcntl.h>
41#include <utmp.h>
42#include <libgen.h>
43
44#include <sys/protosw.h>
45#include <procinfo.h>
46#include <sys/proc.h>
47#include <sys/procfs.h>
48
49#include <ctype.h>
50
51#include <sys/mntctl.h>
52#include <sys/vmount.h>
53#include <limits.h>
54#include <strings.h>
55#include <sys/vnode.h>
56
57#include <as400_protos.h>
58#include <as400_types.h>
59
60char* original_exepath = NULL;
61uv_mutex_t process_title_mutex;
62uv_once_t process_title_mutex_once = UV_ONCE_INIT;
63
64typedef struct {
65  int bytes_available;
66  int bytes_returned;
67  char current_date_and_time[8];
68  char system_name[8];
69  char elapsed_time[6];
70  char restricted_state_flag;
71  char reserved;
72  int percent_processing_unit_used;
73  int jobs_in_system;
74  int percent_permanent_addresses;
75  int percent_temporary_addresses;
76  int system_asp;
77  int percent_system_asp_used;
78  int total_auxiliary_storage;
79  int current_unprotected_storage_used;
80  int maximum_unprotected_storage_used;
81  int percent_db_capability;
82  int main_storage_size;
83  int number_of_partitions;
84  int partition_identifier;
85  int reserved1;
86  int current_processing_capacity;
87  char processor_sharing_attribute;
88  char reserved2[3];
89  int number_of_processors;
90  int active_jobs_in_system;
91  int active_threads_in_system;
92  int maximum_jobs_in_system;
93  int percent_temporary_256mb_segments_used;
94  int percent_temporary_4gb_segments_used;
95  int percent_permanent_256mb_segments_used;
96  int percent_permanent_4gb_segments_used;
97  int percent_current_interactive_performance;
98  int percent_uncapped_cpu_capacity_used;
99  int percent_shared_processor_pool_used;
100  long main_storage_size_long;
101} SSTS0200;
102
103
104typedef struct {
105  char header[208];
106  unsigned char loca_adapter_address[12];
107} LIND0500;
108
109
110typedef struct {
111  int bytes_provided;
112  int bytes_available;
113  char msgid[7];
114} errcode_s;
115
116
117static const unsigned char e2a[256] = {
118    0, 1, 2, 3, 156, 9, 134, 127, 151, 141, 142, 11, 12, 13, 14, 15,
119    16, 17, 18, 19, 157, 133, 8, 135, 24, 25, 146, 143, 28, 29, 30, 31,
120    128, 129, 130, 131, 132, 10, 23, 27, 136, 137, 138, 139, 140, 5, 6, 7,
121    144, 145, 22, 147, 148, 149, 150, 4, 152, 153, 154, 155, 20, 21, 158, 26,
122    32, 160, 161, 162, 163, 164, 165, 166, 167, 168, 91, 46, 60, 40, 43, 33,
123    38, 169, 170, 171, 172, 173, 174, 175, 176, 177, 93, 36, 42, 41, 59, 94,
124    45, 47, 178, 179, 180, 181, 182, 183, 184, 185, 124, 44, 37, 95, 62, 63,
125    186, 187, 188, 189, 190, 191, 192, 193, 194, 96, 58, 35, 64, 39, 61, 34,
126    195, 97, 98, 99, 100, 101, 102, 103, 104, 105, 196, 197, 198, 199, 200, 201,
127    202, 106, 107, 108, 109, 110, 111, 112, 113, 114, 203, 204, 205, 206, 207, 208,
128    209, 126, 115, 116, 117, 118, 119, 120, 121, 122, 210, 211, 212, 213, 214, 215,
129    216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231,
130    123, 65, 66, 67, 68, 69, 70, 71, 72, 73, 232, 233, 234, 235, 236, 237,
131    125, 74, 75, 76, 77, 78, 79, 80, 81, 82, 238, 239, 240, 241, 242, 243,
132    92, 159, 83, 84, 85, 86, 87, 88, 89, 90, 244, 245, 246, 247, 248, 249,
133    48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 250, 251, 252, 253, 254, 255};
134
135
136static const unsigned char a2e[256] = {
137    0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15,
138    16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31,
139    64, 79, 127, 123, 91, 108, 80, 125, 77, 93, 92, 78, 107, 96, 75, 97,
140    240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 122, 94, 76, 126, 110, 111,
141    124, 193, 194, 195, 196, 197, 198, 199, 200, 201, 209, 210, 211, 212, 213, 214,
142    215, 216, 217, 226, 227, 228, 229, 230, 231, 232, 233, 74, 224, 90, 95, 109,
143    121, 129, 130, 131, 132, 133, 134, 135, 136, 137, 145, 146, 147, 148, 149, 150,
144    151, 152, 153, 162, 163, 164, 165, 166, 167, 168, 169, 192, 106, 208, 161, 7,
145    32, 33, 34, 35, 36, 21, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27,
146    48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62, 225,
147    65, 66, 67, 68, 69, 70, 71, 72, 73, 81, 82, 83, 84, 85, 86, 87,
148    88, 89, 98, 99, 100, 101, 102, 103, 104, 105, 112, 113, 114, 115, 116, 117,
149    118, 119, 120, 128, 138, 139, 140, 141, 142, 143, 144, 154, 155, 156, 157, 158,
150    159, 160, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183,
151    184, 185, 186, 187, 188, 189, 190, 191, 202, 203, 204, 205, 206, 207, 218, 219,
152    220, 221, 222, 223, 234, 235, 236, 237, 238, 239, 250, 251, 252, 253, 254, 255};
153
154
155static void iconv_e2a(unsigned char src[], unsigned char dst[], size_t length) {
156  size_t i;
157  for (i = 0; i < length; i++)
158    dst[i] = e2a[src[i]];
159}
160
161
162static void iconv_a2e(const char* src, unsigned char dst[], size_t length) {
163  size_t srclen;
164  size_t i;
165
166  srclen = strlen(src);
167  if (srclen > length)
168    srclen = length;
169  for (i = 0; i < srclen; i++)
170    dst[i] = a2e[src[i]];
171  /* padding the remaining part with spaces */
172  for (; i < length; i++)
173    dst[i] = a2e[' '];
174}
175
176void init_process_title_mutex_once(void) {
177  uv_mutex_init(&process_title_mutex);
178}
179
180static int get_ibmi_system_status(SSTS0200* rcvr) {
181  /* rcvrlen is input parameter 2 to QWCRSSTS */
182  unsigned int rcvrlen = sizeof(*rcvr);
183  unsigned char format[8], reset_status[10];
184
185  /* format is input parameter 3 to QWCRSSTS */
186  iconv_a2e("SSTS0200", format, sizeof(format));
187  /* reset_status is input parameter 4 */
188  iconv_a2e("*NO", reset_status, sizeof(reset_status));
189
190  /* errcode is input parameter 5 to QWCRSSTS */
191  errcode_s errcode;
192
193  /* qwcrssts_pointer is the 16-byte tagged system pointer to QWCRSSTS */
194  ILEpointer __attribute__((aligned(16))) qwcrssts_pointer;
195
196  /* qwcrssts_argv is the array of argument pointers to QWCRSSTS */
197  void* qwcrssts_argv[6];
198
199  /* Set the IBM i pointer to the QSYS/QWCRSSTS *PGM object */
200  int rc = _RSLOBJ2(&qwcrssts_pointer, RSLOBJ_TS_PGM, "QWCRSSTS", "QSYS");
201
202  if (rc != 0)
203    return rc;
204
205  /* initialize the QWCRSSTS returned info structure */
206  memset(rcvr, 0, sizeof(*rcvr));
207
208  /* initialize the QWCRSSTS error code structure */
209  memset(&errcode, 0, sizeof(errcode));
210  errcode.bytes_provided = sizeof(errcode);
211
212  /* initialize the array of argument pointers for the QWCRSSTS API */
213  qwcrssts_argv[0] = rcvr;
214  qwcrssts_argv[1] = &rcvrlen;
215  qwcrssts_argv[2] = &format;
216  qwcrssts_argv[3] = &reset_status;
217  qwcrssts_argv[4] = &errcode;
218  qwcrssts_argv[5] = NULL;
219
220  /* Call the IBM i QWCRSSTS API from PASE */
221  rc = _PGMCALL(&qwcrssts_pointer, qwcrssts_argv, 0);
222
223  return rc;
224}
225
226
227uint64_t uv_get_free_memory(void) {
228  SSTS0200 rcvr;
229
230  if (get_ibmi_system_status(&rcvr))
231    return 0;
232
233  return (uint64_t)rcvr.main_storage_size * 1024ULL;
234}
235
236
237uint64_t uv_get_total_memory(void) {
238  SSTS0200 rcvr;
239
240  if (get_ibmi_system_status(&rcvr))
241    return 0;
242
243  return (uint64_t)rcvr.main_storage_size * 1024ULL;
244}
245
246
247uint64_t uv_get_constrained_memory(void) {
248  return 0;  /* Memory constraints are unknown. */
249}
250
251
252void uv_loadavg(double avg[3]) {
253  SSTS0200 rcvr;
254
255  if (get_ibmi_system_status(&rcvr)) {
256    avg[0] = avg[1] = avg[2] = 0;
257    return;
258  }
259
260  /* The average (in tenths) of the elapsed time during which the processing
261   * units were in use. For example, a value of 411 in binary would be 41.1%.
262   * This percentage could be greater than 100% for an uncapped partition.
263   */
264  double processing_unit_used_percent =
265    rcvr.percent_processing_unit_used / 1000.0;
266
267  avg[0] = avg[1] = avg[2] = processing_unit_used_percent;
268}
269
270
271int uv_resident_set_memory(size_t* rss) {
272  *rss = 0;
273  return 0;
274}
275
276
277int uv_uptime(double* uptime) {
278  return UV_ENOSYS;
279}
280
281
282int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
283  unsigned int numcpus, idx = 0;
284  uv_cpu_info_t* cpu_info;
285
286  *cpu_infos = NULL;
287  *count = 0;
288
289  numcpus = sysconf(_SC_NPROCESSORS_ONLN);
290
291  *cpu_infos = uv__malloc(numcpus * sizeof(uv_cpu_info_t));
292  if (!*cpu_infos) {
293    return UV_ENOMEM;
294  }
295
296  cpu_info = *cpu_infos;
297  for (idx = 0; idx < numcpus; idx++) {
298    cpu_info->speed = 0;
299    cpu_info->model = uv__strdup("unknown");
300    cpu_info->cpu_times.user = 0;
301    cpu_info->cpu_times.sys = 0;
302    cpu_info->cpu_times.idle = 0;
303    cpu_info->cpu_times.irq = 0;
304    cpu_info->cpu_times.nice = 0;
305    cpu_info++;
306  }
307  *count = numcpus;
308
309  return 0;
310}
311
312
313static int get_ibmi_physical_address(const char* line, char (*phys_addr)[6]) {
314  LIND0500 rcvr;
315  /* rcvrlen is input parameter 2 to QDCRLIND */
316  unsigned int rcvrlen = sizeof(rcvr);
317  unsigned char format[8], line_name[10];
318  unsigned char mac_addr[sizeof(rcvr.loca_adapter_address)];
319  int c[6];
320
321  /* format is input parameter 3 to QDCRLIND */
322  iconv_a2e("LIND0500", format, sizeof(format));
323
324  /* line_name is input parameter 4 to QDCRLIND */
325  iconv_a2e(line, line_name, sizeof(line_name));
326
327  /* err is input parameter 5 to QDCRLIND */
328  errcode_s err;
329
330  /* qwcrssts_pointer is the 16-byte tagged system pointer to QDCRLIND */
331  ILEpointer __attribute__((aligned(16))) qdcrlind_pointer;
332
333  /* qwcrssts_argv is the array of argument pointers to QDCRLIND */
334  void* qdcrlind_argv[6];
335
336  /* Set the IBM i pointer to the QSYS/QDCRLIND *PGM object */
337  int rc = _RSLOBJ2(&qdcrlind_pointer, RSLOBJ_TS_PGM, "QDCRLIND", "QSYS");
338
339  if (rc != 0)
340    return rc;
341
342  /* initialize the QDCRLIND returned info structure */
343  memset(&rcvr, 0, sizeof(rcvr));
344
345  /* initialize the QDCRLIND error code structure */
346  memset(&err, 0, sizeof(err));
347  err.bytes_provided = sizeof(err);
348
349  /* initialize the array of argument pointers for the QDCRLIND API */
350  qdcrlind_argv[0] = &rcvr;
351  qdcrlind_argv[1] = &rcvrlen;
352  qdcrlind_argv[2] = &format;
353  qdcrlind_argv[3] = &line_name;
354  qdcrlind_argv[4] = &err;
355  qdcrlind_argv[5] = NULL;
356
357  /* Call the IBM i QDCRLIND API from PASE */
358  rc = _PGMCALL(&qdcrlind_pointer, qdcrlind_argv, 0);
359  if (rc != 0)
360    return rc;
361
362  if (err.bytes_available > 0) {
363    return -1;
364  }
365
366  /* convert ebcdic loca_adapter_address to ascii first */
367  iconv_e2a(rcvr.loca_adapter_address, mac_addr,
368            sizeof(rcvr.loca_adapter_address));
369
370  /* convert loca_adapter_address(char[12]) to phys_addr(char[6]) */
371  int r = sscanf(mac_addr, "%02x%02x%02x%02x%02x%02x",
372                &c[0], &c[1], &c[2], &c[3], &c[4], &c[5]);
373
374  if (r == ARRAY_SIZE(c)) {
375    (*phys_addr)[0] = c[0];
376    (*phys_addr)[1] = c[1];
377    (*phys_addr)[2] = c[2];
378    (*phys_addr)[3] = c[3];
379    (*phys_addr)[4] = c[4];
380    (*phys_addr)[5] = c[5];
381  } else {
382    memset(*phys_addr, 0, sizeof(*phys_addr));
383    rc = -1;
384  }
385  return rc;
386}
387
388
389int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
390  uv_interface_address_t* address;
391  struct ifaddrs_pase *ifap = NULL, *cur;
392  int inet6, r = 0;
393
394  *count = 0;
395  *addresses = NULL;
396
397  if (Qp2getifaddrs(&ifap))
398    return UV_ENOSYS;
399
400  /* The first loop to get the size of the array to be allocated */
401  for (cur = ifap; cur; cur = cur->ifa_next) {
402    if (!(cur->ifa_addr->sa_family == AF_INET6 ||
403          cur->ifa_addr->sa_family == AF_INET))
404      continue;
405
406    if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING))
407      continue;
408
409    (*count)++;
410  }
411
412  if (*count == 0) {
413    Qp2freeifaddrs(ifap);
414    return 0;
415  }
416
417  /* Alloc the return interface structs */
418  *addresses = uv__calloc(*count, sizeof(**addresses));
419  if (*addresses == NULL) {
420    Qp2freeifaddrs(ifap);
421    return UV_ENOMEM;
422  }
423  address = *addresses;
424
425  /* The second loop to fill in the array */
426  for (cur = ifap; cur; cur = cur->ifa_next) {
427    if (!(cur->ifa_addr->sa_family == AF_INET6 ||
428          cur->ifa_addr->sa_family == AF_INET))
429      continue;
430
431    if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING))
432      continue;
433
434    address->name = uv__strdup(cur->ifa_name);
435
436    inet6 = (cur->ifa_addr->sa_family == AF_INET6);
437
438    if (inet6) {
439      address->address.address6 = *((struct sockaddr_in6*)cur->ifa_addr);
440      address->netmask.netmask6 = *((struct sockaddr_in6*)cur->ifa_netmask);
441      address->netmask.netmask6.sin6_family = AF_INET6;
442    } else {
443      address->address.address4 = *((struct sockaddr_in*)cur->ifa_addr);
444      address->netmask.netmask4 = *((struct sockaddr_in*)cur->ifa_netmask);
445      address->netmask.netmask4.sin_family = AF_INET;
446    }
447    address->is_internal = cur->ifa_flags & IFF_LOOPBACK ? 1 : 0;
448    if (!address->is_internal) {
449      int rc = -1;
450      size_t name_len = strlen(address->name);
451      /* To get the associated MAC address, we must convert the address to a
452       * line description. Normally, the name field contains the line
453       * description name, but for VLANs it has the VLAN appended with a
454       * period. Since object names can also contain periods and numbers, there
455       * is no way to know if a returned name is for a VLAN or not. eg.
456       * *LIND ETH1.1 and *LIND ETH1, VLAN 1 both have the same name: ETH1.1
457       *
458       * Instead, we apply the same heuristic used by some of the XPF ioctls:
459       * - names > 10 *must* contain a VLAN
460       * - assume names <= 10 do not contain a VLAN and try directly
461       * - if >10 or QDCRLIND returned an error, try to strip off a VLAN
462       *   and try again
463       * - if we still get an error or couldn't find a period, leave the MAC as
464       *   00:00:00:00:00:00
465       */
466      if (name_len <= 10) {
467        /* Assume name does not contain a VLAN ID */
468        rc = get_ibmi_physical_address(address->name, &address->phys_addr);
469      }
470
471      if (name_len > 10 || rc != 0) {
472        /* The interface name must contain a VLAN ID suffix. Attempt to strip
473         * it off so we can get the line description to pass to QDCRLIND.
474         */
475        char* temp_name = uv__strdup(address->name);
476        char* dot = strrchr(temp_name, '.');
477        if (dot != NULL) {
478          *dot = '\0';
479          if (strlen(temp_name) <= 10) {
480            rc = get_ibmi_physical_address(temp_name, &address->phys_addr);
481          }
482        }
483        uv__free(temp_name);
484      }
485    }
486
487    address++;
488  }
489
490  Qp2freeifaddrs(ifap);
491  return r;
492}
493
494
495void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) {
496  int i;
497
498  for (i = 0; i < count; ++i) {
499    uv__free(addresses[i].name);
500  }
501
502  uv__free(addresses);
503}
504
505char** uv_setup_args(int argc, char** argv) {
506  char exepath[UV__PATH_MAX];
507  char* s;
508  size_t size;
509
510  if (argc > 0) {
511    /* Use argv[0] to determine value for uv_exepath(). */
512    size = sizeof(exepath);
513    if (uv__search_path(argv[0], exepath, &size) == 0) {
514      uv_once(&process_title_mutex_once, init_process_title_mutex_once);
515      uv_mutex_lock(&process_title_mutex);
516      original_exepath = uv__strdup(exepath);
517      uv_mutex_unlock(&process_title_mutex);
518    }
519  }
520
521  return argv;
522}
523
524int uv_set_process_title(const char* title) {
525  return 0;
526}
527
528int uv_get_process_title(char* buffer, size_t size) {
529  if (buffer == NULL || size == 0)
530    return UV_EINVAL;
531
532  buffer[0] = '\0';
533  return 0;
534}
535
536void uv__process_title_cleanup(void) {
537}
538