Rune - Implement hard-locking model feature
[rune.git] / libruntime / sys_fd.c
1 /*
2  * SYS_FD.C
3  */
4
5 #include "defs.h"
6
7 struct read_args {
8         LValueStor      lvs;
9         PointerStor     buf;
10         runesize_t      bytes;
11         runeoff_t       offset;
12 };
13
14 struct write_args {
15         LValueStor      lvs;
16         PointerStor     buf;
17         runesize_t      bytes;
18         runeoff_t       offset;
19 };
20
21 struct open_args {
22         LValueStor      lvs;
23         PointerStor     path;
24         int32_t         flags;
25         int32_t         modes;
26 };
27
28 struct close_args {
29         LValueStor      lvs;
30 };
31
32 struct dup_args {
33         LValueStor      lvs;
34         int             sfd;
35 #if LONG_BITS == 64
36         int             filler01;
37 #endif
38 };
39
40 struct dup2_args {
41         LValueStor      lvs;
42         int             sfd;
43         int             dfd;
44 };
45
46 struct umask_args {
47         mode_t          mode;
48         mode_t          filler01;
49 };
50
51 struct lseek_args {
52         LValueStor      lvs;
53         int64_t         off;
54         int32_t         how;
55 };
56
57 struct fsimple_args {
58         LValueStor      lvs;
59         runebool_t      enable;
60 };
61
62 struct pipe2_args {
63         LValueStor      fdr;
64         LValueStor      fdw;
65         int             flags;
66 #if LONG_BIT == 64
67         int             filler01;
68 #endif
69 };
70
71 struct socketpair_args {
72         int             domain;
73         int             type;
74         int             proto;
75 #if LONG_BIT == 64
76         int             filler01;
77 #endif
78         LValueStor      fdr;
79         LValueStor      fdw;
80 };
81
82 struct iowait_args {
83         LValueStor      lvs;
84 };
85
86 struct symlink_args {
87         LValueStor      lvs;
88         PointerStor     buf;
89         PointerStor     nfile;
90 };
91
92 struct link_args {
93         LValueStor      lvs;
94         PointerStor     ofile;
95         PointerStor     nfile;
96 };
97
98 struct readlink_args {
99         LValueStor      lvs;
100         PointerStor     target;
101         PointerStor     buf;
102 };
103
104 struct unlink_args {
105         LValueStor      lvs;
106         PointerStor     target;
107 };
108
109 /*
110  * Normal read
111  */
112 void
113 RuneSysCall_read(struct read_args *args, runesize_t *rval)
114 {
115         FDStor *fdp;
116         runesize_t n;
117         runesize_t r;
118         char *ptr;
119
120         BOUNDSCHECK(&args->buf, args->bytes);
121         fdp = (void *)args->lvs.s_Addr;
122
123         ptr = args->buf.s_Addr;
124         r = 0;
125         while (r < args->bytes) {
126                 if (args->offset < 0) {
127                         n = extpread(fdp->fd, args->buf.s_Addr,
128                                      args->bytes - r,
129                                      O_FNONBLOCKING, args->offset);
130                 } else {
131                         n = extpread(fdp->fd, args->buf.s_Addr,
132                                      args->bytes - r,
133                                      O_FNONBLOCKING, args->offset + r);
134                 }
135                 if (n < 0) {
136                         if (errno == EINTR)
137                                 continue;
138                         if (errno == EAGAIN) {
139                                 if (threadWaitEvent(fdp->fd, THWAIT_READ) < 0)
140                                         fdp->error = errno;
141                                 else
142                                         fdp->error = 0;
143                                 continue;
144                         }
145                         fdp->error = errno;
146                         if (r == 0)
147                                 r = -1;
148                         break;
149                 }
150                 if (n == 0)
151                         break;
152                 fdp->error = 0;
153                 r += n;
154                 ptr += n;
155         }
156         *rval = r;
157 }
158
159 /*
160  * Semi-blocking read, read at least 1 byte.
161  *
162  * Will retry on EINTR or EAGAIN until at least 1 byte is read.  Other errors
163  * will break out.
164  */
165 void
166 RuneSysCall_read1(struct read_args *args, runesize_t *rval)
167 {
168         FDStor *fdp;
169
170         BOUNDSCHECK(&args->buf, args->bytes);
171         fdp = (void *)args->lvs.s_Addr;
172 again:
173         *rval = extpread(fdp->fd, args->buf.s_Addr, args->bytes,
174                          O_FNONBLOCKING, args->offset);
175
176         if (*rval < 0) {
177                 if (errno == EINTR)
178                         goto again;
179                 if (errno == EAGAIN) {
180                         if (threadWaitEvent(fdp->fd, THWAIT_READ) < 0)
181                                 fdp->error = errno;
182                         else
183                                 fdp->error = 0;
184                         goto again;
185                 }
186                 fdp->error = errno;
187         } else {
188                 fdp->error = 0;
189         }
190 }
191
192 /*
193  * readn - non-blocking read.  Can also be interrupted by EINTR.
194  */
195 void
196 RuneSysCall_readn(struct read_args *args, runesize_t *rval)
197 {
198         FDStor *fdp;
199
200         BOUNDSCHECK(&args->buf, args->bytes);
201         fdp = (void *)args->lvs.s_Addr;
202
203         *rval = extpread(fdp->fd, args->buf.s_Addr, args->bytes,
204                          O_FNONBLOCKING, args->offset);
205
206         if (*rval < 0) {
207                 fdp->error = errno;
208         } else {
209                 fdp->error = 0;
210         }
211 }
212
213 void
214 RuneSysCall_write(struct write_args *args, runesize_t *rval)
215 {
216         FDStor *fdp;
217         runesize_t n;
218         runesize_t r;
219         char *ptr;
220
221         BOUNDSCHECK(&args->buf, args->bytes);
222         fdp = (void *)args->lvs.s_Addr;
223
224         ptr = args->buf.s_Addr;
225         r = 0;
226         while (r < args->bytes) {
227                 if (args->offset < 0) {
228                         n = extpwrite(fdp->fd, ptr, args->bytes - r,
229                                       O_FNONBLOCKING, args->offset);
230                 } else {
231                         n = extpwrite(fdp->fd, ptr, args->bytes - r,
232                                       O_FNONBLOCKING, args->offset + r);
233                 }
234                 if (n < 0) {
235                         if (errno == EINTR)
236                                 continue;
237                         if (errno == EAGAIN) {
238                                 if (threadWaitEvent(fdp->fd, THWAIT_WRITE) < 0)
239                                         fdp->error = errno;
240                                 else
241                                         fdp->error = 0;
242                                 continue;
243                         }
244                         fdp->error = errno;
245                         if (r == 0)
246                                 r = -1;
247                         break;
248                 }
249                 fdp->error = 0;
250                 r += n;
251                 ptr += n;
252         }
253         *rval = r;
254 }
255
256 /*
257  * Semi-blocking write, write at least 1 byte.
258  *
259  * Will retry on EINTR or EAGAIN until at least 1 byte is write.  Other errors
260  * will break out.
261  */
262 void
263 RuneSysCall_write1(struct write_args *args, runesize_t *rval)
264 {
265         FDStor *fdp;
266
267         BOUNDSCHECK(&args->buf, args->bytes);
268         fdp = (void *)args->lvs.s_Addr;
269
270 again:
271         *rval = extpwrite(fdp->fd, args->buf.s_Addr, args->bytes,
272                           O_FNONBLOCKING, args->offset);
273
274         if (*rval < 0) {
275                 if (errno == EINTR)
276                         goto again;
277                 if (errno == EAGAIN) {
278                         if (threadWaitEvent(fdp->fd, THWAIT_WRITE) < 0)
279                                 fdp->error = errno;
280                         else
281                                 fdp->error = 0;
282                         goto again;
283                 }
284                 fdp->error = errno;
285         } else {
286                 fdp->error = 0;
287         }
288 }
289
290 void
291 RuneSysCall_writen(struct write_args *args, runesize_t *rval)
292 {
293         FDStor *fdp;
294
295         BOUNDSCHECK(&args->buf, args->bytes);
296         fdp = (void *)args->lvs.s_Addr;
297
298         *rval = extpwrite(fdp->fd, args->buf.s_Addr, args->bytes,
299                          O_FNONBLOCKING, args->offset);
300
301         if (*rval < 0) {
302                 fdp->error = errno;
303         } else {
304                 fdp->error = 0;
305         }
306 }
307
308 void
309 RuneSysCall_open(struct open_args *args, int *rval)
310 {
311         FDStor *fdp;
312
313         BOUNDSCHECK(&args->path, 1);
314         dassert(args->path.s_End[-1] == 0);
315         fdp = (void *)args->lvs.s_Addr;
316
317         fdp->fd = open(args->path.s_Addr, args->flags | O_CLOEXEC, args->modes);
318         if (fdp->fd < 0) {
319                 fdp->error = errno;
320                 *rval = -1;
321         } else {
322                 fdp->error = 0;
323                 *rval = 0;
324         }
325 }
326
327 void
328 RuneSysCall_close(struct close_args *args, int *rval)
329 {
330         FDStor *fdp;
331
332         fdp = (void *)args->lvs.s_Addr;
333         *rval = close(fdp->fd);
334         fdp->fd = -1;
335         if (*rval < 0)
336                 fdp->error = errno;
337         else
338                 fdp->error = 0;
339 }
340
341 void
342 RuneSysCall_dup(struct dup_args *args, int *rval)
343 {
344         FDStor *fdp;
345
346         fdp = (void *)args->lvs.s_Addr;
347         *rval = dup(args->sfd);
348         if (*rval < 0) {
349                 fdp->fd = -1;
350                 fdp->error = errno;
351         } else {
352                 fdp->fd = *rval;
353                 fdp->error = 0;
354         }
355 }
356
357 void
358 RuneSysCall_dup2(struct dup2_args *args, int *rval)
359 {
360         FDStor *fdp;
361
362         fdp = (void *)args->lvs.s_Addr;
363         *rval = dup2(args->sfd, args->dfd);
364         if (*rval < 0) {
365                 fdp->fd = -1;
366                 fdp->error = errno;
367         } else {
368                 fdp->fd = *rval;
369                 fdp->error = 0;
370         }
371 }
372
373 void
374 RuneSysCall_umask(struct umask_args *args, runemode_t *rval)
375 {
376         *rval = umask(args->mode);
377 }
378
379 void
380 RuneSysCall_lseek(struct lseek_args *args, runesize_t *rval)
381 {
382         FDStor *fdp;
383
384         fdp = (void *)args->lvs.s_Addr;
385         *rval = lseek(fdp->fd, args->off, args->how);
386         if (*rval < 0)
387                 fdp->error = errno;
388         else
389                 fdp->error = 0;
390 }
391
392 void
393 RuneSysCall_fcloexec(struct fsimple_args *args, int *rval)
394 {
395         FDStor *fdp;
396
397         fdp = (void *)args->lvs.s_Addr;
398         *rval = fcntl(fdp->fd, F_SETFD, (args->enable ? FD_CLOEXEC : 0));
399         if (*rval < 0)
400                 fdp->error = errno;
401 }
402
403 void
404 RuneSysCall_fappend(struct fsimple_args *args, int *rval)
405 {
406         FDStor *fdp;
407         int flags;
408
409         fdp = (void *)args->lvs.s_Addr;
410         flags = fcntl(fdp->fd, F_GETFL, 0);
411         if (flags < 0) {
412                 fdp->error = errno;
413                 *rval = -1;
414         } else {
415                 if (args->enable)
416                         flags |= O_APPEND;
417                 else
418                         flags &= ~O_APPEND;
419                 *rval = fcntl(fdp->fd, F_SETFL, flags);
420                 if (*rval < 0)
421                         fdp->error = errno;
422         }
423 }
424
425 void
426 RuneSysCall_fnonblock(struct fsimple_args *args, int *rval)
427 {
428         FDStor *fdp;
429         int flags;
430
431         fdp = (void *)args->lvs.s_Addr;
432         flags = fcntl(fdp->fd, F_GETFL, 0);
433         if (flags < 0) {
434                 fdp->error = errno;
435                 *rval = -1;
436         } else {
437                 if (args->enable)
438                         flags |= O_NONBLOCK;
439                 else
440                         flags &= ~O_NONBLOCK;
441                 *rval = fcntl(fdp->fd, F_SETFL, flags);
442                 if (*rval < 0)
443                         fdp->error = errno;
444         }
445 }
446
447 void
448 RuneSysCall_fdirect(struct fsimple_args *args, int *rval)
449 {
450         FDStor *fdp;
451         int flags;
452
453         fdp = (void *)args->lvs.s_Addr;
454         flags = fcntl(fdp->fd, F_GETFL, 0);
455         if (flags < 0) {
456                 fdp->error = errno;
457                 *rval = -1;
458         } else {
459                 if (args->enable)
460                         flags |= O_DIRECT;
461                 else
462                         flags &= ~O_DIRECT;
463                 *rval = fcntl(fdp->fd, F_SETFL, flags);
464                 if (*rval < 0)
465                         fdp->error = errno;
466         }
467 }
468
469 void
470 RuneSysCall_iowait_rd(struct iowait_args *args, void *rval)
471 {
472         FDStor *fdp;
473
474         fdp = (void *)args->lvs.s_Addr;
475         if (threadWaitEvent(fdp->fd, THWAIT_READ) < 0)
476                 fdp->error = errno;
477         else
478                 fdp->error = 0;
479 }
480
481 void
482 RuneSysCall_iowait_wr(struct iowait_args *args, void *rval)
483 {
484         FDStor *fdp;
485
486         fdp = (void *)args->lvs.s_Addr;
487         if (threadWaitEvent(fdp->fd, THWAIT_WRITE) < 0)
488                 fdp->error = errno;
489         else
490                 fdp->error = 0;
491 }
492
493 void
494 RuneSysCall_pipe2(struct pipe2_args *args, int *rval)
495 {
496         FDStor *fdr = args->fdr.s_Addr;
497         FDStor *fdw = args->fdw.s_Addr;
498         int fds[2];
499
500         if (pipe2(fds, args->flags) < 0) {
501                 fdr->fd = -1;
502                 fdr->error = errno;
503                 fdw->fd = -1;
504                 fdw->error = errno;
505                 *rval = -1;
506         } else {
507                 fdr->fd = fds[0];
508                 fdr->error = 0;
509                 fdw->fd = fds[1];
510                 fdw->error = 0;
511                 *rval = 0;
512         }
513 }
514
515 void
516 RuneSysCall_socketpair(struct socketpair_args *args, int *rval)
517 {
518         FDStor *fdr = args->fdr.s_Addr;
519         FDStor *fdw = args->fdw.s_Addr;
520         int fds[2];
521
522         if (socketpair(args->domain, args->type, args->proto, fds) < 0) {
523                 fdr->error = errno;
524                 fdr->fd = -1;
525                 fdw->error = errno;
526                 fdw->fd = -1;
527                 *rval = -1;
528         } else {
529                 fdr->fd = fds[0];
530                 fdr->error = 0;
531                 fdw->fd = fds[1];
532                 fdw->error = 0;
533                 *rval = 0;
534         }
535 }
536
537 void
538 RuneSysCall_symlink(struct symlink_args *args, int *rval)
539 {
540         FDStor *fdp = (void *)args->lvs.s_Addr;
541         const char *buf;
542         const char *nfile;
543
544         buf = STRBOUNDSCHECK(&args->buf, 255);
545         nfile = STRBOUNDSCHECK(&args->nfile, PATH_MAX);
546         if (symlink(buf, nfile) < 0) {
547                 *rval = -1;
548                 fdp->error = errno;
549         } else {
550                 *rval = 0;
551                 fdp->error = 0;
552         }
553 }
554
555 void
556 RuneSysCall_link(struct link_args *args, int *rval)
557 {
558         FDStor *fdp = (void *)args->lvs.s_Addr;
559         const char *ofile;
560         const char *nfile;
561
562         ofile = STRBOUNDSCHECK(&args->ofile, PATH_MAX);
563         nfile = STRBOUNDSCHECK(&args->nfile, PATH_MAX);
564         if (link(ofile, nfile) < 0) {
565                 *rval = -1;
566                 fdp->error = errno;
567         } else {
568                 *rval = 0;
569                 fdp->error = 0;
570         }
571 }
572
573 void
574 RuneSysCall_readlink(struct readlink_args *args, int *rval)
575 {
576         FDStor *fdp = (void *)args->lvs.s_Addr;
577         const char *target;
578         char *buf;
579         size_t bufsize;
580
581         target = STRBOUNDSCHECK(&args->target, PATH_MAX);
582         BOUNDSCHECK(&args->buf, 1);
583         buf = args->buf.s_Addr;
584         bufsize = args->buf.s_End - args->buf.s_Beg;
585         if (bufsize > 0x7FFFFFFF)       /* ensure no overflow w/int return */
586                 bufsize = 0x7FFFFFFF;
587         *rval = readlink(target, buf, bufsize - 1);
588         if (*rval < 0) {
589                 *rval = -1;
590                 fdp->error = errno;
591         } else {
592                 buf[*rval] = 0;         /* rune zero-terminates the buffer */
593                 fdp->error = 0;
594         }
595 }
596
597 void
598 RuneSysCall_unlink(struct unlink_args *args, int *rval)
599 {
600         FDStor *fdp = (void *)args->lvs.s_Addr;
601         const char *target;
602
603         target = STRBOUNDSCHECK(&args->target, PATH_MAX);
604         *rval = unlink(target);
605         if (*rval < 0) {
606                 *rval = -1;
607                 fdp->error = errno;
608         } else {
609                 fdp->error = 0;
610         }
611 }
612