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 23 #include "os390-syscalls.h" 24 #include <errno.h> 25 #include <stdlib.h> 26 #include <search.h> 27 #include <termios.h> 28 #include <sys/msg.h> 29 30 #define CW_INTRPT 1 31 #define CW_CONDVAR 32 32 33 #pragma linkage(BPX4CTW, OS) 34 #pragma linkage(BPX1CTW, OS) 35 36 static int number_of_epolls; 37 static QUEUE global_epoll_queue; 38 static uv_mutex_t global_epoll_lock; 39 static uv_once_t once = UV_ONCE_INIT; 40 41 int scandir(const char* maindir, struct dirent*** namelist, 42 int (*filter)(const struct dirent*), 43 int (*compar)(const struct dirent**, 44 const struct dirent **)) { 45 struct dirent** nl; 46 struct dirent** nl_copy; 47 struct dirent* dirent; 48 unsigned count; 49 size_t allocated; 50 DIR* mdir; 51 52 nl = NULL; 53 count = 0; 54 allocated = 0; 55 mdir = opendir(maindir); 56 if (!mdir) 57 return -1; 58 59 while (1) { 60 dirent = readdir(mdir); 61 if (!dirent) 62 break; 63 if (!filter || filter(dirent)) { 64 struct dirent* copy; 65 copy = uv__malloc(sizeof(*copy)); 66 if (!copy) 67 goto error; 68 memcpy(copy, dirent, sizeof(*copy)); 69 70 nl_copy = uv__realloc(nl, sizeof(*copy) * (count + 1)); 71 if (nl_copy == NULL) { 72 uv__free(copy); 73 goto error; 74 } 75 76 nl = nl_copy; 77 nl[count++] = copy; 78 } 79 } 80 81 qsort(nl, count, sizeof(struct dirent *), 82 (int (*)(const void *, const void *)) compar); 83 84 closedir(mdir); 85 86 *namelist = nl; 87 return count; 88 89 error: 90 while (count > 0) { 91 dirent = nl[--count]; 92 uv__free(dirent); 93 } 94 uv__free(nl); 95 closedir(mdir); 96 errno = ENOMEM; 97 return -1; 98 } 99 100 101 static unsigned int next_power_of_two(unsigned int val) { 102 val -= 1; 103 val |= val >> 1; 104 val |= val >> 2; 105 val |= val >> 4; 106 val |= val >> 8; 107 val |= val >> 16; 108 val += 1; 109 return val; 110 } 111 112 113 static void maybe_resize(uv__os390_epoll* lst, unsigned int len) { 114 unsigned int newsize; 115 unsigned int i; 116 struct pollfd* newlst; 117 struct pollfd event; 118 119 if (len <= lst->size) 120 return; 121 122 if (lst->size == 0) 123 event.fd = -1; 124 else { 125 /* Extract the message queue at the end. */ 126 event = lst->items[lst->size - 1]; 127 lst->items[lst->size - 1].fd = -1; 128 } 129 130 newsize = next_power_of_two(len); 131 newlst = uv__reallocf(lst->items, newsize * sizeof(lst->items[0])); 132 133 if (newlst == NULL) 134 abort(); 135 for (i = lst->size; i < newsize; ++i) 136 newlst[i].fd = -1; 137 138 /* Restore the message queue at the end */ 139 newlst[newsize - 1] = event; 140 141 lst->items = newlst; 142 lst->size = newsize; 143 } 144 145 146 static void init_message_queue(uv__os390_epoll* lst) { 147 struct { 148 long int header; 149 char body; 150 } msg; 151 152 /* initialize message queue */ 153 lst->msg_queue = msgget(IPC_PRIVATE, 0600 | IPC_CREAT); 154 if (lst->msg_queue == -1) 155 abort(); 156 157 /* 158 On z/OS, the message queue will be affiliated with the process only 159 when a send is performed on it. Once this is done, the system 160 can be queried for all message queues belonging to our process id. 161 */ 162 msg.header = 1; 163 if (msgsnd(lst->msg_queue, &msg, sizeof(msg.body), 0) != 0) 164 abort(); 165 166 /* Clean up the dummy message sent above */ 167 if (msgrcv(lst->msg_queue, &msg, sizeof(msg.body), 0, 0) != sizeof(msg.body)) 168 abort(); 169 } 170 171 172 static void before_fork(void) { 173 uv_mutex_lock(&global_epoll_lock); 174 } 175 176 177 static void after_fork(void) { 178 uv_mutex_unlock(&global_epoll_lock); 179 } 180 181 182 static void child_fork(void) { 183 QUEUE* q; 184 uv_once_t child_once = UV_ONCE_INIT; 185 186 /* reset once */ 187 memcpy(&once, &child_once, sizeof(child_once)); 188 189 /* reset epoll list */ 190 while (!QUEUE_EMPTY(&global_epoll_queue)) { 191 uv__os390_epoll* lst; 192 q = QUEUE_HEAD(&global_epoll_queue); 193 QUEUE_REMOVE(q); 194 lst = QUEUE_DATA(q, uv__os390_epoll, member); 195 uv__free(lst->items); 196 lst->items = NULL; 197 lst->size = 0; 198 } 199 200 uv_mutex_unlock(&global_epoll_lock); 201 uv_mutex_destroy(&global_epoll_lock); 202 } 203 204 205 static void epoll_init(void) { 206 QUEUE_INIT(&global_epoll_queue); 207 if (uv_mutex_init(&global_epoll_lock)) 208 abort(); 209 210 if (pthread_atfork(&before_fork, &after_fork, &child_fork)) 211 abort(); 212 } 213 214 215 uv__os390_epoll* epoll_create1(int flags) { 216 uv__os390_epoll* lst; 217 218 lst = uv__malloc(sizeof(*lst)); 219 if (lst != NULL) { 220 /* initialize list */ 221 lst->size = 0; 222 lst->items = NULL; 223 init_message_queue(lst); 224 maybe_resize(lst, 1); 225 lst->items[lst->size - 1].fd = lst->msg_queue; 226 lst->items[lst->size - 1].events = POLLIN; 227 lst->items[lst->size - 1].revents = 0; 228 uv_once(&once, epoll_init); 229 uv_mutex_lock(&global_epoll_lock); 230 QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member); 231 uv_mutex_unlock(&global_epoll_lock); 232 } 233 234 return lst; 235 } 236 237 238 int epoll_ctl(uv__os390_epoll* lst, 239 int op, 240 int fd, 241 struct epoll_event *event) { 242 uv_mutex_lock(&global_epoll_lock); 243 244 if (op == EPOLL_CTL_DEL) { 245 if (fd >= lst->size || lst->items[fd].fd == -1) { 246 uv_mutex_unlock(&global_epoll_lock); 247 errno = ENOENT; 248 return -1; 249 } 250 lst->items[fd].fd = -1; 251 } else if (op == EPOLL_CTL_ADD) { 252 253 /* Resizing to 'fd + 1' would expand the list to contain at least 254 * 'fd'. But we need to guarantee that the last index on the list 255 * is reserved for the message queue. So specify 'fd + 2' instead. 256 */ 257 maybe_resize(lst, fd + 2); 258 if (lst->items[fd].fd != -1) { 259 uv_mutex_unlock(&global_epoll_lock); 260 errno = EEXIST; 261 return -1; 262 } 263 lst->items[fd].fd = fd; 264 lst->items[fd].events = event->events; 265 lst->items[fd].revents = 0; 266 } else if (op == EPOLL_CTL_MOD) { 267 if (fd >= lst->size - 1 || lst->items[fd].fd == -1) { 268 uv_mutex_unlock(&global_epoll_lock); 269 errno = ENOENT; 270 return -1; 271 } 272 lst->items[fd].events = event->events; 273 lst->items[fd].revents = 0; 274 } else 275 abort(); 276 277 uv_mutex_unlock(&global_epoll_lock); 278 return 0; 279 } 280 281 #define EP_MAX_PFDS (ULONG_MAX / sizeof(struct pollfd)) 282 #define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event)) 283 284 int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events, 285 int maxevents, int timeout) { 286 nmsgsfds_t size; 287 struct pollfd* pfds; 288 int pollret; 289 int reventcount; 290 int nevents; 291 struct pollfd msg_fd; 292 int i; 293 294 if (!lst || !lst->items || !events) { 295 errno = EFAULT; 296 return -1; 297 } 298 299 if (lst->size > EP_MAX_PFDS) { 300 errno = EINVAL; 301 return -1; 302 } 303 304 if (maxevents <= 0 || maxevents > EP_MAX_EVENTS) { 305 errno = EINVAL; 306 return -1; 307 } 308 309 if (lst->size > 0) 310 _SET_FDS_MSGS(size, 1, lst->size - 1); 311 else 312 _SET_FDS_MSGS(size, 0, 0); 313 pfds = lst->items; 314 pollret = poll(pfds, size, timeout); 315 if (pollret <= 0) 316 return pollret; 317 318 assert(lst->size > 0); 319 320 pollret = _NFDS(pollret) + _NMSGS(pollret); 321 322 reventcount = 0; 323 nevents = 0; 324 msg_fd = pfds[lst->size - 1]; 325 for (i = 0; 326 i < lst->size && i < maxevents && reventcount < pollret; ++i) { 327 struct epoll_event ev; 328 struct pollfd* pfd; 329 330 pfd = &pfds[i]; 331 if (pfd->fd == -1 || pfd->revents == 0) 332 continue; 333 334 ev.fd = pfd->fd; 335 ev.events = pfd->revents; 336 ev.is_msg = 0; 337 if (pfd->revents & POLLIN && pfd->revents & POLLOUT) 338 reventcount += 2; 339 else if (pfd->revents & (POLLIN | POLLOUT)) 340 ++reventcount; 341 342 pfd->revents = 0; 343 events[nevents++] = ev; 344 } 345 346 if (msg_fd.revents != 0 && msg_fd.fd != -1) 347 if (i == lst->size) 348 events[nevents - 1].is_msg = 1; 349 350 return nevents; 351 } 352 353 354 int epoll_file_close(int fd) { 355 QUEUE* q; 356 357 uv_once(&once, epoll_init); 358 uv_mutex_lock(&global_epoll_lock); 359 QUEUE_FOREACH(q, &global_epoll_queue) { 360 uv__os390_epoll* lst; 361 362 lst = QUEUE_DATA(q, uv__os390_epoll, member); 363 if (fd < lst->size && lst->items != NULL && lst->items[fd].fd != -1) 364 lst->items[fd].fd = -1; 365 } 366 367 uv_mutex_unlock(&global_epoll_lock); 368 return 0; 369 } 370 371 void epoll_queue_close(uv__os390_epoll* lst) { 372 /* Remove epoll instance from global queue */ 373 uv_mutex_lock(&global_epoll_lock); 374 QUEUE_REMOVE(&lst->member); 375 uv_mutex_unlock(&global_epoll_lock); 376 377 /* Free resources */ 378 msgctl(lst->msg_queue, IPC_RMID, NULL); 379 lst->msg_queue = -1; 380 uv__free(lst->items); 381 lst->items = NULL; 382 } 383 384 385 int nanosleep(const struct timespec* req, struct timespec* rem) { 386 unsigned nano; 387 unsigned seconds; 388 unsigned events; 389 unsigned secrem; 390 unsigned nanorem; 391 int rv; 392 int err; 393 int rsn; 394 395 nano = (int)req->tv_nsec; 396 seconds = req->tv_sec; 397 events = CW_CONDVAR | CW_INTRPT; 398 secrem = 0; 399 nanorem = 0; 400 401 #if defined(_LP64) 402 BPX4CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &err, &rsn); 403 #else 404 BPX1CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &err, &rsn); 405 #endif 406 407 /* Don't clobber errno unless BPX1CTW/BPX4CTW errored. 408 * Don't leak EAGAIN, that just means the timeout expired. 409 */ 410 if (rv == -1) 411 if (err == EAGAIN) 412 rv = 0; 413 else 414 errno = err; 415 416 if (rem != NULL && (rv == 0 || err == EINTR)) { 417 rem->tv_nsec = nanorem; 418 rem->tv_sec = secrem; 419 } 420 421 return rv; 422 } 423 424 425 char* mkdtemp(char* path) { 426 static const char* tempchars = 427 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 428 static const size_t num_chars = 62; 429 static const size_t num_x = 6; 430 char *ep, *cp; 431 unsigned int tries, i; 432 size_t len; 433 uint64_t v; 434 int fd; 435 int retval; 436 int saved_errno; 437 438 len = strlen(path); 439 ep = path + len; 440 if (len < num_x || strncmp(ep - num_x, "XXXXXX", num_x)) { 441 errno = EINVAL; 442 return NULL; 443 } 444 445 fd = open("/dev/urandom", O_RDONLY); 446 if (fd == -1) 447 return NULL; 448 449 tries = TMP_MAX; 450 retval = -1; 451 do { 452 if (read(fd, &v, sizeof(v)) != sizeof(v)) 453 break; 454 455 cp = ep - num_x; 456 for (i = 0; i < num_x; i++) { 457 *cp++ = tempchars[v % num_chars]; 458 v /= num_chars; 459 } 460 461 if (mkdir(path, S_IRWXU) == 0) { 462 retval = 0; 463 break; 464 } 465 else if (errno != EEXIST) 466 break; 467 } while (--tries); 468 469 saved_errno = errno; 470 uv__close(fd); 471 if (tries == 0) { 472 errno = EEXIST; 473 return NULL; 474 } 475 476 if (retval == -1) { 477 errno = saved_errno; 478 return NULL; 479 } 480 481 return path; 482 } 483 484 485 ssize_t os390_readlink(const char* path, char* buf, size_t len) { 486 ssize_t rlen; 487 ssize_t vlen; 488 ssize_t plen; 489 char* delimiter; 490 char old_delim; 491 char* tmpbuf; 492 char realpathstr[PATH_MAX + 1]; 493 494 tmpbuf = uv__malloc(len + 1); 495 if (tmpbuf == NULL) { 496 errno = ENOMEM; 497 return -1; 498 } 499 500 rlen = readlink(path, tmpbuf, len); 501 if (rlen < 0) { 502 uv__free(tmpbuf); 503 return rlen; 504 } 505 506 if (rlen < 3 || strncmp("/$", tmpbuf, 2) != 0) { 507 /* Straightforward readlink. */ 508 memcpy(buf, tmpbuf, rlen); 509 uv__free(tmpbuf); 510 return rlen; 511 } 512 513 /* 514 * There is a parmlib variable at the beginning 515 * which needs interpretation. 516 */ 517 tmpbuf[rlen] = '\0'; 518 delimiter = strchr(tmpbuf + 2, '/'); 519 if (delimiter == NULL) 520 /* No slash at the end */ 521 delimiter = strchr(tmpbuf + 2, '\0'); 522 523 /* Read real path of the variable. */ 524 old_delim = *delimiter; 525 *delimiter = '\0'; 526 if (realpath(tmpbuf, realpathstr) == NULL) { 527 uv__free(tmpbuf); 528 return -1; 529 } 530 531 /* realpathstr is not guaranteed to end with null byte.*/ 532 realpathstr[PATH_MAX] = '\0'; 533 534 /* Reset the delimiter and fill up the buffer. */ 535 *delimiter = old_delim; 536 plen = strlen(delimiter); 537 vlen = strlen(realpathstr); 538 rlen = plen + vlen; 539 if (rlen > len) { 540 uv__free(tmpbuf); 541 errno = ENAMETOOLONG; 542 return -1; 543 } 544 memcpy(buf, realpathstr, vlen); 545 memcpy(buf + vlen, delimiter, plen); 546 547 /* Done using temporary buffer. */ 548 uv__free(tmpbuf); 549 550 return rlen; 551 } 552 553 554 size_t strnlen(const char* str, size_t maxlen) { 555 char* p = memchr(str, 0, maxlen); 556 if (p == NULL) 557 return maxlen; 558 else 559 return p - str; 560 } 561 562 563 int sem_init(UV_PLATFORM_SEM_T* semid, int pshared, unsigned int value) { 564 UNREACHABLE(); 565 } 566 567 568 int sem_destroy(UV_PLATFORM_SEM_T* semid) { 569 UNREACHABLE(); 570 } 571 572 573 int sem_post(UV_PLATFORM_SEM_T* semid) { 574 UNREACHABLE(); 575 } 576 577 578 int sem_trywait(UV_PLATFORM_SEM_T* semid) { 579 UNREACHABLE(); 580 } 581 582 583 int sem_wait(UV_PLATFORM_SEM_T* semid) { 584 UNREACHABLE(); 585 } 586