xref: /netbsd-src/external/mit/libuv/dist/src/unix/ibmi.c (revision 181254a7b1bdde6873432bffef2d2decc4b5c22f)
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 <assert.h>
30 #include <errno.h>
31 
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/ioctl.h>
35 #include <net/if.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 
39 #include <sys/time.h>
40 #include <unistd.h>
41 #include <fcntl.h>
42 #include <utmp.h>
43 #include <libgen.h>
44 
45 #include <sys/protosw.h>
46 #include <procinfo.h>
47 #include <sys/proc.h>
48 #include <sys/procfs.h>
49 
50 #include <ctype.h>
51 
52 #include <sys/mntctl.h>
53 #include <sys/vmount.h>
54 #include <limits.h>
55 #include <strings.h>
56 #include <sys/vnode.h>
57 
58 #include <as400_protos.h>
59 #include <as400_types.h>
60 
61 
62 typedef struct {
63   int bytes_available;
64   int bytes_returned;
65   char current_date_and_time[8];
66   char system_name[8];
67   char elapsed_time[6];
68   char restricted_state_flag;
69   char reserved;
70   int percent_processing_unit_used;
71   int jobs_in_system;
72   int percent_permanent_addresses;
73   int percent_temporary_addresses;
74   int system_asp;
75   int percent_system_asp_used;
76   int total_auxiliary_storage;
77   int current_unprotected_storage_used;
78   int maximum_unprotected_storage_used;
79   int percent_db_capability;
80   int main_storage_size;
81   int number_of_partitions;
82   int partition_identifier;
83   int reserved1;
84   int current_processing_capacity;
85   char processor_sharing_attribute;
86   char reserved2[3];
87   int number_of_processors;
88   int active_jobs_in_system;
89   int active_threads_in_system;
90   int maximum_jobs_in_system;
91   int percent_temporary_256mb_segments_used;
92   int percent_temporary_4gb_segments_used;
93   int percent_permanent_256mb_segments_used;
94   int percent_permanent_4gb_segments_used;
95   int percent_current_interactive_performance;
96   int percent_uncapped_cpu_capacity_used;
97   int percent_shared_processor_pool_used;
98   long main_storage_size_long;
99 } SSTS0200;
100 
101 
102 typedef struct {
103   char header[208];
104   unsigned char loca_adapter_address[12];
105 } LIND0500;
106 
107 
108 typedef struct {
109   int bytes_provided;
110   int bytes_available;
111   char msgid[7];
112 } errcode_s;
113 
114 
115 static const unsigned char e2a[256] = {
116     0, 1, 2, 3, 156, 9, 134, 127, 151, 141, 142, 11, 12, 13, 14, 15,
117     16, 17, 18, 19, 157, 133, 8, 135, 24, 25, 146, 143, 28, 29, 30, 31,
118     128, 129, 130, 131, 132, 10, 23, 27, 136, 137, 138, 139, 140, 5, 6, 7,
119     144, 145, 22, 147, 148, 149, 150, 4, 152, 153, 154, 155, 20, 21, 158, 26,
120     32, 160, 161, 162, 163, 164, 165, 166, 167, 168, 91, 46, 60, 40, 43, 33,
121     38, 169, 170, 171, 172, 173, 174, 175, 176, 177, 93, 36, 42, 41, 59, 94,
122     45, 47, 178, 179, 180, 181, 182, 183, 184, 185, 124, 44, 37, 95, 62, 63,
123     186, 187, 188, 189, 190, 191, 192, 193, 194, 96, 58, 35, 64, 39, 61, 34,
124     195, 97, 98, 99, 100, 101, 102, 103, 104, 105, 196, 197, 198, 199, 200, 201,
125     202, 106, 107, 108, 109, 110, 111, 112, 113, 114, 203, 204, 205, 206, 207, 208,
126     209, 126, 115, 116, 117, 118, 119, 120, 121, 122, 210, 211, 212, 213, 214, 215,
127     216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231,
128     123, 65, 66, 67, 68, 69, 70, 71, 72, 73, 232, 233, 234, 235, 236, 237,
129     125, 74, 75, 76, 77, 78, 79, 80, 81, 82, 238, 239, 240, 241, 242, 243,
130     92, 159, 83, 84, 85, 86, 87, 88, 89, 90, 244, 245, 246, 247, 248, 249,
131     48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 250, 251, 252, 253, 254, 255};
132 
133 
134 static const unsigned char a2e[256] = {
135     0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15,
136     16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31,
137     64, 79, 127, 123, 91, 108, 80, 125, 77, 93, 92, 78, 107, 96, 75, 97,
138     240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 122, 94, 76, 126, 110, 111,
139     124, 193, 194, 195, 196, 197, 198, 199, 200, 201, 209, 210, 211, 212, 213, 214,
140     215, 216, 217, 226, 227, 228, 229, 230, 231, 232, 233, 74, 224, 90, 95, 109,
141     121, 129, 130, 131, 132, 133, 134, 135, 136, 137, 145, 146, 147, 148, 149, 150,
142     151, 152, 153, 162, 163, 164, 165, 166, 167, 168, 169, 192, 106, 208, 161, 7,
143     32, 33, 34, 35, 36, 21, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27,
144     48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62, 225,
145     65, 66, 67, 68, 69, 70, 71, 72, 73, 81, 82, 83, 84, 85, 86, 87,
146     88, 89, 98, 99, 100, 101, 102, 103, 104, 105, 112, 113, 114, 115, 116, 117,
147     118, 119, 120, 128, 138, 139, 140, 141, 142, 143, 144, 154, 155, 156, 157, 158,
148     159, 160, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183,
149     184, 185, 186, 187, 188, 189, 190, 191, 202, 203, 204, 205, 206, 207, 218, 219,
150     220, 221, 222, 223, 234, 235, 236, 237, 238, 239, 250, 251, 252, 253, 254, 255};
151 
152 
153 static void iconv_e2a(unsigned char src[], unsigned char dst[], size_t length) {
154   size_t i;
155   for (i = 0; i < length; i++)
156     dst[i] = e2a[src[i]];
157 }
158 
159 
160 static void iconv_a2e(const char* src, unsigned char dst[], size_t length) {
161   size_t srclen;
162   size_t i;
163 
164   srclen = strlen(src);
165   if (srclen > length)
166     abort();
167   for (i = 0; i < srclen; i++)
168     dst[i] = a2e[src[i]];
169   /* padding the remaining part with spaces */
170   for (; i < length; i++)
171     dst[i] = a2e[' '];
172 }
173 
174 
175 static int get_ibmi_system_status(SSTS0200* rcvr) {
176   /* rcvrlen is input parameter 2 to QWCRSSTS */
177   unsigned int rcvrlen = sizeof(*rcvr);
178   unsigned char format[8], reset_status[10];
179 
180   /* format is input parameter 3 to QWCRSSTS */
181   iconv_a2e("SSTS0200", format, sizeof(format));
182   /* reset_status is input parameter 4 */
183   iconv_a2e("*NO", reset_status, sizeof(reset_status));
184 
185   /* errcode is input parameter 5 to QWCRSSTS */
186   errcode_s errcode;
187 
188   /* qwcrssts_pointer is the 16-byte tagged system pointer to QWCRSSTS */
189   ILEpointer __attribute__((aligned(16))) qwcrssts_pointer;
190 
191   /* qwcrssts_argv is the array of argument pointers to QWCRSSTS */
192   void* qwcrssts_argv[6];
193 
194   /* Set the IBM i pointer to the QSYS/QWCRSSTS *PGM object */
195   int rc = _RSLOBJ2(&qwcrssts_pointer, RSLOBJ_TS_PGM, "QWCRSSTS", "QSYS");
196 
197   if (rc != 0)
198     return rc;
199 
200   /* initialize the QWCRSSTS returned info structure */
201   memset(rcvr, 0, sizeof(*rcvr));
202 
203   /* initialize the QWCRSSTS error code structure */
204   memset(&errcode, 0, sizeof(errcode));
205   errcode.bytes_provided = sizeof(errcode);
206 
207   /* initialize the array of argument pointers for the QWCRSSTS API */
208   qwcrssts_argv[0] = rcvr;
209   qwcrssts_argv[1] = &rcvrlen;
210   qwcrssts_argv[2] = &format;
211   qwcrssts_argv[3] = &reset_status;
212   qwcrssts_argv[4] = &errcode;
213   qwcrssts_argv[5] = NULL;
214 
215   /* Call the IBM i QWCRSSTS API from PASE */
216   rc = _PGMCALL(&qwcrssts_pointer, qwcrssts_argv, 0);
217 
218   return rc;
219 }
220 
221 
222 uint64_t uv_get_free_memory(void) {
223   SSTS0200 rcvr;
224 
225   if (get_ibmi_system_status(&rcvr))
226     return 0;
227 
228   return (uint64_t)rcvr.main_storage_size * 1024ULL;
229 }
230 
231 
232 uint64_t uv_get_total_memory(void) {
233   SSTS0200 rcvr;
234 
235   if (get_ibmi_system_status(&rcvr))
236     return 0;
237 
238   return (uint64_t)rcvr.main_storage_size * 1024ULL;
239 }
240 
241 
242 uint64_t uv_get_constrained_memory(void) {
243   return 0;  /* Memory constraints are unknown. */
244 }
245 
246 
247 void uv_loadavg(double avg[3]) {
248   SSTS0200 rcvr;
249 
250   if (get_ibmi_system_status(&rcvr)) {
251     avg[0] = avg[1] = avg[2] = 0;
252     return;
253   }
254 
255   /* The average (in tenths) of the elapsed time during which the processing
256    * units were in use. For example, a value of 411 in binary would be 41.1%.
257    * This percentage could be greater than 100% for an uncapped partition.
258    */
259   double processing_unit_used_percent =
260     rcvr.percent_processing_unit_used / 1000.0;
261 
262   avg[0] = avg[1] = avg[2] = processing_unit_used_percent;
263 }
264 
265 
266 int uv_resident_set_memory(size_t* rss) {
267   *rss = 0;
268   return 0;
269 }
270 
271 
272 int uv_uptime(double* uptime) {
273   return UV_ENOSYS;
274 }
275 
276 
277 int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
278   unsigned int numcpus, idx = 0;
279   uv_cpu_info_t* cpu_info;
280 
281   *cpu_infos = NULL;
282   *count = 0;
283 
284   numcpus = sysconf(_SC_NPROCESSORS_ONLN);
285 
286   *cpu_infos = uv__malloc(numcpus * sizeof(uv_cpu_info_t));
287   if (!*cpu_infos) {
288     return UV_ENOMEM;
289   }
290 
291   cpu_info = *cpu_infos;
292   for (idx = 0; idx < numcpus; idx++) {
293     cpu_info->speed = 0;
294     cpu_info->model = uv__strdup("unknown");
295     cpu_info->cpu_times.user = 0;
296     cpu_info->cpu_times.sys = 0;
297     cpu_info->cpu_times.idle = 0;
298     cpu_info->cpu_times.irq = 0;
299     cpu_info->cpu_times.nice = 0;
300     cpu_info++;
301   }
302   *count = numcpus;
303 
304   return 0;
305 }
306 
307 
308 static int get_ibmi_physical_address(const char* line, char (*phys_addr)[6]) {
309   LIND0500 rcvr;
310   /* rcvrlen is input parameter 2 to QDCRLIND */
311   unsigned int rcvrlen = sizeof(rcvr);
312   unsigned char format[8], line_name[10];
313   unsigned char mac_addr[sizeof(rcvr.loca_adapter_address)];
314   int c[6];
315 
316   /* format is input parameter 3 to QDCRLIND */
317   iconv_a2e("LIND0500", format, sizeof(format));
318 
319   /* line_name is input parameter 4 to QDCRLIND */
320   iconv_a2e(line, line_name, sizeof(line_name));
321 
322   /* err is input parameter 5 to QDCRLIND */
323   errcode_s err;
324 
325   /* qwcrssts_pointer is the 16-byte tagged system pointer to QDCRLIND */
326   ILEpointer __attribute__((aligned(16))) qdcrlind_pointer;
327 
328   /* qwcrssts_argv is the array of argument pointers to QDCRLIND */
329   void* qdcrlind_argv[6];
330 
331   /* Set the IBM i pointer to the QSYS/QDCRLIND *PGM object */
332   int rc = _RSLOBJ2(&qdcrlind_pointer, RSLOBJ_TS_PGM, "QDCRLIND", "QSYS");
333 
334   if (rc != 0)
335     return rc;
336 
337   /* initialize the QDCRLIND returned info structure */
338   memset(&rcvr, 0, sizeof(rcvr));
339 
340   /* initialize the QDCRLIND error code structure */
341   memset(&err, 0, sizeof(err));
342   err.bytes_provided = sizeof(err);
343 
344   /* initialize the array of argument pointers for the QDCRLIND API */
345   qdcrlind_argv[0] = &rcvr;
346   qdcrlind_argv[1] = &rcvrlen;
347   qdcrlind_argv[2] = &format;
348   qdcrlind_argv[3] = &line_name;
349   qdcrlind_argv[4] = &err;
350   qdcrlind_argv[5] = NULL;
351 
352   /* Call the IBM i QDCRLIND API from PASE */
353   rc = _PGMCALL(&qdcrlind_pointer, qdcrlind_argv, 0);
354   if (rc != 0)
355     return rc;
356 
357   /* convert ebcdic loca_adapter_address to ascii first */
358   iconv_e2a(rcvr.loca_adapter_address, mac_addr,
359             sizeof(rcvr.loca_adapter_address));
360 
361   /* convert loca_adapter_address(char[12]) to phys_addr(char[6]) */
362   int r = sscanf(mac_addr, "%02x%02x%02x%02x%02x%02x",
363                 &c[0], &c[1], &c[2], &c[3], &c[4], &c[5]);
364 
365   if (r == ARRAY_SIZE(c)) {
366     (*phys_addr)[0] = c[0];
367     (*phys_addr)[1] = c[1];
368     (*phys_addr)[2] = c[2];
369     (*phys_addr)[3] = c[3];
370     (*phys_addr)[4] = c[4];
371     (*phys_addr)[5] = c[5];
372   } else {
373     memset(*phys_addr, 0, sizeof(*phys_addr));
374     rc = -1;
375   }
376   return rc;
377 }
378 
379 
380 int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
381   uv_interface_address_t* address;
382   struct ifaddrs_pase *ifap = NULL, *cur;
383   int inet6, r = 0;
384 
385   *count = 0;
386   *addresses = NULL;
387 
388   if (Qp2getifaddrs(&ifap))
389     return UV_ENOSYS;
390 
391   /* The first loop to get the size of the array to be allocated */
392   for (cur = ifap; cur; cur = cur->ifa_next) {
393     if (!(cur->ifa_addr->sa_family == AF_INET6 ||
394           cur->ifa_addr->sa_family == AF_INET))
395       continue;
396 
397     if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING))
398       continue;
399 
400     (*count)++;
401   }
402 
403   if (*count == 0) {
404     Qp2freeifaddrs(ifap);
405     return 0;
406   }
407 
408   /* Alloc the return interface structs */
409   *addresses = uv__calloc(*count, sizeof(**addresses));
410   if (*addresses == NULL) {
411     Qp2freeifaddrs(ifap);
412     return UV_ENOMEM;
413   }
414   address = *addresses;
415 
416   /* The second loop to fill in the array */
417   for (cur = ifap; cur; cur = cur->ifa_next) {
418     if (!(cur->ifa_addr->sa_family == AF_INET6 ||
419           cur->ifa_addr->sa_family == AF_INET))
420       continue;
421 
422     if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING))
423       continue;
424 
425     address->name = uv__strdup(cur->ifa_name);
426 
427     inet6 = (cur->ifa_addr->sa_family == AF_INET6);
428 
429     if (inet6) {
430       address->address.address6 = *((struct sockaddr_in6*)cur->ifa_addr);
431       address->netmask.netmask6 = *((struct sockaddr_in6*)cur->ifa_netmask);
432       address->netmask.netmask6.sin6_family = AF_INET6;
433     } else {
434       address->address.address4 = *((struct sockaddr_in*)cur->ifa_addr);
435       address->netmask.netmask4 = *((struct sockaddr_in*)cur->ifa_netmask);
436       address->netmask.netmask4.sin_family = AF_INET;
437     }
438     address->is_internal = cur->ifa_flags & IFF_LOOPBACK ? 1 : 0;
439     if (!address->is_internal) {
440       int rc = get_ibmi_physical_address(address->name, &address->phys_addr);
441       if (rc != 0)
442         r = rc;
443     }
444 
445     address++;
446   }
447 
448   Qp2freeifaddrs(ifap);
449   return r;
450 }
451 
452 
453 void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) {
454   int i;
455 
456   for (i = 0; i < count; ++i) {
457     uv__free(addresses[i].name);
458   }
459 
460   uv__free(addresses);
461 }
462