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 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 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 176 void init_process_title_mutex_once(void) { 177 uv_mutex_init(&process_title_mutex); 178 } 179 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 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 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 247 uint64_t uv_get_constrained_memory(void) { 248 return 0; /* Memory constraints are unknown. */ 249 } 250 251 252 void 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 271 int uv_resident_set_memory(size_t* rss) { 272 *rss = 0; 273 return 0; 274 } 275 276 277 int uv_uptime(double* uptime) { 278 return UV_ENOSYS; 279 } 280 281 282 int 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 313 static 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 389 int 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 495 void 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 505 char** 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 524 int uv_set_process_title(const char* title) { 525 return 0; 526 } 527 528 int 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 536 void uv__process_title_cleanup(void) { 537 } 538