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