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