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
iconv_e2a(unsigned char src[],unsigned char dst[],size_t length)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
iconv_a2e(const char * src,unsigned char dst[],size_t length)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
get_ibmi_system_status(SSTS0200 * rcvr)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
uv_get_free_memory(void)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
uv_get_total_memory(void)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
uv_get_constrained_memory(void)242 uint64_t uv_get_constrained_memory(void) {
243 return 0; /* Memory constraints are unknown. */
244 }
245
246
uv_loadavg(double avg[3])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
uv_resident_set_memory(size_t * rss)266 int uv_resident_set_memory(size_t* rss) {
267 *rss = 0;
268 return 0;
269 }
270
271
uv_uptime(double * uptime)272 int uv_uptime(double* uptime) {
273 return UV_ENOSYS;
274 }
275
276
uv_cpu_info(uv_cpu_info_t ** cpu_infos,int * count)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
get_ibmi_physical_address(const char * line,char (* phys_addr)[6])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
uv_interface_addresses(uv_interface_address_t ** addresses,int * count)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
uv_free_interface_addresses(uv_interface_address_t * addresses,int count)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