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