xref: /linux/tools/include/nolibc/sys.h (revision 3d66c4e14fbf4d59ca4665391d133655fa668042)
1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2 /*
3  * Syscall definitions for NOLIBC (those in man(2))
4  * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
5  */
6 
7 /* make sure to include all global symbols */
8 #include "nolibc.h"
9 
10 #ifndef _NOLIBC_SYS_H
11 #define _NOLIBC_SYS_H
12 
13 #include "std.h"
14 
15 /* system includes */
16 #include <linux/unistd.h>
17 #include <linux/signal.h>  /* for SIGCHLD */
18 #include <linux/termios.h>
19 #include <linux/mman.h>
20 #include <linux/fs.h>
21 #include <linux/loop.h>
22 #include <linux/time.h>
23 #include <linux/auxvec.h>
24 #include <linux/fcntl.h> /* for O_* and AT_* */
25 #include <linux/sched.h> /* for clone_args */
26 #include <linux/stat.h>  /* for statx() */
27 
28 #include "errno.h"
29 #include "stdarg.h"
30 #include "types.h"
31 
32 
33 /* Syscall return helper: takes the syscall value in argument and checks for an
34  * error in it. This may only be used with signed returns (int or long), but
35  * not with pointers. An error is any value < 0. When an error is encountered,
36  * -ret is set into errno and -1 is returned. Otherwise the returned value is
37  * passed as-is with its type preserved.
38  */
39 
40 #define __sysret(arg)							\
41 ({									\
42 	__typeof__(arg) __sysret_arg = (arg);				\
43 	(__sysret_arg < 0)                              /* error ? */	\
44 		? (({ SET_ERRNO(-__sysret_arg); }), -1) /* ret -1 with errno = -arg */ \
45 		: __sysret_arg;                         /* return original value */ \
46 })
47 
48 /* Syscall ENOSYS helper: Avoids unused-parameter warnings and provides a
49  * debugging hook.
50  */
51 
52 static __inline__ int __nolibc_enosys(const char *syscall, ...)
53 {
54 	(void)syscall;
55 	return -ENOSYS;
56 }
57 
58 
59 /* Functions in this file only describe syscalls. They're declared static so
60  * that the compiler usually decides to inline them while still being allowed
61  * to pass a pointer to one of their instances. Each syscall exists in two
62  * versions:
63  *   - the "internal" ones, which matches the raw syscall interface at the
64  *     kernel level, which may sometimes slightly differ from the documented
65  *     libc-level ones. For example most of them return either a valid value
66  *     or -errno. All of these are prefixed with "sys_". They may be called
67  *     by non-portable applications if desired.
68  *
69  *   - the "exported" ones, whose interface must closely match the one
70  *     documented in man(2), that applications are supposed to expect. These
71  *     ones rely on the internal ones, and set errno.
72  *
73  * Each syscall will be defined with the two functions, sorted in alphabetical
74  * order applied to the exported names.
75  *
76  * In case of doubt about the relevance of a function here, only those which
77  * set errno should be defined here. Wrappers like those appearing in man(3)
78  * should not be placed here.
79  */
80 
81 
82 /*
83  * int brk(void *addr);
84  * void *sbrk(intptr_t inc)
85  */
86 
87 static __attribute__((unused))
88 void *sys_brk(void *addr)
89 {
90 	return (void *)my_syscall1(__NR_brk, addr);
91 }
92 
93 static __attribute__((unused))
94 int brk(void *addr)
95 {
96 	void *ret = sys_brk(addr);
97 
98 	if (!ret) {
99 		SET_ERRNO(ENOMEM);
100 		return -1;
101 	}
102 	return 0;
103 }
104 
105 static __attribute__((unused))
106 void *sbrk(intptr_t inc)
107 {
108 	/* first call to find current end */
109 	void *ret = sys_brk(0);
110 
111 	if (ret && sys_brk(ret + inc) == ret + inc)
112 		return ret + inc;
113 
114 	SET_ERRNO(ENOMEM);
115 	return (void *)-1;
116 }
117 
118 
119 /*
120  * int chdir(const char *path);
121  */
122 
123 static __attribute__((unused))
124 int sys_chdir(const char *path)
125 {
126 	return my_syscall1(__NR_chdir, path);
127 }
128 
129 static __attribute__((unused))
130 int chdir(const char *path)
131 {
132 	return __sysret(sys_chdir(path));
133 }
134 
135 
136 /*
137  * int chmod(const char *path, mode_t mode);
138  */
139 
140 static __attribute__((unused))
141 int sys_chmod(const char *path, mode_t mode)
142 {
143 #if defined(__NR_fchmodat)
144 	return my_syscall4(__NR_fchmodat, AT_FDCWD, path, mode, 0);
145 #else
146 	return my_syscall2(__NR_chmod, path, mode);
147 #endif
148 }
149 
150 static __attribute__((unused))
151 int chmod(const char *path, mode_t mode)
152 {
153 	return __sysret(sys_chmod(path, mode));
154 }
155 
156 
157 /*
158  * int chown(const char *path, uid_t owner, gid_t group);
159  */
160 
161 static __attribute__((unused))
162 int sys_chown(const char *path, uid_t owner, gid_t group)
163 {
164 #if defined(__NR_fchownat)
165 	return my_syscall5(__NR_fchownat, AT_FDCWD, path, owner, group, 0);
166 #else
167 	return my_syscall3(__NR_chown, path, owner, group);
168 #endif
169 }
170 
171 static __attribute__((unused))
172 int chown(const char *path, uid_t owner, gid_t group)
173 {
174 	return __sysret(sys_chown(path, owner, group));
175 }
176 
177 
178 /*
179  * int chroot(const char *path);
180  */
181 
182 static __attribute__((unused))
183 int sys_chroot(const char *path)
184 {
185 	return my_syscall1(__NR_chroot, path);
186 }
187 
188 static __attribute__((unused))
189 int chroot(const char *path)
190 {
191 	return __sysret(sys_chroot(path));
192 }
193 
194 
195 /*
196  * int close(int fd);
197  */
198 
199 static __attribute__((unused))
200 int sys_close(int fd)
201 {
202 	return my_syscall1(__NR_close, fd);
203 }
204 
205 static __attribute__((unused))
206 int close(int fd)
207 {
208 	return __sysret(sys_close(fd));
209 }
210 
211 
212 /*
213  * int dup(int fd);
214  */
215 
216 static __attribute__((unused))
217 int sys_dup(int fd)
218 {
219 	return my_syscall1(__NR_dup, fd);
220 }
221 
222 static __attribute__((unused))
223 int dup(int fd)
224 {
225 	return __sysret(sys_dup(fd));
226 }
227 
228 
229 /*
230  * int dup2(int old, int new);
231  */
232 
233 static __attribute__((unused))
234 int sys_dup2(int old, int new)
235 {
236 #if defined(__NR_dup3)
237 	int ret, nr_fcntl;
238 
239 #ifdef __NR_fcntl64
240 	nr_fcntl = __NR_fcntl64;
241 #else
242 	nr_fcntl = __NR_fcntl;
243 #endif
244 
245 	if (old == new) {
246 		ret = my_syscall2(nr_fcntl, old, F_GETFD);
247 		return ret < 0 ? ret : old;
248 	}
249 
250 	return my_syscall3(__NR_dup3, old, new, 0);
251 #else
252 	return my_syscall2(__NR_dup2, old, new);
253 #endif
254 }
255 
256 static __attribute__((unused))
257 int dup2(int old, int new)
258 {
259 	return __sysret(sys_dup2(old, new));
260 }
261 
262 
263 /*
264  * int dup3(int old, int new, int flags);
265  */
266 
267 #if defined(__NR_dup3)
268 static __attribute__((unused))
269 int sys_dup3(int old, int new, int flags)
270 {
271 	return my_syscall3(__NR_dup3, old, new, flags);
272 }
273 
274 static __attribute__((unused))
275 int dup3(int old, int new, int flags)
276 {
277 	return __sysret(sys_dup3(old, new, flags));
278 }
279 #endif
280 
281 
282 /*
283  * int execve(const char *filename, char *const argv[], char *const envp[]);
284  */
285 
286 static __attribute__((unused))
287 int sys_execve(const char *filename, char *const argv[], char *const envp[])
288 {
289 	return my_syscall3(__NR_execve, filename, argv, envp);
290 }
291 
292 static __attribute__((unused))
293 int execve(const char *filename, char *const argv[], char *const envp[])
294 {
295 	return __sysret(sys_execve(filename, argv, envp));
296 }
297 
298 
299 /*
300  * void exit(int status);
301  */
302 
303 static __attribute__((noreturn,unused))
304 void sys_exit(int status)
305 {
306 	my_syscall1(__NR_exit, status & 255);
307 	while(1); /* shut the "noreturn" warnings. */
308 }
309 
310 static __attribute__((noreturn,unused))
311 void _exit(int status)
312 {
313 	sys_exit(status);
314 }
315 
316 static __attribute__((noreturn,unused))
317 void exit(int status)
318 {
319 	_exit(status);
320 }
321 
322 
323 /*
324  * pid_t fork(void);
325  */
326 
327 #ifndef sys_fork
328 static __attribute__((unused))
329 pid_t sys_fork(void)
330 {
331 #if defined(__NR_clone)
332 	/* note: some archs only have clone() and not fork(). Different archs
333 	 * have a different API, but most archs have the flags on first arg and
334 	 * will not use the rest with no other flag.
335 	 */
336 	return my_syscall5(__NR_clone, SIGCHLD, 0, 0, 0, 0);
337 #else
338 	return my_syscall0(__NR_fork);
339 #endif
340 }
341 #endif
342 
343 static __attribute__((unused))
344 pid_t fork(void)
345 {
346 	return __sysret(sys_fork());
347 }
348 
349 #ifndef sys_vfork
350 static __attribute__((unused))
351 pid_t sys_vfork(void)
352 {
353 #if defined(__NR_vfork)
354 	return my_syscall0(__NR_vfork);
355 #else
356 	/*
357 	 * clone() could be used but has different argument orders per
358 	 * architecture.
359 	 */
360 	struct clone_args args = {
361 		.flags		= CLONE_VM | CLONE_VFORK,
362 		.exit_signal	= SIGCHLD,
363 	};
364 
365 	return my_syscall2(__NR_clone3, &args, sizeof(args));
366 #endif
367 }
368 #endif
369 
370 static __attribute__((unused))
371 pid_t vfork(void)
372 {
373 	return __sysret(sys_vfork());
374 }
375 
376 /*
377  * int fsync(int fd);
378  */
379 
380 static __attribute__((unused))
381 int sys_fsync(int fd)
382 {
383 	return my_syscall1(__NR_fsync, fd);
384 }
385 
386 static __attribute__((unused))
387 int fsync(int fd)
388 {
389 	return __sysret(sys_fsync(fd));
390 }
391 
392 
393 /*
394  * int getdents64(int fd, struct linux_dirent64 *dirp, int count);
395  */
396 
397 static __attribute__((unused))
398 int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count)
399 {
400 	return my_syscall3(__NR_getdents64, fd, dirp, count);
401 }
402 
403 static __attribute__((unused))
404 int getdents64(int fd, struct linux_dirent64 *dirp, int count)
405 {
406 	return __sysret(sys_getdents64(fd, dirp, count));
407 }
408 
409 
410 /*
411  * uid_t geteuid(void);
412  */
413 
414 static __attribute__((unused))
415 uid_t sys_geteuid(void)
416 {
417 #if defined(__NR_geteuid32)
418 	return my_syscall0(__NR_geteuid32);
419 #else
420 	return my_syscall0(__NR_geteuid);
421 #endif
422 }
423 
424 static __attribute__((unused))
425 uid_t geteuid(void)
426 {
427 	return sys_geteuid();
428 }
429 
430 
431 /*
432  * pid_t getpgid(pid_t pid);
433  */
434 
435 static __attribute__((unused))
436 pid_t sys_getpgid(pid_t pid)
437 {
438 	return my_syscall1(__NR_getpgid, pid);
439 }
440 
441 static __attribute__((unused))
442 pid_t getpgid(pid_t pid)
443 {
444 	return __sysret(sys_getpgid(pid));
445 }
446 
447 
448 /*
449  * pid_t getpgrp(void);
450  */
451 
452 static __attribute__((unused))
453 pid_t sys_getpgrp(void)
454 {
455 	return sys_getpgid(0);
456 }
457 
458 static __attribute__((unused))
459 pid_t getpgrp(void)
460 {
461 	return sys_getpgrp();
462 }
463 
464 
465 /*
466  * pid_t getpid(void);
467  */
468 
469 static __attribute__((unused))
470 pid_t sys_getpid(void)
471 {
472 	return my_syscall0(__NR_getpid);
473 }
474 
475 static __attribute__((unused))
476 pid_t getpid(void)
477 {
478 	return sys_getpid();
479 }
480 
481 
482 /*
483  * pid_t getppid(void);
484  */
485 
486 static __attribute__((unused))
487 pid_t sys_getppid(void)
488 {
489 	return my_syscall0(__NR_getppid);
490 }
491 
492 static __attribute__((unused))
493 pid_t getppid(void)
494 {
495 	return sys_getppid();
496 }
497 
498 
499 /*
500  * pid_t gettid(void);
501  */
502 
503 static __attribute__((unused))
504 pid_t sys_gettid(void)
505 {
506 	return my_syscall0(__NR_gettid);
507 }
508 
509 static __attribute__((unused))
510 pid_t gettid(void)
511 {
512 	return sys_gettid();
513 }
514 
515 #ifndef NOLIBC_NO_RUNTIME
516 static unsigned long getauxval(unsigned long key);
517 
518 /*
519  * int getpagesize(void);
520  */
521 
522 static __attribute__((unused))
523 int getpagesize(void)
524 {
525 	return __sysret((int)getauxval(AT_PAGESZ) ?: -ENOENT);
526 }
527 #endif /* NOLIBC_NO_RUNTIME */
528 
529 /*
530  * uid_t getuid(void);
531  */
532 
533 static __attribute__((unused))
534 uid_t sys_getuid(void)
535 {
536 #if defined(__NR_getuid32)
537 	return my_syscall0(__NR_getuid32);
538 #else
539 	return my_syscall0(__NR_getuid);
540 #endif
541 }
542 
543 static __attribute__((unused))
544 uid_t getuid(void)
545 {
546 	return sys_getuid();
547 }
548 
549 
550 /*
551  * int kill(pid_t pid, int signal);
552  */
553 
554 static __attribute__((unused))
555 int sys_kill(pid_t pid, int signal)
556 {
557 	return my_syscall2(__NR_kill, pid, signal);
558 }
559 
560 static __attribute__((unused))
561 int kill(pid_t pid, int signal)
562 {
563 	return __sysret(sys_kill(pid, signal));
564 }
565 
566 
567 /*
568  * int link(const char *old, const char *new);
569  */
570 
571 static __attribute__((unused))
572 int sys_link(const char *old, const char *new)
573 {
574 #if defined(__NR_linkat)
575 	return my_syscall5(__NR_linkat, AT_FDCWD, old, AT_FDCWD, new, 0);
576 #else
577 	return my_syscall2(__NR_link, old, new);
578 #endif
579 }
580 
581 static __attribute__((unused))
582 int link(const char *old, const char *new)
583 {
584 	return __sysret(sys_link(old, new));
585 }
586 
587 
588 /*
589  * off_t lseek(int fd, off_t offset, int whence);
590  */
591 
592 static __attribute__((unused))
593 off_t sys_lseek(int fd, off_t offset, int whence)
594 {
595 #if defined(__NR_lseek)
596 	return my_syscall3(__NR_lseek, fd, offset, whence);
597 #else
598 	__kernel_loff_t loff = 0;
599 	off_t result;
600 	int ret;
601 
602 	/* Only exists on 32bit where nolibc off_t is also 32bit */
603 	ret = my_syscall5(__NR_llseek, fd, 0, offset, &loff, whence);
604 	if (ret < 0)
605 		result = ret;
606 	else if (loff != (off_t)loff)
607 		result = -EOVERFLOW;
608 	else
609 		result = loff;
610 
611 	return result;
612 #endif
613 }
614 
615 static __attribute__((unused))
616 off_t lseek(int fd, off_t offset, int whence)
617 {
618 	return __sysret(sys_lseek(fd, offset, whence));
619 }
620 
621 
622 /*
623  * int mkdir(const char *path, mode_t mode);
624  */
625 
626 static __attribute__((unused))
627 int sys_mkdir(const char *path, mode_t mode)
628 {
629 #if defined(__NR_mkdirat)
630 	return my_syscall3(__NR_mkdirat, AT_FDCWD, path, mode);
631 #else
632 	return my_syscall2(__NR_mkdir, path, mode);
633 #endif
634 }
635 
636 static __attribute__((unused))
637 int mkdir(const char *path, mode_t mode)
638 {
639 	return __sysret(sys_mkdir(path, mode));
640 }
641 
642 /*
643  * int rmdir(const char *path);
644  */
645 
646 static __attribute__((unused))
647 int sys_rmdir(const char *path)
648 {
649 #if defined(__NR_rmdir)
650 	return my_syscall1(__NR_rmdir, path);
651 #else
652 	return my_syscall3(__NR_unlinkat, AT_FDCWD, path, AT_REMOVEDIR);
653 #endif
654 }
655 
656 static __attribute__((unused))
657 int rmdir(const char *path)
658 {
659 	return __sysret(sys_rmdir(path));
660 }
661 
662 
663 /*
664  * int mknod(const char *path, mode_t mode, dev_t dev);
665  */
666 
667 static __attribute__((unused))
668 long sys_mknod(const char *path, mode_t mode, dev_t dev)
669 {
670 #if defined(__NR_mknodat)
671 	return my_syscall4(__NR_mknodat, AT_FDCWD, path, mode, dev);
672 #else
673 	return my_syscall3(__NR_mknod, path, mode, dev);
674 #endif
675 }
676 
677 static __attribute__((unused))
678 int mknod(const char *path, mode_t mode, dev_t dev)
679 {
680 	return __sysret(sys_mknod(path, mode, dev));
681 }
682 
683 
684 /*
685  * int pipe2(int pipefd[2], int flags);
686  * int pipe(int pipefd[2]);
687  */
688 
689 static __attribute__((unused))
690 int sys_pipe2(int pipefd[2], int flags)
691 {
692 	return my_syscall2(__NR_pipe2, pipefd, flags);
693 }
694 
695 static __attribute__((unused))
696 int pipe2(int pipefd[2], int flags)
697 {
698 	return __sysret(sys_pipe2(pipefd, flags));
699 }
700 
701 static __attribute__((unused))
702 int pipe(int pipefd[2])
703 {
704 	return pipe2(pipefd, 0);
705 }
706 
707 
708 /*
709  * int pivot_root(const char *new, const char *old);
710  */
711 
712 static __attribute__((unused))
713 int sys_pivot_root(const char *new, const char *old)
714 {
715 	return my_syscall2(__NR_pivot_root, new, old);
716 }
717 
718 static __attribute__((unused))
719 int pivot_root(const char *new, const char *old)
720 {
721 	return __sysret(sys_pivot_root(new, old));
722 }
723 
724 
725 /*
726  * ssize_t read(int fd, void *buf, size_t count);
727  */
728 
729 static __attribute__((unused))
730 ssize_t sys_read(int fd, void *buf, size_t count)
731 {
732 	return my_syscall3(__NR_read, fd, buf, count);
733 }
734 
735 static __attribute__((unused))
736 ssize_t read(int fd, void *buf, size_t count)
737 {
738 	return __sysret(sys_read(fd, buf, count));
739 }
740 
741 
742 /*
743  * int sched_yield(void);
744  */
745 
746 static __attribute__((unused))
747 int sys_sched_yield(void)
748 {
749 	return my_syscall0(__NR_sched_yield);
750 }
751 
752 static __attribute__((unused))
753 int sched_yield(void)
754 {
755 	return __sysret(sys_sched_yield());
756 }
757 
758 
759 /*
760  * int select(int nfds, fd_set *read_fds, fd_set *write_fds,
761  *            fd_set *except_fds, struct timeval *timeout);
762  */
763 
764 static __attribute__((unused))
765 int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout)
766 {
767 #if defined(__ARCH_WANT_SYS_OLD_SELECT) && !defined(__NR__newselect)
768 	struct sel_arg_struct {
769 		unsigned long n;
770 		fd_set *r, *w, *e;
771 		struct timeval *t;
772 	} arg = { .n = nfds, .r = rfds, .w = wfds, .e = efds, .t = timeout };
773 	return my_syscall1(__NR_select, &arg);
774 #elif defined(__NR__newselect)
775 	return my_syscall5(__NR__newselect, nfds, rfds, wfds, efds, timeout);
776 #elif defined(__NR_select)
777 	return my_syscall5(__NR_select, nfds, rfds, wfds, efds, timeout);
778 #elif defined(__NR_pselect6)
779 	struct timespec t;
780 
781 	if (timeout) {
782 		t.tv_sec  = timeout->tv_sec;
783 		t.tv_nsec = timeout->tv_usec * 1000;
784 	}
785 	return my_syscall6(__NR_pselect6, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL);
786 #else
787 	struct __kernel_timespec t;
788 
789 	if (timeout) {
790 		t.tv_sec  = timeout->tv_sec;
791 		t.tv_nsec = timeout->tv_usec * 1000;
792 	}
793 	return my_syscall6(__NR_pselect6_time64, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL);
794 #endif
795 }
796 
797 static __attribute__((unused))
798 int select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout)
799 {
800 	return __sysret(sys_select(nfds, rfds, wfds, efds, timeout));
801 }
802 
803 
804 /*
805  * int setpgid(pid_t pid, pid_t pgid);
806  */
807 
808 static __attribute__((unused))
809 int sys_setpgid(pid_t pid, pid_t pgid)
810 {
811 	return my_syscall2(__NR_setpgid, pid, pgid);
812 }
813 
814 static __attribute__((unused))
815 int setpgid(pid_t pid, pid_t pgid)
816 {
817 	return __sysret(sys_setpgid(pid, pgid));
818 }
819 
820 /*
821  * pid_t setpgrp(void)
822  */
823 
824 static __attribute__((unused))
825 pid_t setpgrp(void)
826 {
827 	return setpgid(0, 0);
828 }
829 
830 
831 /*
832  * pid_t setsid(void);
833  */
834 
835 static __attribute__((unused))
836 pid_t sys_setsid(void)
837 {
838 	return my_syscall0(__NR_setsid);
839 }
840 
841 static __attribute__((unused))
842 pid_t setsid(void)
843 {
844 	return __sysret(sys_setsid());
845 }
846 
847 
848 /*
849  * int symlink(const char *old, const char *new);
850  */
851 
852 static __attribute__((unused))
853 int sys_symlink(const char *old, const char *new)
854 {
855 #if defined(__NR_symlinkat)
856 	return my_syscall3(__NR_symlinkat, old, AT_FDCWD, new);
857 #else
858 	return my_syscall2(__NR_symlink, old, new);
859 #endif
860 }
861 
862 static __attribute__((unused))
863 int symlink(const char *old, const char *new)
864 {
865 	return __sysret(sys_symlink(old, new));
866 }
867 
868 
869 /*
870  * mode_t umask(mode_t mode);
871  */
872 
873 static __attribute__((unused))
874 mode_t sys_umask(mode_t mode)
875 {
876 	return my_syscall1(__NR_umask, mode);
877 }
878 
879 static __attribute__((unused))
880 mode_t umask(mode_t mode)
881 {
882 	return sys_umask(mode);
883 }
884 
885 
886 /*
887  * int umount2(const char *path, int flags);
888  */
889 
890 static __attribute__((unused))
891 int sys_umount2(const char *path, int flags)
892 {
893 	return my_syscall2(__NR_umount2, path, flags);
894 }
895 
896 static __attribute__((unused))
897 int umount2(const char *path, int flags)
898 {
899 	return __sysret(sys_umount2(path, flags));
900 }
901 
902 
903 /*
904  * int unlink(const char *path);
905  */
906 
907 static __attribute__((unused))
908 int sys_unlink(const char *path)
909 {
910 #if defined(__NR_unlinkat)
911 	return my_syscall3(__NR_unlinkat, AT_FDCWD, path, 0);
912 #else
913 	return my_syscall1(__NR_unlink, path);
914 #endif
915 }
916 
917 static __attribute__((unused))
918 int unlink(const char *path)
919 {
920 	return __sysret(sys_unlink(path));
921 }
922 
923 
924 /*
925  * ssize_t write(int fd, const void *buf, size_t count);
926  */
927 
928 static __attribute__((unused))
929 ssize_t sys_write(int fd, const void *buf, size_t count)
930 {
931 	return my_syscall3(__NR_write, fd, buf, count);
932 }
933 
934 static __attribute__((unused))
935 ssize_t write(int fd, const void *buf, size_t count)
936 {
937 	return __sysret(sys_write(fd, buf, count));
938 }
939 
940 
941 /*
942  * int memfd_create(const char *name, unsigned int flags);
943  */
944 
945 static __attribute__((unused))
946 int sys_memfd_create(const char *name, unsigned int flags)
947 {
948 	return my_syscall2(__NR_memfd_create, name, flags);
949 }
950 
951 static __attribute__((unused))
952 int memfd_create(const char *name, unsigned int flags)
953 {
954 	return __sysret(sys_memfd_create(name, flags));
955 }
956 
957 #endif /* _NOLIBC_SYS_H */
958