a74112701a4d3770828c62fa93759f6167a831eb
[platform/upstream/cmake.git] / Utilities / cmlibuv / src / unix / os390-syscalls.c
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 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   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
203 static 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
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     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 reventcount;
288   int nevents;
289   struct pollfd msg_fd;
290   int i;
291
292   if (!lst || !lst->items || !events) {
293     errno = EFAULT;
294     return -1;
295   }
296
297   if (lst->size > EP_MAX_PFDS) {
298     errno = EINVAL;
299     return -1;
300   }
301
302   if (maxevents <= 0 || maxevents > EP_MAX_EVENTS) {
303     errno = EINVAL;
304     return -1;
305   }
306
307   if (lst->size > 0)
308     _SET_FDS_MSGS(size, 1, lst->size - 1);
309   else
310     _SET_FDS_MSGS(size, 0, 0);
311   pfds = lst->items;
312   pollret = poll(pfds, size, timeout);
313   if (pollret <= 0)
314     return pollret;
315
316   assert(lst->size > 0);
317
318   pollret = _NFDS(pollret) + _NMSGS(pollret);
319
320   reventcount = 0;
321   nevents = 0;
322   msg_fd = pfds[lst->size - 1];
323   for (i = 0;
324        i < lst->size && i < maxevents && reventcount < pollret; ++i) {
325     struct epoll_event ev;
326     struct pollfd* pfd;
327
328     pfd = &pfds[i];
329     if (pfd->fd == -1 || pfd->revents == 0)
330       continue;
331
332     ev.fd = pfd->fd;
333     ev.events = pfd->revents;
334     ev.is_msg = 0;
335     if (pfd->revents & POLLIN && pfd->revents & POLLOUT)
336       reventcount += 2;
337     else if (pfd->revents & (POLLIN | POLLOUT))
338       ++reventcount;
339
340     pfd->revents = 0;
341     events[nevents++] = ev;
342   }
343
344   if (msg_fd.revents != 0 && msg_fd.fd != -1)
345     if (i == lst->size)
346       events[nevents - 1].is_msg = 1;
347
348   return nevents;
349 }
350
351
352 int epoll_file_close(int fd) {
353   QUEUE* q;
354
355   uv_once(&once, epoll_init);
356   uv_mutex_lock(&global_epoll_lock);
357   QUEUE_FOREACH(q, &global_epoll_queue) {
358     uv__os390_epoll* lst;
359
360     lst = QUEUE_DATA(q, uv__os390_epoll, member);
361     if (fd < lst->size && lst->items != NULL && lst->items[fd].fd != -1)
362       lst->items[fd].fd = -1;
363   }
364
365   uv_mutex_unlock(&global_epoll_lock);
366   return 0;
367 }
368
369 void epoll_queue_close(uv__os390_epoll* lst) {
370   /* Remove epoll instance from global queue */
371   uv_mutex_lock(&global_epoll_lock);
372   QUEUE_REMOVE(&lst->member);
373   uv_mutex_unlock(&global_epoll_lock);
374
375   /* Free resources */
376   msgctl(lst->msg_queue, IPC_RMID, NULL);
377   lst->msg_queue = -1;
378   uv__free(lst->items);
379   lst->items = NULL;
380 }
381
382
383 char* mkdtemp(char* path) {
384   static const char* tempchars =
385     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
386   static const size_t num_chars = 62;
387   static const size_t num_x = 6;
388   char *ep, *cp;
389   unsigned int tries, i;
390   size_t len;
391   uint64_t v;
392   int fd;
393   int retval;
394   int saved_errno;
395
396   len = strlen(path);
397   ep = path + len;
398   if (len < num_x || strncmp(ep - num_x, "XXXXXX", num_x)) {
399     errno = EINVAL;
400     return NULL;
401   }
402
403   fd = open("/dev/urandom", O_RDONLY);
404   if (fd == -1)
405     return NULL;
406
407   tries = TMP_MAX;
408   retval = -1;
409   do {
410     if (read(fd, &v, sizeof(v)) != sizeof(v))
411       break;
412
413     cp = ep - num_x;
414     for (i = 0; i < num_x; i++) {
415       *cp++ = tempchars[v % num_chars];
416       v /= num_chars;
417     }
418
419     if (mkdir(path, S_IRWXU) == 0) {
420       retval = 0;
421       break;
422     }
423     else if (errno != EEXIST)
424       break;
425   } while (--tries);
426
427   saved_errno = errno;
428   uv__close(fd);
429   if (tries == 0) {
430     errno = EEXIST;
431     return NULL;
432   }
433
434   if (retval == -1) {
435     errno = saved_errno;
436     return NULL;
437   }
438
439   return path;
440 }
441
442
443 ssize_t os390_readlink(const char* path, char* buf, size_t len) {
444   ssize_t rlen;
445   ssize_t vlen;
446   ssize_t plen;
447   char* delimiter;
448   char old_delim;
449   char* tmpbuf;
450   char realpathstr[PATH_MAX + 1];
451
452   tmpbuf = uv__malloc(len + 1);
453   if (tmpbuf == NULL) {
454     errno = ENOMEM;
455     return -1;
456   }
457
458   rlen = readlink(path, tmpbuf, len);
459   if (rlen < 0) {
460     uv__free(tmpbuf);
461     return rlen;
462   }
463
464   if (rlen < 3 || strncmp("/$", tmpbuf, 2) != 0) {
465     /* Straightforward readlink. */
466     memcpy(buf, tmpbuf, rlen);
467     uv__free(tmpbuf);
468     return rlen;
469   }
470
471   /*
472    * There is a parmlib variable at the beginning
473    * which needs interpretation.
474    */
475   tmpbuf[rlen] = '\0';
476   delimiter = strchr(tmpbuf + 2, '/');
477   if (delimiter == NULL)
478     /* No slash at the end */
479     delimiter = strchr(tmpbuf + 2, '\0');
480
481   /* Read real path of the variable. */
482   old_delim = *delimiter;
483   *delimiter = '\0';
484   if (realpath(tmpbuf, realpathstr) == NULL) {
485     uv__free(tmpbuf);
486     return -1;
487   }
488
489   /* realpathstr is not guaranteed to end with null byte.*/
490   realpathstr[PATH_MAX] = '\0';
491
492   /* Reset the delimiter and fill up the buffer. */
493   *delimiter = old_delim;
494   plen = strlen(delimiter);
495   vlen = strlen(realpathstr);
496   rlen = plen + vlen;
497   if (rlen > len) {
498     uv__free(tmpbuf);
499     errno = ENAMETOOLONG;
500     return -1;
501   }
502   memcpy(buf, realpathstr, vlen);
503   memcpy(buf + vlen, delimiter, plen);
504
505   /* Done using temporary buffer. */
506   uv__free(tmpbuf);
507
508   return rlen;
509 }
510
511
512 int sem_init(UV_PLATFORM_SEM_T* semid, int pshared, unsigned int value) {
513   UNREACHABLE();
514 }
515
516
517 int sem_destroy(UV_PLATFORM_SEM_T* semid) {
518   UNREACHABLE();
519 }
520
521
522 int sem_post(UV_PLATFORM_SEM_T* semid) {
523   UNREACHABLE();
524 }
525
526
527 int sem_trywait(UV_PLATFORM_SEM_T* semid) {
528   UNREACHABLE();
529 }
530
531
532 int sem_wait(UV_PLATFORM_SEM_T* semid) {
533   UNREACHABLE();
534 }