xref: /libuv/src/unix/ibmi.c (revision 988d225c)
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 
60 char* original_exepath = NULL;
61 uv_mutex_t process_title_mutex;
62 uv_once_t process_title_mutex_once = UV_ONCE_INIT;
63 
64 typedef 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 
104 typedef struct {
105   char header[208];
106   unsigned char loca_adapter_address[12];
107 } LIND0500;
108 
109 
110 typedef struct {
111   int bytes_provided;
112   int bytes_available;
113   char msgid[7];
114 } errcode_s;
115 
116 
117 static 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 
136 static 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 
iconv_e2a(unsigned char src[],unsigned char dst[],size_t length)155 static 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 
iconv_a2e(const char * src,unsigned char dst[],size_t length)162 static 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 
init_process_title_mutex_once(void)176 void init_process_title_mutex_once(void) {
177   uv_mutex_init(&process_title_mutex);
178 }
179 
get_ibmi_system_status(SSTS0200 * rcvr)180 static 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 
uv_get_free_memory(void)227 uint64_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 
uv_get_total_memory(void)237 uint64_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 
uv_get_constrained_memory(void)247 uint64_t uv_get_constrained_memory(void) {
248   return 0;  /* Memory constraints are unknown. */
249 }
250 
251 
uv_get_available_memory(void)252 uint64_t uv_get_available_memory(void) {
253   return uv_get_free_memory();
254 }
255 
256 
uv_loadavg(double avg[3])257 void uv_loadavg(double avg[3]) {
258   SSTS0200 rcvr;
259 
260   if (get_ibmi_system_status(&rcvr)) {
261     avg[0] = avg[1] = avg[2] = 0;
262     return;
263   }
264 
265   /* The average (in tenths) of the elapsed time during which the processing
266    * units were in use. For example, a value of 411 in binary would be 41.1%.
267    * This percentage could be greater than 100% for an uncapped partition.
268    */
269   double processing_unit_used_percent =
270     rcvr.percent_processing_unit_used / 1000.0;
271 
272   avg[0] = avg[1] = avg[2] = processing_unit_used_percent;
273 }
274 
275 
uv_resident_set_memory(size_t * rss)276 int uv_resident_set_memory(size_t* rss) {
277   *rss = 0;
278   return 0;
279 }
280 
281 
uv_uptime(double * uptime)282 int uv_uptime(double* uptime) {
283   return UV_ENOSYS;
284 }
285 
286 
uv_cpu_info(uv_cpu_info_t ** cpu_infos,int * count)287 int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
288   unsigned int numcpus, idx = 0;
289   uv_cpu_info_t* cpu_info;
290 
291   *cpu_infos = NULL;
292   *count = 0;
293 
294   numcpus = sysconf(_SC_NPROCESSORS_ONLN);
295 
296   *cpu_infos = uv__malloc(numcpus * sizeof(uv_cpu_info_t));
297   if (!*cpu_infos) {
298     return UV_ENOMEM;
299   }
300 
301   cpu_info = *cpu_infos;
302   for (idx = 0; idx < numcpus; idx++) {
303     cpu_info->speed = 0;
304     cpu_info->model = uv__strdup("unknown");
305     cpu_info->cpu_times.user = 0;
306     cpu_info->cpu_times.sys = 0;
307     cpu_info->cpu_times.idle = 0;
308     cpu_info->cpu_times.irq = 0;
309     cpu_info->cpu_times.nice = 0;
310     cpu_info++;
311   }
312   *count = numcpus;
313 
314   return 0;
315 }
316 
317 
get_ibmi_physical_address(const char * line,char (* phys_addr)[6])318 static int get_ibmi_physical_address(const char* line, char (*phys_addr)[6]) {
319   LIND0500 rcvr;
320   /* rcvrlen is input parameter 2 to QDCRLIND */
321   unsigned int rcvrlen = sizeof(rcvr);
322   unsigned char format[8], line_name[10];
323   unsigned char mac_addr[sizeof(rcvr.loca_adapter_address)];
324   int c[6];
325 
326   /* format is input parameter 3 to QDCRLIND */
327   iconv_a2e("LIND0500", format, sizeof(format));
328 
329   /* line_name is input parameter 4 to QDCRLIND */
330   iconv_a2e(line, line_name, sizeof(line_name));
331 
332   /* err is input parameter 5 to QDCRLIND */
333   errcode_s err;
334 
335   /* qwcrssts_pointer is the 16-byte tagged system pointer to QDCRLIND */
336   ILEpointer __attribute__((aligned(16))) qdcrlind_pointer;
337 
338   /* qwcrssts_argv is the array of argument pointers to QDCRLIND */
339   void* qdcrlind_argv[6];
340 
341   /* Set the IBM i pointer to the QSYS/QDCRLIND *PGM object */
342   int rc = _RSLOBJ2(&qdcrlind_pointer, RSLOBJ_TS_PGM, "QDCRLIND", "QSYS");
343 
344   if (rc != 0)
345     return rc;
346 
347   /* initialize the QDCRLIND returned info structure */
348   memset(&rcvr, 0, sizeof(rcvr));
349 
350   /* initialize the QDCRLIND error code structure */
351   memset(&err, 0, sizeof(err));
352   err.bytes_provided = sizeof(err);
353 
354   /* initialize the array of argument pointers for the QDCRLIND API */
355   qdcrlind_argv[0] = &rcvr;
356   qdcrlind_argv[1] = &rcvrlen;
357   qdcrlind_argv[2] = &format;
358   qdcrlind_argv[3] = &line_name;
359   qdcrlind_argv[4] = &err;
360   qdcrlind_argv[5] = NULL;
361 
362   /* Call the IBM i QDCRLIND API from PASE */
363   rc = _PGMCALL(&qdcrlind_pointer, qdcrlind_argv, 0);
364   if (rc != 0)
365     return rc;
366 
367   if (err.bytes_available > 0) {
368     return -1;
369   }
370 
371   /* convert ebcdic loca_adapter_address to ascii first */
372   iconv_e2a(rcvr.loca_adapter_address, mac_addr,
373             sizeof(rcvr.loca_adapter_address));
374 
375   /* convert loca_adapter_address(char[12]) to phys_addr(char[6]) */
376   int r = sscanf(mac_addr, "%02x%02x%02x%02x%02x%02x",
377                 &c[0], &c[1], &c[2], &c[3], &c[4], &c[5]);
378 
379   if (r == ARRAY_SIZE(c)) {
380     (*phys_addr)[0] = c[0];
381     (*phys_addr)[1] = c[1];
382     (*phys_addr)[2] = c[2];
383     (*phys_addr)[3] = c[3];
384     (*phys_addr)[4] = c[4];
385     (*phys_addr)[5] = c[5];
386   } else {
387     memset(*phys_addr, 0, sizeof(*phys_addr));
388     rc = -1;
389   }
390   return rc;
391 }
392 
393 
uv_interface_addresses(uv_interface_address_t ** addresses,int * count)394 int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
395   uv_interface_address_t* address;
396   struct ifaddrs_pase *ifap = NULL, *cur;
397   int inet6, r = 0;
398 
399   *count = 0;
400   *addresses = NULL;
401 
402   if (Qp2getifaddrs(&ifap))
403     return UV_ENOSYS;
404 
405   /* The first loop to get the size of the array to be allocated */
406   for (cur = ifap; cur; cur = cur->ifa_next) {
407     if (!(cur->ifa_addr->sa_family == AF_INET6 ||
408           cur->ifa_addr->sa_family == AF_INET))
409       continue;
410 
411     if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING))
412       continue;
413 
414     (*count)++;
415   }
416 
417   if (*count == 0) {
418     Qp2freeifaddrs(ifap);
419     return 0;
420   }
421 
422   /* Alloc the return interface structs */
423   *addresses = uv__calloc(*count, sizeof(**addresses));
424   if (*addresses == NULL) {
425     Qp2freeifaddrs(ifap);
426     return UV_ENOMEM;
427   }
428   address = *addresses;
429 
430   /* The second loop to fill in the array */
431   for (cur = ifap; cur; cur = cur->ifa_next) {
432     if (!(cur->ifa_addr->sa_family == AF_INET6 ||
433           cur->ifa_addr->sa_family == AF_INET))
434       continue;
435 
436     if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING))
437       continue;
438 
439     address->name = uv__strdup(cur->ifa_name);
440 
441     inet6 = (cur->ifa_addr->sa_family == AF_INET6);
442 
443     if (inet6) {
444       address->address.address6 = *((struct sockaddr_in6*)cur->ifa_addr);
445       address->netmask.netmask6 = *((struct sockaddr_in6*)cur->ifa_netmask);
446       address->netmask.netmask6.sin6_family = AF_INET6;
447     } else {
448       address->address.address4 = *((struct sockaddr_in*)cur->ifa_addr);
449       address->netmask.netmask4 = *((struct sockaddr_in*)cur->ifa_netmask);
450       address->netmask.netmask4.sin_family = AF_INET;
451     }
452     address->is_internal = cur->ifa_flags & IFF_LOOPBACK ? 1 : 0;
453     if (!address->is_internal) {
454       int rc = -1;
455       size_t name_len = strlen(address->name);
456       /* To get the associated MAC address, we must convert the address to a
457        * line description. Normally, the name field contains the line
458        * description name, but for VLANs it has the VLAN appended with a
459        * period. Since object names can also contain periods and numbers, there
460        * is no way to know if a returned name is for a VLAN or not. eg.
461        * *LIND ETH1.1 and *LIND ETH1, VLAN 1 both have the same name: ETH1.1
462        *
463        * Instead, we apply the same heuristic used by some of the XPF ioctls:
464        * - names > 10 *must* contain a VLAN
465        * - assume names <= 10 do not contain a VLAN and try directly
466        * - if >10 or QDCRLIND returned an error, try to strip off a VLAN
467        *   and try again
468        * - if we still get an error or couldn't find a period, leave the MAC as
469        *   00:00:00:00:00:00
470        */
471       if (name_len <= 10) {
472         /* Assume name does not contain a VLAN ID */
473         rc = get_ibmi_physical_address(address->name, &address->phys_addr);
474       }
475 
476       if (name_len > 10 || rc != 0) {
477         /* The interface name must contain a VLAN ID suffix. Attempt to strip
478          * it off so we can get the line description to pass to QDCRLIND.
479          */
480         char* temp_name = uv__strdup(address->name);
481         char* dot = strrchr(temp_name, '.');
482         if (dot != NULL) {
483           *dot = '\0';
484           if (strlen(temp_name) <= 10) {
485             rc = get_ibmi_physical_address(temp_name, &address->phys_addr);
486           }
487         }
488         uv__free(temp_name);
489       }
490     }
491 
492     address++;
493   }
494 
495   Qp2freeifaddrs(ifap);
496   return r;
497 }
498 
499 
uv_free_interface_addresses(uv_interface_address_t * addresses,int count)500 void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) {
501   int i;
502 
503   for (i = 0; i < count; ++i) {
504     uv__free(addresses[i].name);
505   }
506 
507   uv__free(addresses);
508 }
509 
uv_setup_args(int argc,char ** argv)510 char** uv_setup_args(int argc, char** argv) {
511   char exepath[UV__PATH_MAX];
512   char* s;
513   size_t size;
514 
515   if (argc > 0) {
516     /* Use argv[0] to determine value for uv_exepath(). */
517     size = sizeof(exepath);
518     if (uv__search_path(argv[0], exepath, &size) == 0) {
519       uv_once(&process_title_mutex_once, init_process_title_mutex_once);
520       uv_mutex_lock(&process_title_mutex);
521       original_exepath = uv__strdup(exepath);
522       uv_mutex_unlock(&process_title_mutex);
523     }
524   }
525 
526   return argv;
527 }
528 
uv_set_process_title(const char * title)529 int uv_set_process_title(const char* title) {
530   return 0;
531 }
532 
uv_get_process_title(char * buffer,size_t size)533 int uv_get_process_title(char* buffer, size_t size) {
534   if (buffer == NULL || size == 0)
535     return UV_EINVAL;
536 
537   buffer[0] = '\0';
538   return 0;
539 }
540 
uv__process_title_cleanup(void)541 void uv__process_title_cleanup(void) {
542 }
543