Warning: This file is not a C or C++ file. It does not have highlighting.
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 | #ifndef _NOLIBC_SYS_H |
8 | #define _NOLIBC_SYS_H |
9 | |
10 | #include "std.h" |
11 | |
12 | /* system includes */ |
13 | #include <asm/unistd.h> |
14 | #include <asm/signal.h> /* for SIGCHLD */ |
15 | #include <asm/ioctls.h> |
16 | #include <asm/mman.h> |
17 | #include <linux/fs.h> |
18 | #include <linux/loop.h> |
19 | #include <linux/time.h> |
20 | #include <linux/auxvec.h> |
21 | #include <linux/fcntl.h> /* for O_* and AT_* */ |
22 | #include <linux/stat.h> /* for statx() */ |
23 | #include <linux/prctl.h> |
24 | #include <linux/resource.h> |
25 | |
26 | #include "arch.h" |
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 | |
51 | static __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 | |
86 | static __attribute__((unused)) |
87 | void *sys_brk(void *addr) |
88 | { |
89 | return (void *)my_syscall1(__NR_brk, addr); |
90 | } |
91 | |
92 | static __attribute__((unused)) |
93 | int 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 | |
104 | static __attribute__((unused)) |
105 | void *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 | |
122 | static __attribute__((unused)) |
123 | int sys_chdir(const char *path) |
124 | { |
125 | return my_syscall1(__NR_chdir, path); |
126 | } |
127 | |
128 | static __attribute__((unused)) |
129 | int 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 | |
139 | static __attribute__((unused)) |
140 | int 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 | |
151 | static __attribute__((unused)) |
152 | int 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 | |
162 | static __attribute__((unused)) |
163 | int 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 | |
174 | static __attribute__((unused)) |
175 | int 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 | |
185 | static __attribute__((unused)) |
186 | int sys_chroot(const char *path) |
187 | { |
188 | return my_syscall1(__NR_chroot, path); |
189 | } |
190 | |
191 | static __attribute__((unused)) |
192 | int chroot(const char *path) |
193 | { |
194 | return __sysret(sys_chroot(path)); |
195 | } |
196 | |
197 | |
198 | /* |
199 | * int close(int fd); |
200 | */ |
201 | |
202 | static __attribute__((unused)) |
203 | int sys_close(int fd) |
204 | { |
205 | return my_syscall1(__NR_close, fd); |
206 | } |
207 | |
208 | static __attribute__((unused)) |
209 | int close(int fd) |
210 | { |
211 | return __sysret(sys_close(fd)); |
212 | } |
213 | |
214 | |
215 | /* |
216 | * int dup(int fd); |
217 | */ |
218 | |
219 | static __attribute__((unused)) |
220 | int sys_dup(int fd) |
221 | { |
222 | return my_syscall1(__NR_dup, fd); |
223 | } |
224 | |
225 | static __attribute__((unused)) |
226 | int dup(int fd) |
227 | { |
228 | return __sysret(sys_dup(fd)); |
229 | } |
230 | |
231 | |
232 | /* |
233 | * int dup2(int old, int new); |
234 | */ |
235 | |
236 | static __attribute__((unused)) |
237 | int 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 | |
248 | static __attribute__((unused)) |
249 | int 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 |
260 | static __attribute__((unused)) |
261 | int sys_dup3(int old, int new, int flags) |
262 | { |
263 | return my_syscall3(__NR_dup3, old, new, flags); |
264 | } |
265 | |
266 | static __attribute__((unused)) |
267 | int 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 | |
278 | static __attribute__((unused)) |
279 | int sys_execve(const char *filename, char *const argv[], char *const envp[]) |
280 | { |
281 | return my_syscall3(__NR_execve, filename, argv, envp); |
282 | } |
283 | |
284 | static __attribute__((unused)) |
285 | int 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 | |
295 | static __attribute__((noreturn,unused)) |
296 | void sys_exit(int status) |
297 | { |
298 | my_syscall1(__NR_exit, status & 255); |
299 | while(1); /* shut the "noreturn" warnings. */ |
300 | } |
301 | |
302 | static __attribute__((noreturn,unused)) |
303 | void exit(int status) |
304 | { |
305 | sys_exit(status); |
306 | } |
307 | |
308 | |
309 | /* |
310 | * pid_t fork(void); |
311 | */ |
312 | |
313 | #ifndef sys_fork |
314 | static __attribute__((unused)) |
315 | pid_t sys_fork(void) |
316 | { |
317 | #ifdef __NR_clone |
318 | /* note: some archs only have clone() and not fork(). Different archs |
319 | * have a different API, but most archs have the flags on first arg and |
320 | * will not use the rest with no other flag. |
321 | */ |
322 | return my_syscall5(__NR_clone, SIGCHLD, 0, 0, 0, 0); |
323 | #elif defined(__NR_fork) |
324 | return my_syscall0(__NR_fork); |
325 | #else |
326 | return __nolibc_enosys(__func__); |
327 | #endif |
328 | } |
329 | #endif |
330 | |
331 | static __attribute__((unused)) |
332 | pid_t fork(void) |
333 | { |
334 | return __sysret(sys_fork()); |
335 | } |
336 | |
337 | |
338 | /* |
339 | * int fsync(int fd); |
340 | */ |
341 | |
342 | static __attribute__((unused)) |
343 | int sys_fsync(int fd) |
344 | { |
345 | return my_syscall1(__NR_fsync, fd); |
346 | } |
347 | |
348 | static __attribute__((unused)) |
349 | int fsync(int fd) |
350 | { |
351 | return __sysret(sys_fsync(fd)); |
352 | } |
353 | |
354 | |
355 | /* |
356 | * int getdents64(int fd, struct linux_dirent64 *dirp, int count); |
357 | */ |
358 | |
359 | static __attribute__((unused)) |
360 | int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count) |
361 | { |
362 | return my_syscall3(__NR_getdents64, fd, dirp, count); |
363 | } |
364 | |
365 | static __attribute__((unused)) |
366 | int getdents64(int fd, struct linux_dirent64 *dirp, int count) |
367 | { |
368 | return __sysret(sys_getdents64(fd, dirp, count)); |
369 | } |
370 | |
371 | |
372 | /* |
373 | * uid_t geteuid(void); |
374 | */ |
375 | |
376 | static __attribute__((unused)) |
377 | uid_t sys_geteuid(void) |
378 | { |
379 | #ifdef __NR_geteuid32 |
380 | return my_syscall0(__NR_geteuid32); |
381 | #else |
382 | return my_syscall0(__NR_geteuid); |
383 | #endif |
384 | } |
385 | |
386 | static __attribute__((unused)) |
387 | uid_t geteuid(void) |
388 | { |
389 | return sys_geteuid(); |
390 | } |
391 | |
392 | |
393 | /* |
394 | * pid_t getpgid(pid_t pid); |
395 | */ |
396 | |
397 | static __attribute__((unused)) |
398 | pid_t sys_getpgid(pid_t pid) |
399 | { |
400 | return my_syscall1(__NR_getpgid, pid); |
401 | } |
402 | |
403 | static __attribute__((unused)) |
404 | pid_t getpgid(pid_t pid) |
405 | { |
406 | return __sysret(sys_getpgid(pid)); |
407 | } |
408 | |
409 | |
410 | /* |
411 | * pid_t getpgrp(void); |
412 | */ |
413 | |
414 | static __attribute__((unused)) |
415 | pid_t sys_getpgrp(void) |
416 | { |
417 | return sys_getpgid(0); |
418 | } |
419 | |
420 | static __attribute__((unused)) |
421 | pid_t getpgrp(void) |
422 | { |
423 | return sys_getpgrp(); |
424 | } |
425 | |
426 | |
427 | /* |
428 | * pid_t getpid(void); |
429 | */ |
430 | |
431 | static __attribute__((unused)) |
432 | pid_t sys_getpid(void) |
433 | { |
434 | return my_syscall0(__NR_getpid); |
435 | } |
436 | |
437 | static __attribute__((unused)) |
438 | pid_t getpid(void) |
439 | { |
440 | return sys_getpid(); |
441 | } |
442 | |
443 | |
444 | /* |
445 | * pid_t getppid(void); |
446 | */ |
447 | |
448 | static __attribute__((unused)) |
449 | pid_t sys_getppid(void) |
450 | { |
451 | return my_syscall0(__NR_getppid); |
452 | } |
453 | |
454 | static __attribute__((unused)) |
455 | pid_t getppid(void) |
456 | { |
457 | return sys_getppid(); |
458 | } |
459 | |
460 | |
461 | /* |
462 | * pid_t gettid(void); |
463 | */ |
464 | |
465 | static __attribute__((unused)) |
466 | pid_t sys_gettid(void) |
467 | { |
468 | return my_syscall0(__NR_gettid); |
469 | } |
470 | |
471 | static __attribute__((unused)) |
472 | pid_t gettid(void) |
473 | { |
474 | return sys_gettid(); |
475 | } |
476 | |
477 | static unsigned long getauxval(unsigned long key); |
478 | |
479 | /* |
480 | * int getpagesize(void); |
481 | */ |
482 | |
483 | static __attribute__((unused)) |
484 | int getpagesize(void) |
485 | { |
486 | return __sysret((int)getauxval(AT_PAGESZ) ?: -ENOENT); |
487 | } |
488 | |
489 | |
490 | /* |
491 | * int gettimeofday(struct timeval *tv, struct timezone *tz); |
492 | */ |
493 | |
494 | static __attribute__((unused)) |
495 | int sys_gettimeofday(struct timeval *tv, struct timezone *tz) |
496 | { |
497 | #ifdef __NR_gettimeofday |
498 | return my_syscall2(__NR_gettimeofday, tv, tz); |
499 | #else |
500 | return __nolibc_enosys(__func__, tv, tz); |
501 | #endif |
502 | } |
503 | |
504 | static __attribute__((unused)) |
505 | int gettimeofday(struct timeval *tv, struct timezone *tz) |
506 | { |
507 | return __sysret(sys_gettimeofday(tv, tz)); |
508 | } |
509 | |
510 | |
511 | /* |
512 | * uid_t getuid(void); |
513 | */ |
514 | |
515 | static __attribute__((unused)) |
516 | uid_t sys_getuid(void) |
517 | { |
518 | #ifdef __NR_getuid32 |
519 | return my_syscall0(__NR_getuid32); |
520 | #else |
521 | return my_syscall0(__NR_getuid); |
522 | #endif |
523 | } |
524 | |
525 | static __attribute__((unused)) |
526 | uid_t getuid(void) |
527 | { |
528 | return sys_getuid(); |
529 | } |
530 | |
531 | |
532 | /* |
533 | * int ioctl(int fd, unsigned long req, void *value); |
534 | */ |
535 | |
536 | static __attribute__((unused)) |
537 | int sys_ioctl(int fd, unsigned long req, void *value) |
538 | { |
539 | return my_syscall3(__NR_ioctl, fd, req, value); |
540 | } |
541 | |
542 | static __attribute__((unused)) |
543 | int ioctl(int fd, unsigned long req, void *value) |
544 | { |
545 | return __sysret(sys_ioctl(fd, req, value)); |
546 | } |
547 | |
548 | /* |
549 | * int kill(pid_t pid, int signal); |
550 | */ |
551 | |
552 | static __attribute__((unused)) |
553 | int sys_kill(pid_t pid, int signal) |
554 | { |
555 | return my_syscall2(__NR_kill, pid, signal); |
556 | } |
557 | |
558 | static __attribute__((unused)) |
559 | int kill(pid_t pid, int signal) |
560 | { |
561 | return __sysret(sys_kill(pid, signal)); |
562 | } |
563 | |
564 | |
565 | /* |
566 | * int link(const char *old, const char *new); |
567 | */ |
568 | |
569 | static __attribute__((unused)) |
570 | int sys_link(const char *old, const char *new) |
571 | { |
572 | #ifdef __NR_linkat |
573 | return my_syscall5(__NR_linkat, AT_FDCWD, old, AT_FDCWD, new, 0); |
574 | #elif defined(__NR_link) |
575 | return my_syscall2(__NR_link, old, new); |
576 | #else |
577 | return __nolibc_enosys(__func__, old, new); |
578 | #endif |
579 | } |
580 | |
581 | static __attribute__((unused)) |
582 | int link(const char *old, const char *new) |
583 | { |
584 | return __sysret(sys_link(old, new)); |
585 | } |
586 | |
587 | |
588 | /* |
589 | * off_t lseek(int fd, off_t offset, int whence); |
590 | */ |
591 | |
592 | static __attribute__((unused)) |
593 | off_t sys_lseek(int fd, off_t offset, int whence) |
594 | { |
595 | #ifdef __NR_lseek |
596 | return my_syscall3(__NR_lseek, fd, offset, whence); |
597 | #else |
598 | return __nolibc_enosys(__func__, fd, offset, whence); |
599 | #endif |
600 | } |
601 | |
602 | static __attribute__((unused)) |
603 | off_t lseek(int fd, off_t offset, int whence) |
604 | { |
605 | return __sysret(sys_lseek(fd, offset, whence)); |
606 | } |
607 | |
608 | |
609 | /* |
610 | * int mkdir(const char *path, mode_t mode); |
611 | */ |
612 | |
613 | static __attribute__((unused)) |
614 | int sys_mkdir(const char *path, mode_t mode) |
615 | { |
616 | #ifdef __NR_mkdirat |
617 | return my_syscall3(__NR_mkdirat, AT_FDCWD, path, mode); |
618 | #elif defined(__NR_mkdir) |
619 | return my_syscall2(__NR_mkdir, path, mode); |
620 | #else |
621 | return __nolibc_enosys(__func__, path, mode); |
622 | #endif |
623 | } |
624 | |
625 | static __attribute__((unused)) |
626 | int mkdir(const char *path, mode_t mode) |
627 | { |
628 | return __sysret(sys_mkdir(path, mode)); |
629 | } |
630 | |
631 | /* |
632 | * int rmdir(const char *path); |
633 | */ |
634 | |
635 | static __attribute__((unused)) |
636 | int sys_rmdir(const char *path) |
637 | { |
638 | #ifdef __NR_rmdir |
639 | return my_syscall1(__NR_rmdir, path); |
640 | #elif defined(__NR_unlinkat) |
641 | return my_syscall3(__NR_unlinkat, AT_FDCWD, path, AT_REMOVEDIR); |
642 | #else |
643 | return __nolibc_enosys(__func__, path); |
644 | #endif |
645 | } |
646 | |
647 | static __attribute__((unused)) |
648 | int rmdir(const char *path) |
649 | { |
650 | return __sysret(sys_rmdir(path)); |
651 | } |
652 | |
653 | |
654 | /* |
655 | * int mknod(const char *path, mode_t mode, dev_t dev); |
656 | */ |
657 | |
658 | static __attribute__((unused)) |
659 | long sys_mknod(const char *path, mode_t mode, dev_t dev) |
660 | { |
661 | #ifdef __NR_mknodat |
662 | return my_syscall4(__NR_mknodat, AT_FDCWD, path, mode, dev); |
663 | #elif defined(__NR_mknod) |
664 | return my_syscall3(__NR_mknod, path, mode, dev); |
665 | #else |
666 | return __nolibc_enosys(__func__, path, mode, dev); |
667 | #endif |
668 | } |
669 | |
670 | static __attribute__((unused)) |
671 | int mknod(const char *path, mode_t mode, dev_t dev) |
672 | { |
673 | return __sysret(sys_mknod(path, mode, dev)); |
674 | } |
675 | |
676 | #ifndef sys_mmap |
677 | static __attribute__((unused)) |
678 | void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, |
679 | off_t offset) |
680 | { |
681 | int n; |
682 | |
683 | #if defined(__NR_mmap2) |
684 | n = __NR_mmap2; |
685 | offset >>= 12; |
686 | #else |
687 | n = __NR_mmap; |
688 | #endif |
689 | |
690 | return (void *)my_syscall6(n, addr, length, prot, flags, fd, offset); |
691 | } |
692 | #endif |
693 | |
694 | /* Note that on Linux, MAP_FAILED is -1 so we can use the generic __sysret() |
695 | * which returns -1 upon error and still satisfy user land that checks for |
696 | * MAP_FAILED. |
697 | */ |
698 | |
699 | static __attribute__((unused)) |
700 | void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) |
701 | { |
702 | void *ret = sys_mmap(addr, length, prot, flags, fd, offset); |
703 | |
704 | if ((unsigned long)ret >= -4095UL) { |
705 | SET_ERRNO(-(long)ret); |
706 | ret = MAP_FAILED; |
707 | } |
708 | return ret; |
709 | } |
710 | |
711 | static __attribute__((unused)) |
712 | int sys_munmap(void *addr, size_t length) |
713 | { |
714 | return my_syscall2(__NR_munmap, addr, length); |
715 | } |
716 | |
717 | static __attribute__((unused)) |
718 | int munmap(void *addr, size_t length) |
719 | { |
720 | return __sysret(sys_munmap(addr, length)); |
721 | } |
722 | |
723 | /* |
724 | * int mount(const char *source, const char *target, |
725 | * const char *fstype, unsigned long flags, |
726 | * const void *data); |
727 | */ |
728 | static __attribute__((unused)) |
729 | int sys_mount(const char *src, const char *tgt, const char *fst, |
730 | unsigned long flags, const void *data) |
731 | { |
732 | return my_syscall5(__NR_mount, src, tgt, fst, flags, data); |
733 | } |
734 | |
735 | static __attribute__((unused)) |
736 | int mount(const char *src, const char *tgt, |
737 | const char *fst, unsigned long flags, |
738 | const void *data) |
739 | { |
740 | return __sysret(sys_mount(src, tgt, fst, flags, data)); |
741 | } |
742 | |
743 | |
744 | /* |
745 | * int open(const char *path, int flags[, mode_t mode]); |
746 | */ |
747 | |
748 | static __attribute__((unused)) |
749 | int sys_open(const char *path, int flags, mode_t mode) |
750 | { |
751 | #ifdef __NR_openat |
752 | return my_syscall4(__NR_openat, AT_FDCWD, path, flags, mode); |
753 | #elif defined(__NR_open) |
754 | return my_syscall3(__NR_open, path, flags, mode); |
755 | #else |
756 | return __nolibc_enosys(__func__, path, flags, mode); |
757 | #endif |
758 | } |
759 | |
760 | static __attribute__((unused)) |
761 | int open(const char *path, int flags, ...) |
762 | { |
763 | mode_t mode = 0; |
764 | |
765 | if (flags & O_CREAT) { |
766 | va_list args; |
767 | |
768 | va_start(args, flags); |
769 | mode = va_arg(args, int); |
770 | va_end(args); |
771 | } |
772 | |
773 | return __sysret(sys_open(path, flags, mode)); |
774 | } |
775 | |
776 | |
777 | /* |
778 | * int pipe2(int pipefd[2], int flags); |
779 | * int pipe(int pipefd[2]); |
780 | */ |
781 | |
782 | static __attribute__((unused)) |
783 | int sys_pipe2(int pipefd[2], int flags) |
784 | { |
785 | return my_syscall2(__NR_pipe2, pipefd, flags); |
786 | } |
787 | |
788 | static __attribute__((unused)) |
789 | int pipe2(int pipefd[2], int flags) |
790 | { |
791 | return __sysret(sys_pipe2(pipefd, flags)); |
792 | } |
793 | |
794 | static __attribute__((unused)) |
795 | int pipe(int pipefd[2]) |
796 | { |
797 | return pipe2(pipefd, 0); |
798 | } |
799 | |
800 | |
801 | /* |
802 | * int prctl(int option, unsigned long arg2, unsigned long arg3, |
803 | * unsigned long arg4, unsigned long arg5); |
804 | */ |
805 | |
806 | static __attribute__((unused)) |
807 | int sys_prctl(int option, unsigned long arg2, unsigned long arg3, |
808 | unsigned long arg4, unsigned long arg5) |
809 | { |
810 | return my_syscall5(__NR_prctl, option, arg2, arg3, arg4, arg5); |
811 | } |
812 | |
813 | static __attribute__((unused)) |
814 | int prctl(int option, unsigned long arg2, unsigned long arg3, |
815 | unsigned long arg4, unsigned long arg5) |
816 | { |
817 | return __sysret(sys_prctl(option, arg2, arg3, arg4, arg5)); |
818 | } |
819 | |
820 | |
821 | /* |
822 | * int pivot_root(const char *new, const char *old); |
823 | */ |
824 | |
825 | static __attribute__((unused)) |
826 | int sys_pivot_root(const char *new, const char *old) |
827 | { |
828 | return my_syscall2(__NR_pivot_root, new, old); |
829 | } |
830 | |
831 | static __attribute__((unused)) |
832 | int pivot_root(const char *new, const char *old) |
833 | { |
834 | return __sysret(sys_pivot_root(new, old)); |
835 | } |
836 | |
837 | |
838 | /* |
839 | * int poll(struct pollfd *fds, int nfds, int timeout); |
840 | */ |
841 | |
842 | static __attribute__((unused)) |
843 | int sys_poll(struct pollfd *fds, int nfds, int timeout) |
844 | { |
845 | #if defined(__NR_ppoll) |
846 | struct timespec t; |
847 | |
848 | if (timeout >= 0) { |
849 | t.tv_sec = timeout / 1000; |
850 | t.tv_nsec = (timeout % 1000) * 1000000; |
851 | } |
852 | return my_syscall5(__NR_ppoll, fds, nfds, (timeout >= 0) ? &t : NULL, NULL, 0); |
853 | #elif defined(__NR_poll) |
854 | return my_syscall3(__NR_poll, fds, nfds, timeout); |
855 | #else |
856 | return __nolibc_enosys(__func__, fds, nfds, timeout); |
857 | #endif |
858 | } |
859 | |
860 | static __attribute__((unused)) |
861 | int poll(struct pollfd *fds, int nfds, int timeout) |
862 | { |
863 | return __sysret(sys_poll(fds, nfds, timeout)); |
864 | } |
865 | |
866 | |
867 | /* |
868 | * ssize_t read(int fd, void *buf, size_t count); |
869 | */ |
870 | |
871 | static __attribute__((unused)) |
872 | ssize_t sys_read(int fd, void *buf, size_t count) |
873 | { |
874 | return my_syscall3(__NR_read, fd, buf, count); |
875 | } |
876 | |
877 | static __attribute__((unused)) |
878 | ssize_t read(int fd, void *buf, size_t count) |
879 | { |
880 | return __sysret(sys_read(fd, buf, count)); |
881 | } |
882 | |
883 | |
884 | /* |
885 | * int reboot(int cmd); |
886 | * <cmd> is among LINUX_REBOOT_CMD_* |
887 | */ |
888 | |
889 | static __attribute__((unused)) |
890 | ssize_t sys_reboot(int magic1, int magic2, int cmd, void *arg) |
891 | { |
892 | return my_syscall4(__NR_reboot, magic1, magic2, cmd, arg); |
893 | } |
894 | |
895 | static __attribute__((unused)) |
896 | int reboot(int cmd) |
897 | { |
898 | return __sysret(sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, 0)); |
899 | } |
900 | |
901 | |
902 | /* |
903 | * int getrlimit(int resource, struct rlimit *rlim); |
904 | * int setrlimit(int resource, const struct rlimit *rlim); |
905 | */ |
906 | |
907 | static __attribute__((unused)) |
908 | int sys_prlimit64(pid_t pid, int resource, |
909 | const struct rlimit64 *new_limit, struct rlimit64 *old_limit) |
910 | { |
911 | return my_syscall4(__NR_prlimit64, pid, resource, new_limit, old_limit); |
912 | } |
913 | |
914 | static __attribute__((unused)) |
915 | int getrlimit(int resource, struct rlimit *rlim) |
916 | { |
917 | struct rlimit64 rlim64; |
918 | int ret; |
919 | |
920 | ret = __sysret(sys_prlimit64(0, resource, NULL, &rlim64)); |
921 | rlim->rlim_cur = rlim64.rlim_cur; |
922 | rlim->rlim_max = rlim64.rlim_max; |
923 | |
924 | return ret; |
925 | } |
926 | |
927 | static __attribute__((unused)) |
928 | int setrlimit(int resource, const struct rlimit *rlim) |
929 | { |
930 | struct rlimit64 rlim64 = { |
931 | .rlim_cur = rlim->rlim_cur, |
932 | .rlim_max = rlim->rlim_max, |
933 | }; |
934 | |
935 | return __sysret(sys_prlimit64(0, resource, &rlim64, NULL)); |
936 | } |
937 | |
938 | |
939 | /* |
940 | * int sched_yield(void); |
941 | */ |
942 | |
943 | static __attribute__((unused)) |
944 | int sys_sched_yield(void) |
945 | { |
946 | return my_syscall0(__NR_sched_yield); |
947 | } |
948 | |
949 | static __attribute__((unused)) |
950 | int sched_yield(void) |
951 | { |
952 | return __sysret(sys_sched_yield()); |
953 | } |
954 | |
955 | |
956 | /* |
957 | * int select(int nfds, fd_set *read_fds, fd_set *write_fds, |
958 | * fd_set *except_fds, struct timeval *timeout); |
959 | */ |
960 | |
961 | static __attribute__((unused)) |
962 | int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) |
963 | { |
964 | #if defined(__ARCH_WANT_SYS_OLD_SELECT) && !defined(__NR__newselect) |
965 | struct sel_arg_struct { |
966 | unsigned long n; |
967 | fd_set *r, *w, *e; |
968 | struct timeval *t; |
969 | } arg = { .n = nfds, .r = rfds, .w = wfds, .e = efds, .t = timeout }; |
970 | return my_syscall1(__NR_select, &arg); |
971 | #elif defined(__NR__newselect) |
972 | return my_syscall5(__NR__newselect, nfds, rfds, wfds, efds, timeout); |
973 | #elif defined(__NR_select) |
974 | return my_syscall5(__NR_select, nfds, rfds, wfds, efds, timeout); |
975 | #elif defined(__NR_pselect6) |
976 | struct timespec t; |
977 | |
978 | if (timeout) { |
979 | t.tv_sec = timeout->tv_sec; |
980 | t.tv_nsec = timeout->tv_usec * 1000; |
981 | } |
982 | return my_syscall6(__NR_pselect6, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL); |
983 | #else |
984 | return __nolibc_enosys(__func__, nfds, rfds, wfds, efds, timeout); |
985 | #endif |
986 | } |
987 | |
988 | static __attribute__((unused)) |
989 | int select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) |
990 | { |
991 | return __sysret(sys_select(nfds, rfds, wfds, efds, timeout)); |
992 | } |
993 | |
994 | |
995 | /* |
996 | * int setpgid(pid_t pid, pid_t pgid); |
997 | */ |
998 | |
999 | static __attribute__((unused)) |
1000 | int sys_setpgid(pid_t pid, pid_t pgid) |
1001 | { |
1002 | return my_syscall2(__NR_setpgid, pid, pgid); |
1003 | } |
1004 | |
1005 | static __attribute__((unused)) |
1006 | int setpgid(pid_t pid, pid_t pgid) |
1007 | { |
1008 | return __sysret(sys_setpgid(pid, pgid)); |
1009 | } |
1010 | |
1011 | |
1012 | /* |
1013 | * pid_t setsid(void); |
1014 | */ |
1015 | |
1016 | static __attribute__((unused)) |
1017 | pid_t sys_setsid(void) |
1018 | { |
1019 | return my_syscall0(__NR_setsid); |
1020 | } |
1021 | |
1022 | static __attribute__((unused)) |
1023 | pid_t setsid(void) |
1024 | { |
1025 | return __sysret(sys_setsid()); |
1026 | } |
1027 | |
1028 | /* |
1029 | * int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf); |
1030 | * int stat(const char *path, struct stat *buf); |
1031 | */ |
1032 | |
1033 | static __attribute__((unused)) |
1034 | int sys_statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf) |
1035 | { |
1036 | #ifdef __NR_statx |
1037 | return my_syscall5(__NR_statx, fd, path, flags, mask, buf); |
1038 | #else |
1039 | return __nolibc_enosys(__func__, fd, path, flags, mask, buf); |
1040 | #endif |
1041 | } |
1042 | |
1043 | static __attribute__((unused)) |
1044 | int statx(int fd, const char *path, int flags, unsigned int mask, struct statx *buf) |
1045 | { |
1046 | return __sysret(sys_statx(fd, path, flags, mask, buf)); |
1047 | } |
1048 | |
1049 | |
1050 | static __attribute__((unused)) |
1051 | int stat(const char *path, struct stat *buf) |
1052 | { |
1053 | struct statx statx; |
1054 | long ret; |
1055 | |
1056 | ret = __sysret(sys_statx(AT_FDCWD, path, AT_NO_AUTOMOUNT, STATX_BASIC_STATS, &statx)); |
1057 | if (ret == -1) |
1058 | return ret; |
1059 | |
1060 | buf->st_dev = ((statx.stx_dev_minor & 0xff) |
1061 | | (statx.stx_dev_major << 8) |
1062 | | ((statx.stx_dev_minor & ~0xff) << 12)); |
1063 | buf->st_ino = statx.stx_ino; |
1064 | buf->st_mode = statx.stx_mode; |
1065 | buf->st_nlink = statx.stx_nlink; |
1066 | buf->st_uid = statx.stx_uid; |
1067 | buf->st_gid = statx.stx_gid; |
1068 | buf->st_rdev = ((statx.stx_rdev_minor & 0xff) |
1069 | | (statx.stx_rdev_major << 8) |
1070 | | ((statx.stx_rdev_minor & ~0xff) << 12)); |
1071 | buf->st_size = statx.stx_size; |
1072 | buf->st_blksize = statx.stx_blksize; |
1073 | buf->st_blocks = statx.stx_blocks; |
1074 | buf->st_atim.tv_sec = statx.stx_atime.tv_sec; |
1075 | buf->st_atim.tv_nsec = statx.stx_atime.tv_nsec; |
1076 | buf->st_mtim.tv_sec = statx.stx_mtime.tv_sec; |
1077 | buf->st_mtim.tv_nsec = statx.stx_mtime.tv_nsec; |
1078 | buf->st_ctim.tv_sec = statx.stx_ctime.tv_sec; |
1079 | buf->st_ctim.tv_nsec = statx.stx_ctime.tv_nsec; |
1080 | |
1081 | return 0; |
1082 | } |
1083 | |
1084 | |
1085 | /* |
1086 | * int symlink(const char *old, const char *new); |
1087 | */ |
1088 | |
1089 | static __attribute__((unused)) |
1090 | int sys_symlink(const char *old, const char *new) |
1091 | { |
1092 | #ifdef __NR_symlinkat |
1093 | return my_syscall3(__NR_symlinkat, old, AT_FDCWD, new); |
1094 | #elif defined(__NR_symlink) |
1095 | return my_syscall2(__NR_symlink, old, new); |
1096 | #else |
1097 | return __nolibc_enosys(__func__, old, new); |
1098 | #endif |
1099 | } |
1100 | |
1101 | static __attribute__((unused)) |
1102 | int symlink(const char *old, const char *new) |
1103 | { |
1104 | return __sysret(sys_symlink(old, new)); |
1105 | } |
1106 | |
1107 | |
1108 | /* |
1109 | * mode_t umask(mode_t mode); |
1110 | */ |
1111 | |
1112 | static __attribute__((unused)) |
1113 | mode_t sys_umask(mode_t mode) |
1114 | { |
1115 | return my_syscall1(__NR_umask, mode); |
1116 | } |
1117 | |
1118 | static __attribute__((unused)) |
1119 | mode_t umask(mode_t mode) |
1120 | { |
1121 | return sys_umask(mode); |
1122 | } |
1123 | |
1124 | |
1125 | /* |
1126 | * int umount2(const char *path, int flags); |
1127 | */ |
1128 | |
1129 | static __attribute__((unused)) |
1130 | int sys_umount2(const char *path, int flags) |
1131 | { |
1132 | return my_syscall2(__NR_umount2, path, flags); |
1133 | } |
1134 | |
1135 | static __attribute__((unused)) |
1136 | int umount2(const char *path, int flags) |
1137 | { |
1138 | return __sysret(sys_umount2(path, flags)); |
1139 | } |
1140 | |
1141 | |
1142 | /* |
1143 | * int unlink(const char *path); |
1144 | */ |
1145 | |
1146 | static __attribute__((unused)) |
1147 | int sys_unlink(const char *path) |
1148 | { |
1149 | #ifdef __NR_unlinkat |
1150 | return my_syscall3(__NR_unlinkat, AT_FDCWD, path, 0); |
1151 | #elif defined(__NR_unlink) |
1152 | return my_syscall1(__NR_unlink, path); |
1153 | #else |
1154 | return __nolibc_enosys(__func__, path); |
1155 | #endif |
1156 | } |
1157 | |
1158 | static __attribute__((unused)) |
1159 | int unlink(const char *path) |
1160 | { |
1161 | return __sysret(sys_unlink(path)); |
1162 | } |
1163 | |
1164 | |
1165 | /* |
1166 | * pid_t wait(int *status); |
1167 | * pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage); |
1168 | * pid_t waitpid(pid_t pid, int *status, int options); |
1169 | */ |
1170 | |
1171 | static __attribute__((unused)) |
1172 | pid_t sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage) |
1173 | { |
1174 | #ifdef __NR_wait4 |
1175 | return my_syscall4(__NR_wait4, pid, status, options, rusage); |
1176 | #else |
1177 | return __nolibc_enosys(__func__, pid, status, options, rusage); |
1178 | #endif |
1179 | } |
1180 | |
1181 | static __attribute__((unused)) |
1182 | pid_t wait(int *status) |
1183 | { |
1184 | return __sysret(sys_wait4(-1, status, 0, NULL)); |
1185 | } |
1186 | |
1187 | static __attribute__((unused)) |
1188 | pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage) |
1189 | { |
1190 | return __sysret(sys_wait4(pid, status, options, rusage)); |
1191 | } |
1192 | |
1193 | |
1194 | static __attribute__((unused)) |
1195 | pid_t waitpid(pid_t pid, int *status, int options) |
1196 | { |
1197 | return __sysret(sys_wait4(pid, status, options, NULL)); |
1198 | } |
1199 | |
1200 | |
1201 | /* |
1202 | * ssize_t write(int fd, const void *buf, size_t count); |
1203 | */ |
1204 | |
1205 | static __attribute__((unused)) |
1206 | ssize_t sys_write(int fd, const void *buf, size_t count) |
1207 | { |
1208 | return my_syscall3(__NR_write, fd, buf, count); |
1209 | } |
1210 | |
1211 | static __attribute__((unused)) |
1212 | ssize_t write(int fd, const void *buf, size_t count) |
1213 | { |
1214 | return __sysret(sys_write(fd, buf, count)); |
1215 | } |
1216 | |
1217 | |
1218 | /* |
1219 | * int memfd_create(const char *name, unsigned int flags); |
1220 | */ |
1221 | |
1222 | static __attribute__((unused)) |
1223 | int sys_memfd_create(const char *name, unsigned int flags) |
1224 | { |
1225 | return my_syscall2(__NR_memfd_create, name, flags); |
1226 | } |
1227 | |
1228 | static __attribute__((unused)) |
1229 | int memfd_create(const char *name, unsigned int flags) |
1230 | { |
1231 | return __sysret(sys_memfd_create(name, flags)); |
1232 | } |
1233 | |
1234 | /* make sure to include all global symbols */ |
1235 | #include "nolibc.h" |
1236 | |
1237 | #endif /* _NOLIBC_SYS_H */ |
1238 |
Warning: This file is not a C or C++ file. It does not have highlighting.