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