Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
52static __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
87static __attribute__((unused))
88void *sys_brk(void *addr)
89{
90 return (void *)my_syscall1(__NR_brk, addr);
91}
92
93static __attribute__((unused))
94int 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
105static __attribute__((unused))
106void *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
123static __attribute__((unused))
124int sys_chdir(const char *path)
125{
126 return my_syscall1(__NR_chdir, path);
127}
128
129static __attribute__((unused))
130int 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
140static __attribute__((unused))
141int 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
150static __attribute__((unused))
151int 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
161static __attribute__((unused))
162int 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
171static __attribute__((unused))
172int 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
182static __attribute__((unused))
183int sys_chroot(const char *path)
184{
185 return my_syscall1(__NR_chroot, path);
186}
187
188static __attribute__((unused))
189int chroot(const char *path)
190{
191 return __sysret(sys_chroot(path));
192}
193
194
195/*
196 * int close(int fd);
197 */
198
199static __attribute__((unused))
200int sys_close(int fd)
201{
202 return my_syscall1(__NR_close, fd);
203}
204
205static __attribute__((unused))
206int close(int fd)
207{
208 return __sysret(sys_close(fd));
209}
210
211
212/*
213 * int dup(int fd);
214 */
215
216static __attribute__((unused))
217int sys_dup(int fd)
218{
219 return my_syscall1(__NR_dup, fd);
220}
221
222static __attribute__((unused))
223int dup(int fd)
224{
225 return __sysret(sys_dup(fd));
226}
227
228
229/*
230 * int dup2(int old, int new);
231 */
232
233static __attribute__((unused))
234int 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
256static __attribute__((unused))
257int 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)
268static __attribute__((unused))
269int sys_dup3(int old, int new, int flags)
270{
271 return my_syscall3(__NR_dup3, old, new, flags);
272}
273
274static __attribute__((unused))
275int 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
286static __attribute__((unused))
287int sys_execve(const char *filename, char *const argv[], char *const envp[])
288{
289 return my_syscall3(__NR_execve, filename, argv, envp);
290}
291
292static __attribute__((unused))
293int 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
303static __attribute__((noreturn,unused))
304void sys_exit(int status)
305{
306 my_syscall1(__NR_exit, status & 255);
307 while(1); /* shut the "noreturn" warnings. */
308}
309
310static __attribute__((noreturn,unused))
311void _exit(int status)
312{
313 sys_exit(status);
314}
315
316static __attribute__((noreturn,unused))
317void exit(int status)
318{
319 _exit(status);
320}
321
322
323/*
324 * pid_t fork(void);
325 */
326
327#ifndef sys_fork
328static __attribute__((unused))
329pid_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
343static __attribute__((unused))
344pid_t fork(void)
345{
346 return __sysret(sys_fork());
347}
348
349#ifndef sys_vfork
350static __attribute__((unused))
351pid_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
370static __attribute__((unused))
371pid_t vfork(void)
372{
373 return __sysret(sys_vfork());
374}
375
376/*
377 * int fsync(int fd);
378 */
379
380static __attribute__((unused))
381int sys_fsync(int fd)
382{
383 return my_syscall1(__NR_fsync, fd);
384}
385
386static __attribute__((unused))
387int 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
397static __attribute__((unused))
398int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count)
399{
400 return my_syscall3(__NR_getdents64, fd, dirp, count);
401}
402
403static __attribute__((unused))
404int 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
414static __attribute__((unused))
415uid_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
424static __attribute__((unused))
425uid_t geteuid(void)
426{
427 return sys_geteuid();
428}
429
430
431/*
432 * pid_t getpgid(pid_t pid);
433 */
434
435static __attribute__((unused))
436pid_t sys_getpgid(pid_t pid)
437{
438 return my_syscall1(__NR_getpgid, pid);
439}
440
441static __attribute__((unused))
442pid_t getpgid(pid_t pid)
443{
444 return __sysret(sys_getpgid(pid));
445}
446
447
448/*
449 * pid_t getpgrp(void);
450 */
451
452static __attribute__((unused))
453pid_t sys_getpgrp(void)
454{
455 return sys_getpgid(0);
456}
457
458static __attribute__((unused))
459pid_t getpgrp(void)
460{
461 return sys_getpgrp();
462}
463
464
465/*
466 * pid_t getpid(void);
467 */
468
469static __attribute__((unused))
470pid_t sys_getpid(void)
471{
472 return my_syscall0(__NR_getpid);
473}
474
475static __attribute__((unused))
476pid_t getpid(void)
477{
478 return sys_getpid();
479}
480
481
482/*
483 * pid_t getppid(void);
484 */
485
486static __attribute__((unused))
487pid_t sys_getppid(void)
488{
489 return my_syscall0(__NR_getppid);
490}
491
492static __attribute__((unused))
493pid_t getppid(void)
494{
495 return sys_getppid();
496}
497
498
499/*
500 * pid_t gettid(void);
501 */
502
503static __attribute__((unused))
504pid_t sys_gettid(void)
505{
506 return my_syscall0(__NR_gettid);
507}
508
509static __attribute__((unused))
510pid_t gettid(void)
511{
512 return sys_gettid();
513}
514
515static unsigned long getauxval(unsigned long key);
516
517/*
518 * int getpagesize(void);
519 */
520
521static __attribute__((unused))
522int getpagesize(void)
523{
524 return __sysret((int)getauxval(AT_PAGESZ) ?: -ENOENT);
525}
526
527
528/*
529 * uid_t getuid(void);
530 */
531
532static __attribute__((unused))
533uid_t sys_getuid(void)
534{
535#if defined(__NR_getuid32)
536 return my_syscall0(__NR_getuid32);
537#else
538 return my_syscall0(__NR_getuid);
539#endif
540}
541
542static __attribute__((unused))
543uid_t getuid(void)
544{
545 return sys_getuid();
546}
547
548
549/*
550 * int kill(pid_t pid, int signal);
551 */
552
553static __attribute__((unused))
554int sys_kill(pid_t pid, int signal)
555{
556 return my_syscall2(__NR_kill, pid, signal);
557}
558
559static __attribute__((unused))
560int kill(pid_t pid, int signal)
561{
562 return __sysret(sys_kill(pid, signal));
563}
564
565
566/*
567 * int link(const char *old, const char *new);
568 */
569
570static __attribute__((unused))
571int sys_link(const char *old, const char *new)
572{
573#if defined(__NR_linkat)
574 return my_syscall5(__NR_linkat, AT_FDCWD, old, AT_FDCWD, new, 0);
575#else
576 return my_syscall2(__NR_link, old, new);
577#endif
578}
579
580static __attribute__((unused))
581int link(const char *old, const char *new)
582{
583 return __sysret(sys_link(old, new));
584}
585
586
587/*
588 * off_t lseek(int fd, off_t offset, int whence);
589 */
590
591static __attribute__((unused))
592off_t sys_lseek(int fd, off_t offset, int whence)
593{
594#if defined(__NR_lseek)
595 return my_syscall3(__NR_lseek, fd, offset, whence);
596#else
597 __kernel_loff_t loff = 0;
598 off_t result;
599 int ret;
600
601 /* Only exists on 32bit where nolibc off_t is also 32bit */
602 ret = my_syscall5(__NR_llseek, fd, 0, offset, &loff, whence);
603 if (ret < 0)
604 result = ret;
605 else if (loff != (off_t)loff)
606 result = -EOVERFLOW;
607 else
608 result = loff;
609
610 return result;
611#endif
612}
613
614static __attribute__((unused))
615off_t lseek(int fd, off_t offset, int whence)
616{
617 return __sysret(sys_lseek(fd, offset, whence));
618}
619
620
621/*
622 * int mkdir(const char *path, mode_t mode);
623 */
624
625static __attribute__((unused))
626int sys_mkdir(const char *path, mode_t mode)
627{
628#if defined(__NR_mkdirat)
629 return my_syscall3(__NR_mkdirat, AT_FDCWD, path, mode);
630#else
631 return my_syscall2(__NR_mkdir, path, mode);
632#endif
633}
634
635static __attribute__((unused))
636int mkdir(const char *path, mode_t mode)
637{
638 return __sysret(sys_mkdir(path, mode));
639}
640
641/*
642 * int rmdir(const char *path);
643 */
644
645static __attribute__((unused))
646int sys_rmdir(const char *path)
647{
648#if defined(__NR_rmdir)
649 return my_syscall1(__NR_rmdir, path);
650#else
651 return my_syscall3(__NR_unlinkat, AT_FDCWD, path, AT_REMOVEDIR);
652#endif
653}
654
655static __attribute__((unused))
656int rmdir(const char *path)
657{
658 return __sysret(sys_rmdir(path));
659}
660
661
662/*
663 * int mknod(const char *path, mode_t mode, dev_t dev);
664 */
665
666static __attribute__((unused))
667long sys_mknod(const char *path, mode_t mode, dev_t dev)
668{
669#if defined(__NR_mknodat)
670 return my_syscall4(__NR_mknodat, AT_FDCWD, path, mode, dev);
671#else
672 return my_syscall3(__NR_mknod, path, mode, dev);
673#endif
674}
675
676static __attribute__((unused))
677int mknod(const char *path, mode_t mode, dev_t dev)
678{
679 return __sysret(sys_mknod(path, mode, dev));
680}
681
682
683/*
684 * int pipe2(int pipefd[2], int flags);
685 * int pipe(int pipefd[2]);
686 */
687
688static __attribute__((unused))
689int sys_pipe2(int pipefd[2], int flags)
690{
691 return my_syscall2(__NR_pipe2, pipefd, flags);
692}
693
694static __attribute__((unused))
695int pipe2(int pipefd[2], int flags)
696{
697 return __sysret(sys_pipe2(pipefd, flags));
698}
699
700static __attribute__((unused))
701int pipe(int pipefd[2])
702{
703 return pipe2(pipefd, 0);
704}
705
706
707/*
708 * int pivot_root(const char *new, const char *old);
709 */
710
711static __attribute__((unused))
712int sys_pivot_root(const char *new, const char *old)
713{
714 return my_syscall2(__NR_pivot_root, new, old);
715}
716
717static __attribute__((unused))
718int pivot_root(const char *new, const char *old)
719{
720 return __sysret(sys_pivot_root(new, old));
721}
722
723
724/*
725 * ssize_t read(int fd, void *buf, size_t count);
726 */
727
728static __attribute__((unused))
729ssize_t sys_read(int fd, void *buf, size_t count)
730{
731 return my_syscall3(__NR_read, fd, buf, count);
732}
733
734static __attribute__((unused))
735ssize_t read(int fd, void *buf, size_t count)
736{
737 return __sysret(sys_read(fd, buf, count));
738}
739
740
741/*
742 * int sched_yield(void);
743 */
744
745static __attribute__((unused))
746int sys_sched_yield(void)
747{
748 return my_syscall0(__NR_sched_yield);
749}
750
751static __attribute__((unused))
752int sched_yield(void)
753{
754 return __sysret(sys_sched_yield());
755}
756
757
758/*
759 * int select(int nfds, fd_set *read_fds, fd_set *write_fds,
760 * fd_set *except_fds, struct timeval *timeout);
761 */
762
763static __attribute__((unused))
764int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout)
765{
766#if defined(__ARCH_WANT_SYS_OLD_SELECT) && !defined(__NR__newselect)
767 struct sel_arg_struct {
768 unsigned long n;
769 fd_set *r, *w, *e;
770 struct timeval *t;
771 } arg = { .n = nfds, .r = rfds, .w = wfds, .e = efds, .t = timeout };
772 return my_syscall1(__NR_select, &arg);
773#elif defined(__NR__newselect)
774 return my_syscall5(__NR__newselect, nfds, rfds, wfds, efds, timeout);
775#elif defined(__NR_select)
776 return my_syscall5(__NR_select, nfds, rfds, wfds, efds, timeout);
777#elif defined(__NR_pselect6)
778 struct timespec t;
779
780 if (timeout) {
781 t.tv_sec = timeout->tv_sec;
782 t.tv_nsec = timeout->tv_usec * 1000;
783 }
784 return my_syscall6(__NR_pselect6, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL);
785#else
786 struct __kernel_timespec t;
787
788 if (timeout) {
789 t.tv_sec = timeout->tv_sec;
790 t.tv_nsec = timeout->tv_usec * 1000;
791 }
792 return my_syscall6(__NR_pselect6_time64, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL);
793#endif
794}
795
796static __attribute__((unused))
797int select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout)
798{
799 return __sysret(sys_select(nfds, rfds, wfds, efds, timeout));
800}
801
802
803/*
804 * int setpgid(pid_t pid, pid_t pgid);
805 */
806
807static __attribute__((unused))
808int sys_setpgid(pid_t pid, pid_t pgid)
809{
810 return my_syscall2(__NR_setpgid, pid, pgid);
811}
812
813static __attribute__((unused))
814int setpgid(pid_t pid, pid_t pgid)
815{
816 return __sysret(sys_setpgid(pid, pgid));
817}
818
819/*
820 * pid_t setpgrp(void)
821 */
822
823static __attribute__((unused))
824pid_t setpgrp(void)
825{
826 return setpgid(0, 0);
827}
828
829
830/*
831 * pid_t setsid(void);
832 */
833
834static __attribute__((unused))
835pid_t sys_setsid(void)
836{
837 return my_syscall0(__NR_setsid);
838}
839
840static __attribute__((unused))
841pid_t setsid(void)
842{
843 return __sysret(sys_setsid());
844}
845
846
847/*
848 * int symlink(const char *old, const char *new);
849 */
850
851static __attribute__((unused))
852int sys_symlink(const char *old, const char *new)
853{
854#if defined(__NR_symlinkat)
855 return my_syscall3(__NR_symlinkat, old, AT_FDCWD, new);
856#else
857 return my_syscall2(__NR_symlink, old, new);
858#endif
859}
860
861static __attribute__((unused))
862int symlink(const char *old, const char *new)
863{
864 return __sysret(sys_symlink(old, new));
865}
866
867
868/*
869 * mode_t umask(mode_t mode);
870 */
871
872static __attribute__((unused))
873mode_t sys_umask(mode_t mode)
874{
875 return my_syscall1(__NR_umask, mode);
876}
877
878static __attribute__((unused))
879mode_t umask(mode_t mode)
880{
881 return sys_umask(mode);
882}
883
884
885/*
886 * int umount2(const char *path, int flags);
887 */
888
889static __attribute__((unused))
890int sys_umount2(const char *path, int flags)
891{
892 return my_syscall2(__NR_umount2, path, flags);
893}
894
895static __attribute__((unused))
896int umount2(const char *path, int flags)
897{
898 return __sysret(sys_umount2(path, flags));
899}
900
901
902/*
903 * int unlink(const char *path);
904 */
905
906static __attribute__((unused))
907int sys_unlink(const char *path)
908{
909#if defined(__NR_unlinkat)
910 return my_syscall3(__NR_unlinkat, AT_FDCWD, path, 0);
911#else
912 return my_syscall1(__NR_unlink, path);
913#endif
914}
915
916static __attribute__((unused))
917int unlink(const char *path)
918{
919 return __sysret(sys_unlink(path));
920}
921
922
923/*
924 * ssize_t write(int fd, const void *buf, size_t count);
925 */
926
927static __attribute__((unused))
928ssize_t sys_write(int fd, const void *buf, size_t count)
929{
930 return my_syscall3(__NR_write, fd, buf, count);
931}
932
933static __attribute__((unused))
934ssize_t write(int fd, const void *buf, size_t count)
935{
936 return __sysret(sys_write(fd, buf, count));
937}
938
939
940/*
941 * int memfd_create(const char *name, unsigned int flags);
942 */
943
944static __attribute__((unused))
945int sys_memfd_create(const char *name, unsigned int flags)
946{
947 return my_syscall2(__NR_memfd_create, name, flags);
948}
949
950static __attribute__((unused))
951int memfd_create(const char *name, unsigned int flags)
952{
953 return __sysret(sys_memfd_create(name, flags));
954}
955
956#endif /* _NOLIBC_SYS_H */