|
160
|
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 }
|