xref: /netbsd-src/external/mit/libuv/dist/src/unix/os390-syscalls.c (revision 5f2f42719cd62ff11fd913b40b7ce19f07c4fd25)
10e552da7Schristos /* Copyright libuv project contributors. All rights reserved.
20e552da7Schristos  *
30e552da7Schristos  * Permission is hereby granted, free of charge, to any person obtaining a copy
40e552da7Schristos  * of this software and associated documentation files (the "Software"), to
50e552da7Schristos  * deal in the Software without restriction, including without limitation the
60e552da7Schristos  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
70e552da7Schristos  * sell copies of the Software, and to permit persons to whom the Software is
80e552da7Schristos  * furnished to do so, subject to the following conditions:
90e552da7Schristos  *
100e552da7Schristos  * The above copyright notice and this permission notice shall be included in
110e552da7Schristos  * all copies or substantial portions of the Software.
120e552da7Schristos  *
130e552da7Schristos  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
140e552da7Schristos  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
150e552da7Schristos  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
160e552da7Schristos  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
170e552da7Schristos  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
180e552da7Schristos  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
190e552da7Schristos  * IN THE SOFTWARE.
200e552da7Schristos  */
210e552da7Schristos 
220e552da7Schristos 
230e552da7Schristos #include "os390-syscalls.h"
240e552da7Schristos #include <errno.h>
250e552da7Schristos #include <stdlib.h>
260e552da7Schristos #include <search.h>
270e552da7Schristos #include <termios.h>
280e552da7Schristos #include <sys/msg.h>
290e552da7Schristos 
300e552da7Schristos static QUEUE global_epoll_queue;
310e552da7Schristos static uv_mutex_t global_epoll_lock;
320e552da7Schristos static uv_once_t once = UV_ONCE_INIT;
330e552da7Schristos 
scandir(const char * maindir,struct dirent *** namelist,int (* filter)(const struct dirent *),int (* compar)(const struct dirent **,const struct dirent **))340e552da7Schristos int scandir(const char* maindir, struct dirent*** namelist,
350e552da7Schristos             int (*filter)(const struct dirent*),
360e552da7Schristos             int (*compar)(const struct dirent**,
370e552da7Schristos             const struct dirent **)) {
380e552da7Schristos   struct dirent** nl;
390e552da7Schristos   struct dirent** nl_copy;
400e552da7Schristos   struct dirent* dirent;
410e552da7Schristos   unsigned count;
420e552da7Schristos   size_t allocated;
430e552da7Schristos   DIR* mdir;
440e552da7Schristos 
450e552da7Schristos   nl = NULL;
460e552da7Schristos   count = 0;
470e552da7Schristos   allocated = 0;
480e552da7Schristos   mdir = opendir(maindir);
490e552da7Schristos   if (!mdir)
500e552da7Schristos     return -1;
510e552da7Schristos 
52*5f2f4271Schristos   for (;;) {
530e552da7Schristos     dirent = readdir(mdir);
540e552da7Schristos     if (!dirent)
550e552da7Schristos       break;
560e552da7Schristos     if (!filter || filter(dirent)) {
570e552da7Schristos       struct dirent* copy;
580e552da7Schristos       copy = uv__malloc(sizeof(*copy));
590e552da7Schristos       if (!copy)
600e552da7Schristos         goto error;
610e552da7Schristos       memcpy(copy, dirent, sizeof(*copy));
620e552da7Schristos 
630e552da7Schristos       nl_copy = uv__realloc(nl, sizeof(*copy) * (count + 1));
640e552da7Schristos       if (nl_copy == NULL) {
650e552da7Schristos         uv__free(copy);
660e552da7Schristos         goto error;
670e552da7Schristos       }
680e552da7Schristos 
690e552da7Schristos       nl = nl_copy;
700e552da7Schristos       nl[count++] = copy;
710e552da7Schristos     }
720e552da7Schristos   }
730e552da7Schristos 
740e552da7Schristos   qsort(nl, count, sizeof(struct dirent *),
750e552da7Schristos        (int (*)(const void *, const void *)) compar);
760e552da7Schristos 
770e552da7Schristos   closedir(mdir);
780e552da7Schristos 
790e552da7Schristos   *namelist = nl;
800e552da7Schristos   return count;
810e552da7Schristos 
820e552da7Schristos error:
830e552da7Schristos   while (count > 0) {
840e552da7Schristos     dirent = nl[--count];
850e552da7Schristos     uv__free(dirent);
860e552da7Schristos   }
870e552da7Schristos   uv__free(nl);
880e552da7Schristos   closedir(mdir);
890e552da7Schristos   errno = ENOMEM;
900e552da7Schristos   return -1;
910e552da7Schristos }
920e552da7Schristos 
930e552da7Schristos 
next_power_of_two(unsigned int val)940e552da7Schristos static unsigned int next_power_of_two(unsigned int val) {
950e552da7Schristos   val -= 1;
960e552da7Schristos   val |= val >> 1;
970e552da7Schristos   val |= val >> 2;
980e552da7Schristos   val |= val >> 4;
990e552da7Schristos   val |= val >> 8;
1000e552da7Schristos   val |= val >> 16;
1010e552da7Schristos   val += 1;
1020e552da7Schristos   return val;
1030e552da7Schristos }
1040e552da7Schristos 
1050e552da7Schristos 
maybe_resize(uv__os390_epoll * lst,unsigned int len)1060e552da7Schristos static void maybe_resize(uv__os390_epoll* lst, unsigned int len) {
1070e552da7Schristos   unsigned int newsize;
1080e552da7Schristos   unsigned int i;
1090e552da7Schristos   struct pollfd* newlst;
1100e552da7Schristos   struct pollfd event;
1110e552da7Schristos 
1120e552da7Schristos   if (len <= lst->size)
1130e552da7Schristos     return;
1140e552da7Schristos 
1150e552da7Schristos   if (lst->size == 0)
1160e552da7Schristos     event.fd = -1;
1170e552da7Schristos   else {
1180e552da7Schristos     /* Extract the message queue at the end. */
1190e552da7Schristos     event = lst->items[lst->size - 1];
1200e552da7Schristos     lst->items[lst->size - 1].fd = -1;
1210e552da7Schristos   }
1220e552da7Schristos 
1230e552da7Schristos   newsize = next_power_of_two(len);
1240e552da7Schristos   newlst = uv__reallocf(lst->items, newsize * sizeof(lst->items[0]));
1250e552da7Schristos 
1260e552da7Schristos   if (newlst == NULL)
1270e552da7Schristos     abort();
1280e552da7Schristos   for (i = lst->size; i < newsize; ++i)
1290e552da7Schristos     newlst[i].fd = -1;
1300e552da7Schristos 
1310e552da7Schristos   /* Restore the message queue at the end */
1320e552da7Schristos   newlst[newsize - 1] = event;
1330e552da7Schristos 
1340e552da7Schristos   lst->items = newlst;
1350e552da7Schristos   lst->size = newsize;
1360e552da7Schristos }
1370e552da7Schristos 
1380e552da7Schristos 
uv__os390_cleanup(void)139*5f2f4271Schristos void uv__os390_cleanup(void) {
140*5f2f4271Schristos   msgctl(uv_backend_fd(uv_default_loop()), IPC_RMID, NULL);
141*5f2f4271Schristos }
142*5f2f4271Schristos 
143*5f2f4271Schristos 
init_message_queue(uv__os390_epoll * lst)1440e552da7Schristos static void init_message_queue(uv__os390_epoll* lst) {
1450e552da7Schristos   struct {
1460e552da7Schristos     long int header;
1470e552da7Schristos     char body;
1480e552da7Schristos   } msg;
1490e552da7Schristos 
1500e552da7Schristos   /* initialize message queue */
1510e552da7Schristos   lst->msg_queue = msgget(IPC_PRIVATE, 0600 | IPC_CREAT);
1520e552da7Schristos   if (lst->msg_queue == -1)
1530e552da7Schristos     abort();
1540e552da7Schristos 
1550e552da7Schristos   /*
1560e552da7Schristos      On z/OS, the message queue will be affiliated with the process only
1570e552da7Schristos      when a send is performed on it. Once this is done, the system
1580e552da7Schristos      can be queried for all message queues belonging to our process id.
1590e552da7Schristos   */
1600e552da7Schristos   msg.header = 1;
1610e552da7Schristos   if (msgsnd(lst->msg_queue, &msg, sizeof(msg.body), 0) != 0)
1620e552da7Schristos     abort();
1630e552da7Schristos 
1640e552da7Schristos   /* Clean up the dummy message sent above */
1650e552da7Schristos   if (msgrcv(lst->msg_queue, &msg, sizeof(msg.body), 0, 0) != sizeof(msg.body))
1660e552da7Schristos     abort();
1670e552da7Schristos }
1680e552da7Schristos 
1690e552da7Schristos 
before_fork(void)1700e552da7Schristos static void before_fork(void) {
1710e552da7Schristos   uv_mutex_lock(&global_epoll_lock);
1720e552da7Schristos }
1730e552da7Schristos 
1740e552da7Schristos 
after_fork(void)1750e552da7Schristos static void after_fork(void) {
1760e552da7Schristos   uv_mutex_unlock(&global_epoll_lock);
1770e552da7Schristos }
1780e552da7Schristos 
1790e552da7Schristos 
child_fork(void)1800e552da7Schristos static void child_fork(void) {
1810e552da7Schristos   QUEUE* q;
1820e552da7Schristos   uv_once_t child_once = UV_ONCE_INIT;
1830e552da7Schristos 
1840e552da7Schristos   /* reset once */
1850e552da7Schristos   memcpy(&once, &child_once, sizeof(child_once));
1860e552da7Schristos 
1870e552da7Schristos   /* reset epoll list */
1880e552da7Schristos   while (!QUEUE_EMPTY(&global_epoll_queue)) {
1890e552da7Schristos     uv__os390_epoll* lst;
1900e552da7Schristos     q = QUEUE_HEAD(&global_epoll_queue);
1910e552da7Schristos     QUEUE_REMOVE(q);
1920e552da7Schristos     lst = QUEUE_DATA(q, uv__os390_epoll, member);
1930e552da7Schristos     uv__free(lst->items);
1940e552da7Schristos     lst->items = NULL;
1950e552da7Schristos     lst->size = 0;
1960e552da7Schristos   }
1970e552da7Schristos 
1980e552da7Schristos   uv_mutex_unlock(&global_epoll_lock);
1990e552da7Schristos   uv_mutex_destroy(&global_epoll_lock);
2000e552da7Schristos }
2010e552da7Schristos 
2020e552da7Schristos 
epoll_init(void)2030e552da7Schristos static void epoll_init(void) {
2040e552da7Schristos   QUEUE_INIT(&global_epoll_queue);
2050e552da7Schristos   if (uv_mutex_init(&global_epoll_lock))
2060e552da7Schristos     abort();
2070e552da7Schristos 
2080e552da7Schristos   if (pthread_atfork(&before_fork, &after_fork, &child_fork))
2090e552da7Schristos     abort();
2100e552da7Schristos }
2110e552da7Schristos 
2120e552da7Schristos 
epoll_create1(int flags)2130e552da7Schristos uv__os390_epoll* epoll_create1(int flags) {
2140e552da7Schristos   uv__os390_epoll* lst;
2150e552da7Schristos 
2160e552da7Schristos   lst = uv__malloc(sizeof(*lst));
2170e552da7Schristos   if (lst != NULL) {
2180e552da7Schristos     /* initialize list */
2190e552da7Schristos     lst->size = 0;
2200e552da7Schristos     lst->items = NULL;
2210e552da7Schristos     init_message_queue(lst);
2220e552da7Schristos     maybe_resize(lst, 1);
2230e552da7Schristos     lst->items[lst->size - 1].fd = lst->msg_queue;
2240e552da7Schristos     lst->items[lst->size - 1].events = POLLIN;
2250e552da7Schristos     lst->items[lst->size - 1].revents = 0;
2260e552da7Schristos     uv_once(&once, epoll_init);
2270e552da7Schristos     uv_mutex_lock(&global_epoll_lock);
2280e552da7Schristos     QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member);
2290e552da7Schristos     uv_mutex_unlock(&global_epoll_lock);
2300e552da7Schristos   }
2310e552da7Schristos 
2320e552da7Schristos   return lst;
2330e552da7Schristos }
2340e552da7Schristos 
2350e552da7Schristos 
epoll_ctl(uv__os390_epoll * lst,int op,int fd,struct epoll_event * event)2360e552da7Schristos int epoll_ctl(uv__os390_epoll* lst,
2370e552da7Schristos               int op,
2380e552da7Schristos               int fd,
2390e552da7Schristos               struct epoll_event *event) {
2400e552da7Schristos   uv_mutex_lock(&global_epoll_lock);
2410e552da7Schristos 
2420e552da7Schristos   if (op == EPOLL_CTL_DEL) {
2430e552da7Schristos     if (fd >= lst->size || lst->items[fd].fd == -1) {
2440e552da7Schristos       uv_mutex_unlock(&global_epoll_lock);
2450e552da7Schristos       errno = ENOENT;
2460e552da7Schristos       return -1;
2470e552da7Schristos     }
2480e552da7Schristos     lst->items[fd].fd = -1;
2490e552da7Schristos   } else if (op == EPOLL_CTL_ADD) {
2500e552da7Schristos 
2510e552da7Schristos     /* Resizing to 'fd + 1' would expand the list to contain at least
2520e552da7Schristos      * 'fd'. But we need to guarantee that the last index on the list
2530e552da7Schristos      * is reserved for the message queue. So specify 'fd + 2' instead.
2540e552da7Schristos      */
2550e552da7Schristos     maybe_resize(lst, fd + 2);
2560e552da7Schristos     if (lst->items[fd].fd != -1) {
2570e552da7Schristos       uv_mutex_unlock(&global_epoll_lock);
2580e552da7Schristos       errno = EEXIST;
2590e552da7Schristos       return -1;
2600e552da7Schristos     }
2610e552da7Schristos     lst->items[fd].fd = fd;
2620e552da7Schristos     lst->items[fd].events = event->events;
2630e552da7Schristos     lst->items[fd].revents = 0;
2640e552da7Schristos   } else if (op == EPOLL_CTL_MOD) {
2650e552da7Schristos     if (fd >= lst->size - 1 || lst->items[fd].fd == -1) {
2660e552da7Schristos       uv_mutex_unlock(&global_epoll_lock);
2670e552da7Schristos       errno = ENOENT;
2680e552da7Schristos       return -1;
2690e552da7Schristos     }
2700e552da7Schristos     lst->items[fd].events = event->events;
2710e552da7Schristos     lst->items[fd].revents = 0;
2720e552da7Schristos   } else
2730e552da7Schristos     abort();
2740e552da7Schristos 
2750e552da7Schristos   uv_mutex_unlock(&global_epoll_lock);
2760e552da7Schristos   return 0;
2770e552da7Schristos }
2780e552da7Schristos 
2790e552da7Schristos #define EP_MAX_PFDS (ULONG_MAX / sizeof(struct pollfd))
2800e552da7Schristos #define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
2810e552da7Schristos 
epoll_wait(uv__os390_epoll * lst,struct epoll_event * events,int maxevents,int timeout)2820e552da7Schristos int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
2830e552da7Schristos                int maxevents, int timeout) {
2840e552da7Schristos   nmsgsfds_t size;
2850e552da7Schristos   struct pollfd* pfds;
2860e552da7Schristos   int pollret;
287*5f2f4271Schristos   int pollfdret;
288*5f2f4271Schristos   int pollmsgret;
2890e552da7Schristos   int reventcount;
2900e552da7Schristos   int nevents;
2910e552da7Schristos   struct pollfd msg_fd;
2920e552da7Schristos   int i;
2930e552da7Schristos 
2940e552da7Schristos   if (!lst || !lst->items || !events) {
2950e552da7Schristos     errno = EFAULT;
2960e552da7Schristos     return -1;
2970e552da7Schristos   }
2980e552da7Schristos 
2990e552da7Schristos   if (lst->size > EP_MAX_PFDS) {
3000e552da7Schristos     errno = EINVAL;
3010e552da7Schristos     return -1;
3020e552da7Schristos   }
3030e552da7Schristos 
3040e552da7Schristos   if (maxevents <= 0 || maxevents > EP_MAX_EVENTS) {
3050e552da7Schristos     errno = EINVAL;
3060e552da7Schristos     return -1;
3070e552da7Schristos   }
3080e552da7Schristos 
309*5f2f4271Schristos   assert(lst->size > 0);
3100e552da7Schristos   _SET_FDS_MSGS(size, 1, lst->size - 1);
3110e552da7Schristos   pfds = lst->items;
3120e552da7Schristos   pollret = poll(pfds, size, timeout);
3130e552da7Schristos   if (pollret <= 0)
3140e552da7Schristos     return pollret;
3150e552da7Schristos 
316*5f2f4271Schristos   pollfdret = _NFDS(pollret);
317*5f2f4271Schristos   pollmsgret = _NMSGS(pollret);
3180e552da7Schristos 
3190e552da7Schristos   reventcount = 0;
3200e552da7Schristos   nevents = 0;
321*5f2f4271Schristos   msg_fd = pfds[lst->size - 1]; /* message queue is always last entry */
322*5f2f4271Schristos   maxevents = maxevents - pollmsgret; /* allow spot for message queue */
3230e552da7Schristos   for (i = 0;
324*5f2f4271Schristos        i < lst->size - 1 &&
325*5f2f4271Schristos        nevents < maxevents &&
326*5f2f4271Schristos        reventcount < pollfdret; ++i) {
3270e552da7Schristos     struct epoll_event ev;
3280e552da7Schristos     struct pollfd* pfd;
3290e552da7Schristos 
3300e552da7Schristos     pfd = &pfds[i];
3310e552da7Schristos     if (pfd->fd == -1 || pfd->revents == 0)
3320e552da7Schristos       continue;
3330e552da7Schristos 
3340e552da7Schristos     ev.fd = pfd->fd;
3350e552da7Schristos     ev.events = pfd->revents;
3360e552da7Schristos     ev.is_msg = 0;
3370e552da7Schristos 
338*5f2f4271Schristos     reventcount++;
3390e552da7Schristos     events[nevents++] = ev;
3400e552da7Schristos   }
3410e552da7Schristos 
342*5f2f4271Schristos   if (pollmsgret > 0 && msg_fd.revents != 0 && msg_fd.fd != -1) {
343*5f2f4271Schristos     struct epoll_event ev;
344*5f2f4271Schristos     ev.fd = msg_fd.fd;
345*5f2f4271Schristos     ev.events = msg_fd.revents;
346*5f2f4271Schristos     ev.is_msg = 1;
347*5f2f4271Schristos     events[nevents++] = ev;
348*5f2f4271Schristos   }
3490e552da7Schristos 
3500e552da7Schristos   return nevents;
3510e552da7Schristos }
3520e552da7Schristos 
3530e552da7Schristos 
epoll_file_close(int fd)3540e552da7Schristos int epoll_file_close(int fd) {
3550e552da7Schristos   QUEUE* q;
3560e552da7Schristos 
3570e552da7Schristos   uv_once(&once, epoll_init);
3580e552da7Schristos   uv_mutex_lock(&global_epoll_lock);
3590e552da7Schristos   QUEUE_FOREACH(q, &global_epoll_queue) {
3600e552da7Schristos     uv__os390_epoll* lst;
3610e552da7Schristos 
3620e552da7Schristos     lst = QUEUE_DATA(q, uv__os390_epoll, member);
3630e552da7Schristos     if (fd < lst->size && lst->items != NULL && lst->items[fd].fd != -1)
3640e552da7Schristos       lst->items[fd].fd = -1;
3650e552da7Schristos   }
3660e552da7Schristos 
3670e552da7Schristos   uv_mutex_unlock(&global_epoll_lock);
3680e552da7Schristos   return 0;
3690e552da7Schristos }
3700e552da7Schristos 
epoll_queue_close(uv__os390_epoll * lst)3710e552da7Schristos void epoll_queue_close(uv__os390_epoll* lst) {
3720e552da7Schristos   /* Remove epoll instance from global queue */
3730e552da7Schristos   uv_mutex_lock(&global_epoll_lock);
3740e552da7Schristos   QUEUE_REMOVE(&lst->member);
3750e552da7Schristos   uv_mutex_unlock(&global_epoll_lock);
3760e552da7Schristos 
3770e552da7Schristos   /* Free resources */
3780e552da7Schristos   msgctl(lst->msg_queue, IPC_RMID, NULL);
3790e552da7Schristos   lst->msg_queue = -1;
3800e552da7Schristos   uv__free(lst->items);
3810e552da7Schristos   lst->items = NULL;
3820e552da7Schristos }
3830e552da7Schristos 
3840e552da7Schristos 
mkdtemp(char * path)3850e552da7Schristos char* mkdtemp(char* path) {
3860e552da7Schristos   static const char* tempchars =
3870e552da7Schristos     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
3880e552da7Schristos   static const size_t num_chars = 62;
3890e552da7Schristos   static const size_t num_x = 6;
3900e552da7Schristos   char *ep, *cp;
3910e552da7Schristos   unsigned int tries, i;
3920e552da7Schristos   size_t len;
3930e552da7Schristos   uint64_t v;
3940e552da7Schristos   int fd;
3950e552da7Schristos   int retval;
3960e552da7Schristos   int saved_errno;
3970e552da7Schristos 
3980e552da7Schristos   len = strlen(path);
3990e552da7Schristos   ep = path + len;
4000e552da7Schristos   if (len < num_x || strncmp(ep - num_x, "XXXXXX", num_x)) {
4010e552da7Schristos     errno = EINVAL;
4020e552da7Schristos     return NULL;
4030e552da7Schristos   }
4040e552da7Schristos 
4050e552da7Schristos   fd = open("/dev/urandom", O_RDONLY);
4060e552da7Schristos   if (fd == -1)
4070e552da7Schristos     return NULL;
4080e552da7Schristos 
4090e552da7Schristos   tries = TMP_MAX;
4100e552da7Schristos   retval = -1;
4110e552da7Schristos   do {
4120e552da7Schristos     if (read(fd, &v, sizeof(v)) != sizeof(v))
4130e552da7Schristos       break;
4140e552da7Schristos 
4150e552da7Schristos     cp = ep - num_x;
4160e552da7Schristos     for (i = 0; i < num_x; i++) {
4170e552da7Schristos       *cp++ = tempchars[v % num_chars];
4180e552da7Schristos       v /= num_chars;
4190e552da7Schristos     }
4200e552da7Schristos 
4210e552da7Schristos     if (mkdir(path, S_IRWXU) == 0) {
4220e552da7Schristos       retval = 0;
4230e552da7Schristos       break;
4240e552da7Schristos     }
4250e552da7Schristos     else if (errno != EEXIST)
4260e552da7Schristos       break;
4270e552da7Schristos   } while (--tries);
4280e552da7Schristos 
4290e552da7Schristos   saved_errno = errno;
4300e552da7Schristos   uv__close(fd);
4310e552da7Schristos   if (tries == 0) {
4320e552da7Schristos     errno = EEXIST;
4330e552da7Schristos     return NULL;
4340e552da7Schristos   }
4350e552da7Schristos 
4360e552da7Schristos   if (retval == -1) {
4370e552da7Schristos     errno = saved_errno;
4380e552da7Schristos     return NULL;
4390e552da7Schristos   }
4400e552da7Schristos 
4410e552da7Schristos   return path;
4420e552da7Schristos }
4430e552da7Schristos 
4440e552da7Schristos 
os390_readlink(const char * path,char * buf,size_t len)4450e552da7Schristos ssize_t os390_readlink(const char* path, char* buf, size_t len) {
4460e552da7Schristos   ssize_t rlen;
4470e552da7Schristos   ssize_t vlen;
4480e552da7Schristos   ssize_t plen;
4490e552da7Schristos   char* delimiter;
4500e552da7Schristos   char old_delim;
4510e552da7Schristos   char* tmpbuf;
4520e552da7Schristos   char realpathstr[PATH_MAX + 1];
4530e552da7Schristos 
4540e552da7Schristos   tmpbuf = uv__malloc(len + 1);
4550e552da7Schristos   if (tmpbuf == NULL) {
4560e552da7Schristos     errno = ENOMEM;
4570e552da7Schristos     return -1;
4580e552da7Schristos   }
4590e552da7Schristos 
4600e552da7Schristos   rlen = readlink(path, tmpbuf, len);
4610e552da7Schristos   if (rlen < 0) {
4620e552da7Schristos     uv__free(tmpbuf);
4630e552da7Schristos     return rlen;
4640e552da7Schristos   }
4650e552da7Schristos 
4660e552da7Schristos   if (rlen < 3 || strncmp("/$", tmpbuf, 2) != 0) {
4670e552da7Schristos     /* Straightforward readlink. */
4680e552da7Schristos     memcpy(buf, tmpbuf, rlen);
4690e552da7Schristos     uv__free(tmpbuf);
4700e552da7Schristos     return rlen;
4710e552da7Schristos   }
4720e552da7Schristos 
4730e552da7Schristos   /*
4740e552da7Schristos    * There is a parmlib variable at the beginning
4750e552da7Schristos    * which needs interpretation.
4760e552da7Schristos    */
4770e552da7Schristos   tmpbuf[rlen] = '\0';
4780e552da7Schristos   delimiter = strchr(tmpbuf + 2, '/');
4790e552da7Schristos   if (delimiter == NULL)
4800e552da7Schristos     /* No slash at the end */
4810e552da7Schristos     delimiter = strchr(tmpbuf + 2, '\0');
4820e552da7Schristos 
4830e552da7Schristos   /* Read real path of the variable. */
4840e552da7Schristos   old_delim = *delimiter;
4850e552da7Schristos   *delimiter = '\0';
4860e552da7Schristos   if (realpath(tmpbuf, realpathstr) == NULL) {
4870e552da7Schristos     uv__free(tmpbuf);
4880e552da7Schristos     return -1;
4890e552da7Schristos   }
4900e552da7Schristos 
4910e552da7Schristos   /* realpathstr is not guaranteed to end with null byte.*/
4920e552da7Schristos   realpathstr[PATH_MAX] = '\0';
4930e552da7Schristos 
4940e552da7Schristos   /* Reset the delimiter and fill up the buffer. */
4950e552da7Schristos   *delimiter = old_delim;
4960e552da7Schristos   plen = strlen(delimiter);
4970e552da7Schristos   vlen = strlen(realpathstr);
4980e552da7Schristos   rlen = plen + vlen;
4990e552da7Schristos   if (rlen > len) {
5000e552da7Schristos     uv__free(tmpbuf);
5010e552da7Schristos     errno = ENAMETOOLONG;
5020e552da7Schristos     return -1;
5030e552da7Schristos   }
5040e552da7Schristos   memcpy(buf, realpathstr, vlen);
5050e552da7Schristos   memcpy(buf + vlen, delimiter, plen);
5060e552da7Schristos 
5070e552da7Schristos   /* Done using temporary buffer. */
5080e552da7Schristos   uv__free(tmpbuf);
5090e552da7Schristos 
5100e552da7Schristos   return rlen;
5110e552da7Schristos }
5120e552da7Schristos 
5130e552da7Schristos 
sem_init(UV_PLATFORM_SEM_T * semid,int pshared,unsigned int value)5140e552da7Schristos int sem_init(UV_PLATFORM_SEM_T* semid, int pshared, unsigned int value) {
5150e552da7Schristos   UNREACHABLE();
5160e552da7Schristos }
5170e552da7Schristos 
5180e552da7Schristos 
sem_destroy(UV_PLATFORM_SEM_T * semid)5190e552da7Schristos int sem_destroy(UV_PLATFORM_SEM_T* semid) {
5200e552da7Schristos   UNREACHABLE();
5210e552da7Schristos }
5220e552da7Schristos 
5230e552da7Schristos 
sem_post(UV_PLATFORM_SEM_T * semid)5240e552da7Schristos int sem_post(UV_PLATFORM_SEM_T* semid) {
5250e552da7Schristos   UNREACHABLE();
5260e552da7Schristos }
5270e552da7Schristos 
5280e552da7Schristos 
sem_trywait(UV_PLATFORM_SEM_T * semid)5290e552da7Schristos int sem_trywait(UV_PLATFORM_SEM_T* semid) {
5300e552da7Schristos   UNREACHABLE();
5310e552da7Schristos }
5320e552da7Schristos 
5330e552da7Schristos 
sem_wait(UV_PLATFORM_SEM_T * semid)5340e552da7Schristos int sem_wait(UV_PLATFORM_SEM_T* semid) {
5350e552da7Schristos   UNREACHABLE();
5360e552da7Schristos }
537