xref: /linux/tools/include/nolibc/sys.h (revision b22d81ed319cbe2d5b45f605cab18aaf82a66a50)
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 #elif defined(__NR_chmod)
146 	return my_syscall2(__NR_chmod, path, mode);
147 #else
148 	return __nolibc_enosys(__func__, path, mode);
149 #endif
150 }
151 
152 static __attribute__((unused))
153 int chmod(const char *path, mode_t mode)
154 {
155 	return __sysret(sys_chmod(path, mode));
156 }
157 
158 
159 /*
160  * int chown(const char *path, uid_t owner, gid_t group);
161  */
162 
163 static __attribute__((unused))
164 int sys_chown(const char *path, uid_t owner, gid_t group)
165 {
166 #if defined(__NR_fchownat)
167 	return my_syscall5(__NR_fchownat, AT_FDCWD, path, owner, group, 0);
168 #elif defined(__NR_chown)
169 	return my_syscall3(__NR_chown, path, owner, group);
170 #else
171 	return __nolibc_enosys(__func__, path, owner, group);
172 #endif
173 }
174 
175 static __attribute__((unused))
176 int chown(const char *path, uid_t owner, gid_t group)
177 {
178 	return __sysret(sys_chown(path, owner, group));
179 }
180 
181 
182 /*
183  * int chroot(const char *path);
184  */
185 
186 static __attribute__((unused))
187 int sys_chroot(const char *path)
188 {
189 	return my_syscall1(__NR_chroot, path);
190 }
191 
192 static __attribute__((unused))
193 int chroot(const char *path)
194 {
195 	return __sysret(sys_chroot(path));
196 }
197 
198 
199 /*
200  * int close(int fd);
201  */
202 
203 static __attribute__((unused))
204 int sys_close(int fd)
205 {
206 	return my_syscall1(__NR_close, fd);
207 }
208 
209 static __attribute__((unused))
210 int close(int fd)
211 {
212 	return __sysret(sys_close(fd));
213 }
214 
215 
216 /*
217  * int dup(int fd);
218  */
219 
220 static __attribute__((unused))
221 int sys_dup(int fd)
222 {
223 	return my_syscall1(__NR_dup, fd);
224 }
225 
226 static __attribute__((unused))
227 int dup(int fd)
228 {
229 	return __sysret(sys_dup(fd));
230 }
231 
232 
233 /*
234  * int dup2(int old, int new);
235  */
236 
237 static __attribute__((unused))
238 int sys_dup2(int old, int new)
239 {
240 #if defined(__NR_dup3)
241 	int ret, nr_fcntl;
242 
243 #ifdef __NR_fcntl64
244 	nr_fcntl = __NR_fcntl64;
245 #else
246 	nr_fcntl = __NR_fcntl;
247 #endif
248 
249 	if (old == new) {
250 		ret = my_syscall2(nr_fcntl, old, F_GETFD);
251 		return ret < 0 ? ret : old;
252 	}
253 
254 	return my_syscall3(__NR_dup3, old, new, 0);
255 #elif defined(__NR_dup2)
256 	return my_syscall2(__NR_dup2, old, new);
257 #else
258 	return __nolibc_enosys(__func__, old, new);
259 #endif
260 }
261 
262 static __attribute__((unused))
263 int dup2(int old, int new)
264 {
265 	return __sysret(sys_dup2(old, new));
266 }
267 
268 
269 /*
270  * int dup3(int old, int new, int flags);
271  */
272 
273 #if defined(__NR_dup3)
274 static __attribute__((unused))
275 int sys_dup3(int old, int new, int flags)
276 {
277 	return my_syscall3(__NR_dup3, old, new, flags);
278 }
279 
280 static __attribute__((unused))
281 int dup3(int old, int new, int flags)
282 {
283 	return __sysret(sys_dup3(old, new, flags));
284 }
285 #endif
286 
287 
288 /*
289  * int execve(const char *filename, char *const argv[], char *const envp[]);
290  */
291 
292 static __attribute__((unused))
293 int sys_execve(const char *filename, char *const argv[], char *const envp[])
294 {
295 	return my_syscall3(__NR_execve, filename, argv, envp);
296 }
297 
298 static __attribute__((unused))
299 int execve(const char *filename, char *const argv[], char *const envp[])
300 {
301 	return __sysret(sys_execve(filename, argv, envp));
302 }
303 
304 
305 /*
306  * void exit(int status);
307  */
308 
309 static __attribute__((noreturn,unused))
310 void sys_exit(int status)
311 {
312 	my_syscall1(__NR_exit, status & 255);
313 	while(1); /* shut the "noreturn" warnings. */
314 }
315 
316 static __attribute__((noreturn,unused))
317 void _exit(int status)
318 {
319 	sys_exit(status);
320 }
321 
322 static __attribute__((noreturn,unused))
323 void exit(int status)
324 {
325 	_exit(status);
326 }
327 
328 
329 /*
330  * pid_t fork(void);
331  */
332 
333 #ifndef sys_fork
334 static __attribute__((unused))
335 pid_t sys_fork(void)
336 {
337 #if defined(__NR_clone)
338 	/* note: some archs only have clone() and not fork(). Different archs
339 	 * have a different API, but most archs have the flags on first arg and
340 	 * will not use the rest with no other flag.
341 	 */
342 	return my_syscall5(__NR_clone, SIGCHLD, 0, 0, 0, 0);
343 #elif defined(__NR_fork)
344 	return my_syscall0(__NR_fork);
345 #else
346 	return __nolibc_enosys(__func__);
347 #endif
348 }
349 #endif
350 
351 static __attribute__((unused))
352 pid_t fork(void)
353 {
354 	return __sysret(sys_fork());
355 }
356 
357 #ifndef sys_vfork
358 static __attribute__((unused))
359 pid_t sys_vfork(void)
360 {
361 #if defined(__NR_vfork)
362 	return my_syscall0(__NR_vfork);
363 #elif defined(__NR_clone3)
364 	/*
365 	 * clone() could be used but has different argument orders per
366 	 * architecture.
367 	 */
368 	struct clone_args args = {
369 		.flags		= CLONE_VM | CLONE_VFORK,
370 		.exit_signal	= SIGCHLD,
371 	};
372 
373 	return my_syscall2(__NR_clone3, &args, sizeof(args));
374 #else
375 	return __nolibc_enosys(__func__);
376 #endif
377 }
378 #endif
379 
380 static __attribute__((unused))
381 pid_t vfork(void)
382 {
383 	return __sysret(sys_vfork());
384 }
385 
386 /*
387  * int fsync(int fd);
388  */
389 
390 static __attribute__((unused))
391 int sys_fsync(int fd)
392 {
393 	return my_syscall1(__NR_fsync, fd);
394 }
395 
396 static __attribute__((unused))
397 int fsync(int fd)
398 {
399 	return __sysret(sys_fsync(fd));
400 }
401 
402 
403 /*
404  * int getdents64(int fd, struct linux_dirent64 *dirp, int count);
405  */
406 
407 static __attribute__((unused))
408 int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count)
409 {
410 	return my_syscall3(__NR_getdents64, fd, dirp, count);
411 }
412 
413 static __attribute__((unused))
414 int getdents64(int fd, struct linux_dirent64 *dirp, int count)
415 {
416 	return __sysret(sys_getdents64(fd, dirp, count));
417 }
418 
419 
420 /*
421  * uid_t geteuid(void);
422  */
423 
424 static __attribute__((unused))
425 uid_t sys_geteuid(void)
426 {
427 #if defined(__NR_geteuid32)
428 	return my_syscall0(__NR_geteuid32);
429 #else
430 	return my_syscall0(__NR_geteuid);
431 #endif
432 }
433 
434 static __attribute__((unused))
435 uid_t geteuid(void)
436 {
437 	return sys_geteuid();
438 }
439 
440 
441 /*
442  * pid_t getpgid(pid_t pid);
443  */
444 
445 static __attribute__((unused))
446 pid_t sys_getpgid(pid_t pid)
447 {
448 	return my_syscall1(__NR_getpgid, pid);
449 }
450 
451 static __attribute__((unused))
452 pid_t getpgid(pid_t pid)
453 {
454 	return __sysret(sys_getpgid(pid));
455 }
456 
457 
458 /*
459  * pid_t getpgrp(void);
460  */
461 
462 static __attribute__((unused))
463 pid_t sys_getpgrp(void)
464 {
465 	return sys_getpgid(0);
466 }
467 
468 static __attribute__((unused))
469 pid_t getpgrp(void)
470 {
471 	return sys_getpgrp();
472 }
473 
474 
475 /*
476  * pid_t getpid(void);
477  */
478 
479 static __attribute__((unused))
480 pid_t sys_getpid(void)
481 {
482 	return my_syscall0(__NR_getpid);
483 }
484 
485 static __attribute__((unused))
486 pid_t getpid(void)
487 {
488 	return sys_getpid();
489 }
490 
491 
492 /*
493  * pid_t getppid(void);
494  */
495 
496 static __attribute__((unused))
497 pid_t sys_getppid(void)
498 {
499 	return my_syscall0(__NR_getppid);
500 }
501 
502 static __attribute__((unused))
503 pid_t getppid(void)
504 {
505 	return sys_getppid();
506 }
507 
508 
509 /*
510  * pid_t gettid(void);
511  */
512 
513 static __attribute__((unused))
514 pid_t sys_gettid(void)
515 {
516 	return my_syscall0(__NR_gettid);
517 }
518 
519 static __attribute__((unused))
520 pid_t gettid(void)
521 {
522 	return sys_gettid();
523 }
524 
525 static unsigned long getauxval(unsigned long key);
526 
527 /*
528  * int getpagesize(void);
529  */
530 
531 static __attribute__((unused))
532 int getpagesize(void)
533 {
534 	return __sysret((int)getauxval(AT_PAGESZ) ?: -ENOENT);
535 }
536 
537 
538 /*
539  * uid_t getuid(void);
540  */
541 
542 static __attribute__((unused))
543 uid_t sys_getuid(void)
544 {
545 #if defined(__NR_getuid32)
546 	return my_syscall0(__NR_getuid32);
547 #else
548 	return my_syscall0(__NR_getuid);
549 #endif
550 }
551 
552 static __attribute__((unused))
553 uid_t getuid(void)
554 {
555 	return sys_getuid();
556 }
557 
558 
559 /*
560  * int kill(pid_t pid, int signal);
561  */
562 
563 static __attribute__((unused))
564 int sys_kill(pid_t pid, int signal)
565 {
566 	return my_syscall2(__NR_kill, pid, signal);
567 }
568 
569 static __attribute__((unused))
570 int kill(pid_t pid, int signal)
571 {
572 	return __sysret(sys_kill(pid, signal));
573 }
574 
575 
576 /*
577  * int link(const char *old, const char *new);
578  */
579 
580 static __attribute__((unused))
581 int sys_link(const char *old, const char *new)
582 {
583 #if defined(__NR_linkat)
584 	return my_syscall5(__NR_linkat, AT_FDCWD, old, AT_FDCWD, new, 0);
585 #elif defined(__NR_link)
586 	return my_syscall2(__NR_link, old, new);
587 #else
588 	return __nolibc_enosys(__func__, old, new);
589 #endif
590 }
591 
592 static __attribute__((unused))
593 int link(const char *old, const char *new)
594 {
595 	return __sysret(sys_link(old, new));
596 }
597 
598 
599 /*
600  * off_t lseek(int fd, off_t offset, int whence);
601  */
602 
603 static __attribute__((unused))
604 off_t sys_lseek(int fd, off_t offset, int whence)
605 {
606 #if defined(__NR_lseek)
607 	return my_syscall3(__NR_lseek, fd, offset, whence);
608 #else
609 	return __nolibc_enosys(__func__, fd, offset, whence);
610 #endif
611 }
612 
613 static __attribute__((unused))
614 int sys_llseek(int fd, unsigned long offset_high, unsigned long offset_low,
615 	       __kernel_loff_t *result, int whence)
616 {
617 #if defined(__NR_llseek)
618 	return my_syscall5(__NR_llseek, fd, offset_high, offset_low, result, whence);
619 #else
620 	return __nolibc_enosys(__func__, fd, offset_high, offset_low, result, whence);
621 #endif
622 }
623 
624 static __attribute__((unused))
625 off_t lseek(int fd, off_t offset, int whence)
626 {
627 	__kernel_loff_t loff = 0;
628 	off_t result;
629 	int ret;
630 
631 	result = sys_lseek(fd, offset, whence);
632 	if (result == -ENOSYS) {
633 		/* Only exists on 32bit where nolibc off_t is also 32bit */
634 		ret = sys_llseek(fd, 0, offset, &loff, whence);
635 		if (ret < 0)
636 			result = ret;
637 		else if (loff != (off_t)loff)
638 			result = -EOVERFLOW;
639 		else
640 			result = loff;
641 	}
642 
643 	return __sysret(result);
644 }
645 
646 
647 /*
648  * int mkdir(const char *path, mode_t mode);
649  */
650 
651 static __attribute__((unused))
652 int sys_mkdir(const char *path, mode_t mode)
653 {
654 #if defined(__NR_mkdirat)
655 	return my_syscall3(__NR_mkdirat, AT_FDCWD, path, mode);
656 #elif defined(__NR_mkdir)
657 	return my_syscall2(__NR_mkdir, path, mode);
658 #else
659 	return __nolibc_enosys(__func__, path, mode);
660 #endif
661 }
662 
663 static __attribute__((unused))
664 int mkdir(const char *path, mode_t mode)
665 {
666 	return __sysret(sys_mkdir(path, mode));
667 }
668 
669 /*
670  * int rmdir(const char *path);
671  */
672 
673 static __attribute__((unused))
674 int sys_rmdir(const char *path)
675 {
676 #if defined(__NR_rmdir)
677 	return my_syscall1(__NR_rmdir, path);
678 #elif defined(__NR_unlinkat)
679 	return my_syscall3(__NR_unlinkat, AT_FDCWD, path, AT_REMOVEDIR);
680 #else
681 	return __nolibc_enosys(__func__, path);
682 #endif
683 }
684 
685 static __attribute__((unused))
686 int rmdir(const char *path)
687 {
688 	return __sysret(sys_rmdir(path));
689 }
690 
691 
692 /*
693  * int mknod(const char *path, mode_t mode, dev_t dev);
694  */
695 
696 static __attribute__((unused))
697 long sys_mknod(const char *path, mode_t mode, dev_t dev)
698 {
699 #if defined(__NR_mknodat)
700 	return my_syscall4(__NR_mknodat, AT_FDCWD, path, mode, dev);
701 #elif defined(__NR_mknod)
702 	return my_syscall3(__NR_mknod, path, mode, dev);
703 #else
704 	return __nolibc_enosys(__func__, path, mode, dev);
705 #endif
706 }
707 
708 static __attribute__((unused))
709 int mknod(const char *path, mode_t mode, dev_t dev)
710 {
711 	return __sysret(sys_mknod(path, mode, dev));
712 }
713 
714 
715 /*
716  * int pipe2(int pipefd[2], int flags);
717  * int pipe(int pipefd[2]);
718  */
719 
720 static __attribute__((unused))
721 int sys_pipe2(int pipefd[2], int flags)
722 {
723 	return my_syscall2(__NR_pipe2, pipefd, flags);
724 }
725 
726 static __attribute__((unused))
727 int pipe2(int pipefd[2], int flags)
728 {
729 	return __sysret(sys_pipe2(pipefd, flags));
730 }
731 
732 static __attribute__((unused))
733 int pipe(int pipefd[2])
734 {
735 	return pipe2(pipefd, 0);
736 }
737 
738 
739 /*
740  * int pivot_root(const char *new, const char *old);
741  */
742 
743 static __attribute__((unused))
744 int sys_pivot_root(const char *new, const char *old)
745 {
746 	return my_syscall2(__NR_pivot_root, new, old);
747 }
748 
749 static __attribute__((unused))
750 int pivot_root(const char *new, const char *old)
751 {
752 	return __sysret(sys_pivot_root(new, old));
753 }
754 
755 
756 /*
757  * ssize_t read(int fd, void *buf, size_t count);
758  */
759 
760 static __attribute__((unused))
761 ssize_t sys_read(int fd, void *buf, size_t count)
762 {
763 	return my_syscall3(__NR_read, fd, buf, count);
764 }
765 
766 static __attribute__((unused))
767 ssize_t read(int fd, void *buf, size_t count)
768 {
769 	return __sysret(sys_read(fd, buf, count));
770 }
771 
772 
773 /*
774  * int sched_yield(void);
775  */
776 
777 static __attribute__((unused))
778 int sys_sched_yield(void)
779 {
780 	return my_syscall0(__NR_sched_yield);
781 }
782 
783 static __attribute__((unused))
784 int sched_yield(void)
785 {
786 	return __sysret(sys_sched_yield());
787 }
788 
789 
790 /*
791  * int select(int nfds, fd_set *read_fds, fd_set *write_fds,
792  *            fd_set *except_fds, struct timeval *timeout);
793  */
794 
795 static __attribute__((unused))
796 int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout)
797 {
798 #if defined(__ARCH_WANT_SYS_OLD_SELECT) && !defined(__NR__newselect)
799 	struct sel_arg_struct {
800 		unsigned long n;
801 		fd_set *r, *w, *e;
802 		struct timeval *t;
803 	} arg = { .n = nfds, .r = rfds, .w = wfds, .e = efds, .t = timeout };
804 	return my_syscall1(__NR_select, &arg);
805 #elif defined(__NR__newselect)
806 	return my_syscall5(__NR__newselect, nfds, rfds, wfds, efds, timeout);
807 #elif defined(__NR_select)
808 	return my_syscall5(__NR_select, nfds, rfds, wfds, efds, timeout);
809 #elif defined(__NR_pselect6)
810 	struct timespec t;
811 
812 	if (timeout) {
813 		t.tv_sec  = timeout->tv_sec;
814 		t.tv_nsec = timeout->tv_usec * 1000;
815 	}
816 	return my_syscall6(__NR_pselect6, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL);
817 #elif defined(__NR_pselect6_time64)
818 	struct __kernel_timespec t;
819 
820 	if (timeout) {
821 		t.tv_sec  = timeout->tv_sec;
822 		t.tv_nsec = timeout->tv_usec * 1000;
823 	}
824 	return my_syscall6(__NR_pselect6_time64, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL);
825 #else
826 	return __nolibc_enosys(__func__, nfds, rfds, wfds, efds, timeout);
827 #endif
828 }
829 
830 static __attribute__((unused))
831 int select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout)
832 {
833 	return __sysret(sys_select(nfds, rfds, wfds, efds, timeout));
834 }
835 
836 
837 /*
838  * int setpgid(pid_t pid, pid_t pgid);
839  */
840 
841 static __attribute__((unused))
842 int sys_setpgid(pid_t pid, pid_t pgid)
843 {
844 	return my_syscall2(__NR_setpgid, pid, pgid);
845 }
846 
847 static __attribute__((unused))
848 int setpgid(pid_t pid, pid_t pgid)
849 {
850 	return __sysret(sys_setpgid(pid, pgid));
851 }
852 
853 /*
854  * pid_t setpgrp(void)
855  */
856 
857 static __attribute__((unused))
858 pid_t setpgrp(void)
859 {
860 	return setpgid(0, 0);
861 }
862 
863 
864 /*
865  * pid_t setsid(void);
866  */
867 
868 static __attribute__((unused))
869 pid_t sys_setsid(void)
870 {
871 	return my_syscall0(__NR_setsid);
872 }
873 
874 static __attribute__((unused))
875 pid_t setsid(void)
876 {
877 	return __sysret(sys_setsid());
878 }
879 
880 
881 /*
882  * int symlink(const char *old, const char *new);
883  */
884 
885 static __attribute__((unused))
886 int sys_symlink(const char *old, const char *new)
887 {
888 #if defined(__NR_symlinkat)
889 	return my_syscall3(__NR_symlinkat, old, AT_FDCWD, new);
890 #elif defined(__NR_symlink)
891 	return my_syscall2(__NR_symlink, old, new);
892 #else
893 	return __nolibc_enosys(__func__, old, new);
894 #endif
895 }
896 
897 static __attribute__((unused))
898 int symlink(const char *old, const char *new)
899 {
900 	return __sysret(sys_symlink(old, new));
901 }
902 
903 
904 /*
905  * mode_t umask(mode_t mode);
906  */
907 
908 static __attribute__((unused))
909 mode_t sys_umask(mode_t mode)
910 {
911 	return my_syscall1(__NR_umask, mode);
912 }
913 
914 static __attribute__((unused))
915 mode_t umask(mode_t mode)
916 {
917 	return sys_umask(mode);
918 }
919 
920 
921 /*
922  * int umount2(const char *path, int flags);
923  */
924 
925 static __attribute__((unused))
926 int sys_umount2(const char *path, int flags)
927 {
928 	return my_syscall2(__NR_umount2, path, flags);
929 }
930 
931 static __attribute__((unused))
932 int umount2(const char *path, int flags)
933 {
934 	return __sysret(sys_umount2(path, flags));
935 }
936 
937 
938 /*
939  * int unlink(const char *path);
940  */
941 
942 static __attribute__((unused))
943 int sys_unlink(const char *path)
944 {
945 #if defined(__NR_unlinkat)
946 	return my_syscall3(__NR_unlinkat, AT_FDCWD, path, 0);
947 #elif defined(__NR_unlink)
948 	return my_syscall1(__NR_unlink, path);
949 #else
950 	return __nolibc_enosys(__func__, path);
951 #endif
952 }
953 
954 static __attribute__((unused))
955 int unlink(const char *path)
956 {
957 	return __sysret(sys_unlink(path));
958 }
959 
960 
961 /*
962  * ssize_t write(int fd, const void *buf, size_t count);
963  */
964 
965 static __attribute__((unused))
966 ssize_t sys_write(int fd, const void *buf, size_t count)
967 {
968 	return my_syscall3(__NR_write, fd, buf, count);
969 }
970 
971 static __attribute__((unused))
972 ssize_t write(int fd, const void *buf, size_t count)
973 {
974 	return __sysret(sys_write(fd, buf, count));
975 }
976 
977 
978 /*
979  * int memfd_create(const char *name, unsigned int flags);
980  */
981 
982 static __attribute__((unused))
983 int sys_memfd_create(const char *name, unsigned int flags)
984 {
985 	return my_syscall2(__NR_memfd_create, name, flags);
986 }
987 
988 static __attribute__((unused))
989 int memfd_create(const char *name, unsigned int flags)
990 {
991 	return __sysret(sys_memfd_create(name, flags));
992 }
993 
994 #endif /* _NOLIBC_SYS_H */
995