Home | History | Annotate | Line # | Download | only in unix
      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 static struct uv__queue global_epoll_queue;
     31 static uv_mutex_t global_epoll_lock;
     32 static uv_once_t once = UV_ONCE_INIT;
     33 
     34 int 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 
     82 error:
     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 
     94 static 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 
    106 static 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 
    139 void uv__os390_cleanup(void) {
    140   msgctl(uv_backend_fd(uv_default_loop()), IPC_RMID, NULL);
    141 }
    142 
    143 
    144 static 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 
    170 static void before_fork(void) {
    171   uv_mutex_lock(&global_epoll_lock);
    172 }
    173 
    174 
    175 static void after_fork(void) {
    176   uv_mutex_unlock(&global_epoll_lock);
    177 }
    178 
    179 
    180 static void child_fork(void) {
    181   struct uv__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 (!uv__queue_empty(&global_epoll_queue)) {
    189     uv__os390_epoll* lst;
    190     q = uv__queue_head(&global_epoll_queue);
    191     uv__queue_remove(q);
    192     lst = uv__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 
    203 static void epoll_init(void) {
    204   uv__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 
    213 uv__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     uv__queue_insert_tail(&global_epoll_queue, &lst->member);
    229     uv_mutex_unlock(&global_epoll_lock);
    230   }
    231 
    232   return lst;
    233 }
    234 
    235 
    236 int 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 
    282 int 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 
    354 int epoll_file_close(int fd) {
    355   struct uv__queue* q;
    356 
    357   uv_once(&once, epoll_init);
    358   uv_mutex_lock(&global_epoll_lock);
    359   uv__queue_foreach(q, &global_epoll_queue) {
    360     uv__os390_epoll* lst;
    361 
    362     lst = uv__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   uv__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 char* 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 
    445 ssize_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 
    514 int sem_init(UV_PLATFORM_SEM_T* semid, int pshared, unsigned int value) {
    515   UNREACHABLE();
    516 }
    517 
    518 
    519 int sem_destroy(UV_PLATFORM_SEM_T* semid) {
    520   UNREACHABLE();
    521 }
    522 
    523 
    524 int sem_post(UV_PLATFORM_SEM_T* semid) {
    525   UNREACHABLE();
    526 }
    527 
    528 
    529 int sem_trywait(UV_PLATFORM_SEM_T* semid) {
    530   UNREACHABLE();
    531 }
    532 
    533 
    534 int sem_wait(UV_PLATFORM_SEM_T* semid) {
    535   UNREACHABLE();
    536 }
    537