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