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