Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Kitware
GitHub Repository: Kitware/CMake
Path: blob/master/Utilities/cmlibuv/src/unix/ibmi.c
3156 views
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
539
540