xref: /libuv/src/unix/os390-syscalls.c (revision 1b01b786)
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 
scandir(const char * maindir,struct dirent *** namelist,int (* filter)(const struct dirent *),int (* compar)(const struct dirent **,const struct dirent **))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 
next_power_of_two(unsigned int val)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 
maybe_resize(uv__os390_epoll * lst,unsigned int len)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 
uv__os390_cleanup(void)139 void uv__os390_cleanup(void) {
140   msgctl(uv_backend_fd(uv_default_loop()), IPC_RMID, NULL);
141 }
142 
143 
init_message_queue(uv__os390_epoll * lst)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 
before_fork(void)170 static void before_fork(void) {
171   uv_mutex_lock(&global_epoll_lock);
172 }
173 
174 
after_fork(void)175 static void after_fork(void) {
176   uv_mutex_unlock(&global_epoll_lock);
177 }
178 
179 
child_fork(void)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 
epoll_init(void)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 
epoll_create1(int flags)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 
epoll_ctl(uv__os390_epoll * lst,int op,int fd,struct epoll_event * event)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 
epoll_wait(uv__os390_epoll * lst,struct epoll_event * events,int maxevents,int timeout)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 
epoll_file_close(int fd)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 
epoll_queue_close(uv__os390_epoll * lst)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 
mkdtemp(char * path)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 
os390_readlink(const char * path,char * buf,size_t len)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 
sem_init(UV_PLATFORM_SEM_T * semid,int pshared,unsigned int value)514 int sem_init(UV_PLATFORM_SEM_T* semid, int pshared, unsigned int value) {
515   UNREACHABLE();
516 }
517 
518 
sem_destroy(UV_PLATFORM_SEM_T * semid)519 int sem_destroy(UV_PLATFORM_SEM_T* semid) {
520   UNREACHABLE();
521 }
522 
523 
sem_post(UV_PLATFORM_SEM_T * semid)524 int sem_post(UV_PLATFORM_SEM_T* semid) {
525   UNREACHABLE();
526 }
527 
528 
sem_trywait(UV_PLATFORM_SEM_T * semid)529 int sem_trywait(UV_PLATFORM_SEM_T* semid) {
530   UNREACHABLE();
531 }
532 
533 
sem_wait(UV_PLATFORM_SEM_T * semid)534 int sem_wait(UV_PLATFORM_SEM_T* semid) {
535   UNREACHABLE();
536 }
537